dlib C++ Library - Algorithms

The Library
  • Algorithms
  • API Wrappers
  • Bayesian Nets
  • Compression
  • Containers
  • Graph Tools
  • Image Processing
  • Linear Algebra
  • Machine Learning
  • Metaprogramming
  • Miscellaneous
  • Networking
  • Optimization
  • Parsing

Help/Info
  • Dlib Blog
  • Examples: C++
    • 3D Point Cloud
    • Assignment Learning
    • Base64 Encoder
    • Bayesian Network From Disk
    • Bayesian Network GUI
    • Bayesian Network
    • Bridge
    • BSP
    • C-Support Vector Machine
    • Cmd Line Parser
    • Compress Stream
    • Config File Reader
    • Custom Trainers
    • Directory Navigation
    • Empirical Kernel Map
    • Face Detection
    • Face Landmark Detection
    • FHOG Feature Extraction
    • FHOG Object Detection
    • Graph Labeling
    • GUI
    • Hough Transform
    • HTTP Server
    • Image
    • IO Socket Streams
    • IO Streams Server
    • Kernel Centroid
    • Kernel K-Means Clustering
    • Kernel Ridge Regression
    • Kernel RLS Filtering
    • Kernel RLS Regression
    • KRR Classification
    • Learning to Track
    • Linear Assignment Problems
    • Linear Manifold Regularizer
    • Linear Model Predictive Control
    • Logger Advanced
    • Logger Custom Output
    • Logger
    • Matrix Expressions
    • Matrix
    • Member Function Pointer
    • Model Selection
    • Multiclass Classification
    • Multithreaded Object
    • Neural Network
    • Non-Linear Least Squares
    • Nu-Support Vector Machine
    • Numerical Integration
    • Object Detector Advanced
    • Object Detector
    • One Class Classifiers
    • Online SVM
    • Optimization
    • Parallel For Loops
    • Pipe 2
    • Pipe
    • Quantum Computing
    • Queue
    • Rank Features
    • Relevance Vector Classification
    • Relevance Vector Regression
    • Running Stats
    • Sequence Labeling
    • Sequence Segmentation
    • Sockets
    • Sockstreambuf
    • Sparse Vectors
    • SQLite
    • Std C++ Allocator
    • Structural Support Vector Machines
    • Support Vector Regression
    • SURF
    • SVM-Rank
    • Thread Function
    • Thread Pool
    • Threaded Object
    • Threads
    • Timer
    • Train Object Detector
    • Train Shape Predictor
    • Using Custom Kernels
    • Video Object Tracking
    • Webcam Face Pose Estimation
    • XML Parser
  • Examples: Python
    • Face Detector
    • Face Landmark Detection
    • find candidate object locations
    • Linear Assignment Problems
    • Sequence Segmenter
    • Structural Support Vector Machines
    • SVM-Rank
    • Train Object Detector
    • Train Shape Predictor
    • Video Object Tracking
  • FAQ
  • Forums
  • Home
  • How to compile
  • How to contribute
  • Index
  • Introduction
  • License
  • Python API
  • Suggested Books
  • Who uses dlib?

Current Release
  • Change Log
  • Release Notes
  • Version: 18.18

Last Modified:
Sep 13, 2015
Algorithms

This page documents library components that are all basically just implementations of mathematical functions or algorithms that don't fit in any of the other pages of the dlib documentation. So this includes things like checksums, cryptographic hashes, sorting, etc.

Tools
  • bigint
  • disjoint_subsets
  • hsort_array
  • integrate_function_adapt_simp
  • isort_array
  • numeric_constants
  • put_in_range
  • qsort_array
  • Quantum Computing
    • gate
    • quantum_register
  • Set Utilities
    • set_difference
    • set_intersection
    • set_intersection_size
    • set_union
  • split_array
  • square_root

Statistics
  • correlation
  • covariance
  • mean_sign_agreement
  • mean_squared_error
  • median
  • rand
  • randomly_subsample
  • random_subset_selector
  • running_covariance
  • running_cross_covariance
  • running_scalar_covariance
  • running_stats
  • r_squared

Hashing
  • count_bits
  • crc32
  • create_max_margin_projection_hash
  • create_random_projection_hash
  • gaussian_random_hash
  • hamming_distance
  • hash
  • hash_samples
  • hash_similar_angles_128
  • hash_similar_angles_256
  • hash_similar_angles_512
  • hash_similar_angles_64
  • md5
  • murmur_hash3
  • murmur_hash3_128bit
  • projection_hash
  • uniform_random_hash

Filtering
  • kalman_filter
  • rls_filter

[top]

bigint

This object represents an arbitrary precision unsigned integer. It's pretty simple. It's interface is just like a normal int, you don't have to tell it how much memory to use or anything unusual. It just goes :)
More Details...
#include <dlib/bigint.h>

Implementations:
bigint_kernel_1:
This implementation is done using an array of unsigned shorts. It is also reference counted. For further details see the above link. Also note that kernel_2 should be faster in almost every case so you should really just use that version of the bigint object.
kernel_1a
is a typedef for bigint_kernel_1
kernel_1a_c
 is a typedef for kernel_1a that checks its preconditions.
bigint_kernel_2:
This implementation is basically the same as kernel_1 except it uses the Fast Fourier Transform to perform multiplications much faster.
kernel_2a
is a typedef for bigint_kernel_2
kernel_2a_c
 is a typedef for kernel_2a that checks its preconditions.
[top]

correlation

This is a function for computing the correlation between matching elements of two std::vectors.
More Details...
#include <dlib/statistics.h>
[top]

count_bits

This function counts the number of bits in an unsigned integer which are set to 1.
More Details...
#include <dlib/hash.h>
[top]

covariance

This is a function for computing the covariance between matching elements of two std::vectors.
More Details...
#include <dlib/statistics.h>
[top]

crc32

This object represents the CRC-32 algorithm for calculating checksums.
More Details...
#include <dlib/crc32.h>
[top]

create_max_margin_projection_hash

Creates a random projection based locality sensitive hashing function. This is accomplished using a variation on the random hyperplane generation technique from the paper:
Random Maximum Margin Hashing by Alexis Joly and Olivier Buisson
In particular, we use a linear support vector machine to generate planes. We train it on randomly selected and randomly labeled points from the data to be hashed.
More Details...
#include <dlib/lsh.h>
[top]

create_random_projection_hash

Creates a random projection based locality sensitive hashing function. The projection matrix is generated by sampling its elements from a Gaussian random number generator.
More Details...
#include <dlib/lsh.h>
[top]

disjoint_subsets

This object represents a set of integers which is partitioned into a number of disjoint subsets. It supports the two fundamental operations of finding which subset a particular integer belongs to as well as merging subsets.
More Details...
#include <dlib/disjoint_subsets.h>
[top]

gate

This object represents a quantum gate that operates on a quantum_register.

C++ Example Programs: quantum_computing_ex.cpp
More Details...
#include <dlib/quantum_computing.h>
[top]

gaussian_random_hash

This function uses hashing to generate Gaussian distributed random values with mean 0 and variance 1.
More Details...
#include <dlib/hash.h>
[top]

hamming_distance

This function returns the hamming distance between two unsigned integers. That is, it returns the number of bits which differer in the two integers.
More Details...
#include <dlib/hash.h>
[top]

hash

This is a set of convenience functions for invoking murmur_hash3 on std::strings, std::vectors, std::maps, or dlib::matrix objects.

As an aside, the hash() for matrix objects is defined here. It has the same interface as all the others.

More Details...
#include <dlib/hash.h>
[top]

hash_samples

This is a simple function for hashing a bunch of vectors using a locality sensitive hashing object such as hash_similar_angles_128. It is also capable of running in parallel on a multi-core CPU.
More Details...
#include <dlib/graph_utils_threaded.h>
[top]

hash_similar_angles_128

This object is a tool for computing locality sensitive hashes that give vectors with small angles between each other similar hash values. In particular, this object creates 128 random planes which pass though the origin and uses them to create a 128bit hash.
More Details...
#include <dlib/lsh.h>
[top]

hash_similar_angles_256

This object is a tool for computing locality sensitive hashes that give vectors with small angles between each other similar hash values. In particular, this object creates 256 random planes which pass though the origin and uses them to create a 256bit hash.
More Details...
#include <dlib/lsh.h>
[top]

hash_similar_angles_512

This object is a tool for computing locality sensitive hashes that give vectors with small angles between each other similar hash values. In particular, this object creates 512 random planes which pass though the origin and uses them to create a 512bit hash.
More Details...
#include <dlib/lsh.h>
[top]

hash_similar_angles_64

This object is a tool for computing locality sensitive hashes that give vectors with small angles between each other similar hash values. In particular, this object creates 64 random planes which pass though the origin and uses them to create a 64bit hash.
More Details...
#include <dlib/lsh.h>
[top]

hsort_array

hsort_array is an implementation of the heapsort algorithm. It will sort anything that has an array like operator[] interface.
More Details...
#include <dlib/sort.h>
[top]

integrate_function_adapt_simp

Computes an approximation of the integral of a real valued function using the adaptive Simpson method outlined in
Gander, W. and W. Gautshi, "Adaptive Quadrature -- Revisited" BIT, Vol. 40, (2000), pp.84-101

C++ Example Programs: integrate_function_adapt_simp_ex.cpp
More Details...
#include <dlib/numerical_integration.h>
[top]

isort_array

isort_array is an implementation of the insertion sort algorithm. It will sort anything that has an array like operator[] interface.
More Details...
#include <dlib/sort.h>
[top]

kalman_filter

This object implements the Kalman filter, which is a tool for recursively estimating the state of a process given measurements related to that process. To use this tool you will have to be familiar with the workings of the Kalman filter. An excellent introduction can be found in the paper:
An Introduction to the Kalman Filter by Greg Welch and Gary Bishop

More Details...
#include <dlib/filtering.h>
[top]

md5

This is an implementation of The MD5 Message-Digest Algorithm as described in rfc1321.
More Details...
#include <dlib/md5.h>
[top]

mean_sign_agreement

This is a function for computing the probability that matching elements of two std::vectors have the same sign.
More Details...
#include <dlib/statistics.h>
[top]

mean_squared_error

This is a function for computing the mean squared error between matching elements of two std::vectors.
More Details...
#include <dlib/statistics.h>
[top]

median

This function takes three parameters and finds the median of the three. The median is swapped into the first parameter and the first parameter ends up in one of the other two, unless the first parameter was the median to begin with of course.
More Details...
#include <dlib/algs.h>
[top]

murmur_hash3

This function takes a block of memory and returns a 32bit hash. The hashing algorithm used is Austin Appleby's excellent MurmurHash3.
More Details...
#include <dlib/hash.h>
[top]

murmur_hash3_128bit

This function takes a block of memory and returns a 128bit hash. The hashing algorithm used is Austin Appleby's excellent MurmurHash3.
More Details...
#include <dlib/hash.h>
[top]

numeric_constants

This is just a header file containing definitions of common numeric constants such as pi and e.
More Details...
#include <dlib/numeric_constants.h>
[top]

projection_hash

This is a tool for hashing elements of a vector space into the integers. It is intended to represent locality sensitive hashing functions such as the popular random projection hashing method.
More Details...
#include <dlib/lsh.h>
[top]

put_in_range

This is a simple function that takes a range and a value and returns the given value if it is within the range. If it isn't in the range then it returns the end of range value that is closest.
More Details...
#include <dlib/algs.h>
[top]

qsort_array

qsort_array is an implementation of the QuickSort algorithm. It will sort anything that has an array like operator[] interface. If the quick sort becomes unstable then it switches to a heap sort. This way sorting is guaranteed to take at most N*log(N) time.
More Details...
#include <dlib/sort.h>
[top]

quantum_register

This object represents a set of quantum bits. It can be used with the quantum gate object to simulate quantum algorithms.

C++ Example Programs: quantum_computing_ex.cpp
More Details...
#include <dlib/quantum_computing.h>
[top]

rand

This object represents a pseudorandom number generator.
More Details...
#include <dlib/rand.h>
[top]

randomly_subsample

This is a set of convenience functions for creating random subsets of data.
More Details...
#include <dlib/statistics.h>
[top]

random_subset_selector

This object is a tool to help you select a random subset of a large body of data. In particular, it is useful when the body of data is too large to fit into memory.
More Details...
#include <dlib/statistics.h>
[top]

rls_filter

This object is a tool for doing time series prediction using linear recursive least squares. In particular, this object takes a sequence of points from the user and, at each step, attempts to predict the value of the next point.
More Details...
#include <dlib/filtering.h>
[top]

running_covariance

This object is a simple tool for computing the mean and covariance of a sequence of vectors.
More Details...
#include <dlib/statistics.h>
[top]

running_cross_covariance

This object is a simple tool for computing the mean and cross-covariance matrices of a sequence of pairs of vectors.
More Details...
#include <dlib/statistics.h>
[top]

running_scalar_covariance

This object is a simple tool for computing the covariance of a sequence of scalar values.
More Details...
#include <dlib/statistics.h>
[top]

running_stats

This object represents something that can compute the running mean, variance, skewness, and kurtosis statistics of a stream of real numbers.

C++ Example Programs: running_stats_ex.cpp, kcentroid_ex.cpp
More Details...
#include <dlib/statistics.h>
[top]

r_squared

This is a function for computing the R squared coefficient between matching elements of two std::vectors.
More Details...
#include <dlib/statistics.h>
[top]

set_difference

This function takes two set objects and gives you their difference.
More Details...
#include <dlib/set_utils.h>
[top]

set_intersection

This function takes two set objects and gives you their intersection.
More Details...
#include <dlib/set_utils.h>
[top]

set_intersection_size

This function takes two set objects and tells you how many items they have in common.
More Details...
#include <dlib/set_utils.h>
[top]

set_union

This function takes two set objects and gives you their union.
More Details...
#include <dlib/set_utils.h>
[top]

split_array

This function is used to efficiently split array like objects into two parts. It uses the global swap() function instead of copying to move elements around, so it works on arrays of non-copyable types.
More Details...
#include <dlib/array.h>
[top]

square_root

square_root is a function which takes an unsigned long and returns the square root of it or if the root is not an integer then it is rounded up to the next integer.
More Details...
#include <dlib/algs.h>
[top]

uniform_random_hash

This function uses hashing to generate uniform random values in the range [0,1).
More Details...
#include <dlib/hash.h>


dlib C++ Library - bigint_kernel_abstract.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_BIGINT_KERNEl_ABSTRACT_
#ifdef DLIB_BIGINT_KERNEl_ABSTRACT_

#include <iosfwd>
#include "../algs.h"
#include "../serialize.h"
#include "../uintn.h"

namespace dlib
{
    using namespace dlib::relational_operators; // defined in algs.h

    class bigint
    {
        /*!
            INITIAL VALUE
                *this == 0

            WHAT THIS OBJECT REPRESENTS
                This object represents an arbitrary precision unsigned integer

                the following operators are supported:
                operator +
                operator +=
                operator -
                operator -=
                operator *
                operator *=
                operator /
                operator /=
                operator %
                operator %=
                operator ==
                operator <
                operator =
                operator << (for writing to ostreams)
                operator >> (for reading from istreams)
                operator++       // pre increment
                operator++(int)  // post increment
                operator--       // pre decrement
                operator--(int)  // post decrement

                the other comparason operators(>, !=, <=, and >=) are
                available and come from the templates in dlib::relational_operators

            THREAD SAFETY
                bigint may be reference counted so it is very unthread safe.
                use with care in a multithreaded program

        !*/

    public:

        bigint (
        );
        /*!
            ensures
                - #*this is properly initialized
            throws
                - std::bad_alloc
                    if this is thrown the bigint will be unusable but
                    will not leak memory
        !*/

        bigint (
            uint32 value
        );
        /*!
            requires
                - value <= (2^32)-1
            ensures
                - #*this is properly initialized
                - #*this == value
            throws
                - std::bad_alloc
                    if this is thrown the bigint will be unusable but
                    will not leak memory
        !*/

        bigint (
            const bigint& item
        );
        /*!
            ensures
                - #*this is properly initialized
                - #*this == value
            throws
                - std::bad_alloc
                    if this is thrown the bigint will be unusable but
                    will not leak memory
        !*/

        virtual ~bigint (
        );
        /*!
            ensures
                - all resources associated with #*this have been released
        !*/

        const bigint operator+ (
            const bigint& rhs
        ) const;
        /*!
            ensures
                - returns the result of adding rhs to *this
            throws
                - std::bad_alloc
                    if this function throws then it has no effect
        !*/

        bigint& operator+= (
            const bigint& rhs
        );
        /*!
            ensures
                - #*this == *this + rhs
                - returns #*this
            throws
                - std::bad_alloc
                    if this function throws then it has no effect
        !*/

        const bigint operator- (
            const bigint& rhs
        ) const;
        /*!
            requires
                - *this >= rhs
            ensures
                - returns the result of subtracting rhs from *this
            throws
                - std::bad_alloc
                    if this function throws then it has no effect
        !*/

        bigint& operator-= (
            const bigint& rhs
        );
        /*!
            requires
                - *this >= rhs
            ensures
                - #*this == *this - rhs
                - returns #*this
            throws
                - std::bad_alloc
                    if this function throws then it has no effect
        !*/

        const bigint operator* (
            const bigint& rhs
        ) const;
        /*!
            ensures
                - returns the result of multiplying *this and rhs
            throws
                - std::bad_alloc
                    if this function throws then it has no effect
        !*/

        bigint& operator*= (
            const bigint& rhs
        );
        /*!
            ensures
                - #*this == *this * rhs
                - returns #*this
            throws
                - std::bad_alloc
                    if this function throws then it has no effect
        !*/

        const bigint operator/ (
            const bigint& rhs
        ) const;
        /*!
            requires
                - rhs != 0
            ensures
                - returns the result of dividing *this by rhs
            throws
                - std::bad_alloc
                    if this function throws then it has no effect
        !*/

        bigint& operator/= (
            const bigint& rhs
        );
        /*!
            requires
                - rhs != 0
            ensures
                - #*this == *this / rhs
                - returns #*this
            throws
                - std::bad_alloc
                    if this function throws then it has no effect
        !*/

        const bigint operator% (
            const bigint& rhs
        ) const;
        /*!
            requires
                - rhs != 0
            ensures
                - returns the result of *this mod rhs
            throws
                - std::bad_alloc
                    if this function throws then it has no effect
        !*/

        bigint& operator%= (
            const bigint& rhs
        );
        /*!
            requires
                - rhs != 0
            ensures
                - #*this == *this % rhs
                - returns #*this
            throws
                - std::bad_alloc
                    if this function throws then it has no effect
        !*/

        bool operator < (
            const bigint& rhs
        ) const;
        /*!
            ensures
                - returns true if *this is less than rhs
                - returns false otherwise
        !*/

        bool operator == (
            const bigint& rhs
        ) const;
        /*!
            ensures
                - returns true if *this and rhs represent the same number
                - returns false otherwise
        !*/

        bigint& operator= (
            const bigint& rhs
        );
        /*!
            ensures
                - #*this == rhs
            throws
                - std::bad_alloc
                    if this function throws then it has no effect
        !*/

        friend std::ostream& operator<< (
            std::ostream& out,
            const bigint& rhs
        );
        /*!
            ensures
                - the number in *this has been written to #out as a base ten number
            throws
                - std::bad_alloc
                    if this function throws then it has no effect (nothing
                    is written to out)
        !*/

        friend std::istream& operator>> (
            std::istream& in,
            bigint& rhs
        );
        /*!
            ensures
                - reads a number from in and puts it into #*this
                - if (there is no positive base ten number on the input stream ) then
                    - #in.fail() == true
            throws
                - std::bad_alloc
                    if this function throws the value in rhs is undefined and some
                    characters may have been read from in.  rhs is still usable though,
                    its value is just unknown.
        !*/

        bigint& operator++ (
        );
        /*!
            ensures
                - #*this == *this + 1
                - returns #*this
            throws
                - std::bad_alloc
                    if this function throws then it has no effect
        !*/

        const bigint operator++ (
            int
        );
        /*!
            ensures
                - #*this == *this + 1
                - returns *this
            throws
                - std::bad_alloc
                    if this function throws then it has no effect
        !*/

        bigint& operator-- (
        );
        /*!
            requires
                - *this != 0
            ensures
                - #*this == *this - 1
                - returns #*this
            throws
                - std::bad_alloc
                    if this function throws then it has no effect
        !*/

        const bigint operator-- (
            int
        );
        /*!
            requires
                - *this != 0
            ensures
                - #*this == *this - 1
                - returns *this
            throws
                - std::bad_alloc
                    if this function throws then it has no effect
        !*/

        void swap (
            bigint& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/

        // ------------------------------------------------------------------
        // ----    The following functions are identical to the above   -----
        // ----  but take uint16 as one of their arguments. They  ---
        // ----  exist only to allow for a more efficient implementation  ---
        // ------------------------------------------------------------------

        friend const bigint operator+ (
            uint16 lhs,
            const bigint& rhs
        );
        /*!
            requires
                - lhs <= 65535
            ensures
                - returns the result of adding rhs to lhs
            throws
                - std::bad_alloc
                    if this function throws then it has no effect
        !*/

        friend const bigint operator+ (
            const bigint& lhs,
            uint16 rhs
        );
        /*!
            requires
                - rhs <= 65535
            ensures
                - returns the result of adding rhs to lhs
            throws
                - std::bad_alloc
                    if this function throws then it has no effect
        !*/

        bigint& operator+= (
            uint16 rhs
        );
        /*!
            requires
                - rhs <= 65535
            ensures
                - #*this == *this + rhs
                - returns #this
            throws
                - std::bad_alloc
                    if this function throws then it has no effect
        !*/

        friend const bigint operator- (
            uint16 lhs,
            const bigint& rhs
        );
        /*!
            requires
                - lhs >= rhs
                - lhs <= 65535
            ensures
                - returns the result of subtracting rhs from lhs
            throws
                - std::bad_alloc
                    if this function throws then it has no effect
        !*/

        friend const bigint operator- (
            const bigint& lhs,
            uint16 rhs
        );
        /*!
            requires
                - lhs >= rhs
                - rhs <= 65535
            ensures
                - returns the result of subtracting rhs from lhs
            throws
                - std::bad_alloc
                    if this function throws then it has no effect
        !*/

        bigint& operator-= (
            uint16 rhs
        );
        /*!
            requires
                - *this >= rhs
                - rhs <= 65535
            ensures
                - #*this == *this - rhs
                - returns #*this
            throws
                - std::bad_alloc
                    if this function throws then it has no effect
        !*/

        friend const bigint operator* (
            uint16 lhs,
            const bigint& rhs
        );
        /*!
            requires
                - lhs <= 65535
            ensures
                - returns the result of multiplying lhs and rhs
            throws
                - std::bad_alloc
                    if this function throws then it has no effect
        !*/

        friend const bigint operator* (
            const bigint& lhs,
            uint16 rhs
        );
        /*!
            requires
                - rhs <= 65535
            ensures
                - returns the result of multiplying lhs and rhs
            throws
                - std::bad_alloc
                    if this function throws then it has no effect
        !*/

        bigint& operator*= (
            uint16 rhs
        );
        /*!
            requires
                - rhs <= 65535
            ensures
                - #*this == *this * rhs
                - returns #*this
            throws
                - std::bad_alloc
                    if this function throws then it has no effect
        !*/

        friend const bigint operator/ (
            uint16 lhs,
            const bigint& rhs
        );
        /*!
            requires
                - rhs != 0
                - lhs <= 65535
            ensures
                - returns the result of dividing lhs by rhs
            throws
                - std::bad_alloc
                    if this function throws then it has no effect
        !*/

        friend const bigint operator/ (
            const bigint& lhs,
            uint16 rhs
        );
        /*!
            requires
                - rhs != 0
                - rhs <= 65535
            ensures
                - returns the result of dividing lhs by rhs
            throws
                - std::bad_alloc
                    if this function throws then it has no effect
        !*/

        bigint& operator/= (
            uint16 rhs
        );
        /*!
            requires
                - rhs != 0
                - rhs <= 65535
            ensures
                - #*this == *this / rhs
                - returns #*this
            throws
                - std::bad_alloc
                    if this function throws then it has no effect
        !*/

        friend const bigint operator% (
            uint16 lhs,
            const bigint& rhs
        );
        /*!
            requires
                - rhs != 0
                - lhs <= 65535
            ensures
                - returns the result of lhs mod rhs
            throws
                - std::bad_alloc
                    if this function throws then it has no effect
        !*/

        friend const bigint operator% (
            const bigint& lhs,
            uint16 rhs
        );
        /*!
            requires
                - rhs != 0
                - rhs <= 65535
            ensures
                - returns the result of lhs mod rhs
            throws
                - std::bad_alloc
                    if this function throws then it has no effect
        !*/

        bigint& operator%= (
            uint16 rhs
        );
        /*!
            requires
                - rhs != 0
                - rhs <= 65535
            ensures
                - #*this == *this % rhs
                - returns #*this
            throws
                - std::bad_alloc
                    if this function throws then it has no effect
        !*/

        friend bool operator < (
            uint16 lhs,
            const bigint& rhs
        );
        /*!
            requires
                - lhs <= 65535
            ensures
                - returns true if lhs is less than rhs
                - returns false otherwise
        !*/

        friend bool operator < (
            const bigint& lhs,
            uint16 rhs
        );
        /*!
            requires
                - rhs <= 65535
            ensures
                - returns true if lhs is less than rhs
                - returns false otherwise
        !*/

        friend bool operator == (
            const bigint& lhs,
            uint16 rhs
        );
        /*!
            requires
                - rhs <= 65535
            ensures
                - returns true if lhs and rhs represent the same number
                - returns false otherwise
        !*/

        friend bool operator == (
            uint16 lhs,
            const bigint& rhs
        );
        /*!
            requires
                - lhs <= 65535
            ensures
                - returns true if lhs and rhs represent the same number
                - returns false otherwise
        !*/

        bigint& operator= (
            uint16 rhs
        );
        /*!
            requires
                - rhs <= 65535
            ensures
                - #*this == rhs
                - returns #*this
            throws
                - std::bad_alloc
                    if this function throws then it has no effect
        !*/

    };

    inline void swap (
        bigint& a,
        bigint& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

    void serialize (
        const bigint& item,
        std::istream& in
    );
    /*!
        provides serialization support
    !*/

    void deserialize (
        bigint& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

}

#endif // DLIB_BIGINT_KERNEl_ABSTRACT_


dlib C++ Library - disjoint_subsets_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_DISJOINT_SUBsETS_ABSTRACT_Hh_
#ifdef DLIB_DISJOINT_SUBsETS_ABSTRACT_Hh_

#include <vector>
#include "../algs.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class disjoint_subsets
    {
        /*!
            INITIAL VALUE
                - size() == 0

            WHAT THIS OBJECT REPRESENTS
                This object represents a set of integers which is partitioned into
                a number of disjoint subsets.  It supports the two fundamental operations
                of finding which subset a particular integer belongs to as well as
                merging subsets.
        !*/
    public:

        void clear (
        );
        /*!
            ensures
                - #size() == 0
                - returns this object to its initial value
        !*/

        void set_size (
            unsigned long new_size
        );
        /*!
            ensures
                - #size() == new_size
                - for all valid i:
                    - #find_set(i) == i
                      (i.e. this object contains new_size subsets, each containing exactly one element)
        !*/

        unsigned long size (
        ) const;
        /*!
            ensures
                - returns the total number of integer elements represented
                  by this object.
        !*/

        unsigned long find_set (
            unsigned long item
        ) const;
        /*!
            requires
                - item < size()
            ensures
                - Each disjoint subset can be represented by any of its elements (since
                  the sets are all disjoint).  In particular, for each subset we define
                  a special "representative element" which is used to represent it.
                  Therefore, this function returns the representative element for the
                  set which contains item.
                - find_set(find_set(item)) == find_set(item)
                - Note that if A and B are both elements of the same subset then we always
                  have find_set(A) == find_set(B).
        !*/

        unsigned long merge_sets (
            unsigned long a,
            unsigned long b
        );
        /*!
            requires
                - a != b
                - a < size()
                - b < size()
                - find_set(a) == a
                  (i.e. a is the representative element of some set)
                - find_set(b) == b
                  (i.e. b is the representative element of some set)
            ensures
                - #find_set(a) == #find_set(b)
                  (i.e. merges the set's containing a and b)
                - returns #find_set(a)
        !*/

    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_DISJOINT_SUBsETS_ABSTRACT_Hh_


dlib C++ Library - sort.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SORt_
#define DLIB_SORt_

#include "algs.h"
#include <functional>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename compare
        >
    inline void qsort_array (
        T& array,
        unsigned long left,
        unsigned long right,
        const compare& comp
    );
    /*!
        requires
            - T implements operator[]
            - the items in array must be comparable by comp where comp is a function
              object with the same syntax as std::less<>
            - the items in array must be swappable by a global swap()
            - left and right are within the bounds of array
              i.e. array[left] and array[right] are valid elements
            - left <= right
        ensures
            - for all elements in #array between and including left and right the
              ith element is < the i+1 element
            - sorts using a quick sort algorithm
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename compare
        >
    void hsort_array (
        T& array,
        unsigned long left,
        unsigned long right,
        const compare& comp
    );
    /*!
        requires
            - T implements operator[]
            - the items in array must be comparable by comp where comp is a function
              object with the same syntax as std::less<>
            - the items in array must be swappable by a global swap()
            - left and right are within the bounds of array
              i.e. array[left] and array[right] are valid elements
            - left <= right
        ensures
            - for all elements in #array between and including left and right the
              ith element is < the i+1 element
            - sorts using a heapsort algorithm
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename compare
        >
    void isort_array (
        T& array,
        unsigned long left,
        unsigned long right,
        const compare& comp
    );
    /*!
        requires
            - T implements operator[]
            - the items in array must be comparable by comp where comp is a function
              object with the same syntax as std::less<>
            - the items in array must be swappable by a global swap()
            - left and right are within the bounds of array
              i.e. array[left] and array[right] are valid elements
            - left <= right
        ensures
            - for all elements in #array between and including left and right the
              ith element is < the i+1 element
            - sorts using an insertion sort algorithm
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    inline void qsort_array (
        T& array,
        unsigned long left,
        unsigned long right
    );
    /*!
        requires
            - T implements operator[]
            - the items in array must be comparable by std::less
            - the items in array must be swappable by a global swap()
            - left and right are within the bounds of array
              i.e. array[left] and array[right] are valid elements
            - left <= right
        ensures
            - for all elements in #array between and including left and right the
              ith element is < the i+1 element
            - sorts using a quick sort algorithm
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    void hsort_array (
        T& array,
        unsigned long left,
        unsigned long right
    );
    /*!
        requires
            - T implements operator[]
            - the items in array must be comparable by std::less
            - the items in array must be swappable by a global swap()
            - left and right are within the bounds of array
              i.e. array[left] and array[right] are valid elements
            - left <= right
        ensures
            - for all elements in #array between and including left and right the
              ith element is < the i+1 element
            - sorts using a heapsort algorithm
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    void isort_array (
        T& array,
        unsigned long left,
        unsigned long right
    );
    /*!
        requires
            - T implements operator[]
            - the items in array must be comparable by std::less
            - the items in array must be swappable by a global swap()
            - left and right are within the bounds of array
              i.e. array[left] and array[right] are valid elements
            - left <= right
        ensures
            - for all elements in #array between and including left and right the
              ith element is < the i+1 element
            - sorts using an insertion sort algorithm
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                            IMPLEMENTATION DETAILS
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    namespace sort_helpers
    {
        template <typename T>
        inline const std::less<T> comp (const T&)
        {
            return std::less<T>();
        }

        template <
            typename T,
            typename Y,
            typename compare
            >
        inline unsigned long qsort_partition (
            T& array,
            Y& pivot,
            const unsigned long left,
            const unsigned long right,
            const compare& comp
        )
        /*!
            requires
                - &pivot == &array[right]
                - T implements operator[]
                - the items in array must be comparable by comp
                - left and right are within the bounts of the array
                - left < right
            ensures
                - returns a number called partition_element such that:
                    - left <= partition_element <= right
                    - all elements in #array < #array[partition_element] have
                    indices >= left and < partition_element
                    - all elements in #array > #array[partition_element] have
                    indices > partition_element and <= right
        !*/
        {
            DLIB_ASSERT (&pivot == &array[right] && left < right,
                    "\tunsigned long qsort_partition()"
                    << "\n\t&pivot:        " << &pivot
                    << "\n\t&array[right]: " << &array[right]
                    << "\n\tleft:          " << left
                    << "\n\tright:         " << right );

            exchange(array[(right-left)/2 +left],pivot);

            unsigned long i = left;
            for (unsigned long j = left; j < right; ++j)
            {
                if (comp(array[j] , pivot))
                {
                    swap(array[i],array[j]);
                    ++i;
                }
            }
            exchange(array[i],pivot);

            return i;
        }

// ----------------------------------------------------------------------------------------

        template <
            typename T,
            typename compare
            >
        void qsort_array_main (
            T& array,
            const unsigned long left,
            const unsigned long right,
            unsigned long depth_check,
            const compare& comp
        )
        /*!
            requires
                - T implements operator[]
                - the items in array must be comparable by comp
                - the items in array must be swappable by a global swap()
                - left and right are within the bounds of array
                  i.e. array[left] and array[right] are valid elements
            ensures
                - for all elements in #array between and including left and right the
                  ith element is < the i+1 element
                - will only recurse about as deep as log(depth_check) calls
                - sorts using a quick sort algorithm
        !*/
        {
            if ( left < right)
            {
                if (right-left < 30 || depth_check == 0)
                {
                    hsort_array(array,left,right,comp);
                }
                else
                {
                    // The idea here is to only let quick sort go about log(N)
                    // calls deep before it kicks into something else.
                    depth_check >>= 1;
                    depth_check += (depth_check>>4);

                    unsigned long partition_element =
                        qsort_partition(array,array[right],left,right,comp);

                    if (partition_element > 0)
                        qsort_array_main(array,left,partition_element-1,depth_check,comp);
                    qsort_array_main(array,partition_element+1,right,depth_check,comp);
                }
            }
        }

// ----------------------------------------------------------------------------------------

        template <
            typename T,
            typename compare
            >
        void heapify (
            T& array,
            const unsigned long start,
            const unsigned long end,
            unsigned long i,
            const compare& comp
        )
        /*!
            requires
                - T implements operator[]
                - the items in array must be comparable by comp
                - the items in array must be swappable by a global swap()
                - start, end, and i are within the bounds of array
                  i.e. array[start], array[end], and array[i] are valid elements
                - start <= i <= end
                - array[i/2] is a max heap
                - array[i/2+1] is a max heap
                - start and end specify the range of the array we are working with.
            ensures
                - array[i] is now a max heap
        !*/
        {
            DLIB_ASSERT (start <= i && i <= end,
                    "\tvoid heapify()"
                    << "\n\tstart:   " << start
                    << "\n\tend:     " << end
                    << "\n\ti:       " << i );

            bool keep_going = true;
            unsigned long left;
            unsigned long right;
            unsigned long largest;
            while (keep_going)
            {
                keep_going = false;
                left = (i<<1)+1-start;
                right = left+1;

                if (left <= end && comp(array[i] , array[left]))
                    largest = left;
                else
                    largest = i;

                if (right <= end && comp(array[largest] , array[right]))
                    largest = right;

                if (largest != i)
                {
                    exchange(array[i],array[largest]);
                    i = largest;
                    keep_going = true;
                }
            }
        }

// ----------------------------------------------------------------------------------------
    }
// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    inline void qsort_array (
        T& array,
        unsigned long left,
        unsigned long right
    )
    {
        using namespace sort_helpers;
        qsort_array(array,left,right,comp(array[left]));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    void hsort_array (
        T& array,
        unsigned long left,
        unsigned long right
    )
    {
        using namespace sort_helpers;
        hsort_array(array,left,right,comp(array[left]));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    void isort_array (
        T& array,
        unsigned long left,
        unsigned long right
    )
    {
        using namespace sort_helpers;
        isort_array(array,left,right,comp(array[left]));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename compare
        >
    void isort_array (
        T& array,
        const unsigned long left,
        const unsigned long right,
        const compare& comp
    )
    {
        DLIB_ASSERT (left <= right,
                "\tvoid isort_array()"
                << "\n\tleft:          " << left
                << "\n\tright:         " << right );
        using namespace sort_helpers;

        unsigned long pos;
        for (unsigned long i = left+1; i <= right; ++i)
        {
            // everything from left to i-1 is sorted.
            pos = i;
            for (unsigned long j = i-1; comp(array[pos] , array[j]); --j)
            {
                exchange(array[pos],array[j]);
                pos = j;

                if (j == left)
                    break;
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename compare
        >
    void qsort_array (
        T& array,
        const unsigned long left,
        const unsigned long right,
        const compare& comp
    )
    {
        DLIB_ASSERT (left <= right,
                "\tvoid qsort_array()"
                << "\n\tleft:          " << left
                << "\n\tright:         " << right );

        sort_helpers::qsort_array_main(array,left,right,right-left,comp);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename compare
        >
    void hsort_array (
        T& array,
        const unsigned long left,
        const unsigned long right,
        const compare& comp
    )
    {
        DLIB_ASSERT (left <= right,
                "\tvoid hsort_array()"
                << "\n\tleft:          " << left
                << "\n\tright:         " << right );

        if (right-left < 30)
        {
            isort_array(array,left,right,comp);
            return;
        }

        // turn array into a max heap
        for (unsigned long i = left+((right-left)>>1);; --i)
        {
            sort_helpers::heapify(array,left,right,i,comp);
            if (i == left)
                break;
        }

        // now sort the array
        for (unsigned long i = right; i > left;)
        {
            exchange(array[i],array[left]);
            sort_helpers::heapify(array,left,--i,left,comp);
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SORt_


dlib C++ Library - integrate_function_adapt_simpson_abstract.h

// Copyright (C) 2013 Steve Taylor (steve98654@gmail.com)
// License: Boost Software License  See LICENSE.txt for the full license.
#undef DLIB_INTEGRATE_FUNCTION_ADAPT_SIMPSON_ABSTRACTh_
#ifdef DLIB_INTEGRATE_FUNCTION_ADAPT_SIMPSON_ABSTRACTh_

namespace dlib
{

    template <typename T, typename funct>
    T integrate_function_adapt_simp(
        const funct& f,
        T a,
        T b,
        T tol = 1e-10
    );
    /*!
        requires
            - b > a
            - tol > 0
            - T should be either float, double, or long double
            - The expression f(a) should be a valid expression that evaluates to a T.
              I.e. f() should be a real valued function of a single variable.
        ensures
            - returns an approximation of the integral of f over the domain [a,b] using the
              adaptive Simpson method outlined in Gander, W. and W. Gautshi, "Adaptive
              Quadrature -- Revisited" BIT, Vol. 40, (2000), pp.84-101
            - tol is a tolerance parameter that determines the overall accuracy of
              approximated integral.  We suggest a default value of 1e-10 for tol.
    !*/

}

#endif // DLIB_INTEGRATE_FUNCTION_ADAPT_SIMPSON_ABSTRACTh_


dlib C++ Library - numeric_constants.h

//Copyright (C) 2013 Steve Taylor (steve98654@gmail.com), Davis E. King
//License: Boost Software License.  See LICENSE.txt for full license.
#ifndef DLIB_NUMERIC_CONSTANTs_H_
#define DLIB_NUMERIC_CONSTANTs_H_

namespace dlib
{

    // pi -- Pi
    const double pi = 3.1415926535897932385;

    // e  -- Euler's Constant
    const double e = 2.7182818284590452354;

    // sqrt_2 -- The square root of 2
    const double sqrt_2 = 1.4142135623730950488;

    // sqrt_3 -- The square root of 3
    const double sqrt_3 = 1.7320508075688772935;

    // log10_2 -- The logarithm base 10 of two
    const double log10_2 = 0.30102999566398119521;

    // light_spd -- The speed of light in vacuum in meters per second
    const double light_spd = 2.99792458e8;

    // newton_G  -- Newton's gravitational constant (in metric units of m^3/(kg*s^2))
    const double newton_G = 6.67384e-11;

    // planck_cst -- Planck's constant (in units of Joules * seconds)
    const double planck_cst = 6.62606957e-34;

    // golden_ratio -- The Golden Ratio
    const double golden_ratio = 1.6180339887498948482;

    // euler_gamma -- The Euler Mascheroni Constant
    const double euler_gamma = 0.5772156649015328606065;

    // catalan -- Catalan's Constant
    const double catalan = 0.91596559417721901505;

    // glaisher -- Glaisher Kinkelin constant
    const double glaisher = 1.2824271291006226369;

    // khinchin -- Khinchin's constant
    const double khinchin = 2.6854520010653064453;

    // apery -- Apery's constant
    const double apery = 1.2020569031595942854;
}

#endif //DLIB_NUMERIC_CONSTANTs_H_


dlib C++ Library - algs.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ALGs_
#define DLIB_ALGs_

// this file contains miscellaneous stuff

#ifdef _MSC_VER
// Disable the following warnings for Visual Studio

// this is to disable the "'this' : used in base member initializer list"
// warning you get from some of the GUI objects since all the objects
// require that their parent class be passed into their constructor.
// In this case though it is totally safe so it is ok to disable this warning.
#pragma warning(disable : 4355)

// This is a warning you get sometimes when Visual Studio performs a Koenig Lookup.
// This is a bug in visual studio.  It is a totally legitimate thing to
// expect from a compiler.
#pragma warning(disable : 4675)

// This is a warning you get from visual studio 2005 about things in the standard C++
// library being "deprecated."  I checked the C++ standard and it doesn't say jack
// about any of them (I checked the searchable PDF).   So this warning is total Bunk.
#pragma warning(disable : 4996)

// This is a warning you get from visual studio 2003:
//    warning C4345: behavior change: an object of POD type constructed with an initializer
//    of the form () will be default-initialized.
// I love it when this compiler gives warnings about bugs in previous versions of itself.
#pragma warning(disable : 4345)

// Disable warnings about conversion from size_t to unsigned long and long.
#pragma warning(disable : 4267)

// Disable warnings about conversion from double to float
#pragma warning(disable : 4244)
#pragma warning(disable : 4305)

// Disable "warning C4180: qualifier applied to function type has no meaning; ignored".
// This warning happens often in generic code that works with functions and isn't useful.
#pragma warning(disable : 4180)

// Disable "warning C4290: C++ exception specification ignored except to indicate a function is not __declspec(nothrow)"
#pragma warning(disable : 4290)

#endif

#ifdef __BORLANDC__
// Disable the following warnings for the Borland Compilers
//
// These warnings just say that the compiler is refusing to inline functions with
// loops or try blocks in them.
//
#pragma option -w-8027
#pragma option -w-8026
#endif

#include <string>       // for the exceptions

#ifdef __CYGWIN__
namespace std
{
   typedef std::basic_string<wchar_t> wstring;
}
#endif

#include "platform.h"
#include "windows_magic.h"

#include <algorithm>    // for std::swap
#include <new>          // for std::bad_alloc
#include <cstdlib>
#include <limits> // for std::numeric_limits for is_finite()
#include "assert.h"
#include "error.h"
#include "noncopyable.h"
#include "enable_if.h"
#include "uintn.h"
#include "numeric_constants.h"
#include "memory_manager_stateless/memory_manager_stateless_kernel_1.h" // for the default memory manager

// ----------------------------------------------------------------------------------------
/*!A _dT !*/

template <typename charT>
inline charT _dTcast (const char a, const wchar_t b);
template <>
inline char _dTcast<char> (const char a, const wchar_t ) { return a; }
template <>
inline wchar_t _dTcast<wchar_t> (const char , const wchar_t b) { return b; }

template <typename charT>
inline const charT* _dTcast ( const char* a, const wchar_t* b);
template <>
inline const char* _dTcast<char> ( const char* a, const wchar_t* ) { return a; }
template <>
inline const wchar_t* _dTcast<wchar_t> ( const char* , const wchar_t* b) { return b; }

#define _dT(charT,str) _dTcast<charT>(str,L##str)
/*!
    requires
        - charT == char or wchar_t
        - str == a string or character literal
    ensures
        - returns the literal in the form of a charT type literal.
!*/

// ----------------------------------------------------------------------------------------

namespace dlib
{

// ----------------------------------------------------------------------------------------

    /*!A default_memory_manager

        This memory manager just calls new and delete directly.

    !*/
    typedef memory_manager_stateless_kernel_1<char> default_memory_manager;

// ----------------------------------------------------------------------------------------

    /*!A swap !*/
    // make swap available in the dlib namespace
    using std::swap;

// ----------------------------------------------------------------------------------------

    /*!
        Here is where I define my return codes.  It is
        important that they all be < 0.
    !*/

    enum general_return_codes
    {
        TIMEOUT     = -1,
        WOULDBLOCK  = -2,
        OTHER_ERROR = -3,
        SHUTDOWN    = -4,
        PORTINUSE   = -5
    };

// ----------------------------------------------------------------------------------------

    inline unsigned long square_root (
        unsigned long value
    )
    /*!
        requires
            - value <= 2^32 - 1
        ensures
            - returns the square root of value.  if the square root is not an
              integer then it will be rounded up to the nearest integer.
    !*/
    {
        unsigned long x;

        // set the initial guess for what the root is depending on
        // how big value is
        if (value < 3)
            return value;
        else if (value < 4096) // 12
            x = 45;
        else if (value < 65536) // 16
            x = 179;
        else if (value < 1048576) // 20
            x = 717;
        else if (value < 16777216) // 24
            x = 2867;
        else if (value < 268435456) // 28
            x = 11469;
        else   // 32
            x = 45875;

        // find the root
        x = (x + value/x)>>1;
        x = (x + value/x)>>1;
        x = (x + value/x)>>1;
        x = (x + value/x)>>1;

        if (x*x < value)
            return x+1;
        else
            return x;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    void median (
        T& one,
        T& two,
        T& three
    );
    /*!
        requires
            - T implements operator<
            - T is swappable by a global swap()
        ensures
            - #one is the median
            - #one, #two, and #three is some permutation of one, two, and three.
    !*/

    template <
        typename T
        >
    void median (
        T& one,
        T& two,
        T& three
    )
    {
        using std::swap;
        using dlib::swap;

        if ( one < two )
        {
            // one < two
            if ( two < three )
            {
                // one < two < three : two
                swap(one,two);

            }
            else
            {
                // one < two >= three
                if ( one < three)
                {
                    // three
                    swap(three,one);
                }
            }

        }
        else
        {
            // one >= two
            if ( three < one )
            {
                // three <= one >= two
                if ( three < two )
                {
                    // two
                    swap(two,one);
                }
                else
                {
                    // three
                    swap(three,one);
                }
            }
        }
    }

// ----------------------------------------------------------------------------------------

    namespace relational_operators
    {
        template <
            typename A,
            typename B
            >
        bool operator> (
            const A& a,
            const B& b
        ) { return b < a; }

    // ---------------------------------

        template <
            typename A,
            typename B
            >
        bool operator!= (
            const A& a,
            const B& b
        ) { return !(a == b); }

    // ---------------------------------

        template <
            typename A,
            typename B
            >
        bool operator<= (
            const A& a,
            const B& b
        ) { return !(b < a); }

    // ---------------------------------

        template <
            typename A,
            typename B
            >
        bool operator>= (
            const A& a,
            const B& b
        ) { return !(a < b); }

    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    void exchange (
        T& a,
        T& b
    )
    /*!
        This function does the exact same thing that global swap does and it does it by
        just calling swap.  But a lot of compilers have problems doing a Koenig Lookup
        and the fact that this has a different name (global swap has the same name as
        the member functions called swap) makes them compile right.

        So this is a workaround but not too ugly of one.  But hopefully I get get
        rid of this in a few years.  So this function is already deprecated.

        This also means you should NOT use this function in your own code unless
        you have to support an old buggy compiler that benefits from this hack.
    !*/
    {
        using std::swap;
        using dlib::swap;
        swap(a,b);
    }

// ----------------------------------------------------------------------------------------

    /*!A is_pointer_type

        This is a template where is_pointer_type<T>::value == true when T is a pointer
        type and false otherwise.
    !*/

    template <
        typename T
        >
    class is_pointer_type
    {
    public:
        enum { value = false };
    private:
        is_pointer_type();
    };

    template <
        typename T
        >
    class is_pointer_type<T*>
    {
    public:
        enum { value = true };
    private:
        is_pointer_type();
    };

// ----------------------------------------------------------------------------------------

    /*!A is_const_type

        This is a template where is_const_type<T>::value == true when T is a const
        type and false otherwise.
    !*/

    template <typename T>
    struct is_const_type
    {
        static const bool value = false;
    };
    template <typename T>
    struct is_const_type<const T>
    {
        static const bool value = true;
    };
    template <typename T>
    struct is_const_type<const T&>
    {
        static const bool value = true;
    };

// ----------------------------------------------------------------------------------------

    /*!A is_reference_type

        This is a template where is_reference_type<T>::value == true when T is a reference
        type and false otherwise.
    !*/

    template <typename T>
    struct is_reference_type
    {
        static const bool value = false;
    };

    template <typename T> struct is_reference_type<const T&> { static const bool value = true; };
    template <typename T> struct is_reference_type<T&> { static const bool value = true; };

// ----------------------------------------------------------------------------------------

    /*!A is_same_type

        This is a template where is_same_type<T,U>::value == true when T and U are the
        same type and false otherwise.
    !*/

    template <
        typename T,
        typename U
        >
    class is_same_type
    {
    public:
        enum {value = false};
    private:
        is_same_type();
    };

    template <typename T>
    class is_same_type<T,T>
    {
    public:
        enum {value = true};
    private:
        is_same_type();
    };

// ----------------------------------------------------------------------------------------

    /*!A is_float_type

        This is a template that can be used to determine if a type is one of the built
        int floating point types (i.e. float, double, or long double).
    !*/

    template < typename T > struct is_float_type  { const static bool value = false; };
    template <> struct is_float_type<float>       { const static bool value = true; };
    template <> struct is_float_type<double>      { const static bool value = true; };
    template <> struct is_float_type<long double> { const static bool value = true; };

// ----------------------------------------------------------------------------------------

    /*!A is_convertible

        This is a template that can be used to determine if one type is convertible
        into another type.

        For example:
            is_convertible<int,float>::value == true    // because ints are convertible to floats
            is_convertible<int*,float>::value == false  // because int pointers are NOT convertible to floats
    !*/

    template <typename from, typename to>
    struct is_convertible
    {
        struct yes_type { char a; };
        struct no_type { yes_type a[2]; };
        static const from& from_helper();
        static yes_type test(to);
        static no_type test(...);
        const static bool value = sizeof(test(from_helper())) == sizeof(yes_type);
    };

// ----------------------------------------------------------------------------------------

    /*!A is_same_object

        This is a templated function which checks if both of its arguments are actually
        references to the same object.  It returns true if they are and false otherwise.

    !*/

    // handle the case where T and U are unrelated types.
    template < typename T, typename U >
    typename disable_if_c<is_convertible<T*, U*>::value || is_convertible<U*,T*>::value, bool>::type
    is_same_object (
        const T& a,
        const U& b
    )
    {
        return ((void*)&a == (void*)&b);
    }

    // handle the case where T and U are related types because their pointers can be
    // implicitly converted into one or the other.  E.g. a derived class and its base class.
    // Or where both T and U are just the same type.  This way we make sure that if there is a
    // valid way to convert between these two pointer types then we will take that route rather
    // than the void* approach used otherwise.
    template < typename T, typename U >
    typename enable_if_c<is_convertible<T*, U*>::value || is_convertible<U*,T*>::value, bool>::type
    is_same_object (
        const T& a,
        const U& b
    )
    {
        return (&a == &b);
    }

// ----------------------------------------------------------------------------------------

    /*!A is_unsigned_type

        This is a template where is_unsigned_type<T>::value == true when T is an unsigned
        scalar type and false when T is a signed scalar type.
    !*/
    template <
        typename T
        >
    struct is_unsigned_type
    {
        static const bool value = static_cast<T>((static_cast<T>(0)-static_cast<T>(1))) > 0;
    };
    template <> struct is_unsigned_type<long double> { static const bool value = false; };
    template <> struct is_unsigned_type<double>      { static const bool value = false; };
    template <> struct is_unsigned_type<float>       { static const bool value = false; };

// ----------------------------------------------------------------------------------------

    /*!A is_signed_type

        This is a template where is_signed_type<T>::value == true when T is a signed
        scalar type and false when T is an unsigned scalar type.
    !*/
    template <
        typename T
        >
    struct is_signed_type
    {
        static const bool value = !is_unsigned_type<T>::value;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    class copy_functor
    {
    public:
        void operator() (
            const T& source,
            T& destination
        ) const
        {
            destination = source;
        }
    };

// ----------------------------------------------------------------------------------------

    /*!A static_switch

        To use this template you give it some number of boolean expressions and it
        tells you which one of them is true.   If more than one of them is true then
        it causes a compile time error.

        for example:
            static_switch<1 + 1 == 2, 4 - 1 == 4>::value == 1  // because the first expression is true
            static_switch<1 + 1 == 3, 4 == 4>::value == 2      // because the second expression is true
            static_switch<1 + 1 == 3, 4 == 5>::value == 0      // 0 here because none of them are true
            static_switch<1 + 1 == 2, 4 == 4>::value == compiler error  // because more than one expression is true
    !*/

    template < bool v1 = 0, bool v2 = 0, bool v3 = 0, bool v4 = 0, bool v5 = 0,
               bool v6 = 0, bool v7 = 0, bool v8 = 0, bool v9 = 0, bool v10 = 0,
               bool v11 = 0, bool v12 = 0, bool v13 = 0, bool v14 = 0, bool v15 = 0 >
    struct static_switch;

    template <> struct static_switch<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0> { const static int value = 0; };
    template <> struct static_switch<1,0,0,0,0,0,0,0,0,0,0,0,0,0,0> { const static int value = 1; };
    template <> struct static_switch<0,1,0,0,0,0,0,0,0,0,0,0,0,0,0> { const static int value = 2; };
    template <> struct static_switch<0,0,1,0,0,0,0,0,0,0,0,0,0,0,0> { const static int value = 3; };
    template <> struct static_switch<0,0,0,1,0,0,0,0,0,0,0,0,0,0,0> { const static int value = 4; };
    template <> struct static_switch<0,0,0,0,1,0,0,0,0,0,0,0,0,0,0> { const static int value = 5; };
    template <> struct static_switch<0,0,0,0,0,1,0,0,0,0,0,0,0,0,0> { const static int value = 6; };
    template <> struct static_switch<0,0,0,0,0,0,1,0,0,0,0,0,0,0,0> { const static int value = 7; };
    template <> struct static_switch<0,0,0,0,0,0,0,1,0,0,0,0,0,0,0> { const static int value = 8; };
    template <> struct static_switch<0,0,0,0,0,0,0,0,1,0,0,0,0,0,0> { const static int value = 9; };
    template <> struct static_switch<0,0,0,0,0,0,0,0,0,1,0,0,0,0,0> { const static int value = 10; };
    template <> struct static_switch<0,0,0,0,0,0,0,0,0,0,1,0,0,0,0> { const static int value = 11; };
    template <> struct static_switch<0,0,0,0,0,0,0,0,0,0,0,1,0,0,0> { const static int value = 12; };
    template <> struct static_switch<0,0,0,0,0,0,0,0,0,0,0,0,1,0,0> { const static int value = 13; };
    template <> struct static_switch<0,0,0,0,0,0,0,0,0,0,0,0,0,1,0> { const static int value = 14; };
    template <> struct static_switch<0,0,0,0,0,0,0,0,0,0,0,0,0,0,1> { const static int value = 15; };

// ----------------------------------------------------------------------------------------
    /*!A is_built_in_scalar_type

        This is a template that allows you to determine if the given type is a built
        in scalar type such as an int, char, float, short, etc.

        For example, is_built_in_scalar_type<char>::value == true
        For example, is_built_in_scalar_type<std::string>::value == false
    !*/

    template <typename T> struct is_built_in_scalar_type        { const static bool value = false; };

    template <> struct is_built_in_scalar_type<float>           { const static bool value = true; };
    template <> struct is_built_in_scalar_type<double>          { const static bool value = true; };
    template <> struct is_built_in_scalar_type<long double>     { const static bool value = true; };
    template <> struct is_built_in_scalar_type<short>           { const static bool value = true; };
    template <> struct is_built_in_scalar_type<int>             { const static bool value = true; };
    template <> struct is_built_in_scalar_type<long>            { const static bool value = true; };
    template <> struct is_built_in_scalar_type<unsigned short>  { const static bool value = true; };
    template <> struct is_built_in_scalar_type<unsigned int>    { const static bool value = true; };
    template <> struct is_built_in_scalar_type<unsigned long>   { const static bool value = true; };
    template <> struct is_built_in_scalar_type<uint64>          { const static bool value = true; };
    template <> struct is_built_in_scalar_type<int64>           { const static bool value = true; };
    template <> struct is_built_in_scalar_type<char>            { const static bool value = true; };
    template <> struct is_built_in_scalar_type<signed char>     { const static bool value = true; };
    template <> struct is_built_in_scalar_type<unsigned char>   { const static bool value = true; };
    // Don't define one for wchar_t when using a version of visual studio
    // older than 8.0 (visual studio 2005) since before then they improperly set
    // wchar_t to be a typedef rather than its own type as required by the C++
    // standard.
#if !defined(_MSC_VER) || _NATIVE_WCHAR_T_DEFINED
    template <> struct is_built_in_scalar_type<wchar_t>         { const static bool value = true; };
#endif

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    typename enable_if<is_built_in_scalar_type<T>,bool>::type is_finite (
        const T& value
    )
    /*!
        requires
            - value must be some kind of scalar type such as int or double
        ensures
            - returns true if value is a finite value (e.g. not infinity or NaN) and false
              otherwise.
    !*/
    {
        if (is_float_type<T>::value)
            return -std::numeric_limits<T>::infinity() < value && value < std::numeric_limits<T>::infinity();
        else
            return true;
    }

// ----------------------------------------------------------------------------------------

    /*!A promote

        This is a template that takes one of the built in scalar types and gives you another
        scalar type that should be big enough to hold sums of values from the original scalar
        type.  The new scalar type will also always be signed.

        For example, promote<uint16>::type == int32
    !*/

    template <typename T, size_t s = sizeof(T)> struct promote;
    template <typename T> struct promote<T,1> { typedef int32 type; };
    template <typename T> struct promote<T,2> { typedef int32 type; };
    template <typename T> struct promote<T,4> { typedef int64 type; };
    template <typename T> struct promote<T,8> { typedef int64 type; };

    template <> struct promote<float,sizeof(float)>             { typedef double type; };
    template <> struct promote<double,sizeof(double)>           { typedef double type; };
    template <> struct promote<long double,sizeof(long double)> { typedef long double type; };

// ----------------------------------------------------------------------------------------

    /*!A assign_zero_if_built_in_scalar_type

        This function assigns its argument the value of 0 if it is a built in scalar
        type according to the is_built_in_scalar_type<> template.  If it isn't a
        built in scalar type then it does nothing.
    !*/

    template <typename T> inline typename disable_if<is_built_in_scalar_type<T>,void>::type assign_zero_if_built_in_scalar_type (T&){}
    template <typename T> inline typename enable_if<is_built_in_scalar_type<T>,void>::type assign_zero_if_built_in_scalar_type (T& a){a=0;}

// ----------------------------------------------------------------------------------------

    /*!A basic_type

        This is a template that takes a type and strips off any const, volatile, or reference
        qualifiers and gives you back the basic underlying type.  So for example:

        basic_type<const int&>::type == int
    !*/

    template <typename T> struct basic_type { typedef T type; };
    template <typename T> struct basic_type<const T> { typedef T type; };
    template <typename T> struct basic_type<const T&> { typedef T type; };
    template <typename T> struct basic_type<volatile const T&> { typedef T type; };
    template <typename T> struct basic_type<T&> { typedef T type; };
    template <typename T> struct basic_type<volatile T&> { typedef T type; };
    template <typename T> struct basic_type<volatile T> { typedef T type; };
    template <typename T> struct basic_type<volatile const T> { typedef T type; };

// ----------------------------------------------------------------------------------------

    template <typename T>
    T put_in_range (
        const T& a,
        const T& b,
        const T& val
    )
    /*!
        requires
            - T is a type that looks like double, float, int, or so forth
        ensures
            - if (val is within the range [a,b]) then
                - returns val
            - else
                - returns the end of the range [a,b] that is closest to val
    !*/
    {
        if (a < b)
        {
            if (val < a)
                return a;
            else if (val > b)
                return b;
        }
        else
        {
            if (val < b)
                return b;
            else if (val > a)
                return a;
        }

        return val;
    }

    // overload for double
    inline double put_in_range(const double& a, const double& b, const double& val)
    { return put_in_range<double>(a,b,val); }

// ----------------------------------------------------------------------------------------

    /*!A tabs

        This is a template to compute the absolute value a number at compile time.

        For example,
            abs<-4>::value == 4
            abs<4>::value == 4
    !*/

        template <long x, typename enabled=void>
        struct tabs { const static long value = x; };
        template <long x>
        struct tabs<x,typename enable_if_c<(x < 0)>::type> { const static long value = -x; };

// ----------------------------------------------------------------------------------------

    /*!A tmax

        This is a template to compute the max of two values at compile time

        For example,
            abs<4,7>::value == 7
    !*/

        template <long x, long y, typename enabled=void>
        struct tmax { const static long value = x; };
        template <long x, long y>
        struct tmax<x,y,typename enable_if_c<(y > x)>::type> { const static long value = y; };

// ----------------------------------------------------------------------------------------

    /*!A tmin

        This is a template to compute the min of two values at compile time

        For example,
            abs<4,7>::value == 4
    !*/

        template <long x, long y, typename enabled=void>
        struct tmin { const static long value = x; };
        template <long x, long y>
        struct tmin<x,y,typename enable_if_c<(y < x)>::type> { const static long value = y; };

    // ----------------------------------------------------------------------------------------

#define DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST(testname, returnT, funct_name, args)                        \
    struct _two_bytes_##testname { char a[2]; };                                                       \
    template < typename T, returnT (T::*funct)args >                                                   \
    struct _helper_##testname { typedef char type; };                                                  \
    template <typename T>                                                                              \
    static char _has_##testname##_helper( typename _helper_##testname<T,&T::funct_name >::type ) { return 0;} \
    template <typename T>                                                                              \
    static _two_bytes_##testname _has_##testname##_helper(int) { return _two_bytes_##testname();}             \
    template <typename T> struct _##testname##workaroundbug {                                          \
                const static unsigned long U = sizeof(_has_##testname##_helper<T>('a')); };            \
    template <typename T, unsigned long U = _##testname##workaroundbug<T>::U >                         \
    struct testname      { static const bool value = false; };                                         \
    template <typename T>                                                                              \
    struct testname<T,1> { static const bool value = true; };
    /*!A DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST

        The DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST() macro is used to define traits templates
        that tell you if a class has a certain member function.  For example, to make a
        test to see if a class has a public method with the signature void print(int) you
        would say:
            DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST(has_print, void, print, (int))

        Then you can check if a class, T, has this method by looking at the boolean value:
            has_print<T>::value
        which will be true if the member function is in the T class.

        Note that you can test for member functions taking no arguments by simply passing
        in empty () like so:
            DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST(has_print, void, print, ())
        This would test for a member of the form:
            void print().

        To test for const member functions you would use a statement such as this:
            DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST(has_print, void, print, ()const)
        This would test for a member of the form:
            void print() const.

        To test for const templated member functions you would use a statement such as this:
            DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST(has_print, void, template print<int>, ())
        This would test for a member of the form:
            template <typename T> void print().
    !*/

// ----------------------------------------------------------------------------------------

    /*!A is_function

        This is a template that allows you to determine if the given type is a function.

        For example,
            void funct();

            is_built_in_scalar_type<funct>::value == true
            is_built_in_scalar_type<int>::value == false
    !*/

    template <typename T> struct is_function { static const bool value = false; };
    template <typename T>
    struct is_function<T (void)> { static const bool value = true; };
    template <typename T, typename A0>
    struct is_function<T (A0)> { static const bool value = true; };
    template <typename T, typename A0, typename A1>
    struct is_function<T (A0, A1)> { static const bool value = true; };
    template <typename T, typename A0, typename A1, typename A2>
    struct is_function<T (A0, A1, A2)> { static const bool value = true; };
    template <typename T, typename A0, typename A1, typename A2, typename A3>
    struct is_function<T (A0, A1, A2, A3)> { static const bool value = true; };
    template <typename T, typename A0, typename A1, typename A2, typename A3, typename A4>
    struct is_function<T (A0, A1, A2, A3, A4)> { static const bool value = true; };
    template <typename T, typename A0, typename A1, typename A2, typename A3, typename A4,
                          typename A5>
    struct is_function<T (A0,A1,A2,A3,A4,A5)> { static const bool value = true; };
    template <typename T, typename A0, typename A1, typename A2, typename A3, typename A4,
                          typename A5, typename A6>
    struct is_function<T (A0,A1,A2,A3,A4,A5,A6)> { static const bool value = true; };
    template <typename T, typename A0, typename A1, typename A2, typename A3, typename A4,
                          typename A5, typename A6, typename A7>
    struct is_function<T (A0,A1,A2,A3,A4,A5,A6,A7)> { static const bool value = true; };
    template <typename T, typename A0, typename A1, typename A2, typename A3, typename A4,
                          typename A5, typename A6, typename A7, typename A8>
    struct is_function<T (A0,A1,A2,A3,A4,A5,A6,A7,A8)> { static const bool value = true; };
    template <typename T, typename A0, typename A1, typename A2, typename A3, typename A4,
                          typename A5, typename A6, typename A7, typename A8, typename A9>
    struct is_function<T (A0,A1,A2,A3,A4,A5,A6,A7,A8,A9)> { static const bool value = true; };

    template <typename T> class funct_wrap0
    {
    public:
        funct_wrap0(T (&f_)()):f(f_){}
        T operator()() const { return f(); }
    private:
        T (&f)();
    };
    template <typename T, typename A0> class funct_wrap1
    {
    public:
        funct_wrap1(T (&f_)(A0)):f(f_){}
        T operator()(A0 a0) const { return f(a0); }
    private:
        T (&f)(A0);
    };
    template <typename T, typename A0, typename A1> class funct_wrap2
    {
    public:
        funct_wrap2(T (&f_)(A0,A1)):f(f_){}
        T operator()(A0 a0, A1 a1) const { return f(a0,a1); }
    private:
        T (&f)(A0,A1);
    };
    template <typename T, typename A0, typename A1, typename A2> class funct_wrap3
    {
    public:
        funct_wrap3(T (&f_)(A0,A1,A2)):f(f_){}
        T operator()(A0 a0, A1 a1, A2 a2) const { return f(a0,a1,a2); }
    private:
        T (&f)(A0,A1,A2);
    };
    template <typename T, typename A0, typename A1, typename A2, typename A3> class funct_wrap4
    {
    public:
        funct_wrap4(T (&f_)(A0,A1,A2,A3)):f(f_){}
        T operator()(A0 a0, A1 a1, A2 a2, A3 a3) const { return f(a0,a1,a2,a3); }
    private:
        T (&f)(A0,A1,A2,A3);
    };
    template <typename T, typename A0, typename A1, typename A2, typename A3, typename A4> class funct_wrap5
    {
    public:
        funct_wrap5(T (&f_)(A0,A1,A2,A3,A4)):f(f_){}
        T operator()(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) const { return f(a0,a1,a2,a3,a4); }
    private:
        T (&f)(A0,A1,A2,A3,A4);
    };

    /*!A wrap_function

        This is a template that allows you to turn a global function into a
        function object.  The reason for this template's existance is so you can
        do stuff like this:

            template <typename T>
            void call_funct(const T& funct)
            {  cout << funct(); }

            std::string test() { return "asdfasf"; }

            int main()
            {
                call_funct(wrap_function(test));
            }

        The above code doesn't work right on some compilers if you don't
        use wrap_function.
    !*/

    template <typename T>
    funct_wrap0<T> wrap_function(T (&f)()) { return funct_wrap0<T>(f); }
    template <typename T, typename A0>
    funct_wrap1<T,A0> wrap_function(T (&f)(A0)) { return funct_wrap1<T,A0>(f); }
    template <typename T, typename A0, typename A1>
    funct_wrap2<T,A0,A1> wrap_function(T (&f)(A0, A1)) { return funct_wrap2<T,A0,A1>(f); }
    template <typename T, typename A0, typename A1, typename A2>
    funct_wrap3<T,A0,A1,A2> wrap_function(T (&f)(A0, A1, A2)) { return funct_wrap3<T,A0,A1,A2>(f); }
    template <typename T, typename A0, typename A1, typename A2, typename A3>
    funct_wrap4<T,A0,A1,A2,A3> wrap_function(T (&f)(A0, A1, A2, A3)) { return funct_wrap4<T,A0,A1,A2,A3>(f); }
    template <typename T, typename A0, typename A1, typename A2, typename A3, typename A4>
    funct_wrap5<T,A0,A1,A2,A3,A4> wrap_function(T (&f)(A0, A1, A2, A3, A4)) { return funct_wrap5<T,A0,A1,A2,A3,A4>(f); }

// ----------------------------------------------------------------------------------------

    template <unsigned long bSIZE>
    class stack_based_memory_block : noncopyable
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is a simple container for a block of memory
                of bSIZE bytes.  This memory block is located on the stack
                and properly aligned to hold any kind of object.
        !*/
    public:
        static const unsigned long size = bSIZE;

        stack_based_memory_block(): data(mem.data) {}

        void* get () { return data; }
        /*!
            ensures
                - returns a pointer to the block of memory contained in this object
        !*/

        const void* get () const { return data; }
        /*!
            ensures
                - returns a pointer to the block of memory contained in this object
        !*/

    private:

        // You obviously can't have a block of memory that has zero bytes in it.
        COMPILE_TIME_ASSERT(bSIZE > 0);

        union mem_block
        {
            // All of this garbage is to make sure this union is properly aligned
            // (a union is always aligned such that everything in it would be properly
            // aligned.  So the assumption here is that one of these objects has
            // a large enough alignment requirement to satisfy any object this
            // block of memory might be cast into).
            void* void_ptr;
            int integer;
            struct {
                void (stack_based_memory_block::*callback)();
                stack_based_memory_block* o;
            } stuff;
            long double more_stuff;

            uint64 var1;
            uint32 var2;
            double var3;

            char data[size];
        } mem;

        // The reason for having this variable is that doing it this way avoids
        // warnings from gcc about violations of strict-aliasing rules.
        void* const data;
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_ALGs_


dlib C++ Library - quantum_computing_abstract.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_QUANTUM_COMPUTINg_ABSTRACT_
#ifdef DLIB_QUANTUM_COMPUTINg_ABSTRACT_

#include <complex>
#include "../matrix.h"
#include "../rand.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    typedef std::complex<double> qc_scalar_type;

// ----------------------------------------------------------------------------------------

    class quantum_register
    {
        /*!
            INITIAL VALUE
                - num_bits() == 1
                - state_vector().nr() == 2
                - state_vector().nc() == 1
                - state_vector()(0) == 1
                - state_vector()(1) == 0
                - probability_of_bit(0) == 0

                - i.e. This register represents a single quantum bit and it is
                  completely in the 0 state.

            WHAT THIS OBJECT REPRESENTS
                This object represents a set of quantum bits.
        !*/

    public:

        quantum_register(
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        int num_bits (
        ) const;
        /*!
            ensures
                - returns the number of quantum bits in this register
        !*/

        void set_num_bits (
            int new_num_bits
        );
        /*!
            requires
                - 1 <= new_num_bits <= 30
            ensures
                - #num_bits() == new_num_bits
                - #state_vector().nr() == 2^new_num_bits
                  (i.e. the size of the state_vector is exponential in the number of bits in a register)
                - for all valid i:
                    - probability_of_bit(i) == 0
        !*/

        void zero_all_bits(
        );
        /*!
            ensures
                - for all valid i:
                    - probability_of_bit(i) == 0
        !*/

        void append (
            const quantum_register& reg
        );
        /*!
            ensures
                - #num_bits() == num_bits() + reg.num_bits()
                - #this->state_vector() == tensor_product(this->state_vector(), reg.state_vector())
                - The original bits in *this become the high order bits of the resulting
                  register and all the bits in reg end up as the low order bits in the
                  resulting register.
        !*/

        double probability_of_bit (
            int bit
        ) const;
        /*!
            requires
                - 0 <= bit < num_bits()
            ensures
                - returns the probability of measuring the given bit and it being in the 1 state.
                - The returned value is also equal to the sum of norm(state_vector()(i)) for all
                  i where the bit'th bit in i is set to 1. (note that the lowest order bit is bit 0)
        !*/

        template <typename rand_type>
        bool measure_bit (
            int bit,
            rand_type& rnd
        );
        /*!
            requires
                - 0 <= bit < num_bits()
                - rand_type == an implementation of dlib/rand/rand_float_abstract.h
            ensures
                - measures the given bit in this register.  Let R denote the boolean
                  result of the measurement, where true means the bit was measured to
                  have value 1 and false means it had a value of 0.
                - if (R == true) then
                    - returns true
                    - #probability_of_bit(bit) == 1
                - else
                    - returns false
                    - #probability_of_bit(bit) == 0
        !*/

        template <typename rand_type>
        bool measure_and_remove_bit (
            int bit,
            rand_type& rnd
        );
        /*!
            requires
                - num_bits() > 1
                - 0 <= bit < num_bits()
                - rand_type == an implementation of dlib/rand/rand_float_abstract.h
            ensures
                - measures the given bit in this register.  Let R denote the boolean
                  result of the measurement, where true means the bit was measured to
                  have value 1 and false means it had a value of 0.
                - #num_bits() == num_bits() - 1
                - removes the bit that was measured from this register.
                - if (R == true) then
                    - returns true
                - else
                    - returns false
        !*/

        const matrix<qc_scalar_type,0,1>& state_vector(
        ) const;
        /*!
            ensures
                - returns a const reference to the state vector that describes the state of
                  the quantum bits in this register.
        !*/

        matrix<qc_scalar_type,0,1>& state_vector(
        );
        /*!
            ensures
                - returns a non-const reference to the state vector that describes the state of
                  the quantum bits in this register.
        !*/

        void swap (
            quantum_register& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/

    };

    inline void swap (
        quantum_register& a,
        quantum_register& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    class gate_exp
    {
        /*!
            REQUIREMENTS ON T
                T must be some object that inherits from gate_exp and implements its own
                version of operator() and compute_state_element().

            WHAT THIS OBJECT REPRESENTS
                This object represents an expression that evaluates to a quantum gate
                that operates on T::num_bits qubits.

                This object makes it easy to create new types of gate objects. All
                you need to do is inherit from gate_exp in the proper way and
                then you can use your new gate objects in conjunction with all the
                others.
        !*/

    public:

        static const long num_bits = T::num_bits;
        static const long dims = T::dims;

        gate_exp(
            T& exp
        );
        /*!
            ensures
                - #&ref() == &exp
        !*/

        const qc_scalar_type operator() (
            long r,
            long c
        ) const;
        /*!
            requires
                - 0 <= r < dims
                - 0 <= c < dims
            ensures
                - returns ref()(r,c)
        !*/

        void apply_gate_to (
            quantum_register& reg
        ) const;
        /*!
            requires
                - reg.num_bits() == num_bits
            ensures
                - applies this quantum gate to the given quantum register
                - Let M represent the matrix for this quantum gate, then
                  #reg().state_vector() = M*reg().state_vector()
        !*/

        template <typename exp>
        qc_scalar_type compute_state_element (
            const matrix_exp<exp>& reg,
            long row_idx
        ) const;
        /*!
            requires
                - reg.nr() == dims
                - reg.nc() == 1
                - 0 <= row_idx < dims
            ensures
                - Let M represent the matrix for this gate, then
                  this function returns rowm(M*reg, row_idx)
                  (i.e. returns the row_idx row of what you get when you apply this
                  gate to the given column vector in reg)
                - This function works by calling ref().compute_state_element(reg,row_idx)
        !*/

        const T& ref(
        );
        /*!
            ensures
                - returns a reference to the subexpression contained in this object
        !*/

        const matrix<qc_scalar_type> mat (
        ) const;
        /*!
            ensures
                - returns a dense matrix object that contains the matrix for this gate
        !*/
    };

// ----------------------------------------------------------------------------------------

    template <typename T, typename U>
    class composite_gate : public gate_exp<composite_gate<T,U> >
    {
        /*!
            REQUIREMENTS ON T AND U
                Both must be gate expressions that inherit from gate_exp

            WHAT THIS OBJECT REPRESENTS
                This object represents a quantum gate that is the tensor product of
                two other quantum gates.

                As an example, suppose you have 3 registers, reg_high, reg_low, and reg_all.  Also
                suppose that reg_all is what you get when you append reg_high and reg_low,
                so reg_all.state_vector() == tensor_product(reg_high.state_vector(),reg_low.state_vector()).

                Then applying a composite gate to reg_all would give you the same thing as
                applying the lhs gate to reg_high and the rhs gate to reg_low and then appending
                the two resulting registers.  So the lhs gate of a composite_gate applies to
                the high order bits of a regitser and the rhs gate applies to the lower order bits.
        !*/
    public:

        composite_gate (
            const composite_gate& g
        );
        /*!
            ensures
                - *this is a copy of g
        !*/

        composite_gate(
            const gate_exp<T>& lhs_,
            const gate_exp<U>& rhs_
        ):
        /*!
            ensures
                - #lhs == lhs_.ref()
                - #rhs == rhs_.ref()
                - #num_bits == T::num_bits + U::num_bits
                - #dims == 2^num_bits
                - #&ref() == this
        !*/

        const qc_scalar_type operator() (
            long r,
            long c
        ) const;
        /*!
            requires
                - 0 <= r < dims
                - 0 <= c < dims
            ensures
                - Let M denote the tensor product of lhs with rhs, then this function
                  returns M(r,c)
                  (i.e. returns lhs(r/U::dims,c/U::dims)*rhs(r%U::dims, c%U::dims))
        !*/

        template <typename exp>
        qc_scalar_type compute_state_element (
            const matrix_exp<exp>& reg,
            long row_idx
        ) const;
        /*!
            requires
                - reg.nr() == dims
                - reg.nc() == 1
                - 0 <= row_idx < dims
            ensures
                - Let M represent the matrix for this gate, then this function
                  returns rowm(M*reg, row_idx)
                  (i.e. returns the row_idx row of what you get when you apply this
                  gate to the given column vector in reg)
                - This function works by calling rhs.compute_state_element() and using elements
                  of the matrix in lhs.
        !*/

        static const long num_bits;
        static const long dims;

        const T lhs;
        const U rhs;
    };

// ----------------------------------------------------------------------------------------

    template <long bits>
    class gate : public gate_exp<gate<bits> >
    {
        /*!
            REQUIREMENTS ON bits
                0 < bits <= 30

            WHAT THIS OBJECT REPRESENTS
                This object represents a quantum gate that operates on bits qubits.
                It stores its gate matrix explicitly in a dense in-memory matrix.
        !*/

    public:
        gate(
        );
        /*!
            ensures
                - num_bits == bits
                - dims == 2^bits
                - #&ref() == this
                - for all valid r and c:
                    #(*this)(r,c) == 0
        !*/

        gate (
            const gate& g
        );
        /*!
            ensures
                - *this is a copy of g
        !*/

        template <typename T>
        explicit gate(
            const gate_exp<T>& g
        );
        /*!
            requires
                - T::num_bits == num_bits
            ensures
                - num_bits == bits
                - dims == 2^bits
                - #&ref() == this
                - for all valid r and c:
                    #(*this)(r,c) == g(r,c)
        !*/

        const qc_scalar_type& operator() (
            long r,
            long c
        ) const;
        /*!
            requires
                - 0 <= r < dims
                - 0 <= c < dims
            ensures
                - Let M denote the matrix for this gate, then this function
                  returns a const reference to M(r,c)
        !*/

        qc_scalar_type& operator() (
            long r,
            long c
        );
        /*!
            requires
                - 0 <= r < dims
                - 0 <= c < dims
            ensures
                - Let M denote the matrix for this gate, then this function
                  returns a non-const reference to M(r,c)
        !*/

        template <typename exp>
        qc_scalar_type compute_state_element (
            const matrix_exp<exp>& reg,
            long row_idx
        ) const;
        /*!
            requires
                - reg.nr() == dims
                - reg.nc() == 1
                - 0 <= row_idx < dims
            ensures
                - Let M represent the matrix for this gate, then this function
                  returns rowm(M*reg, row_idx)
                  (i.e. returns the row_idx row of what you get when you apply this
                  gate to the given column vector in reg)
        !*/

        static const long num_bits;
        static const long dims;

    };

// ----------------------------------------------------------------------------------------

    template <typename T, typename U>
    const composite_gate<T,U> operator, (
        const gate_exp<T>& lhs,
        const gate_exp<U>& rhs
    ) { return composite_gate<T,U>(lhs,rhs); }
    /*!
        ensures
            - returns a composite_gate that represents the tensor product of the lhs
              gate with the rhs gate.
    !*/

// ----------------------------------------------------------------------------------------

    namespace quantum_gates
    {

        inline const gate<1> hadamard(
        );
        /*!
            ensures
                - returns the Hadamard gate.
                  (i.e. A gate with a matrix of
                                 |1, 1|
                     1/sqrt(2) * |1,-1|   )
        !*/

        inline const gate<1> x(
        );
        /*!
            ensures
                - returns the not gate.
                  (i.e. A gate with a matrix of
                      |0, 1|
                      |1, 0|   )
        !*/

        inline const gate<1> y(
        );
        /*!
            ensures
                - returns the y gate.
                  (i.e. A gate with a matrix of
                      |0,-i|
                      |i, 0|   )
        !*/

        inline const gate<1> z(
        );
        /*!
            ensures
                - returns the z gate.
                  (i.e. A gate with a matrix of
                      |1, 0|
                      |0,-1|   )
        !*/

        inline const gate<1> noop(
        );
        /*!
            ensures
                - returns the no-op or identity gate.
                  (i.e. A gate with a matrix of
                      |1, 0|
                      |0, 1|   )
        !*/

        template <
            int control_bit,
            int target_bit
            >
        class cnot : public gate_exp<cnot<control_bit, target_bit> >
        {
            /*!
                REQUIREMENTS ON control_bit AND target_bit
                    - control_bit != target_bit

                WHAT THIS OBJECT REPRESENTS
                    This object represents the controlled-not quantum gate.  It is a gate that
                    operates on abs(control_bit-target_bit)+1 qubits.

                    In terms of the computational basis vectors, this gate maps input
                    vectors to output vectors in the following way:
                        - if (the input vector corresponds to a state where the control_bit
                          qubit is 1) then
                            - this gate outputs the computational basis vector that
                              corresponds to the state where the target_bit has been flipped
                              with respect to the input vector
                        - else
                            - this gate outputs the input vector unmodified

            !*/
        };

        template <
            int control_bit1,
            int control_bit2,
            int target_bit
            >
        class toffoli : public gate_exp<toffoli<control_bit1, control_bit2, target_bit> >
        {
            /*!
                REQUIREMENTS ON control_bit1, control_bit2, AND target_bit
                    - all the arguments denote different bits, i.e.:
                        - control_bit1 != target_bit
                        - control_bit2 != target_bit
                        - control_bit1 != control_bit2
                    - The target bit can't be in-between the control bits, i.e.:
                        - (control_bit1 < target_bit && control_bit2 < target_bit) ||
                          (control_bit1 > target_bit && control_bit2 > target_bit)

                WHAT THIS OBJECT REPRESENTS
                    This object represents the toffoli variant of a controlled-not quantum gate.
                    It is a gate that operates on max(abs(control_bit2-target_bit),abs(control_bit1-target_bit))+1
                    qubits.

                    In terms of the computational basis vectors, this gate maps input
                    vectors to output vectors in the following way:
                        - if (the input vector corresponds to a state where the control_bit1 and
                          control_bit2 qubits are 1) then
                            - this gate outputs the computational basis vector that
                              corresponds to the state where the target_bit has been flipped
                              with respect to the input vector
                        - else
                            - this gate outputs the input vector unmodified

            !*/
        };

    // ------------------------------------------------------------------------------------

    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_QUANTUM_COMPUTINg_ABSTRACT_


dlib C++ Library - set_utils_abstract.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SET_UTILs_ABSTRACT_
#ifdef DLIB_SET_UTILs_ABSTRACT_

#include "../set.h"
#include "../algs.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename U
        >
    unsigned long set_intersection_size (
        const T& a,
        const U& b
    );
    /*!
        requires
            - T and U must both be implementations of set/set_kernel_abstract.h
        ensures
            - returns the number of elements that are in both set a and b
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename U,
        typename V
        >
    void set_union (
        const T& a,
        const U& b,
        V& u
    );
    /*!
        requires
            - T, U, and V must all be implementations of set/set_kernel_abstract.h
            - the types of objects contained in these sets must be copyable
        ensures
            - #u == the union of a and b.  That is, u contains all elements
              of a and all the elements of b.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename U,
        typename V
        >
    void set_intersection (
        const T& a,
        const U& b,
        V& i
    );
    /*!
        requires
            - T, U, and V must all be implementations of set/set_kernel_abstract.h
            - the types of objects contained in these sets must be copyable
        ensures
            - #i == the intersection of a and b.  That is, i contains all elements
              of a that are also in b.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename U,
        typename V
        >
    void set_difference (
        const T& a,
        const U& b,
        V& d
    );
    /*!
        requires
            - T, U, and V must all be implementations of set/set_kernel_abstract.h
            - the types of objects contained in these sets must be copyable
        ensures
            - #d == the difference of a and b.  That is, d contains all elements
              of a that are NOT in b.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SET_UTILs_ABSTRACT_


dlib C++ Library - array_tools_abstract.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_ARRAY_tOOLS_ABSTRACT_H_
#ifdef DLIB_ARRAY_tOOLS_ABSTRACT_H_

#include "array_kernel_abstract.h"

namespace dlib
{
    template <typename T>
    void split_array (
        T& a,
        T& b,
        double frac
    );
    /*!
        requires
            - 0 <= frac <= 1
            - T must be an array type such as dlib::array or std::vector
        ensures
            - This function takes the elements of a and splits them into two groups.  The
              first group remains in a and the second group is put into b.  The ordering of
              elements in a is preserved.  In particular, concatenating #a with #b will
              reproduce the original contents of a.
            - The elements in a are moved around using global swap().  So they must be
              swappable, but do not need to be copyable.
            - #a.size() == floor(a.size()*frac)
            - #b.size() == a.size()-#a.size()
    !*/
}

#endif // DLIB_ARRAY_tOOLS_ABSTRACT_H_


dlib C++ Library - statistics_abstract.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net), Steve Taylor
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_STATISTICs_ABSTRACT_
#ifdef DLIB_STATISTICs_ABSTRACT_

#include <limits>
#include <cmath>
#include "../matrix/matrix_abstract.h"
#include "../svm/sparse_vector_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename alloc
        >
    double mean_sign_agreement (
        const std::vector<T,alloc>& a,
        const std::vector<T,alloc>& b
    );
    /*!
        requires
            - a.size() == b.size()
        ensures
            - returns the number of times a[i] has the same sign as b[i] divided by
              a.size().  So we return the probability that elements of a and b have
              the same sign.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename alloc
        >
    double correlation (
        const std::vector<T,alloc>& a,
        const std::vector<T,alloc>& b
    );
    /*!
        requires
            - a.size() == b.size()
            - a.size() > 1
        ensures
            - returns the correlation coefficient between all the elements of a and b.
              (i.e. how correlated is a(i) with b(i))
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename alloc
        >
    double covariance (
        const std::vector<T,alloc>& a,
        const std::vector<T,alloc>& b
    );
    /*!
        requires
            - a.size() == b.size()
            - a.size() > 1
        ensures
            - returns the covariance between all the elements of a and b.
              (i.e. how does a(i) vary with b(i))
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename alloc
        >
    double r_squared (
        const std::vector<T,alloc>& a,
        const std::vector<T,alloc>& b
    );
    /*!
        requires
            - a.size() == b.size()
            - a.size() > 1
        ensures
            - returns the R^2 coefficient of determination between all the elements of a and b.
              This value is just the square of correlation(a,b).
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename alloc
        >
    double mean_squared_error (
        const std::vector<T,alloc>& a,
        const std::vector<T,alloc>& b
    );
    /*!
        requires
            - a.size() == b.size()
        ensures
            - returns the mean squared error between all the elements of a and b.
              (i.e. mean(squared(mat(a)-mat(b))))
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    class running_stats
    {
        /*!
            REQUIREMENTS ON T
                - T must be a float, double, or long double type

            INITIAL VALUE
                - mean() == 0
                - current_n() == 0

            WHAT THIS OBJECT REPRESENTS
                This object represents something that can compute the running mean,
                variance, skewness, and excess kurtosis of a stream of real numbers.
        !*/
    public:

        running_stats(
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        void clear(
        );
        /*!
            ensures
                - this object has its initial value
                - clears all memory of any previous data points
        !*/

        T current_n (
        ) const;
        /*!
            ensures
                - returns the number of points given to this object so far.
        !*/

        void add (
            const T& val
        );
        /*!
            ensures
                - updates the mean, variance, skewness, and kurtosis stored in this object
                  so that the new value is factored into them.
                - #mean() == mean()*current_n()/(current_n()+1) + val/(current_n()+1).
                  (i.e. the updated mean value that takes the new value into account)
                - #variance() == the updated variance that takes this new value into account.
                - #skewness() == the updated skewness that takes this new value into account.
                - #ex_kurtosis() == the updated kurtosis that takes this new value into account.
                - #current_n() == current_n() + 1
        !*/

        T mean (
        ) const;
        /*!
            ensures
                - returns the mean of all the values presented to this object
                  so far.
        !*/

        T variance (
        ) const;
        /*!
            requires
                - current_n() > 1
            ensures
                - returns the unbiased sample variance of all the values presented to this
                  object so far.
        !*/

        T stddev (
        ) const;
        /*!
            requires
                - current_n() > 1
            ensures
                - returns the unbiased sampled standard deviation of all the values
                  presented to this object so far.
        !*/

        T skewness (
        ) const;
        /*!
            requires
                - current_n() > 2
            ensures
                - returns the unbiased sample skewness of all the values presented
                  to this object so far.
        !*/

        T ex_kurtosis(
        ) const;
        /*!
            requires
                - current_n() > 3
            ensures
                - returns the unbiased sample kurtosis of all the values presented
                  to this object so far.
        !*/

        T max (
        ) const;
        /*!
            requires
                - current_n() > 1
            ensures
                - returns the largest value presented to this object so far.
        !*/

        T min (
        ) const;
        /*!
            requires
                - current_n() > 1
            ensures
                - returns the smallest value presented to this object so far.
        !*/

        T scale (
            const T& val
        ) const;
        /*!
            requires
                - current_n() > 1
            ensures
                - return (val-mean())/stddev();
        !*/

        running_stats operator+ (
            const running_stats& rhs
        ) const;
        /*!
            ensures
                - returns a new running_stats object that represents the combination of all
                  the values given to *this and rhs.  That is, this function returns a
                  running_stats object, R, that is equivalent to what you would obtain if
                  all calls to this->add() and rhs.add() had instead been done to R.
        !*/
    };

    template <typename T>
    void serialize (
        const running_stats<T>& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

    template <typename T>
    void deserialize (
        running_stats<T>& item,
        std::istream& in
    );
    /*!
        provides serialization support
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    class running_scalar_covariance
    {
        /*!
            REQUIREMENTS ON T
                - T must be a float, double, or long double type

            INITIAL VALUE
                - mean_x() == 0
                - mean_y() == 0
                - current_n() == 0

            WHAT THIS OBJECT REPRESENTS
                This object represents something that can compute the running covariance
                of a stream of real number pairs.
        !*/

    public:

        running_scalar_covariance(
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        void clear(
        );
        /*!
            ensures
                - this object has its initial value
                - clears all memory of any previous data points
        !*/

        void add (
            const T& x,
            const T& y
        );
        /*!
            ensures
                - updates the statistics stored in this object so that
                  the new pair (x,y) is factored into them.
                - #current_n() == current_n() + 1
        !*/

        T current_n (
        ) const;
        /*!
            ensures
                - returns the number of points given to this object so far.
        !*/

        T mean_x (
        ) const;
        /*!
            ensures
                - returns the mean value of all x samples presented to this object
                  via add().
        !*/

        T mean_y (
        ) const;
        /*!
            ensures
                - returns the mean value of all y samples presented to this object
                  via add().
        !*/

        T covariance (
        ) const;
        /*!
            requires
                - current_n() > 1
            ensures
                - returns the covariance between all the x and y samples presented
                  to this object via add()
        !*/

        T correlation (
        ) const;
        /*!
            requires
                - current_n() > 1
            ensures
                - returns the correlation coefficient between all the x and y samples
                  presented to this object via add()
        !*/

        T variance_x (
        ) const;
        /*!
            requires
                - current_n() > 1
            ensures
                - returns the unbiased sample variance value of all x samples presented
                  to this object via add().
        !*/

        T variance_y (
        ) const;
        /*!
            requires
                - current_n() > 1
            ensures
                - returns the unbiased sample variance value of all y samples presented
                  to this object via add().
        !*/

        T stddev_x (
        ) const;
        /*!
            requires
                - current_n() > 1
            ensures
                - returns the unbiased sample standard deviation of all x samples
                  presented to this object via add().
        !*/

        T stddev_y (
        ) const;
        /*!
            requires
                - current_n() > 1
            ensures
                - returns the unbiased sample standard deviation of all y samples
                  presented to this object via add().
        !*/

        running_scalar_covariance operator+ (
            const running_covariance& rhs
        ) const;
        /*!
            ensures
                - returns a new running_scalar_covariance object that represents the
                  combination of all the values given to *this and rhs.  That is, this
                  function returns a running_scalar_covariance object, R, that is
                  equivalent to what you would obtain if all calls to this->add() and
                  rhs.add() had instead been done to R.
        !*/
    };

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_type
        >
    class running_covariance
    {
        /*!
            REQUIREMENTS ON matrix_type
                Must be some type of dlib::matrix.

            INITIAL VALUE
                - in_vector_size() == 0
                - current_n() == 0

            WHAT THIS OBJECT REPRESENTS
                This object is a simple tool for computing the mean and
                covariance of a sequence of vectors.
        !*/
    public:

        typedef typename matrix_type::mem_manager_type mem_manager_type;
        typedef typename matrix_type::type scalar_type;
        typedef typename matrix_type::layout_type layout_type;
        typedef matrix<scalar_type,0,0,mem_manager_type,layout_type> general_matrix;
        typedef matrix<scalar_type,0,1,mem_manager_type,layout_type> column_matrix;

        running_covariance(
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        void clear(
        );
        /*!
            ensures
                - this object has its initial value
                - clears all memory of any previous data points
        !*/

        long current_n (
        ) const;
        /*!
            ensures
                - returns the number of samples that have been presented to this object
        !*/

        long in_vector_size (
        ) const;
        /*!
            ensures
                - if (this object has been presented with any input vectors or
                  set_dimension() has been called) then
                    - returns the dimension of the column vectors used with this object
                - else
                    - returns 0
        !*/

        void set_dimension (
            long size
        );
        /*!
            requires
                - size > 0
            ensures
                - #in_vector_size() == size
                - #current_n() == 0
        !*/

        template <typename T>
        void add (
            const T& val
        );
        /*!
            requires
                - val must represent a column vector.  It can either be a dlib::matrix
                  object or some kind of unsorted sparse vector type.  See the top of
                  dlib/svm/sparse_vector_abstract.h for a definition of unsorted sparse vector.
                - val must have a number of dimensions which is compatible with the current
                  setting of in_vector_size().  In particular, this means that the
                  following must hold:
                    - if (val is a dlib::matrix) then
                        - in_vector_size() == 0 || val.size() == val_vector_size()
                    - else
                        - max_index_plus_one(val) <= in_vector_size()
                        - in_vector_size() > 0
                          (i.e. you must call set_dimension() prior to calling add() if
                          you want to use sparse vectors.)
            ensures
                - updates the mean and covariance stored in this object so that
                  the new value is factored into them.
                - if (val is a dlib::matrix) then
                    - #in_vector_size() == val.size()
        !*/

        const column_matrix mean (
        ) const;
        /*!
            requires
                - in_vector_size() != 0
            ensures
                - returns the mean of all the vectors presented to this object
                  so far.
        !*/

        const general_matrix covariance (
        ) const;
        /*!
            requires
                - in_vector_size() != 0
                - current_n() > 1
            ensures
                - returns the unbiased sample covariance matrix for all the vectors
                  presented to this object so far.
        !*/

        const running_covariance operator+ (
            const running_covariance& item
        ) const;
        /*!
            requires
                - in_vector_size() == 0 || item.in_vector_size() == 0 || in_vector_size() == item.in_vector_size()
                  (i.e. the in_vector_size() of *this and item must match or one must be zero)
            ensures
                - returns a new running_covariance object that represents the combination of all
                  the vectors given to *this and item.  That is, this function returns a
                  running_covariance object, R, that is equivalent to what you would obtain if all
                  calls to this->add() and item.add() had instead been done to R.
        !*/
    };

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_type
        >
    class running_cross_covariance
    {
        /*!
            REQUIREMENTS ON matrix_type
                Must be some type of dlib::matrix.

            INITIAL VALUE
                - x_vector_size() == 0
                - y_vector_size() == 0
                - current_n() == 0

            WHAT THIS OBJECT REPRESENTS
                This object is a simple tool for computing the mean and cross-covariance
                matrices of a sequence of pairs of vectors.
        !*/

    public:

        typedef typename matrix_type::mem_manager_type mem_manager_type;
        typedef typename matrix_type::type scalar_type;
        typedef typename matrix_type::layout_type layout_type;
        typedef matrix<scalar_type,0,0,mem_manager_type,layout_type> general_matrix;
        typedef matrix<scalar_type,0,1,mem_manager_type,layout_type> column_matrix;

        running_cross_covariance(
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        void clear(
        );
        /*!
            ensures
                - This object has its initial value.
                - Clears all memory of any previous data points.
        !*/

        long x_vector_size (
        ) const;
        /*!
            ensures
                - if (this object has been presented with any input vectors or
                  set_dimensions() has been called) then
                    - returns the dimension of the x vectors given to this object via add().
                - else
                    - returns 0
        !*/

        long y_vector_size (
        ) const;
        /*!
            ensures
                - if (this object has been presented with any input vectors or
                  set_dimensions() has been called) then
                    - returns the dimension of the y vectors given to this object via add().
                - else
                    - returns 0
        !*/

        void set_dimensions (
            long x_size,
            long y_size
        );
        /*!
            requires
                - x_size > 0
                - y_size > 0
            ensures
                - #x_vector_size() == x_size
                - #y_vector_size() == y_size
                - #current_n() == 0
        !*/

        long current_n (
        ) const;
        /*!
            ensures
                - returns the number of samples that have been presented to this object.
        !*/

        template <typename T, typename U>
        void add (
            const T& x,
            const U& y
        );
        /*!
            requires
                - x and y must represent column vectors.  They can either be dlib::matrix
                  objects or some kind of unsorted sparse vector type.  See the top of
                  dlib/svm/sparse_vector_abstract.h for a definition of unsorted sparse vector.
                - x and y must have a number of dimensions which is compatible with the
                  current setting of x_vector_size() and y_vector_size().  In particular,
                  this means that the following must hold:
                    - if (x or y is a sparse vector type) then
                        - x_vector_size() > 0 && y_vector_size() > 0
                          (i.e. you must call set_dimensions() prior to calling add() if
                          you want to use sparse vectors.)
                    - if (x is a dlib::matrix) then
                        - x_vector_size() == 0 || x.size() == x_vector_size()
                    - else
                        - max_index_plus_one(x) <= x_vector_size()
                    - if (y is a dlib::matrix) then
                        - y_vector_size() == 0 || y.size() == y_vector_size()
                    - else
                        - max_index_plus_one(y) <= y_vector_size()
            ensures
                - updates the mean and cross-covariance matrices stored in this object so
                  that the new (x,y) vector pair is factored into them.
                - if (x is a dlib::matrix) then
                    - #x_vector_size() == x.size()
                - if (y is a dlib::matrix) then
                    - #y_vector_size() == y.size()
        !*/

        const column_matrix mean_x (
        ) const;
        /*!
            requires
                - current_n() != 0
            ensures
                - returns the mean of all the x vectors presented to this object so far.
                - The returned vector will have x_vector_size() dimensions.
        !*/

        const column_matrix mean_y (
        ) const;
        /*!
            requires
                - current_n() != 0
            ensures
                - returns the mean of all the y vectors presented to this object so far.
                - The returned vector will have y_vector_size() dimensions.
        !*/

        const general_matrix covariance_xy (
        ) const;
        /*!
            requires
                - current_n() > 1
            ensures
                - returns the unbiased sample cross-covariance matrix for all the vector
                  pairs presented to this object so far.  In particular, returns a matrix
                  M such that:
                    - M.nr() == x_vector_size()
                    - M.nc() == y_vector_size()
                    - M == the cross-covariance matrix of the data given to add().
        !*/

        const running_cross_covariance operator+ (
            const running_cross_covariance& item
        ) const;
        /*!
            requires
                - x_vector_size() == 0 || item.x_vector_size() == 0 || x_vector_size() == item.x_vector_size()
                  (i.e. the x_vector_size() of *this and item must match or one must be zero)
                - y_vector_size() == 0 || item.y_vector_size() == 0 || y_vector_size() == item.y_vector_size()
                  (i.e. the y_vector_size() of *this and item must match or one must be zero)
            ensures
                - returns a new running_cross_covariance object that represents the
                  combination of all the vectors given to *this and item.  That is, this
                  function returns a running_cross_covariance object, R, that is equivalent
                  to what you would obtain if all calls to this->add() and item.add() had
                  instead been done to R.
        !*/
    };

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_type
        >
    class vector_normalizer
    {
        /*!
            REQUIREMENTS ON matrix_type
                - must be a dlib::matrix object capable of representing column
                  vectors

            INITIAL VALUE
                - in_vector_size() == 0
                - out_vector_size() == 0
                - means().size() == 0
                - std_devs().size() == 0

            WHAT THIS OBJECT REPRESENTS
                This object represents something that can learn to normalize a set
                of column vectors.  In particular, normalized column vectors should
                have zero mean and a variance of one.

                Also, if desired, this object can use principal component
                analysis for the purposes of reducing the number of elements in a
                vector.

            THREAD SAFETY
                Note that this object contains a cached matrix object it uses
                to store intermediate results for normalization.  This avoids
                needing to reallocate it every time this object performs normalization
                but also makes it non-thread safe.  So make sure you don't share
                instances of this object between threads.
        !*/

    public:
        typedef typename matrix_type::mem_manager_type mem_manager_type;
        typedef typename matrix_type::type scalar_type;
        typedef matrix_type result_type;

        template <typename vector_type>
        void train (
            const vector_type& samples
        );
        /*!
            requires
                - samples.size() > 0
                - samples == a column matrix or something convertible to a column
                  matrix via mat().  Also, x should contain
                  matrix_type objects that represent nonempty column vectors.
                - samples does not contain any infinite or NaN values
            ensures
                - #in_vector_size() == samples(0).nr()
                - #out_vector_size() == samples(0).nr()
                - This object has learned how to normalize vectors that look like
                  vectors in the given set of samples.
                - #means() == mean(samples)
                - #std_devs() == reciprocal(sqrt(variance(samples)));
        !*/

        long in_vector_size (
        ) const;
        /*!
            ensures
                - returns the number of rows that input vectors are
                  required to contain if they are to be normalized by
                  this object.
        !*/

        long out_vector_size (
        ) const;
        /*!
            ensures
                - returns the number of rows in the normalized vectors
                  that come out of this object.
        !*/

        const matrix_type& means (
        ) const;
        /*!
            ensures
                - returns a matrix M such that:
                    - M.nc() == 1
                    - M.nr() == in_vector_size()
                    - M(i) == the mean of the ith input feature shown to train()
        !*/

        const matrix_type& std_devs (
        ) const;
        /*!
            ensures
                - returns a matrix SD such that:
                    - SD.nc() == 1
                    - SD.nr() == in_vector_size()
                    - SD(i) == the reciprocal of the standard deviation of the ith
                      input feature shown to train()
        !*/

        const result_type& operator() (
            const matrix_type& x
        ) const;
        /*!
            requires
                - x.nr() == in_vector_size()
                - x.nc() == 1
            ensures
                - returns a normalized version of x, call it Z, that has the
                  following properties:
                    - Z.nr() == out_vector_size()
                    - Z.nc() == 1
                    - the mean of each element of Z is 0
                    - the variance of each element of Z is 1
                    - Z == pointwise_multiply(x-means(), std_devs());
        !*/

        void swap (
            vector_normalizer& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/
    };

    template <
        typename matrix_type
        >
    inline void swap (
        vector_normalizer<matrix_type>& a,
        vector_normalizer<matrix_type>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

    template <
        typename matrix_type,
        >
    void deserialize (
        vector_normalizer<matrix_type>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

    template <
        typename matrix_type,
        >
    void serialize (
        const vector_normalizer<matrix_type>& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_type
        >
    class vector_normalizer_pca
    {
        /*!
            REQUIREMENTS ON matrix_type
                - must be a dlib::matrix object capable of representing column
                  vectors

            INITIAL VALUE
                - in_vector_size() == 0
                - out_vector_size() == 0
                - means().size() == 0
                - std_devs().size() == 0
                - pca_matrix().size() == 0

            WHAT THIS OBJECT REPRESENTS
                This object represents something that can learn to normalize a set
                of column vectors.  In particular, normalized column vectors should
                have zero mean and a variance of one.

                Also, this object uses principal component analysis for the purposes
                of reducing the number of elements in a vector.

            THREAD SAFETY
                Note that this object contains a cached matrix object it uses
                to store intermediate results for normalization.  This avoids
                needing to reallocate it every time this object performs normalization
                but also makes it non-thread safe.  So make sure you don't share
                instances of this object between threads.
        !*/

    public:
        typedef typename matrix_type::mem_manager_type mem_manager_type;
        typedef typename matrix_type::type scalar_type;
        typedef matrix<scalar_type,0,1,mem_manager_type> result_type;

        template <typename vector_type>
        void train (
            const vector_type& samples,
            const double eps = 0.99
        );
        /*!
            requires
                - 0 < eps <= 1
                - samples.size() > 0
                - samples == a column matrix or something convertible to a column
                  matrix via mat().  Also, x should contain
                  matrix_type objects that represent nonempty column vectors.
                - samples does not contain any infinite or NaN values
            ensures
                - This object has learned how to normalize vectors that look like
                  vectors in the given set of samples.
                - Principal component analysis is performed to find a transform
                  that might reduce the number of output features.
                - #in_vector_size() == samples(0).nr()
                - 0 < #out_vector_size() <= samples(0).nr()
                - eps is a number that controls how "lossy" the pca transform will be.
                  Large values of eps result in #out_vector_size() being larger and
                  smaller values of eps result in #out_vector_size() being smaller.
                - #means() == mean(samples)
                - #std_devs() == reciprocal(sqrt(variance(samples)));
                - #pca_matrix() == the PCA transform matrix that is out_vector_size()
                  rows by in_vector_size() columns.
        !*/

        long in_vector_size (
        ) const;
        /*!
            ensures
                - returns the number of rows that input vectors are
                  required to contain if they are to be normalized by
                  this object.
        !*/

        long out_vector_size (
        ) const;
        /*!
            ensures
                - returns the number of rows in the normalized vectors
                  that come out of this object.
        !*/

        const matrix<scalar_type,0,1,mem_manager_type>& means (
        ) const;
        /*!
            ensures
                - returns a matrix M such that:
                    - M.nc() == 1
                    - M.nr() == in_vector_size()
                    - M(i) == the mean of the ith input feature shown to train()
        !*/

        const matrix<scalar_type,0,1,mem_manager_type>& std_devs (
        ) const;
        /*!
            ensures
                - returns a matrix SD such that:
                    - SD.nc() == 1
                    - SD.nr() == in_vector_size()
                    - SD(i) == the reciprocal of the standard deviation of the ith
                      input feature shown to train()
        !*/

        const matrix<scalar_type,0,0,mem_manager_type>& pca_matrix (
        ) const;
        /*!
            ensures
                - returns a matrix PCA such that:
                    - PCA.nr() == out_vector_size()
                    - PCA.nc() == in_vector_size()
                    - PCA == the principal component analysis transformation
                      matrix
        !*/

        const result_type& operator() (
            const matrix_type& x
        ) const;
        /*!
            requires
                - x.nr() == in_vector_size()
                - x.nc() == 1
            ensures
                - returns a normalized version of x, call it Z, that has the
                  following properties:
                    - Z.nr() == out_vector_size()
                    - Z.nc() == 1
                    - the mean of each element of Z is 0
                    - the variance of each element of Z is 1
                    - Z == pca_matrix()*pointwise_multiply(x-means(), std_devs());
        !*/

        void swap (
            vector_normalizer_pca& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/
    };

    template <
        typename matrix_type
        >
    inline void swap (
        vector_normalizer_pca<matrix_type>& a,
        vector_normalizer_pca<matrix_type>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

    template <
        typename matrix_type,
        >
    void deserialize (
        vector_normalizer_pca<matrix_type>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

    template <
        typename matrix_type,
        >
    void serialize (
        const vector_normalizer_pca<matrix_type>& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_STATISTICs_ABSTRACT_


dlib C++ Library - rand_kernel_abstract.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_RAND_KERNEl_ABSTRACT_
#ifdef DLIB_RAND_KERNEl_ABSTRACT_

#include <string>
#include "../uintn.h"

namespace dlib
{

    class rand
    {

        /*!
            INITIAL VALUE
                get_seed() == ""

            WHAT THIS OBJECT REPRESENTS
                This object represents a pseudorandom number generator.
        !*/

        public:

            rand(
            );
            /*!
                ensures
                    - #*this is properly initialized
                throws
                    - std::bad_alloc
            !*/

            rand (
                const std::string& seed_value
            );
            /*!
                ensures
                    - #*this is properly initialized
                    - #get_seed() == seed_value
                    - This version of the constructor is equivalent to using
                      the default constructor and then calling set_seed(seed_value)
                throws
                    - std::bad_alloc
            !*/

            virtual ~rand(
            );
            /*!
                ensures
                    - all memory associated with *this has been released
            !*/

            void clear(
            );
            /*!
                ensures
                    - #*this has its initial value
                throws
                    - std::bad_alloc
                        if this exception is thrown then *this is unusable
                        until clear() is called and succeeds
            !*/

            const std::string& get_seed (
            );
            /*!
                ensures
                    - returns the string currently being used as the random seed.
            !*/

            void set_seed (
                const std::string& value
            );
            /*!
                ensures
                    - #get_seed() == value
            !*/

            unsigned char get_random_8bit_number (
            );
            /*!
                ensures
                    - returns a pseudorandom number in the range 0 to 255
            !*/

            uint16 get_random_16bit_number (
            );
            /*!
                ensures
                    - returns a pseudorandom number in the range 0 to 2^16-1
            !*/

            uint32 get_random_32bit_number (
            );
            /*!
                ensures
                    - returns a pseudorandom number in the range 0 to 2^32-1
            !*/

            uint64 get_random_64bit_number (
            );
            /*!
                ensures
                    - returns a pseudorandom number in the range 0 to 2^64-1
            !*/

            float get_random_float (
            );
            /*!
                ensures
                    - returns a random float number N where:  0.0 <= N < 1.0.
            !*/

            double get_random_double (
            );
            /*!
                ensures
                    - returns a random double number N where:  0.0 <= N < 1.0.
            !*/

            double get_random_gaussian (
            );
            /*!
                ensures
                    - returns a random number sampled from a Gaussian distribution
                      with mean 0 and standard deviation 1.
            !*/

            void swap (
                rand& item
            );
            /*!
                ensures
                    - swaps *this and item
            !*/

    };

    inline void swap (
        rand& a,
        rand& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

    void serialize (
        const rand& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

    void deserialize (
        rand& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/
}

#endif // DLIB_RAND_KERNEl_ABSTRACT_


dlib C++ Library - random_subset_selector_abstract.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_RANDOM_SUBSeT_SELECTOR_ABSTRACT_H_
#ifdef DLIB_RANDOM_SUBSeT_SELECTOR_ABSTRACT_H_

#include <vector>
#include "../rand/rand_kernel_abstract.h"
#include "../algs.h"
#include "../string.h"

namespace dlib
{
    template <
        typename T,
        typename Rand_type = dlib::rand
        >
    class random_subset_selector
    {
        /*!
            REQUIREMENTS ON T
                T must be a copyable type

            REQUIREMENTS ON Rand_type
                must be an implementation of dlib/rand/rand_kernel_abstract.h

            INITIAL VALUE
                - size() == 0
                - max_size() == 0
                - next_add_accepts() == false

            WHAT THIS OBJECT REPRESENTS
                This object is a tool to help you select a random subset of a large body of data.
                In particular, it is useful when the body of data is too large to fit into memory.

                So for example, suppose you have 1000000 data samples and you want to select a
                random subset of size 1000.   Then you could do that as follows:

                    random_subset_selector<sample_type> rand_subset;
                    rand_subset.set_max_size(1000)
                    for (int i = 0; i < 1000000; ++i)
                        rand_subset.add( get_next_data_sample());

                At the end of the for loop you will have your random subset of 1000 samples.  And by
                random I mean that each of the 1000000 data samples has an equal chance of ending
                up in the rand_subset object.

                Note that the above example calls get_next_data_sample() for each data sample.  This
                may be inefficient since most of the data samples are just ignored.  An alternative
                method that doesn't require you to load each sample can also be used.  Consider the
                following:

                    random_subset_selector<sample_type> rand_subset;
                    rand_subset.set_max_size(1000)
                    for (int i = 0; i < 1000000; ++i)
                        if (rand_subset.next_add_accepts())
                            rand_subset.add(get_data_sample(i));
                        else
                            rand_subset.add()

                In the above example we only actually fetch the data sample into memory if we
                know that the rand_subset would include it into the random subset.  Otherwise,
                we can just call the empty add().

                Finally, note that the random_subset_selector uses a deterministic pseudo-random
                number generator under the hood.  Moreover, the default constructor always seeds
                the random number generator in the same way.  So unless you call set_seed()
                each instance of the random_subset_selector will function identically.
        !*/
    public:
        typedef T type;
        typedef T value_type;
        typedef default_memory_manager mem_manager_type;
        typedef Rand_type rand_type;

        typedef typename std::vector<T>::iterator iterator;
        typedef typename std::vector<T>::const_iterator const_iterator;

        random_subset_selector (
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        void set_seed(
            const std::string& value
        );
        /*!
            ensures
                - sets the seed of the random number generator that is embedded in
                  this object to the given value.
        !*/

        void make_empty (
        );
        /*!
            ensures
                - #size() == 0
        !*/

        unsigned long size (
        ) const;
        /*!
            ensures
                - returns the number of items of type T currently contained in this object
        !*/

        void set_max_size (
            unsigned long new_max_size
        );
        /*!
            ensures
                - #max_size() == new_max_size
                - #size() == 0
        !*/

        unsigned long max_size (
        ) const;
        /*!
            ensures
                - returns the maximum allowable size for this object
        !*/

        T& operator[] (
            unsigned long idx
        );
        /*!
            requires
                - idx < size()
            ensures
                - returns a non-const reference to the idx'th element of this object
        !*/

        const T& operator[] (
            unsigned long idx
        ) const;
        /*!
            requires
                - idx < size()
            ensures
                - returns a const reference to the idx'th element of this object
        !*/

        bool next_add_accepts (
        ) const;
        /*!
            ensures
                - if (the next call to add(item) will result in item being included
                  into *this) then
                    - returns true
                    - Note that the next item will always be accepted if size() < max_size().
                - else
                    - returns false
                    - Note that the next item will never be accepted if max_size() == 0.
        !*/

        void add (
            const T& new_item
        );
        /*!
            ensures
                - if (next_add_accepts()) then
                    - places new_item into *this object at a random location
                    - if (size() < max_size()) then
                        - #size() == size() + 1
                - #next_add_accepts() == The updated information about the acceptance
                  of the next call to add()
        !*/

        void add (
        );
        /*!
            requires
                - next_add_accepts() == false
            ensures
                - This function does nothing but update the value of #next_add_accepts()
        !*/

        iterator begin(
        );
        /*!
            ensures
                - if (size() > 0) then
                    - returns an iterator referring to the first element in
                      this container.
                - else
                    - returns end()
        !*/

        const_iterator begin(
        ) const;
        /*!
            ensures
                - if (size() > 0) then
                    - returns a const_iterator referring to the first element in
                      this container.
                - else
                    - returns end()
        !*/

        iterator end(
        );
        /*!
            ensures
                - returns an iterator that represents one past the end of
                  this container
        !*/

        const_iterator end(
        ) const;
        /*!
            ensures
                - returns an iterator that represents one past the end of
                  this container
        !*/

        const std::vector<T>& to_std_vector(
        ) const;
        /*!
            ensures
                - returns a const reference to the underlying std::vector<T> that contains
                  all elements in this object.  That is, this function returns a vector, V,
                  which has the following properties:
                    - V.size()  == this->size()
                    - V.begin() == this->begin()
                    - V.end()   == this->end()
        !*/

        void swap (
            random_subset_selector& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/

    };

    template <
        typename T,
        typename rand_type
        >
    void swap (
        random_subset_selector<T,rand_type>& a,
        random_subset_selector<T,rand_type>& b
    ) { a.swap(b); }
    /*!
        provides global swap support
    !*/

    template <
        typename T,
        typename rand_type
        >
    void serialize (
        const random_subset_selector<T,rand_type>& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

    template <
        typename T,
        typename rand_type
        >
    void deserialize (
        random_subset_selector<T,rand_type>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename alloc
        >
    random_subset_selector<T> randomly_subsample (
        const std::vector<T,alloc>& samples,
        unsigned long num
    );
    /*!
        ensures
            - returns a random subset R such that:
                - R contains a random subset of the given samples
                - R.size() == min(num, samples.size())
                - R.max_size() == num
            - The random number generator used by this function will always be
              initialized in the same way.  I.e. this function will always pick
              the same random subsample if called multiple times.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename alloc,
        typename U
        >
    random_subset_selector<T> randomly_subsample (
        const std::vector<T,alloc>& samples,
        unsigned long num,
        const U& random_seed
    );
    /*!
        requires
            - random_seed must be convertible to a string by dlib::cast_to_string()
        ensures
            - returns a random subset R such that:
                - R contains a random subset of the given samples
                - R.size() == min(num, samples.size())
                - R.max_size() == num
            - The given random_seed will be used to initialize the random number
              generator used by this function.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    random_subset_selector<T> randomly_subsample (
        const random_subset_selector<T>& samples,
        unsigned long num
    );
    /*!
        ensures
            - returns a random subset R such that:
                - R contains a random subset of the given samples
                - R.size() == min(num, samples.size())
                - R.max_size() == num
            - The random number generator used by this function will always be
              initialized in the same way.  I.e. this function will always pick
              the same random subsample if called multiple times.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename U
        >
    random_subset_selector<T> randomly_subsample (
        const random_subset_selector<T>& samples,
        unsigned long num,
        const U& random_seed
    );
    /*!
        requires
            - random_seed must be convertible to a string by dlib::cast_to_string()
        ensures
            - returns a random subset R such that:
                - R contains a random subset of the given samples
                - R.size() == min(num, samples.size())
                - R.max_size() == num
            - The given random_seed will be used to initialize the random number
              generator used by this function.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    const matrix_exp mat (
        const random_subset_selector<T>& m
    );
    /*!
        ensures
            - returns a matrix R such that:
                - is_col_vector(R) == true
                - R.size() == m.size()
                - for all valid r:
                  R(r) == m[r]
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_RANDOM_SUBSeT_SELECTOR_ABSTRACT_H_


dlib C++ Library - count_bits_abstract.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_COUNT_BiTS_ABSTRACT_Hh_
#ifdef DLIB_COUNT_BiTS_ABSTRACT_Hh_

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    T count_bits (
        T v
    );
    /*!
        requires
            - T is an unsigned integral type
        ensures
            - returns the number of bits in v which are set to 1.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    T hamming_distance (
        const T& a,
        const T& b
    );
    /*!
        requires
            - T is an unsigned integral type
        ensures
            - returns the number of bits which differ between a and b.  (I.e. returns
              count_bits(a^b).)
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_COUNT_BiTS_ABSTRACT_Hh_


dlib C++ Library - crc32_kernel_abstract.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_CRC32_KERNEl_ABSTRACT_
#ifdef DLIB_CRC32_KERNEl_ABSTRACT_

#include "../algs.h"
#include <string>
#include <vector>

namespace dlib
{

    class crc32
    {
        /*!
            INITIAL VALUE
                The current checksum covers zero bytes.
                get_checksum() == 0x00000000

            WHAT THIS OBJECT REPRESENTS
                This object represents the CRC32 algorithm for calculating
                checksums.
        !*/

    public:

        crc32 (
        );
        /*!
            ensures
                - #*this is properly initialized
        !*/

        crc32 (
            const std::string& item
        );
        /*!
            ensures
                - #*this is properly initialized
                - calls this->add(item).
                  (i.e. Using this constructor is the same as using the default
                  constructor and then calling add() on item)
        !*/

        crc32 (
            const std::vector<char>& item
        );
        /*!
            ensures
                - #*this is properly initialized
                - calls this->add(item).
                  (i.e. Using this constructor is the same as using the default
                  constructor and then calling add() on item)
        !*/

        virtual ~crc32 (
        );
        /*!
            ensures
                - any resources associated with *this have been released
        !*/

        void clear(
        );
        /*!
            ensures
                - #*this has its initial value
        !*/

        void add (
            unsigned char item
        );
        /*!
            ensures
                - #get_checksum() == The checksum of all items added to *this previously
                  concatenated with item.
        !*/

        void add (
            const std::string& item
        );
        /*!
            ensures
                - #get_checksum() == The checksum of all items added to *this previously
                  concatenated with item.
        !*/

        void add (
            const std::vector<char>& item
        );
        /*!
            ensures
                - #get_checksum() == The checksum of all items added to *this previously
                  concatenated with item.
        !*/

        unsigned long get_checksum (
        ) const;
        /*!
            ensures
                - returns the current checksum
        !*/

        operator unsigned long (
        ) const;
        /*!
            ensures
                - returns get_checksum()
        !*/

        void swap (
            crc32& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/

    };

    void swap (
        crc32& a,
        crc32& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

}

#endif // DLIB_CRC32_KERNEl_ABSTRACT_


dlib C++ Library - create_random_projection_hash_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_CREATE_RANDOM_PROJECTION_HAsH_ABSTRACT_Hh_
#ifdef DLIB_CREATE_RANDOM_PROJECTION_HAsH_ABSTRACT_Hh_

#include "projection_hash_abstract.h"
#include "../rand.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type
        >
    projection_hash create_random_projection_hash (
        const vector_type& v,
        const int bits,
        dlib::rand& rnd
    );
    /*!
        requires
            - 0 < bits <= 32
            - v.size() > 1
            - vector_type == a std::vector or compatible type containing dlib::matrix
              objects, each representing a column vector of the same size.
            - for all valid i, j:
                - is_col_vector(v[i]) == true
                - v[i].size() > 0
                - v[i].size() == v[j].size()
                - i.e. v contains only column vectors and all the column vectors
                  have the same non-zero length
            - rand_type == a type that implements the dlib/rand/rand_kernel_abstract.h interface
        ensures
            - returns a hash function H such that:
                - H.num_hash_bins() == pow(2,bits)
                - H will be setup so that it hashes the contents of v such that each bin
                  ends up with roughly the same number of elements in it.  This is
                  accomplished by picking random hyperplanes passing though the data.  In
                  particular, each plane normal vector is filled with Gaussian random
                  numbers and we also perform basic centering to ensure the plane passes
                  though the data.
            - This function uses the supplied random number generator, rnd, to drive part
              of it's processing.  Therefore, giving different random number generators
              will produce different outputs.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type
        >
    projection_hash create_random_projection_hash (
        const vector_type& v,
        const int bits
    );
    /*!
        requires
            - 0 < bits <= 32
            - v.size() > 1
            - vector_type == a std::vector or compatible type containing dlib::matrix
              objects, each representing a column vector of the same size.
            - for all valid i, j:
                - is_col_vector(v[i]) == true
                - v[i].size() > 0
                - v[i].size() == v[j].size()
                - i.e. v contains only column vectors and all the column vectors
                  have the same non-zero length
        ensures
            - returns create_random_projection_hash(v,bits,dlib::rand())
              (i.e. calls the above function with a default initialized random number generator)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type
        >
    projection_hash create_max_margin_projection_hash (
        const vector_type& v,
        const int bits,
        const double C,
        dlib::rand& rnd
    );
    /*!
        requires
            - 0 < bits <= 32
            - v.size() > 1
            - vector_type == a std::vector or compatible type containing dlib::matrix
              objects, each representing a column vector of the same size.
            - for all valid i, j:
                - is_col_vector(v[i]) == true
                - v[i].size() > 0
                - v[i].size() == v[j].size()
                - i.e. v contains only column vectors and all the column vectors
                  have the same non-zero length
            - rand_type == a type that implements the dlib/rand/rand_kernel_abstract.h interface
        ensures
            - returns a hash function H such that:
                - H.num_hash_bins() == pow(2,bits)
                - H will be setup so that it hashes the contents of v such that
                  each bin ends up with roughly the same number of elements
                  in it.  This is accomplished using a variation on the random hyperplane
                  generation technique from the paper:
                    Random Maximum Margin Hashing by Alexis Joly and Olivier Buisson
                  In particular, we use the svm_c_linear_dcd_trainer to generate planes.
                  We train it on randomly selected and randomly labeled points from v.
                  The C SVM parameter is set to the given C argument.
            - This function uses the supplied random number generator, rnd, to drive part
              of it's processing.  Therefore, giving different random number generators
              will produce different outputs.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type
        >
    projection_hash create_max_margin_projection_hash (
        const vector_type& v,
        const int bits,
        const double C = 10
    );
    /*!
        requires
            - 0 < bits <= 32
            - v.size() > 1
            - vector_type == a std::vector or compatible type containing dlib::matrix
              objects, each representing a column vector of the same size.
            - for all valid i, j:
                - is_col_vector(v[i]) == true
                - v[i].size() > 0
                - v[i].size() == v[j].size()
                - i.e. v contains only column vectors and all the column vectors
                  have the same non-zero length
        ensures
            - returns create_max_margin_projection_hash(v,bits,C,dlib::rand())
              (i.e. calls the above function with a default initialized random number generator)
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_CREATE_RANDOM_PROJECTION_HAsH_ABSTRACT_Hh_


dlib C++ Library - random_hashing_abstract.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_RANDOM_HAsHING_ABSTRACT_Hh_
#ifdef DLIB_RANDOM_HAsHING_ABSTRACT_Hh_

#include "random_hashing_abstract.h"
#include "murmur_hash3.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    double uniform_random_hash (
        const uint64& k1,
        const uint64& k2,
        const uint64& k3
    );
    /*!
        ensures
            - This function uses hashing to generate uniform random values in the range [0,1).
            - To define this function precisely, assume we have an arbitrary sequence of
              input triplets.  Then calling uniform_random_hash() on each of them should
              result in a sequence of double values that look like numbers sampled
              independently and uniformly at random from the interval [0,1).  This is true
              even if there is some simple pattern in the inputs.  For example, (0,0,0),
              (1,0,0), (2,0,0), (3,0,0), etc.
            - This function is deterministic.  That is, the same output is always returned
              when given the same input.
    !*/

// ----------------------------------------------------------------------------------------

    double gaussian_random_hash (
        const uint64& k1,
        const uint64& k2,
        const uint64& k3
    );
    /*!
        ensures
            - This function uses hashing to generate Gaussian distributed random values
              with mean 0 and variance 1.
            - To define this function precisely, assume we have an arbitrary sequence of
              input triplets.  Then calling gaussian_random_hash() on each of them should
              result in a sequence of double values that look like numbers sampled
              independently from a standard normal distribution.  This is true even if
              there is some simple pattern in the inputs.  For example, (0,0,0), (1,0,0),
              (2,0,0), (3,0,0), etc.
            - This function is deterministic.  That is, the same output is always returned
              when given the same input.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_RANDOM_HAsHING_ABSTRACT_Hh_


dlib C++ Library - hash_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_HAsH_ABSTRACT_Hh_
#ifdef DLIB_HAsH_ABSTRACT_Hh_

#include "murmur_hash3_abstract.h"
#include <vector>
#include <string>
#include <map>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    uint32 hash (
        const std::string& item,
        uint32 seed = 0
    );
    /*!
        ensures
            - returns a 32bit hash of the data stored in item.
            - Each value of seed results in a different hash function being used.
              (e.g. hash(item,0) should generally not be equal to hash(item,1))
            - uses the murmur_hash3() routine to compute the actual hash.
            - This routine will always give the same hash value when presented
              with the same input string.
    !*/

// ----------------------------------------------------------------------------------------

    uint32 hash (
        const std::wstring& item,
        uint32 seed = 0
    );
    /*!
        ensures
            - returns a 32bit hash of the data stored in item.
            - Each value of seed results in a different hash function being used.
              (e.g. hash(item,0) should generally not be equal to hash(item,1))
            - uses the murmur_hash3() routine to compute the actual hash.
            - Note that if the memory layout of the elements in item change between
              hardware platforms then hash() will give different outputs.  If you want
              hash() to always give the same output for the same input then you must
              ensure that elements of item always have the same layout in memory.
              Typically this means using fixed width types and performing byte swapping
              to account for endianness before passing item to hash().
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T, typename alloc>
    uint32 hash (
        const std::vector<T,alloc>& item,
        uint32 seed = 0
    );
    /*!
        requires
            - T is a standard layout type (e.g. a POD type like int, float,
              or a simple struct).
        ensures
            - returns a 32bit hash of the data stored in item.
            - Each value of seed results in a different hash function being used.
              (e.g. hash(item,0) should generally not be equal to hash(item,1))
            - uses the murmur_hash3() routine to compute the actual hash.
            - Note that if the memory layout of the elements in item change between
              hardware platforms then hash() will give different outputs.  If you want
              hash() to always give the same output for the same input then you must
              ensure that elements of item always have the same layout in memory.
              Typically this means using fixed width types and performing byte swapping
              to account for endianness before passing item to hash().
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T, typename U, typename alloc>
    uint32 hash (
        const std::vector<std::pair<T,U>,alloc>& item,
        uint32 seed = 0
    );
    /*!
        requires
            - T and U are standard layout types (e.g. POD types like int, float,
              or simple structs).
        ensures
            - returns a 32bit hash of the data stored in item.
            - Each value of seed results in a different hash function being used.
              (e.g. hash(item,0) should generally not be equal to hash(item,1))
            - uses the murmur_hash3() routine to compute the actual hash.
            - Note that if the memory layout of the elements in item change between
              hardware platforms then hash() will give different outputs.  If you want
              hash() to always give the same output for the same input then you must
              ensure that elements of item always have the same layout in memory.
              Typically this means using fixed width types and performing byte swapping
              to account for endianness before passing item to hash().
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T, typename U, typename comp, typename alloc>
    uint32 hash (
        const std::map<T,U,comp,alloc>& item,
        uint32 seed = 0
    );
    /*!
        requires
            - T and U are standard layout types (e.g. POD types like int, float,
              or simple structs).
        ensures
            - returns a 32bit hash of the data stored in item.
            - Each value of seed results in a different hash function being used.
              (e.g. hash(item,0) should generally not be equal to hash(item,1))
            - uses the murmur_hash3() routine to compute the actual hash.
            - Note that if the memory layout of the elements in item change between
              hardware platforms then hash() will give different outputs.  If you want
              hash() to always give the same output for the same input then you must
              ensure that elements of item always have the same layout in memory.
              Typically this means using fixed width types and performing byte swapping
              to account for endianness before passing item to hash().  However, since
              you can't modify the keys in a map you may have to copy it into a
              std::vector and then work from there.
    !*/

// ----------------------------------------------------------------------------------------

    inline uint32 hash (
        uint32 item,
        uint32 seed = 0
    );
    /*!
        ensures
            - returns a 32bit hash of the data stored in item.
            - Each value of seed results in a different hash function being used.
              (e.g. hash(item,0) should generally not be equal to hash(item,1))
            - uses the murmur_hash3_2() routine to compute the actual hash.
            - This routine will always give the same hash value when presented
              with the same input.
    !*/

// ----------------------------------------------------------------------------------------

    inline uint32 hash (
        uint64 item,
        uint32 seed = 0
    );
    /*!
        ensures
            - returns a 32bit hash of the data stored in item.
            - Each value of seed results in a different hash function being used.
              (e.g. hash(item,0) should generally not be equal to hash(item,1))
            - uses the murmur_hash3_128bit_3() routine to compute the actual hash.
            - This routine will always give the same hash value when presented
              with the same input.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T, typename U>
    uint32 hash (
        const std::pair<T,U>& item,
        uint32 seed = 0
    );
    /*!
        requires
            - hash() is defined for objects of type T and U
        ensures
            - returns a 32bit hash of the data stored in item.
            - Each value of seed results in a different hash function being used.
              (e.g. hash(item,0) should generally not be equal to hash(item,1))
            - if (calling hash() on items of type T and U is always guaranteed to give the
              same hash values when presented with the same input) then
                - This routine will always give the same hash value when presented
                  with the same input.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_HAsH_ABSTRACT_Hh_


dlib C++ Library - find_k_nearest_neighbors_lsh_abstract.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_FIND_K_NEAREST_NEIGHBOrS_LSH_ABSTRACT_Hh_
#ifdef DLIB_FIND_K_NEAREST_NEIGHBOrS_LSH_ABSTRACT_Hh_

#include "../lsh/hashes_abstract.h"
#include "sample_pair_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type,
        typename hash_function_type
        >
    void hash_samples (
        const vector_type& samples,
        const hash_function_type& hash_funct,
        const unsigned long num_threads,
        std::vector<typename hash_function_type::result_type>& hashes
    );
    /*!
        requires
            - hash_funct() is threadsafe.  This means that it must be safe for multiple
              threads to invoke the member functions of hash_funct() at the same time.
            - vector_type is any container that looks like a std::vector or dlib::array.
            - hash_funct must be a function object with an interface compatible with the
              objects defined in dlib/lsh/hashes_abstract.h.  In particular, hash_funct
              must be capable of hashing the elements in the samples vector.
        ensures
            - This function hashes all the elements in samples and stores the results in
              hashes.  It will also use num_threads concurrent threads to do this.  You
              should set this value equal to the number of processing cores on your
              computer for maximum speed.
            - #hashes.size() == 0
            - for all valid i:
                - #hashes[i] = hash_funct(samples[i])
                  (i.e. #hashes[i] will contain the hash of samples[i])
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type,
        typename distance_function_type,
        typename hash_function_type,
        typename alloc
        >
    void find_k_nearest_neighbors_lsh (
        const vector_type& samples,
        const distance_function_type& dist_funct,
        const hash_function_type& hash_funct,
        const unsigned long k,
        const unsigned long num_threads,
        std::vector<sample_pair, alloc>& edges,
        const unsigned long k_oversample = 20
    );
    /*!
        requires
            - hash_funct and dist_funct are threadsafe.  This means that it must be safe
              for multiple threads to invoke the member functions of these objects at the
              same time.
            - k > 0
            - k_oversample > 0
            - dist_funct(samples[i], samples[j]) must be a valid expression that evaluates
              to a floating point number
            - vector_type is any container that looks like a std::vector or dlib::array.
            - hash_funct must be a function object with an interface compatible with the
              objects defined in dlib/lsh/hashes_abstract.h.  In particular, hash_funct
              must be capable of hashing the elements in the samples vector.
        ensures
            - This function computes an approximate form of a k nearest neighbors graph of
              the elements in samples.  In particular, the way it works is that it first
              hashes all elements in samples using the provided locality sensitive hash
              function hash_funct().  Then it performs an exact k nearest neighbors on the
              hashes which can be done very quickly.  For each of these neighbors we
              compute the true distance using dist_funct() and the k nearest neighbors for
              each sample are stored into #edges.
            - Note that samples with an infinite distance between them are considered to be
              not connected at all. Therefore, we exclude edges with such distances from
              being output.
            - for all valid i:
                - #edges[i].distance() == dist_funct(samples[#edges[i].index1()], samples[#edges[i].index2()])
                - #edges[i].distance() < std::numeric_limits<double>::infinity()
            - contains_duplicate_pairs(#edges) == false
            - This function will use num_threads concurrent threads of processing.  You
              should set this value equal to the number of processing cores on your
              computer for maximum speed.
            - The hash based k nearest neighbor step is approximate, however, you can
              improve the output accuracy by using a larger k value for this first step.
              Therefore, this function finds k*k_oversample nearest neighbors during the
              first hashing based step.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_FIND_K_NEAREST_NEIGHBOrS_LSH_ABSTRACT_Hh_


dlib C++ Library - hashes_abstract.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_LSH_HAShES_ABSTRACT_Hh_
#ifdef DLIB_LSH_HAShES_ABSTRACT_Hh_

#include "../matrix.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class hash_similar_angles_64
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is a tool for computing locality sensitive hashes that give
                vectors with small angles between each other similar hash values.  In
                particular, this object creates 64 random planes which pass though the
                origin and uses them to create a 64bit hash.  To compute the hash for a new
                vector, this object checks which side of each plane the vector falls on and
                records this information into a 64bit integer.
        !*/

    public:

        hash_similar_angles_64 (
        );
        /*!
            ensures
                - #get_seed() == 0
        !*/

        hash_similar_angles_64 (
            const uint64 seed
        );
        /*!
            ensures
                - #get_seed() == seed
        !*/

        uint64 get_seed (
        ) const;
        /*!
            ensures
                - returns the random seed used to generate the random planes used for
                  hashing.
        !*/

        typedef uint64 result_type;

        template <typename vector_type>
        result_type perator() (
            const vector_type& v
        ) const;
        /*!
            requires
                - v is an unsorted sparse vector or a dlib matrix representing either a
                  column or row vector.
            ensures
                - returns a 64 bit hash of the input vector v.  The bits in the hash record
                  which side of each random plane v falls on.

        !*/

        unsigned int distance (
            const result_type& a,
            const result_type& b
        ) const;
        /*!
            ensures
                - returns the Hamming distance between the two hashes given to this
                  function.  That is, we return the number of bits in a and b which differ.
        !*/
    };

// ----------------------------------------------------------------------------------------

    struct hash_similar_angles_128
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is a tool for computing locality sensitive hashes that give
                vectors with small angles between each other similar hash values.  In
                particular, this object creates 128 random planes which pass though the
                origin and uses them to create a 128bit hash.  To compute the hash for a new
                vector, this object checks which side of each plane the vector falls on and
                records this information into a 128bit integer.
        !*/

    public:

        hash_similar_angles_128 (
        );
        /*!
            ensures
                - #get_seed() == 0
        !*/

        hash_similar_angles_128 (
            const uint64 seed
        );
        /*!
            ensures
                - #get_seed() == seed
        !*/

        uint64 get_seed (
        ) const;
        /*!
            ensures
                - returns the random seed used to generate the random planes used for
                  hashing.
        !*/

        typedef std::pair<uint64,uint64> result_type;

        template <typename vector_type>
        result_type perator() (
            const vector_type& v
        ) const;
        /*!
            requires
                - v is an unsorted sparse vector or a dlib matrix representing either a
                  column or row vector.
            ensures
                - returns a 128 bit hash of the input vector v.  The bits in the hash record
                  which side of each random plane v falls on.

        !*/

        unsigned int distance (
            const result_type& a,
            const result_type& b
        ) const;
        /*!
            ensures
                - returns the Hamming distance between the two hashes given to this
                  function.  That is, we return the number of bits in a and b which differ.
        !*/

    };

// ----------------------------------------------------------------------------------------

    struct hash_similar_angles_256
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is a tool for computing locality sensitive hashes that give
                vectors with small angles between each other similar hash values.  In
                particular, this object creates 256 random planes which pass though the
                origin and uses them to create a 256bit hash.  To compute the hash for a new
                vector, this object checks which side of each plane the vector falls on and
                records this information into a 256bit integer.
        !*/

    public:

        hash_similar_angles_256 (
        );
        /*!
            ensures
                - #get_seed() == 0
        !*/

        hash_similar_angles_256 (
            const uint64 seed
        );
        /*!
            ensures
                - #get_seed() == seed
        !*/

        uint64 get_seed (
        ) const;
        /*!
            ensures
                - returns the random seed used to generate the random planes used for
                  hashing.
        !*/

        typedef std::pair<uint64,uint64> hash128_type;
        typedef std::pair<hash128_type,hash128_type> result_type;

        template <typename vector_type>
        result_type perator() (
            const vector_type& v
        ) const;
        /*!
            requires
                - v is an unsorted sparse vector or a dlib matrix representing either a
                  column or row vector.
            ensures
                - returns a 256 bit hash of the input vector v.  The bits in the hash record
                  which side of each random plane v falls on.

        !*/

        unsigned int distance (
            const result_type& a,
            const result_type& b
        ) const;
        /*!
            ensures
                - returns the Hamming distance between the two hashes given to this
                  function.  That is, we return the number of bits in a and b which differ.
        !*/

    };

// ----------------------------------------------------------------------------------------

    struct hash_similar_angles_512
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is a tool for computing locality sensitive hashes that give
                vectors with small angles between each other similar hash values.  In
                particular, this object creates 512 random planes which pass though the
                origin and uses them to create a 512bit hash.  To compute the hash for a new
                vector, this object checks which side of each plane the vector falls on and
                records this information into a 512bit integer.
        !*/

    public:

        hash_similar_angles_512 (
        );
        /*!
            ensures
                - #get_seed() == 0
        !*/

        hash_similar_angles_512 (
            const uint64 seed
        );
        /*!
            ensures
                - #get_seed() == seed
        !*/

        uint64 get_seed (
        ) const;
        /*!
            ensures
                - returns the random seed used to generate the random planes used for
                  hashing.
        !*/

        typedef hash_similar_angles_256::result_type hash256_type;
        typedef std::pair<hash256_type,hash256_type> result_type;

        template <typename vector_type>
        result_type perator() (
            const vector_type& v
        ) const;
        /*!
            requires
                - v is an unsorted sparse vector or a dlib matrix representing either a
                  column or row vector.
            ensures
                - returns a 512 bit hash of the input vector v.  The bits in the hash record
                  which side of each random plane v falls on.

        !*/

        unsigned int distance (
            const result_type& a,
            const result_type& b
        ) const;
        /*!
            ensures
                - returns the Hamming distance between the two hashes given to this
                  function.  That is, we return the number of bits in a and b which differ.
        !*/

    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_LSH_HAShES_ABSTRACT_Hh_


dlib C++ Library - md5_kernel_abstract.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_MD5_KERNEl_ABSTRACT_
#ifdef DLIB_MD5_KERNEl_ABSTRACT_

#include <string>
#include <iosfwd>

namespace dlib
{

    /*!
        NOTE:
        This is the RSA Data Security, Inc. MD5 Message-Digest Algorithm
        as described in rfc1321

        For the functions which return a unsigned char*.  The array contains
        the 16 bytes of the digest and are in the correct order.
        i.e.  output[0], output[1], output[2], ...
    !*/

// ----------------------------------------------------------------------------------------

    const std::string md5 (
        const std::string& input
    );
    /*!
        ensures
            - returns the md5 digest of input as a hexadecimal string
    !*/

// ----------------------------------------------------------------------------------------

    void md5 (
        const unsigned char* input,
        unsigned long len,
        unsigned char* output
    );
    /*!
        requires
            - input  == pointer to len bytes
            - output == pointer to 16 bytes
            - input != output
        ensures
            - #output == the md5 digest of input.
    !*/

// ----------------------------------------------------------------------------------------

    const std::string md5 (
        std::istream& input
    );
    /*!
        requires
            - input.fail() == false
        ensures
            - returns the md5 digest of input as a hexadecimal string
            - #input.eof()     == true
            - #input.fail()    == false
    !*/

// ----------------------------------------------------------------------------------------

    void md5 (
        std::istream& input
        unsigned char* output
    );
    /*!
        requires
            - input.fail() == false
            - output       == pointer to 16 bytes
        ensures
            - #output       == the md5 digest of input
            - #input.eof()  == true
            - #input.fail() == false
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MD5_KERNEl_ABSTRACT_


dlib C++ Library - murmur_hash3_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_MURMUR_HAsH_3_ABSTRACT_Hh_
#ifdef DLIB_MURMUR_HAsH_3_ABSTRACT_Hh_

#include "../uintn.h"
#include <utility>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    uint32 murmur_hash3 (
        const void* key,
        const int len,
        const uint32 seed = 0
    );
    /*!
        requires
            - key == a pointer to a block of memory len bytes long
        ensures
            - returns a 32bit hash of the len bytes pointed to by key.
            - Each value of seed results in a different hash function being used.
              (e.g. murmur_hash3(key,len,0) should generally not be equal to murmur_hash3(key,len,1))
            - This function is machine architecture agnostic and should always give the same
              hash value when presented with the same inputs.
            - This hashing algorithm is Austin Appleby's excellent MurmurHash3_x86_32.
              See: http://code.google.com/p/smhasher/
    !*/

// ----------------------------------------------------------------------------------------

    inline uint32 murmur_hash3_2 (
        const uint32 v1,
        const uint32 v2
    );
    /*!
        ensures
            - returns a 32bit hash of the two integers given to this function.
            - This function is machine architecture agnostic and should always give the same
              hash value when presented with the same inputs.
            - This hashing algorithm is Austin Appleby's excellent MurmurHash3_x86_32.
              See: http://code.google.com/p/smhasher/
    !*/

// ----------------------------------------------------------------------------------------

    inline uint32 murmur_hash3_3 (
        const uint32 v1,
        const uint32 v2,
        const uint32 v3
    );
    /*!
        ensures
            - returns a 32bit hash of the three integers given to this function.
            - This function is machine architecture agnostic and should always give the same
              hash value when presented with the same inputs.
            - This hashing algorithm is Austin Appleby's excellent MurmurHash3_x86_32.
              See: http://code.google.com/p/smhasher/
    !*/

// ----------------------------------------------------------------------------------------

    std::pair<uint64,uint64> murmur_hash3_128bit (
        const void* key,
        const int len,
        const uint32 seed = 0
    );
    /*!
        requires
            - key == a pointer to a block of memory len bytes long
        ensures
            - returns a 128bit hash (as two 64bit numbers) of the len bytes pointed to by key.
            - Each value of seed results in a different hash function being used.
              (e.g. murmur_hash3_128bit(key,len,0) should generally not be equal to
              murmur_hash3_128bit(key,len,1))
            - This function is machine architecture agnostic and should always give the same
              hash value when presented with the same inputs.
            - This hashing algorithm is Austin Appleby's excellent MurmurHash3_x64_128.
              See: http://code.google.com/p/smhasher/
    !*/

// ----------------------------------------------------------------------------------------

    std::pair<uint64,uint64> murmur_hash3_128bit (
        const uint32& v1,
        const uint32& v2,
        const uint32& v3,
        const uint32& v4
    );
    /*!
        ensures
            - returns a 128bit hash (as two 64bit numbers) of the 4 integers given to this
              function.
            - This function is machine architecture agnostic and should always give the
              same hash value when presented with the same inputs.
            - This hashing algorithm is Austin Appleby's excellent MurmurHash3_x64_128.
              See: http://code.google.com/p/smhasher/
    !*/

// ----------------------------------------------------------------------------------------

    std::pair<uint64,uint64> murmur_hash3_128bit_3 (
        uint64 k1,
        uint64 k2,
        uint64 k3
    );
    /*!
        ensures
            - returns a 128bit hash (as two 64bit numbers) of the 3 integers given to this
              function.
            - This function is machine architecture agnostic and should always give the
              same hash value when presented with the same inputs.
            - This hashing algorithm is Austin Appleby's excellent MurmurHash3_x64_128.
              See: http://code.google.com/p/smhasher/
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MURMUR_HAsH_3_ABSTRACT_Hh_


dlib C++ Library - projection_hash_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_PROJECTION_HASh_ABSTRACT_Hh_
#ifdef DLIB_PROJECTION_HASh_ABSTRACT_Hh_

#include "../matrix.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class projection_hash
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is a tool for hashing elements of a vector space into the integers.
                It is intended to represent locality sensitive hashing functions such as
                the popular random projection hashing method.

                In particular, it represents hash functions of the form:
                    hash bit 0 = sign(rowm(P*v + O,0))
                    hash bit 1 = sign(rowm(P*v + O,1))
                    hash bit 2 = sign(rowm(P*v + O,2))
                    ...
                Where v is the vector to be hashed.  The parameters of the projection
                hash are the P and O matrices.

            THREAD SAFETY
                The const members of this object can be called concurrently from multiple
                threads, however, any operation that modifies the state of an instance of
                this object must serialize access to that instance.
        !*/
    public:

        projection_hash(
        );
        /*!
            ensures
                - #get_projection_matrix().size() == 0
                - #get_offset_matrix().size() == 0
        !*/

        template <typename EXP1, typename EXP2>
        projection_hash(
            const matrix_exp<EXP1>& proj,
            const matrix_exp<EXP2>& offset
        );
        /*!
            requires
                - proj.nr() == offset.nr()
            ensures
                - #get_projection_matrix() == proj
                - #get_offset_matrix() == offset
        !*/

        const matrix<double>& get_projection_matrix (
        ) const;
        /*!
            ensures
                - returns the P matrix discussed above in the WHAT THIS OBJECT REPRESENTS
                  section.
        !*/

        const matrix<double,0,1>& get_offset_matrix (
        ) const;
        /*!
            ensures
                - returns the O matrix discussed above in the WHAT THIS OBJECT REPRESENTS
                  section.
        !*/

        unsigned long num_hash_bins (
        ) const;
        /*!
            ensures
                - returns the number of possible outputs from this hashing function.
                - Specifically, returns: std::pow(2, get_offset_matrix().size())
        !*/

        template <typename EXP>
        unsigned long operator() (
            const matrix_exp<EXP>& v
        ) const;
        /*!
            requires
                - is_col_vector(v) == true
                - v.size() == get_projection_matrix().nc()
                - v.size() > 0
            ensures
                - hashes v into the range [0, num_hash_bins()) using the method
                  discussed in the WHAT THIS OBJECT REPRESENTS section.
        !*/
    };

// ----------------------------------------------------------------------------------------

    void serialize (
        const projection_hash& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

    void deserialize (
        projection_hash& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_PROJECTION_HASh_ABSTRACT_Hh_


dlib C++ Library - kalman_filter_abstract.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_KALMAN_FiLTER_ABSTRACT_Hh_
#ifdef DLIB_KALMAN_FiLTER_ABSTRACT_Hh_

#include "../serialize.h"
#include "../matrix.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        long states,
        long measurements
        >
    class kalman_filter
    {
        /*!
            REQUIREMENTS ON states
                states > 0

            REQUIREMENTS ON measurements
                measurements > 0

            WHAT THIS OBJECT REPRESENTS
                This object implements the Kalman filter, which is a tool for
                recursively estimating the state of a process given measurements
                related to that process.  To use this tool you will have to
                be familiar with the workings of the Kalman filter.  An excellent
                introduction can be found in the paper:
                    An Introduction to the Kalman Filter
                    by Greg Welch and Gary Bishop

        !*/

    public:

        kalman_filter(
        );
        /*!
            - #get_observation_model()    == 0
            - #get_transition_model()     == 0
            - #get_process_noise()        == 0
            - #get_measurement_noise()    == 0
            - #get_current_state()        == 0
            - #get_predicted_next_state() == 0
            - #get_current_estimation_error_covariance() == the identity matrix
        !*/

        void set_observation_model (
            const matrix<double,measurements,states>& H
        );
        /*!
            ensures
                - #get_observation_model() == H
        !*/

        void set_transition_model  (
            const matrix<double,states,states>& A
        );
        /*!
            ensures
                - #get_transition_model() == A
        !*/

        void set_process_noise     (
            const matrix<double,states,states>& Q
        );
        /*!
            ensures
                - #get_process_noise() == Q
        !*/

        void set_measurement_noise (
            const matrix<double,measurements,measurements>& R
        );
        /*!
            ensures
                - #get_measurement_noise() == R
        !*/

        void set_estimation_error_covariance (
            const matrix<double,states,states>& P
        );
        /*!
            ensures
                - #get_current_estimation_error_covariance() == P
                  (Note that you should only set this before you start filtering
                  since the Kalman filter will maintain the value of P on its own.
                  So only set this during initialization unless you are sure you
                  understand what you are doing.)
        !*/

        const matrix<double,measurements,states>& get_observation_model (
        ) const;
        /*!
            ensures
                - Returns the matrix "H" which relates process states x to measurements z.
                  The relation is linear, therefore, z = H*x.  That is, multiplying a
                  state by H gives the measurement you expect to observe for that state.
        !*/

        const matrix<double,states,states>& get_transition_model (
        ) const;
        /*!
            ensures
                - Returns the matrix "A" which determines how process states change over time.
                  The relation is linear, therefore, given a state vector x, the value you
                  expect it to have at the next time step is A*x.
        !*/

        const matrix<double,states,states>& get_process_noise (
        ) const;
        /*!
            ensures
                - returns the process noise covariance matrix.  You can think of this
                  covariance matrix as a measure of how wrong the assumption of
                  linear state transitions is.
        !*/

        const matrix<double,measurements,measurements>& get_measurement_noise (
        ) const;
        /*!
            ensures
                - returns the measurement noise covariance matrix.  That is, when we
                  measure a state x we only obtain H*x corrupted by Gaussian noise.
                  The measurement noise is the covariance matrix of this Gaussian
                  noise which corrupts our measurements.
        !*/

        void update (
        );
        /*!
            ensures
                - propagates the current state estimate forward in time one
                  time step.  In particular:
                    - #get_current_state() == get_predicted_next_state()
                    - #get_predicted_next_state() == get_transition_model()*get_current_state()
                    - #get_current_estimation_error_covariance() == the propagated value of this covariance matrix
        !*/

        void update (
            const matrix<double,measurements,1>& z
        );
        /*!
            ensures
                - propagates the current state estimate forward in time one time step.
                  Also applies a correction based on the given measurement z.  In particular:
                    - #get_current_state(), #get_predicted_next_state(), and
                      #get_current_estimation_error_covariance() are updated using the
                      Kalman filter method based on the new measurement in z.
        !*/

        const matrix<double,states,1>& get_current_state(
        ) const;
        /*!
            ensures
                - returns the current estimate of the state of the process.  This
                  estimate is based on all the measurements supplied to the update()
                  method.
        !*/

        const matrix<double,states,1>& get_predicted_next_state(
        ) const;
        /*!
            ensures
                - returns the next expected value of the process state.
                - Specifically, returns get_transition_model()*get_current_state()

        !*/

        const matrix<double,states,states>& get_current_estimation_error_covariance(
        ) const;
        /*!
            ensures
                - returns the current state error estimation covariance matrix.
                  This matrix captures our uncertainty about the value of get_current_state().
        !*/

    };

// ----------------------------------------------------------------------------------------

    void serialize (
        const kalman_filter& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

    void deserialize (
        kalman_filter& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_KALMAN_FiLTER_ABSTRACT_Hh_


dlib C++ Library - rls_filter_abstract.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_RLS_FiLTER_ABSTRACT_Hh_
#ifdef DLIB_RLS_FiLTER_ABSTRACT_Hh_

#include "../svm/rls_abstract.h"
#include "../matrix/matrix_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class rls_filter
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is a tool for doing time series prediction using linear
                recursive least squares.  In particular, this object takes a sequence
                of points from the user and, at each step, attempts to predict the
                value of the next point.

                To accomplish this, this object maintains a fixed size buffer of recent
                points.  Each prediction is a linear combination of the points in this
                history buffer.  It uses the recursive least squares algorithm to
                determine how to best combine the contents of the history buffer to
                predict each point.  Therefore, each time update() is called with
                a point, recursive least squares updates the linear combination weights,
                and then it inserts the point into the history buffer.  After that, the
                next prediction is based on these updated weights and the current history
                buffer.
        !*/

    public:

        rls_filter(
        );
        /*!
            ensures
                - #get_window_size() == 5
                - #get_forget_factor() == 0.8
                - #get_c() == 100
                - #get_predicted_next_state().size() == 0
        !*/

        explicit rls_filter (
            unsigned long size,
            double forget_factor = 0.8,
            double C = 100
        );
        /*!
            requires
                - 0 < forget_factor <= 1
                - 0 < C
                - size >= 2
            ensures
                - #get_window_size() == size
                - #get_forget_factor() == forget_factor
                - #get_c() == C
                - #get_predicted_next_state().size() == 0
        !*/

        double get_c(
        ) const;
        /*!
            ensures
                - returns the regularization parameter.  It is the parameter that determines
                  the trade-off between trying to fit the data points given to update() or
                  allowing more errors but hopefully improving the generalization of the
                  predictions.  Larger values encourage exact fitting while smaller values
                  of C may encourage better generalization.
        !*/

        double get_forget_factor(
        ) const;
        /*!
            ensures
                - This object uses exponential forgetting in its implementation of recursive
                  least squares.  Therefore, this function returns the "forget factor".
                - if (get_forget_factor() == 1) then
                    - In this case, exponential forgetting is disabled.
                    - The recursive least squares algorithm will implicitly take all previous
                      calls to update(z) into account when estimating the optimal weights for
                      linearly combining the history buffer into a prediction of the next point.
                - else
                    - Old calls to update(z) are eventually forgotten.  That is, the smaller
                      the forget factor, the less recursive least squares will care about
                      attempting to find linear combination weights which would have make
                      good predictions on old points.  It will care more about fitting recent
                      points.  This is appropriate if the statistical properties of the time
                      series we are modeling are not constant.
        !*/

        unsigned long get_window_size (
        ) const;
        /*!
            ensures
                - returns the size of the history buffer.  This is the number of points which
                  are linearly combine to make the predictions returned by get_predicted_next_state().
        !*/

        void update (
        );
        /*!
            ensures
                - Propagates the prediction forward in time.
                - In particular, the value in get_predicted_next_state() is inserted
                  into the history buffer and then the next prediction is estimated
                  based on this updated history buffer.
                - #get_predicted_next_state() == the prediction for the next point
                  in the time series.
        !*/

        template <typename EXP>
        void update (
            const matrix_exp<EXP>& z
        );
        /*!
            requires
                - is_col_vector(z) == true
                - z.size() != 0
                - if (get_predicted_next_state().size() != 0) then
                    - z.size() == get_predicted_next_state().size()
                      (i.e. z must be the same size as all the previous z values given
                      to this function)
            ensures
                - Updates the state of this filter based on the current measurement in z.
                - In particular, the filter weights are updated and z is inserted into
                  the history buffer.  Then the next prediction is estimated based on
                  these updated weights and history buffer.
                - #get_predicted_next_state() == the prediction for the next point
                  in the time series.
                - #get_predicted_next_state().size() == z.size()
        !*/

        const matrix<double,0,1>& get_predicted_next_state(
        );
        /*!
            ensures
                - returns the estimate of the next point we will observe in the
                  time series data.
        !*/

    };

// ----------------------------------------------------------------------------------------

    void serialize (
        const rls_filter& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

    void deserialize (
        rls_filter& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_RLS_FiLTER_ABSTRACT_Hh_


dlib C++ Library - API Wrappers

The Library
  • Algorithms
  • API Wrappers
  • Bayesian Nets
  • Compression
  • Containers
  • Graph Tools
  • Image Processing
  • Linear Algebra
  • Machine Learning
  • Metaprogramming
  • Miscellaneous
  • Networking
  • Optimization
  • Parsing

Help/Info
  • Dlib Blog
  • Examples: C++
    • 3D Point Cloud
    • Assignment Learning
    • Base64 Encoder
    • Bayesian Network From Disk
    • Bayesian Network GUI
    • Bayesian Network
    • Bridge
    • BSP
    • C-Support Vector Machine
    • Cmd Line Parser
    • Compress Stream
    • Config File Reader
    • Custom Trainers
    • Directory Navigation
    • Empirical Kernel Map
    • Face Detection
    • Face Landmark Detection
    • FHOG Feature Extraction
    • FHOG Object Detection
    • Graph Labeling
    • GUI
    • Hough Transform
    • HTTP Server
    • Image
    • IO Socket Streams
    • IO Streams Server
    • Kernel Centroid
    • Kernel K-Means Clustering
    • Kernel Ridge Regression
    • Kernel RLS Filtering
    • Kernel RLS Regression
    • KRR Classification
    • Learning to Track
    • Linear Assignment Problems
    • Linear Manifold Regularizer
    • Linear Model Predictive Control
    • Logger Advanced
    • Logger Custom Output
    • Logger
    • Matrix Expressions
    • Matrix
    • Member Function Pointer
    • Model Selection
    • Multiclass Classification
    • Multithreaded Object
    • Neural Network
    • Non-Linear Least Squares
    • Nu-Support Vector Machine
    • Numerical Integration
    • Object Detector Advanced
    • Object Detector
    • One Class Classifiers
    • Online SVM
    • Optimization
    • Parallel For Loops
    • Pipe 2
    • Pipe
    • Quantum Computing
    • Queue
    • Rank Features
    • Relevance Vector Classification
    • Relevance Vector Regression
    • Running Stats
    • Sequence Labeling
    • Sequence Segmentation
    • Sockets
    • Sockstreambuf
    • Sparse Vectors
    • SQLite
    • Std C++ Allocator
    • Structural Support Vector Machines
    • Support Vector Regression
    • SURF
    • SVM-Rank
    • Thread Function
    • Thread Pool
    • Threaded Object
    • Threads
    • Timer
    • Train Object Detector
    • Train Shape Predictor
    • Using Custom Kernels
    • Video Object Tracking
    • Webcam Face Pose Estimation
    • XML Parser
  • Examples: Python
    • Face Detector
    • Face Landmark Detection
    • find candidate object locations
    • Linear Assignment Problems
    • Sequence Segmenter
    • Structural Support Vector Machines
    • SVM-Rank
    • Train Object Detector
    • Train Shape Predictor
    • Video Object Tracking
  • FAQ
  • Forums
  • Home
  • How to compile
  • How to contribute
  • Index
  • Introduction
  • License
  • Python API
  • Suggested Books
  • Who uses dlib?

Current Release
  • Change Log
  • Release Notes
  • Version: 18.18

Last Modified:
Sep 13, 2015
API Wrappers

These wrappers provide a portable object oriented interface for networking, multithreading, GUI development, and file browsing. Programs written using them can be compiled under POSIX or MS Windows platforms without changing the code.

API
  • dir_nav
    • directory
    • file
    • file_exists
    • get_filesystem_roots
    • get_files_in_directory_tree
    • get_parent_directory
  • gui_core
    • base_window
    • canvas
    • get_from_clipboard
    • put_on_clipboard
  • gui_widgets
    • canvas drawing functions
      • draw_button_down
      • draw_button_up
      • draw_checkered
      • draw_circle
      • draw_image
      • draw_line
      • draw_pixel
      • draw_rectangle
      • draw_rounded_rectangle
      • draw_solid_circle
      • draw_solid_convex_polygon
      • draw_sunken_rectangle
      • fill_gradient_rounded
      • fill_rect
      • fill_rect_with_vertical_gradient
    • drawable
      • disable
      • disable_events
      • enable
      • enable_events
      • events
        • draw
        • on_focus_gained
        • on_focus_lost
        • on_keydown
        • on_mouse_down
        • on_mouse_enter
        • on_mouse_leave
        • on_mouse_move
        • on_mouse_up
        • on_string_put
        • on_user_event
        • on_wheel_down
        • on_wheel_up
        • on_window_moved
        • on_window_resized
      • events_are_enabled
      • hide
      • is_enabled
      • is_hidden
      • main_font
      • next_free_user_event_number
      • parent_window
      • set_main_font
      • set_pos
      • set_z_order
      • shape
        • bottom
        • get_rect
        • height
        • left
        • right
        • top
        • width
      • show
      • z_order
    • drawable_window
    • fonts
      • bdf_font
      • default_font
      • font
      • get_native_font
      • letter
    • styles
      • button_style
      • button_style_arrow
      • button_style_default
      • button_style_toolbar1
      • button_style_toolbar_icon1
      • list_box_style
      • list_box_style_default
      • scrollable_region_style
      • scrollable_region_style_default
      • scroll_bar_style
      • scroll_bar_style_default
      • text_box_style
      • text_box_style_default
      • text_field_style
      • text_field_style_default
      • toggle_button_style
      • toggle_button_style_check_box
      • toggle_button_style_default
      • toggle_button_style_radio_button
    • widgets
      • button
      • button_action
      • check_box
      • directed_graph_drawer
      • draggable
      • image_display
      • image_widget
      • image_window
      • label
      • list_box
      • menu_bar
      • menu_item
      • menu_item_separator
      • menu_item_submenu
      • menu_item_text
      • message_box
      • message_box_blocking
      • mouse_over_event
      • mouse_tracker
      • named_rectangle
      • open_existing_file_box
      • open_file_box
      • perspective_display
      • perspective_window
      • popup_menu
      • popup_menu_region
      • radio_button
      • save_file_box
      • scrollable_region
      • scroll_bar
      • tabbed_display
      • text_box
      • text_field
      • text_grid
      • toggle_button
      • tooltip
      • widget_group
      • zoomable_region
  • misc_api
    • create_directory
    • get_current_dir
    • locally_change_current_dir
    • set_current_dir
    • sleep
    • timestamper
  • sockets
    • extensions
      • close_gracefully
      • connect
      • is_ip_address
      • network_address
    • functions
      • create_connection
      • create_listener
      • get_local_hostname
      • hostname_to_ip
      • ip_to_hostname
    • objects
      • connection
      • listener
  • threads
    • create_new_thread
    • extensions
      • auto_mutex
      • auto_mutex_readonly
      • auto_unlock
      • auto_unlock_readonly
      • create_new_thread_extension
      • future
      • multithreaded_object
      • parallel_for
      • read_write_mutex
      • rmutex
      • rsignaler
      • threaded_object
      • thread_function
      • thread_pool
      • thread_specific_data
    • get_thread_id
    • is_dlib_thread
    • mutex
    • register_thread_end_handler
    • signaler
    • unregister_thread_end_handler

[top]

dir_nav

This is a set of objects that provide an easy and portable way to traverse a directory tree.

C++ Example Programs: dir_nav_ex.cpp
More Details...
#include <dlib/dir_nav.h>

Implementations:
dir_nav_kernel_1: MS Windows implementation
dir_nav_kernel_2: POSIX implementation

Extensions to dir_nav

dir_nav_extensions

This is just some miscellaneous extensions to the dir_nav component.

More Details...
[top]

gui_core

This is a set of objects and functions which provide a very basic framework for manipulating windows. It is intended to provide a portable interface which can be used to build a more complex windowing toolkit.
More Details...
#include <dlib/gui_core.h>

Implementations:
gui_core_kernel_1: MS Windows implementation
gui_core_kernel_2: X Windows implementation
[top]

gui_widgets

This component is a collection of various windowing widgets such as buttons, labels, text boxes, and so on. It also includes the drawable interface, drawable_window, and font handling objects. dlib/gui_widgets/widgets_abstract.h defines all of the high level graphical widgets provided by this component that can appear in a drawable_window. To view the specifications for the other members of this component look at dlib/gui_widgets/fonts_abstract.h, dlib/gui_widgets/drawable_abstract.h, and dlib/gui_widgets/base_widgets_abstract.h.

This component isn't actually a wrapper on top of OS APIs. Rather, it is implemented on top of the gui_core component. I put it on this page just because I expect that people would look here when searching for the sort of functionality provided by this component.

Primary widgets

C++ Example Programs: gui_api_ex.cpp, image_ex.cpp, 3d_point_cloud_ex.cpp, surf_ex.cpp, bayes_net_gui_ex.cpp
#include <dlib/gui_widgets.h>
[top]

misc_api

This is just a collection of miscellaneous APIs that were small/simple enough not to warrant their own module.
More Details...
#include <dlib/misc_api.h>

Implementations:
misc_api_kernel_1: MS Windows implementation
misc_api_kernel_2: POSIX implementation
[top]

sockets

This is a set of objects that provides an easy to use and object oriented interface for dealing with TCP networking. There are currently two implementations, one for UNIX and another for all versions of Windows after Windows95. Both provide the exact same interface so programs written with them can be recompiled on either platform without a problem.

You also may want to take note of the timeout object. It provides a mechanism which you can use to add a timeout to a network operation.

C++ Example Programs: iosockstream_ex.cpp, sockets_ex.cpp, sockstreambuf_ex.cpp, server_http_ex.cpp, server_iostream_ex.cpp
More Details...
#include <dlib/sockets.h>

Implementations:
sockets_kernel_1: MS Windows implementation
sockets_kernel_2: POSIX implementation

Extensions to sockets

sockets_extensions

This is just some miscellaneous extensions to the socket api.

More Details...
[top]

threads

This is a set of objects that provides an easy to use and object oriented interface for creating multi-threaded programs. There are currently two implementations, one for UNIX and another for any variant of MS Windows after Windows 95. Both provide the exact same interface so programs written with them can be recompiled on either platform without a problem.

You also probably want to take note of the pipe object. It provides an easy to use typesafe mechanism to send messages between threads.

C++ Example Programs: threads_ex.cpp, logger_ex_2.cpp, pipe_ex.cpp, multithreaded_object_ex.cpp, threaded_object_ex.cpp, thread_function_ex.cpp, thread_pool_ex.cpp
More Details...
#include <dlib/threads.h>

Implementations:
threads_kernel_1: MS Windows implementation
threads_kernel_2: POSIX implementation

Extensions to threads

auto_mutex

This extension adds a mechanism to automatically lock and unlock a mutex. Also note that this extension is included by dlib/threads.h so you don't have to include anything extra to get it.

C++ Example Programs: threads_ex.cpp More Details...
auto_mutex_readonly

This extension adds a mechanism to automatically perform a readonly lock and unlock of a read_write_mutex. Also note that this extension is included by dlib/threads.h so you don't have to include anything extra to get it.

More Details...
auto_unlock

This extension adds a mechanism to automatically unlock a mutex. Also note that this extension is included by dlib/threads.h so you don't have to include anything extra to get it.

More Details...
auto_unlock_readonly

This extension adds a mechanism to automatically remove a readonly unlock from a read_write_mutex. Also note that this extension is included by dlib/threads.h so you don't have to include anything extra to get it.

More Details...
create_new_thread_extension

This extension adds some templated overloads to the create_new_thread() function. They allow you to create new threads using member functions from a class. Also note that this extension is included by dlib/threads.h so you don't have to include anything extra to get it.

More Details...
multithreaded_object

This object represents a multithreaded object. It is similar to the threaded_object except it allows you to have many threads in a single object rather than just one.

C++ Example Programs: multithreaded_object_ex.cpp, pipe_ex.cpp More Details...
parallel_for

This is a set of functions for executing the contents of a for loop in parallel. It is useful for taking advantage of multi-processor systems.

C++ Example Programs: parallel_for_ex.cpp More Details...
read_write_mutex

This extension adds a mutex object that can perform both normal "write locks" as well as "readonly locks". See the specification for details. Also note that this extension is included by dlib/threads.h so you don't have to include anything extra to get it.

More Details...
rmutex

This extension adds a mutex object that can handle recursive calls to lock(). Also note that this extension is included by dlib/threads.h so you don't have to include anything extra to get it.

More Details...
rsignaler

This extension adds a signaler object that can be used with the rmutex object. Also note that this extension is included by dlib/threads.h so you don't have to include anything extra to get it.

More Details...
threaded_object

This extension represents a simple threaded object. It provides a convenient mechanism to create an object that contains a thread.

C++ Example Programs: threaded_object_ex.cpp More Details...
thread_function

This object represents a thread on a global C++ function. That is, it allows you to run a global function in its own thread.

C++ Example Programs: thread_function_ex.cpp More Details...
thread_pool

This object represents a fixed size group of threads which you can submit tasks to and then wait for those tasks to be completed. It also provides a future object that provides a container which allows you to safely pass objects into the tasks.

The implementation of this extension can be found here. It is implemented such that no memory allocations occur after the thread pool has been constructed so long as the user doesn't call any of the add_task_by_value() routines. The future object also doesn't perform any memory allocations or contain any system resources such as mutex objects.

C++ Example Programs: thread_pool_ex.cpp More Details...
thread_specific_data

This extension adds the ability to easily create thread specific data.

More Details...


dlib C++ Library - dir_nav_kernel_abstract.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_DIR_NAV_KERNEl_ABSTRACT_
#ifdef DLIB_DIR_NAV_KERNEl_ABSTRACT_

#include <string>
#include <vector>
#include "../uintn.h"
#include "../algs.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    /*!
        GENERAL WARNING
            Don't call any of these functions or make any of these objects
            before main() has been entered.   That means no instances
            of file or directory at the global scope.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename queue_of_dir
        >
    void get_filesystem_roots (
        queue_of_dir& roots
    );
    /*!
        requires
            - queue_of_dirs == an implementation of queue/queue_kernel_abstract.h with T
              set to directory or a std::vector<directory> or dlib::std_vector_c<directory>.
        ensures
            - #roots == a queue containing directories that represent all the roots
              of the filesystem on this machine.   (e.g. in windows you have c:\, d:\
              etc.)
        throws
            - std::bad_alloc
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // file object
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class file
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object represents a file.

                Note that the size of a file is determined at the time the file
                object is constructed.  Thus if a file changes sizes after its
                file object has been created its file object's size() method
                will not reflect the new file size.
        !*/

    public:

        class file_not_found : public error {};

        file (
        );
        /*!
            ensures
                - #*this has been properly initialized
                - #name() == ""
                - #full_name() == ""
                - #size() == 0
                - #*this does not represent any file
            throws
                - std::bad_alloc
        !*/

        file (
            const std::string& name
        );
        /*!
            ensures
                - #*this has been properly initialized
                - #*this represents the file given by name
                  Note that name can be a fully qualified path or just a path
                  relative to the current working directory.  Also, any symbolic
                  links in name will be resolved.
            throws
                - std::bad_alloc
                - file_not_found
                    This exception is thrown if the file can not be found or
                    accessed.
        !*/

        file (
            const char* name
        );
        /*!
            ensures
                - this function is identical to file(const std::string& name)
        !*/

        file (
            const file& item
        );
        /*!
            ensures
                - #*this == item
            throws
                - std::bad_alloc
        !*/

        ~file (
        );
        /*!
            ensures
                - all resources associated with *this have been released
        !*/

        const std::string& name (
        ) const;
        /*!
            ensures
                - returns the name of the file.  This is full_name() minus
                  the path to the file.
        !*/

        const std::string& full_name (
        ) const;
        /*!
            ensures
                - returns the fully qualified name for the file represented by *this
        !*/

        uint64 size (
        ) const;
        /*!
            ensures
                - returns the size of this file in bytes.
        !*/

        operator std::string (
        ) const;
        /*!
            ensures
                - returns full_name()
                  (i.e. provides an implicit conversion to string from dlib::file)
        !*/

        file& operator= (
            const file& rhs
        );
        /*!
            ensures
                - #*this == rhs
        !*/

        bool operator == (
            const file& rhs
        ) const;
        /*!
            ensures
                - if (*this and rhs represent the same file) then
                    - returns true
                - else
                    - returns false
        !*/

        bool operator != (
            const file& rhs
        ) const;
        /*!
            ensures
                - if (*this and rhs represent the same file) then
                    - returns false
                - else
                    - returns true
        !*/

        bool operator < (
            const file& item
        ) const;
        /*!
            ensures
                - if (full_name() < item.full_name()) then
                    - returns true
                - else
                    - returns false
        !*/

        void swap (
            file& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // directory object
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class directory
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object represents a directory in a file system.  It gives
                the ability to traverse a directory tree.

                Note that the directories . and .. are not returned by get_dirs()
        !*/

    public:

        class dir_not_found : public error {};
        class listing_error : public error {};

        directory (
        );
        /*!
            ensures
                - #*this has been properly initialized
                - #full_name() == ""
                - #name() == ""
                - #is_root() == true
                - #*this does not represent any directory
            throws
                - std::bad_alloc
        !*/

        directory (
            const std::string& name
        );
        /*!
            ensures
                - #*this has been properly initialized
                - #*this represents the directory given by name.
                  Note that name can be a fully qualified path or just a path
                  relative to the current working directory. Also, any symbolic
                  links in name will be resolved.
            throws
                - std::bad_alloc
                - dir_not_found
                    This exception is thrown if the directory can not be found or
                    accessed.
        !*/

        directory (
            const char* name
        );
        /*!
            ensures
                - this function is identical to directory(const std::string& name)
        !*/

        directory (
            const directory& item
        );
        /*!
            ensures
                - #*this == item
            throws
                - std::bad_alloc
        !*/

        ~directory (
        );
        /*!
            ensures
                - all resources associated with *this have been released
        !*/

        static char get_separator (
        );
        /*!
            ensures
                - returns the character used to separate directories and file names in a
                  path.  (i.e.  \ on windows and / in unix)
        !*/

        template <
            typename queue_of_files
            >
        void get_files (
            queue_of_files& files
        ) const;
        /*!
            requires
                - queue_of_files == an implementation of queue/queue_kernel_abstract.h with T
                  set to file or a std::vector<file> or dlib::std_vector_c<file>.
            ensures
                - #files == A queue containing all the files present in this directory.
                  (Note that symbolic links will not have been resolved in the names
                  of the returned files.)
                - #files.size() == the number of files in this directory
            throws
                - bad_alloc
                    If this exception is thrown then the call to get_files() has
                    no effect on *this and #files is unusable until files.clear()
                    is called and succeeds.
                - listing_error
                    This exception is thrown if listing access has been denied to this
                    directory or if some error occurred that prevented us from successfully
                    getting the contents of this directory.
                    If this exception is thrown then the call to get_files() has
                    no effect on *this and #files.size()==0.
        !*/

        std::vector<file> get_files (
        ) const;
        /*!
            ensures
                - This function simply calls get_files(temp_vector) and then returns temp_vector.
        !*/

        template <
            typename queue_of_dirs
            >
        void get_dirs (
            queue_of_dirs& dirs
        ) const;
        /*!
            requires
                - queue_of_dirs == an implementation of queue/queue_kernel_abstract.h with T
                  set to directory or a std::vector<directory> or dlib::std_vector_c<directory>.
            ensures
                - #dirs == a queue containing all the directories present in this directory.
                  (note that symbolic links will not have been resolved in the names
                  of the returned directories.)
                - #dirs.size() == the number of subdirectories in this directory
            throws
                - bad_alloc
                    If this exception is thrown then the call to get_files() has
                    no effect on *this and #files is unusable until files.clear()
                    is called and succeeds.
                - listing_error
                    This exception is thrown if listing access has been denied to this
                    directory or if some error occurred that prevented us from successfully
                    getting the contents of this directory.
                    If this exception is thrown then the call to get_dirs() has
                    no effect on *this and #dirs.size()==0.
        !*/

        std::vector<directory> get_dirs (
        ) const;
        /*!
            ensures
                - This function simply calls get_dirs(temp_vector) and then returns temp_vector.
        !*/

        bool is_root (
        ) const;
        /*!
            ensures
                - if (*this represents the root of this directory tree) then
                    - returns true
                - else
                    - returns false
        !*/

        const directory get_parent (
        ) const;
        /*!
            ensures
                - if (is_root()) then
                    - returns a copy of *this
                - else
                    - returns the parent directory of *this
            throws
                - bad_alloc
                    If this exception is thrown then the call to get_parent() will
                    have no effect.
        !*/

        const std::string& name (
        ) const;
        /*!
            ensures
                - if (is_root()) then
                    - returns ""
                - else
                    - returns the name of the directory.  This is full_name() minus
                      the path to the directory.
        !*/

        const std::string& full_name (
        ) const;
        /*!
            ensures
                - returns the fully qualified directory name for *this
                - if (is_root()) then
                    - the last character of #full_name() is get_separator()
                - else
                    - the last character of #full_name() is NOT get_separator()
        !*/

        operator std::string (
        ) const;
        /*!
            ensures
                - returns full_name()
                  (i.e. provides an implicit conversion to string from dlib::directory)
        !*/

        directory& operator= (
            const directory& rhs
        );
        /*!
            ensures
                - #*this == rhs
        !*/

        bool operator == (
            const directory& rhs
        ) const;
        /*!
            ensures
                - if (*this and rhs represent the same directory) then
                    - returns true
                - else
                    - returns false
        !*/

        bool operator != (
            const directory& rhs
        ) const;
        /*!
            ensures
                - if (*this and rhs represent the same directory) then
                    - returns false
                - else
                    - returns true
        !*/

        bool operator < (
            const directory& item
        ) const;
        /*!
            ensures
                - if (full_name() < item.full_name()) then
                    - returns true
                - else
                    - returns false
        !*/

        void swap (
            directory& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/

    };

// ----------------------------------------------------------------------------------------

    inline std::ostream& operator<< (
        std::ostream& out,
        const directory& item
    );
    /*!
        ensures
            - performs: out << item.full_name()
            - returns out
    !*/

    inline std::ostream& operator<< (
        std::ostream& out,
        const file& item
    );
    /*!
        ensures
            - performs: out << item.full_name()
            - returns out
    !*/

// ----------------------------------------------------------------------------------------

    inline void swap (
        file& a,
        file& b
    ) { a.swap(b); }
    /*!
        provides a global swap function for file objects
    !*/

// ----------------------------------------------------------------------------------------

    inline void swap (
        directory& a,
        directory& b
    ) { a.swap(b); }
    /*!
        provides a global swap function for directory objects
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_DIR_NAV_KERNEl_ABSTRACT_


dlib C++ Library - dir_nav_extensions_abstract.h

// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_DIR_NAV_EXTENSIONs_ABSTRACT_
#ifdef DLIB_DIR_NAV_EXTENSIONs_ABSTRACT_

#include <string>
#include <vector>
#include "dir_nav_kernel_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    bool file_exists (
        const std::string& filename
    );
    /*!
        ensures
            - if (a file with the given filename exists) then
                - returns true
            - else
                - returns false
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    const std::vector<file> get_files_in_directory_tree (
        const directory& top_of_tree,
        const T& add_file,
        unsigned long max_depth = 30
    );
    /*!
        requires
            - add_file must be a function object with the following prototype:
                bool add_file (file f);
        ensures
            - performs a recursive search through the directory top_of_tree and all
              its sub-directories (up to the given max depth).  All files in these
              directories are examined by passing them to add_file() and if it
              returns true then they will be included in the returned std::vector<file>
              object.
            - Note that a max_depth of 0 means that only the files in the directory
              top_of_tree will be considered.  A depth of 1 means that only files in
              top_of_tree and its immediate sub-directories will be considered.  And
              so on...
    !*/

// ----------------------------------------------------------------------------------------

    class match_ending
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is a simple function object that can be used with the
                above get_files_in_directory_tree() function.  This object
                just looks for files with a certain ending.
        !*/

    public:
        match_ending (
            const std::string& ending
        );
        /*!
            ensures
                - this object will be a function that checks if a file has a
                  name that ends with the given ending string.
        !*/

        bool operator() (
            const file& f
        ) const;
        /*!
            ensures
                - if (the file f has a name that ends with the ending string given
                  to this object's constructor) then
                    - returns true
                - else
                    - returns false
        !*/
    };

// ----------------------------------------------------------------------------------------

    class match_endings
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is a simple function object that can be used with the
                above get_files_in_directory_tree() function.  This object
                allows you to look for files with a number of different
                endings.
        !*/

    public:
        match_endings (
            const std::string& ending_list
        );
        /*!
            ensures
                - ending_list is interpreted as a whitespace separated list
                  of file endings.
                - this object will be a function that checks if a file has a
                  name that ends with one of the strings in ending_list.
        !*/

        bool operator() (
            const file& f
        ) const;
        /*!
            ensures
                - if (the file f has a name that ends with one of the ending strings
                  given to this object's constructor) then
                    - returns true
                - else
                    - returns false
        !*/
    };

// ----------------------------------------------------------------------------------------

    class match_all
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is a simple function object that can be used with the
                above get_files_in_directory_tree() function.  This object
                matches all files.
        !*/

    public:
        bool operator() (
            const file& f
        ) const;
        /*!
            ensures
                - returns true
                  (i.e. this function doesn't do anything.  It just says it
                  matches all files no matter what)
        !*/
    };

// ----------------------------------------------------------------------------------------

    directory get_parent_directory (
        const directory& dir
    );
    /*!
        ensures
            - returns the parent directory of dir.  In particular, this
              function returns the value of dir.get_parent()
    !*/

// ----------------------------------------------------------------------------------------

    directory get_parent_directory (
        const file& f
    );
    /*!
        ensures
            - if (f.full_name() != "") then
                - returns the directory which contains the given file
            - else
                - returns a default initialized directory (i.e. directory())
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_DIR_NAV_EXTENSIONs_ABSTRACT_


dlib C++ Library - gui_core_kernel_abstract.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net), Keita Mochizuki
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_GUI_CORE_KERNEl_ABSTRACT_
#ifdef DLIB_GUI_CORE_KERNEl_ABSTRACT_

#include <string>
#include "../algs.h"
#include "../geometry/rectangle_abstract.h"
#include "../unicode/unicode_abstract.h"

namespace dlib
{

    /*!
        OVERVIEW:
            This is a set of objects and functions which provide a very basic
            framework for manipulating windows.  It is intended to provide a
            portable interface which can be used to build a more complex windowing
            toolkit.

        EXCEPTIONS
            Do not let an exception leave any of the base_window event handlers.
            The results of doing so are undefined.

        THREAD SAFETY
            Event Handlers
                All event handlers are executed in a special event handling thread.
                This means that you must not do anything that will take a long time or
                block while in an event handler.  Doing so will freeze all event
                processing.

                Also, don't rely on get_thread_id() always returning the same ID from
                inside event handlers.

            canvas
                Never access a canvas object outside of the paint() callback
                that supplied it.  Only access a canvas object from the event
                handling thread.  After the paint() event handler has returned do
                not access that canvas object again.

            base_window
                All methods for this class are thread safe.  You may call them
                from any thread and do not need to serialize access.
    !*/

// ----------------------------------------------------------------------------------------

    void put_on_clipboard (
        const std::string& str
    );
    /*!
        ensures
            - posts the contents of str to the system clipboard
        throws
            - std::bad_alloc
            - dlib::gui_error
            - dlib::thread_error
    !*/

    // overloads for wide character strings
    void put_on_clipboard (const std::wstring& str);
    void put_on_clipboard (const dlib::ustring& str);

// ----------------------------------------------------------------------------------------

    void get_from_clipboard (
        std::string& str
    );
    /*!
        ensures
            - if (there is string data on the system clipboard) then
                - #str == the data from the clipboard
            - else
                - #str == ""
        throws
            - std::bad_alloc
            - dlib::gui_error
            - dlib::thread_error
    !*/

    // overloads for wide character strings
    void get_from_clipboard (std::wtring& str);
    void get_from_clipboard (dlib::utring& str);

// ----------------------------------------------------------------------------------------

    class canvas : public rectangle
    {
        /*!
            POINTERS AND REFERENCES TO INTERNAL DATA
                All functions of this object may invalidate pointers and references
                to internal data.

            INITIAL VALUE
                The initial value of each pixel is undefined.
                is_empty() == false

            WHAT THIS OBJECT REPRESENTS
                This object represents a rectangular area of a window that you
                can draw on.

                Each pixel can be accessed with the following syntax:
                    canvas_instance[y][x].red   == the red value for this pixel
                    canvas_instance[y][x].blue  == the blue value for this pixel
                    canvas_instance[y][x].green == the green value for this pixel

                The origin, i.e. (0,0), of the x,y coordinate plane of the canvas is in
                the upper left corner of the canvas.  Note that the upper left corner
                of the canvas appears at the point (left(),top()) in its window.
        !*/

    public:

        struct pixel
        {
            /*!
                WHAT THIS OBJECT REPRESENTS
                    This object represents a single pixel.  Each pixel's value
                    ranges from 0 to 255 with 0 indicating that the color is not
                    present in the pixel at all and 255 indicating that the color
                    is present in the pixel with maximum intensity.

                    Note that the structure, order, and size of of this struct are
                    implementation dependent.  It will always contain fields called
                    red, green, and blue but they may not be in that order and there
                    may be padding.

                    Also note that pixel_traits<> is defined for this pixel type,
                    thus you can use it in assign_pixel() calls.
            !*/
            unsigned char red;
            unsigned char green;
            unsigned char blue;
        };

        pixel* operator[] (
            unsigned long row
        ) const;
        /*!
            requires
                - row < height()
            ensures
                - returns an array of width() pixel structs that represents the given
                  row of pixels in the canvas.
        !*/

        void fill (
            unsigned char red,
            unsigned char green,
            unsigned char blue
        ) const;
        /*!
            ensures
                - for all valid values of x and y:
                    - (#*this)[y][x].red = red
                    - (#*this)[y][x].green = green
                    - (#*this)[y][x].blue = blue
        !*/

    private:

        // restricted functions
        canvas();        // normal constructor
        canvas(canvas&);        // copy constructor
        canvas& operator=(canvas&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------

    class base_window
    {

        /*!
            WHAT THIS OBJECT REPRESENTS
                This object represents a window on the desktop.  A window has a "client
                area" that is a region of the screen that you can draw whatever you like
                on.  You implement the paint() callback and use the canvas object to do
                this drawing.

            INITIAL STATE
                - The initial state of the window is to be hidden.  This means you need
                  to call show() to make it appear.
                - is_closed() == false

            paint() callback:
                This is where you will do all your drawing.  It is triggered when
                part of the window needs to be drawn/redrawn.

            mouse events:
                It is important to note a few things about the mouse events.  First,
                the on_mouse_move() event is not triggered for each pixel the mouse crosses
                but rather its frequency and precision is implementation dependent.

                Second, it is possible that a mouse button may be depressed but the
                corresponding button release event does not go to the window.  For instance,
                if the mouse is outside the window and some other application jumps to the
                top it is possible that the new application will receive any mouse button
                release events rather than the original window.  But the point is that
                you should not rely on always getting a button up event for every button
                down event.

            keydown event:
                Note that the existence of a typematic action (holding down a key
                and having it start to repeat itself after a moment) for each key is
                totally implementation dependent.  So don't rely on it for any key
                and conversely don't assume it isn't present either.

            The base_window::wm mutex
                This is a reference to a global rmutex.  All instances of base_window make
                reference to the same global rmutex.  It is used to synchronize access to
                the base_window to make it thread safe.  It is also always locked before
                an event handler is called.
        !*/

    public:

        enum on_close_return_code
        {
            DO_NOT_CLOSE_WINDOW,
            CLOSE_WINDOW
        };

        enum mouse_state_masks
        {
            /*!
                These constants represent the various buttons referenced by
                mouse events.
            !*/
            NONE = 0,
            LEFT = 1,
            RIGHT = 2,
            MIDDLE = 4,
            SHIFT = 8,
            CONTROL = 16
        };

        enum keyboard_state_masks
        {
            /*!
                These constants represent the various modifier buttons that
                could be in effect during a key press on the keyboard
            !*/
            KBD_MOD_NONE = 0,
            KBD_MOD_SHIFT = 1,
            KBD_MOD_CONTROL = 2,
            KBD_MOD_ALT = 4,
            KBD_MOD_META = 8,
            KBD_MOD_CAPS_LOCK = 16,
            KBD_MOD_NUM_LOCK = 32,
            KBD_MOD_SCROLL_LOCK = 64
        };

        enum non_printable_keyboard_keys
        {
            KEY_BACKSPACE,
            KEY_SHIFT,
            KEY_CTRL,
            KEY_ALT,
            KEY_PAUSE,
            KEY_CAPS_LOCK,
            KEY_ESC,
            KEY_PAGE_UP,
            KEY_PAGE_DOWN,
            KEY_END,
            KEY_HOME,
            KEY_LEFT,           // This is the left arrow key
            KEY_RIGHT,          // This is the right arrow key
            KEY_UP,             // This is the up arrow key
            KEY_DOWN,           // This is the down arrow key
            KEY_INSERT,
            KEY_DELETE,
            KEY_SCROLL_LOCK,

            // Function Keys
            KEY_F1,
            KEY_F2,
            KEY_F3,
            KEY_F4,
            KEY_F5,
            KEY_F6,
            KEY_F7,
            KEY_F8,
            KEY_F9,
            KEY_F10,
            KEY_F11,
            KEY_F12
        };

        base_window (
            bool resizable = true,
            bool undecorated = false
        );
        /*!
            requires
                - if (undecorated == true) then
                    - resizable == false
            ensures
                - #*this has been properly initialized
                - if (resizable == true) then
                    - this window will be resizable by the user
                - else
                    - this window will not be resizable by the user
                - if (undecorated == true) then
                    - this window will not have any graphical elements outside
                      of its drawable area or appear in the system task bar. It
                      also won't take the input focus from other windows.
                      (it is suitable for making things such as popup menus)
            throws
                - std::bad_alloc
                - dlib::thread_error
                - dlib::gui_error
                    This exception is thrown if there is an error while
                    creating this window.
        !*/

        virtual ~base_window (
        );
        /*!
            ensures
                - does NOT trigger the on_window_close() event
                - all resources associated with *this have been released
                - closes this window
        !*/

        void close_window (
        );
        /*!
            ensures
                - #is_closed() == true
                  (i.e. permanently closes this window.  The window is removed from the
                  screen and no more events will be dispatched to this window. )
                - does NOT trigger the on_window_close() event
        !*/

        void wait_until_closed (
        ) const;
        /*!
            ensures
                - blocks until is_closed() == true
        !*/

        bool is_closed (
        ) const;
        /*!
            ensures
                - returns true if this window has been closed, false otherwise.
                  (Note that closed windows do not receive any callbacks at all.
                   They are also not visible on the screen.)
        !*/

        void set_title (
            const std::string& title
        );
        /*!
            ensures
                - if (is_closed() == false) then
                    - sets the title of the window
        !*/

        void set_title (
            const std::wstring& title
        );
        /*!
            ensures
                - if (is_closed() == false) then
                    - sets the title of the window
        !*/

        void set_title (
            const dlib::ustring& title
        );
        /*!
            ensures
                - if (is_closed() == false) then
                    - sets the title of the window
        !*/

        virtual void show (
        );
        /*!
            ensures
                - if (is_closed() == false) then
                    - this window will appear on the screen
        !*/

        virtual void hide(
        );
        /*!
            ensures
                - if (is_closed() == false) then
                    - the window does not appear on the screen
        !*/

        void set_size (
            int width,
            int height
        );
        /*!
            ensures
                - if (is_closed() == false) then
                    - The width of the client area of this window is at least width
                      pixels.
                    - The height of the client area of this window is at least height
                      pixels.
                    - if (the window wasn't already this size) then
                        - triggers the on_window_resized() callback
        !*/

        void set_pos (
            long x,
            long y
        );
        /*!
            ensures
                - if (is_closed() == false) then
                    - sets the upper left corner of this window to the position (x,y)
                      on the desktop.  Note that the origin (0,0) is at the upper left
                      corner of the desktop.
        !*/

        void get_pos (
            long& x,
            long& y
        ) const;
        /*!
            ensures
                - if (is_closed() == false) then
                    - #x == the x coordinate of the upper left corner of the client area of
                      this window.
                    - #y == the y coordinate of the upper left corner of the client area of
                      this window.
                    - i.e. the point (#x,#y) on the desktop is coincident with the point
                      (0,0) in the client area of this window.
                - else
                    - #x == 0
                    - #y == 0
        !*/

        void get_size (
            unsigned long& width,
            unsigned long& height
        ) const;
        /*!
            ensures
                - if (is_closed() == false) then
                    - #width == the width of the client area of this window in pixels
                    - #height == the height of the client area of this window in pixels
                - else
                    - #width == 0
                    - #height == 0
        !*/

        void get_display_size (
            unsigned long& width,
            unsigned long& height
        ) const;
        /*!
            ensures
                - if (is_closed() == false) then
                    - #width == the width in pixels of the display device that contains this window
                    - #height == the height in pixels of the display device that contains this window
                - else
                    - #width == 0
                    - #height == 0
        !*/

        void invalidate_rectangle (
            const rectangle& rect
        );
        /*!
            ensures
                - if (is_closed() == false) then
                    - causes the area of this window defined by rect to become invalid.
                      This means that a paint() message will be dispatched to repaint
                      this area of the window.  Note that it is possible that the
                      resulting paint() message may include a bigger rectangle than
                      the one defined by rect.
        !*/

        void trigger_user_event (
            void* p,
            int i
        );
        /*!
            ensures
                - will never block (even if some other thread has a lock on the
                  global mutex referenced by wm.)
                - if (is_closed() == false) then
                    - causes the on_user_event() event to be called with
                      the given arguments.
        !*/

        void set_im_pos (
            long x_,
            long y_
        );
        /*!
            ensures
                - if (is_closed() == false) then
                    - sets the left-top position of input method rectangle used
                      for wide character input methods.
        !*/

    protected:
        const rmutex& wm;

        // let the window close by default
        virtual on_close_return_code on_window_close(
        ){return CLOSE_WINDOW;}
        /*!
            requires
                - is_closed() == false
                - mutex wm is locked
                - is called when the user attempts to close this window
                - if (this function returns CLOSE_WINDOW) then
                    - #is_closed() == true  (i.e. this window will be closed)
                    - it is safe to call "delete this;" inside on_window_close()
                      if *this was allocated on the heap and no one will try to
                      access *this anymore.
                - else
                    - this window will not be closed and the attempt to close it
                      by the user will have no effect.
                    - #is_closed() == false
            ensures
                - does not change the state of mutex wm
        !*/

        // do nothing by default
        virtual void on_user_event (
            void* p,
            int i
        ){}
        /*!
            requires
                - is_closed() == false
                - mutex wm is locked
                - is called whenever someone calls trigger_user_event()
            ensures
                - does not change the state of mutex wm
        !*/

        // do nothing by default
        virtual void on_window_resized(
        ){}
        /*!
            requires
                - is_closed() == false
                - mutex wm is locked
                - is called when this window is resized
            ensures
                - does not change the state of mutex wm
        !*/

        // do nothing by default
        virtual void on_window_moved(
        ){}
        /*!
            requires
                - is_closed() == false
                - mutex wm is locked
                - is called when this window's position changes
            ensures
                - does not change the state of mutex wm
        !*/

        // do nothing by default
        virtual void on_mouse_down (
            unsigned long btn,
            unsigned long state,
            long x,
            long y,
            bool is_double_click
        ){}
        /*!
            requires
                - is_closed() == false
                - mutex wm is locked
                - is called when the user depresses one of the mouse buttons
                - btn == the button that was depressed. (either LEFT, MIDDLE, or RIGHT)
                - state == the bitwise OR of the buttons that are currently depressed
                  excluding the button given by btn. (from the mouse_state_masks enum)
                - (x,y) == the position of the mouse (relative to the upper left corner
                  of the window) when this event occurred.  Note that the mouse may be
                  outside the window.
                - if (this is the second button press of a double click) then
                    - is_double_click == true
                - else
                    - is_double_click == false
            ensures
                - does not change the state of mutex wm
        !*/

        // do nothing by default
        virtual void on_mouse_up (
            unsigned long btn,
            unsigned long state,
            long x,
            long y
        ){}
        /*!
            requires
                - is_closed() == false
                - mutex wm is locked
                - is called when the user releases one of the mouse buttons
                - btn == the button that was released. (either LEFT, MIDDLE, or RIGHT)
                - state == the bitwise OR of the buttons that are currently depressed
                  (from the mouse_state_masks enum)
                - (x,y) == the position of the mouse (relative to the upper left corner
                  of the window) when this event occurred.  Note that the mouse may be
                  outside the window.
            ensures
                - does not change the state of mutex wm
        !*/

        // do nothing by default
        virtual void on_mouse_move (
            unsigned long state,
            long x,
            long y
        ){}
        /*!
            requires
                - is_closed() == false
                - mutex wm is locked
                - is called when the user moves the mouse
                - state == the bitwise OR of the buttons that are currently depressed
                  (from the mouse_state_masks enum)
                - (x,y) == the position of the mouse (relative to the upper left corner
                  of the window) when this event occurred.
                - if (the user is holding down one or more of the mouse buttons) then
                    - the mouse move events will continue to track the mouse even if
                      it goes out of the window.  This will continue until the user
                      releases all the mouse buttons.
            ensures
                - does not change the state of mutex wm
        !*/

        // do nothing by default
        virtual void on_mouse_leave (
        ){}
        /*!
            requires
                - is_closed() == false
                - mutex wm is locked
                - is called when the mouse leaves this window
            ensures
                - does not change the state of mutex wm
        !*/

        // do nothing by default
        virtual void on_mouse_enter (
        ){}
        /*!
            requires
                - is_closed() == false
                - mutex wm is locked
                - is called when the mouse enters this window
            ensures
                - does not change the state of mutex wm
        !*/

        // do nothing by default
        virtual void on_focus_gained (
        ){}
        /*!
            requires
                - is_closed() == false
                - mutex wm is locked
                - is called when this window gains input focus
            ensures
                - does not change the state of mutex wm
        !*/

        // do nothing by default
        virtual void on_focus_lost (
        ){}
        /*!
            requires
                - is_closed() == false
                - mutex wm is locked
                - is called when this window loses input focus
            ensures
                - does not change the state of mutex wm
        !*/

        // do nothing by default
        virtual void on_wheel_up (
            unsigned long state
        ){}
        /*!
            requires
                - is_closed() == false
                - mutex wm is locked
                - is called every time the mouse wheel is scrolled up one notch
                - state == the bitwise OR of the buttons that are currently depressed
                  (from the mouse_state_masks enum)
            ensures
                - does not change the state of mutex wm
        !*/

        // do nothing by default
        virtual void on_wheel_down (
            unsigned long state
        ){}
        /*!
            requires
                - is_closed() == false
                - mutex wm is locked
                - is called every time the mouse wheel is scrolled down one notch
                - state == the bitwise OR of the buttons that are currently depressed
                  (from the mouse_state_masks enum)
            ensures
                - does not change the state of mutex wm
        !*/

        // do nothing by default
        virtual void on_keydown (
            unsigned long key,
            bool is_printable,
            unsigned long state
        ){}
        /*!
            requires
                - is_closed() == false
                - mutex wm is locked
                - is called when a keyboard key is pressed or if a key is held
                  down then this is called repeatedly at a certain rate once the
                  typematic action begins (note that some keys might not have any
                  typematic action on some platforms).
                - if (is_printable) then
                    - key == the character that was pressed. (e.g. 'a', 'b', '1' etc.)
                    - this is a printable character.  Note that ' ', '\t', and
                      '\n' (this is the return/enter key) are all considered printable.
                - else
                    - key == one of the non_printable_keyboard_keys enums.
                - state == the bitwise OR of the keyboard modifiers that are currently
                  depressed (taken from keyboard_state_masks).
                - if (key is not in the range 'a' to 'z' or 'A' to 'Z') then
                    - if (the shift key was down when this key was pressed) then
                        - (state & KBD_MOD_SHIFT) != 0
                    - else
                        - (state & KBD_MOD_SHIFT) == 0
                - else
                    - the state of the shift key is implementation defined
            ensures
                - does not change the state of mutex wm
        !*/

        virtual void on_string_put (
            const std::wstring &str
        ){}
        /*!
            requires
                - is_closed() == false
                - mutex wm is locked
                - is called when a wide/multibyte character input method determines a string
                  that is being input to the window.
                - str == the string that is being input
            ensures
                - does not change the state of mutex wm
        !*/

    private:

        virtual void paint (
            const canvas& c
        ) =0;
        /*!
            requires
                - is_closed() == false
                - mutex wm is locked
                - is called when part of the window needs to be repainted for
                  any reason.
                - c == a canvas object that represents the invalid area of this
                  window which needs to be painted.
            ensures
                - does not change the state of mutex wm
        !*/

        base_window(base_window&);        // copy constructor
        base_window& operator=(base_window&);    // assignment operator

    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_GUI_CORE_KERNEl_ABSTRACT_


dlib C++ Library - canvas_drawing_abstract.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net), and Nils Labugt
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_GUI_CANVAS_DRAWINg_ABSTRACT_
#ifdef DLIB_GUI_CANVAS_DRAWINg_ABSTRACT_

#include "../gui_core.h"
#include "../pixel.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename pixel_type
        >
    void draw_line (
        const canvas& c,
        const point& p1,
        const point& p2,
        const pixel_type& pixel = rgb_pixel(0,0,0),
        const rectangle& area = rectangle(-infinity,-infinity,infinity,infinity)
    );
    /*!
        requires
            - pixel_traits<pixel_type> is defined
        ensures
            - draws the part of the line from p1 to p1 that overlaps with
              the canvas and area onto the canvas.
            - Uses the given pixel color.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename pixel_type
        >
    void draw_rectangle (
        const canvas& c,
        rectangle rect,
        const pixel_type& pixel = rgb_pixel(0,0,0),
        const rectangle& area = rectangle(-infinity,-infinity,infinity,infinity)
    );
    /*!
        requires
            - pixel_traits<pixel_type> is defined
        ensures
            - Draws the part of the rectangle that overlaps with
              the canvas and area onto the canvas.
            - Uses the given pixel color.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename pixel_type
        >
    void draw_circle (
        const canvas& c,
        const point& center_point,
        double radius,
        const pixel_type& pixel = rgb_pixel(0,0,0),
        const rectangle& area = rectangle(-infinity,-infinity,infinity,infinity)
    );
    /*!
        requires
            - pixel_traits<pixel_type> is defined
        ensures
            - draws the part of the circle centered at center_point with the given radius
              that overlaps with the canvas and area onto the canvas.
            - Uses the given pixel color.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename pixel_type
        >
    void draw_pixel (
        const canvas& c,
        const point& p,
        const pixel_type& pixel
    );
    /*!
        requires
            - pixel_traits<pixel_type> is defined
        ensures
            - if (c.contains(p)) then
                - sets the pixel in c that represents the point p to the
                  given pixel color.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename pixel_type
        >
    void draw_solid_circle (
        const canvas& c,
        const point& center_point,
        double radius,
        const pixel_type& pixel = rgb_pixel(0,0,0),
        const rectangle& area = rectangle(-infinity,-infinity,infinity,infinity)
    );
    /*!
        requires
            - pixel_traits<pixel_type> is defined
        ensures
            - draws the part of the solid circle centered at center_point with the given
              radius that overlaps with the canvas and area onto the canvas.
              ("solid" means that the interior is also filled in with the given
              pixel color)
            - Uses the given pixel color.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename pixel_type
        >
    void draw_solid_convex_polygon (
        const canvas& c,
        const std::vector<point>& polygon,
        const pixel_type& pixel = rgb_pixel(0,0,0),
        const rectangle& area = rectangle(-infinity,-infinity,infinity,infinity)
    );
    /*!
        requires
            - pixel_traits<pixel_type> is defined
        ensures
            - Interprets the given std::vector polygon object as defining a convex polygon
              shape.  In particular, the polygon is given by taking the points and drawing
              lines between them.  That is, imagine drawing a line connecting polygon[i]
              and polygon[(i+1)%polygon.size()], for all valid i, and then filling in the
              interior of the polygon.  That is what this function does.
            - When drawing the polygon, only the part of the polygon which overlaps both
              the given canvas and area rectangle is drawn.
            - Uses the given pixel color to draw the polygon.
    !*/

// ----------------------------------------------------------------------------------------

    void draw_button_down (
        const canvas& c,
        const rectangle& btn,
        unsigned char alpha = 255
    );
    /*!
        requires
            - 0 <= alpha <= 255
        ensures
            - draws the border of a button onto canvas c:
                - the border will be that of a button that is depressed
                - only the part of the border that overlaps with the canvas object
                  will be drawn.
                - the border will be for the button whose area is defined by the
                  rectangle btn.
            - performs alpha blending such that the button is drawn with full opacity
              when alpha is 255 and fully transparent when alpha is 0.
    !*/

// ----------------------------------------------------------------------------------------

    void draw_sunken_rectangle (
        const canvas& c,
        const rectangle& border,
        unsigned char alpha = 255
    );
    /*!
        requires
            - 0 <= alpha <= 255
        ensures
            - draws a sunken rectangle around the given border.
              (This is the type of border used for text_fields and
              check_boxes and the like).
            - performs alpha blending such that the rectangle is drawn with full opacity
              when alpha is 255 and fully transparent when alpha is 0.
    !*/

// ----------------------------------------------------------------------------------------

    void draw_button_up (
        const canvas& c,
        const rectangle& btn,
        unsigned char alpha = 255
    );
    /*!
        requires
            - 0 <= alpha <= 255
        ensures
            - draws the border of a button onto canvas c:
                - the border will be that of a button that is NOT depressed
                - only the part of the border that overlaps with the canvas object
                  will be drawn.
                - the border will be for the button whose area is defined by the
                  rectangle btn.
            - performs alpha blending such that the button is drawn with full opacity
              when alpha is 255 and fully transparent when alpha is 0.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename pixel_type
        >
    void draw_checkered (
        const canvas& c,
        const rectangle& area,
        const pixel_type& pixel1,
        const pixel_type& pixel2
    );
    /*!
        requires
            - pixel_traits<pixel_type> is defined
        ensures
            - fills the area on the given canvas defined by the rectangle area with a checkers
              board pattern where every other pixel gets assigned either pixel1 or pixel2.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    void draw_image (
        const canvas& c
        const point& p,
        const image_type& image,
        const rectangle& area = rectangle(-infinity,-infinity,infinity,infinity)
    );
    /*!
        requires
            - image_type == an implementation of array2d/array2d_kernel_abstract.h
            - pixel_traits<typename image_type::type> is defined
        ensures
            - draws the given image object onto the canvas such that the upper left corner of the
              image will appear at the point p in the canvas's window.  (note that the
              upper left corner of the image is assumed to be the pixel image[0][0] and the
              lower right corner of the image is assumed to be image[image.nr()-1][image.nc()-1])
            - only draws the part of the image that overlaps with the area rectangle
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    void draw_image (
        const canvas& c,
        const rectangle& rect,
        const image_type& img,
        const rectangle& area = rectangle(-infinity,-infinity,infinity,infinity)
    );
    /*!
        requires
            - image_type == an implementation of array2d/array2d_kernel_abstract.h
            - pixel_traits<typename image_type::type> is defined
        ensures
            - draws the given image object onto the canvas such that the upper left corner
              of the image will appear at the point rect.tl_corner() in the canvas's window
              and the lower right corner of the image will appear at rect.br_corner() in
              the canvas's window.  (note that the upper left corner of the image is
              assumed to be the pixel image[0][0] and the lower right corner of the image
              is assumed to be image[image.nr()-1][image.nc()-1])
            - only draws the part of the image that overlaps with the area rectangle
            - Uses nearest neighbor interpolation when the given rect isn't the same size
              as the input image.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename pixel_type
        >
    void fill_rect (
        const canvas& c,
        const rectangle& rect,
        const pixel_type& pixel
    );
    /*!
        requires
            - pixel_traits<pixel_type> is defined
        ensures
            - fills the area defined by rect in the given canvas with the given pixel color.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename pixel_type
        >
    void fill_rect_with_vertical_gradient (
        const canvas& c,
        const rectangle& rect,
        const pixel_type& pixel_top,
        const pixel_type& pixel_bottom,
        const rectangle& area = rectangle(-infinity,-infinity,infinity,infinity)
    );
    /*!
        requires
            - pixel_traits<pixel_type> is defined
        ensures
            - fills the rectangle defined by rect in the given canvas with the given colors.
              The top of the area will have the pixel_top color and will slowly fade
              towards the pixel_bottom color towards the bottom of rect.
            - only draws the part of the image that overlaps with the area rectangle
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename pixel_type
        >
    void fill_gradient_rounded (
        const canvas& c,
        const rectangle& rect,
        unsigned long radius,
        const pixel_type& top_color,
        const pixel_type& bottom_color,
        const rectangle& area = rectangle(-infinity,-infinity,infinity,infinity)
    );
    /*!
        requires
            - pixel_traits<pixel_type> is defined
        ensures
            - Fills the region defined by rect in the given canvas with the given colors.
              The top of the region will have the top_color color and will slowly fade
              towards the bottom_color color towards the bottom of rect.
            - The drawn rectangle will have rounded corners and with the amount of
            - rounding given by the radius argument.
            - only the part of this object that overlaps with area and the canvas
              will be drawn on the canvas
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename pixel_type
        >
    void draw_rounded_rectangle (
        const canvas& c,
        const rectangle& rect,
        unsigned radius,
        const pixel_type& color,
        const rectangle& area = rectangle(-infinity,-infinity,infinity,infinity)
    );
    /*!
        requires
            - pixel_traits<pixel_type> is defined
        ensures
            - Draws the part of the rectangle that overlaps with
              the canvas onto the canvas.
            - The drawn rectangle will have rounded corners and with the amount of
              rounding given by the radius argument.
            - Uses the given pixel color.
            - only draws the part of the image that overlaps with the area rectangle
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_GUI_CANVAS_DRAWINg_ABSTRACT_


dlib C++ Library - drawable_abstract.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.

#undef DLIB_DRAWABLe_ABSTRACT_
#ifdef DLIB_DRAWABLe_ABSTRACT_

#include "../gui_core.h"
#include "fonts_abstract.h"
#include "canvas_drawing_abstract.h"

namespace dlib
{

    /*!
        GENERAL REMARKS
            This file defines the drawable interface class and the drawable_window which
            is just a window that is capable of displaying drawable objects (i.e. objects
            that implement the drawable interface).

            The drawable interface is a simple framework for creating more complex
            graphical widgets.  It provides a default set of functionality and a
            set of events which a gui widget may use.

        THREAD SAFETY
            All objects and functions defined in this file are thread safe.  You may
            call them from any thread without serializing access to them.
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class drawable_window
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class drawable_window : public base_window
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object represents a window on the desktop that is capable of
                containing drawable objects.

            INITIAL STATE
                The initial state of the drawable_window is to be hidden.  This means
                you need to call show() to make it appear.

            EVENTS
                The drawable_window object uses all the events provided by base_window
                except for the on_window_close() event.  This means that if you
                define handlers for these events yourself you will have to call
                the drawable_window's version of them so that the drawable_window
                can continue to process and forward these events to its drawable
                objects.
        !*/
    public:

        drawable_window (
            bool resizable = true,
            bool undecorated = false
        );
        /*!
            requires
                - if (undecorated == true) then
                    - resizable == false
            ensures
                - #*this has been properly initialized
                - #background_color() == rgb_pixel(212,208,200)
                - if (resizable == true) then
                    - this window will be resizable by the user
                - else
                    - this window will not be resizable by the user
                - if (undecorated == true) then
                    - this window will not have any graphical elements outside
                      of its drawable area or appear in the system task bar.
                      (e.g. a popup menu)
            throws
                - std::bad_alloc
                - dlib::thread_error
                - dlib::gui_error
                    This exception is thrown if there is an error while
                    creating this window.
        !*/

        virtual ~drawable_window(
        )=0;
        /*!
            ensures
                - if (this window has not already been closed) then
                    - closes the window
                - does NOT trigger the on_window_close() event
                - all resources associated with *this have been released
        !*/

        void set_background_color (
            unsigned long red,
            unsigned long green,
            unsigned long blue
        );
        /*!
            ensures
                - #background_color().red == red
                - #background_color().green == green
                - #background_color().blue == blue
        !*/

        rgb_pixel background_color (
        ) const;
        /*!
            ensures
                - returns the background color this window paints its canvas
                  with before it passes it onto its drawable widgets
        !*/

    private:
        // restricted functions
        drawable_window(drawable_window&);        // copy constructor
        drawable_window& operator=(drawable_window&);    // assignment operator

        friend class drawable;
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class drawable
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    enum
    {
        MOUSE_MOVE = 1,
        MOUSE_CLICK = 2,
        MOUSE_WHEEL = 4,
        WINDOW_RESIZED = 8,
        KEYBOARD_EVENTS = 16,
        FOCUS_EVENTS = 32,
        WINDOW_MOVED = 64,
        STRING_PUT = 128
    };

    class drawable
    {
        /*!
            INITIAL VALUE
                top() == 0
                left() == 0
                right() == -1
                bottom() == -1
                get_rect().is_empty() == true
                is_hidden() == false
                is_enabled() == true
                z_order() == 0
                main_font() == default_font::get_font()

            WHAT THIS OBJECT REPRESENTS
                This is an interface that all drawable widgets implement.  It
                provides a standard method (draw()) to draw a widget onto a canvas
                and many other convenient functions for drawable objects.

            EVENT FORWARDING
                All the events that come to a drawable object are forwarded from its
                parent window.  Additionally, there is no filtering.  This means that
                if a drawable registers to receive a certain kind of event then whenever
                its parent window receives that event the drawable object will get a
                forwarded copy of it as well even if the event occurred outside the
                drawable's rectangle.

                The only events that have anything in the way of filtering are the
                draw() and on_user_event() events.  draw() is only called on a drawable
                object when that object is not hidden.  on_user_event() is only called
                for drawables that the on_user_event()'s first argument specifically
                references.  All other events are not filtered at all though.

            Z ORDER
                Z order defines the order in which drawable objects are drawn.  The
                lower numbered drawables are drawn first and then the higher numbered
                ones.  So a drawable with a z order of 0 is drawn before one with a
                z order of 1 and so on.
        !*/

    public:

        friend class drawable_window;

        drawable (
            drawable_window& w,
            unsigned long events = 0
        ) :
            m(w.wm),
            parent(w),
            hidden(false),
            enabled(true)
        {}
        /*!
            ensures
                - #*this is properly initialized
                - #parent_window() == w
                - #*this will not receive any events or draw() requests until
                  enable_events() is called
                - once events_are_enabled() == true this drawable will receive
                  the on_user_event() event. (i.e. you always get this event, you don't
                  have to enable it by setting something in the events bitset).
                - if (events & MOUSE_MOVE) then
                    - once events_are_enabled() == true this drawable will receive
                      the following events related to mouse movement: on_mouse_move,
                      on_mouse_leave, and on_mouse_enter.
                - if (events & MOUSE_CLICK) then
                    - once events_are_enabled() == true this drawable will receive
                      the following events related to mouse clicks: on_mouse_down and
                      on_mouse_up.
                - if (events & MOUSE_WHEEL) then
                    - once events_are_enabled() == true this drawable will receive
                      the following events related to mouse wheel scrolling:
                      on_wheel_up and on_wheel_down.
                - if (events & WINDOW_RESIZED) then
                    - once events_are_enabled() == true this drawable will receive
                      the following event related to its parent window resizing:
                      on_window_resized.
                - if (events & KEYBOARD_EVENTS) then
                    - once events_are_enabled() == true this drawable will receive
                      the following keyboard event: on_keydown.
                - if (events & FOCUS_EVENTS) then
                    - once events_are_enabled() == true this drawable will receive
                      the following focus events: on_focus_gained and on_focus_lost.
                - if (events & WINDOW_MOVED) then
                    - once events_are_enabled() == true this drawable will receive
                      the following event related to its parent window moving:
                      on_window_moved.
                - if (events & STRING_PUT) then
                    - once events_are_enabled() == true this drawable will receive
                      the following event related to wide character string input:
                      on_string_put.
            throws
                - std::bad_alloc
                - dlib::thread_error
        !*/

        virtual ~drawable (
        );
        /*!
            requires
                - events_are_enabled() == false
            ensures
                - any resources associated with *this have been released
                - *this has been removed from its containing window parent_window() and
                  its parent window will no longer try to dispatch events to it.
                  Note that this does not trigger a redraw of the parent window.  If you
                  want to do that you must do it yourself.
        !*/

        long z_order (
        ) const;
        /*!
            ensures
                - returns the z order for this drawable.
        !*/

        virtual void set_z_order (
            long order
        );
        /*!
            ensures
                - #z_order() == order
                - if (events_are_enabled() == true) then
                    - parent_window() is updated to reflect the new state of #*this
            throws
                - std::bad_alloc
        !*/

        const rectangle get_rect (
        ) const;
        /*!
            ensures
                - returns the rectangle that defines the area and position of this
                  drawable inside its containing window parent_window().
        !*/

        long bottom (
        ) const;
        /*!
            ensures
                - returns get_rect().bottom()
        !*/

        long top (
        ) const;
        /*!
            ensures
                - returns get_rect().top()
        !*/

        long left (
        ) const;
        /*!
            ensures
                - returns get_rect().left()
        !*/

        long right (
        ) const;
        /*!
            ensures
                - returns get_rect().right()
        !*/

        unsigned long width (
        ) const;
        /*!
            ensures
                - returns get_rect().width()
        !*/

        unsigned long height (
        ) const;
        /*!
            ensures
                - returns get_rect().height()
        !*/

        virtual void set_pos (
            long x,
            long y
        );
        /*!
            ensures
                - #top() == y
                - #left() == x
                - #width() == width()
                - #height() == height()
                - if (events_are_enabled() == true) then
                    - parent_window() is updated to reflect the new state of #*this
                - i.e. This just sets the upper left corner of this drawable to the
                  location (x,y)
        !*/

        bool is_enabled (
        ) const;
        /*!
            ensures
                - returns true if this object is enabled and false otherwise.
                  (it is up to derived classes to define exactly what it means to be
                  "enabled")
        !*/

        virtual void enable (
        );
        /*!
            ensures
                - #is_enabled() == true
                - if (events_are_enabled() == true) then
                    - parent_window() is updated to reflect the new state of #*this
        !*/

        virtual void disable (
        );
        /*!
            ensures
                - #is_enabled() == false
                - if (events_are_enabled() == true) then
                    - parent_window() is updated to reflect the new state of #*this
        !*/

        virtual void set_main_font (
            const shared_ptr_thread_safe<font>& f
        );
        /*!
            ensures
                - #main_font() == f
                - if (events_are_enabled() == true) then
                    - parent_window() is updated to reflect the new state of #*this
        !*/

        const shared_ptr_thread_safe<font> main_font (
        ) const;
        /*!
            ensures
                - returns the current main font being used by this widget
        !*/

        bool is_hidden (
        ) const;
        /*!
            ensures
                - returns true if this object is NOT currently displayed on parent_window()
                  and false otherwise.
        !*/

        virtual void show (
        );
        /*!
            ensures
                - #is_hidden() == false
                - if (events_are_enabled() == true) then
                    - parent_window() is updated to reflect the new state of #*this
        !*/

        virtual void hide (
        );
        /*!
            ensures
                - #is_hidden() == true
                - if (events_are_enabled() == true) then
                    - parent_window() is updated to reflect the new state of #*this
        !*/

        drawable_window& parent_window (
        );
        /*!
            ensures
                - returns a reference to the drawable_window that this drawable is
                  being drawn on and receiving events from.
        !*/

        const drawable_window& parent_window (
        ) const;
        /*!
            ensures
                - returns a const reference to the drawable_window that this drawable
                  is being drawn on and receiving events from.
        !*/

        virtual int next_free_user_event_number (
        )const { return 0; }
        /*!
            ensures
                - returns the smallest number, i, that is the next user event number you
                  can use in calls to parent.trigger_user_event((void*)this,i).
                - This function exists because of the following scenario.  Suppose
                  you make a class called derived1 that inherits from drawable and
                  in derived1 you use a user event to do something.  Then suppose
                  you inherit from derived1 to make derived2.  Now in derived2 you
                  may want to use a user event to do something as well.  How are you
                  to know which user event numbers are in use already?  This function
                  solves that problem.  You would define derived1::next_free_user_event_number()
                  so that it returned a number bigger than any user event numbers used by
                  derived1 or its ancestors.  Then derived2 could just call
                  derived1::next_free_user_event_number() to find out what numbers it could use.
        !*/

    protected:
        /*!A drawable_protected_variables

            These protected members are provided because they are needed to
            implement drawable widgets.
        !*/

        // This is the rectangle that is returned by get_rect()
        rectangle rect;

        // This is the mutex used to serialize access to this class.
        const rmutex& m;

        // This is the parent window of this drawable
        drawable_window& parent;

        // This is the bool returned by is_hidden()
        bool hidden;

        // This is the bool returned by is_enabled()
        bool enabled;

        // This is the font pointer returned by main_font()
        shared_ptr_thread_safe<font> mfont;

        // This is the x coordinate that we last saw the mouse at or -1 if the mouse
        // is outside the parent window.
        const long& lastx;

        // This is the y coordinate that we last saw the mouse at or -1 if the mouse
        // is outside the parent window.
        const long& lasty;

        void enable_events (
        );
        /*!
            ensures
                - #events_are_enabled() == true
        !*/

        void disable_events (
        );
        /*!
            ensures
                - #events_are_enabled() == false
        !*/

        bool events_are_enabled (
        ) const;
        /*!
            ensures
                - returns true if this object is receiving events and draw()
                  requests from its parent window.
                - returns false otherwise
        !*/

        // ---------------- EVENT HANDLERS ------------------

        virtual void on_user_event (
            int i
        ){}
        /*!
            requires
                - events_are_enabled() == true
                - mutex m is locked
                - is called whenever the parent window receives an on_user_event(p,i) event
                  where p == this.  (i.e. this is just a redirect of on_user_event for
                  cases where the first argument of on_user_event is equal to the
                  this pointer).
            ensures
                - does not change the state of mutex m.
        !*/

        virtual void on_window_resized(
        ){}
        /*!
            requires
                - events_are_enabled() == true
                - mutex m is locked
                - this is just the base_window::on_window_resized() event forwarded to
                  this object.  See the gui_core specs for the details about this event.
            ensures
                - does not change the state of mutex m.
        !*/

        virtual void on_window_moved(
        ){}
        /*!
            requires
                - events_are_enabled() == true
                - mutex m is locked
                - this is just the base_window::on_window_moved() event forwarded to
                  this object.  See the gui_core specs for the details about this event.
            ensures
                - does not change the state of mutex m.
        !*/

        virtual void on_mouse_down (
            unsigned long btn,
            unsigned long state,
            long x,
            long y,
            bool is_double_click
        ){}
        /*!
            requires
                - events_are_enabled() == true
                - mutex m is locked
                - this is just the base_window::on_mouse_down() event forwarded to
                  this object.  See the gui_core specs for the details about this event.
            ensures
                - does not change the state of mutex m.
        !*/

        virtual void on_mouse_up (
            unsigned long btn,
            unsigned long state,
            long x,
            long y
        ){}
        /*!
            requires
                - events_are_enabled() == true
                - mutex m is locked
                - this is just the base_window::on_mouse_up() event forwarded to
                  this object.  See the gui_core specs for the details about this event.
            ensures
                - does not change the state of mutex m.
        !*/

        virtual void on_mouse_move (
            unsigned long state,
            long x,
            long y
        ){}
        /*!
            requires
                - events_are_enabled() == true
                - mutex m is locked
                - x == lastx
                - y == lasty
                - this is just the base_window::on_mouse_move() event forwarded to
                  this object.  See the gui_core specs for the details about this event.
            ensures
                - does not change the state of mutex m.
        !*/

        virtual void on_mouse_leave (
        ){}
        /*!
            requires
                - events_are_enabled() == true
                - mutex m is locked
                - this is just the base_window::on_mouse_leave() event forwarded to
                  this object.  See the gui_core specs for the details about this event.
            ensures
                - does not change the state of mutex m.
        !*/

        virtual void on_mouse_enter (
        ){}
        /*!
            requires
                - events_are_enabled() == true
                - mutex m is locked
                - this is just the base_window::on_mouse_enter() event forwarded to
                  this object.  See the gui_core specs for the details about this event.
            ensures
                - does not change the state of mutex m.
        !*/

        virtual void on_wheel_up (
            unsigned long state
        ){}
        /*!
            requires
                - events_are_enabled() == true
                - mutex m is locked
                - this is just the base_window::on_wheel_up() event forwarded to
                  this object.  See the gui_core specs for the details about this event.
            ensures
                - does not change the state of mutex m.
        !*/

        virtual void on_wheel_down (
            unsigned long state
        ){}
        /*!
            requires
                - events_are_enabled() == true
                - mutex m is locked
                - this is just the base_window::on_wheel_down() event forwarded to
                  this object.  See the gui_core specs for the details about this event.
            ensures
                - does not change the state of mutex m.
        !*/

        virtual void on_focus_gained (
        ){}
        /*!
            requires
                - events_are_enabled() == true
                - mutex m is locked
                - this is just the base_window::on_focus_gained() event forwarded to
                  this object.  See the gui_core specs for the details about this event.
            ensures
                - does not change the state of mutex m.
        !*/

        virtual void on_focus_lost (
        ){}
        /*!
            requires
                - events_are_enabled() == true
                - mutex m is locked
                - this is just the base_window::on_focus_lost() event forwarded to
                  this object.  See the gui_core specs for the details about this event.
            ensures
                - does not change the state of mutex m.
        !*/

        virtual void on_keydown (
            unsigned long key,
            bool is_printable,
            unsigned long state
        ){}
        /*!
            requires
                - events_are_enabled() == true
                - mutex m is locked
                - this is just the base_window::on_keydown() event forwarded to
                  this object.  See the gui_core specs for the details about this event.
            ensures
                - does not change the state of mutex m.
        !*/

        virtual void on_string_put (
            const std::wstring &str
        ){}
        /*!
            requires
                - events_are_enabled() == true
                - mutex m is locked
                - this is just the base_window::on_put_string() event forwarded to
                  this object.  See the gui_core specs for the details about this event.
            ensures
                - does not change the state of mutex m.
        !*/

        virtual void draw (
            const canvas& c
        ) const=0;
        /*!
            requires
                - events_are_enabled() == true
                - mutex m is locked
                - is_hidden() == false
                - is called by parent_window() when it needs to repaint itself.
                - c == the canvas object for the area of parent_window() that needs
                  to be repainted.
            ensures
                - does not change the state of mutex m.
                - draws the area of *this that intersects with the canvas onto
                  the canvas object c.
        !*/

    private:

        // restricted functions
        drawable(drawable&);        // copy constructor
        drawable& operator=(drawable&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_DRAWABLe_ABSTRACT_


dlib C++ Library - fonts_abstract.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net), Nils Labugt, Keita Mochizuki
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_FONTs_ABSTRACT_
#ifdef DLIB_FONTs_ABSTRACT_

#include "../gui_core.h"
#include <string>
#include "../serialize.h"
#include "../unicode.h"
#include <iostream>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class letter
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object represents a letter in a font.  It tells you the nominal
                width of the letter and which pixels form the letter.

            THREAD SAFETY
                const versions of this object are thread safe but if you are going to
                be modifying it then you must serialize access to it.
        !*/
    public:
        struct point
        {
            /*!
                WHAT THIS OBJECT REPRESENTS
                    This object represents one of the pixels of a letter.

                    The origin (i.e. (0,0)) of the coordinate plane is at the left
                    side of the letter's baseline.  Also note that y is negative when
                    above the baseline and positive below (it is zero on the baseline
                    itself).

                    The x value is positive going to the right and negative to the left.
                    The meaning of a negative x value is that any points with a negative
                    x value will overlap with the preceding letter.
            !*/

            point (
            );
            /*!
                ensures
                    - This constructor does nothing.  The value of x and y
                      are undefined after its execution.
            !*/

            point (
                signed char x_,
                signed char y_
            );
            /*!
                ensures
                    - #x == x_
                    - #y == y_
            !*/

            signed char x;
            signed char y;
        };

        // ---------------------------------

        letter (
        );
        /*!
            ensures
                - #width() == 0
                - #num_of_points() == 0
        !*/

        letter (
            unsigned short width_,
            unsigned short point_count
        );
        /*!
            ensures
                - #width() == width_
                - #num_of_points() == point_count
        !*/

        ~letter(
        );
        /*!
            ensures
                - any resources used by *this have been freed
        !*/

        const unsigned short width (
        ) const;
        /*!
            ensures
                - returns the width reserved for this letter in pixels.  This is the
                  number of pixels that are reserved for this letter between adjoining
                  letters.  It isn't necessarily the width of the actual letter itself.
                  (for example, you can make a letter with a width less than how wide it
                  actually is so that it overlaps with its neighbor letters.)
        !*/

        const unsigned short num_of_points (
        ) const;
        /*!
            ensures
                - returns the number of pixels that make up this letter.
        !*/

        point& operator[] (
            unsigned short i
        );
        /*!
            requires
                - i < num_of_points()
            ensures
                - returns a non-const reference to the ith point in this letter.
        !*/

        const point& operator[] (
            unsigned short i
        ) const;
        /*!
            requires
                - i < num_of_points()
            ensures
                - returns a const reference to the ith point in this letter.
        !*/

        void swap (
            letter& item
        );
        /*!
            ensures
                - swaps *this with item
        !*/

        private:

        // restricted functions
        letter(letter&);        // copy constructor
        letter& operator=(letter&);    // assignment operator
    };

    inline void swap (
        letter& a,
        letter& b
    ) { a.swap(b); }
    /*!
        provides a global swap
    !*/

// ----------------------------------------------------------------------------------------

    void serialize (
        const letter& item,
        std::ostream& out
    );
    /*!
        provides serialization support for letter objects
    !*/

    void deserialize (
        letter& item,
        std::istream& in
    );
    /*!
        provides deserialization support for letter objects
    !*/

// ----------------------------------------------------------------------------------------

    class font
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object defines an interface for a font type.  It provides metrics
                for the font and functions to help you draw strings on a canvas object.

            THREAD SAFETY
                All the functions in this class are thread safe.
        !*/

    public:

        virtual bool has_character (
            unichar ch
        )const=0;
        /*!
            ensures
                - if (this font has a glyph for the given character) then
                    - returns true
                - else
                    - returns false
        !*/
        bool has_character(char ch) const    { return this->has_character(zero_extend_cast<unichar>(ch)); }
        bool has_character(wchar_t ch) const { return this->has_character(zero_extend_cast<unichar>(ch)); }
        /* Cast char and wchar_t to unichar correctly when char or wchar_t is a signed type */

        virtual const letter& operator[] (
            unichar ch
        )const=0;
        /*!
            ensures
                - if (has_character(ch) == true) then
                    - returns a letter object that tells you how to draw this character.
                - else
                    - returns some default glyph for characters that aren't in this font.
        !*/
        const letter& operator[] (char ch)    const { return (*this)[zero_extend_cast<unichar>(ch)]; };
        const letter& operator[] (wchar_t ch) const { return (*this)[zero_extend_cast<unichar>(ch)]; };
        /* Cast char and wchar_t to unichar correctly when char or wchar_t is a signed type */

        virtual const unsigned long height (
        ) const = 0;
        /*!
            ensures
                - returns the height in pixels of the tallest letter in the font
        !*/

        virtual const unsigned long ascender (
        ) const = 0;
        /*!
            ensures
                - returns the height() minus the number of pixels below the baseline used
                  by the letter that hangs the lowest below the baseline.
        !*/

        virtual const unsigned long left_overflow (
        ) const = 0;
        /*!
            ensures
                - returns how far outside and to the left of its width a letter
                  from this font may set pixels.  (i.e. how many extra pixels to its
                  left may a font use)
        !*/

        virtual const unsigned long right_overflow (
        ) const = 0;
        /*!
            ensures
                - returns how far outside and to the right of its width a letter
                  from this font may set pixels.  (i.e. how many extra pixels to its
                  right may a font use)
        !*/

        template <typename T, typename traits, typename alloc>
        void compute_size (
            const std::basic_string<T,traits,alloc>& str,
            unsigned long& width,
            unsigned long& height,
            typename std::basic_string<T,traits,alloc>::size_type first = 0,
            typename std::basic_string<T,traits,alloc>::size_type last = std::basic_string<T,traits,alloc>::npos
        ) const;
        /*!
            requires
                - if (last != std::basic_string<T,traits,alloc>::npos) then
                    - first <= last
                    - last < str.size()
            ensures
                - all characters in str with an index < first are ignored by this
                  function.
                - if (last != std::basic_string<T,traits,alloc>::npos) then
                    - all characters in str with an index > last are ignored by
                      this function.
                - if (str.size() == 0) then
                    - #width == 0
                    - #height == 0
                - else
                    - #width == sum of the widths of the characters in the widest
                      line in str + left_overflow() + right_overflow().
                    - #height == (count(str.begin(),str.end(),'\n')+1)*height()
        !*/

        template <typename T, typename traits, typename alloc, typename pixel_type>
        void draw_string (
            const canvas& c,
            const rectangle& rect,
            const std::basic_string<T,traits,alloc>& str,
            const pixel_type& color = rgb_pixel(0,0,0),
            typename std::basic_string<T,traits,alloc>::size_type first = 0,
            typename std::basic_string<T,traits,alloc>::size_type last = std::basic_string<T,traits,alloc>::npos,
            const rectangle area = rectangle(-infinity,-infinity,infinity,infinity)
        ) const;
        /*!
            requires
                - if (last != std::basic_string<T,traits,alloc>::npos) then
                    - first <= last
                    - last < str.size()
            ensures
                - all characters in str with an index < first are ignored by this
                  function.
                - if (last != std::basic_string<T,traits,alloc>::npos) then
                    - all characters in str with an index > last are ignored by
                      this function.
                - if (str.size() == 0) then
                    - does nothing
                - else
                    - draws str on the given canvas at the position defined by rect.
                      Also uses the given pixel colors for the font color.
                - If the string is too big to fit in rect then the right and
                  bottom sides of it will be clipped to make it fit.
                - only the part of the string that is contained inside the area
                  rectangle will be drawn
        !*/

        template <typename T, typename traits, typename alloc>
        const rectangle compute_cursor_rect (
            const rectangle& rect,
            const std::basic_string<T,traits,alloc>& str,
            unsigned long index,
            typename std::basic_string<T,traits,alloc>::size_type first = 0,
            typename std::basic_string<T,traits,alloc>::size_type last = std::basic_string<T,traits,alloc>::npos
        ) const;
        /*!
            requires
                - if (last != std::basic_string<T,traits,alloc>::npos) then
                    - first <= last
                    - last < str.size()
            ensures
                - the returned rectangle has a width of 1 and a
                  height of this->height().
                - computes the location of the cursor that would sit just before
                  the character str[index] if str were drawn on the screen by
                  draw_string(rect,str,...,first,last).  The cursor location is
                  returned in the form of a rectangle.
                - if (index < first) then
                    - the returned cursor will be just before the character str[first].
                - if (last != std::basic_string<T,traits,alloc>::npos && index > last) then
                    - the returned cursor will be just after the character str[last]
                - if (str.size() == 0) then
                    - the returned cursor will be just at the start of the rectangle where
                      str would be drawn if it wasn't empty.
                - if (index > str.size()-1) then
                    - the returned cursor will be just after the character str[str.size()-1]
        !*/

        template <typename T, typename traits, typename alloc>
        const unsigned long compute_cursor_pos (
            const rectangle& rect,
            const std::basic_string<T,traits,alloc>& str,
            long x,
            long y,
            typename std::basic_string<T,traits,alloc>::size_type first = 0,
            typename std::basic_string<T,traits,alloc>::size_type last = std::basic_string<T,traits,alloc>::npos
        ) const;
        /*!
            requires
                - if (last != std::basic_string<T,traits,alloc>::npos) then
                    - first <= last
                    - last < str.size()
            ensures
                - returns a number idx that has the following properties:
                    - if (first < str.size()) then
                        - first <= idx
                    - else
                        - idx == str.size()
                    - if (last != std::basic_string<T,traits,alloc>::npos) then
                        - idx <= last + 1
                    - compute_cursor_rect(rect,str,idx,first,last) == the cursor
                      position that is closest to the pixel (x,y)
        !*/

    private:

        // restricted functions
        font(font&);        // copy constructor
        font& operator=(font&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------

    class default_font : public font
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is an implementation of the Helvetica 12 point font.

            THREAD SAFETY
                It is safe to call get_font() and access the returned font from any
                thread and no synchronization is needed as long as it is called
                after the main() function has been entered.
        !*/

    public:
        static const shared_ptr_thread_safe<font> get_font(
        );
        /*!
            ensures
                - returns an instance of this font.
            throws
                - std::bad_alloc
                    This exception is thrown if there is a problem gathering the needed
                    memory for the font object.
        !*/

    private:

        // restricted functions
        default_font();        // normal constructor
        default_font(default_font&);        // copy constructor
        default_font& operator=(default_font&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------

    class bdf_font : public font
    {

        /*!
            WHAT THIS OBJECT REPRESENTS
                This is a font object that is capable of loading of loading BDF (Glyph
                Bitmap Distribution Format) font files.

            THREAD SAFETY
                If you only access this object via the functions in the parent class font
                then this object is thread safe.  But if you need to call any of the
                functions introduced in this derived class then you need to serialize
                access to this object while you call these functions.
        !*/

    public:

        bdf_font(
            long default_char = -1
        );
        /*!
            ensures
                - for all x:
                    - #has_character(x) == false
                      (i.e. this font starts out empty.  You have to call read_bdf_file()
                      to load it with data)
                - if (default_char == -1) then
                    - the letter returned by (*this)[ch] for values of
                      ch where has_character(ch) == false will be the
                      default glyph defined in the bdf file.
                - else
                    - the letter returned by (*this)[ch] for values of
                      ch where has_character(ch) == false will be the
                      letter (*this)[default_char].
        !*/

        long read_bdf_file(
            std::istream& in,
            unichar max_enc,
            unichar min_enc = 0
        );
        /*!
            ensures
                - attempts to read the font data from the given input stream into
                  *this.  The input stream is expected to contain a valid BDF file.
                - reads in characters with encodings in the range min_enc to max_enc
                  into this font.  All characters in the font file outside this range
                  are ignored.
                - returns the number of characters loaded into this font from the
                  given input stream.
        !*/

        void adjust_metrics();
        /*!
            ensures
                - Computes metrics based on actual glyphs loaded, instead of using
                  the values in the bdf file header. (May be useful if loading glyphs
                  from more than one file or a small part of a file.)
        !*/

    private:

        bdf_font( bdf_font& );      // copy constructor
        bdf_font& operator=( bdf_font& );  // assignment operator

    };

// ----------------------------------------------------------------------------------------

    const shared_ptr_thread_safe<font> get_native_font(
    );
    /*!
        ensures
            - returns a font object that uses the local font
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_FONTs_ABSTRACT_


dlib C++ Library - style_abstract.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net), and Nils Labugt
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_WIDGETs_STYLE_ABSTRACT_
#ifdef DLIB_WIDGETs_STYLE_ABSTRACT_

#include "../algs.h"
#include "../gui_core.h"
#include "widgets_abstract.h"
#include "../unicode/unicode_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // button styles
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class button_style
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is an abstract class that defines the interface a
                button style object must implement.

                Note that derived classes must be copyable via
                their copy constructors.
        !*/

    public:

        virtual ~button_style() {}

        virtual bool redraw_on_mouse_over (
        ) const { return false; }
        /*!
            ensures
                - if (this style draws buttons differently when a mouse is over them) then
                    - returns true
                - else
                    - returns false
        !*/

        virtual rectangle get_invalidation_rect (
            const rectangle& rect
        ) const { return rect; }
        /*!
            requires
                - the mutex drawable::m is locked
                - rect == the get_rect() that defines where the button is
            ensures
                - returns a rectangle that should be invalidated whenever a button
                  needs to redraw itself.  (e.g. If you wanted your button style to
                  draw outside the button then you could return a larger rectangle)
        !*/

        virtual rectangle get_min_size (
            const ustring& name,
            const font& mfont
        ) const = 0;
        /*!
            requires
                - the mutex drawable::m is locked
            ensures
                - returns a rectangle that represents the minimum size of the button
                  given the name and font.
        !*/

        virtual void draw_button (
            const canvas& c,
            const rectangle& rect,
            const bool enabled,
            const font& mfont,
            const long lastx,
            const long lasty,
            const ustring& name,
            const bool is_depressed
        ) const = 0;
        /*!
            requires
                - the mutex drawable::m is locked
                - c == the canvas to draw on
                - rect, enabled, mfont, lastx, and lasty are the variables
                  defined in the protected section of the drawable class.
                - name == the name of the button to be drawn
                - is_depressed == true if the button is to be drawn in a depressed state
            ensures
                - draws the button on the canvas c at the location given by rect.
        !*/
    };

// ----------------------------------------------------------------------------------------

    class button_style_default : public button_style
    {
        /*!
            This is the default style for button objects.  It will cause
            a button to appear as the simple MS Windows 2000 button style.
        !*/
    };

// ----------------------------------------------------------------------------------------

    class button_style_toolbar1 : public button_style
    {
        /*!
            This draws a simple toolbar style button that displays its name in the
            middle of itself.  When the mouse moves over it it will light up.
        !*/
    };

// ----------------------------------------------------------------------------------------

    class button_style_toolbar_icon1 : public button_style
    {
        /*!
            This draws a simple toolbar style button that displays an image in the
            middle of itself.  When the mouse moves over it it will light up.
        !*/
        template <typename image_type>
        button_style_toolbar_icon1 (
            const image_type& img,
            unsigned long border_size = 6
        );
        /*!
            requires
                - image_type == an implementation of array2d/array2d_kernel_abstract.h
                - pixel_traits<typename image_type::type> is defined
            ensures
                - displays image img in the middle of the button
                - the distance between the edge of the button and the image
                  will be border_size pixels
        !*/
    };

// ----------------------------------------------------------------------------------------

    class button_style_arrow : public button_style
    {
    public:
        /*!
            This draws a simple button with an arrow in it
        !*/

        enum arrow_direction
        {
            UP,
            DOWN,
            LEFT,
            RIGHT
        };

        button_style_arrow (
            arrow_direction dir
        );
        /*!
            ensures
                - the arrow in the button will point in the given direction
        !*/
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // toggle button styles
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class toggle_button_style
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is an abstract class that defines the interface a
                toggle button style object must implement.

                Note that derived classes must be copyable via
                their copy constructors.
        !*/

    public:

        virtual ~toggle_button_style() {}

        virtual bool redraw_on_mouse_over (
        ) const { return false; }
        /*!
            ensures
                - if (this style draws buttons differently when a mouse is over them) then
                    - returns true
                - else
                    - returns false
        !*/

        virtual rectangle get_min_size (
            const ustring& name,
            const font& mfont
        ) const = 0;
        /*!
            requires
                - the mutex drawable::m is locked
            ensures
                - returns a rectangle that represents the minimum size of the button
                  given the name and font.
        !*/

        virtual void draw_toggle_button (
            const canvas& c,
            const rectangle& rect,
            const bool enabled,
            const font& mfont,
            const long lastx,
            const long lasty,
            const ustring& name,
            const bool is_depressed,
            const bool is_checked
        ) const = 0;
        /*!
            requires
                - the mutex drawable::m is locked
                - c == the canvas to draw on
                - rect, enabled, mfont, lastx, and lasty are the variables
                  defined in the protected section of the drawable class.
                - name == the name of the button to be drawn
                - is_depressed == true if the button is to be drawn in a depressed state
                - is_checked == true if the toggle_button is in the checked state
            ensures
                - draws the button on the canvas c at the location given by rect.
        !*/
    };

// ----------------------------------------------------------------------------------------

    class toggle_button_style_default : public toggle_button_style
    {
        /*!
            This is the default style for toggle_button objects.  It will cause
            a button to appear as the simple MS Windows 2000 button style.
        !*/
    };

// ----------------------------------------------------------------------------------------

    class toggle_button_style_check_box : public toggle_button_style
    {
        /*!
            This draws a simple check box style toggle button that displays its
            name to the right of a check box.
        !*/
    };

// ----------------------------------------------------------------------------------------

    class toggle_button_style_radio_button : public toggle_button_style
    {
        /*!
            This draws a simple radio button style toggle button that displays its
            name to the right of a circular radio button.
        !*/
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // scroll_bar styles
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class scroll_bar_style
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is an abstract class that defines the interface a
                scroll_bar style object must implement.

                Note that derived classes must be copyable via
                their copy constructors.

                There are three parts of a scroll bar, the slider, the background,
                and the two buttons on its ends.  The "slider" is the thing that you
                drag around on the scroll bar and the "background" is the part
                in between the slider and the buttons on the ends.
        !*/

    public:

        virtual ~scroll_bar_style() {}

        virtual bool redraw_on_mouse_over_slider (
        ) const { return false; }
        /*!
            ensures
                - if (this style draws a scroll_bar's slider differently when a mouse is over it
                  or it is being dragged) then
                    - returns true
                - else
                    - returns false
        !*/

        virtual long get_width (
        ) const = 0;
        /*!
            requires
                - the mutex drawable::m is locked
            ensures
                - returns the width in pixels of the scroll bar
        !*/

        virtual long get_slider_length (
            long total_length,
            long max_pos
        ) const = 0;
        /*!
            requires
                - the mutex drawable::m is locked
                - total_length == the total length in pixels of the scroll bar
                - max_pos == the value of scroll_bar::max_slider_pos() for this
                  scroll bar
            ensures
                - returns the length in pixels of the scroll bar's slider
        !*/

        virtual long get_button_length (
            long total_length,
            long max_pos
        ) const = 0;
        /*!
            requires
                - the mutex drawable::m is locked
                - total_length == the total length in pixels of the scroll bar
                - max_pos == the value of scroll_bar::max_slider_pos() for this
                  scroll bar
            ensures
                - returns the length in pixels of each of the scroll bar's
                  buttons
        !*/

        virtual void draw_scroll_bar_background (
            const canvas& c,
            const rectangle& rect,
            const bool enabled,
            const long lastx,
            const long lasty,
            const bool is_depressed
        ) const = 0;
        /*!
            requires
                - the mutex drawable::m is locked
                - c == the canvas to draw on
                - rect, enabled, lastx, and lasty are the variables
                  defined in the protected section of the drawable class.
                - is_depressed == true if the background area of the scroll_bar is to
                  be drawn in a depressed state (because the user is clicking on it)
            ensures
                - draws the background part of the scroll_bar on the canvas c at the
                  location given by rect.
        !*/

        virtual void draw_scroll_bar_slider (
            const canvas& c,
            const rectangle& rect,
            const bool enabled,
            const long lastx,
            const long lasty,
            const bool is_being_dragged
        ) const = 0;
        /*!
            requires
                - the mutex drawable::m is locked
                - c == the canvas to draw on
                - rect, enabled, lastx, and lasty are the variables
                  defined in the protected section of the drawable class
                - is_being_dragged == true if the user is dragging the slider
            ensures
                - draws the slider part of the scroll_bar on the canvas c at the
                  location given by rect.
        !*/

        button_style_type get_up_button_style (
        ) const;
        /*!
            ensures
                - returns the type of button_style to use for a button on the
                  top side of a vertical scroll bar.
        !*/

        button_style_type get_down_button_style (
        ) const;
        /*!
            ensures
                - returns the type of button_style to use for a button on the
                  bottom side of a vertical scroll bar.
        !*/

        button_style_type get_left_button_style (
        ) const;
        /*!
            ensures
                - returns the type of button_style to use for a button on the
                  left side of a horizontal scroll bar.
        !*/

        button_style_type get_right_button_style (
        ) const;
        /*!
            ensures
                - returns the type of button_style to use for a button on the
                  right side of a horizontal scroll bar.
        !*/
    };

// ----------------------------------------------------------------------------------------

    class scroll_bar_style_default : public scroll_bar_style
    {
        /*!
            This is the default style for scroll_bar objects.  It will cause
            a scroll_bar to appear as the simple MS Windows 2000 scroll_bar style.
        !*/
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // scrollable_region (and zoomable_region) styles
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class scrollable_region_style
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is an abstract class that defines the interface a
                scrollable_region and zoomable_region style object must implement.

                Note that derived classes must be copyable via
                their copy constructors.
        !*/
    public:

        virtual ~scrollable_region_style() {}

        virtual long get_border_size (
        ) const = 0;
        /*!
            requires
                - the mutex drawable::m is locked
            ensures
                - returns the size of the border region in pixels
        !*/

        virtual void draw_scrollable_region_border (
            const canvas& c,
            const rectangle& rect,
            const bool enabled
        ) const = 0;
        /*!
            requires
                - the mutex drawable::m is locked
                - c == the canvas to draw on
                - rect and enabled are the variables defined in the protected section
                  of the drawable class.
            ensures
                - draws the border part of a scrollable_region on the canvas c at the
                  location given by rect.
        !*/

        scroll_bar_style_type get_horizontal_scroll_bar_style (
        ) const;
        /*!
            ensures
                - returns the style of scroll_bar to use for the
                  horizontal scroll_bar in this widget.
        !*/

        scroll_bar_style_type get_vertical_scroll_bar_style (
        ) const;
        /*!
            ensures
                - returns the style of scroll_bar to use for the
                  vertical scroll_bar in this widget.
        !*/
    };

// ----------------------------------------------------------------------------------------

    class scrollable_region_style_default : public scrollable_region_style
    {
    public:
        /*!
            This is the default style for scrollable_region and zoomable_region objects.
        !*/
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // text_box styles
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class text_box_style
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is an abstract class that defines the interface a
                text_box style object must implement.

                Note that derived classes must be copyable via
                their copy constructors.
        !*/
    public:

        virtual ~text_field_style() {}

        scrollable_region_style_type get_scrollable_region_style (
        ) const;
        /*!
            ensures
                - returns the style of scrollable_region to use for the
                  text_box.
        !*/

        virtual unsigned long get_padding (
            const font& mfont
        ) const = 0;
        /*!
            requires
                - the mutex drawable::m is locked
            ensures
                - returns the number of pixels that separate the text in the text_box
                  from the edge of the text_box widget itself.
        !*/

        virtual void draw_text_box (
            const canvas& c,
            const rectangle& display_rect,
            const rectangle& text_rect,
            const bool enabled,
            const font& mfont,
            const ustring& text,
            const rectangle& cursor_rect,
            const rgb_pixel& text_color,
            const rgb_pixel& bg_color,
            const bool has_focus,
            const bool cursor_visible,
            const long highlight_start,
            const long highlight_end
        ) const = 0;
        /*!
            requires
                - the mutex drawable::m is locked
                - c == the canvas to draw on
                - enabled and mfont are the variables defined in the protected section
                - text_rect == the rectangle in which we should draw the given text
                  of the drawable class.
                - display_rect == the rectangle returned by scrollable_region::display_rect()
                - text == the current text in the text_box
                - cursor_rect == A rectangle of width 1 that represents the current
                  position of the cursor on the screen.
                - text_color == the color of the text to be drawn
                - bg_color == the background color of the text field
                - has_focus == true if this text field has keyboard input focus
                - cursor_visible == true if the cursor should be drawn
                - if (highlight_start <= highlight_end) then
                    - text[highlight_start] though text[highlight_end] should be
                      highlighted
            ensures
                - draws the text_box on the canvas c at the location given by text_rect.
                  (Note that the scroll bars and borders are drawn by the scrollable_region
                  and therefore the style returned by get_scrollable_region_style()
                  controls how those appear)
                - doesn't draw anything outside display_rect
        !*/
    };

// ----------------------------------------------------------------------------------------

    class text_box_style_default : public text_box_style
    {
    public:
        /*!
            This is the default style for text_box objects.
        !*/
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // list_box styles
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class list_box_style
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is an abstract class that defines the interface a
                list_box style object must implement.

                Note that derived classes must be copyable via
                their copy constructors.
        !*/
    public:

        virtual ~list_box_style() {}

        virtual void draw_list_box_background (
            const canvas& c,
            const rectangle& display_rect,
            const bool enabled
        ) const = 0;
        /*!
            requires
                - the mutex drawable::m is locked
                - c == the canvas to draw on
                - display_rect == the display_rect for the list_box.  This is the area
                  in which list box items are drawn (see display_rect in the scrollable_region
                  widget for more info)
                - enabled == true if the list box is enabled
            ensures
                - draws the background of a list box on the canvas c at the location given
                  by display_rect.
        !*/

        scrollable_region_style_type get_scrollable_region_style (
        ) const;
        /*!
            ensures
                - returns the style of scrollable_region to use for the
                  list_box.
        !*/

        virtual void draw_list_box_item (
            const canvas& c,
            const rectangle& rect,
            const rectangle& display_rect,
            const bool enabled,
            const font& mfont,
            const std::string& text,
            const bool is_selected
        ) const = 0;
        /*!
            requires
                - the mutex drawable::m is locked
                - c == the canvas to draw on
                - rect == the rectangle that defines where on the screen this list box item is.
                - display_rect == the display_rect for the list_box.  This is the area
                  in which list box items are drawn (see display_rect in the scrollable_region
                  widget for more info)
                - mfont == the font to use to draw the list box item
                - text == the text of the list box item to be drawn
                - enabled == true if the list box is enabled
                - is_selected == true if the item is to be drawn in a selected state
            ensures
                - draws the list box item on the canvas c at the location given by rect.
        !*/

        // wide character overloads
        virtual void draw_list_box_item (
            const canvas& c,
            const rectangle& rect,
            const rectangle& display_rect,
            const bool enabled,
            const font& mfont,
            const std::wstring& text,
            const bool is_selected
        ) const = 0;

        virtual void draw_list_box_item (
            const canvas& c,
            const rectangle& rect,
            const rectangle& display_rect,
            const bool enabled,
            const font& mfont,
            const ustring& text,
            const bool is_selected
        ) const = 0;

    };

// ----------------------------------------------------------------------------------------

    class list_box_style_default : public list_box_style
    {
    public:
        /*!
            This is the default style for list_box objects.
        !*/
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // text_field styles
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class text_field_style
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is an abstract class that defines the interface a
                text_field style object must implement.

                Note that derived classes must be copyable via
                their copy constructors.
        !*/
    public:

        virtual ~text_field_style() {}

        virtual unsigned long get_padding (
            const font& mfont
        ) const = 0;
        /*!
            requires
                - the mutex drawable::m is locked
            ensures
                - returns the number of pixels that separate the text in the text_field
                  from the edge of the text_field widget itself.
        !*/

        virtual void draw_text_field (
            const canvas& c,
            const rectangle& rect,
            const rectangle& text_rect,
            const bool enabled,
            const font& mfont,
            const ustring& text,
            const unsigned long cursor_x,
            const unsigned long text_pos,
            const rgb_pixel& text_color,
            const rgb_pixel& bg_color,
            const bool has_focus,
            const bool cursor_visible,
            const long highlight_start,
            const long highlight_end
        ) const = 0;
        /*!
            requires
                - the mutex drawable::m is locked
                - c == the canvas to draw on
                - rect, enabled, and mfont are the variables defined in the protected section
                  of the drawable class.
                - text == the current text in the text_field
                - text_rect == the rectangle in which we should draw the given text
                - cursor_x == the x coordinate of the cursor relative to the left side
                  of rect.  i.e. the number of pixels that separate the cursor from the
                  left side of the text_field.
                - text_pos == the index of the first letter in text that appears in
                  this text field.
                - text_color == the color of the text to be drawn
                - bg_color == the background color of the text field
                - has_focus == true if this text field has keyboard input focus
                - cursor_visible == true if the cursor should be drawn
                - if (highlight_start <= highlight_end) then
                    - text[highlight_start] though text[highlight_end] should be
                      highlighted
            ensures
                - draws the text_field on the canvas c at the location given by rect.
        !*/

    };

// ----------------------------------------------------------------------------------------

    class text_field_style_default : public text_field_style
    {
    public:
        /*!
            This is the default style for text_field objects.
        !*/
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_WIDGETs_STYLE_ABSTRACT_


dlib C++ Library - base_widgets_abstract.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net), Keita Mochizuki
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_BASE_WIDGETs_ABSTRACT_
#ifdef DLIB_BASE_WIDGETs_ABSTRACT_

#include "fonts_abstract.h"
#include "drawable_abstract.h"

#include "../gui_core.h"
#include <string>

namespace dlib
{

    /*!
        GENERAL REMARKS
            This file contains objects that are useful for creating complex drawable
            widgets.

        THREAD SAFETY
            All objects and functions defined in this file are thread safe.  You may
            call them from any thread without serializing access to them.

        EVENT HANDLERS
            If you derive from any of the drawable objects and redefine any of the on_*()
            event handlers then you should ensure that your version calls the same event
            handler in the base object so that the base class part of your object will also
            be able to process the event.

            Also note that all event handlers, including the user registered callback
            functions, are executed in the event handling thread.   Additionally,
            the drawable::m mutex will always be locked while these event handlers
            are running.  Also, don't rely on get_thread_id() always returning the
            same ID from inside event handlers.
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class draggable
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class draggable : public drawable
    {
        /*!
            INITIAL VALUE
                draggable_area() == an initial value for its type

            WHAT THIS OBJECT REPRESENTS
                This object represents a drawable object that is draggable by the mouse.
                You use it by inheriting from it and defining the draw() method and any
                of the on_*() event handlers you need.

                This object is draggable by the user when is_enabled() == true and
                not draggable otherwise.
        !*/

    public:

        draggable(
            drawable_window& w,
            unsigned long events = 0
        );
        /*!
            ensures
                - #*this is properly initialized
                - #*this has been added to window w
                - #parent_window() == w
                - This object will not receive any events or draw() requests until
                  enable_events() is called
                - the events flags are passed on to the drawable object's
                  constructor.
            throws
                - std::bad_alloc
                - dlib::thread_error
        !*/

        virtual ~draggable(
        ) = 0;
        /*!
            ensures
                - all resources associated with *this have been released
        !*/

        rectangle draggable_area (
        ) const;
        /*!
            ensures
                - returns the area that this draggable can be dragged around in.
        !*/

        void set_draggable_area (
            const rectangle& area
        );
        /*!
            ensures
                - #draggable_area() == area
        !*/

    protected:

        bool is_being_dragged (
        ) const;
        /*!
            requires
                - mutex drawable::m is locked
            ensures
                - if (this widget is currently being dragged by the user) then
                    - returns true
                - else
                    - returns false
        !*/

        // does nothing by default
        virtual void on_drag (
        ){}
        /*!
            requires
                - enable_events() has been called
                - is_enabled() == true
                - is_hidden() == false
                - mutex drawable::m is locked
                - is called when the user drags this object
                - get_rect() == the rectangle that defines the new position
                  of this object.
                - is_being_dragged() == true
            ensures
                - does not change the state of mutex drawable::m.
        !*/

        // does nothing by default
        virtual void on_drag_stop (
        ){}
        /*!
            requires
                - enable_events() has been called
                - mutex drawable::m is locked
                - is called when the user stops dragging this object
                - is_being_dragged() == false
            ensures
                - does not change the state of mutex drawable::m.
        !*/

    private:

        // restricted functions
        draggable(draggable&);        // copy constructor
        draggable& operator=(draggable&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class mouse_over_event
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class mouse_over_event : public drawable
    {
        /*!
            INITIAL VALUE
                is_mouse_over() == false

            WHAT THIS OBJECT REPRESENTS
                This object represents a drawable object with the addition of two events
                that will alert you when the mouse enters or leaves your drawable object.

                You use it by inheriting from it and defining the draw() method and any
                of the on_*() event handlers you need.
        !*/

    public:

        mouse_over_event(
            drawable_window& w,
            unsigned long events = 0
        );
        /*!
            ensures
                - #*this is properly initialized
                - #*this has been added to window w
                - #parent_window() == w
                - #*this will not receive any events or draw() requests until
                  enable_events() is called
                - the events flags are passed on to the drawable object's
                  constructor.
            throws
                - std::bad_alloc
                - dlib::thread_error
        !*/

        virtual ~mouse_over_event(
        ) = 0;
        /*!
            ensures
                - all resources associated with *this have been released
        !*/

    protected:

        bool is_mouse_over (
        ) const;
        /*!
            requires
                - mutex drawable::m is locked
            ensures
                - if (the mouse is currently over this widget) then
                    - returns true
                - else
                    - returns false
        !*/

        // does nothing by default
        virtual void on_mouse_over (
        ){}
        /*!
            requires
                - enable_events() has been called
                - mutex drawable::m is locked
                - is_enabled() == true
                - is_hidden() == false
                - is called whenever this object transitions from the state where
                  is_mouse_over() == false to is_mouse_over() == true
            ensures
                - does not change the state of mutex drawable::m.
        !*/

        // does nothing by default
        virtual void on_mouse_not_over (
        ){}
        /*!
            requires
                - enable_events() has been called
                - mutex drawable::m is locked
                - is called whenever this object transitions from the state where
                  is_mouse_over() == true to is_mouse_over() == false
            ensures
                - does not change the state of mutex drawable::m.
        !*/

    private:

        // restricted functions
        mouse_over_event(mouse_over_event&);        // copy constructor
        mouse_over_event& operator=(mouse_over_event&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class button_action
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class button_action : public mouse_over_event
    {
        /*!
            INITIAL VALUE
                is_depressed() == false

            WHAT THIS OBJECT REPRESENTS
                This object represents the clicking action of a push button.  It provides
                simple callbacks that can be used to make various kinds of button
                widgets.

                You use it by inheriting from it and defining the draw() method and any
                of the on_*() event handlers you need.
        !*/

    public:

        button_action(
            drawable_window& w,
            unsigned long events = 0
        );
        /*!
            ensures
                - #*this is properly initialized
                - #*this has been added to window w
                - #parent_window() == w
                - #*this will not receive any events or draw() requests until
                  enable_events() is called
                - the events flags are passed on to the drawable object's
                  constructor.
            throws
                - std::bad_alloc
                - dlib::thread_error
        !*/

        virtual ~button_action(
        ) = 0;
        /*!
            ensures
                - all resources associated with *this have been released
        !*/

    protected:

        bool is_depressed (
        ) const;
        /*!
            requires
                - mutex drawable::m is locked
            ensures
                - if (this button is currently in a depressed state) then
                    - the user has left clicked on this drawable and is still
                      holding the left mouse button down over it.
                    - returns true
                - else
                    - returns false
        !*/

        // does nothing by default
        virtual void on_button_down (
        ){}
        /*!
            requires
                - enable_events() has been called
                - mutex drawable::m is locked
                - is_enabled() == true
                - is_hidden() == false
                - the area in parent_window() defined by get_rect() has been invalidated.
                  (This means you don't have to call invalidate_rectangle())
                - is called whenever this object transitions from the state where
                  is_depressed() == false to is_depressed() == true
            ensures
                - does not change the state of mutex drawable::m.
        !*/

        // does nothing by default
        virtual void on_button_up (
            bool mouse_over
        ){}
        /*!
            requires
                - enable_events() has been called
                - mutex drawable::m is locked
                - the area in parent_window() defined by get_rect() has been invalidated.
                  (This means you don't have to call invalidate_rectangle())
                - is called whenever this object transitions from the state where
                  is_depressed() == true to is_depressed() == false
                - if (the mouse was over this button when this event occurred) then
                    - mouse_over == true
                - else
                    - mouse_over == false
            ensures
                - does not change the state of mutex drawable::m.
        !*/

    private:

        // restricted functions
        button_action(button_action&);        // copy constructor
        button_action& operator=(button_action&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class button
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class button : public button_action
    {
        /*!
            INITIAL VALUE
                name() == ""
                tooltip_text() == "" (i.e. there is no tooltip by default)

            WHAT THIS OBJECT REPRESENTS
                This object represents a simple button.

                When this object is disabled it means it will not respond to user clicks.
        !*/

    public:

        button(
            drawable_window& w
        );
        /*!
            ensures
                - #*this is properly initialized
                - #*this has been added to window w
                - #parent_window() == w
            throws
                - std::bad_alloc
                - dlib::thread_error
        !*/

        virtual ~button(
        );
        /*!
            ensures
                - all resources associated with *this have been released
        !*/

        void set_size (
            unsigned long width_,
            unsigned long height_
        );
        /*!
            ensures
                - if (width and height are big enough to contain the name of this button) then
                    - #width() == width_
                    - #height() == height_
                    - #top() == top()
                    - #left() == left()
                    - i.e. The location of the upper left corner of this button stays the
                      same but its width and height are modified
        !*/

        void set_name (const std::wstring& name);
        void set_name (const dlib::ustring& name);
        void set_name (
            const std::string& name
        );
        /*!
            ensures
                - #name() == name
                - this button has been resized such that it is big enough to contain
                  the new name.
            throws
                - std::bad_alloc
        !*/

        const std::wstring wname () const;
        const dlib::string uname () const;
        const std::string  name (
        ) const;
        /*!
            ensures
                - returns the name of this button
            throws
                - std::bad_alloc
        !*/

        void set_tooltip_text (const std::wstring& text);
        void set_tooltip_text (const dlib::ustring& text);
        void set_tooltip_text (
            const std::string& text
        );
        /*!
            ensures
                - #tooltip_text() == text
                - enables the tooltip for this button
        !*/

        const dlib::ustring tooltip_utext () const;
        const std::wstring  tooltip_wtext () const;
        const std::string   tooltip_text (
        ) const;
        /*!
            ensures
                - returns the text that is displayed in the tooltip for this button
        !*/

        bool is_depressed (
        ) const;
        /*!
            ensures
                - if (this button is currently in a depressed state) then
                    - the user has left clicked on this widget and is still
                      holding the left mouse button down over it.
                    - returns true
                - else
                    - returns false
        !*/

        template <
            typename style_type
            >
        void set_style (
            const style_type& style
        );
        /*!
            requires
                - style_type == a type that inherits from button_style
            ensures
                - this button object will draw itself using the given
                  button style
        !*/

        template <
            typename T
            >
        void set_click_handler (
            T& object,
            void (T::*event_handler)()
        );
        /*!
            requires
                - event_handler is a valid pointer to a member function in T
            ensures
                - the event_handler function is called on object when the button is
                  clicked by the user.
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

        void set_click_handler (
            const any_function<void()>& event_handler
        );
        /*!
            ensures
                - the event_handler function is called when the button is clicked by
                  the user.
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

        template <
            typename T
            >
        void set_click_handler (
            T& object,
            void (T::*event_handler)(button& self)
        );
        /*!
            requires
                - event_handler is a valid pointer to a member function in T
            ensures
                - &self == this
                - the event_handler function is called on object when the button is
                  clicked by the user.
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

        void set_sourced_click_handler (
            const any_function<void(button& self)>& event_handler
        );
        /*!
            ensures
                - &self == this
                - the event_handler function is called when the button is clicked by
                  the user.
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

        template <
            typename T
            >
        void set_button_down_handler (
            T& object,
            void (T::*event_handler)()
        );
        /*!
            requires
                - event_handler is a valid pointer to a member function in T
            ensures
                - the event_handler function is called on object when the user causes
                  the button to go into its depressed state.
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

        void set_button_down_handler (
            const any_function<void()>& event_handler
        );
        /*!
            ensures
                - the event_handler function is called when the user causes the button
                  to go into its depressed state.
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

        template <
            typename T
            >
        void set_button_up_handler (
            T& object,
            void (T::*event_handler)(bool mouse_over)
        );
        /*!
            requires
                - event_handler is a valid pointer to a member function in T
            ensures
                - the event_handler function is called on object when the user causes
                  the button to go into its non-depressed state.
                - if (the mouse is over this button when this event occurs) then
                    - mouse_over == true
                - else
                    - mouse_over == false
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

        void set_button_up_handler (
            const any_function<void(bool mouse_over)>& event_handler
        );
        /*!
            ensures
                - the event_handler function is called when the user causes the
                  button to go into its non-depressed state.
                - if (the mouse is over this button when this event occurs) then
                    - mouse_over == true
                - else
                    - mouse_over == false
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

        template <
            typename T
            >
        void set_button_down_handler (
            T& object,
            void (T::*event_handler)(button& self)
        );
        /*!
            requires
                - event_handler is a valid pointer to a member function in T
            ensures
                - &self == this
                - the event_handler function is called on object when the user causes
                  the button to go into its depressed state.
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

        void set_sourced_button_down_handler (
            const any_function<void(button& self)>& event_handler
        );
        /*!
            ensures
                - &self == this
                - the event_handler function is called when the user causes the button
                  to go into its depressed state.
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

        template <
            typename T
            >
        void set_button_up_handler (
            T& object,
            void (T::*event_handler)(bool mouse_over, button& self)
        );
        /*!
            requires
                - event_handler is a valid pointer to a member function in T
            ensures
                - &self == this
                - the event_handler function is called on object when the user causes
                  the button to go into its non-depressed state.
                - if (the mouse is over this button when this event occurs) then
                    - mouse_over == true
                - else
                    - mouse_over == false
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

        void set_sourced_button_up_handler (
            const any_function<void(bool mouse_over, button& self)>& event_handler
        );
        /*!
            ensures
                - &self == this
                - the event_handler function is called when the user causes the
                  button to go into its non-depressed state.
                - if (the mouse is over this button when this event occurs) then
                    - mouse_over == true
                - else
                    - mouse_over == false
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

    private:

        // restricted functions
        button(button&);        // copy constructor
        button& operator=(button&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class scroll_bar
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class scroll_bar : public drawable
    {
        /*!
            INITIAL VALUE
                orientation() == a value given to the constructor.
                max_slider_pos() == 0
                slider_pos() == 0
                jump_size() == 10

            WHAT THIS OBJECT REPRESENTS
                This object represents a scroll bar.  The slider_pos() of the scroll bar
                ranges from 0 to max_slider_pos().  The 0 position of the scroll_bar is
                in the top or left side of the scroll_bar depending on its orientation.

                When this object is disabled it means it will not respond to user clicks.
        !*/

    public:
        enum bar_orientation
        {
            HORIZONTAL,
            VERTICAL
        };

        scroll_bar(
            drawable_window& w,
            bar_orientation orientation
        );
        /*!
            ensures
                - #*this is properly initialized
                - #*this has been added to window w
                - #orientation() == orientation
                - #parent_window() == w
            throws
                - std::bad_alloc
                - dlib::thread_error
        !*/

        virtual ~scroll_bar(
        );
        /*!
            ensures
                - all resources associated with *this have been released
        !*/

        bar_orientation orientation (
        ) const;
        /*!
            ensures
                - returns the orientation of this scroll_bar
        !*/

        template <
            typename style_type
            >
        void set_style (
            const style_type& style
        );
        /*!
            requires
                - style_type == a type that inherits from scroll_bar_style
            ensures
                - this scroll_bar object will draw itself using the given
                  scroll bar style
        !*/

        void set_length (
            unsigned long length,
        );
        /*!
            ensures
                - if (orientation() == HORIZONTAL) then
                    - #width() == max(length,1)
                - else
                    - #height() == max(length,1)
        !*/

        long max_slider_pos (
        ) const;
        /*!
            ensures
                - returns the maximum value that slider_pos() can take.
        !*/

        void set_max_slider_pos (
            long mpos
        );
        /*!
            ensures
                - if (mpos < 0) then
                    - #max_slider_pos() == 0
                - else
                    - #max_slider_pos() == mpos
                - if (slider_pos() > #max_slider_pos()) then
                    - #slider_pos() == #max_slider_pos()
                - else
                    - #slider_pos() == slider_pos()
        !*/

        void set_slider_pos (
            unsigned long pos
        );
        /*!
            ensures
                - if (pos < 0) then
                    - #slider_pos() == 0
                - else if (pos > max_slider_pos()) then
                    - #slider_pos() == max_slider_pos()
                - else
                    - #slider_pos() == pos
        !*/

        long slider_pos (
        ) const;
        /*!
            ensures
                - returns the current position of the slider box within the scroll bar.
        !*/

        long jump_size (
        ) const;
        /*!
            ensures
                - returns the number of positions that the slider bar will jump when the
                  user clicks on the empty gaps above or below the slider bar.
                  (note that the slider will jump less than the jump size if it hits the
                  end of the scroll bar)
        !*/

        void set_jump_size (
            long js
        );
        /*!
            ensures
                - if (js < 1) then
                    - #jump_size() == 1
                - else
                    - #jump_size() == js
        !*/

        template <
            typename T
            >
        void set_scroll_handler (
            T& object,
            void (T::*event_handler)()
        );
        /*!
            requires
                - event_handler is a valid pointer to a member function in T
            ensures
                - The event_handler function is called whenever the user causes the slider box
                  to move.
                - This event is NOT triggered by calling set_slider_pos()
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

        void set_scroll_handler (
            const any_function<void()>& event_handler
        );
        /*!
            ensures
                - The event_handler function is called whenever the user causes the slider box
                  to move.
                - This event is NOT triggered by calling set_slider_pos()
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

    private:

        // restricted functions
        scroll_bar(scroll_bar&);        // copy constructor
        scroll_bar& operator=(scroll_bar&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class widget_group
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class widget_group : public drawable
    {
        /*!
            INITIAL VALUE
                size() == 0
                get_rect().is_empty() == true
                left() == 0
                top() == 0

            WHAT THIS OBJECT REPRESENTS
                This object represents a grouping of drawable widgets.  It doesn't draw
                anything itself, rather it lets you manipulate the position, enabled
                status, and visibility of a set of widgets as a group.
        !*/

    public:
        widget_group(
            drawable_window& w
        );
        /*!
            ensures
                - #*this is properly initialized
                - #*this has been added to window w
                - #parent_window() == w
            throws
                - std::bad_alloc
                - dlib::thread_error
        !*/

        virtual ~widget_group(
        );
        /*!
            ensures
                - all resources associated with *this have been released.
        !*/

        void empty (
        );
        /*!
            ensures
                - #size() == 0
        !*/

        void fit_to_contents (
        );
        /*!
            ensures
                - does not change the position of this object.
                  (i.e. the upper left corner of get_rect() remains at the same position)
                - if (size() == 0) then
                    - #get_rect().is_empty() == true
                - else
                    - recursively calls fit_to_contents() on any widget_groups inside
                      this object.
                    - #get_rect() will be the smallest rectangle that contains all the
                      widgets in this group and the upper left corner of get_rect().
        !*/

        unsigned long size (
        ) const;
        /*!
            ensures
                - returns the number of widgets currently in *this.
        !*/

        void add (
            drawable& widget,
            unsigned long x,
            unsigned long y
        );
        /*!
            ensures
                - #is_member(widget) == true
                - if (is_member(widget) == false) then
                    - #size() == size() + 1
                - else
                    - #size() == size()
                - The following conditions apply to this function as well as to all of the
                  following functions so long as is_member(widget) == true:
                  enable(), disable(), hide(), show(), set_z_order(), and set_pos().
                    - #widget.left() == left()+x
                    - #widget.width() == widget.width()
                    - #widget.top() == top()+y
                    - #widget.height() == widget.height()
                    - #widget.is_hidden() == is_hidden()
                    - #widget.is_enabled() == is_enabled()
                    - #widget.z_order() == z_order()
            throws
                - std::bad_alloc
        !*/

        bool is_member (
            const drawable& widget
        ) const;
        /*!
            ensures
                - returns true if widget is currently in this object, returns false otherwise.
        !*/

        void remove (
            const drawable& widget
        );
        /*!
            ensures
                - #is_member(widget) == false
                - if (is_member(widget) == true) then
                    - #size() == size() - 1
                - else
                    - #size() == size()
        !*/

    protected:

        // this object doesn't draw anything but also isn't abstract
        void draw (
            const canvas& c
        ) const {}

    private:

        // restricted functions
        widget_group(widget_group&);        // copy constructor
        widget_group& operator=(widget_group&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class image_widget
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class image_widget : public draggable
    {
        /*!
            INITIAL VALUE
                draggable_area() == an initial value for its type.
                This object isn't displaying anything.

            WHAT THIS OBJECT REPRESENTS
                This object represents a draggable image.  You give it an image to display
                by calling set_image().

                Also note that initially the draggable area is empty so it won't be
                draggable unless you call set_draggable_area() to some non-empty region.

                The image is drawn such that:
                    - the pixel img[0][0] is the upper left corner of the image.
                    - the pixel img[img.nr()-1][0] is the lower left corner of the image.
                    - the pixel img[0][img.nc()-1] is the upper right corner of the image.
                    - the pixel img[img.nr()-1][img.nc()-1] is the lower right corner of the image.

        !*/

    public:

        image_widget(
            drawable_window& w
        );
        /*!
            ensures
                - #*this is properly initialized
                - #*this has been added to window w
                - #parent_window() == w
            throws
                - std::bad_alloc
                - dlib::thread_error
        !*/

        virtual ~image_widget(
        );
        /*!
            ensures
                - all resources associated with *this have been released
        !*/

        template <
            typename image_type
            >
        void set_image (
            const image_type& img
        );
        /*!
            requires
                - image_type == an implementation of array2d/array2d_kernel_abstract.h
                - pixel_traits<typename image_type::type> must be defined
            ensures
                - #width() == img.nc()
                - #height() == img.nr()
                - #*this widget is now displaying the given image img.
        !*/

    private:

        // restricted functions
        image_widget(image_widget&);        // copy constructor
        image_widget& operator=(image_widget&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class tooltip
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class tooltip : public mouse_over_event
    {
        /*!
            INITIAL VALUE
                - text() == ""
                - the tooltip is inactive until the text is changed to
                  a non-empty string.

            WHAT THIS OBJECT REPRESENTS
                This object represents a region on a window where if the user
                hovers the mouse over this region a tooltip with a message
                appears.
        !*/

    public:

        tooltip(
            drawable_window& w
        );
        /*!
            ensures
                - #*this is properly initialized
                - #*this has been added to window w
                - #parent_window() == w
            throws
                - std::bad_alloc
                - dlib::thread_error
        !*/

        virtual ~tooltip(
        );
        /*!
            ensures
                - all resources associated with *this have been released
        !*/

        void set_size (
            unsigned long width_,
            unsigned long height_
        );
        /*!
            ensures
                - #width() == width_
                - #height() == height_
                - #top() == top()
                - #left() == left()
                - i.e. The location of the upper left corner of this widget stays the
                  same but its width and height are modified
        !*/

        void set_text (const std::wstring& str);
        void set_text (const dlib::ustring& str);
        void set_text (
            const std::string& str
        );
        /*!
            ensures
                - #text() == str
                - activates the tooltip.  i.e. after this function the tooltip
                  will display on the screen when the user hovers the mouse over it
        !*/

        const std::wstring  wtext () const;
        const dlib::ustring utext () const;
        const std::string   text (
        ) const;
        /*!
            ensures
                - returns the text that is displayed inside this
                  tooltip
        !*/

    private:

        // restricted functions
        tooltip(tooltip&);        // copy constructor
        tooltip& operator=(tooltip&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // popup menu stuff
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class menu_item
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is an abstract class that defines the interface a
                menu item in a popup_menu must implement.

                Note that a menu_item is drawn as 3 separate pieces:
                    ---------------------------------
                    | left | middle |         right |
                    ---------------------------------

                Also note that derived classes must be copyable via
                their copy constructors.
        !*/

    public:

        virtual ~menu_item() {}

        virtual void on_click (
        ) const {}
        /*!
            requires
                - the mutex drawable::m is locked
                - if (has_click_event()) then
                    - this function is called when the user clicks on this menu_item
        !*/

        virtual bool has_click_event (
        ) const { return false; }
        /*!
            ensures
                - if (this menu_item wants to receive on_click events) then
                    - returns true
                - else
                    - returns false
        !*/

        virtual unichar get_hot_key (
        ) const { return 0; }
        /*!
            ensures
                - if (this menu item has a keyboard hot key) then
                    - returns the unicode value of the key
                - else
                    - returns 0
        !*/

        virtual rectangle get_left_size (
        ) const { return rectangle(); } // return empty rect by default
        /*!
            ensures
                - returns the dimensions of the left part of the menu_item
        !*/

        virtual rectangle get_middle_size (
        ) const = 0;
        /*!
            ensures
                - returns the dimensions of the middle part of the menu_item
        !*/

        virtual rectangle get_right_size (
        ) const { return rectangle(); } // return empty rect by default
        /*!
            ensures
                - returns the dimensions of the right part of the menu_item
        !*/

        virtual void draw_background (
            const canvas& c,
            const rectangle& rect,
            const bool enabled,
            const bool is_selected
        ) const {}
        /*!
            requires
                - the mutex drawable::m is locked
            requires
                - c == the canvas to draw on
                - rect == the rectangle in which we are to draw the background
                - enabled == true if the menu_item is to be drawn enabled
                - is_selected == true if the menu_item is to be drawn selected
            ensures
                - draws the background of the menu_item on the canvas c at the location
                  given by rect.
        !*/

        virtual void draw_left (
            const canvas& c,
            const rectangle& rect,
            const bool enabled,
            const bool is_selected
        ) const {}
        /*!
            requires
                - the mutex drawable::m is locked
            requires
                - c == the canvas to draw on
                - rect == the rectangle in which we are to draw the background
                - enabled == true if the menu_item is to be drawn enabled
                - is_selected == true if the menu_item is to be drawn selected
            ensures
                - draws the left part of the menu_item on the canvas c at the location
                  given by rect.
        !*/

        virtual void draw_middle (
            const canvas& c,
            const rectangle& rect,
            const bool enabled,
            const bool is_selected
        ) const = 0;
        /*!
            requires
                - the mutex drawable::m is locked
            requires
                - c == the canvas to draw on
                - rect == the rectangle in which we are to draw the background
                - enabled == true if the menu_item is to be drawn enabled
                - is_selected == true if the menu_item is to be drawn selected
            ensures
                - draws the middle part of the menu_item on the canvas c at the location
                  given by rect.
        !*/

        virtual void draw_right (
            const canvas& c,
            const rectangle& rect,
            const bool enabled,
            const bool is_selected
        ) const {}
        /*!
            requires
                - the mutex drawable::m is locked
            requires
                - c == the canvas to draw on
                - rect == the rectangle in which we are to draw the background
                - enabled == true if the menu_item is to be drawn enabled
                - is_selected == true if the menu_item is to be drawn selected
            ensures
                - draws the right part of the menu_item on the canvas c at the location
                  given by rect.
        !*/
    };

// ----------------------------------------------------------------------------------------

    class menu_item_text : public menu_item
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is a simple text menu item
        !*/

    public:

        template <
            typename T
            >
        menu_item_text (
            const std::string& str,
            T& object,
            void (T::*on_click_handler)(),
            unichar hotkey = 0
        );
        /*!
            ensures
                - The text of this menu item will be str
                - the on_click_handler function is called on object when this menu_item
                  clicked by the user.
                - #get_hot_key() == hotkey
        !*/

        menu_item_text (
            const std::string& str,
            const any_function<void()>& on_click_handler,
            unichar hotkey = 0
        );
        /*!
            ensures
                - The text of this menu item will be str
                - the on_click_handler function is called when this menu_item
                  clicked by the user.
                - #get_hot_key() == hotkey
        !*/

        // overloads for wide character strings
        template <
            typename T
            >
        menu_item_text (
            const std::wstring& str,
            T& object,
            void (T::*on_click_handler)(),
            unichar hotkey = 0
        );

        menu_item_text (
            const std::wstring& str,
            const any_function<void()>& on_click_handler,
            unichar hotkey = 0
        );

        template <
            typename T
            >
        menu_item_text (
            const dlib::ustring& str,
            T& object,
            void (T::*on_click_handler)(),
            unichar hotkey = 0
        );

        template <
            typename T
            >
        menu_item_text (
            const dlib::ustring& str,
            const any_function<void()>& on_click_handler,
            unichar hotkey = 0
        );
    };

// ----------------------------------------------------------------------------------------

    class menu_item_submenu : public menu_item
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is a simple text item intended to be used with
                submenus inside a popup_menu.
        !*/

    public:

        menu_item_submenu (
            const std::string& str,
            unichar hotkey = 0
        );
        /*!
            ensures
                - The text of this menu item will be str
                - #get_hot_key() == hotkey
        !*/

        //overloads for wide character strings
        menu_item_submenu (
            const std::wstring& str,
            unichar hotkey = 0
        );

        menu_item_submenu (
            const dlib::ustring& str,
            unichar hotkey = 0
        );
    };

// ----------------------------------------------------------------------------------------

    class menu_item_separator : public menu_item
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is a horizontal separator in a popup menu
        !*/
    };

// ----------------------------------------------------------------------------------------

    class popup_menu : public base_window
    {
        /*!
            INITIAL VALUE
                - size() == 0

            WHAT THIS OBJECT REPRESENTS
                This object represents a popup menu window capable of containing
                menu_item objects.
        !*/

    public:

        popup_menu (
        );
        /*!
            ensures
                - #*this is properly initialized
            throws
                - std::bad_alloc
                - dlib::thread_error
                - dlib::gui_error
        !*/

        void clear (
        );
        /*!
            ensures
                - #*this has its initial value
            throws
                - std::bad_alloc
                  if this exception is thrown then *this is unusable
                  until clear() is called and succeeds
        !*/

        template <
            typename menu_item_type
            >
        unsigned long add_menu_item (
            const menu_item_type& new_item
        );
        /*!
            requires
                - menu_item_type == a type that inherits from menu_item
            ensures
                - adds new_item onto the bottom of this popup_menu.
                - returns size()
                  (This is also the index by which this item can be
                  referenced by the enable_menu_item() and disable_menu_item()
                  functions.)
        !*/

        template <
            typename menu_item_type
            >
        unsigned long add_submenu (
            const menu_item_type& new_item,
            popup_menu& submenu
        );
        /*!
            requires
                - menu_item_type == a type that inherits from menu_item
            ensures
                - adds new_item onto the bottom of this popup_menu.
                - when the user puts the mouse above this menu_item the given
                  submenu popup_menu will be displayed.
                - returns size()
                  (This is also the index by which this item can be
                  referenced by the enable_menu_item() and disable_menu_item()
                  functions.)
        !*/

        void enable_menu_item (
            unsigned long idx
        );
        /*!
            requires
                - idx < size()
            ensures
                - the menu_item in this with the index idx has been enabled
        !*/

        void disable_menu_item (
            unsigned long idx
        );
        /*!
            requires
                - idx < size()
            ensures
                - the menu_item in this with the index idx has been disabled
        !*/

        unsigned long size (
        ) const;
        /*!
            ensures
                - returns the number of menu_item objects in this popup_menu
        !*/

        template <typename T>
        void set_on_hide_handler (
            T& object,
            void (T::*event_handler)()
        );
        /*!
            ensures
                - the event_handler function is called on object when this popup_menu
                  hides itself due to an action by the user.
                - Note that you can register multiple handlers for this event.
        !*/

        void select_first_item (
        );
        /*!
            ensures
                - causes this popup menu to highlight the first
                  menu item that it contains which has a click event
                  and is enabled.
        !*/

        bool forwarded_on_keydown (
            unsigned long key,
            bool is_printable,
            unsigned long state
        );
        /*!
            requires
                - key, is_printable, and state are the variables from the
                  base_window::on_keydown() event
            ensures
                - forwards this keyboard event to this popup window so that it
                  may deal with keyboard events from other windows.
                - if (this popup_menu uses the keyboard event) then
                    - returns true
                - else
                    - returns false
        !*/

    private:

        // restricted functions
        popup_menu(popup_menu&);        // copy constructor
        popup_menu& operator=(popup_menu&);    // assignment operator

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class popup_menu_region
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class popup_menu_region : public drawable
    {
        /*!
            INITIAL VALUE
                - popup_menu_visible() == false

            WHAT THIS OBJECT REPRESENTS
                This object represents a region on a window where if the user
                right clicks the mouse over this region a popup_menu pops up.

                Note that this widget doesn't actually draw anything, it just
                provides a region the user can click on to get a popup menu.
        !*/

    public:

        popup_menu_region(
            drawable_window& w
        );
        /*!
            ensures
                - #*this is properly initialized
                - #*this has been added to window w
                - #parent_window() == w
            throws
                - std::bad_alloc
                - dlib::thread_error
        !*/

        virtual ~popup_menu_region(
        );
        /*!
            ensures
                - all resources associated with *this have been released
        !*/

        void set_size (
            unsigned long width_,
            unsigned long height_
        );
        /*!
            ensures
                - #width() == width_
                - #height() == height_
                - #top() == top()
                - #left() == left()
                - i.e. The location of the upper left corner of this widget stays the
                  same but its width and height are modified
        !*/

        void set_rect (
            const rectangle& new_rect
        );
        /*!
            ensures
                - #get_rect() == new_rect
        !*/

        bool popup_menu_visible (
        ) const;
        /*!
            ensures
                - if (the popup menu is currently visible on the screen) then
                    - returns true
                - else
                    - returns false
        !*/

        popup_menu& menu (
        );
        /*!
            ensures
                - returns a reference to the popup_menu for this object. It is
                  the menu that is displayed when the user right clicks on
                  this widget
        !*/

    private:

        // restricted functions
        popup_menu_region(popup_menu_region&);        // copy constructor
        popup_menu_region& operator=(popup_menu_region&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class zoomable_region
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class zoomable_region : public drawable
    {
        /*
            INITIAL VALUE
                - min_zoom_scale() == 0.15
                - max_zoom_scale() == 1.0
                - zoom_increment() == 0.90
                - zoom_scale() == 1.0

            WHAT THIS OBJECT REPRESENTS
                This object represents a 2D Cartesian graph that you can zoom into and
                out of.  It is a graphical widget that draws a rectangle with
                a horizontal and vertical scroll bar that allow the user to scroll
                around on a Cartesian graph that is much larger than the actual
                area occupied by this object on the screen.  It also allows
                the user to zoom in and out.

                To use this object you inherit from it and make use of its public and
                protected member functions.  It provides functions for converting between
                pixel locations and the points in our 2D Cartesian graph so that when the
                user is scrolling/zooming the widget you can still determine where
                things are to be placed on the screen and what screen pixels correspond
                to in the Cartesian graph.

                Note that the Cartesian graph in this object is bounded by the point
                (0,0), corresponding to the upper left corner when we are zoomed all
                the way out, and max_graph_point() which corresponds to the lower right
                corner when zoomed all the way out. The value of max_graph_point() is
                determined automatically from the size of this object's on screen
                rectangle and the value of min_zoom_scale() which determines how far
                out you can zoom.
        */

    public:

        zoomable_region (
            drawable_window& w,
            unsigned long events = 0
        );
        /*!
            ensures
                - #*this is properly initialized
                - #*this has been added to window w
                - #parent_window() == w
                - This object will not receive any events or draw() requests until
                  enable_events() is called
                - the events flags are passed on to the drawable object's
                  constructor.
            throws
                - std::bad_alloc
                - dlib::thread_error
        !*/

        virtual ~zoomable_region (
        ) = 0;
        /*!
            ensures
                - all resources associated with *this have been released
        !*/

        template <
            typename style_type
            >
        void set_style (
            const style_type& style_
        );
        /*!
            requires
                - style_type == a type that inherits from scrollable_region_style
            ensures
                - this zoomable_region object will draw itself using the given
                  style
        !*/

        void set_zoom_increment (
            double zi
        );
        /*!
            requires
                - 0 < zi < 1
            ensures
                - #zoom_increment() == zi
        !*/

        double zoom_increment (
        ) const;
        /*!
            ensures
                - When the user zooms in using the mouse wheel:
                    - #zoom_scale() == zoom_scale() / zoom_increment()
                - When the user zooms out using the mouse wheel:
                    - #zoom_scale() == zoom_scale() * zoom_increment()
                - So this function returns the number that determines how much the zoom
                  changes when the mouse wheel is moved.
        !*/

        void set_max_zoom_scale (
            double ms
        );
        /*!
            requires
                - ms > 0
            ensures
                - #max_zoom_scale() == ms
        !*/

        void set_min_zoom_scale (
            double ms
        );
        /*!
            requires
                - ms > 0
            ensures
                - #min_zoom_scale() == ms
        !*/

        double min_zoom_scale (
        ) const;
        /*!
            ensures
                - returns the minimum allowed value of zoom_scale()
                  (i.e. this is the number that determines how far out the user is allowed to zoom)
        !*/

        double max_zoom_scale (
        ) const;
        /*!
            ensures
                - returns the maximum allowed value of zoom_scale()
                  (i.e. this is the number that determines how far in the user is allowed to zoom)
        !*/

        virtual void set_size (
            unsigned long width,
            unsigned long height
        );
        /*!
            ensures
                - #width() == width_
                - #height() == height_
                - #top() == top()
                - #left() == left()
                - i.e. The location of the upper left corner of this button stays the
                  same but its width and height are modified
        !*/

    protected:

        rectangle display_rect (
        ) const;
        /*!
            requires
                - mutex drawable::m is locked
            ensures
                - returns the rectangle on the screen that contains the Cartesian
                  graph in this widget.  I.e. this is the area of this widget minus
                  the area taken up by the scroll bars and border decorations.
        !*/

        point graph_to_gui_space (
            const vector<double,2>& graph_point
        ) const;
        /*!
            requires
                - mutex drawable::m is locked
            ensures
                - returns the location of the pixel on the screen that corresponds
                  to the given point in Cartesian graph space
        !*/

        vector<double,2> gui_to_graph_space (
            const point& pixel_point
        ) const;
        /*!
            requires
                - mutex drawable::m is locked
            ensures
                - returns the point in Cartesian graph space that corresponds to the given
                  pixel location
        !*/

        vector<double,2> max_graph_point (
        ) const;
        /*!
            requires
                - mutex drawable::m is locked
            ensures
                - returns the pixel farthest from the graph point (0,0) that is still
                  in the graph.  I.e. returns the point in graph space that corresponds
                  to the lower right corner of the display_rect() when we are zoomed
                  all the way out.
        !*/

        double zoom_scale (
        ) const;
        /*!
            requires
                - mutex drawable::m is locked
            ensures
                - returns a double Z that represents the current zoom.
                    - Smaller values of Z represent the user zooming out.
                    - Bigger values of Z represent the user zooming in.
                    - The default unzoomed case is when Z == 1
                    - objects should be drawn such that they are zoom_scale()
                      times their normal size
        !*/

        void set_zoom_scale (
            double new_scale
        );
        /*!
            requires
                - mutex drawable::m is locked
            ensures
                - invalidates the display_rect() so that it will be redrawn
                - if (min_zoom_scale() <= new_scale && new_scale <= max_zoom_scale()) then
                    - #zoom_scale() == new_scale
                - else if (new_scale < min_zoom_scale()) then
                    - #zoom_scale() == min_zoom_scale()
                - else if (new_scale > max_zoom_scale()) then
                    - #zoom_scale() == max_zoom_scale()
        !*/

        void center_display_at_graph_point (
            const vector<double,2>& graph_point
        );
        /*!
            requires
                - mutex drawable::m is locked
            ensures
                - causes the given graph point to be centered in the display
                  if possible
                - invalidates the display_rect() so that it will be redrawn
        !*/

        virtual void on_view_changed (
        ) {}
        /*!
            requires
                - events_are_enabled() == true
                - mutex drawable::m is locked
            ensures
                - on_view_changed() is called whenever the user causes the view of the
                  zoomable_region to change.  That is, this function is called when the
                  user scrolls or zooms around in the region.
        !*/

    // ---------------------------- event handlers ----------------------------
    // The following event handlers are used in this object.  So if you
    // use any of them in your derived object you should pass the events
    // back to it so that they still operate unless you wish to hijack the
    // event for your own reasons (e.g. to override the mouse drag this object
    // performs)

        void on_wheel_down (unsigned long state);
        void on_wheel_up (unsigned long state);
        void on_mouse_move ( unsigned long state, long x, long y);
        void on_mouse_up ( unsigned long btn, unsigned long state, long x, long y);
        void on_mouse_down ( unsigned long btn, unsigned long state, long x, long y, bool is_double_click);
        void draw ( const canvas& c) const;

    private:

        // restricted functions
        zoomable_region(zoomable_region&);        // copy constructor
        zoomable_region& operator=(zoomable_region&);    // assignment operator

    };

// ----------------------------------------------------------------------------------------

    class scrollable_region : public drawable
    {
        /*!
            INITIAL VALUE
                - horizontal_scroll_pos() == 0
                - horizontal_scroll_increment() == 1
                - horizontal_mouse_wheel_scroll_increment() == 1
                - vertical_scroll_pos() == 0
                - vertical_scroll_increment() == 1
                - vertical_mouse_wheel_scroll_increment() == 1
                - total_rect().empty() == true
                - mouse_drag_enabled() == false

            WHAT THIS OBJECT REPRESENTS
                This object represents a 2D region of arbitrary size that is displayed
                within a possibly smaller scrollable gui widget.  That is, it is a
                graphical widget that draws a rectangle with a horizontal and vertical
                scroll bar that allows the user to scroll around on a region that is much
                larger than the actual area occupied by this object on the screen.

                To use this object you inherit from it and make use of its public and
                protected member functions.  It provides a function, total_rect(), that
                tells you where the 2D region is on the screen.  You draw your stuff
                inside total_rect() as you would normally except that you only modify
                pixels that are also inside display_rect().  When the user moves the
                scroll bars the position of total_rect() is updated accordingly, causing
                the widget's content to scroll across the screen.
        !*/

    public:
        scrollable_region (
            drawable_window& w,
            unsigned long events = 0
        );
        /*!
            ensures
                - #*this is properly initialized
                - #*this has been added to window w
                - #parent_window() == w
                - This object will not receive any events or draw() requests until
                  enable_events() is called
                - the events flags are passed on to the drawable object's
                  constructor.
            throws
                - std::bad_alloc
                - dlib::thread_error
        !*/

        virtual ~scrollable_region (
        ) = 0;
        /*!
            ensures
                - all resources associated with *this have been released
        !*/

        template <
            typename style_type
            >
        void set_style (
            const style_type& style_
        );
        /*!
            requires
                - style_type == a type that inherits from scrollable_region_style
            ensures
                - this scrollable_region object will draw itself using the given
                  style
        !*/

        virtual void set_size (
            unsigned long width,
            unsigned long height
        );
        /*!
            ensures
                - #width() == width_
                - #height() == height_
                - #top() == top()
                - #left() == left()
                - i.e. The location of the upper left corner of this widget stays the
                  same but its width and height are modified.
        !*/

        long horizontal_scroll_pos (
        ) const;
        /*!
            ensures
                - returns the current position of the horizontal scroll bar.
                  0 means it is at the far left while bigger values represent
                  scroll positions closer to the right.
        !*/

        long vertical_scroll_pos (
        ) const;
        /*!
            ensures
                - returns the current position of the vertical scroll bar.
                  0 means it is at the top and bigger values represent scroll positions
                  closer to the bottom.
        !*/

        void set_horizontal_scroll_pos (
            long pos
        );
        /*!
            ensures
                - if (pos is a valid horizontal scroll position) then
                    - #horizontal_scroll_pos() == pos
                - else
                    - #horizontal_scroll_pos() == the valid scroll position closest to pos
        !*/

        void set_vertical_scroll_pos (
            long pos
        );
        /*!
            ensures
                - if (pos is a valid vertical scroll position) then
                    - #vertical_scroll_pos() == pos
                - else
                    - #vertical_scroll_pos() == the valid scroll position closest to pos
        !*/

        unsigned long horizontal_mouse_wheel_scroll_increment (
        ) const;
        /*!
            ensures
                - returns the number of positions the horizontal scroll bar
                  moves when the user scrolls the mouse wheel.
        !*/

        unsigned long vertical_mouse_wheel_scroll_increment (
        ) const;
        /*!
            ensures
                - returns the number of positions the vertical scroll bar
                  moves when the user scrolls the mouse wheel.
        !*/

        void set_horizontal_mouse_wheel_scroll_increment (
            unsigned long inc
        );
        /*!
            ensures
                - #horizontal_mouse_wheel_scroll_increment() == inc
        !*/

        void set_vertical_mouse_wheel_scroll_increment (
            unsigned long inc
        );
        /*!
            ensures
                - #vertical_mouse_wheel_scroll_increment() == inc
        !*/

        unsigned long horizontal_scroll_increment (
        ) const;
        /*!
            ensures
                - returns the number of pixels that total_rect() is moved by when
                  the horizontal scroll bar moves by one position
        !*/

        unsigned long vertical_scroll_increment (
        ) const;
        /*!
            ensures
                - returns the number of pixels that total_rect() is moved by when
                  the vertical scroll bar moves by one position
        !*/

        void set_horizontal_scroll_increment (
            unsigned long inc
        );
        /*!
            ensures
                - #horizontal_scroll_increment() == inc
        !*/

        void set_vertical_scroll_increment (
            unsigned long inc
        );
        /*!
            ensures
                - #vertical_scroll_increment() == inc
        !*/

        bool mouse_drag_enabled (
        ) const;
        /*!
            ensures
                - if (the user can drag this contents of this widget around by
                  holding down the left mouse button and dragging) then
                    - returns true
                - else
                    - returns false
        !*/

        void enable_mouse_drag (
        );
        /*!
            ensures
                - #mouse_drag_enabled() == true
        !*/

        void disable_mouse_drag (
        );
        /*!
            ensures
                - #mouse_drag_enabled() == false
        !*/

    protected:

        rectangle display_rect (
        ) const;
        /*!
            requires
                - mutex drawable::m is locked
            ensures
                - returns the rectangle on the screen that contains the scrollable
                  area in this widget.  I.e. this is the area of this widget minus
                  the area taken up by the scroll bars and border decorations.
        !*/

        void set_total_rect_size (
            unsigned long width,
            unsigned long height
        );
        /*!
            requires
                - mutex drawable::m is locked
                - (width > 0 && height > 0) || (width == 0 && height == 0)
            ensures
                - #total_rect().width()  == width
                - #total_rect().height() == height
                - The scroll bars as well as the position of #total_rect()
                  is updated so that the total rect is still in the correct
                  position with respect to the scroll bars.
        !*/

        const rectangle& total_rect (
        ) const;
        /*!
            requires
                - mutex drawable::m is locked
            ensures
                - returns a rectangle that represents the entire scrollable
                  region inside this widget, even the parts that are outside
                  display_rect().
        !*/

        void scroll_to_rect (
            const rectangle& r
        );
        /*!
            requires
                - mutex drawable::m is locked
            ensures
                - Adjusts the scroll bars of this object so that the part of
                  the total_rect() rectangle that overlaps with r is displayed in
                  the display_rect() rectangle on the screen.
        !*/

        virtual void on_view_changed (
        ) {}
        /*!
            requires
                - events_are_enabled() == true
                - mutex drawable::m is locked
            ensures
                - on_view_changed() is called whenever the user causes the view of the
                  scrollable_region to change.  That is, this function is called when the
                  user scrolls around in the region.
        !*/

    // ---------------------------- event handlers ----------------------------
    // The following event handlers are used in this object.  So if you
    // use any of them in your derived object you should pass the events
    // back to it so that they still operate unless you wish to hijack the
    // event for your own reasons (e.g. to override the mouse wheel action
    // this object performs)

        void on_wheel_down (unsigned long state);
        void on_wheel_up   (unsigned long state);
        void on_mouse_move (unsigned long state, long x, long y);
        void on_mouse_down (unsigned long btn, unsigned long state, long x, long y, bool is_double_click);
        void on_mouse_up   (unsigned long btn, unsigned long state, long x, long y);
        void draw (const canvas& c) const;

    private:

        // restricted functions
        scrollable_region(scrollable_region&);        // copy constructor
        scrollable_region& operator=(scrollable_region&);    // assignment operator

    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_BASE_WIDGETs_ABSTRACT_


dlib C++ Library - widgets_abstract.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net), Keita Mochizuki
// License: Boost Software License   See LICENSE.txt for the full license.

#undef DLIB_WIDGETs_ABSTRACT_
#ifdef DLIB_WIDGETs_ABSTRACT_

#include "fonts_abstract.h"
#include "drawable_abstract.h"
#include "base_widgets_abstract.h"

#include "../gui_core.h"
#include <string>
#include <map>
#include "../interfaces/enumerable.h"
#include "style_abstract.h"
#include "../image_processing/full_object_detection_abstract.h"

namespace dlib
{

    /*!
        GENERAL REMARKS
            This component is a collection of various windowing widgets such as buttons,
            labels, text boxes, and so on.  This component also includes the drawable
            interface, drawable_window, and font handling objects.  The file you are
            currently viewing defines all the high level graphical widgets which are
            provided by this component that can appear in a drawable_window.  To view
            the specifications for the other members of this component look at
            fonts_abstract.h, base_widgets_abstract.h, and drawable_abstract.h

        THREAD SAFETY
            All objects and functions defined in this file are thread safe.  You may
            call them from any thread without serializing access to them.

        EVENT HANDLERS
            Note that all event handlers, including the user registered callback
            functions, are executed in the event handling thread.   Additionally,
            the drawable::m mutex will always be locked while these event handlers
            are running.  Also, don't rely on get_thread_id() always returning the
            same ID from inside event handlers.
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // function open_file_box(), open_existing_file_box(), and save_file_box()
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    void open_file_box (
        T& object,
        void (T::*event_handler)(const std::string&)
    );
    /*!
        requires
            - event_handler == a valid pointer to a member function of object T.
        ensures
            - Displays a window titled "Open File" that will allow the user to select a
              file.
            - The displayed window will start out showing the directory get_current_dir()
              (i.e. it starts in the current working directory)
            - The event_handler function is called on object if the user selects
              a file.  If the user closes the window without selecting a file
              then nothing occurs.
    !*/

    void open_file_box (
        const any_function<void(const std::string&)>& event_handler
    );
    /*!
        ensures
            - Displays a window titled "Open File" that will allow the user to select a
              file.
            - The displayed window will start out showing the directory get_current_dir()
              (i.e. it starts in the current working directory)
            - The event_handler function is called if the user selects
              a file.  If the user closes the window without selecting a file
              then nothing occurs.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    void open_existing_file_box (
        T& object,
        void (T::*event_handler)(const std::string&)
    );
    /*!
        requires
            - event_handler == a valid pointer to a member function of object T.
        ensures
            - Displays a window titled "Open File" that will allow the user to select
              a file.  But only a file that already exists.
            - The displayed window will start out showing the directory get_current_dir()
              (i.e. it starts in the current working directory)
            - The event_handler function is called on object if the user selects
              a file.  If the user closes the window without selecting a file
              then nothing occurs.
    !*/

    void open_existing_file_box (
        const any_function<void(const std::string&)>& event_handler
    );
    /*!
        ensures
            - Displays a window titled "Open File" that will allow the user to select
              a file.  But only a file that already exists.
            - The displayed window will start out showing the directory get_current_dir()
              (i.e. it starts in the current working directory)
            - The event_handler function is called if the user selects
              a file.  If the user closes the window without selecting a file
              then nothing occurs.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    void save_file_box (
        T& object,
        void (T::*event_handler)(const std::string&)
    );
    /*!
        requires
            - event_handler == a valid pointer to a member function of object T.
        ensures
            - Displays a window titled "Save File" that will allow the user to select
              a file.
            - The displayed window will start out showing the directory get_current_dir()
              (i.e. it starts in the current working directory)
            - The event_handler function is called on object if the user selects
              a file.  If the user closes the window without selecting a file
              then nothing occurs.
    !*/

    void save_file_box (
        const any_function<void(const std::string&)>& event_handler
    );
    /*!
        ensures
            - Displays a window titled "Save File" that will allow the user to select
              a file.
            - The displayed window will start out showing the directory get_current_dir()
              (i.e. it starts in the current working directory)
            - The event_handler function is called if the user selects
              a file.  If the user closes the window without selecting a file
              then nothing occurs.
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // function message_box()
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    void message_box (
        const std::string& title,
        const std::string& message
    );
    /*!
        ensures
            - displays a message box with the given title and message.  It will have a
              single button and when the user clicks it the message box will go away.
            - this function does not block but instead returns immediately.
    !*/

    void message_box_blocking (
        const std::string& title,
        const std::string& message
    );
    /*!
        ensures
            - displays a message box with the given title and message.  It will have a
              single button and when the user clicks it the message box will go away.
            - this function blocks until the user clicks on the message box and
              causes it to go away.
    !*/

    template <
        typename T
        >
    void message_box (
        const std::string& title,
        const std::string& message,
        T& object,
        void (T::*event_handler)()
    );
    /*!
        requires
            - event_handler == a valid pointer to a member function of object T.
        ensures
            - Displays a message box with the given title and message.  It will have a
              single button and when the user clicks it the message box will go away.
            - The event_handler function is called on object when the user clicks
              ok or otherwise closes the message box window.
            - this function does not block but instead returns immediately.
    !*/

    void message_box (
        const std::string& title,
        const std::string& message,
        const any_function<void()>& event_handler
    );
    /*!
        ensures
            - Displays a message box with the given title and message.  It will have a
              single button and when the user clicks it the message box will go away.
            - The event_handler function is called when the user clicks
              ok or otherwise closes the message box window.
            - this function does not block but instead returns immediately.
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class label
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class label : public drawable
    {
        /*!
            INITIAL VALUE
                text() == ""
                the text color will be black

            WHAT THIS OBJECT REPRESENTS
                This object represents a simple text label.  The size of the label
                is automatically set to be just big enough to contain its text.
        !*/

    public:

        label(
            drawable_window& w
        );
        /*!
            ensures
                - #*this is properly initialized
                - #*this has been added to window w
                - #parent_window() == w
            throws
                - std::bad_alloc
                - dlib::thread_error
        !*/

        virtual ~label(
        );
        /*!
            ensures
                - all resources associated with *this have been released
        !*/

        void set_text (const std::wstring& text);
        void set_text (const dlib::ustring& text);
        void set_text (
            const std::string& text
        );
        /*!
            ensures
                - #text() == text
            throws
                - std::bad_alloc
        !*/

        const std::wstring  wtext () const;
        const dlib::ustring utext () const;
        const std::string   text (
        ) const;
        /*!
            ensures
                - returns the text of this label
            throws
                - std::bad_alloc
        !*/

        void set_text_color (
            const rgb_pixel color
        );
        /*!
            ensures
                - #text_color() == color
        !*/

        const rgb_pixel text_color (
        ) const;
        /*!
            ensures
                - returns the color used to draw the text in this widget
        !*/

    private:

        // restricted functions
        label(label&);        // copy constructor
        label& operator=(label&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class toggle_button
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class toggle_button : public button_action
    {
        /*!
            INITIAL VALUE
                name() == ""
                is_checked() == false

            WHAT THIS OBJECT REPRESENTS
                This object represents a simple two state toggle button.  Is is either
                in the checked or unchecked state and when a user clicks on it it toggles its
                state.

                When this object is disabled it means it will not respond to user clicks.
        !*/

    public:

        toggle_button(
            drawable_window& w
        );
        /*!
            ensures
                - #*this is properly initialized
                - #*this has been added to window w
                - #parent_window() == w
            throws
                - std::bad_alloc
                - dlib::thread_error
        !*/

        virtual ~toggle_button(
        );
        /*!
            ensures
                - all resources associated with *this have been released
        !*/

        void set_name (const std::wstring& name);
        void set_name (const dlib::ustring& name);
        void set_name (
            const std::string& name
        );
        /*!
            ensures
                - #name() == name
                - this toggle_button has been resized such that it is big enough to contain
                  the new name.
            throws
                - std::bad_alloc
        !*/

        void set_size (
            unsigned long width_,
            unsigned long height_
        );
        /*!
            ensures
                - if (width and height are big enough to contain the name of this button) then
                    - #width() == width_
                    - #height() == height_
                    - #top() == top()
                    - #left() == left()
                    - i.e. The location of the upper left corner of this button stays the
                      same but its width and height are modified
        !*/

        void set_tooltip_text (const std::wstring& text);
        void set_tooltip_text (const dlib::ustring& text);
        void set_tooltip_text (
            const std::string& text
        );
        /*!
            ensures
                - #tooltip_text() == text
                - enables the tooltip for this toggle_button
        !*/

        const dlib::ustring tooltip_utext () const;
        const std::wstring  tooltip_wtext () const;
        const std::string   tooltip_text (
        ) const;
        /*!
            ensures
                - returns the text that is displayed in the tooltip for this toggle_button
        !*/

        template <
            typename style_type
            >
        void set_style (
            const style_type& style
        );
        /*!
            requires
                - style_type == a type that inherits from toggle_button_style
            ensures
                - this toggle_button object will draw itself using the given
                  button style
        !*/

        bool is_checked (
        ) const;
        /*!
            ensures
                - if (this box is currently checked) then
                    - returns true
                - else
                    - returns false
        !*/

        const std::wstring  wname () const;
        const dlib::ustring uname () const;
        const std::string   name (
        ) const;
        /*!
            ensures
                - returns the name of this toggle_button.  The name is a string
                  that appears to the right of the actual check box.
            throws
                - std::bad_alloc
        !*/

        void set_checked (
        );
        /*!
            ensures
                - #is_checked() == true
        !*/

        void set_unchecked (
        );
        /*!
            ensures
                - #is_checked() == false
        !*/

        template <
            typename T
            >
        void set_click_handler (
            T& object,
            void (T::*event_handler)()
        );
        /*!
            requires
                - event_handler is a valid pointer to a member function in T
            ensures
                - the event_handler function is called on object when the toggle_button is
                  toggled by the user.
                - this event is NOT triggered by calling set_checked() or set_unchecked().
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

        void set_click_handler (
            const any_function<void()>& event_handler
        );
        /*!
            ensures
                - the event_handler function is called when the toggle_button is
                  toggled by the user.
                - this event is NOT triggered by calling set_checked() or set_unchecked().
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

        template <
            typename T
            >
        void set_click_handler (
            T& object,
            void (T::*event_handler)(toggle_button& self)
        );
        /*!
            requires
                - event_handler is a valid pointer to a member function in T.
            ensures
                - the event_handler function is called on object when the toggle_button is
                  toggled by the user. self will be a reference to the toggle_button object
                  that the user clicked.
                - this event is NOT triggered by calling set_checked() or set_unchecked().
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

        void set_sourced_click_handler (
            const any_function<void(toggle_button& self)>& event_handler
        );
        /*!
            ensures
                - the event_handler function is called when the toggle_button is
                  toggled by the user. self will be a reference to the toggle_button object
                  that the user clicked.
                - this event is NOT triggered by calling set_checked() or set_unchecked().
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

    private:

        // restricted functions
        toggle_button(toggle_button&);        // copy constructor
        toggle_button& operator=(toggle_button&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class text_field
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class text_field : public drawable
    {
        /*!
            INITIAL VALUE
                - text() == ""
                - width() == 10
                - height() == a height appropriate for the font used.  The text color will
                  be black.
                - has_input_focus() == false

            WHAT THIS OBJECT REPRESENTS
                This object represents a simple one line text input field.
        !*/

    public:

        text_field(
            drawable_window& w
        );
        /*!
            ensures
                - #*this is properly initialized
                - #*this has been added to window w
                - #parent_window() == w
            throws
                - std::bad_alloc
                - dlib::thread_error
        !*/

        virtual ~text_field(
        );
        /*!
            ensures
                - all resources associated with *this have been released
        !*/

        template <
            typename style_type
            >
        void set_style (
            const style_type& style
        );
        /*!
            requires
                - style_type == a type that inherits from text_field_style
            ensures
                - this text_field object will draw itself using the given
                  text field style
        !*/

        void set_text (const std::wstring& text);
        void set_text (const dlib::ustring& text);
        void set_text (
            const std::string& text
        );
        /*!
            requires
                - text.find_first_of('\n') == std::string::npos
                  (i.e. there aren't any new lines in text)
            ensures
                - #text() == text
            throws
                - std::bad_alloc
        !*/

        const std::wstring  wtext () const;
        const dlib::ustring utext () const;
        const std::string   text (
        ) const;
        /*!
            ensures
                - returns the text of this text_field
            throws
                - std::bad_alloc
        !*/

        void set_width (
            unsigned long width_
        );
        /*!
            ensures
                - if (width >= 10) then
                    - #width()  == width_
                    - #height() == height()
                    - #top()    == top()
                    - #left()   == left()
                    - i.e. The width of this drawable is set to the given width but
                      nothing else changes.
        !*/

        void give_input_focus (
        );
        /*!
            ensures
                - #has_input_focus() == true
        !*/

        bool has_input_focus (
        );
        /*!
            ensures
                - Returns true if this txt field has input keyboard focus.  If this
                  is the case then it means that when the user types on the keyboard
                  the output will appear inside the text field.
        !*/

        void select_all_text (
        );
        /*!
            ensures
                - causes all the text in the text field to become selected.
                  (note that it doesn't give input focus)
        !*/

        void set_text_color (
            const rgb_pixel color
        );
        /*!
            ensures
                - #text_color() == color
        !*/

        const rgb_pixel text_color (
        ) const;
        /*!
            ensures
                - returns the color used to draw the text in this widget
        !*/

        void set_background_color (
            const rgb_pixel color
        );
        /*!
            ensures
                - #background_color() == color
        !*/

        const rgb_pixel background_color (
        ) const;
        /*!
            ensures
                - returns the color used to fill in the background of this widget
        !*/

        template <
            typename T
            >
        void set_text_modified_handler (
            T& object,
            void (T::*event_handler)()
        );
        /*!
            requires
                - event_handler is a valid pointer to a member function in T
            ensures
                - the event_handler function is called on object when the text
                  in this text_field is modified by the user.
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

        void set_text_modified_handler (
            const any_function<void()>& event_handler
        );
        /*!
            ensures
                - the event_handler function is called when the text in this text_field
                  is modified by the user.
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

        template <
            typename T
            >
        void set_enter_key_handler (
            T& object,
            void (T::*event_handler)()
        );
        /*!
            requires
                - event_handler is a valid pointer to a member function in T
            ensures
                - the event_handler function is called on object when this text field
                  has input focus and the user hits the enter key on their keyboard.
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

        void set_enter_key_handler (
            const any_function<void()>& event_handler
        );
        /*!
            ensures
                - the event_handler function is called when this text field has input
                  focus and the user hits the enter key on their keyboard.
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

        template <
            typename T
            >
        void set_focus_lost_handler (
            T& object,
            void (T::*event_handler)()
        );
        /*!
            requires
                - event_handler is a valid pointer to a member function in T
            ensures
                - the event_handler function is called on object when this object
                  loses input focus due to the user clicking outside the text field
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

        void set_focus_lost_handler (
            const any_function<void()>& event_handler
        );
        /*!
            ensures
                - the event_handler function is called when this object loses input
                  focus due to the user clicking outside the text field
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

    private:

        // restricted functions
        text_field(text_field&);        // copy constructor
        text_field& operator=(text_field&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class text_box
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class text_box : public scrollable_region
    {
        /*!
            INITIAL VALUE
                - text() == ""
                - The text color will be black.
                - width() == 100
                - height() == 100

            WHAT THIS OBJECT REPRESENTS
                This object represents a simple multi-line text input box.
        !*/

    public:

        text_box(
            drawable_window& w
        );
        /*!
            ensures
                - #*this is properly initialized
                - #*this has been added to window w
                - #parent_window() == w
            throws
                - std::bad_alloc
                - dlib::thread_error
        !*/

        virtual ~text_box(
        );
        /*!
            ensures
                - all resources associated with *this have been released
        !*/

        template <
            typename style_type
            >
        void set_style (
            const style_type& style
        );
        /*!
            requires
                - style_type == a type that inherits from text_box_style
            ensures
                - this text_box object will draw itself using the given
                  text box style
        !*/

        void set_text (const std::wstring& text);
        void set_text (const dlib::ustring& text);
        void set_text (
            const std::string& text
        );
        /*!
            ensures
                - #text() == text
            throws
                - std::bad_alloc
        !*/

        const std::wstring  wtext () const;
        const dlib::ustring utext () const;
        const std::string   text (
        ) const;
        /*!
            ensures
                - returns the text of this text_box
            throws
                - std::bad_alloc
        !*/

        void set_size (
            unsigned long width,
            unsigned long height
        );
        /*!
            ensures
                - #width() == width_
                - #height() == height_
                - #top() == top()
                - #left() == left()
                - i.e. The location of the upper left corner of this widget stays the
                  same but its width and height are modified
        !*/

        void set_text_color (
            const rgb_pixel color
        );
        /*!
            ensures
                - #text_color() == color
        !*/

        const rgb_pixel text_color (
        ) const;
        /*!
            ensures
                - returns the color used to draw the text in this widget
        !*/

        void set_background_color (
            const rgb_pixel color
        );
        /*!
            ensures
                - #background_color() == color
        !*/

        const rgb_pixel background_color (
        ) const;
        /*!
            ensures
                - returns the color used to fill in the background of this widget
        !*/

        template <
            typename T
            >
        void set_text_modified_handler (
            T& object,
            void (T::*event_handler)()
        );
        /*!
            requires
                - event_handler is a valid pointer to a member function in T
            ensures
                - the event_handler function is called on object when the text
                  in this text_box is modified by the user.
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

        void set_text_modified_handler (
            const any_function<void()>& event_handler
        );
        /*!
            ensures
                - the event_handler function is called when the text in this text_box
                  is modified by the user.
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

        template <
            typename T
            >
        void set_enter_key_handler (
            T& object,
            void (T::*event_handler)()
        );
        /*!
            requires
                - event_handler is a valid pointer to a member function in T
            ensures
                - the event_handler function is called on object when this text box
                  has input focus and the user hits the enter key on their keyboard.
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

        void set_enter_key_handler (
            const any_function<void()>& event_handler
        );
        /*!
            ensures
                - the event_handler function is called when this text box has input
                  focus and the user hits the enter key on their keyboard.
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

        template <
            typename T
            >
        void set_focus_lost_handler (
            T& object,
            void (T::*event_handler)()
        );
        /*!
            requires
                - event_handler is a valid pointer to a member function in T
            ensures
                - the event_handler function is called on object when this object
                  loses input focus due to the user clicking outside the text box
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

        void set_focus_lost_handler (
            const any_function<void()>& event_handler
        );
        /*!
            ensures
                - the event_handler function is called when this object loses input
                  focus due to the user clicking outside the text box
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

    private:

        // restricted functions
        text_box(text_box&);        // copy constructor
        text_box& operator=(text_box&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class check_box
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class check_box : public toggle_button
    {
        /*!
            This is just a toggle button with the style set to
            toggle_button_style_check_box.
        !*/
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class radio_button
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class radio_button : public toggle_button
    {
        /*!
            This is just a toggle button with the style set to
            toggle_button_style_radio_button.
        !*/
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class tabbed_display
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class tabbed_display : public drawable
    {
        /*!
            INITIAL VALUE
                number_of_tabs() == 1
                selected_tab() == 0

            WHAT THIS OBJECT REPRESENTS
                This object represents a row of tabs that are user selectable.

                When this object is disabled it means it will not respond to user clicks.
        !*/

    public:

        tabbed_display(
            drawable_window& w
        );
        /*!
            ensures
                - #*this is properly initialized
                - #*this has been added to window w
                - #parent_window() == w
            throws
                - std::bad_alloc
                - dlib::thread_error
        !*/

        virtual ~tabbed_display(
        );
        /*!
            ensures
                - all resources associated with *this have been released
        !*/

        void set_size (
            unsigned long width_,
            unsigned long height_
        );
        /*!
            ensures
                - if (width and height are big enough to contain the tabs) then
                    - #width() == width_
                    - #height() == height_
                    - #top() == top()
                    - #left() == left()
                    - i.e. The location of the upper left corner of this widget stays the
                      same but its width and height are modified
        !*/

        void set_number_of_tabs (
            unsigned long num
        );
        /*!
            requires
                - num > 0
            ensures
                - #number_of_tabs() == num
                - no tabs have any widget_groups associated with them.
                - for all valid idx:
                    - #tab_name(idx) == ""
            throws
                - std::bad_alloc
        !*/

        unsigned long selected_tab (
        ) const;
        /*!
            ensures
                - returns the index of the currently selected tab
        !*/

        unsigned long number_of_tabs (
        ) const;
        /*!
            ensures
                - returns the number of tabs in this tabbed_display
        !*/

        const std::wstring&  tab_wname (unsigned long idx) const;
        const dlib::ustring& tab_uname (unsigned long idx) const;
        const std::string&   tab_name (
            unsigned long idx
        ) const;
        /*!
            requires
                - idx < number_of_tabs()
            ensures
                - returns a const reference to the name of the tab given by idx
        !*/

        void set_tab_name (unsigned long idx, const std::wstring& new_name);
        void set_tab_name (unsigned long idx, const dlib::ustring& new_name);
        void set_tab_name (
            unsigned long idx,
            const std::string& new_name
        );
        /*!
            requires
                - idx < number_of_tabs()
            ensures
                - #tab_name(idx) == new_name
            throws
                - std::bad_alloc
        !*/

        void set_tab_group (
            unsigned long idx,
            widget_group& group
        );
        /*!
            requires
                - idx < number_of_tabs()
            ensures
                - if (is_hidden()) then
                    - group.is_hidden() == true
                - else
                    - whenever the tab with index idx is selected group.is_hidden() == false
                    - whenever the tab with index idx is deselected group.is_hidden() == true
                - whenever the position of *this changes the position of group will be
                  updated so that it is still inside the tabbed_display.  The position of group
                  will also be updated after this call to set_tab_group().
                - any previous calls to set_tab_group() with this index are overridden by this
                  new call.  (i.e. you can only have one widget_group associated with a single
                  tab at a time)
        !*/

        void fit_to_contents (
        );
        /*!
            ensures
                - Adjusts the size this tabbed_display so that it nicely contains
                  all of its widget_group objects.
                - does not change the position of this object.
                  (i.e. the upper left corner of get_rect() remains at the same position)
        !*/

        template <
            typename T
            >
        void set_click_handler (
            T& object,
            void (T::*event_handler)(unsigned long new_idx, unsigned long old_idx)
        );
        /*!
            requires
                - event_handler is a valid pointer to a member function in T
            ensures
                - The event_handler function is called on object when the user clicks
                  on a tab that isn't already selected.  new_idx will give the index of
                  the newly selected tab and old_idx will give the index of the tab
                  that was previously selected.
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

        void set_click_handler (
            const any_function<void(unsigned long new_idx, unsigned long old_idx)>& eh
        );
        /*!
            ensures
                - The event_handler function is called when the user clicks on a tab
                  that isn't already selected.  new_idx will give the index of the
                  newly selected tab and old_idx will give the index of the tab that
                  was previously selected.
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

    private:

        // restricted functions
        tabbed_display(tabbed_display&);        // copy constructor
        tabbed_display& operator=(tabbed_display&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class named_rectangle
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class named_rectangle : public drawable
    {
        /*!
            INITIAL VALUE
                name() == ""

            WHAT THIS OBJECT REPRESENTS
                This object represents a simple named rectangle.
        !*/

    public:

        named_rectangle(
            drawable_window& w
        );
        /*!
            ensures
                - #*this is properly initialized
                - #*this has been added to window w
                - #parent_window() == w
            throws
                - std::bad_alloc
                - dlib::thread_error
        !*/

        virtual ~named_rectangle(
        );
        /*!
            ensures
                - all resources associated with *this have been released
        !*/

        void set_size (
            unsigned long width_,
            unsigned long height_
        );
        /*!
            ensures
                - #width() == width_
                - #height() == height_
                - #top() == top()
                - #left() == left()
                - i.e. The location of the upper left corner of this widget stays the
                  same but its width and height are modified
        !*/

        void wrap_around (
            const rectangle& rect
        );
        /*!
            ensures
                - This object will be repositioned and sized so that it fits
                  around the given rectangle.
        !*/

        void set_name (const std::wstring& name);
        void set_name (const dlib::ustring& name);
        void set_name (
            const std::string& name
        );
        /*!
            ensures
                - #name() == name
            throws
                - std::bad_alloc
        !*/

        const std::wstring  wname () const;
        const dlib::ustring uname () const;
        const std::string   name (
        ) const;
        /*!
            ensures
                - returns the name of this named_rectangle
            throws
                - std::bad_alloc
        !*/

    private:

        // restricted functions
        named_rectangle(named_rectangle&);        // copy constructor
        named_rectangle& operator=(named_rectangle&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class mouse_tracker
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class mouse_tracker : public draggable
    {
        /*!
            INITIAL VALUE
                draggable_area() == rectangle(0,0,500,500)

            WHAT THIS OBJECT REPRESENTS
                This object represents a simple draggable box that displays the
                current location of the mouse.

                Also, if you hold shift and left click on the parent window then the
                mouse_tracker will place a single red pixel where you clicked and will
                display the mouse position relative to that point.
        !*/

    public:

        mouse_tracker(
            drawable_window& w
        );
        /*!
            ensures
                - #*this is properly initialized
                - #*this has been added to window w
                - #parent_window() == w
            throws
                - std::bad_alloc
                - dlib::thread_error
        !*/

        virtual ~mouse_tracker(
        );
        /*!
            ensures
                - all resources associated with *this have been released
        !*/

    private:

        // restricted functions
        mouse_tracker(mouse_tracker&);        // copy constructor
        mouse_tracker& operator=(mouse_tracker&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class list_box
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class list_box : public scrollable_region,
                     public enumerable<const std::string>
    {
        /*!
            INITIAL VALUE
                multiple_select_enabled() == false
                size() == 0

            ENUMERATION ORDER
                The enumerator will iterate over the elements in the list_box from
                the 0th element to the (size()-1)th element.  i.e. (*this)[0] to
                (*this)[size()-1].

            WHAT THIS OBJECT REPRESENTS
                This object represents a simple textual list box.  It contains a
                vertical list of strings which the user may select from.
        !*/

    public:

        list_box(
            drawable_window& w
        );
        /*!
            ensures
                - #*this is properly initialized
                - #*this has been added to window w
                - #parent_window() == w
            throws
                - std::bad_alloc
                - dlib::thread_error
        !*/

        virtual ~list_box(
        );
        /*!
            ensures
                - all resources associated with *this have been released
        !*/

        template <
            typename style_type
            >
        void set_style (
            const style_type& style
        );
        /*!
            requires
                - style_type == a type that inherits from list_box_style
            ensures
                - this list_box object will draw itself using the given style
        !*/

        void set_size (
            unsigned long width_,
            unsigned long height_
        );
        /*!
            ensures
                - #width() == width_
                - #height() == height_
                - #top() == top()
                - #left() == left()
                - i.e. The location of the upper left corner of this widget stays the
                  same but its width and height are modified
        !*/

        bool is_selected (
            unsigned long index
        ) const;
        /*!
            requires
                - index < size()
            ensures
                - if (the item given by index is currently selected) then
                    - returns true
                - else
                    - returns false
        !*/

        void select (
            unsigned long index
        );
        /*!
            requires
                - index < size()
            ensures
                - #is_selected(index) == true
        !*/

        void unselect (
            unsigned long index
        );
        /*!
            requires
                - index < size()
            ensures
                - #is_selected(index) == false
        !*/

        template <typename T>
        void get_selected (
            T& list
        ) const;
        /*!
            requires
                - T == an implementation of dlib/queue/queue_kernel_abstract.h
                - T::type == unsigned long
            ensures
                - #list == a list of all the currently selected indices for this list_box.
        !*/

        unsigned long get_selected (
        ) const;
        /*!
            requires
                - multiple_select_enabled() == false
            ensures
                - if (there is currently something selected) then
                    - returns the index of the selected item
                - else
                    - returns size()
        !*/

        template <typename T>
        void load (
            const T& list
        );
        /*!
            requires
                - T == compatible with dlib::enumerable<std::string>
            ensures
                - #size() == list.size()
                - Copies all the strings from list into *this in the order in which they are enumerated.
                  (i.e. The first one goes into (*this)[0], the second into (*this)[1], and so on...)
        !*/

        const std::string& operator[] (
            unsigned long index
        ) const;
        /*!
            requires
                - index < size()
            ensures
                - returns the name of the indexth item/row in this list box.
        !*/

        bool multiple_select_enabled (
        ) const;
        /*!
            ensures
                - if (this object will allow the user to select more than one item at a time) then
                    - returns true
                - else
                    - returns false
        !*/

        void enable_multiple_select (
        );
        /*!
            ensures
                - #multiple_select_enabled() == true
        !*/

        void disable_multiple_select (
        );
        /*!
            ensures
                - #multiple_select_enabled() == false
        !*/

        template <
            typename T
            >
        void set_double_click_handler (
            T& object,
            void (T::*event_handler)(unsigned long index)
        );
        /*!
            requires
                - event_handler is a valid pointer to a member function in T.
            ensures
                - The event_handler function is called on object when the user double
                  clicks on one of the rows in this list box.  index gives the row
                  number for the item the user clicked.
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

        void set_double_click_handler (
            const any_function<void(unsigned long index)>& event_handler
        );
        /*!
            ensures
                - The event_handler function is called when the user double clicks on
                  one of the rows in this list box.  index gives the row number for
                  the item the user clicked.
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

        template <
            typename T
            >
        void set_click_handler (
            T& object,
            void (T::*event_handler)(unsigned long index)
        );
        /*!
            requires
                - event_handler is a valid pointer to a member function in T.
            ensures
                - The event_handler function is called on object when the user
                  clicks on one of the rows in this list box.  index gives the row
                  number for the item the user clicked.  (Note that the second click
                  in a double click triggers the double click handler above instead
                  of this event)
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

        void set_click_handler (
            const any_function<void(unsigned long index)>& event_handler
        );
        /*!
            ensures
                - The event_handler function is called when the user clicks on one
                  of the rows in this list box.  index gives the row number for the
                  item the user clicked.  (Note that the second click in a double
                  click triggers the double click handler above instead of this event)
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

    private:

        // restricted functions
        list_box(list_box&);        // copy constructor
        list_box& operator=(list_box&);    // assignment operator
    };

    class wlist_box : public scrollable_region,
    public enumerable<const std::wstring>;
    /*!
        same as list_box except for std::wstring instead of std::string
    !*/

    class ulist_box : public scrollable_region,
    public enumerable<const dlib::ustring>;
    /*!
        same as list_box except for dlib::ustring instead of std::string
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class menu_bar
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class menu_bar : public drawable
    {
        /*!
            INITIAL VALUE
                - number_of_menus() == 0

            WHAT THIS OBJECT REPRESENTS
                This object represents a menu bar that appears at the top of a
                window.
        !*/

    public:

        menu_bar(
            drawable_window& w
        );
        /*!
            ensures
                - #*this is properly initialized
                - #*this has been added to window w
                - #parent_window() == w
            throws
                - std::bad_alloc
                - dlib::thread_error
        !*/

        virtual ~menu_bar(
        );
        /*!
            ensures
                - all resources associated with *this have been released
        !*/

        void set_number_of_menus (
            unsigned long num
        );
        /*!
            ensures
                - #number_of_menus() == num
        !*/

        unsigned long number_of_menus (
        ) const;
        /*!
            ensures
                - returns the number of menus in this menu_bar
        !*/

        void set_menu_name (unsigned long idx, const std::wstring name, char underline_ch = '\0');
        void set_menu_name (unsigned long idx, const dlib::ustring name, char underline_ch = '\0');
        void set_menu_name (
            unsigned long idx,
            const std::string name,
            char underline_ch = '\0'
        );
        /*!
            requires
                - idx < number_of_menus()
            ensures
                - #menu_name(idx) == name
                - if (underline_ch is present in name) then
                    - The menu with index idx will have the first underline_ch character
                      in its name underlined and users will be able to activate the menu
                      by hitting alt+underline_char
        !*/

        const std::wstring  menu_wname (unsigned long idx) const;
        const dlib::ustring menu_uname (unsigned long idx) const;
        const std::string   menu_name (
            unsigned long idx
        ) const;
        /*!
            requires
                - idx < number_of_menus()
            ensures
                - returns the name of the menu with index idx
        !*/

        popup_menu& menu (
            unsigned long idx
        );
        /*!
            requires
                - idx < number_of_menus()
            ensures
                - returns a non-const reference to the popup_menu for the menu with
                  index idx.
        !*/

        const popup_menu& menu (
            unsigned long idx
        ) const;
        /*!
            requires
                - idx < number_of_menus()
            ensures
                - returns a const reference to the popup_menu for the menu with
                  index idx.
        !*/

    private:

        // restricted functions
        menu_bar(menu_bar&);        // copy constructor
        menu_bar& operator=(menu_bar&);    // assignment operator

    };

// ----------------------------------------------------------------------------------------

    template <
        typename graph_type
        >
    class directed_graph_drawer : public zoomable_region
    {
        /*!
            REQUIREMENTS ON graph_type
                - must be an implementation of directed_graph/directed_graph_kernel_abstract.h

            INITIAL VALUE
                - get_graph().size() == 0

            WHAT THIS OBJECT REPRESENTS
                This object represents a graphical widget that allows the user to draw
                a directed graph.

                The user can create nodes by right clicking on the draw area and add
                edges by selecting a node (via left clicking on it) and then holding
                shift and clicking on the node that is to be the child node of the
                selected node.
        !*/

    public:

        directed_graph_drawer (
            drawable_window& w
        );
        /*!
            ensures
                - #*this is properly initialized
                - #*this has been added to window w
                - #parent_window() == w
            throws
                - std::bad_alloc
                - dlib::thread_error
        !*/

        virtual ~directed_graph_drawer (
        );
        /*!
            ensures
                - all resources associated with *this have been released
        !*/

        const graph_type& graph (
        ) const;
        /*!
            requires
                - drawable::m is locked
            ensures
                - returns a const reference to the graph that this widget has been drawing
        !*/

        unsigned long number_of_nodes (
        ) const;
        /*!
            ensures
                - returns graph().number_of_nodes()
        !*/

        void clear_graph (
        );
        /*!
            ensures
                - #number_of_nodes() == 0
        !*/

        const typename graph_type::node_type& graph_node (
            unsigned long i
        ) const;
        /*!
            requires
                - drawable::m is locked
                - i < number_of_nodes()
            ensures
                - returns a const reference to get_graph().node(i)
        !*/

        typename graph_type::node_type& graph_node (
            unsigned long i
        );
        /*!
            requires
                - drawable::m is locked
                - i < number_of_nodes()
            ensures
                - returns a non-const reference to get_graph().node(i)
        !*/

        void save_graph (
            std::ostream& out
        );
        /*!
            ensures
                - saves the state of the graph to the output stream.  Does so in a
                  way that not only preserves the state of the graph this->graph()
                  but also preserves the graphical layout of the graph in this
                  GUI widget.
                - Also, the first part of the saved state is a serialized
                  version of this->graph().  Thus, you can deserialize just the
                  this->graph() object from the serialized data if you like.
        !*/

        void load_graph (
            std::istream& in
        );
        /*!
            ensures
                - loads a saved graph from the given input stream.
        !*/

        void set_node_label (unsigned long i, const std::wstring& label);
        void set_node_label (unsigned long i, const dlib::ustring& label);
        void set_node_label (
            unsigned long i,
            const std::string& label
        );
        /*!
            requires
                - i < number_of_nodes()
            ensures
                - #node_label(i) == label
        !*/

        void set_node_color (
            unsigned long i,
            rgb_pixel color
        );
        /*!
            requires
                - i < number_of_nodes()
            ensures
                - #node_color(i) == color
        !*/

        rgb_pixel node_color (
            unsigned long i
        ) const;
        /*!
            requires
                - i < number_of_nodes()
            ensures
                - returns the color used to draw node graph_node(i)
        !*/

        const std::wstring  node_wlabel (unsigned long i) const;
        const dlib::ustring node_ulabel (unsigned long i) const;
        const std::string   node_label (
            unsigned long i
        ) const;
        /*!
            requires
                - i < number_of_nodes()
            ensures
                - returns the text label for node graph_node(i)
        !*/

        template <
            typename T
            >
        void set_node_selected_handler (
            T& object,
            void (T::*event_handler)(unsigned long node_index)
        );
        /*!
            requires
                - event_handler is a valid pointer to a member function in T
            ensures
                - the event_handler function is called on object when the user selects
                  a node.
                - node_index == the index of the node that was selected
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

        void set_node_selected_handler (
            const any_function<void(unsigned long node_index)>& event_handler
        );
        /*!
            ensures
                - the event_handler function is called when the user selects
                  a node.
                - node_index == the index of the node that was selected
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

        template <
            typename T
            >
        void set_node_deselected_handler (
            T& object,
            void (T::*event_handler)(unsigned long node_index)
        );
        /*!
            requires
                - event_handler is a valid pointer to a member function in T
            ensures
                - the event_handler function is called on object when the user
                  deselects a node.
                - node_index == the index of the node that was deselected
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

        void set_node_deselected_handler (
            const any_function<void(unsigned long node_index)>& event_handler
        );
        /*!
            ensures
                - the event_handler function is called when the user deselects a node.
                - node_index == the index of the node that was deselected
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

        template <
            typename T
            >
        void set_node_deleted_handler (
            T& object,
            void (T::*event_handler)()
        );
        /*!
            requires
                - event_handler is a valid pointer to a member function in T
            ensures
                - the event_handler function is called on object when the user
                  deletes a node.
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

        void set_node_deleted_handler (
            const any_function<void()>& event_handler
        );
        /*!
            ensures
                - the event_handler function is called when the user deletes a node.
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

        template <
            typename T
            >
        void set_graph_modified_handler (
            T& object,
            void (T::*event_handler)()
        );
        /*!
            requires
                - event_handler is a valid pointer to a member function in T
            ensures
                - the event_handler function is called on object when the user
                  modifies the graph (i.e. adds or removes a node or edge)
                - the event_handler function is not called when the user just
                  moves nodes around on the screen.
                - This event is always dispatched before any more specific event
                  that results from the user modifying the graph.
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

        void set_graph_modified_handler (
            const any_function<void()>& event_handler
        );
        /*!
            ensures
                - the event_handler function is called when the user modifies
                  the graph (i.e. adds or removes a node or edge)
                - the event_handler function is not called when the user just
                  moves nodes around on the screen.
                - This event is always dispatched before any more specific event
                  that results from the user modifying the graph.
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

    private:

        // restricted functions
        directed_graph_drawer(directed_graph_drawer&);        // copy constructor
        directed_graph_drawer& operator=(directed_graph_drawer&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------

    class text_grid : public scrollable_region
    {
        /*!
            INITIAL VALUE
                - vertical_scroll_increment() == 10
                - horizontal_scroll_increment() == 10
                - border_color() == rgb_pixel(128,128,128)
                - number_of_columns() == 0
                - number_of_rows() == 0

            WHAT THIS OBJECT REPRESENTS
                This object represents a simple grid of square text fields that
                looks more or less like a spreadsheet grid.
        !*/

    public:

        text_grid (
            drawable_window& w
        );
        /*!
            ensures
                - #*this is properly initialized
                - #*this has been added to window w
                - #parent_window() == w
            throws
                - std::bad_alloc
                - dlib::thread_error
        !*/

        virtual ~text_grid (
        );
        /*!
            ensures
                - all resources associated with *this have been released
        !*/

        void set_grid_size (
            unsigned long rows,
            unsigned long cols
        );
        /*!
            ensures
                - #number_of_rows() == rows
                - #number_of_columns() == cols
                - for all valid r and c:
                    - #text(r,c) == ""
                    - #text_color(r,c) == rgb_pixel(0,0,0)
                    - #background_color(r,c) == rgb_pixel(255,255,255)
                    - #is_editable(r,c) == true
        !*/

        unsigned long number_of_columns (
        ) const;
        /*!
            ensures
                - returns the number of columns contained in this grid
        !*/

        unsigned long number_of_rows (
        ) const;
        /*!
            ensures
                - returns the number of rows contained in this grid
        !*/

        rgb_pixel border_color (
        ) const;
        /*!
            ensures
                - returns the color of the lines drawn between the grid elements
        !*/

        void set_border_color (
            rgb_pixel color
        );
        /*!
            ensures
                - #border_color() == color
        !*/

        const std::wstring  wtext (unsigned long row, unsigned long col) const;
        const dlib::ustring utext (unsigned long row, unsigned long col) const;
        const std::string   text (
            unsigned long row,
            unsigned long col
        ) const;
        /*!
            requires
                - row < number_of_rows()
                - col < number_of_columns()
            ensures
                - returns the text in the given grid location
        !*/

        void set_text (unsigned long row, unsigned long col, const std::wstring& str);
        void set_text (unsigned long row, unsigned long col, const dlib::ustring& str);
        void set_text (
            unsigned long row,
            unsigned long col,
            const std::string& str
        );
        /*!
            requires
                - row < number_of_rows()
                - col < number_of_columns()
            ensures
                - #text(row,col) == str
        !*/

        const rgb_pixel text_color (
            unsigned long row,
            unsigned long col
        ) const;
        /*!
            requires
                - row < number_of_rows()
                - col < number_of_columns()
            ensures
                - returns the color of the text in the given grid location
        !*/

        void set_text_color (
            unsigned long row,
            unsigned long col,
            const rgb_pixel color
        );
        /*!
            requires
                - row < number_of_rows()
                - col < number_of_columns()
            ensures
                - #text_color(row,col) == color
        !*/

        const rgb_pixel background_color (
            unsigned long row,
            unsigned long col
        ) const;
        /*!
            requires
                - row < number_of_rows()
                - col < number_of_columns()
            ensures
                - returns the background color of the given grid location
        !*/

        void set_background_color (
            unsigned long row,
            unsigned long col,
            const rgb_pixel color
        );
        /*!
            requires
                - row < number_of_rows()
                - col < number_of_columns()
            ensures
                - #background_color(row,col) == color
        !*/

        bool is_editable (
            unsigned long row,
            unsigned long col
        ) const;
        /*!
            requires
                - row < number_of_rows()
                - col < number_of_columns()
            ensures
                - if (the given grid location is editable by the user) then
                    - returns true
                - else
                    - returns false
        !*/

        void set_editable (
            unsigned long row,
            unsigned long col,
            bool editable
        );
        /*!
            requires
                - row < number_of_rows()
                - col < number_of_columns()
            ensures
                - #is_editable(row,col) == editable
        !*/

        void set_column_width (
            unsigned long col,
            unsigned long width
        );
        /*!
            requires
                - col < number_of_columns()
            ensures
                - the given column will be displayed such that it is width pixels wide
        !*/

        void set_row_height (
            unsigned long row,
            unsigned long height
        );
        /*!
            requires
                - row < number_of_rows()
            ensures
                - the given row will be displayed such that it is height pixels wide
        !*/

        template <
            typename T
            >
        void set_text_modified_handler (
            T& object,
            void (T::*event_handler)(unsigned long row, unsigned long col)
        );
        /*!
            requires
                - event_handler is a valid pointer to a member function in T
            ensures
                - the event_handler function is called on object when the user selects
                  a node.
                - row == row will give the row of the grid item that was modified
                - col == col will give the column of the grid item that was modified
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

        void set_text_modified_handler (
            const any_function<void(unsigned long row, unsigned long col)>& event_handler
        );
        /*!
            ensures
                - the event_handler function is called when the user selects a node.
                - row == row will give the row of the grid item that was modified
                - col == col will give the column of the grid item that was modified
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        !*/

    private:

        // restricted functions
        text_grid(text_grid&);        // copy constructor
        text_grid& operator=(text_grid&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------

    class image_display : public scrollable_region
    {
        /*!
            INITIAL VALUE
                - This object isn't displaying anything.
                - get_overlay_rects().size() == 0
                - get_default_overlay_rect_label() == ""
                - get_default_overlay_rect_color() == rgb_alpha_pixel(255,0,0,255) (i.e. RED)
                - This object does not have any user labelable parts defined.
                - overlay_editing_is_enabled() == true

            WHAT THIS OBJECT REPRESENTS
                This object represents an image inside a scrollable region.
                You give it an image to display by calling set_image().
                This widget also allows you to add rectangle and line overlays that
                will be drawn on top of the image.

                If you hold the Ctrl key you can zoom in and out using the mouse wheel.
                You can also add new overlay rectangles by holding shift, left clicking,
                and dragging the mouse.  Additionally, you can delete an overlay rectangle
                by double clicking on it and hitting delete or backspace.  Finally, you
                can also add part labels (if they have been defined by calling add_labelable_part_name())
                by selecting an overlay rectangle with the mouse and then right clicking
                on the part.  If you want to move any rectangle or an object part then
                shift+right click and drag it.

                Finally, if you hold Ctrl and left click an overlay rectangle it will
                change its label to get_default_overlay_rect_label().

                The image is drawn such that:
                    - the pixel img[0][0] is the upper left corner of the image.
                    - the pixel img[img.nr()-1][0] is the lower left corner of the image.
                    - the pixel img[0][img.nc()-1] is the upper right corner of the image.
                    - the pixel img[img.nr()-1][img.nc()-1] is the lower right corner of the image.
        !*/

    public:

        image_display(
            drawable_window& w
        );
        /*!
            ensures
                - #*this is properly initialized
                - #*this has been added to window w
                - #parent_window() == w
        !*/

        ~image_display(
        );
        /*!
            ensures
                - all resources associated with *this have been released
        !*/

        template <
            typename image_type
            >
        void set_image (
            const image_type& new_img
        );
        /*!
            requires
                - image_type == an implementation of array2d/array2d_kernel_abstract.h or
                  a dlib::matrix or something convertible to a matrix via mat()
                - pixel_traits<typename image_type::type> must be defined
            ensures
                - #*this widget is now displaying the given image new_img.
        !*/

        struct overlay_rect
        {
            /*!
                WHAT THIS OBJECT REPRESENTS
                    This object represents a rectangle that is drawn on top of the
                    image shown by this object.  Each rectangle is represented by
                    a rectangle object as well as a color and text label.  The label
                    is drawn below the lower right corner of the rectangle.

                    Moreover, the rectangle can have sub-parts. Each part is listed
                    in the parts member variable.  This variable maps the name of the
                    part to its position.

                    Rectangles with crossed_out == true will be drawn with an X through
                    them.
            !*/

            rectangle rect;
            rgb_alpha_pixel color;
            std::string label;
            std::map<std::string,point> parts;
            bool crossed_out;

            overlay_rect(
            );
            /*!
                ensures
                    - #color == rgb_alpha_pixel(0,0,0,0)
                    - #rect == rectangle()
                    - #label.size() == 0
                    - #crossed_out == false
            !*/

            template <typename pixel_type>
            overlay_rect(
                const rectangle& r,
                pixel_type p
            );
            /*!
                ensures
                    - #rect == r
                    - performs assign_pixel(color, p)
                    - #label.size() == 0
                    - #crossed_out == false
            !*/

            template <typename pixel_type>
            overlay_rect(
                const rectangle& r,
                pixel_type p,
                const std::string& l
            );
            /*!
                ensures
                    - #rect == r
                    - performs assign_pixel(color, p)
                    - #label == l
                    - #crossed_out == false
            !*/

            template <typename pixel_type>
            overlay_rect(
                const rectangle& r,
                pixel_type p,
                const std::string& l,
                const std::map<std::string,point>& parts_
            );
            /*!
                ensures
                    - #rect == r
                    - performs assign_pixel(color, p)
                    - #label == l
                    - #parts == parts_
                    - #crossed_out == false
            !*/

        };

        struct overlay_line
        {
            /*!
                WHAT THIS OBJECT REPRESENTS
                    This object represents a line that is drawn on top of the
                    image shown by this object.  Each line is represented by
                    its two end points (p1 and p2) as well as a color.
            !*/

            point p1;
            point p2;
            rgb_alpha_pixel color;

            overlay_line(
            );
            /*!
                ensures
                    - #color == rgb_alpha_pixel(0,0,0,0)
                    - #p1 == point()
                    - #p2 == point()
            !*/

            template <typename pixel_type>
            overlay_line(
                const point& p1_,
                const point& p2_,
                pixel_type p
            );
            /*!
                ensures
                    - performs assign_pixel(color, p)
                    - #p1 == p1_
                    - #p2 == p2_
            !*/

        };

        struct overlay_circle
        {
            /*!
                WHAT THIS OBJECT REPRESENTS
                    This object represents a circle that is drawn on top of the
                    image shown by this object.  Each circle is represented by
                    its center, radius, and color.  It can also have an optional
                    text label which will appear below the circle.
            !*/

            point center;
            int radius;
            rgb_alpha_pixel color;
            std::string label;

            overlay_circle(
            );
            /*!
                ensures
                    - #center == point(0,0)
                    - #radius == 0
                    - #color == rgb_alpha_pixel(0,0,0,0)
                    - #label.size() == 0
            !*/

            template <typename pixel_type>
            overlay_circle(
                const point& center_,
                const int radius_,
                pixel_type p
            );
            /*!
                ensures
                    - performs assign_pixel(color, p)
                    - #center == center_
                    - #radius == radius_
            !*/

            template <typename pixel_type>
            overlay_circle(
                const point& center_,
                const int radius_,
                pixel_type p,
                const std::string& label_
            );
            /*!
                ensures
                    - performs assign_pixel(color, p)
                    - #center == center_
                    - #radius == radius_
                    - #label == label_
            !*/

        };

        void add_overlay (
            const overlay_rect& overlay
        );
        /*!
            ensures
                - adds the given overlay rectangle into this object such
                  that it will be displayed.
        !*/

        void add_overlay (
            const overlay_line& overlay
        );
        /*!
            ensures
                - adds the given overlay line into this object such
                  that it will be displayed.
        !*/

        void add_overlay (
            const overlay_circle& overlay
        );
        /*!
            ensures
                - adds the given overlay circle into this object such
                  that it will be displayed.
        !*/

        void add_overlay (
            const std::vector<overlay_rect>& overlay
        );
        /*!
            ensures
                - adds the given set of overlay rectangles into this object such
                  that they will be displayed.
        !*/

        void add_overlay (
            const std::vector<overlay_line>& overlay
        );
        /*!
            ensures
                - adds the given set of overlay lines into this object such
                  that they will be displayed.
        !*/

        void add_overlay (
            const std::vector<overlay_circle>& overlay
        );
        /*!
            ensures
                - adds the given set of overlay circles into this object such
                  that they will be displayed.
        !*/

        void clear_overlay (
        );
        /*!
            ensures
                - removes all overlays from this object.
                - #get_overlay_rects().size() == 0
        !*/

        std::vector<overlay_rect> get_overlay_rects (
        ) const;
        /*!
            ensures
                - returns a copy of all the overlay_rect objects currently displayed.
        !*/

        void set_default_overlay_rect_label (
            const std::string& label
        );
        /*!
            ensures
                - #get_default_overlay_rect_label() == label
        !*/

        std::string get_default_overlay_rect_label (
        ) const;
        /*!
            ensures
                - returns the label given to new overlay rectangles created by the user
                  (i.e. when the user holds shift and adds them with the mouse)
        !*/

        void set_default_overlay_rect_color (
            const rgb_alpha_pixel& color
        );
        /*!
            ensures
                - #get_default_overlay_rect_color() == color
        !*/

        rgb_alpha_pixel get_default_overlay_rect_color (
        ) const;
        /*!
            ensures
                - returns the color given to new overlay rectangles created by the user
                  (i.e. when the user holds shift and adds them with the mouse)
        !*/

        void add_labelable_part_name (
            const std::string& name
        );
        /*!
            ensures
                - adds a user labelable part with the given name.  If the name has
                  already been added then this function has no effect.
                - These parts can be added by the user by selecting an overlay box
                  and then right clicking anywhere in it.  A popup menu will appear
                  listing the parts.  The user can then click a part name and it will
                  add it into the overlay_rect::parts variable and also show it on the
                  screen.
        !*/

        void clear_labelable_part_names (
        );
        /*!
            ensures
                - removes all use labelable parts.  Calling this function undoes
                  all previous calls to add_labelable_part_name().  Therefore, the
                  user won't be able to label any parts after clear_labelable_part_names()
                  is called.
        !*/

        rectangle get_image_display_rect (
        ) const;
        /*!
            ensures
                - returns a rectangle R that tells you how big the image inside the
                  display is when it appears on the screen.  Note that it takes the
                  current zoom level into account.
                    - R.width()  == the width of the displayed image
                    - R.height() == the height of the displayed image
                    - R.tl_corner() == (0,0)
        !*/

        void enable_overlay_editing (
        );
        /*!
            ensures
                - #overlay_editing_is_enabled() == true
        !*/

        void disable_overlay_editing (
        );
        /*!
            ensures
                - #overlay_editing_is_enabled() == false
        !*/

        bool overlay_editing_is_enabled (
        ) const;
        /*!
            ensures
                - if this function returns true then it is possible for the user to add or
                  remove overlay objects (e.g. rectangles) using the mouse and keyboard.
                  If it returns false then the overlay is not user editable.
        !*/

        template <
            typename T
            >
        void set_overlay_rects_changed_handler (
            T& object,
            void (T::*event_handler)()
        );
        /*
            requires
                - event_handler is a valid pointer to a member function in T
            ensures
                - the event_handler function is called on object when the user adds,
                  removes, or modifies an overlay rectangle.
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        */

        void set_overlay_rects_changed_handler (
            const any_function<void()>& event_handler
        );
        /*
            ensures
                - the event_handler function is called when the user adds or removes
                  an overlay rectangle.
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        */

        template <
            typename T
            >
        void set_overlay_rect_selected_handler (
            T& object,
            void (T::*event_handler)(const overlay_rect& orect)
        );
        /*
            requires
                - event_handler is a valid pointer to a member function in T
            ensures
                - The event_handler function is called on object when the user selects
                  an overlay rectangle by double clicking on it.  The selected rectangle
                  will be passed to event_handler().
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        */

        void set_overlay_rect_selected_handler (
            const any_function<void(const overlay_rect& orect)>& event_handler
        );
        /*
            ensures
                - The event_handler function is called when the user selects an overlay
                  rectangle by double clicking on it.  The selected rectangle will be
                  passed to event_handler().
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        */

        template <
            typename T
            >
        void set_image_clicked_handler (
            T& object,
            void (T::*event_handler)(const point& p, bool is_double_click)
        );
        /*
            requires
                - event_handler is a valid pointer to a member function in T
            ensures
                - The event_handler function is called on object when the user left clicks
                  anywhere on the image.  When they do so this callback is called with the
                  location of the image pixel which was clicked.  The is_double_click bool
                  will also tell you if it was a double click or single click.
                - any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
            throws
                - std::bad_alloc
        */

        void set_image_clicked_handler (
            const any_function<void(const point& p, bool is_double_click)>& event_handler
        );
        /*
            ensures
                - The event_handler function is called when the user left clicks anywhere
                  on the image.  When they do so this callback is called with the location
                  of the image pixel which was clicked.  The is_double_click bool will also
                  tell you if it was a double click or single click.
                - Any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this event at a
                  time)
            throws
                - std::bad_alloc
        */

    private:

        // restricted functions
        image_display(image_display&);        // copy constructor
        image_display& operator=(image_display&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------

    class image_window : public drawable_window
    {
        /*!
            INITIAL VALUE
                - initially, this object is visible on the screen
                - events_tied() == false

            WHAT THIS OBJECT REPRESENTS
                This is a simple window that is just a container for an image_display.
                It exists to make it easy to throw image_displays onto the screen
                without having to put together your own drawable_window objects.
        !*/
    public:

        typedef image_display::overlay_rect overlay_rect;
        typedef image_display::overlay_line overlay_line;
        typedef image_display::overlay_circle overlay_circle;

        image_window(
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        template <typename image_type>
        image_window(
            const image_type& img
        );
        /*!
            requires
                - image_type == an implementation of array2d/array2d_kernel_abstract.h or
                  a dlib::matrix or something convertible to a matrix via mat()
                - pixel_traits<typename image_type::type> must be defined
            ensures
                - this object is properly initialized
                - #*this window is now displaying the given image img.
        !*/

        template < typename image_type>
        image_window(
            const image_type& img,
            const std::string& title
        );
        /*!
            requires
                - image_type == an implementation of array2d/array2d_kernel_abstract.h or
                  a dlib::matrix or something convertible to a matrix via mat()
                - pixel_traits<typename image_type::type> must be defined
            ensures
                - this object is properly initialized
                - #*this window is now displaying the given image img.
                - The title of the window will be set to the given title string.
        !*/

        ~image_window(
        );
        /*!
            ensures
                - any resources associated with this object have been released
        !*/

        template <typename image_type>
        void set_image (
            const image_type& img
        );
        /*!
            requires
                - image_type == an implementation of array2d/array2d_kernel_abstract.h
                - pixel_traits<typename image_type::type> must be defined
            ensures
                - #*this window is now displaying the given image img.
        !*/

        void add_overlay (
            const overlay_rect& overlay
        );
        /*!
            ensures
                - adds the given overlay rectangle into this object such
                  that it will be displayed.
        !*/

        template <typename pixel_type>
        void add_overlay(
            const rectangle& r,
            pixel_type p = rgb_pixel(255,0,0)
        );
        /*!
            ensures
                - performs: add_overlay(overlay_rect(r,p));
        !*/

        template <typename pixel_type>
        void add_overlay(
            const rectangle& r,
            pixel_type p,
            const std::string& l
        );
        /*!
            ensures
                - performs: add_overlay(overlay_rect(r,p,l));
        !*/

        template <typename pixel_type>
        void add_overlay(
            const std::vector<rectangle>& r,
            pixel_type p = rgb_pixel(255,0,0)
        );
        /*!
            ensures
                - adds the given set of rectangles into this object such
                  that they will be displayed with the color specific by p.
        !*/

        void add_overlay(
            const full_object_detection& object,
            const std::vector<std::string>& part_names
        );
        /*!
            ensures
                - adds the given full_object_detection to the overlays
                  and shows it on the screen.  This includes any of its
                  parts that are not set equal to OBJECT_PART_NOT_PRESENT.
                - for all valid i < part_names.size():
                    - the part object.part(i) will be labeled with the string
                      part_names[i].
        !*/

        void add_overlay(
            const full_object_detection& object
        );
        /*!
            ensures
                - adds the given full_object_detection to the overlays
                  and shows it on the screen.  This includes any of its
                  parts that are not set equal to OBJECT_PART_NOT_PRESENT.
        !*/

        void add_overlay(
            const std::vector<full_object_detection>& objects,
            const std::vector<std::string>& part_names
        );
        /*!
            ensures
                - calling this function is equivalent to calling the following
                  sequence of functions, for all valid i:
                    - add_overlay(objects[i], part_names);
        !*/

        void add_overlay(
            const std::vector<full_object_detection>& objects
        );
        /*!
            ensures
                - calling this function is equivalent to calling the following
                  sequence of functions, for all valid i:
                    - add_overlay(objects[i]);
        !*/

        void add_overlay (
            const overlay_line& overlay
        );
        /*!
            ensures
                - adds the given overlay line into this object such
                  that it will be displayed.
        !*/

        void add_overlay (
            const overlay_circle& overlay
        );
        /*!
            ensures
                - adds the given overlay circle into this object such
                  that it will be displayed.
        !*/

        template <typename pixel_type>
        void add_overlay(
            const point& p1,
            const point& p2,
            pixel_type p
        );
        /*!
            ensures
                - performs: add_overlay(overlay_line(p1,p2,p));
        !*/

        void add_overlay (
            const std::vector<overlay_rect>& overlay
        );
        /*!
            ensures
                - adds the given set of overlay rectangles into this object such
                  that they will be displayed.
        !*/

        void add_overlay (
            const std::vector<overlay_line>& overlay
        );
        /*!
            ensures
                - adds the given set of overlay lines into this object such
                  that they will be displayed.
        !*/

        void add_overlay (
            const std::vector<overlay_circle>& overlay
        );
        /*!
            ensures
                - adds the given set of overlay circles into this object such
                  that they will be displayed.
        !*/

        void clear_overlay (
        );
        /*!
            ensures
                - removes all overlays from this object.
        !*/

        void tie_events (
        );
        /*!
            ensures
                - #events_tied() == true
        !*/

        void untie_events (
        );
        /*!
            ensures
                - #events_tied() == false
        !*/

        bool events_tied (
        ) const;
        /*!
            ensures
                - returns true if and only if the get_next_double_click() and
                  get_next_keypress() events are tied together.  If they are tied it means
                  that you can use a loop of the following form to listen for both events
                  simultaneously:
                    while (mywindow.get_next_double_click(p) || mywindow.get_next_keypress(key,printable))
                    {
                        if (p.x() < 0)
                            // Do something with the keyboard event
                        else
                            // Do something with the mouse event
                    }
        !*/

        bool get_next_double_click (
            point& p
        );
        /*!
            ensures
                - This function blocks until the user double clicks on the image or the
                  window is closed by the user.  It will also unblock for a keyboard key
                  press if events_tied() == true.
                - if (this function returns true) then
                    - This means the user double clicked the mouse.
                    - #p == the next image pixel the user clicked.
                - else
                    - #p == point(-1,1)
        !*/

        bool get_next_double_click (
            point& p,
            unsigned long& mouse_button
        );
        /*!
            ensures
                - This function blocks until the user double clicks on the image or the
                  window is closed by the user.  It will also unblock for a keyboard key
                  press if events_tied() == true.
                - if (this function returns true) then
                    - This means the user double clicked the mouse.
                    - #p == the next image pixel the user clicked.
                    - #mouse_button == the mouse button which was used to double click.
                      This will be either dlib::base_window::LEFT,
                      dlib::base_window::MIDDLE, or dlib::base_window::RIGHT
                - else
                    - #p == point(-1,1)
                      (Note that this point is outside any possible image)
        !*/

        bool get_next_keypress (
            unsigned long& key,
            bool& is_printable,
            unsigned long& state
        );
        /*!
            ensures
                - This function blocks until the user presses a keyboard key or the
                  window is closed by the user.  It will also unblock for a mouse double
                  click if events_tied() == true.
                - if (this function returns true) then
                    - This means the user pressed a keyboard key.
                    - The keyboard button press is recorded into #key, #is_printable, and
                      #state.  In particular, these variables are populated with the three
                      identically named arguments to the base_window::on_keydown(key,is_printable,state)
                      event.
        !*/

        bool get_next_keypress (
            unsigned long& key,
            bool& is_printable
        );
        /*!
            ensures
                - This function blocks until the user presses a keyboard key or the
                  window is closed by the user.  It will also unblock for a mouse double
                  click if events_tied() == true.
                - This function is the equivalent to calling get_next_keypress(key,is_printable,temp)
                  and then discarding temp.
        !*/

    private:

        // restricted functions
        image_window(image_window&);
        image_window& operator= (image_window&);
    };

// ----------------------------------------------------------------------------------------

    class perspective_display : public drawable, noncopyable
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is a tool for displaying 3D point clouds on a screen.  You can
                navigate the display with the mouse.  Left click and drag rotates the
                camera around the displayed data.  Scrolling the mouse wheel zooms and
                shift+left click (or just right click) and drag pans the view around.
        !*/

    public:

        perspective_display(
            drawable_window& w
        );
        /*!
            ensures
                - #*this is properly initialized
                - #*this has been added to window w
                - #parent_window() == w
        !*/

        ~perspective_display(
        );
        /*!
            ensures
                - all resources associated with *this have been released
        !*/

        void set_size (
            unsigned long width,
            unsigned long height
        );
        /*!
            ensures
                - #width() == width
                - #height() == height
                - #top() == top()
                - #left() == left()
                - i.e. The location of the upper left corner of this widget stays the
                  same but its width and height are modified.
        !*/

        struct overlay_line
        {
            /*!
                WHAT THIS OBJECT REPRESENTS
                    This object represents a line that is drawn on the screen.  Each line
                    is represented by its two end points (p1 and p2) as well as a color.
            !*/

            overlay_line() { assign_pixel(color, 0);}

            overlay_line(const vector<double>& p1_, const vector<double>& p2_)
                : p1(p1_), p2(p2_) { assign_pixel(color, 255); }

            template <typename pixel_type>
            overlay_line(const vector<double>& p1_, const vector<double>& p2_, pixel_type p)
                : p1(p1_), p2(p2_) { assign_pixel(color, p); }

            vector<double> p1;
            vector<double> p2;
            rgb_pixel color;
        };

        struct overlay_dot
        {
            /*!
                WHAT THIS OBJECT REPRESENTS
                    This object represents a dot that is drawn on the screen.  Each dot is
                    represented by one point and a color.
            !*/

            overlay_dot() { assign_pixel(color, 0);}

            overlay_dot(const vector<double>& p_)
                : p(p_) { assign_pixel(color, 255); }

            template <typename pixel_type>
            overlay_dot(const vector<double>& p_, pixel_type color_)
                : p(p_) { assign_pixel(color, color_); }

            vector<double> p; // The location of the dot
            rgb_pixel color;
        };

        void add_overlay (
            const std::vector<overlay_line>& overlay
        );
        /*!
            ensures
                - Adds the given overlay lines into this object such that it will be
                  displayed.
        !*/

        void add_overlay (
            const std::vector<overlay_dot>& overlay
        );
        /*!
            ensures
                - Adds the given overlay dots into this object such that it will be
                  displayed.
        !*/

        void clear_overlay (
        );
        /*!
            ensures
                - Removes all overlays from this object.  The display will be empty.
        !*/

        template <typename T>
        void set_dot_double_clicked_handler (
            T& object,
            void (T::*event_handler)(const vector<double>&)
        );
        /*
            requires
                - event_handler is a valid pointer to a member function in T
            ensures
                - The event_handler function is called on object when the user double
                  clicks on one of the overlay dots.  The selected dot will be passed to
                  event_handler().
                - Any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
        */

        void set_dot_double_clicked_handler (
            const any_function<void(const vector<double>&)>& event_handler
        );
        /*
            ensures
                - The event_handler function is called when the user double clicks on one
                  of the overlay dots.  The selected dot will be passed to event_handler().
                - Any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
        */
    };

// ----------------------------------------------------------------------------------------

    class perspective_window : public drawable_window, noncopyable
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is a simple window that is just a container for a perspective_display.
                It exists to make it easy to throw perspective_displays onto the screen
                without having to put together your own drawable_window objects.
        !*/
    public:

        typedef perspective_display::overlay_line overlay_line;
        typedef perspective_display::overlay_dot overlay_dot;

        perspective_window(
        );
        /*!
            ensures
                - The window is displayed on the screen and is 100x100 pixels in size.
        !*/

        perspective_window(
            const std::vector<dlib::vector<double> >& point_cloud
        );
        /*!
            ensures
                - The window is displayed on the screen and is 100x100 pixels in size.
                - This window will have point_cloud added to it via add_overlay() and the
                  points will all be white.
        !*/

        perspective_window(
            const std::vector<dlib::vector<double> >& point_cloud,
            const std::string& title
        );
        /*!
            ensures
                - The window is displayed on the screen and is 100x100 pixels in size.
                - This window will have point_cloud added to it via add_overlay() and the
                  points will all be white.
                - The title of the window will be set to the given title string.
        !*/

        ~perspective_window(
        );
        /*!
            ensures
                - any resources associated with this object have been released
        !*/

        void add_overlay (
            const std::vector<overlay_line>& overlay
        );
        /*!
            ensures
                - Adds the given overlay lines into this object such that it will be
                  displayed.
        !*/

        void add_overlay (
            const std::vector<overlay_dot>& overlay
        );
        /*!
            ensures
                - Adds the given overlay dots into this object such that it will be
                  displayed.
        !*/

        void clear_overlay (
        );
        /*!
            ensures
                - Removes all overlays from this object.  The display will be empty.
        !*/

        void add_overlay(
            const std::vector<dlib::vector<double> >& d
        );
        /*!
            ensures
                - Adds the given dots into this object such that it will be
                  displayed.  They will be colored white.
        !*/

        template <typename pixel_type>
        void add_overlay(
            const std::vector<dlib::vector<double> >& d,
            pixel_type p
        );
        /*!
            ensures
                - Adds the given dots into this object such that it will be
                  displayed.  They will be colored by pixel color p.
        !*/

        template <typename pixel_type>
        void add_overlay(
            const vector<double>& p1,
            const vector<double>& p2,
            pixel_type color
        );
        /*!
            ensures
                - Adds an overlay line going from p1 to p2 with the given color.
        !*/

        template < typename T >
        void set_dot_double_clicked_handler (
            T& object,
            void (T::*event_handler)(const vector<double>&)
        );
        /*
            requires
                - event_handler is a valid pointer to a member function in T
            ensures
                - The event_handler function is called on object when the user double
                  clicks on one of the overlay dots.  The selected dot will be passed to
                  event_handler().
                - Any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
        */

        void set_dot_double_clicked_handler (
            const any_function<void(const vector<double>&)>& event_handler
        );
        /*
            ensures
                - The event_handler function is called when the user double clicks on one
                  of the overlay dots.  The selected dot will be passed to event_handler().
                - Any previous calls to this function are overridden by this new call.
                  (i.e. you can only have one event handler associated with this
                  event at a time)
        */

    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_WIDGETs_ABSTRACT_


dlib C++ Library - misc_api_kernel_abstract.h

// Copyright (C) 2004  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_MISC_API_KERNEl_ABSTRACT_
#ifdef DLIB_MISC_API_KERNEl_ABSTRACT_

#include <string>
#include "../uintn.h"
#include "../algs.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    /*!
        GENERAL COMMENTS
            This file just contains miscellaneous api functions
    !*/

// ----------------------------------------------------------------------------------------

    void sleep (
        unsigned long milliseconds
    );
    /*!
        ensures
            - causes the calling thread to sleep for the given number of
              milliseconds.
    !*/

// ----------------------------------------------------------------------------------------

    std::string get_current_dir (
    );
    /*!
        ensures
            - if (no errors occur) then
                - returns the path to the current working directory
            - else
                - returns ""
        throws
            - std::bad_alloc
    !*/

// ----------------------------------------------------------------------------------------

    class set_current_dir_error : public error;

    void set_current_dir (
        const std::string& new_dir
    );
    /*!
        ensures
            - sets the current working directory to new_dir
        throws
            - std::bad_alloc
            - set_current_dir_error
              This exception is thrown if there is an error when attempting
              to change the current working directory.
    !*/

// ----------------------------------------------------------------------------------------

    class locally_change_current_dir : noncopyable
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is a RAII tool for safely switching the current directory
                to a new directory and then automatically switching back to the original
                directory upon this object's destruction.
        !*/
    public:
        explicit locally_change_current_dir (
            const std::string& new_dir
        );
        /*!
            ensures
                - calls set_current_dir(new_dir)
                - #old_dir() == The value of get_current_dir() prior to switching to new_dir.
        !*/

        const std::string& old_dir (
        ) const;
        /*!
            ensures
                - returns the directory we switch back to once this object is destructed.
        !*/

        ~locally_change_current_dir(
        );
        /*!
            ensures
                - if (revert() hasn't already been called) then
                    - calls set_current_dir(old_dir())
        !*/

        void revert (
        );
        /*!
            ensures
                - if (revert() hasn't already been called) then
                    - calls set_current_dir(old_dir())
        !*/
    };

// ----------------------------------------------------------------------------------------

    class dir_create_error : public error {
    public:
        const std::string name
    };

    void create_directory (
        const std::string& dir
    );
    /*!
        ensures
            - if (dir does not already exist) then
                - creates the given directory.
            - else
                - the call to create_directory() has no effect.
        throws
            - dir_create_error
                This exception is thrown if we were unable to create the requested
                directory and it didn't already exist.  The type member of the exception
                will bet set to EDIR_CREATE and the name member will be set to dir.
    !*/

// ----------------------------------------------------------------------------------------

    class timestamper
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object represents a timer that is capable of returning
                timestamps.

                Note that the time is measured in microseconds but you are not
                guaranteed to have that level of resolution.  The actual resolution
                is implementation dependent.
        !*/

    public:
        uint64 get_timestamp (
        ) const;
        /*!
            ensures
                - returns a timestamp that measures the time in microseconds since an
                  arbitrary point in the past.  Note that this arbitrary point remains
                  the same between all calls to get_timestamp().
        !*/
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MISC_API_KERNEl_ABSTRACT_


dlib C++ Library - sockets_extensions_abstract.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SOCKETS_EXTENSIONs_ABSTRACT_
#ifdef DLIB_SOCKETS_EXTENSIONs_ABSTRACT_

#include <string>
#include "sockets_kernel_abstract.h"
#include "../smart_pointers.h"
#include "../error.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class invalid_network_address : public dlib::error
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is the exception thrown by network_address's constructor if the
                input is invalid.
        !*/
    };

// ----------------------------------------------------------------------------------------

    struct network_address
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is simply a container for two things:
                    - A host machine address which is either an IP address or DNS name
                      for a machine.
                    - A port number.

                Together, these things define a machine and port on that machine.
        !*/

        network_address(
        );
        /*!
            ensures
                - host_address == ""
                - #port == 0
        !*/

        network_address(
            const std::string& full_address
        );
        /*!
            ensures
                - interprets full_address as a network address of the form:
                    host_address:port
                  and assigns each part into #host_address and #port.  For example,
                  network_address("localhost:80") would result in a network_address
                  object where host_address was "localhost" and port was 80.
            throws
                - invalid_network_address
                    This exception is thrown if the full_address string can't be
                    interpreted as a valid network address.
        !*/

        network_address (
            const char* full_address
        );
        /*!
            requires
                - full_address == a valid pointer to a null terminated string
            ensures
                - Invoking this constructor is equivalent to performing
                  network_address(std::string(full_address))
        !*/

        network_address(
            const std::string& host_address_,
            const unsigned short port_
        );
        /*!
            ensures
                - #host_address == host_address_
                - #port == port_
        !*/

        std::string host_address;
        unsigned short port;
    };

// ----------------------------------------------------------------------------------------

    inline bool operator < (
        const network_address& a,
        const network_address& b
    );
    /*!
        ensures
            - provides a total ordering over network_address objects so you can use them in
              the standard associative containers.  The ordering is defined such that if
              you sorted network addresses they would sort first on the host_address string
              and then, for network_address objects with equal host_address, they would
              sort on the port number
    !*/

    inline bool operator== (
        const network_address& a,
        const network_address& b
    );
    /*!
        ensures
            - returns true if a and b contain exactly the same address and false otherwise.
              That is, the following must be true for this function to return true:
                - a.host_address == b.host_address
                - a.port == b.port
              Note that this means that two addresses which are logically equivalent but
              written differently will not compare equal.  For example, suppose example.com
              has the IP address 10.1.1.1.  Then network_address("10.1.1.1:80") and
              network_address("example.com:80") really refer to the same network resource
              but will nevertheless not compare equal since.
    !*/

    inline bool operator != (
        const network_address& a,
        const network_address& b
    );
    /*!
        ensures
            - returns !(a == b)
    !*/

// ----------------------------------------------------------------------------------------

    void serialize(
        const network_address& item,
        std::ostream& out
    );
    /*!
        ensures
            - provides serialization support
    !*/

    void deserialize(
        network_address& item,
        std::istream& in
    );
    /*!
        ensures
            - provides deserialization support
    !*/

    std::ostream& operator<< (
        std::ostream& out,
        const network_address& item
    );
    /*!
        ensures
            - writes the given network_address to the output stream.  The format is the
              host_address, then a colon, then the port number.  So for example:
                cout << network_address("localhost", 80);
              would print:
                localhost:80
            - returns #out
    !*/

    std::istream& operator>> (
        std::istream& in,
        network_address& item
    );
    /*!
        ensures
            - reads a network_address from the given input stream.  The expected format is
              the same as the one used to print them by the above operator<<() routine.
            - returns #in
            - if (there is an error reading the network_address) then
                - #in.good() == false
    !*/

// ----------------------------------------------------------------------------------------

    connection* connect (
        const std::string& host_or_ip,
        unsigned short port
    );
    /*!
        ensures
            - returns a connection object that is connected to the given host at the
              given port
        throws
            - dlib::socket_error
                This exception is thrown if there is some problem that prevents us from
                creating the connection
            - std::bad_alloc
    !*/

// ----------------------------------------------------------------------------------------

    connection* connect (
        const network_address& addr
    );
    /*!
        ensures
            - returns connect(addr.host_address, addr_port);
    !*/

// ----------------------------------------------------------------------------------------

    connection* connect (
        const std::string& host_or_ip,
        unsigned short port,
        unsigned long timeout
    );
    /*!
        ensures
            - returns a connection object that is connected to the given host at the
              given port.
            - blocks for at most timeout milliseconds
        throws
            - dlib::socket_error
                This exception is thrown if there is some problem that prevents us from
                creating the connection or if timeout milliseconds elapses before the
                connect is successful.
            - std::bad_alloc
    !*/

// ----------------------------------------------------------------------------------------

    bool is_ip_address (
        std::string ip
    );
    /*!
        ensures
            - if (ip is a valid ip address) then
                - returns true
            - else
                - returns false
    !*/

// ----------------------------------------------------------------------------------------

    void close_gracefully (
        connection* con,
        unsigned long timeout = 500
    );
    /*!
        requires
            - con == a valid pointer to a connection object or 0
        ensures
            - This function does nothing if con == 0, otherwise it performs the following:
                - performs a graceful close of the given connection and if it takes longer
                  than timeout milliseconds to complete then forces the connection closed.
                    - Specifically, a graceful close means that the outgoing part of con is
                      closed (a FIN is sent) and then we wait for the other end to to close
                      their end of the connection.  This way any data still on its way to
                      the other end of the connection will be received properly.
                - This function will block until the graceful close is completed or we
                  timeout.
                - calls "delete con;".  Thus con is no longer a valid pointer after this
                  function has finished.
        throws
            - std::bad_alloc or dlib::thread_error
                If either of these exceptions are thrown con will still be closed via
                "delete con;"
    !*/

// ----------------------------------------------------------------------------------------

    void close_gracefully (
        scoped_ptr<connection>& con,
        unsigned long timeout = 500
    );
    /*!
        requires
            - con == a valid pointer to a connection object or con.get() == 0
        ensures
            - This function does nothing if con.get() == 0, otherwise it performs the
              following:
                - performs a graceful close of the given connection and if it takes longer
                  than timeout milliseconds to complete then forces the connection closed.
                    - Specifically, a graceful close means that the outgoing part of con is
                      closed (a FIN is sent) and then we wait for the other end to to close
                      their end of the connection.  This way any data still on its way to
                      the other end of the connection will be received properly.
                - This function will block until the graceful close is completed or we
                  timeout.
                - #con.get() == 0.  Thus con is no longer a valid pointer after this
                  function has finished.
        throws
            - std::bad_alloc or dlib::thread_error
                If either of these exceptions are thrown con will still be closed and
                deleted (i.e. #con.get() == 0).
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SOCKETS_EXTENSIONs_ABSTRACT_


dlib C++ Library - sockets_kernel_abstract.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SOCKETS_KERNEl_ABSTRACT_
#ifdef DLIB_SOCKETS_KERNEl_ABSTRACT_

#include <string>
#include "../threads.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    /*!
        GENERAL COMMENTS:
            Nothing in here will throw exceptions.

            All ip address strings in this file refer to IPv4 addresses.  For
            example "192.168.1.1"

            Timeouts:
                All timeout values are measured in milliseconds but you are not
                guaranteed to have that level of resolution.  The actual resolution
                is implementation defined.

            GENERAL WARNING
                Don't call any of these functions or make any of these objects
                before main() has been entered.

        EXCEPTIONS
            Unless specified otherwise, nothing in this file throws exceptions.
    !*/

// ----------------------------------------------------------------------------------------

    // LOOKUP FUNCTIONS

    // all lookup functions are thread-safe

    int get_local_hostname (
        std::string& hostname
    );
    /*!
        ensures
            - if (#get_local_hostname() == 0) then
                - #hostname == a string containing the hostname of the local computer

            - returns 0 upon success
            - returns OTHER_ERROR upon failure and in this case #hostname's value
              is undefined
    !*/

// -----------------

    int hostname_to_ip (
        const std::string& hostname,
        std::string& ip,
        int n = 0
    );
    /*!
        requires
            - n >= 0
        ensures
            - if (#hostname_to_ip() == 0) then
                - #ip == string containing the nth ip address associated with the hostname

            - returns 0 upon success
            - returns OTHER_ERROR upon failure
    !*/

// -----------------

    int ip_to_hostname (
        const std::string& ip,
        std::string& hostname
    );
    /*!
        ensures
            - if (#ip_to_hostname() == 0) then
                - #hostname == string containing the hostname associated with ip

            - returns 0 upon success
            - returns OTHER_ERROR upon failure
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    //
    // socket creation functions
    //
    // The following functions are guaranteed to be thread-safe
    //
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    int create_listener (
        listener*& new_listener,
        unsigned short port,
        const std::string& ip = ""
    );
    /*!
        requires
            - 0 <= port <= 65535
        ensures
            - if (#create_listener() == 0) then
                - #new_listener == a pointer to a listener object that is listening on
                  the specified port and ip for an incoming connection
                - if (ip == "") then
                    - the new listener will be listening on all interfaces
                - if (port == 0) then
                    - the operating system will assign a free port to listen on

            - returns 0 if create_listener was successful
            - returns PORTINUSE if the specified local port was already in use
            - returns OTHER_ERROR if some other error occurred
    !*/

    int create_listener (
        scoped_ptr<listener>& new_listener,
        unsigned short port,
        const std::string& ip = ""
    );
    /*!
        This function is just an overload of the above function but it gives you a
        scoped_ptr smart pointer instead of a C pointer.
    !*/

    int create_connection (
        connection*& new_connection,
        unsigned short foreign_port,
        const std::string& foreign_ip,
        unsigned short local_port = 0,
        const std::string& local_ip = ""
    );
    /*!
        requires
            - 0 <  foreign_port <= 65535
            - 0 <= local_port   <= 65535
        ensures
            - if (#create_connection() == 0) then
                - #new_connection  == a pointer to a connection object that is connected
                  to foreign_ip on port foreign_port and is using the local interface
                  local_ip and local port local_port
                - #new_connection->user_data == 0
                - if (local_ip == "") then
                    - the operating system will chose this for you
                - if (local_port == 0) then
                    - the operating system will chose this for you

            - returns 0 if create_connection was successful
            - returns PORTINUSE if the specified local port was already in use
            - returns OTHER_ERROR if some other error occurred
        !*/

    int create_connection (
        scoped_ptr<connection>& new_connection,
        unsigned short foreign_port,
        const std::string& foreign_ip,
        unsigned short local_port = 0,
        const std::string& local_ip = ""
    );
    /*!
        This function is just an overload of the above function but it gives you a
        scoped_ptr smart pointer instead of a C pointer.
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // connection object
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class connection
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object represents a TCP connection.

                Instances of this class can only be created by using the
                create_connection function or listener class defined below.

                NOTE:
                    A connection object must ALWAYS be closed (delete the pointer to the
                    connection) or it will cause a resource leak.

                    Note also that all errors indicated by a return code of OTHER_ERROR
                    are fatal so if one occurs the connection should just be closed.

            CLOSING A CONNECTION
                Note that if ~connection() or shutdown() is called before the remote client
                has received all sent data it is possible that the data will be lost.  To
                avoid this you should call the close_gracefully() function to close your
                connections (unless you actually do want to immediately dispose of a
                connection and don't care about the data).
                (example: close_gracefully(con); // close con gracefully but force it closed
                                                   // if it takes more than 500 milliseconds.)

            THREAD SAFETY
                - It is always safe to call shutdown() or shutdown_outgoing().
                - you may NOT call any function more than once at a time (except the
                  shutdown functions).
                - do not call read() more than once at a time
                - do not call write() more than once at a time
                - You can safely call shutdown or shutdown_outgoing in conjunction with
                  the read/write functions.
                    This is helpful if you want to unblock another thread that is
                    blocking on a read/write operation.  Shutting down the connection
                    will cause the read/write functions to return a value of SHUTDOWN.

            OUT-OF-BAND DATA:
                All out-of-band data will be put inline into the normal data stream.
                This means that you can read any out-of-band data via calls to read().
                (i.e. the SO_OOBINLINE socket option will be set)
        !*/

    public:

        ~connection (
        );
        /*!
            requires
                - no other threads are using this connection object
            ensures
                - closes the connection (this is an abrupt non-graceful close)
                - frees the resources used by this object
        !*/

        void* user_data;
        /*!
            This pointer is provided so that the client programmer may easily associate
            some data with a connection object.  You can really do whatever you want
            with it.  Initially user_data is 0.
        !*/

        long write (
            const char* buf,
            long num
        );
        /*!
            requires
                - num > 0
                - buf points to an array of at least num bytes
            ensures
                - will block until ONE of the following occurs:
                    - num bytes from buf have been written to the connection
                    - an error has occurred
                    - the outgoing channel of the connection has been shutdown locally

                - returns num if write succeeded
                - returns OTHER_ERROR if there was an error (this could be due to a
                  connection close)
                - returns SHUTDOWN if the outgoing channel of the connection has been
                  shutdown locally
        !*/

        long read (
            char* buf,
            long num
        );
        /*!
            requires
                - num > 0
                - buf points to an array of at least num bytes
            ensures
                - read() will not read more than num bytes of data into #buf
                - read blocks until ONE of the following happens:
                    - there is some data available and it has been written into #buf
                    - the remote end of the connection is closed
                    - an error has occurred
                    - the connection has been shutdown locally

                - returns the number of bytes read into #buf if there was any data.
                - returns 0 if the connection has ended/terminated and there is no more data.
                - returns OTHER_ERROR if there was an error.
                - returns SHUTDOWN if the connection has been shutdown locally
        !*/

        long read (
            char* buf,
            long num,
            unsigned long timeout
        );
        /*!
            requires
                - num > 0
                - buf points to an array of at least num bytes
                - timeout < 2000000
            ensures
                - read() will not read more than num bytes of data into #buf
                - if (timeout > 0) then read() blocks until ONE of the following happens:
                    - there is some data available and it has been written into #buf
                    - the remote end of the connection is closed
                    - an error has occurred
                    - the connection has been shutdown locally
                    - timeout milliseconds has elapsed
                - else
                    - read() does not block

                - returns the number of bytes read into #buf if there was any data.
                - returns 0 if the connection has ended/terminated and there is no more data.
                - returns TIMEOUT if timeout milliseconds elapsed before we got any data.
                - returns OTHER_ERROR if there was an error.
                - returns SHUTDOWN if the connection has been shutdown locally
        !*/

        unsigned short get_local_port (
        ) const;
        /*!
            ensures
                - returns the local port number for this connection
        !*/

        unsigned short get_foreign_port (
        ) const;
        /*!
            ensures
                - returns the foreign port number for this connection
        !*/

        const std::string& get_local_ip (
        ) const;
        /*!
            ensures
                - returns the IP of the local interface this connection is using
        !*/

        const std::string& get_foreign_ip (
        ) const;
        /*!
            ensures
                - returns the IP of the foreign host for this connection
        !*/

        int shutdown (
        );
        /*!
            ensures
                - if (#shutdown() == 0 && connection was still open) then
                    - terminates the connection but does not free the resources for the
                      connection object

                - any read() or write() calls on this connection will return immediately
                  with the code SHUTDOWN.

                - returns 0 upon success
                - returns OTHER_ERROR if there was an error
        !*/

        int shutdown_outgoing (
        );
        /*!
            ensures
                - if (#shutdown_outgoing() == 0 && outgoing channel was still open) then
                    - sends a FIN to indicate that no more data will be sent on this
                      connection but leaves the receive half of the connection open to
                      receive more data from the other host

                - any calls to write() will return immediately with the code SHUTDOWN.

                - returns 0 upon success
                - returns OTHER_ERROR if there was an error
        !*/

        int disable_nagle(
        );
        /*!
            ensures
                - Sets the TCP_NODELAY socket option to disable Nagle's algorithm.
                  This can sometimes reduce transmission latency, however, in almost
                  all normal cases you don't want to mess with this as the default
                  setting is usually appropriate.

                - returns 0 upon success
                - returns OTHER_ERROR if there was an error
        !*/

        typedef platform_specific_type socket_descriptor_type;
        socket_descriptor_type get_socket_descriptor (
        ) const;
        /*!
            ensures
                - returns the underlying socket descriptor for this connection
                  object.  The reason you might want access to this is to
                  pass it to some other library that requires a socket file
                  descriptor.  However, if you do this then you probably shouldn't
                  use the dlib::connection read() and write() anymore since
                  whatever you are doing with the socket descriptor is probably
                  doing I/O with the socket.
        !*/

    private:
        // restricted functions
        connection();
        connection(connection&);        // copy constructor
        connection& operator=(connection&);    // assignment operator

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // listener object
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class listener
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object represents a TCP socket waiting for incoming connections.
                Calling accept returns a pointer to any new incoming connections on its
                port.

                Instances of this class can only be created by using the
                create_listener function defined below.

                NOTE:
                    A listener object must ALWAYS be closed (delete the pointer to it) or
                    it will cause a resource leak.

                    Note also that all errors indicated by a return code of OTHER_ERROR
                    are fatal so if one occurs the listener should be closed.

            THREAD SAFETY
                None of the functions in this object are guaranteed to be thread-safe.
                This means that you must serialize all access to this object.
        !*/

    public:

        ~listener (
        );
        /*!
            requires
                - no other threads are using this listener object
            ensures
                - closes the listener
                - frees the resources used by this object
        !*/

        int accept (
            connection*& new_connection,
            unsigned long timeout = 0
        );
        /*!
            requires
                - timeout < 2000000
            ensures
                - blocks until a new connection is ready or timeout milliseconds have
                  elapsed.
                - #new_connection == a pointer to the new connection object
                - #new_connection->user_data == 0
                - if (timeout == 0) then
                    - the timeout argument is ignored

                - returns 0 if accept() was successful
                - returns TIMEOUT if timeout milliseconds have elapsed
                - returns OTHER_ERROR if an error has occurred
        !*/

        int accept (
            scoped_ptr<connection>& new_connection,
            unsigned long timeout = 0
        );
        /*!
            This function is just an overload of the above function but it gives you a
            scoped_ptr smart pointer instead of a C pointer.
        !*/

        unsigned short get_listening_port (
        ) const;
        /*!
            ensures
                - returns the port number that this object is listening on
        !*/

        const std::string& get_listening_ip (
        ) const;
        /*!
            ensures
                - returns a string containing the IP (e.g. "127.0.0.1") of the
                  interface this object is listening on
                - returns "" if it is accepting connections on all interfaces
        !*/

    private:
        // restricted functions
        listener();
        listener(listener&);        // copy constructor
        listener& operator=(listener&);    // assignment operator
    };
}

#endif // DLIB_SOCKETS_KERNEl_ABSTRACT_


dlib C++ Library - threads_kernel_abstract.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_THREADS_KERNEl_ABSTRACT_
#ifdef DLIB_THREADS_KERNEl_ABSTRACT_

namespace dlib
{

// ----------------------------------------------------------------------------------------

    /*!
        THREAD POOLING
            When threads end they go into a global thread pool and each waits there
            for 30 seconds before timing out and having its resources returned to the
            operating system.  When create_new_thread() is called it first looks in the
            thread pool to see if there are any threads it can snatch from the pool, if
            not then it makes a new one.

            Note that whenever I say something happens when a thread "terminates" or "ends"
            I mean "when it returns to the thread pool."  From the client programmer point
            of view a thread terminates/ends when it returns to the dlib thread pool and you
            shouldn't and indeed don't need to know when it actually gets its resources
            reclaimed by the operating system.

            If you want to change the timeout to a different value you can #define
            DLIB_THREAD_POOL_TIMEOUT to whatever value (in milliseconds) that you like.

        EXCEPTIONS
            Unless specified otherwise, nothing in this file throws exceptions.
    !*/

// ----------------------------------------------------------------------------------------

    thread_id_type get_thread_id (
    );
    /*!
        ensures
            - returns a unique id for the calling thread.  Note that while the id is unique
              among all currently existing threads it may have been used by a previous
              thread that has terminated.
    !*/

// ----------------------------------------------------------------------------------------

    bool is_dlib_thread (
        thread_id_type id = get_thread_id()
    );
    /*!
        ensures
            - if (the thread with the given id was spawned by a call to
                  dlib::create_new_thread) then
                - returns true
            - else
                - returns false
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    void register_thread_end_handler (
        T& obj,
        void (T::*handler)()
    );
    /*!
        requires
            - handler == a valid member function pointer for class T
            - handler does not throw
            - handler does not call register_thread_end_handler()
            - handler does not block
            - is_dlib_thread() == true (i.e. the calling thread was spawned by dlib::create_new_thread())
        ensures
            - let ID == the thread id for the thread calling register_thread_end_handler()
            - (obj.*handler)() will be called when the thread with thread id ID is
              terminating and it will be called from within that terminating thread.
              (i.e. inside the handler function get_thread_id() == ID == the id of the
              thread that is terminating. )
            - each call to this function adds another handler that will be called when
              the given thread terminates.  This means that if you call it a bunch of
              times then you will end up registering multiple handlers (or single
              handlers multiple times) that will be called when the thread ends.
        throws
            - std::bad_alloc
              If this exception is thrown then the call to this function had no effect.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    void unregister_thread_end_handler (
        T& obj,
        void (T::*handler)()
    );
    /*!
        requires
            - handler == a valid member function pointer for class T
        ensures
            - Undoes all previous calls to register_thread_end_handler(obj,handler).
              So the given handler won't be called when any threads end.
        throws
            - std::bad_alloc
              If this exception is thrown then the call to this function had no effect.
    !*/

// ----------------------------------------------------------------------------------------

    bool create_new_thread (
        void (*funct)(void*),
        void* param
    );
    /*!
        ensures
            - creates a new thread for the function pointed to by funct
            - passes it param as its parameter. (i.e. calls funct(param) from the new thread)
            - returns true upon success and false upon failure to create the new thread
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // mutex object
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class mutex
    {
        /*!
            INITIAL VALUE
                mutex is in the unlocked state

            WHAT THIS OBJECT REPRESENTS
                This object represents a mutex intended to be used for synchronous
                thread control of shared data. When a thread wants to access some
                shared data it locks out other threads by calling lock() and calls
                unlock() when it is finished.
        !*/
    public:

        mutex (
        );
        /*!
            ensures
                - #*this is properly initialized
            throws
                - dlib::thread_error
                    the constructor may throw this exception if there is a problem
                    gathering resources to create the mutex.
        !*/

        ~mutex (
        );
        /*!
            requires
                - *this is not locked
            ensures
                - all resources allocated by *this have been freed
        !*/

        void lock (
        ) const;
        /*!
            requires
                - the thread calling lock() does not already have a lock on *this
            ensures
                - if (*this is currently locked by another thread) then
                    - the thread that called lock() on *this is put to sleep until
                      it becomes available
                - if (*this is currently unlocked) then
                    - #*this becomes locked and the current thread is NOT put to sleep
                      but now "owns" #*this
        !*/

        void unlock (
        ) const;
        /*!
            requires
                - the thread calling unlock() already has a lock on *this
            ensures
                - #*this is unlocked (i.e. other threads may now lock this object)
        !*/

    private:
        // restricted functions
        mutex(mutex&);        // copy constructor
        mutex& operator=(mutex&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // signaler object
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class signaler
    {
        /*!

            WHAT THIS OBJECT REPRESENTS
                This object represents an event signaling system for threads.  It gives
                a thread the ability to wake up other threads that are waiting for a
                particular signal.

                Each signaler object is associated with one and only one mutex object.
                More than one signaler object may be associated with a single mutex
                but a signaler object may only be associated with a single mutex.

                NOTE:
                You must guard against spurious wakeups.  This means that a thread
                might return from a call to wait even if no other thread called
                signal.  This is rare but must be guarded against.
        !*/
    public:

        signaler (
            const mutex& associated_mutex
        );
        /*!
            ensures
                - #*this is properly initialized
                - #get_mutex() == associated_mutex
            throws
                - dlib::thread_error
                    the constructor may throw this exception if there is a problem
                    gathering resources to create the signaler.
        !*/

        ~signaler (
        );
        /*!
            ensures
                - all resources allocated by *this have been freed
        !*/

        void wait (
        ) const;
        /*!
            requires
                - get_mutex() is locked and owned by the calling thread
            ensures
                - atomically unlocks get_mutex() and blocks the calling thread
                - calling thread may wake if another thread calls signal() or broadcast()
                  on *this
                - when wait() returns the calling thread again has a lock on get_mutex()
        !*/

        bool wait_or_timeout (
            unsigned long milliseconds
        ) const;
        /*!
            requires
                - get_mutex() is locked and owned by the calling thread
            ensures
                - atomically unlocks get_mutex() and blocks the calling thread
                - calling thread may wake if another thread calls signal() or broadcast()
                  on *this
                - after the specified number of milliseconds has elapsed the calling thread
                  will wake once get_mutex() is free
                - when wait returns the calling thread again has a lock on get_mutex()

                - returns false if the call to wait_or_timeout timed out
                - returns true if the call did not time out
        !*/

        void signal (
        ) const;
        /*!
            ensures
                - if (at least one thread is waiting on *this) then
                    - at least one of the waiting threads will wake
        !*/

        void broadcast (
        ) const;
        /*!
            ensures
                - any and all threads waiting on *this will wake
        !*/

        const mutex& get_mutex (
        ) const;
        /*!
            ensures
                - returns a const reference to the mutex associated with *this
        !*/

    private:
        // restricted functions
        signaler(signaler&);        // copy constructor
        signaler& operator=(signaler&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_THREADS_KERNEl_ABSTRACT_


dlib C++ Library - thread_pool_extension_abstract.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_THREAD_POOl_ABSTRACT_Hh_
#ifdef DLIB_THREAD_POOl_ABSTRACT_Hh_

#include "threads_kernel_abstract.h"
#include "../uintn.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    class future
    {
        /*!
            INITIAL VALUE
                - is_ready() == true

            WHAT THIS OBJECT REPRESENTS
                This object represents a container that allows you to safely pass objects
                into the tasks performed by the thread_pool object defined below.  An
                example will make it clear:

                    // Suppose you have a global function defined as follows
                    void add (int a, int b, int& result) { result = a + b; }

                    // Also suppose you have a thread_pool named tp defined somewhere.
                    // Then you could do the following.
                    future<int> a, b, result;
                    a = 3;
                    b = 4;
                    // this function call causes another thread to execute a call to the add() function
                    // and passes in the int objects contained in a, b, and result
                    tp.add_task(add,a,b,result);
                    // This line will wait for the task in the thread pool to finish and then print the
                    // value in the result integer.  So it will print a 7.
                    cout << result << endl;
        !*/

    public:
        future (
        );
        /*!
            ensures
                - The object of type T contained in this future has
                  an initial value for its type.
                - #is_ready() == true
        !*/

        future (
            const T& item
        );
        /*!
            ensures
                - #get() == item
                - #is_ready() == true
        !*/

        future (
            const future& item
        );
        /*!
            ensures
                - if (item.is_ready() == false) then
                    - the call to this function blocks until the thread processing the task related
                      to the item future has finished.
                - #is_ready() == true
                - #item.is_ready() == true
                - #get() == item.get()
        !*/

        ~future (
        );
        /*!
            ensures
                - if (is_ready() == false) then
                    - the call to this function blocks until the thread processing the task related
                      to this future has finished.
        !*/

        bool is_ready (
        ) const;
        /*!
            ensures
                - if (the value of this future may not yet be ready to be accessed because it
                  is in use by a task in a thread_pool) then
                    - returns false
                - else
                    - returns true
        !*/

        future& operator=(
            const T& item
        );
        /*!
            ensures
                - if (is_ready() == false) then
                    - the call to this function blocks until the thread processing the task related
                      to this future has finished.
                - #is_ready() == true
                - #get() == item
                - returns *this
        !*/

        future& operator=(
            const future& item
        );
        /*!
            ensures
                - if (is_ready() == false || item.is_ready() == false) then
                    - the call to this function blocks until the threads processing the tasks related
                      to this future and the item future have finished.
                - #is_ready() == true
                - #item.is_ready() == true
                - #get() == item.get()
                - returns *this
        !*/

        operator T& (
        );
        /*!
            ensures
                - if (is_ready() == false) then
                    - the call to this function blocks until the thread processing the task related
                      to this future has finished.
                - #is_ready() == true
                - returns get()
        !*/

        operator const T& (
        ) const;
        /*!
            ensures
                - if (is_ready() == false) then
                    - the call to this function blocks until the thread processing the task related
                      to this future has finished.
                - #is_ready() == true
                - returns get()
        !*/

        T& get (
        );
        /*!
            ensures
                - if (is_ready() == false) then
                    - the call to this function blocks until the thread processing the task related
                      to this future has finished.
                - #is_ready() == true
                - returns a non-const reference to the object of type T contained inside this future
        !*/

        const T& get (
        ) const;
        /*!
            ensures
                - if (is_ready() == false) then
                    - the call to this function blocks until the thread processing the task related
                      to this future has finished.
                - #is_ready() == true
                - returns a const reference to the object of type T contained inside this future
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <typename T>
    inline void swap (
        future<T>& a,
        future<T>& b
    ) { std::swap(a.get(), b.get()); }
    /*!
        provides a global swap function
    !*/

// ----------------------------------------------------------------------------------------

//  The future object comes with overloads for all the usual comparison operators.

    template <typename T> bool operator== (const future<T>& a, const future<T>& b) { return a.get() == b.get(); }
    template <typename T> bool operator!= (const future<T>& a, const future<T>& b) { return a.get() != b.get(); }
    template <typename T> bool operator<= (const future<T>& a, const future<T>& b) { return a.get() <= b.get(); }
    template <typename T> bool operator>= (const future<T>& a, const future<T>& b) { return a.get() >= b.get(); }
    template <typename T> bool operator<  (const future<T>& a, const future<T>& b) { return a.get() <  b.get(); }
    template <typename T> bool operator>  (const future<T>& a, const future<T>& b) { return a.get() >  b.get(); }

    template <typename T> bool operator== (const future<T>& a, const T& b)         { return a.get() == b; }
    template <typename T> bool operator== (const T& a,         const future<T>& b) { return a       == b.get(); }
    template <typename T> bool operator!= (const future<T>& a, const T& b)         { return a.get() != b; }
    template <typename T> bool operator!= (const T& a,         const future<T>& b) { return a       != b.get(); }
    template <typename T> bool operator<= (const future<T>& a, const T& b)         { return a.get() <= b; }
    template <typename T> bool operator<= (const T& a,         const future<T>& b) { return a       <= b.get(); }
    template <typename T> bool operator>= (const future<T>& a, const T& b)         { return a.get() >= b; }
    template <typename T> bool operator>= (const T& a,         const future<T>& b) { return a       >= b.get(); }
    template <typename T> bool operator<  (const future<T>& a, const T& b)         { return a.get() <  b; }
    template <typename T> bool operator<  (const T& a,         const future<T>& b) { return a       <  b.get(); }
    template <typename T> bool operator>  (const future<T>& a, const T& b)         { return a.get() >  b; }
    template <typename T> bool operator>  (const T& a,         const future<T>& b) { return a       >  b.get(); }

// ----------------------------------------------------------------------------------------

    class thread_pool
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object represents a fixed size group of threads which you can
                submit tasks to and then wait for those tasks to be completed.

                Note that setting the number of threads to 0 is a valid way to
                use this object.  It causes it to not contain any threads
                at all.  When tasks are submitted to the object in this mode
                the tasks are processed within the calling thread.  So in this
                mode any thread that calls add_task() is considered to be
                a thread_pool thread capable of executing tasks.

                This object is also implemented such that no memory allocations occur
                after the thread_pool has been constructed so long as the user doesn't
                call any of the add_task_by_value() routines.  The future object also
                doesn't perform any memory allocations or contain any system resources
                such as mutex objects.

            EXCEPTIONS
                Note that if an exception is thrown inside a task thread and
                is not caught then the normal rule for uncaught exceptions in
                threads applies. That is, the application will be terminated.
        !*/

    public:
        explicit thread_pool (
            unsigned long num_threads
        );
        /*!
            ensures
                - #num_threads_in_pool() == num_threads
            throws
                - std::bad_alloc
                - dlib::thread_error
                    the constructor may throw this exception if there is a problem
                    gathering resources to create threading objects.
        !*/

        ~thread_pool(
        );
        /*!
            ensures
                - blocks until all tasks in the pool have finished.
        !*/

        bool is_task_thread (
        ) const;
        /*!
            ensures
                - if (the thread calling this function is one of the threads in this
                  thread pool or num_threads_in_pool() == 0) then
                    - returns true
                - else
                    - returns false
        !*/

        unsigned long num_threads_in_pool (
        ) const;
        /*!
            ensures
                - returns the number of threads contained in this thread pool.  That is, returns
                  the maximum number of tasks that this object will process concurrently.
        !*/

        template <typename F>
        uint64 add_task_by_value (
            const F& function_object
        );
        /*!
            requires
                - function_object() is a valid expression
            ensures
                - makes a copy of function_object, call it FCOPY.
                - if (is_task_thread() == true and there aren't any free threads available) then
                    - calls FCOPY() within the calling thread and returns when it finishes
                - else
                    - the call to this function blocks until there is a free thread in the pool
                      to process this new task.  Once a free thread is available the task
                      is handed off to that thread which then calls FCOPY().
                - returns a task id that can be used by this->wait_for_task() to wait
                  for the submitted task to finish.
        !*/

        template <typename T>
        uint64 add_task (
            T& obj,
            void (T::*funct)()
        );
        /*!
            requires
                - funct == a valid member function pointer for class T
                - obj will not go out of scope until after the task has completed (i.e.
                  this function passes obj to the task by reference.  If you want to avoid
                  this restriction then use add_task_by_value())
            ensures
                - if (is_task_thread() == true and there aren't any free threads available) then
                    - calls (obj.*funct)() within the calling thread and returns
                      when it finishes.
                - else
                    - the call to this function blocks until there is a free thread in the pool
                      to process this new task.  Once a free thread is available the task
                      is handed off to that thread which then calls (obj.*funct)()
                - returns a task id that can be used by this->wait_for_task() to wait
                  for the submitted task to finish.
        !*/

        template <typename T>
        uint64 add_task_by_value (
            const T& obj,
            void (T::*funct)()
        );
        /*!
            requires
                - funct == a valid member function pointer for class T
            ensures
                - makes a copy of obj, call it OBJ_COPY.
                - if (is_task_thread() == true and there aren't any free threads available) then
                    - calls (OBJ_COPY.*funct)() within the calling thread and returns
                      when it finishes.
                - else
                    - the call to this function blocks until there is a free thread in the pool
                      to process this new task.  Once a free thread is available the task
                      is handed off to that thread which then calls (OBJ_COPY.*funct)().
                - returns a task id that can be used by this->wait_for_task() to wait
                  for the submitted task to finish.
        !*/

        template <typename T>
        uint64 add_task (
            T& obj,
            void (T::*funct)(long),
            long arg1
        );
        /*!
            requires
                - funct == a valid member function pointer for class T
                - obj will not go out of scope until after the task has completed (i.e.
                  this function passes obj to the task by reference.  If you want to avoid
                  this restriction then use add_task_by_value())
            ensures
                - if (is_task_thread() == true and there aren't any free threads available) then
                    - calls (obj.*funct)(arg1) within the calling thread and returns
                      when it finishes
                - else
                    - the call to this function blocks until there is a free thread in the pool
                      to process this new task.  Once a free thread is available the task
                      is handed off to that thread which then calls (obj.*funct)(arg1)
                - returns a task id that can be used by this->wait_for_task() to wait
                  for the submitted task to finish.
        !*/

        template <typename T>
        uint64 add_task (
            T& obj,
            void (T::*funct)(long,long),
            long arg1,
            long arg2
        );
        /*!
            requires
                - funct == a valid member function pointer for class T
                - obj will not go out of scope until after the task has completed (i.e.
                  this function passes obj to the task by reference.  If you want to avoid
                  this restriction then use add_task_by_value())
            ensures
                - if (is_task_thread() == true and there aren't any free threads available) then
                    - calls (obj.*funct)(arg1,arg2) within the calling thread and returns
                      when it finishes
                - else
                    - the call to this function blocks until there is a free thread in the pool
                      to process this new task.  Once a free thread is available the task
                      is handed off to that thread which then calls (obj.*funct)(arg1,arg2)
                - returns a task id that can be used by this->wait_for_task() to wait
                  for the submitted task to finish.
        !*/

        void wait_for_task (
            uint64 task_id
        ) const;
        /*!
            ensures
                - if (there is currently a task with the given id being executed in the thread pool) then
                    - the call to this function blocks until the task with the given id is complete
                - else
                    - the call to this function returns immediately
        !*/

        void wait_for_all_tasks (
        ) const;
        /*!
            ensures
                - the call to this function blocks until all tasks which were submitted
                  to the thread pool by the thread that is calling this function have
                  finished.
        !*/

        // --------------------

        template <typename F, typename A1>
        uint64 add_task (
            F& function_object,
            future<A1>& arg1
        );
        /*!
            requires
                - function_object(arg1.get()) is a valid expression
                  (i.e. The A1 type stored in the future must be a type that can be passed into the given function object)
                - function_object will not go out of scope until after the task has completed (i.e.
                  this function passes function_object to the task by reference.  If you want to avoid
                  this restriction then use add_task_by_value())
            ensures
                - if (is_task_thread() == true and there aren't any free threads available) then
                    - calls function_object(arg1.get()) within the calling thread and returns
                      when it finishes
                - else
                    - the call to this function blocks until there is a free thread in the pool
                      to process this new task.  Once a free thread is available the task
                      is handed off to that thread which then calls function_object(arg1.get()).
                - #arg1.is_ready() == false
                - returns a task id that can be used by this->wait_for_task() to wait
                  for the submitted task to finish.
        !*/

        template <typename F, typename A1>
        uint64 add_task_by_value (
            const F& function_object,
            future<A1>& arg1
        );
        /*!
            requires
                - function_object(arg1.get()) is a valid expression
                  (i.e. The A1 type stored in the future must be a type that can be passed into the given function object)
            ensures
                - makes a copy of function_object, call it FCOPY.
                - if (is_task_thread() == true and there aren't any free threads available) then
                    - calls FCOPY(arg1.get()) within the calling thread and returns when it finishes
                - else
                    - the call to this function blocks until there is a free thread in the pool
                      to process this new task.  Once a free thread is available the task
                      is handed off to that thread which then calls FCOPY(arg1.get()).
                - #arg1.is_ready() == false
                - returns a task id that can be used by this->wait_for_task() to wait
                  for the submitted task to finish.
        !*/

        template <typename T, typename T1, typename A1>
        uint64 add_task (
            T& obj,
            void (T::*funct)(T1),
            future<A1>& arg1
        );
        /*!
            requires
                - funct == a valid member function pointer for class T
                - (obj.*funct)(arg1.get()) must be a valid expression.
                  (i.e. The A1 type stored in the future must be a type that can be passed into the given function)
                - obj will not go out of scope until after the task has completed (i.e.
                  this function passes obj to the task by reference.  If you want to avoid
                  this restriction then use add_task_by_value())
            ensures
                - if (is_task_thread() == true and there aren't any free threads available) then
                    - calls (obj.*funct)(arg1.get()) within the calling thread and returns
                      when it finishes
                - else
                    - the call to this function blocks until there is a free thread in the pool
                      to process this new task.  Once a free thread is available the task
                      is handed off to that thread which then calls (obj.*funct)(arg1.get()).
                - #arg1.is_ready() == false
                - returns a task id that can be used by this->wait_for_task() to wait
                  for the submitted task to finish.
        !*/

        template <typename T, typename T1, typename A1>
        uint64 add_task_by_value (
            const T& obj,
            void (T::*funct)(T1),
            future<A1>& arg1
        );
        /*!
            requires
                - funct == a valid member function pointer for class T
                - (obj.*funct)(arg1.get()) must be a valid expression.
                  (i.e. The A1 type stored in the future must be a type that can be passed into the given function)
            ensures
                - makes a copy of obj, call it OBJ_COPY.
                - if (is_task_thread() == true and there aren't any free threads available) then
                    - calls (OBJ_COPY.*funct)(arg1.get()) within the calling thread and returns
                      when it finishes.
                - else
                    - the call to this function blocks until there is a free thread in the pool
                      to process this new task.  Once a free thread is available the task
                      is handed off to that thread which then calls (OBJ_COPY.*funct)(arg1.get()).
                - returns a task id that can be used by this->wait_for_task() to wait
                  for the submitted task to finish.
        !*/

        template <typename T, typename T1, typename A1>
        uint64 add_task (
            const T& obj,
            void (T::*funct)(T1) const,
            future<A1>& arg1
        );
        /*!
            requires
                - funct == a valid member function pointer for class T
                - (obj.*funct)(arg1.get()) must be a valid expression.
                  (i.e. The A1 type stored in the future must be a type that can be passed into the given function)
                - obj will not go out of scope until after the task has completed (i.e.
                  this function passes obj to the task by reference.  If you want to avoid
                  this restriction then use add_task_by_value())
            ensures
                - if (is_task_thread() == true and there aren't any free threads available) then
                    - calls (obj.*funct)(arg1.get()) within the calling thread and returns
                      when it finishes
                - else
                    - the call to this function blocks until there is a free thread in the pool
                      to process this new task.  Once a free thread is available the task
                      is handed off to that thread which then calls (obj.*funct)(arg1.get()).
                - #arg1.is_ready() == false
                - returns a task id that can be used by this->wait_for_task() to wait
                  for the submitted task to finish.
        !*/

        template <typename T, typename T1, typename A1>
        uint64 add_task_by_value (
            const T& obj,
            void (T::*funct)(T1) const,
            future<A1>& arg1
        );
        /*!
            requires
                - funct == a valid member function pointer for class T
                - (obj.*funct)(arg1.get()) must be a valid expression.
                  (i.e. The A1 type stored in the future must be a type that can be passed into the given function)
            ensures
                - makes a copy of obj, call it OBJ_COPY.
                - if (is_task_thread() == true and there aren't any free threads available) then
                    - calls (OBJ_COPY.*funct)(arg1.get()) within the calling thread and returns
                      when it finishes.
                - else
                    - the call to this function blocks until there is a free thread in the pool
                      to process this new task.  Once a free thread is available the task
                      is handed off to that thread which then calls (OBJ_COPY.*funct)(arg1.get()).
                - returns a task id that can be used by this->wait_for_task() to wait
                  for the submitted task to finish.
        !*/

        template <typename T1, typename A1>
        uint64 add_task (
            void (*funct)(T1),
            future<A1>& arg1
        );
        /*!
            requires
                - funct == a valid function pointer
                - (funct)(arg1.get()) must be a valid expression.
                  (i.e. The A1 type stored in the future must be a type that can be passed into the given function)
            ensures
                - if (is_task_thread() == true and there aren't any free threads available) then
                    - calls funct(arg1.get()) within the calling thread and returns
                      when it finishes
                - else
                    - the call to this function blocks until there is a free thread in the pool
                      to process this new task.  Once a free thread is available the task
                      is handed off to that thread which then calls funct(arg1.get()).
                - #arg1.is_ready() == false
                - returns a task id that can be used by this->wait_for_task() to wait
                  for the submitted task to finish.
        !*/

        // --------------------------------------------------------------------------------
        // The remainder of this class just contains overloads for add_task() and add_task_by_value()
        // that take up to 4 futures (as well as 0 futures).  Their behavior is identical to the above
        // add_task() and add_task_by_value() functions.
        // --------------------------------------------------------------------------------

        template <typename F, typename A1, typename A2>
        uint64 add_task (
            F& function_object,
            future<A1>& arg1,
            future<A2>& arg2
        );

        template <typename F, typename A1, typename A2>
        uint64 add_task_by_value (
            const F& function_object,
            future<A1>& arg1,
            future<A2>& arg2
        );

        template <typename T, typename T1, typename A1,
                              typename T2, typename A2>
        uint64 add_task (
            T& obj,
            void (T::*funct)(T1,T2),
            future<A1>& arg1,
            future<A2>& arg2
        );

        uint64 add_task_by_value (
            const T& obj,
            void (T::*funct)(T1,T2),
            future<A1>& arg1,
            future<A2>& arg2
        );

        template <typename T, typename T1, typename A1,
                              typename T2, typename A2>
        uint64 add_task (
            const T& obj,
            void (T::*funct)(T1,T2) const,
            future<A1>& arg1,
            future<A2>& arg2
        );

        template <typename T, typename T1, typename A1,
                              typename T2, typename A2>
        uint64 add_task_by_value (
            const T& obj,
            void (T::*funct)(T1,T2) const,
            future<A1>& arg1,
            future<A2>& arg2
        );

        template <typename T1, typename A1,
                  typename T2, typename A2>
        uint64 add_task (
            void (*funct)(T1,T2),
            future<A1>& arg1,
            future<A2>& arg2
        );

        // --------------------

        template <typename F, typename A1, typename A2, typename A3>
        uint64 add_task (
            F& function_object,
            future<A1>& arg1,
            future<A2>& arg2,
            future<A3>& arg3
        );

        template <typename F, typename A1, typename A2, typename A3>
        uint64 add_task_by_value (
            const F& function_object,
            future<A1>& arg1,
            future<A2>& arg2,
            future<A3>& arg3
        );

        template <typename T, typename T1, typename A1,
                              typename T2, typename A2,
                              typename T3, typename A3>
        uint64 add_task (
            T& obj,
            void (T::*funct)(T1,T2,T3),
            future<A1>& arg1,
            future<A2>& arg2,
            future<A3>& arg3
        );

        template <typename T, typename T1, typename A1,
                              typename T2, typename A2,
                              typename T3, typename A3>
        uint64 add_task_by_value (
            const T& obj,
            void (T::*funct)(T1,T2,T3),
            future<A1>& arg1,
            future<A2>& arg2,
            future<A3>& arg3
        );

        template <typename T, typename T1, typename A1,
                              typename T2, typename A2,
                              typename T3, typename A3>
        uint64 add_task (
            const T& obj,
            void (T::*funct)(T1,T2,T3) const,
            future<A1>& arg1,
            future<A2>& arg2,
            future<A3>& arg3
        );

        template <typename T, typename T1, typename A1,
                              typename T2, typename A2,
                              typename T3, typename A3>
        uint64 add_task_by_value (
            const T& obj,
            void (T::*funct)(T1,T2,T3) const,
            future<A1>& arg1,
            future<A2>& arg2,
            future<A3>& arg3
        );

        template <typename T1, typename A1,
                  typename T2, typename A2,
                  typename T3, typename A3>
        uint64 add_task (
            void (*funct)(T1,T2,T3),
            future<A1>& arg1,
            future<A2>& arg2,
            future<A3>& arg3
        );

        // --------------------

        template <typename F, typename A1, typename A2, typename A3, typename A4>
        uint64 add_task (
            F& function_object,
            future<A1>& arg1,
            future<A2>& arg2,
            future<A3>& arg3,
            future<A4>& arg4
        );

        template <typename F, typename A1, typename A2, typename A3, typename A4>
        uint64 add_task_by_value (
            const F& function_object,
            future<A1>& arg1,
            future<A2>& arg2,
            future<A3>& arg3,
            future<A4>& arg4
        );

        template <typename T, typename T1, typename A1,
                              typename T2, typename A2,
                              typename T3, typename A3,
                              typename T4, typename A4>
        uint64 add_task (
            T& obj,
            void (T::*funct)(T1,T2,T3,T4),
            future<A1>& arg1,
            future<A2>& arg2,
            future<A3>& arg3,
            future<A4>& arg4
        );

        template <typename T, typename T1, typename A1,
                              typename T2, typename A2,
                              typename T3, typename A3,
                              typename T4, typename A4>
        uint64 add_task_by_value (
            const T& obj,
            void (T::*funct)(T1,T2,T3,T4),
            future<A1>& arg1,
            future<A2>& arg2,
            future<A3>& arg3,
            future<A4>& arg4
        );

        template <typename T, typename T1, typename A1,
                              typename T2, typename A2,
                              typename T3, typename A3,
                              typename T4, typename A4>
        uint64 add_task (
            const T& obj,
            void (T::*funct)(T1,T2,T3,T4) const,
            future<A1>& arg1,
            future<A2>& arg2,
            future<A3>& arg3,
            future<A4>& arg4
        );

        template <typename T, typename T1, typename A1,
                              typename T2, typename A2,
                              typename T3, typename A3,
                              typename T4, typename A4>
        uint64 add_task_by_value (
            const T& obj,
            void (T::*funct)(T1,T2,T3,T4) const,
            future<A1>& arg1,
            future<A2>& arg2,
            future<A3>& arg3,
            future<A4>& arg4
        );

        template <typename T1, typename A1,
                  typename T2, typename A2,
                  typename T3, typename A3,
                  typename T4, typename A4>
        uint64 add_task (
            void (*funct)(T1,T2,T3,T4),
            future<A1>& arg1,
            future<A2>& arg2,
            future<A3>& arg3,
            future<A4>& arg4
        );

        // --------------------

        template <typename F>
        uint64 add_task (
            F& function_object
        );

        template <typename T>
        uint64 add_task (
            const T& obj,
            void (T::*funct)() const,
        );

        template <typename T>
        uint64 add_task_by_value (
            const T& obj,
            void (T::*funct)() const
        );

        uint64 add_task (
            void (*funct)()
        );

        // --------------------

    private:

        // restricted functions
        thread_pool(thread_pool&);        // copy constructor
        thread_pool& operator=(thread_pool&);    // assignment operator
    };

}

// ----------------------------------------------------------------------------------------

#endif // DLIB_THREAD_POOl_ABSTRACT_Hh_


dlib C++ Library - Bayesian Networks

The Library
  • Algorithms
  • API Wrappers
  • Bayesian Nets
  • Compression
  • Containers
  • Graph Tools
  • Image Processing
  • Linear Algebra
  • Machine Learning
  • Metaprogramming
  • Miscellaneous
  • Networking
  • Optimization
  • Parsing

Help/Info
  • Dlib Blog
  • Examples: C++
    • 3D Point Cloud
    • Assignment Learning
    • Base64 Encoder
    • Bayesian Network From Disk
    • Bayesian Network GUI
    • Bayesian Network
    • Bridge
    • BSP
    • C-Support Vector Machine
    • Cmd Line Parser
    • Compress Stream
    • Config File Reader
    • Custom Trainers
    • Directory Navigation
    • Empirical Kernel Map
    • Face Detection
    • Face Landmark Detection
    • FHOG Feature Extraction
    • FHOG Object Detection
    • Graph Labeling
    • GUI
    • Hough Transform
    • HTTP Server
    • Image
    • IO Socket Streams
    • IO Streams Server
    • Kernel Centroid
    • Kernel K-Means Clustering
    • Kernel Ridge Regression
    • Kernel RLS Filtering
    • Kernel RLS Regression
    • KRR Classification
    • Learning to Track
    • Linear Assignment Problems
    • Linear Manifold Regularizer
    • Linear Model Predictive Control
    • Logger Advanced
    • Logger Custom Output
    • Logger
    • Matrix Expressions
    • Matrix
    • Member Function Pointer
    • Model Selection
    • Multiclass Classification
    • Multithreaded Object
    • Neural Network
    • Non-Linear Least Squares
    • Nu-Support Vector Machine
    • Numerical Integration
    • Object Detector Advanced
    • Object Detector
    • One Class Classifiers
    • Online SVM
    • Optimization
    • Parallel For Loops
    • Pipe 2
    • Pipe
    • Quantum Computing
    • Queue
    • Rank Features
    • Relevance Vector Classification
    • Relevance Vector Regression
    • Running Stats
    • Sequence Labeling
    • Sequence Segmentation
    • Sockets
    • Sockstreambuf
    • Sparse Vectors
    • SQLite
    • Std C++ Allocator
    • Structural Support Vector Machines
    • Support Vector Regression
    • SURF
    • SVM-Rank
    • Thread Function
    • Thread Pool
    • Threaded Object
    • Threads
    • Timer
    • Train Object Detector
    • Train Shape Predictor
    • Using Custom Kernels
    • Video Object Tracking
    • Webcam Face Pose Estimation
    • XML Parser
  • Examples: Python
    • Face Detector
    • Face Landmark Detection
    • find candidate object locations
    • Linear Assignment Problems
    • Sequence Segmenter
    • Structural Support Vector Machines
    • SVM-Rank
    • Train Object Detector
    • Train Shape Predictor
    • Video Object Tracking
  • FAQ
  • Forums
  • Home
  • How to compile
  • How to contribute
  • Index
  • Introduction
  • License
  • Python API
  • Suggested Books
  • Who uses dlib?

Current Release
  • Change Log
  • Release Notes
  • Version: 18.18

Last Modified:
Sep 13, 2015
Bayesian Networks

This page documents all the tools within the dlib library that relate to the construction and evaluation of Bayesian networks. If you want a quick introduction to the tools then you should consult the Bayesian Net example program.

The library also comes with a graphical application to assist in the creation of bayesian networks. This application is one of the example programs, so to use it you have to compile it yourself.

Tools
  • assignment
  • bayesian_network_gibbs_sampler
  • bayesian_network_join_tree
  • bayes_node
  • conditional_probability_table
  • joint_probability_table

Node Utilities
  • node_cpt_filled_out
  • node_first_parent_assignment
  • node_is_evidence
  • node_next_parent_assignment
  • node_num_values
  • node_probability
  • node_value
  • set_node_as_evidence
  • set_node_as_nonevidence
  • set_node_num_values
  • set_node_probability
  • set_node_value

[top]

assignment

This object models an assignment of random variables to particular values. It is used with the joint_probability_table and conditional_probability_table objects to represent assignments of various random variables to actual values.

C++ Example Programs: bayes_net_ex.cpp, bayes_net_gui_ex.cpp
More Details...
#include <dlib/bayes_utils.h>
[top]

bayesian_network_gibbs_sampler

This object performs Markov Chain Monte Carlo sampling of a bayesian network using the Gibbs sampling technique.

C++ Example Programs: bayes_net_ex.cpp
More Details...
#include <dlib/bayes_utils.h>
[top]

bayesian_network_join_tree

This object represents an implementation of the join tree algorithm (a.k.a. the junction tree algorithm) for inference in bayesian networks.

C++ Example Programs: bayes_net_ex.cpp, bayes_net_gui_ex.cpp, bayes_net_from_disk_ex.cpp
More Details...
#include <dlib/bayes_utils.h>
[top]

bayes_node

This object represents a node in a bayesian network. It is intended to be used inside the directed_graph object to represent bayesian networks.

C++ Example Programs: bayes_net_ex.cpp, bayes_net_gui_ex.cpp
More Details...
#include <dlib/bayes_utils.h>
[top]

conditional_probability_table

This object represents a conditional probability table.
More Details...
#include <dlib/bayes_utils.h>
[top]

joint_probability_table

This object represents a joint probability table.
More Details...
#include <dlib/bayes_utils.h>
[top]

node_cpt_filled_out

This is a function declared in the dlib::bayes_node_utils namespace. It is a convenience function that allows you to easily verify that a node in a bayesian network has its conditional_probability_table completely filled out.

C++ Example Programs: bayes_net_gui_ex.cpp
More Details...
#include <dlib/bayes_utils.h>
[top]

node_first_parent_assignment

This is a function declared in the dlib::bayes_node_utils namespace. It is a convenience function that allows you to easily obtain an assignment that contains all the parents of a node in a bayesian network.

C++ Example Programs: bayes_net_gui_ex.cpp
More Details...
#include <dlib/bayes_utils.h>
[top]

node_is_evidence

This is a function declared in the dlib::bayes_node_utils namespace. It is a convenience function that allows you to easily determine if a bayes_node is evidence when it is inside a directed_graph object.
More Details...
#include <dlib/bayes_utils.h>
[top]

node_next_parent_assignment

This is a function declared in the dlib::bayes_node_utils namespace. It is a convenience function that allows you to easily loop through all the parent assignments of a node in a bayesian network.

C++ Example Programs: bayes_net_gui_ex.cpp
More Details...
#include <dlib/bayes_utils.h>
[top]

node_num_values

This is a function declared in the dlib::bayes_node_utils namespace. It is a convenience function that allows you to easily obtain the number of values of a bayes_node when it is inside a directed_graph object.
More Details...
#include <dlib/bayes_utils.h>
[top]

node_probability

This is a function declared in the dlib::bayes_node_utils namespace. It is a convenience function that allows you to easily obtain the probability of a bayes_node given its parents when it is inside a directed_graph object.
More Details...
#include <dlib/bayes_utils.h>
[top]

node_value

This is a function declared in the dlib::bayes_node_utils namespace. It is a convenience function that allows you to easily obtain the value of a bayes_node when it is inside a directed_graph object.
More Details...
#include <dlib/bayes_utils.h>
[top]

set_node_as_evidence

This is a function declared in the dlib::bayes_node_utils namespace. It is a convenience function that allows you to easily set the evidence flag of a bayes_node when it is inside a directed_graph object.

C++ Example Programs: bayes_net_ex.cpp
More Details...
#include <dlib/bayes_utils.h>
[top]

set_node_as_nonevidence

This is a function declared in the dlib::bayes_node_utils namespace. It is a convenience function that allows you to easily remove the evidence flag of a bayes_node when it is inside a directed_graph object.

C++ Example Programs: bayes_net_ex.cpp
More Details...
#include <dlib/bayes_utils.h>
[top]

set_node_num_values

This is a function declared in the dlib::bayes_node_utils namespace. It is a convenience function that allows you to easily set the number of values of a bayes_node when it is inside a directed_graph object.

C++ Example Programs: bayes_net_ex.cpp
More Details...
#include <dlib/bayes_utils.h>
[top]

set_node_probability

This is a function declared in the dlib::bayes_node_utils namespace. It is a convenience function that allows you to easily set the probability of a bayes_node given its parents when it is inside a directed_graph object.

C++ Example Programs: bayes_net_ex.cpp
More Details...
#include <dlib/bayes_utils.h>
[top]

set_node_value

This is a function declared in the dlib::bayes_node_utils namespace. It is a convenience function that allows you to easily modify the value of a bayes_node when it is inside a directed_graph object.

C++ Example Programs: bayes_net_ex.cpp
More Details...
#include <dlib/bayes_utils.h>


dlib C++ Library - bayes_utils_abstract.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_BAYES_UTILs_ABSTRACT_
#ifdef DLIB_BAYES_UTILs_ABSTRACT_

#include "../algs.h"
#include "../noncopyable.h"
#include "../interfaces/enumerable.h"
#include "../interfaces/map_pair.h"
#include "../serialize.h"
#include <iostream>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class assignment : public enumerable<map_pair<unsigned long, unsigned long> >
    {
        /*!
            INITIAL VALUE
                - size() == 0

            ENUMERATION ORDER
                The enumerator will iterate over the entries in the assignment in
                ascending order according to index values.  (i.e. the elements are
                enumerated in sorted order according to the value of their keys)

            WHAT THIS OBJECT REPRESENTS
                This object models an assignment of random variables to particular values.
                It is used with the joint_probability_table and conditional_probability_table
                objects to represent assignments of various random variables to actual values.

                So for example, if you had a joint_probability_table that represented the
                following table:
                    P(A = 0, B = 0) = 0.2
                    P(A = 0, B = 1) = 0.3
                    P(A = 1, B = 0) = 0.1
                    P(A = 1, B = 1) = 0.4

                    Also lets define an enum so we have concrete index numbers for A and B
                    enum { A = 0, B = 1};

                Then you could query the value of P(A=1, B=0) as follows:
                    assignment a;
                    a.set(A, 1);
                    a.set(B, 0);
                    // and now it is the case that:
                    table.probability(a) == 0.1
                    a[A] == 1
                    a[B] == 0

                Also note that when enumerating the elements of an assignment object
                the key() refers to the index and the value() refers to the value at that
                index. For example:

                // assume a is an assignment object
                a.reset();
                while (a.move_next())
                {
                    // in this loop it is always the case that:
                    // a[a.element().key()] == a.element().value()
                }
        !*/

    public:

        assignment(
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        assignment(
            const assignment& a
        );
        /*!
            ensures
                - #*this is a copy of a
        !*/

        assignment& operator = (
            const assignment& rhs
        );
        /*!
            ensures
                - #*this is a copy of rhs
                - returns *this
        !*/

        void clear(
        );
        /*!
            ensures
                - this object has been returned to its initial value
        !*/

        bool operator < (
            const assignment& item
        ) const;
        /*!
            ensures
                - The exact functioning of this operator is undefined.  The only guarantee
                  is that it establishes a total ordering on all possible assignment objects.
                  In other words, this operator makes it so that you can use assignment
                  objects in the associative containers but otherwise isn't of any
                  particular use.
        !*/

        bool has_index (
            unsigned long idx
        ) const;
        /*!
            ensures
                - if (this assignment object has an entry for index idx) then
                    - returns true
                - else
                    - returns false
        !*/

        void add (
            unsigned long idx,
            unsigned long value = 0
        );
        /*!
            requires
                - has_index(idx) == false
            ensures
                - #has_index(idx) == true
                - #(*this)[idx] == value
        !*/

        void remove (
            unsigned long idx
        );
        /*!
            requires
                - has_index(idx) == true
            ensures
                - #has_index(idx) == false
        !*/

        unsigned long& operator[] (
            const long idx
        );
        /*!
            requires
                - has_index(idx) == true
            ensures
                - returns a reference to the value associated with index idx
        !*/

        const unsigned long& operator[] (
            const long idx
        ) const;
        /*!
            requires
                - has_index(idx) == true
            ensures
                - returns a const reference to the value associated with index idx
        !*/

        void swap (
            assignment& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/

    };

    inline void swap (
        assignment& a,
        assignment& b
    ) { a.swap(b); }
    /*!
        provides a global swap
    !*/

    std::ostream& operator << (
        std::ostream& out,
        const assignment& a
    );
    /*!
        ensures
            - writes a to the given output stream in the following format:
              (index1:value1, index2:value2, ..., indexN:valueN)
    !*/

    void serialize (
        const assignment& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

    void deserialize (
        assignment& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// ------------------------------------------------------------------------

    class joint_probability_table : public enumerable<map_pair<assignment, double> >
    {
        /*!
            INITIAL VALUE
                - size() == 0

            ENUMERATION ORDER
                The enumerator will iterate over the entries in the probability table
                in no particular order but they will all be visited.

            WHAT THIS OBJECT REPRESENTS
                This object models a joint probability table.  That is, it models
                the function p(X).  So this object models the probability of a particular
                set of variables (referred to as X).
        !*/

    public:

        joint_probability_table(
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        joint_probability_table (
            const joint_probability_table& t
        );
        /*!
            ensures
                - this object is a copy of t
        !*/

        void clear(
        );
        /*!
            ensures
                - this object has its initial value
        !*/

        joint_probability_table& operator= (
            const joint_probability_table& rhs
        );
        /*!
            ensures
                - this object is a copy of rhs
                - returns a reference to *this
        !*/

        bool has_entry_for (
            const assignment& a
        ) const;
        /*!
            ensures
                - if (this joint_probability_table has an entry for p(X = a)) then
                    - returns true
                - else
                    - returns false
        !*/

        void set_probability (
            const assignment& a,
            double p
        );
        /*!
            requires
                - 0 <= p <= 1
            ensures
                - if (has_entry_for(a) == false) then
                    - #size() == size() + 1
                - #probability(a) == p
                - #has_entry_for(a) == true
        !*/

        void add_probability (
            const assignment& a,
            double p
        );
        /*!
            requires
                - 0 <= p <= 1
            ensures
                - if (has_entry_for(a) == false) then
                    - #size() == size() + 1
                    - #probability(a) == p
                - else
                    - #probability(a) == min(probability(a) + p, 1.0)
                      (i.e. does a saturating add)
                - #has_entry_for(a) == true
        !*/

        const double probability (
            const assignment& a
        ) const;
        /*!
            ensures
                - returns the probability p(X == a)
        !*/

        template <
            typename T
            >
        void marginalize (
            const T& vars,
            joint_probability_table& output_table
        ) const;
        /*!
            requires
                - T is an implementation of set/set_kernel_abstract.h
            ensures
                - marginalizes *this by summing over all variables not in vars.  The
                  result is stored in output_table.
        !*/

        void marginalize (
            const unsigned long var,
            joint_probability_table& output_table
        ) const;
        /*!
            ensures
                - is identical to calling the above marginalize() function with a set
                  that contains only var.  Or in other words, performs a marginalization
                  with just one variable var.  So that output_table will contain a table giving
                  the marginal probability of var all by itself.
        !*/

        void normalize (
        );
        /*!
            ensures
                - let sum == the sum of all the probabilities in this table
                - after normalize() has finished it will be the case that the sum of all
                  the entries in this table is 1.0.  This is accomplished by dividing all
                  the entries by the sum described above.
        !*/

        void swap (
            joint_probability_table& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/

    };

    inline void swap (
        joint_probability_table& a,
        joint_probability_table& b
    ) { a.swap(b); }
    /*!
        provides a global swap
    !*/

    void serialize (
        const joint_probability_table& item,
        std::ostream& out
    );
    /*!
        provides deserialization support
    !*/

    void deserialize (
        joint_probability_table& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// ----------------------------------------------------------------------------------------

    class conditional_probability_table : noncopyable
    {
        /*!
            INITIAL VALUE
                - num_values() == 0
                - has_value_for(x, y) == false for all values of x and y

            WHAT THIS OBJECT REPRESENTS
                This object models a conditional probability table.  That is, it models
                the function p( X | parents).  So this object models the conditional
                probability of a particular variable (referred to as X) given another set
                of variables (referred to as parents).
        !*/

    public:

        conditional_probability_table(
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        void clear(
        );
        /*!
            ensures
                - this object has its initial value
        !*/

        void empty_table (
        );
        /*!
            ensures
                - for all possible v and p:
                    - #has_entry_for(v,p) == false
                  (i.e. this function clears out the table when you call it but doesn't
                  change the value of num_values())
        !*/

        void set_num_values (
            unsigned long num
        );
        /*!
            ensures
                - #num_values() == num
                - for all possible v and p:
                    - #has_entry_for(v,p) == false
                  (i.e. this function clears out the table when you call it)
        !*/

        unsigned long num_values (
        ) const;
        /*!
            ensures
                - This object models the probability table p(X | parents).  This
                  function returns the number of values X can take on.
        !*/

        bool has_entry_for (
            unsigned long value,
            const assignment& ps
        ) const;
        /*!
            ensures
                - if (this conditional_probability_table has an entry for p(X = value, parents = ps)) then
                    - returns true
                - else
                    - returns false
        !*/

        void set_probability (
            unsigned long value,
            const assignment& ps,
            double p
        );
        /*!
            requires
                - value < num_values()
                - 0 <= p <= 1
            ensures
                - #probability(ps, value) == p
                - #has_entry_for(value, ps) == true
        !*/

        double probability(
            unsigned long value,
            const assignment& ps
        ) const;
        /*!
            requires
                - value < num_values()
                - has_entry_for(value, ps) == true
            ensures
                - returns the probability p( X = value | parents = ps).
        !*/

        void swap (
            conditional_probability_table& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/
    };

    inline void swap (
        conditional_probability_table& a,
        conditional_probability_table& b
    ) { a.swap(b); }
    /*!
        provides a global swap
    !*/

    void serialize (
        const conditional_probability_table& item,
        std::ostream& out
    );
    /*!
        provides deserialization support
    !*/

    void deserialize (
        conditional_probability_table& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// ------------------------------------------------------------------------
// ------------------------------------------------------------------------
// ------------------------------------------------------------------------

    class bayes_node : noncopyable
    {
        /*!
            INITIAL VALUE
                - is_evidence() == false
                - value() == 0
                - table().num_values() == 0

            WHAT THIS OBJECT REPRESENTS
                This object represents a node in a bayesian network.  It is
                intended to be used inside the dlib::directed_graph object to
                represent bayesian networks.
        !*/

    public:
        bayes_node (
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        unsigned long value (
        ) const;
        /*!
            ensures
                - returns the current value of this node
        !*/

        void set_value (
            unsigned long new_value
        );
        /*!
            requires
                - new_value < table().num_values()
            ensures
                - #value() == new_value
        !*/

        conditional_probability_table& table (
        );
        /*!
            ensures
                - returns a reference to the conditional_probability_table associated with this node
        !*/

        const conditional_probability_table& table (
        ) const;
        /*!
            ensures
                - returns a const reference to the conditional_probability_table associated with this
                  node.
        !*/

        bool is_evidence (
        ) const;
        /*!
            ensures
                - if (this is an evidence node) then
                    - returns true
                - else
                    - returns false
        !*/

        void set_as_nonevidence (
        );
        /*!
            ensures
                - #is_evidence() == false
        !*/

        void set_as_evidence (
        );
        /*!
            ensures
                - #is_evidence() == true
        !*/

        void swap (
            bayes_node& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/

    };

    inline void swap (
        bayes_node& a,
        bayes_node& b
    ) { a.swap(b); }
    /*!
        provides a global swap
    !*/

    void serialize (
        const bayes_node& item,
        std::ostream& out
    );
    /*!
        provides deserialization support
    !*/

    void deserialize (
        bayes_node& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    /*
        The following group of functions are convenience functions for manipulating
        bayes_node objects while they are inside a directed_graph.   These functions
        also have additional requires clauses that, in debug mode, will protect you
        from attempts to manipulate a bayesian network in an inappropriate way.
    */

    namespace bayes_node_utils
    {

        template <
            typename T
            >
        void set_node_value (
            T& bn,
            unsigned long n,
            unsigned long val
        );
        /*!
            requires
                - T is an implementation of directed_graph/directed_graph_kernel_abstract.h
                - T::type == bayes_node
                - n < bn.number_of_nodes()
                - val < node_num_values(bn, n)
            ensures
                - #bn.node(n).data.value() = val
        !*/

    // ------------------------------------------------------------------------------------

        template <
            typename T
            >
        unsigned long node_value (
            const T& bn,
            unsigned long n
        );
        /*!
            requires
                - T is an implementation of directed_graph/directed_graph_kernel_abstract.h
                - T::type == bayes_node
                - n < bn.number_of_nodes()
            ensures
                - returns bn.node(n).data.value()
        !*/

    // ------------------------------------------------------------------------------------

        template <
            typename T
            >
        bool node_is_evidence (
            const T& bn,
            unsigned long n
        );
        /*!
            requires
                - T is an implementation of directed_graph/directed_graph_kernel_abstract.h
                - T::type == bayes_node
                - n < bn.number_of_nodes()
            ensures
                - returns bn.node(n).data.is_evidence()
        !*/

    // ------------------------------------------------------------------------------------

        template <
            typename T
            >
        void set_node_as_evidence (
            T& bn,
            unsigned long n
        );
        /*!
            requires
                - T is an implementation of directed_graph/directed_graph_kernel_abstract.h
                - T::type == bayes_node
                - n < bn.number_of_nodes()
            ensures
                - executes: bn.node(n).data.set_as_evidence()
        !*/

    // ------------------------------------------------------------------------------------

        template <
            typename T
            >
        void set_node_as_nonevidence (
            T& bn,
            unsigned long n
        );
        /*!
            requires
                - T is an implementation of directed_graph/directed_graph_kernel_abstract.h
                - T::type == bayes_node
                - n < bn.number_of_nodes()
            ensures
                - executes: bn.node(n).data.set_as_nonevidence()
        !*/

    // ------------------------------------------------------------------------------------

        template <
            typename T
            >
        void set_node_num_values (
            T& bn,
            unsigned long n,
            unsigned long num
        );
        /*!
            requires
                - T is an implementation of directed_graph/directed_graph_kernel_abstract.h
                - T::type == bayes_node
                - n < bn.number_of_nodes()
            ensures
                - #bn.node(n).data.table().num_values() == num
                  (i.e. sets the number of different values this node can take)
        !*/

    // ------------------------------------------------------------------------------------

        template <
            typename T
            >
        unsigned long node_num_values (
            const T& bn,
            unsigned long n
        );
        /*!
            requires
                - T is an implementation of directed_graph/directed_graph_kernel_abstract.h
                - T::type == bayes_node
                - n < bn.number_of_nodes()
            ensures
                - returns bn.node(n).data.table().num_values()
                  (i.e. returns the number of different values this node can take)
        !*/

    // ------------------------------------------------------------------------------------

        template <
            typename T
            >
        const double node_probability (
            const T& bn,
            unsigned long n,
            unsigned long value,
            const assignment& parents
        );
        /*!
            requires
                - T is an implementation of directed_graph/directed_graph_kernel_abstract.h
                - T::type == bayes_node
                - n < bn.number_of_nodes()
                - value < node_num_values(bn,n)
                - parents.size() == bn.node(n).number_of_parents()
                - if (parents.has_index(x)) then
                    - bn.has_edge(x, n)
                    - parents[x] < node_num_values(bn,x)
            ensures
                - returns bn.node(n).data.table().probability(value, parents)
                  (i.e. returns the probability of node n having the given value when
                  its parents have the given assignment)
        !*/

    // ------------------------------------------------------------------------------------

        template <
            typename T
            >
        const double set_node_probability (
            const T& bn,
            unsigned long n,
            unsigned long value,
            const assignment& parents,
            double p
        );
        /*!
            requires
                - T is an implementation of directed_graph/directed_graph_kernel_abstract.h
                - T::type == bayes_node
                - n < bn.number_of_nodes()
                - value < node_num_values(bn,n)
                - 0 <= p <= 1
                - parents.size() == bn.node(n).number_of_parents()
                - if (parents.has_index(x)) then
                    - bn.has_edge(x, n)
                    - parents[x] < node_num_values(bn,x)
            ensures
                - #bn.node(n).data.table().probability(value, parents) == p
                  (i.e. sets the probability of node n having the given value when
                  its parents have the given assignment to the probability p)
        !*/

    // ------------------------------------------------------------------------------------

        template <typename T>
        const assignment node_first_parent_assignment (
            const T& bn,
            unsigned long n
        );
        /*!
            requires
                - T is an implementation of directed_graph/directed_graph_kernel_abstract.h
                - T::type == bayes_node
                - n < bn.number_of_nodes()
            ensures
                - returns an assignment A such that:
                    - A.size() == bn.node(n).number_of_parents()
                    - if (P is a parent of bn.node(n)) then
                        - A.has_index(P)
                        - A[P] == 0
                    - I.e. this function returns an assignment that contains all
                      the parents of the given node.  Also, all the values of each
                      parent in the assignment is set to zero.
        !*/

    // ------------------------------------------------------------------------------------

        template <typename T>
        bool node_next_parent_assignment (
            const T& bn,
            unsigned long n,
            assignment& A
        );
        /*!
            requires
                - T is an implementation of directed_graph/directed_graph_kernel_abstract.h
                - T::type == bayes_node
                - n < bn.number_of_nodes()
                - A.size() == bn.node(n).number_of_parents()
                - if (A.has_index(x)) then
                    - bn.has_edge(x, n)
                    - A[x] < node_num_values(bn,x)
            ensures
                - The behavior of this function is defined by the following code:
                  assignment a(node_first_parent_assignment(bn,n);
                  do {
                    // this loop loops over all possible parent assignments
                    // of the node bn.node(n).  Each time through the loop variable a
                    // will be the next assignment.
                  } while (node_next_parent_assignment(bn,n,a))
        !*/

    // ------------------------------------------------------------------------------------

        template <typename T>
        bool node_cpt_filled_out (
            const T& bn,
            unsigned long n
        );
        /*!
            requires
                - T is an implementation of directed_graph/directed_graph_kernel_abstract.h
                - T::type == bayes_node
                - n < bn.number_of_nodes()
            ensures
                - if (the conditional_probability_table bn.node(n).data.table() is
                  fully filled out for this node) then
                    - returns true
                    - This means that each parent assignment for the given node
                      along with all possible values of this node shows up in the
                      table.
                    - It also means that all the probabilities conditioned on the
                      same parent assignment sum to 1.0
                - else
                    - returns false
        !*/

    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class bayesian_network_gibbs_sampler : noncopyable
    {
        /*!
            INITIAL VALUE
                This object has no state

            WHAT THIS OBJECT REPRESENTS
                This object performs Markov Chain Monte Carlo sampling of a bayesian
                network using the Gibbs sampling technique.

                Note that this object is limited to only bayesian networks that
                don't contain deterministic nodes.  That is, incorrect results may
                be computed if this object is used when the bayesian network contains
                any nodes that have a probability of 1 in their conditional probability
                tables for any event.  So don't use this object for networks with
                deterministic nodes.
        !*/
    public:

        bayesian_network_gibbs_sampler (
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        template <
            typename T
            >
        void sample_graph (
            T& bn
        )
        /*!
            requires
                - T is an implementation of directed_graph/directed_graph_kernel_abstract.h
                - T::type == bayes_node
            ensures
                - modifies randomly (via the Gibbs sampling technique) samples all the nodes
                  in the network and updates their values with the newly sampled values
        !*/
    };

// ----------------------------------------------------------------------------------------

    class bayesian_network_join_tree : noncopyable
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object represents an implementation of the join tree algorithm
                for inference in bayesian networks.  It doesn't have any mutable state.
                To you use you just give it a directed_graph that contains a bayesian
                network and a graph object that contains that networks corresponding
                join tree.  Then you may query this object to determine the probabilities
                of any variables in the original bayesian network.
        !*/

    public:

        template <
            typename bn_type,
            typename join_tree_type
            >
        bayesian_network_join_tree (
            const bn_type& bn,
            const join_tree_type& join_tree
        );
        /*!
            requires
                - bn_type is an implementation of directed_graph/directed_graph_kernel_abstract.h
                - bn_type::type == bayes_node
                - join_tree_type is an implementation of graph/graph_kernel_abstract.h
                - join_tree_type::type is an implementation of set/set_compare_abstract.h and
                  this set type contains unsigned long objects.
                - join_tree_type::edge_type is an implementation of set/set_compare_abstract.h and
                  this set type contains unsigned long objects.
                - is_join_tree(bn, join_tree) == true
                - bn == a valid bayesian network with all its conditional probability tables
                  filled out
                - for all valid n:
                    - node_cpt_filled_out(bn,n) == true
                - graph_contains_length_one_cycle(bn) == false
                - graph_is_connected(bn) == true
                - bn.number_of_nodes() > 0
            ensures
                - this object is properly initialized
        !*/

        unsigned long number_of_nodes (
        ) const;
        /*!
            ensures
                - returns the number of nodes in the bayesian network that this
                  object was instantiated from.
        !*/

        const matrix<double,1> probability(
            unsigned long idx
        ) const;
        /*!
            requires
                - idx < number_of_nodes()
            ensures
                - returns the probability distribution for the node with index idx that was in the bayesian
                  network that *this was instantiated from.  Let D represent this distribution, then:
                    - D.nc() == the number of values the node idx ranges over
                    - D.nr() == 1
                    - D(i) == the probability of node idx taking on the value i
        !*/

        void swap (
            bayesian_network_join_tree& item
        );
        /*!
            ensures
                - swaps *this with item
        !*/

    };

    inline void swap (
        bayesian_network_join_tree& a,
        bayesian_network_join_tree& b
    ) { a.swap(b); }
    /*!
        provides a global swap
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_BAYES_UTILs_ABSTRACT_


dlib C++ Library - Data Compression

The Library
  • Algorithms
  • API Wrappers
  • Bayesian Nets
  • Compression
  • Containers
  • Graph Tools
  • Image Processing
  • Linear Algebra
  • Machine Learning
  • Metaprogramming
  • Miscellaneous
  • Networking
  • Optimization
  • Parsing

Help/Info
  • Dlib Blog
  • Examples: C++
    • 3D Point Cloud
    • Assignment Learning
    • Base64 Encoder
    • Bayesian Network From Disk
    • Bayesian Network GUI
    • Bayesian Network
    • Bridge
    • BSP
    • C-Support Vector Machine
    • Cmd Line Parser
    • Compress Stream
    • Config File Reader
    • Custom Trainers
    • Directory Navigation
    • Empirical Kernel Map
    • Face Detection
    • Face Landmark Detection
    • FHOG Feature Extraction
    • FHOG Object Detection
    • Graph Labeling
    • GUI
    • Hough Transform
    • HTTP Server
    • Image
    • IO Socket Streams
    • IO Streams Server
    • Kernel Centroid
    • Kernel K-Means Clustering
    • Kernel Ridge Regression
    • Kernel RLS Filtering
    • Kernel RLS Regression
    • KRR Classification
    • Learning to Track
    • Linear Assignment Problems
    • Linear Manifold Regularizer
    • Linear Model Predictive Control
    • Logger Advanced
    • Logger Custom Output
    • Logger
    • Matrix Expressions
    • Matrix
    • Member Function Pointer
    • Model Selection
    • Multiclass Classification
    • Multithreaded Object
    • Neural Network
    • Non-Linear Least Squares
    • Nu-Support Vector Machine
    • Numerical Integration
    • Object Detector Advanced
    • Object Detector
    • One Class Classifiers
    • Online SVM
    • Optimization
    • Parallel For Loops
    • Pipe 2
    • Pipe
    • Quantum Computing
    • Queue
    • Rank Features
    • Relevance Vector Classification
    • Relevance Vector Regression
    • Running Stats
    • Sequence Labeling
    • Sequence Segmentation
    • Sockets
    • Sockstreambuf
    • Sparse Vectors
    • SQLite
    • Std C++ Allocator
    • Structural Support Vector Machines
    • Support Vector Regression
    • SURF
    • SVM-Rank
    • Thread Function
    • Thread Pool
    • Threaded Object
    • Threads
    • Timer
    • Train Object Detector
    • Train Shape Predictor
    • Using Custom Kernels
    • Video Object Tracking
    • Webcam Face Pose Estimation
    • XML Parser
  • Examples: Python
    • Face Detector
    • Face Landmark Detection
    • find candidate object locations
    • Linear Assignment Problems
    • Sequence Segmenter
    • Structural Support Vector Machines
    • SVM-Rank
    • Train Object Detector
    • Train Shape Predictor
    • Video Object Tracking
  • FAQ
  • Forums
  • Home
  • How to compile
  • How to contribute
  • Index
  • Introduction
  • License
  • Python API
  • Suggested Books
  • Who uses dlib?

Current Release
  • Change Log
  • Release Notes
  • Version: 18.18

Last Modified:
Sep 13, 2015
Data Compression

This page contains a bunch of objects that implement various parts of compression algorithms. They can be put together in different ways to construct many different algorithms. Note that the compress_stream object contains complete compression algorithms. So if you just want to compress some data then you can easily use that object and not bother with the others.

In the column to the right you can see benchmark data for each of the compress_stream typedefs. The times measured are the time it takes to compress and then decompress each file. It was run on a 3.0ghz P4. For reference see the Canterbury corpus web site.

Objects
  • compress_stream
  • conditioning_class
  • entropy_decoder
  • entropy_decoder_model
  • entropy_encoder
  • entropy_encoder_model
  • lz77_buffer
  • lzp_buffer

Benchmarks
  • kernel_1a
  • kernel_1b
  • kernel_1c
  • kernel_1da
  • kernel_1db
  • kernel_1ea
  • kernel_1eb
  • kernel_1ec
  • kernel_2a
  • kernel_3a
  • kernel_3b

[top]

compress_stream

This object is pretty straight forward. It has no state and just contains the functions compress and decompress. They do just what their names imply to iostream objects.

C++ Example Programs: compress_stream_ex.cpp, file_to_code_ex.cpp
More Details...
#include <dlib/compress_stream.h>

Implementations:
compress_stream_kernel_1:
This implementation is done using the entropy_encoder_model and entropy_decoder_model objects.
kernel_1a
is a typedef for compress_stream_kernel_1 which uses entropy_decoder_model_kernel_1b and entropy_decoder_model_kernel_1b
kernel_1b
is a typedef for compress_stream_kernel_1 which uses entropy_decoder_model_kernel_2b and entropy_decoder_model_kernel_2b
kernel_1c
is a typedef for compress_stream_kernel_1 which uses entropy_decoder_model_kernel_3b and entropy_decoder_model_kernel_3b
kernel_1da
is a typedef for compress_stream_kernel_1 which uses entropy_decoder_model_kernel_4a and entropy_decoder_model_kernel_4a
kernel_1db
is a typedef for compress_stream_kernel_1 which uses entropy_decoder_model_kernel_4b and entropy_decoder_model_kernel_4b
kernel_1ea
is a typedef for compress_stream_kernel_1 which uses entropy_decoder_model_kernel_5a and entropy_decoder_model_kernel_5a
kernel_1eb
is a typedef for compress_stream_kernel_1 which uses entropy_decoder_model_kernel_5b and entropy_decoder_model_kernel_5b
kernel_1ec
is a typedef for compress_stream_kernel_1 which uses entropy_decoder_model_kernel_5c and entropy_decoder_model_kernel_5c
compress_stream_kernel_2:
This implementation is done using the entropy_encoder_model and entropy_decoder_model objects. It also uses the lz77_buffer object. It uses the entropy coder models to encode symbols when there is no match found by the lz77_buffer.
kernel_2a
is a typedef for compress_stream_kernel_2 which uses entropy_encoder_model_kernel_2b, entropy_decoder_model_kernel_2b, and lz77_buffer_kernel_2a.
compress_stream_kernel_3:
This implementation is done using the lzp_buffer object and crc32 object. It does not use any sort of entropy coding, instead a byte aligned output method is used.
kernel_3a
is a typedef for compress_stream_kernel_3 which uses lzp_buffer_kernel_1.
kernel_3b
is a typedef for compress_stream_kernel_3 which uses lzp_buffer_kernel_2.
[top]

conditioning_class

This object represents a conditioning class used for arithmetic style compression. It maintains the cumulative counts which are needed by the entropy_encoder and entropy_decoder objects below.
More Details...
#include <dlib/conditioning_class.h>

Implementations:
conditioning_class_kernel_1:
This implementation is done using an array to store all the counts and they are summed whenever the cumulative counts are requested. It's pretty straight forward.
kernel_1a
is a typedef for conditioning_class_kernel_1
kernel_1a_c
 is a typedef for kernel_1a that checks its preconditions.
conditioning_class_kernel_2:
This implementation is done using a binary tree where each node in the tree represents one symbol and contains that symbols count and the sum of all the counts for the nodes to the left. This way when you request a cumulative count it can be computed by visiting log n nodes where n is the size of the alphabet.
kernel_2a
is a typedef for conditioning_class_kernel_2
kernel_2a_c
 is a typedef for kernel_2a that checks its preconditions.
conditioning_class_kernel_3:
This implementation is done using an array to store all the counts and they are summed whenever the cumulative counts are requested. The counts are also kept in semi-sorted order to speed up the calculation of the cumulative count.
kernel_3a
is a typedef for conditioning_class_kernel_3
kernel_3a_c
 is a typedef for kernel_3a that checks its preconditions.
conditioning_class_kernel_4:
This implementation is done using a linked list to store all the counts and they are summed whenever the cumulative counts are requested. The counts are also kept in semi-sorted order to speed up the calculation of the cumulative count. This implementation also uses the memory_manager component to create a memory pool of linked list nodes. This implementation is especially useful for high order contexts and/or very large and sparse alphabets.
kernel_4a
is a typedef for conditioning_class_kernel_4 with a memory pool of 10,000 nodes.
kernel_4a_c
 is a typedef for kernel_4a that checks its preconditions.
kernel_4b
is a typedef for conditioning_class_kernel_4 with a memory pool of 100,000 nodes.
kernel_4b_c
 is a typedef for kernel_4b that checks its preconditions.
kernel_4c
is a typedef for conditioning_class_kernel_4 with a memory pool of 1,000,000 nodes.
kernel_4c_c
 is a typedef for kernel_4c that checks its preconditions.
kernel_4d
is a typedef for conditioning_class_kernel_4 with a memory pool of 10,000,000 nodes.
kernel_4d_c
 is a typedef for kernel_4d that checks its preconditions.
[top]

entropy_decoder

This object represents an entropy decoder. E.g. the decoding part of an arithmetic coder.
More Details...
#include <dlib/entropy_decoder.h>

Implementations:
entropy_decoder_kernel_1:
This object is implemented using arithmetic coding and is done in the straight forward way using integers and fixed precision math.
kernel_1a
is a typedef for entropy_decoder_kernel_1
kernel_1a_c
 is a typedef for kernel_1a that checks its preconditions.
entropy_decoder_kernel_2:
This object is implemented using "range" coding and is done in the straight forward way using integers and fixed precision math.
kernel_2a
is a typedef for entropy_decoder_kernel_2
kernel_2a_c
 is a typedef for kernel_2a that checks its preconditions.
[top]

entropy_decoder_model

This object represents some kind of statistical model. You can use it to read symbols from an entropy_decoder and it will calculate the cumulative counts/probabilities and manage contexts for you.
More Details...
#include <dlib/entropy_decoder_model.h>

Implementations:
entropy_decoder_model_kernel_1:
This object is implemented using the conditioning_class component. It implements an order-0 finite context model and uses lazy exclusions and update exclusions. The escape method used is method D.
kernel_1a
is a typedef for entropy_decoder_model_kernel_1 that uses conditioning_class_kernel_1a
kernel_1b
is a typedef for entropy_decoder_model_kernel_1 that uses conditioning_class_kernel_2a
kernel_1c
is a typedef for entropy_decoder_model_kernel_1 that uses conditioning_class_kernel_3a
entropy_decoder_model_kernel_2:
This object is implemented using the conditioning_class component. It implements an order-1-0 finite context model and uses lazy exclusions and update exclusions. The escape method used is method D.
kernel_2a
is a typedef for entropy_decoder_model_kernel_2 that uses conditioning_class_kernel_1a
kernel_2b
is a typedef for entropy_decoder_model_kernel_2 that uses conditioning_class_kernel_2a
kernel_2c
is a typedef for entropy_decoder_model_kernel_2 that uses conditioning_class_kernel_3a
kernel_2d
is a typedef for entropy_decoder_model_kernel_2 that uses conditioning_class_kernel_2a for its order-0 context and conditioning_class_kernel_4b for its order-1 context.
entropy_decoder_model_kernel_3:
This object is implemented using the conditioning_class component. It implements an order-2-1-0 finite context model and uses lazy exclusions and update exclusions. The escape method used is method D.
kernel_3a
 is a typedef for entropy_decoder_model_kernel_3 that uses conditioning_class_kernel_1a for orders 0 and 1 and conditioning_class_kernel_4b for order-2.
kernel_3b
 is a typedef for entropy_decoder_model_kernel_3 that uses conditioning_class_kernel_2a for orders 0 and 1 and conditioning_class_kernel_4b for order-2.
kernel_3c
 is a typedef for entropy_decoder_model_kernel_3 that uses conditioning_class_kernel_3a for orders 0 and 1 and conditioning_class_kernel_4b for order-2.
entropy_decoder_model_kernel_4:
This object is implemented using a variation of the PPM algorithm described by Alistair Moffat in his paper "Implementing the PPM data compression scheme." It provides template arguments to select the maximum order and maximum memory to use. For speed, exclusions are not used. The escape method used is method D.
kernel_4a
 is a typedef for entropy_decoder_model_kernel_4 with the max order set to 4 and the max number of nodes set to 200,000
kernel_4b
 is a typedef for entropy_decoder_model_kernel_4 with the max order set to 5 and the max number of nodes set to 1,000,000
entropy_decoder_model_kernel_5:
This object is implemented using a variation of the PPM algorithm described by Alistair Moffat in his paper "Implementing the PPM data compression scheme." It provides template arguments to select the maximum order and maximum memory to use. Exclusions are used. The escape method used is method D. This implementation is very much like kernel_4 except it is tuned for higher compression rather than speed. This also uses Dmitry Shkarin's Information Inheritance scheme.
kernel_5a
 is a typedef for entropy_decoder_model_kernel_5 with the max order set to 4 and the max number of nodes set to 200,000
kernel_5b
 is a typedef for entropy_decoder_model_kernel_5 with the max order set to 5 and the max number of nodes set to 1,000,000
kernel_5c
 is a typedef for entropy_decoder_model_kernel_5 with the max order set to 7 and the max number of nodes set to 2,500,000
entropy_decoder_model_kernel_6:
This object just assigns every symbol the same probability. I.e. it uses an order-(-1) model.
kernel_6a
is a typedef for entropy_decoder_model_kernel_6
[top]

entropy_encoder

This object represents an entropy encoder. E.g. the encoding part of an arithmetic coder.
More Details...
#include <dlib/entropy_encoder.h>

Implementations:
entropy_encoder_kernel_1:
This object is implemented using arithmetic coding and is done in the straight forward way using integers and fixed precision math.
kernel_1a
is a typedef for entropy_encoder_kernel_1
kernel_1a_c
 is a typedef for kernel_1a that checks its preconditions.
entropy_encoder_kernel_2:
This object is implemented using "range" coding and is done in the straight forward way using integers and fixed precision math.
kernel_2a
is a typedef for entropy_encoder_kernel_2
kernel_2a_c
 is a typedef for kernel_2a that checks its preconditions.
[top]

entropy_encoder_model

This object represents some kind of statistical model. You can use it to write symbols to an entropy_encoder and it will calculate the cumulative counts/probabilities and manage contexts for you.
More Details...
#include <dlib/entropy_encoder_model.h>

Implementations:
entropy_encoder_model_kernel_1:
This object is implemented using the conditioning_class component. It implements an order-0 finite context model and uses lazy exclusions and update exclusions. The escape method used is method D.
kernel_1a
is a typedef for entropy_encoder_model_kernel_1 that uses conditioning_class_kernel_1a
kernel_1a_c
 is a typedef for kernel_1a that checks its preconditions.
kernel_1b
is a typedef for entropy_encoder_model_kernel_1 that uses conditioning_class_kernel_2a
kernel_1b_c
 is a typedef for kernel_1b that checks its preconditions.
kernel_1c
is a typedef for entropy_encoder_model_kernel_1 that uses conditioning_class_kernel_3a
kernel_1c_c
 is a typedef for kernel_1c that checks its preconditions.
entropy_encoder_model_kernel_2:
This object is implemented using the conditioning_class component. It implements an order-1-0 finite context model and uses lazy exclusions and update exclusions. The escape method used is method D.
kernel_2a
is a typedef for entropy_encoder_model_kernel_2 that uses conditioning_class_kernel_1a
kernel_2a_c
 is a typedef for kernel_2a that checks its preconditions.
kernel_2b
is a typedef for entropy_encoder_model_kernel_2 that uses conditioning_class_kernel_2a
kernel_2b_c
 is a typedef for kernel_2b that checks its preconditions.
kernel_2c
is a typedef for entropy_encoder_model_kernel_2 that uses conditioning_class_kernel_3a
kernel_2c_c
 is a typedef for kernel_2c that checks its preconditions.
kernel_2d
is a typedef for entropy_encoder_model_kernel_2 that uses conditioning_class_kernel_2a for its order-0 context and conditioning_class_kernel_4b for its order-1 context.
kernel_2d_c
 is a typedef for kernel_2d that checks its preconditions.
entropy_encoder_model_kernel_3:
This object is implemented using the conditioning_class component. It implements an order-2-1-0 finite context model and uses lazy exclusions and update exclusions. The escape method used is method D.
kernel_3a
 is a typedef for entropy_encoder_model_kernel_3 that uses conditioning_class_kernel_1a for orders 0 and 1 and conditioning_class_kernel_4b for order-2.
kernel_3a_c
 is a typedef for kernel_3a that checks its preconditions.
kernel_3b
 is a typedef for entropy_encoder_model_kernel_3 that uses conditioning_class_kernel_2a for orders 0 and 1 and conditioning_class_kernel_4b for order-2.
kernel_3b_c
 is a typedef for kernel_3b that checks its preconditions.
kernel_3c
 is a typedef for entropy_encoder_model_kernel_3 that uses conditioning_class_kernel_3a for orders 0 and 1 and conditioning_class_kernel_4b for order-2.
kernel_3c_c
 is a typedef for kernel_3c that checks its preconditions.
entropy_encoder_model_kernel_4:
This object is implemented using a variation of the PPM algorithm described by Alistair Moffat in his paper "Implementing the PPM data compression scheme." It provides template arguments to select the maximum order and maximum memory to use. For speed, exclusions are not used. The escape method used is method D.
kernel_4a
 is a typedef for entropy_encoder_model_kernel_4 with the max order set to 4 and the max number of nodes set to 200,000
kernel_4a_c
 is a typedef for kernel_4a that checks its preconditions.
kernel_4b
 is a typedef for entropy_encoder_model_kernel_4 with the max order set to 5 and the max number of nodes set to 1,000,000
kernel_4b_c
 is a typedef for kernel_4b that checks its preconditions.
entropy_encoder_model_kernel_5:
This object is implemented using a variation of the PPM algorithm described by Alistair Moffat in his paper "Implementing the PPM data compression scheme." It provides template arguments to select the maximum order and maximum memory to use. Exclusions are used. The escape method used is method D. This implementation is very much like kernel_4 except it is tuned for higher compression rather than speed. This also uses Dmitry Shkarin's Information Inheritance scheme.
kernel_5a
 is a typedef for entropy_encoder_model_kernel_5 with the max order set to 4 and the max number of nodes set to 200,000
kernel_5a_c
 is a typedef for kernel_5a that checks its preconditions.
kernel_5b
 is a typedef for entropy_encoder_model_kernel_5 with the max order set to 5 and the max number of nodes set to 1,000,000
kernel_5b_c
 is a typedef for kernel_5b that checks its preconditions.
kernel_5c
 is a typedef for entropy_encoder_model_kernel_5 with the max order set to 7 and the max number of nodes set to 2,500,000
kernel_5c_c
 is a typedef for kernel_5c that checks its preconditions.
entropy_encoder_model_kernel_6:
This object just assigns every symbol the same probability. I.e. it uses an order-(-1) model.
kernel_6a
is a typedef for entropy_encoder_model_kernel_6
kernel_6a_c
 is a typedef for kernel_6a that checks its preconditions.
[top]

lz77_buffer

This object represents a pair of buffers (history and lookahead buffers) used during lz77 style compression.
More Details...
#include <dlib/lz77_buffer.h>

Implementations:
lz77_buffer_kernel_1:
This object is implemented using the sliding_buffer and it just does simple linear searches of the history buffer to find matches.
kernel_1a
is a typedef for lz77_buffer_kernel_1 that uses sliding_buffer_kernel_1
kernel_1a_c
 is a typedef for kernel_1a that checks its preconditions.
lz77_buffer_kernel_2:
This object is implemented using the sliding_buffer. It finds matches by using a hash table.
kernel_2a
is a typedef for lz77_buffer_kernel_2 that uses sliding_buffer_kernel_1
kernel_2a_c
 is a typedef for kernel_2a that checks its preconditions.
[top]

lzp_buffer

This object represents some variation on the LZP algorithm described by Charles Bloom in his paper "LZP: a new data compression algorithm"
More Details...
#include <dlib/lzp_buffer.h>

Implementations:
lzp_buffer_kernel_1:
This object is implemented using the sliding_buffer and uses an order-3 model to predict matches.
kernel_1a
is a typedef for lzp_buffer_kernel_1 that uses sliding_buffer_kernel_1
kernel_1a_c
 is a typedef for kernel_1a that checks its preconditions.
lzp_buffer_kernel_2:
This object is implemented using the sliding_buffer and uses an order-5-4-3 model to predict matches.
kernel_2a
is a typedef for lzp_buffer_kernel_2 that uses sliding_buffer_kernel_1
kernel_2a_c
 is a typedef for kernel_2a that checks its preconditions.


dlib C++ Library - compress_stream_kernel_abstract.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_COMPRESS_STREAM_KERNEl_ABSTRACT_
#ifdef DLIB_COMPRESS_STREAM_KERNEl_ABSTRACT_

#include "../algs.h"
#include <iosfwd>

namespace dlib
{

    class compress_stream
    {
        /*!
            INITIAL VALUE
                This object does not have any state associated with it.

            WHAT THIS OBJECT REPRESENTS
                This object consists of the two functions compress and decompress.
                These functions allow you to compress and decompress data.
        !*/

    public:

        class decompression_error : public dlib::error {};

        compress_stream (
        );
        /*!
            ensures
                - #*this is properly initialized
            throws
                - std::bad_alloc
        !*/

        virtual ~compress_stream (
        );
        /*!
            ensures
                - all memory associated with *this has been released
        !*/

        void compress (
            std::istream& in,
            std::ostream& out
        ) const;
        /*!
            ensures
                - reads all data from in (until EOF is reached) and compresses it
                  and writes it to out
            throws
                - std::ios_base::failure
                    if there was a problem writing to out then this exception will
                    be thrown.
                - any other exception
                    this exception may be thrown if there is any other problem
        !*/

        void decompress (
            std::istream& in,
            std::ostream& out
        ) const;
        /*!
            ensures
                - reads data from in, decompresses it and writes it to out.  note that
                  it stops reading data from in when it encounters the end of the
                  compressed data, not when it encounters EOF.
            throws
                - std::ios_base::failure
                    if there was a problem writing to out then this exception will
                    be thrown.
                - decompression_error
                    if an error was detected in the compressed data that prevented
                    it from being correctly decompressed then this exception is
                    thrown.
                - any other exception
                    this exception may be thrown if there is any other problem
        !*/

    private:

        // restricted functions
        compress_stream(compress_stream&);        // copy constructor
        compress_stream& operator=(compress_stream&);    // assignment operator

    };

}

#endif // DLIB_COMPRESS_STREAM_KERNEl_ABSTRACT_


dlib C++ Library - conditioning_class_kernel_abstract.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_CONDITIONING_CLASS_KERNEl_ABSTRACT_
#ifdef DLIB_CONDITIONING_CLASS_KERNEl_ABSTRACT_

#include "../algs.h"

namespace dlib
{

    template <
        unsigned long alphabet_size
        >
    class conditioning_class
    {
        /*!
            REQUIREMENTS ON alphabet_size
                1 < alphabet_size < 65536

            INITIAL VALUE
                get_total() == 1
                get_count(X) == 0 : for all valid values of X except alphabet_size-1
                get_count(alphabet_size-1) == 1

            WHAT THIS OBJECT REPRESENTS
                This object represents a conditioning class used for arithmetic style
                compression.  It maintains the cumulative counts which are needed
                by the entropy_coder and entropy_decoder objects.

                At any moment a conditioning_class object represents a set of
                alphabet_size symbols.  Each symbol is associated with an integer
                called its count.

                All symbols start out with a count of zero except for alphabet_size-1.
                This last symbol will always have a count of at least one.  It is
                intended to be used as an escape into a lower context when coding
                and so it must never have a zero probability or the decoder won't
                be able to identify the escape symbol.

            NOTATION:
                Let MAP(i) be a function which maps integers to symbols.  MAP(i) is
                one to one and onto.  Its domain is 1 to alphabet_size inclusive.

                Let RMAP(s) be the inverse of MAP(i).
                 ( i.e.  RMAP(MAP(i)) == i  and  MAP(RMAP(s)) == s  )

                Let COUNT(i) give the count for the symbol MAP(i).
                 ( i.e.  COUNT(i) == get_count(MAP(i)) )

                Let LOW_COUNT(s) == the sum of COUNT(x) for x == 1 to x == RMAP(s)-1
                  (note that the sum of COUNT(x) for x == 1 to x == 0 is 0)
                Let HIGH_COUNT(s) == LOW_COUNT(s) + get_count(s)

                Basically what this is saying is just that you shoudln't assume you know
                what order the symbols are placed in when calculating the cumulative
                sums.  The specific mapping provided by the MAP() function is unspecified.

            THREAD SAFETY
                This object can be used safely in a multithreaded program as long as the
                global state is not shared between conditioning classes which run on
                different threads.

            GLOBAL_STATE_TYPE
                The global_state_type obejct allows instances of the conditioning_class
                object to share any kind of global state the implementer desires.
                However, the global_state_type object exists primarily to facilitate the
                sharing of a memory pool between many instances of a conditioning_class
                object.  But note that it is not required that there be any kind of
                memory pool at all, it is just a possibility.
        !*/

    public:

        class global_state_type
        {
            global_state_type (
            );
            /*!
                ensures
                    - #*this is properly initialized
                throws
                    - std::bad_alloc
            !*/

            // my contents are implementation specific.
        };

        conditioning_class (
            global_state_type& global_state
        );
        /*!
            ensures
                - #*this is properly initialized
                - &#get_global_state() == &global_state
            throws
                - std::bad_alloc
        !*/

        ~conditioning_class (
        );
        /*!
            ensures
                - all memory associated with *this has been released
        !*/

        void clear(
        );
        /*!
            ensures
                - #*this has its initial value
            throws
                - std::bad_alloc
        !*/

        bool increment_count (
            unsigned long symbol,
            unsigned short amount = 1
        );
        /*!
            requires
                - 0 <= symbol < alphabet_size
                - 0 < amount < 32768
            ensures
                - if (sufficient memory is available to complete this operation) then
                    - returns true
                    - if (get_total()+amount < 65536) then
                        - #get_count(symbol) == get_count(symbol) + amount
                    - else
                        - #get_count(symbol) == get_count(symbol)/2 + amount
                        - if (get_count(alphabet_size-1) == 1) then
                            - #get_count(alphabet_size-1) == 1
                        - else
                            - #get_count(alphabet_size-1) == get_count(alphabet_size-1)/2
                        - for all X where (X != symbol)&&(X != alpahbet_size-1):
                          #get_count(X) == get_count(X)/2
                - else
                    - returns false
        !*/

        unsigned long get_count (
            unsigned long symbol
        ) const;
        /*!
            requires
                - 0 <= symbol < alphabet_size
            ensures
                - returns the count for the specified symbol
        !*/

        unsigned long get_total (
        ) const;
        /*!
            ensures
                - returns the sum of get_count(X) for all valid values of X
                  (i.e. returns the sum of the counts for all the symbols)
        !*/

        unsigned long get_range (
            unsigned long symbol,
            unsigned long& low_count,
            unsigned long& high_count,
            unsigned long& total_count
        ) const;
        /*!
            requires
                - 0 <= symbol < alphabet_size
            ensures
                - returns get_count(symbol)
                - if (get_count(symbol) != 0) then
                    - #total_count == get_total()
                    - #low_count   == LOW_COUNT(symbol)
                    - #high_count  == HIGH_COUNT(symbol)
                    - #low_count < #high_count <= #total_count
        !*/

        void get_symbol (
            unsigned long target,
            unsigned long& symbol,
            unsigned long& low_count,
            unsigned long& high_count
        ) const;
        /*!
            requires
                - 0 <= target < get_total()
            ensures
                - LOW_COUNT(#symbol) <= target < HIGH_COUNT(#symbol)
                - #low_count   == LOW_COUNT(#symbol)
                - #high_count  == HIGH_COUNT(#symbol)
                - #low_count < #high_count <= get_total()
        !*/

        global_state_type& get_global_state (
        );
        /*!
            ensures
                - returns a reference to the global state used by *this
        !*/

        unsigned long get_memory_usage (
        ) const;
        /*!
            ensures
                - returns the number of bytes of memory allocated by all conditioning_class
                  objects that share the global state given by get_global_state()
        !*/

        static unsigned long get_alphabet_size (
        );
        /*!
            ensures
                - returns alphabet_size
        !*/

    private:

        // restricted functions
        conditioning_class(conditioning_class<alphabet_size>&);        // copy constructor
        conditioning_class<alphabet_size>& operator=(conditioning_class<alphabet_size>&);    // assignment operator

    };

}

#endif // DLIB_CONDITIONING_CLASS_KERNEl_ABSTRACT_


dlib C++ Library - entropy_decoder_kernel_abstract.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_ENTROPY_DECODER_KERNEl_ABSTRACT_
#ifdef DLIB_ENTROPY_DECODER_KERNEl_ABSTRACT_

#include "../algs.h"
#include <iosfwd>
#include "../uintn.h"

namespace dlib
{

    class entropy_decoder
    {
        /*!
            INITIAL VALUE
                stream_is_set() == false
                get_target_called() == false

            WHAT THIS OBJECT REPRESENTS
                This object represents an entropy decoder (could be implemented as an
                arithmetic decoder for example).

                Note that all implementations of entropy_encoder and entropy_decoder
                are paired. This means that if you use entropy_encoder_kernel_n to
                encode something then you must use the corresponding
                entropy_decoder_kernel_n to decode it.

                WHERE IS EOF?
                It is important to note that this object will not give any indication
                that is has hit the end of the input stream when it occurs.  It is
                up to you to use some kind of coding scheme to detect this in the
                compressed data stream.

                Another important thing to know is that decode() must be called
                exactly the same number of times as encode() and with the same values
                supplied for TOTAL, high_count, and low_count.  Doing this ensures
                that the decoder consumes exactly all the bytes from the input
                stream that were written by the entropy_encoder.

            NOTATION:
                At any moment each symbol has a certain probability of appearing in
                the input stream.  These probabilities may change as each symbol is
                decoded and the probability model is updated accordingly.

                - Before considering current symbol:

                let P(i) be a function which gives the probability of seeing the ith
                symbol of an N symbol alphabet. Note that P(i) refers to the probability
                of seeing the ith symbol WITHOUT considering the symbol currently given
                by get_target(TOTAL).  ( The domain of P(i) is from 0 to N-1. )

                for each i: P(i) == COUNT/TOTAL where COUNT and TOTAL are integers
                and TOTAL is the same number for all P(i) but COUNT may vary.

                let LOW_COUNT(i)  be the sum of all P(x)*TOTAL from x == 0 to x == i-1
                  (note that LOW_COUNT(0) == 0)
                let HIGH_COUNT(i) be the sum of all P(x)*TOTAL from x == 0 to x == i

                - After considering current symbol:

                let #P(i) be a function which gives the probability of seeing the ith
                symbol after we have updated our probability model to take the symbol
                given by get_target(TOTAL) into account.

                for each i: #P(i) == #COUNT/#TOTAL where #COUNT and #TOTAL are integers
                and #TOTAL is the same number for all #P(i) but #COUNT may vary.
        !*/

    public:

        entropy_decoder (
        );
        /*!
            ensures
                - #*this is properly initialized
            throws
                - std::bad_alloc
        !*/

        virtual ~entropy_decoder (
        );
        /*!
            ensures
                - all memory associated with *this has been released
        !*/

        void clear(
        );
        /*!
            ensures
                - #*this has its initial value
                - if (stream_is_set())
                    - clears any state accumulated in *this from decoding data from
                      the stream get_stream()
            throws
                - any exception
                    if this exception is thrown then #*this is unusable
                    until clear() is called and succeeds
        !*/

        void set_stream (
            std::istream& in
        );
        /*!
            ensures
                - #*this will read data from in and decode it
                - #stream_is_set() == true
                - #get_target() == a number representing the first symbol from in
                - #get_target_called() == false
                - if (stream_is_set())
                    - clears any state accumulated in *this from decoding data from
                      the stream get_stream()
            throws
                - any exception
                    if this exception is thrown then #*this is unusable
                    until clear() is called and succeeds
        !*/

        bool stream_is_set (
        ) const;
        /*!
            ensures
                - returns true if a stream has been associated with *this by calling
                  set_stream()
        !*/

        std::istream& get_stream (
        ) const;
        /*!
            requires
                - stream_is_set() == true
            ensures
                - returns a reference to the istream object that *this is reading
                  encoded data from
        !*/

        void decode (
            uint32 low_count,
            uint32 high_count
        );
        /*!
            requires
                - get_target_called() == true
                - stream_is_set()     == true
                - low_count  == LOW_COUNT(S) where S is the symbol represented
                  by get_target(TOTAL)
                - high_count == HIGH_COUNT(S) where S is the symbol represented
                  by get_target(TOTAL)
                - low_count  <= get_target(TOTAL) < high_count <= TOTAL
            ensures
                - #get_target(#TOTAL) == a number which represents the next symbol
                - #get_target_called() == false
            throws
                - any exception
                    if this exception is thrown then #*this is unusable
                    until clear() is called and succeeds
        !*/

        bool get_target_called (
        ) const;
        /*!
            ensures
                - returns true if get_target() has been called and since then decode()
                  and set_stream() have not been called
                - returns false otherwise
        !*/

        uint32 get_target (
            uint32 total
        );
        /*!
            requires
                - 0 < total < 65536 (2^16)
                - total == TOTAL
                - stream_is_set() == true
            ensures
                - in the next call to decode() the value of TOTAL will be
                  considered to be total
                - #get_target_called() == true
                - returns a number N such that:
                    - N is in the range 0 to total - 1
                    - N represents a symbol S where
                      LOW_COUNT(S) <= N < HIGH_COUNT(S)
            throws
                - any exception
                    if this exception is thrown then #*this is unusable
                    until clear() is called and succeeds
        !*/

    private:

        // restricted functions
        entropy_decoder(entropy_decoder&);        // copy constructor
        entropy_decoder& operator=(entropy_decoder&);    // assignment operator

    };

}

#endif // DLIB_ENTROPY_DECODER_KERNEl_ABSTRACT_


dlib C++ Library - entropy_decoder_model_kernel_abstract.h

// Copyright (C) 2004  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_ENTROPY_DECODER_MODEL_KERNEl_ABSTRACT_
#ifdef DLIB_ENTROPY_DECODER_MODEL_KERNEl_ABSTRACT_

#include "../algs.h"

namespace dlib
{

    template <
        unsigned long alphabet_size,
        typename entropy_decoder
        >
    class entropy_decoder_model
    {
        /*!
            REQUIREMENTS ON alphabet_size
                1 < alphabet_size < 65535

            REQUIREMENTS ON entropy_decoder
                is an implementation of entropy_decoder/entropy_decoder_kernel_abstract.h

            INITIAL VALUE
                Initially this object is at some predefined empty or ground state.

            WHAT THIS OBJECT REPRESENTS
                This object represents some kind of statistical model.  You
                can use it to read symbols from an entropy_decoder and it will calculate
                the cumulative counts/probabilities and manage contexts for you.

                Note that all implementations of entropy_encoder_model and
                entropy_decoder_model are paired. This means that if you use
                entropy_encoder_model_kernel_n to encode something then you must
                use the corresponding entropy_decoder_model_kernel_n to decode it.

                Also note that this object does not perform any buffering of symbols.  It
                reads them from its associated entropy_decoder simply as it needs them.
                This makes it safe to use multiple entropy_decoder_model objects with
                a single entropy_decoder without them trampling each other.
        !*/

    public:

        typedef entropy_decoder entropy_decoder_type;

        entropy_decoder_model (
            entropy_decoder& coder
        );
        /*!
            ensures
                - #*this is properly initialized
                - &#get_entropy_decoder() == &coder
            throws
                - any exception
        !*/

        virtual ~entropy_decoder_model (
        );
        /*!
            ensures
                - all memory associated with *this has been released
        !*/

        void clear(
        );
        /*!
            ensures
                - #*this has its initial value
                - does not modify get_entropy_decoder()
            throws
                - any exception
                    if this exception is thrown then *this is unusable
                    until clear() is called and succeeds
        !*/

        void decode (
            unsigned long& symbol
        );
        /*!
            ensures
                - decodes the next symbol
                - #symbol == the next symbol
                - #symbol < alphabet_size
            throws
                - any exception
                    If this exception is thrown then #*this is unusable until
                    clear() is called and succeeds.
        !*/

        entropy_decoder& get_entropy_decoder (
        );
        /*!
            ensures
                - returns a reference to the entropy_decoder used by *this
        !*/

        static unsigned long get_alphabet_size (
        );
        /*!
            ensures
                - returns alphabet_size
        !*/

    private:

        // restricted functions
        entropy_decoder_model(entropy_decoder_model<alphabet_size>&);        // copy constructor
        entropy_decoder_model<alphabet_size>& operator=(entropy_decoder_model<alphabet_size>&);    // assignment operator

    };

}

#endif // DLIB_ENTROPY_DECODER_MODEL_KERNEl_ABSTRACT_


dlib C++ Library - entropy_encoder_kernel_abstract.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_ENTROPY_ENCODER_KERNEl_ABSTRACT_
#ifdef DLIB_ENTROPY_ENCODER_KERNEl_ABSTRACT_

#include "../algs.h"
#include <iosfwd>
#include "../uintn.h"

namespace dlib
{

    class entropy_encoder
    {
        /*!
            INITIAL VALUE
                stream_is_set() == false

            WHAT THIS OBJECT REPRESENTS
                This object represents an entropy encoder (could be implemented as an
                arithmetic encoder for example).

                Note that all implementations of entropy_encoder and entropy_decoder
                are paired. This means that if you use entropy_encoder_kernel_n to
                encode something then you must use the corresponding
                entropy_decoder_kernel_n to decode it.

            NOTATION:
                At any moment each symbol has a certain probability of appearing in
                the input stream.  These probabilities may change as each symbol is
                encountered and the probability model is updated accordingly.

                let P(i) be a function which gives the probability of seeing the ith
                symbol of an N symbol alphabet BEFORE the probability model is updated
                to account for the current symbol.  ( The domain of P(i) is from 0 to N-1. )

                for each i: P(i) == COUNT/TOTAL where COUNT and TOTAL are integers.
                and TOTAL is the same number for all P(i) but COUNT may vary.

                let LOW_COUNT(i)  be the sum of all P(x)*TOTAL from x == 0 to x == i-1
                  (note that LOW_COUNT(0) == 0)
                let HIGH_COUNT(i) be the sum of all P(x)*TOTAL from x == 0 to x == i
        !*/

    public:

        entropy_encoder (
        );
        /*!
            ensures
                - #*this is properly initialized
            throws
                - std::bad_alloc
        !*/

        virtual ~entropy_encoder (
        );
        /*!
            ensures
                - all memory associated with *this has been released
                - if (stream_is_set()) then
                    - any buffered data in *this will be written to get_stream()
        !*/

        void clear(
        );
        /*!
            ensures
                - #*this has its initial value
                - if (stream_is_set()) then
                    - any buffered data in *this will be written to get_stream()
                    - clears any memory of all previous calls to encode() from #*this
            throws
                - std::ios_base::failure
                    if (stream_is_set() && there was a problem writing to get_stream())
                    then this exception will be thrown.  #*this will be unusable until
                    clear() is called and succeeds
                - any other exception
                    if this exception is thrown then #*this is unusable
                    until clear() is called and succeeds
        !*/

        void set_stream (
            std::ostream& out
        );
        /*!
            ensures
                - #get_stream()    == out
                - #stream_is_set() == true
                - if (stream_is_set()) then
                    - any buffered data in *this will be written to get_stream()
                    - clears any memory of all previous calls to encode() from #*this
            throws
                - std::ios_base::failure
                    if (stream_is_set() && there was a problem writing to get_stream())
                    then this exception will be thrown.  #*this will be unusable until
                    clear() is called and succeeds
                - any other exception
                    if this exception is thrown then #*this is unusable
                    until clear() is called and succeeds
        !*/

        bool stream_is_set (
        ) const;
        /*!
            ensures
                - returns true if a stream has been associated with *this by calling
                  set_stream()
        !*/

        std::ostream& get_stream (
        ) const;
        /*!
            requires
                - stream_is_set() == true
            ensures
                - returns a reference to the ostream object that *this writes its
                  encoded data to
        !*/

        void encode (
            uint32 low_count,
            uint32 high_count,
            uint32 total
        );
        /*!
            requires
                - 0 < total <  65536 (2^16)
                - total == TOTAL
                - low_count < high_count <= total
                - stream_is_set() == true
            ensures
                - encodes the symbol S where:
                    - LOW_COUNT(S)  == low_count
                    - HIGH_COUNT(S) == high_count
            throws
                - std::ios_base::failure
                    if (there was a problem writing to get_stream()) then
                    this exception will be thrown.  #*this will be unusable until
                    clear() is called and succeeds
                - any other exception
                    if this exception is thrown then #*this is unusable
                    until clear() is called and succeeds
        !*/

    private:

        // restricted functions
        entropy_encoder(entropy_encoder&);        // copy constructor
        entropy_encoder& operator=(entropy_encoder&);    // assignment operator

    };

}

#endif // DLIB_ENTROPY_ENCODER_KERNEl_ABSTRACT_


dlib C++ Library - entropy_encoder_model_kernel_abstract.h

// Copyright (C) 2004  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_ENTROPY_ENCODER_MODEL_KERNEl_ABSTRACT_
#ifdef DLIB_ENTROPY_ENCODER_MODEL_KERNEl_ABSTRACT_

#include "../algs.h"

namespace dlib
{

    template <
        unsigned long alphabet_size,
        typename entropy_encoder
        >
    class entropy_encoder_model
    {
        /*!
            REQUIREMENTS ON alphabet_size
                1 < alphabet_size < 65535

            REQUIREMENTS ON entropy_encoder
                is an implementation of entropy_encoder/entropy_encoder_kernel_abstract.h

            INITIAL VALUE
                Initially this object is at some predefined empty or ground state.

            WHAT THIS OBJECT REPRESENTS
                This object represents some kind of statistical model.  You
                can use it to write symbols to an entropy_encoder and it will calculate
                the cumulative counts/probabilities and manage contexts for you.

                Note that all implementations of entropy_encoder_model and
                entropy_decoder_model are paired. This means that if you use
                entropy_encoder_model_kernel_n to encode something then you must
                use the corresponding entropy_decoder_model_kernel_n to decode it.

                Also note that this object does not perform any buffering of symbols.  It
                writes them to its associated entropy_encoder immediately.
                This makes it safe to use multiple entropy_encoder_model objects with
                a single entropy_encoder without them trampling each other.
        !*/

    public:

        typedef entropy_encoder entropy_encoder_type;

        entropy_encoder_model (
            entropy_encoder& coder
        );
        /*!
            ensures
                - #*this is properly initialized
                - &#get_entropy_encoder() == &coder
            throws
                - any exception
        !*/

        virtual ~entropy_encoder_model (
        );
        /*!
            ensures
                - all memory associated with *this has been released
        !*/

        void clear(
        );
        /*!
            ensures
                - #*this has its initial value
                - does not modify get_entropy_encoder()
            throws
                - any exception
                    if this exception is thrown then *this is unusable
                    until clear() is called and succeeds
        !*/

        void encode (
            unsigned long symbol
        );
        /*!
            requires
                - symbol < alphabet_size
            ensures
                - encodes and writes the symbol to get_entropy_encoder().
                  This also means that there is no internal buffering.  symbol is
                  written immediately to the entropy_encoder.
            throws
                - any exception
                    If this exception is thrown then #*this is unusable until
                    clear() is called and succeeds.
        !*/

        entropy_encoder& get_entropy_encoder (
        );
        /*!
            ensures
                - returns a reference to the entropy_encoder used by *this
        !*/

        static unsigned long get_alphabet_size (
        );
        /*!
            ensures
                - returns alphabet_size
        !*/

    private:

        // restricted functions
        entropy_encoder_model(entropy_encoder_model<alphabet_size,entropy_encoder>&);        // copy constructor
        entropy_encoder_model<alphabet_size,entropy_encoder>& operator=(entropy_encoder_model<alphabet_size,entropy_encoder>&);    // assignment operator

    };

}

#endif // DLIB_ENTROPY_ENCODER_MODEL_KERNEl_ABSTRACT_


dlib C++ Library - lz77_buffer_kernel_abstract.h

// Copyright (C) 2004  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_LZ77_BUFFER_KERNEl_ABSTRACT_
#ifdef DLIB_LZ77_BUFFER_KERNEl_ABSTRACT_

#include "../algs.h"

namespace dlib
{

    class lz77_buffer
    {
        /*!
            INITIAL VALUE
                get_history_buffer_limit() == defined by constructor arguments
                get_lookahead_buffer_limit() == defined by constructor arguments
                get_history_buffer_size() == 0
                get_lookahead_buffer_size() == 0

            WHAT THIS OBJECT REPRESENTS
                This object represents a pair of buffers (history and lookahead buffers)
                used during lz77 style compression.

                It's main function is to search the history buffer for long strings which
                match the contents (or a part of the contents) of the lookahead buffer.

            HISTORY AND LOOKAHEAD BUFFERS
                The buffers have the following structure:
                | history buffer | lookahead buffer |  <-- contents of buffers
                |  ...9876543210 | 0123456789...    |  <-- index numbers

                So this means that history_buffer(0) == 'r', history_buffer(1) == 'e'
                and so on.  And lookahead_buffer(0) == 'l', lookahead_buffer(1) == 'o'
                and so on.

                What shift_buffers() does in english:
                    This function just means that the buffers have their contents shifted
                    left by N elements and that elements shifted out of the lookahead buffer
                    go into the history buffer.   An example will make it clearer.

                    Suppose that we have the following buffers before we apply shift_buffers()
                        history_buffer() == "hey" and
                        lookahead_buffer() == "lookahead buffer"
                    And in the same format as the above diagram it would be
                        | hey | lookahead buffer |  <-- contents of buffers
                        | 210 | 0123456789...    |  <-- index numbers

                    Applying shift_buffers(4) will give
                        lookahead_buffer() == "ahead buffer"
                        history_buffer() == "heylook" or "eylook" or "ylook" or "look"

                    You might be wondering why the history_buffer can resize itself in
                    such a nondeterministic way.  It is just to allow a lot of freedom in the
                    implementations of this object.
        !*/

    public:

        lz77_buffer (
            unsigned long total_limit,
            unsigned long lookahead_limit
        );
        /*!
            requires
                - 6 < total_limit < 32
                - 15 < lookahead_limit <= 2^(total_limit-2)
            ensures
                - #*this is properly initialized
                - #get_history_buffer_limit() == 2^total_limit  - lookahead_limit
                - #get_lookahead_buffer_limit() == lookahead_limit
            throws
                - std::bad_alloc
        !*/

        virtual ~lz77_buffer (
        );
        /*!
            ensures
                - any resources associated with *this have been released
        !*/

        void clear(
        );
        /*!
            ensures
                - #*this has its initial value
            throws
                - std::bad_alloc
                    if this exception is thrown then #*this is unusable
                    until clear() is called and succeeds
        !*/

        void shift_buffers (
            unsigned long N
        );
        /*!
            requires
                - N <= get_lookahead_buffer_size()
            ensures
                - #get_lookahead_buffer_size() == get_lookahead_buffer_size() - N
                - #get_history_buffer_size() >= N
                - #get_history_buffer_size() <= get_history_buffer_size()+N
                - #get_history_buffer_size() <= get_history_buffer_limit()
                - for all i where 0 <= i < N:
                    #history_buffer(N-1-i) == lookahead_buffer(i)
                - for all i where 0 <= i < #get_history_buffer_size()-N:
                    #history_buffer(N+i) == history_buffer(i)
                - for all i where 0 <= i < #get_lookahead_buffer_size()
                    #lookahead_buffer(i) == lookahead_buffer(N+i)
        !*/

        void add (
            unsigned char symbol
        );
        /*!
            ensures
                - if (get_lookahead_buffer_size() == get_lookahead_buffer_limit()) then
                    - performs shift_buffers(1)
                    - #lookahead_buffer(get_lookahead_buffer_limit()-1) == symbol
                    - #get_lookahead_buffer_size() == get_lookahead_buffer_size()
                - else
                    - #lookahead_buffer(get_lookahead_buffer_size()) == symbol
                    - #get_lookahead_buffer_size() == get_lookahead_buffer_size() + 1
            throws
                - std::bad_alloc
                    if this exception is thrown then #*this is unusable
                    until clear() is called and succeeds
        !*/

        void find_match (
            unsigned long& index,
            unsigned long& length,
            unsigned long min_match_length
        );
        /*!
            ensures
                - if (#length != 0) then
                    - #length >= min_match_length
                    - for all i where 0 <= i < #length:
                      history_buffer(#index-i) == lookahead_buffer(i)
                    - performs shift_buffers(#length)
            throws
                - std::bad_alloc
                    if this exception is thrown then #*this is unusable
                    until clear() is called and succeeds
        !*/

        unsigned long get_history_buffer_limit (
        ) const;
        /*!
            ensures
                - returns the max number of symbols that can fit in the history buffer
        !*/

        unsigned long get_lookahead_buffer_limit (
        ) const;
        /*!
            ensures
                - returns the max number of symbols that can fit in the lookahead buffer
        !*/

        unsigned long get_history_buffer_size (
        ) const;
        /*!
            ensures
                - returns the number of symbols currently in the history buffer
        !*/

        unsigned long get_lookahead_buffer_size (
        ) const;
        /*!
            ensures
                - returns the number of symbols currently in the lookahead buffer
        !*/

        unsigned char lookahead_buffer (
            unsigned long index
        ) const;
        /*!
            requires
                - index < get_lookahead_buffer_size()
            ensures
                - returns the symbol in the lookahead buffer at location index
        !*/

        unsigned char history_buffer (
            unsigned long index
        ) const;
        /*!
            requires
                - index < get_history_buffer_size()
            ensures
                - returns the symbol in the history buffer at location index
        !*/

    private:

        // restricted functions
        lz77_buffer(lz77_buffer&);        // copy constructor
        lz77_buffer& operator=(lz77_buffer&);    // assignment operator

    };
}

#endif // DLIB_LZ77_BUFFER_KERNEl_ABSTRACT_


dlib C++ Library - lzp_buffer_kernel_abstract.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_LZP_BUFFER_KERNEl_ABSTRACT_
#ifdef DLIB_LZP_BUFFER_KERNEl_ABSTRACT_

#include "../algs.h"

namespace dlib
{

    class lzp_buffer
    {
        /*!
            INITIAL VALUE
                size() == some value defined by the constructor argument
                Initially this object is at some predefined empty or ground state.
                for all i: (*this)[i] == 0

            WHAT THIS OBJECT REPRESENTS
                This object represents some varation on the LZP algorithm
                described by Charles Bloom in his paper "LZP: a new data
                compression algorithm"

                The LZP algorithm is a lot like lz77 except there is no need to pass
                the location of matches in the history buffer to the decoder because
                LZP uses the data it has already seen to predict the location of the
                next match.

            NOTE
                The add() and predict_match() functions must be called in the same
                order by the coder and decoder.  If they aren't the state of the
                lzp_buffer objects in the coder and decoder may differ and the decoder
                won't be able to correctly decode the data stream.
        !*/

    public:

        explicit lzp_buffer (
            unsigned long buffer_size
        );
        /*!
            requires
                - 10 < buffer_size < 32
            ensures
                - #*this is properly initialized
                - #size() == 2^buffer_size
            throws
                - std::bad_alloc
        !*/

        virtual ~lzp_buffer (
        );
        /*!
            ensures
                - any resources associated with *this have been released
        !*/

        void clear(
        );
        /*!
            ensures
                - #*this has its initial value
            throws
                - std::bad_alloc
                    if this exception is thrown then #*this is unusable
                    until clear() is called and succeeds
        !*/

        void add (
            unsigned char symbol
        );
        /*!
            ensures
                - shifts everything in the history buffer left 1.
                  (i.e. #(*this)[i+1] == (*this)[i])
                - #(*this)[0] == symbol
            throws
                - std::bad_alloc
                    if this exception is thrown then #*this is unusable
                    until clear() is called and succeeds
        !*/

        unsigned long predict_match (
            unsigned long& index
        );
        /*!
            ensures
                - updates the prediction for the current context.
                  (the current context is the last few symbols seen. i.e. (*this)[0],
                   (*this)[1], etc.)
                - if (*this can generate a prediction) then
                    - #index == the predicted location of a match in the history buffer.
                      (i.e. (*this)[#index] is the first symbol of the predicted match)
                    - returns the order this prediction came from
                - else
                    - returns 0
            throws
                - std::bad_alloc
                    if this exception is thrown then #*this is unusable
                    until clear() is called and succeeds
        !*/

        unsigned long size (
        ) const;
        /*!
            ensures
                - returns the size of the history buffer
        !*/

        unsigned char operator[] (
            unsigned long index
        ) const;
        /*!
            requires
                - index < size()
            ensures
                - returns the symbol at the given index in the history buffer
        !*/

    private:

        // restricted functions
        lzp_buffer(const lzp_buffer&);        // copy constructor
        lzp_buffer& operator=(const lzp_buffer&);    // assignment operator

    };
}

#endif // DLIB_LZP_BUFFER_KERNEl_ABSTRACT_


dlib C++ Library - kernel_1a

The Library
  • Algorithms
  • API Wrappers
  • Bayesian Nets
  • Compression
  • Containers
  • Graph Tools
  • Image Processing
  • Linear Algebra
  • Machine Learning
  • Metaprogramming
  • Miscellaneous
  • Networking
  • Optimization
  • Parsing

Help/Info
  • Dlib Blog
  • Examples: C++
    • 3D Point Cloud
    • Assignment Learning
    • Base64 Encoder
    • Bayesian Network From Disk
    • Bayesian Network GUI
    • Bayesian Network
    • Bridge
    • BSP
    • C-Support Vector Machine
    • Cmd Line Parser
    • Compress Stream
    • Config File Reader
    • Custom Trainers
    • Directory Navigation
    • Empirical Kernel Map
    • Face Detection
    • Face Landmark Detection
    • FHOG Feature Extraction
    • FHOG Object Detection
    • Graph Labeling
    • GUI
    • Hough Transform
    • HTTP Server
    • Image
    • IO Socket Streams
    • IO Streams Server
    • Kernel Centroid
    • Kernel K-Means Clustering
    • Kernel Ridge Regression
    • Kernel RLS Filtering
    • Kernel RLS Regression
    • KRR Classification
    • Learning to Track
    • Linear Assignment Problems
    • Linear Manifold Regularizer
    • Linear Model Predictive Control
    • Logger Advanced
    • Logger Custom Output
    • Logger
    • Matrix Expressions
    • Matrix
    • Member Function Pointer
    • Model Selection
    • Multiclass Classification
    • Multithreaded Object
    • Neural Network
    • Non-Linear Least Squares
    • Nu-Support Vector Machine
    • Numerical Integration
    • Object Detector Advanced
    • Object Detector
    • One Class Classifiers
    • Online SVM
    • Optimization
    • Parallel For Loops
    • Pipe 2
    • Pipe
    • Quantum Computing
    • Queue
    • Rank Features
    • Relevance Vector Classification
    • Relevance Vector Regression
    • Running Stats
    • Sequence Labeling
    • Sequence Segmentation
    • Sockets
    • Sockstreambuf
    • Sparse Vectors
    • SQLite
    • Std C++ Allocator
    • Structural Support Vector Machines
    • Support Vector Regression
    • SURF
    • SVM-Rank
    • Thread Function
    • Thread Pool
    • Threaded Object
    • Threads
    • Timer
    • Train Object Detector
    • Train Shape Predictor
    • Using Custom Kernels
    • Video Object Tracking
    • Webcam Face Pose Estimation
    • XML Parser
  • Examples: Python
    • Face Detector
    • Face Landmark Detection
    • find candidate object locations
    • Linear Assignment Problems
    • Sequence Segmenter
    • Structural Support Vector Machines
    • SVM-Rank
    • Train Object Detector
    • Train Shape Predictor
    • Video Object Tracking
  • FAQ
  • Forums
  • Home
  • How to compile
  • How to contribute
  • Index
  • Introduction
  • License
  • Python API
  • Suggested Books
  • Who uses dlib?

Current Release
  • Change Log
  • Release Notes
  • Version: 18.18

Last Modified:
Jun 22, 2008
kernel_1a

    The Canterbury Corpus

file      size      packed size      bpb         corruption

text:      152089      86995       4.576          no
play:      125179      75430       4.82062        no
html:      24603       16209       5.27058        no
Csrc:      11150       7084        5.08269        no
list:      3721        2224        4.78151        no
Excl:      1029744     440758      3.42421        no
tech:      426754      248345      4.65552        no
poem:      481861      273394      4.53897        no
fax:       513216      75036       1.16966        no
SPRC:      38240       25660       5.3682         no
man:       4227        2663        5.03998        no

average: 4.42981

time: 875ms

    The Calgary Corpus

file      size      packed size      bpb         corruption

bib:       111261      72533       5.21534        no
book1:     768771      435527      4.53219        no
book2:     610856      364597      4.7749         no
geo:       102400      72600       5.67188        no
news:      377109      244377      5.18422        no
obj1:      21504       16183       6.02046        no
obj2:      246814      189902      6.15531        no
paper1:    53161       33144       4.98772        no
paper2:    82199       47398       4.613          no
pic:       513216      75036       1.16966        no
progc:     39611       25885       5.22784        no
progl:     71646       42688       4.76655        no
progp:     49379       30180       4.88953        no
trans:     93695       64603       5.51603        no

average: 4.9089

time: 1.11sec

    The Artificial Corpus

file      size      packed size      bpb         corruption

a:         1           7           56             no
aaa:       100000      20          0.0016         no
alphabet:  100000      58912       4.71296        no
random:    100000      75202       6.01616        no

average: 16.6827

time: 93ms

    The Large Corpus

file      size      packed size      bpb         corruption

E.coli:    4638690     1162352     2.00462        no
bible:     4047392     2194059     4.33674        no
word:      2473400     1542086     4.98774        no

average: 3.77637

time: 3.766sec
Objects
  • compress_stream
  • conditioning_class
  • entropy_decoder
  • entropy_decoder_model
  • entropy_encoder
  • entropy_encoder_model
  • lz77_buffer
  • lzp_buffer

Benchmarks
  • kernel_1a
  • kernel_1b
  • kernel_1c
  • kernel_1da
  • kernel_1db
  • kernel_1ea
  • kernel_1eb
  • kernel_1ec
  • kernel_2a
  • kernel_3a
  • kernel_3b


dlib C++ Library - kernel_1b

The Library
  • Algorithms
  • API Wrappers
  • Bayesian Nets
  • Compression
  • Containers
  • Graph Tools
  • Image Processing
  • Linear Algebra
  • Machine Learning
  • Metaprogramming
  • Miscellaneous
  • Networking
  • Optimization
  • Parsing

Help/Info
  • Dlib Blog
  • Examples: C++
    • 3D Point Cloud
    • Assignment Learning
    • Base64 Encoder
    • Bayesian Network From Disk
    • Bayesian Network GUI
    • Bayesian Network
    • Bridge
    • BSP
    • C-Support Vector Machine
    • Cmd Line Parser
    • Compress Stream
    • Config File Reader
    • Custom Trainers
    • Directory Navigation
    • Empirical Kernel Map
    • Face Detection
    • Face Landmark Detection
    • FHOG Feature Extraction
    • FHOG Object Detection
    • Graph Labeling
    • GUI
    • Hough Transform
    • HTTP Server
    • Image
    • IO Socket Streams
    • IO Streams Server
    • Kernel Centroid
    • Kernel K-Means Clustering
    • Kernel Ridge Regression
    • Kernel RLS Filtering
    • Kernel RLS Regression
    • KRR Classification
    • Learning to Track
    • Linear Assignment Problems
    • Linear Manifold Regularizer
    • Linear Model Predictive Control
    • Logger Advanced
    • Logger Custom Output
    • Logger
    • Matrix Expressions
    • Matrix
    • Member Function Pointer
    • Model Selection
    • Multiclass Classification
    • Multithreaded Object
    • Neural Network
    • Non-Linear Least Squares
    • Nu-Support Vector Machine
    • Numerical Integration
    • Object Detector Advanced
    • Object Detector
    • One Class Classifiers
    • Online SVM
    • Optimization
    • Parallel For Loops
    • Pipe 2
    • Pipe
    • Quantum Computing
    • Queue
    • Rank Features
    • Relevance Vector Classification
    • Relevance Vector Regression
    • Running Stats
    • Sequence Labeling
    • Sequence Segmentation
    • Sockets
    • Sockstreambuf
    • Sparse Vectors
    • SQLite
    • Std C++ Allocator
    • Structural Support Vector Machines
    • Support Vector Regression
    • SURF
    • SVM-Rank
    • Thread Function
    • Thread Pool
    • Threaded Object
    • Threads
    • Timer
    • Train Object Detector
    • Train Shape Predictor
    • Using Custom Kernels
    • Video Object Tracking
    • Webcam Face Pose Estimation
    • XML Parser
  • Examples: Python
    • Face Detector
    • Face Landmark Detection
    • find candidate object locations
    • Linear Assignment Problems
    • Sequence Segmenter
    • Structural Support Vector Machines
    • SVM-Rank
    • Train Object Detector
    • Train Shape Predictor
    • Video Object Tracking
  • FAQ
  • Forums
  • Home
  • How to compile
  • How to contribute
  • Index
  • Introduction
  • License
  • Python API
  • Suggested Books
  • Who uses dlib?

Current Release
  • Change Log
  • Release Notes
  • Version: 18.18

Last Modified:
Jun 22, 2008
kernel_1b

    The Canterbury Corpus

file      size      packed size      bpb         corruption

text:      152089      66165       3.48033        no
play:      125179      54572       3.48761        no
html:      24603       11661       3.79173        no
Csrc:      11150       4733        3.39587        no
list:      3721        1629        3.50228        no
Excl:      1029744     343447      2.66821        no
tech:      426754      188332      3.5305         no
poem:      481861      204240      3.39085        no
fax:       513216      54127       0.843731       no
SPRC:      38240       18307       3.82992        no
man:       4227        2100        3.97445        no

average: 3.26323

time: 844ms

    The Calgary Corpus

file      size      packed size      bpb         corruption

bib:       111261      48130       3.46069        no
book1:     768771      346572      3.6065         no
book2:     610856      288605      3.77968        no
geo:       102400      61124       4.77531        no
news:      377109      196085      4.15975        no
obj1:      21504       12445       4.62984        no
obj2:      246814      127142      4.12106        no
paper1:    53161       25438       3.82807        no
paper2:    82199       37295       3.62973        no
pic:       513216      54127       0.843731       no
progc:     39611       19090       3.85549        no
progl:     71646       29773       3.32446        no
progp:     49379       20795       3.36904        no
trans:     93695       40922       3.49406        no

average: 3.6341

time: 1.109sec

    The Artificial Corpus

file      size      packed size      bpb         corruption

a:         1           7           56             no
aaa:       100000      20          0.0016         no
alphabet:  100000      83          0.00664        no
random:    100000      77775       6.222          no

average: 15.5576

time: 94ms

    The Large Corpus

file      size      packed size      bpb         corruption

E.coli:    4638690     1151913     1.98662        no
bible:     4047392     1651476     3.26428        no
word:      2473400     1133090     3.66488        no

average: 2.97193

time: 3.672sec
Objects
  • compress_stream
  • conditioning_class
  • entropy_decoder
  • entropy_decoder_model
  • entropy_encoder
  • entropy_encoder_model
  • lz77_buffer
  • lzp_buffer

Benchmarks
  • kernel_1a
  • kernel_1b
  • kernel_1c
  • kernel_1da
  • kernel_1db
  • kernel_1ea
  • kernel_1eb
  • kernel_1ec
  • kernel_2a
  • kernel_3a
  • kernel_3b


dlib C++ Library - kernel_1c

The Library
  • Algorithms
  • API Wrappers
  • Bayesian Nets
  • Compression
  • Containers
  • Graph Tools
  • Image Processing
  • Linear Algebra
  • Machine Learning
  • Metaprogramming
  • Miscellaneous
  • Networking
  • Optimization
  • Parsing

Help/Info
  • Dlib Blog
  • Examples: C++
    • 3D Point Cloud
    • Assignment Learning
    • Base64 Encoder
    • Bayesian Network From Disk
    • Bayesian Network GUI
    • Bayesian Network
    • Bridge
    • BSP
    • C-Support Vector Machine
    • Cmd Line Parser
    • Compress Stream
    • Config File Reader
    • Custom Trainers
    • Directory Navigation
    • Empirical Kernel Map
    • Face Detection
    • Face Landmark Detection
    • FHOG Feature Extraction
    • FHOG Object Detection
    • Graph Labeling
    • GUI
    • Hough Transform
    • HTTP Server
    • Image
    • IO Socket Streams
    • IO Streams Server
    • Kernel Centroid
    • Kernel K-Means Clustering
    • Kernel Ridge Regression
    • Kernel RLS Filtering
    • Kernel RLS Regression
    • KRR Classification
    • Learning to Track
    • Linear Assignment Problems
    • Linear Manifold Regularizer
    • Linear Model Predictive Control
    • Logger Advanced
    • Logger Custom Output
    • Logger
    • Matrix Expressions
    • Matrix
    • Member Function Pointer
    • Model Selection
    • Multiclass Classification
    • Multithreaded Object
    • Neural Network
    • Non-Linear Least Squares
    • Nu-Support Vector Machine
    • Numerical Integration
    • Object Detector Advanced
    • Object Detector
    • One Class Classifiers
    • Online SVM
    • Optimization
    • Parallel For Loops
    • Pipe 2
    • Pipe
    • Quantum Computing
    • Queue
    • Rank Features
    • Relevance Vector Classification
    • Relevance Vector Regression
    • Running Stats
    • Sequence Labeling
    • Sequence Segmentation
    • Sockets
    • Sockstreambuf
    • Sparse Vectors
    • SQLite
    • Std C++ Allocator
    • Structural Support Vector Machines
    • Support Vector Regression
    • SURF
    • SVM-Rank
    • Thread Function
    • Thread Pool
    • Threaded Object
    • Threads
    • Timer
    • Train Object Detector
    • Train Shape Predictor
    • Using Custom Kernels
    • Video Object Tracking
    • Webcam Face Pose Estimation
    • XML Parser
  • Examples: Python
    • Face Detector
    • Face Landmark Detection
    • find candidate object locations
    • Linear Assignment Problems
    • Sequence Segmenter
    • Structural Support Vector Machines
    • SVM-Rank
    • Train Object Detector
    • Train Shape Predictor
    • Video Object Tracking
  • FAQ
  • Forums
  • Home
  • How to compile
  • How to contribute
  • Index
  • Introduction
  • License
  • Python API
  • Suggested Books
  • Who uses dlib?

Current Release
  • Change Log
  • Release Notes
  • Version: 18.18

Last Modified:
Jun 22, 2008
kernel_1c

    The Canterbury Corpus

file      size      packed size      bpb         corruption

text:      152089      51810       2.72525        no
play:      125179      44002       2.8121         no
html:      24603       8602        2.79706        no
Csrc:      11150       3399        2.43874        no
list:      3721        1272        2.73475        no
Excl:      1029744     237165      1.84252        no
tech:      426754      147090      2.75737        no
poem:      481861      169981      2.82208        no
fax:       513216      54230       0.845336       no
SPRC:      38240       15190       3.17782        no
man:       4227        1763        3.33665        no

average: 2.57179

time: 1.031sec

    The Calgary Corpus

file      size      packed size      bpb         corruption

bib:       111261      37264       2.67939        no
book1:     768771      280052      2.91428        no
book2:     610856      221616      2.90237        no
geo:       102400      62115       4.85273        no
news:      377109      155282      3.29416        no
obj1:      21504       11235       4.17969        no
obj2:      246814      97319       3.15441        no
paper1:    53161       19664       2.95916        no
paper2:    82199       29837       2.90388        no
pic:       513216      54230       0.845336       no
progc:     39611       14610       2.9507         no
progl:     71646       21637       2.41599        no
progp:     49379       14204       2.30122        no
trans:     93695       27848       2.37776        no

average: 2.90936

time: 1.297sec

    The Artificial Corpus

file      size      packed size      bpb         corruption

a:         1           7           56             no
aaa:       100000      18          0.00144        no
alphabet:  100000      65          0.0052         no
random:    100000      90704       7.25632        no

average: 15.8157

time: 203ms

    The Large Corpus

file      size      packed size      bpb         corruption

E.coli:    4638690     1141437     1.96855        no
bible:     4047392     1263237     2.49689        no
word:      2473400     876621      2.83536        no

average: 2.4336

time: 3.391sec
Objects
  • compress_stream
  • conditioning_class
  • entropy_decoder
  • entropy_decoder_model
  • entropy_encoder
  • entropy_encoder_model
  • lz77_buffer
  • lzp_buffer

Benchmarks
  • kernel_1a
  • kernel_1b
  • kernel_1c
  • kernel_1da
  • kernel_1db
  • kernel_1ea
  • kernel_1eb
  • kernel_1ec
  • kernel_2a
  • kernel_3a
  • kernel_3b


dlib C++ Library - kernel_1da

The Library
  • Algorithms
  • API Wrappers
  • Bayesian Nets
  • Compression
  • Containers
  • Graph Tools
  • Image Processing
  • Linear Algebra
  • Machine Learning
  • Metaprogramming
  • Miscellaneous
  • Networking
  • Optimization
  • Parsing

Help/Info
  • Dlib Blog
  • Examples: C++
    • 3D Point Cloud
    • Assignment Learning
    • Base64 Encoder
    • Bayesian Network From Disk
    • Bayesian Network GUI
    • Bayesian Network
    • Bridge
    • BSP
    • C-Support Vector Machine
    • Cmd Line Parser
    • Compress Stream
    • Config File Reader
    • Custom Trainers
    • Directory Navigation
    • Empirical Kernel Map
    • Face Detection
    • Face Landmark Detection
    • FHOG Feature Extraction
    • FHOG Object Detection
    • Graph Labeling
    • GUI
    • Hough Transform
    • HTTP Server
    • Image
    • IO Socket Streams
    • IO Streams Server
    • Kernel Centroid
    • Kernel K-Means Clustering
    • Kernel Ridge Regression
    • Kernel RLS Filtering
    • Kernel RLS Regression
    • KRR Classification
    • Learning to Track
    • Linear Assignment Problems
    • Linear Manifold Regularizer
    • Linear Model Predictive Control
    • Logger Advanced
    • Logger Custom Output
    • Logger
    • Matrix Expressions
    • Matrix
    • Member Function Pointer
    • Model Selection
    • Multiclass Classification
    • Multithreaded Object
    • Neural Network
    • Non-Linear Least Squares
    • Nu-Support Vector Machine
    • Numerical Integration
    • Object Detector Advanced
    • Object Detector
    • One Class Classifiers
    • Online SVM
    • Optimization
    • Parallel For Loops
    • Pipe 2
    • Pipe
    • Quantum Computing
    • Queue
    • Rank Features
    • Relevance Vector Classification
    • Relevance Vector Regression
    • Running Stats
    • Sequence Labeling
    • Sequence Segmentation
    • Sockets
    • Sockstreambuf
    • Sparse Vectors
    • SQLite
    • Std C++ Allocator
    • Structural Support Vector Machines
    • Support Vector Regression
    • SURF
    • SVM-Rank
    • Thread Function
    • Thread Pool
    • Threaded Object
    • Threads
    • Timer
    • Train Object Detector
    • Train Shape Predictor
    • Using Custom Kernels
    • Video Object Tracking
    • Webcam Face Pose Estimation
    • XML Parser
  • Examples: Python
    • Face Detector
    • Face Landmark Detection
    • find candidate object locations
    • Linear Assignment Problems
    • Sequence Segmenter
    • Structural Support Vector Machines
    • SVM-Rank
    • Train Object Detector
    • Train Shape Predictor
    • Video Object Tracking
  • FAQ
  • Forums
  • Home
  • How to compile
  • How to contribute
  • Index
  • Introduction
  • License
  • Python API
  • Suggested Books
  • Who uses dlib?

Current Release
  • Change Log
  • Release Notes
  • Version: 18.18

Last Modified:
Jun 22, 2008
kernel_1da

    The Canterbury Corpus

file      size      packed size      bpb         corruption

text:      152089      45580       2.39754        no
play:      125179      42432       2.71176        no
html:      24603       7745        2.51839        no
Csrc:      11150       3165        2.27085        no
list:      3721        1238        2.66165        no
Excl:      1029744     194875      1.51397        no
tech:      426754      111838      2.09653        no
poem:      481861      148110      2.45897        no
fax:       513216      56075       0.874096       no
SPRC:      38240       14248       2.98075        no
man:       4227        1736        3.28555        no

average: 2.34273

time: 1.812sec

    The Calgary Corpus

file      size      packed size      bpb         corruption

bib:       111261      29161       2.09676        no
book1:     768771      235667      2.4524         no
book2:     610856      165032      2.16132        no
geo:       102400      67663       5.28617        no
news:      377109      128148      2.71853        no
obj1:      21504       10750       3.99926        no
obj2:      246814      82894       2.68685        no
paper1:    53161       17398       2.61816        no
paper2:    82199       26449       2.57414        no
pic:       513216      56075       0.874096       no
progc:     39611       13188       2.6635         no
progl:     71646       17135       1.9133         no
progp:     49379       11764       1.90591        no
trans:     93695       19602       1.67369        no

average: 2.54458

time: 2.36sec

    The Artificial Corpus

file      size      packed size      bpb         corruption

a:         1           6           48             no
aaa:       100000      19          0.00152        no
alphabet:  100000      66          0.00528        no
random:    100000      89652       7.17216        no

average: 13.7947

time: 375ms

    The Large Corpus

file      size      packed size      bpb         corruption

E.coli:    4638690     1130363     1.94945        no
bible:     4047392     871537      1.72266        no
word:      2473400     589688      1.9073         no

average: 1.8598

time: 4.484sec
Objects
  • compress_stream
  • conditioning_class
  • entropy_decoder
  • entropy_decoder_model
  • entropy_encoder
  • entropy_encoder_model
  • lz77_buffer
  • lzp_buffer

Benchmarks
  • kernel_1a
  • kernel_1b
  • kernel_1c
  • kernel_1da
  • kernel_1db
  • kernel_1ea
  • kernel_1eb
  • kernel_1ec
  • kernel_2a
  • kernel_3a
  • kernel_3b


dlib C++ Library - kernel_1db

The Library
  • Algorithms
  • API Wrappers
  • Bayesian Nets
  • Compression
  • Containers
  • Graph Tools
  • Image Processing
  • Linear Algebra
  • Machine Learning
  • Metaprogramming
  • Miscellaneous
  • Networking
  • Optimization
  • Parsing

Help/Info
  • Dlib Blog
  • Examples: C++
    • 3D Point Cloud
    • Assignment Learning
    • Base64 Encoder
    • Bayesian Network From Disk
    • Bayesian Network GUI
    • Bayesian Network
    • Bridge
    • BSP
    • C-Support Vector Machine
    • Cmd Line Parser
    • Compress Stream
    • Config File Reader
    • Custom Trainers
    • Directory Navigation
    • Empirical Kernel Map
    • Face Detection
    • Face Landmark Detection
    • FHOG Feature Extraction
    • FHOG Object Detection
    • Graph Labeling
    • GUI
    • Hough Transform
    • HTTP Server
    • Image
    • IO Socket Streams
    • IO Streams Server
    • Kernel Centroid
    • Kernel K-Means Clustering
    • Kernel Ridge Regression
    • Kernel RLS Filtering
    • Kernel RLS Regression
    • KRR Classification
    • Learning to Track
    • Linear Assignment Problems
    • Linear Manifold Regularizer
    • Linear Model Predictive Control
    • Logger Advanced
    • Logger Custom Output
    • Logger
    • Matrix Expressions
    • Matrix
    • Member Function Pointer
    • Model Selection
    • Multiclass Classification
    • Multithreaded Object
    • Neural Network
    • Non-Linear Least Squares
    • Nu-Support Vector Machine
    • Numerical Integration
    • Object Detector Advanced
    • Object Detector
    • One Class Classifiers
    • Online SVM
    • Optimization
    • Parallel For Loops
    • Pipe 2
    • Pipe
    • Quantum Computing
    • Queue
    • Rank Features
    • Relevance Vector Classification
    • Relevance Vector Regression
    • Running Stats
    • Sequence Labeling
    • Sequence Segmentation
    • Sockets
    • Sockstreambuf
    • Sparse Vectors
    • SQLite
    • Std C++ Allocator
    • Structural Support Vector Machines
    • Support Vector Regression
    • SURF
    • SVM-Rank
    • Thread Function
    • Thread Pool
    • Threaded Object
    • Threads
    • Timer
    • Train Object Detector
    • Train Shape Predictor
    • Using Custom Kernels
    • Video Object Tracking
    • Webcam Face Pose Estimation
    • XML Parser
  • Examples: Python
    • Face Detector
    • Face Landmark Detection
    • find candidate object locations
    • Linear Assignment Problems
    • Sequence Segmenter
    • Structural Support Vector Machines
    • SVM-Rank
    • Train Object Detector
    • Train Shape Predictor
    • Video Object Tracking
  • FAQ
  • Forums
  • Home
  • How to compile
  • How to contribute
  • Index
  • Introduction
  • License
  • Python API
  • Suggested Books
  • Who uses dlib?

Current Release
  • Change Log
  • Release Notes
  • Version: 18.18

Last Modified:
Jun 22, 2008
kernel_1db

    The Canterbury Corpus

file      size      packed size      bpb         corruption

text:      152089      47843       2.51658        no
play:      125179      45069       2.88029        no
html:      24603       7914        2.57334        no
Csrc:      11150       3279        2.35265        no
list:      3721        1281        2.7541         no
Excl:      1029744     210286      1.6337         no
tech:      426754      115826      2.17129        no
poem:      481861      157348      2.61234        no
fax:       513216      56477       0.880362       no
SPRC:      38240       14466       3.02636        no
man:       4227        1780        3.36882        no

average: 2.43362

time: 2.296sec

    The Calgary Corpus

file      size      packed size      bpb         corruption

bib:       111261      29758       2.13969        no
book1:     768771      247700      2.57762        no
book2:     610856      168694      2.20928        no
geo:       102400      67817       5.2982         no
news:      377109      126675      2.68729        no
obj1:      21504       10871       4.04427        no
obj2:      246814      82948       2.6886         no
paper1:    53161       18113       2.72576        no
paper2:    82199       27700       2.6959         no
pic:       513216      56477       0.880362       no
progc:     39611       13622       2.75115        no
progl:     71646       17263       1.92759        no
progp:     49379       12032       1.94933        no
trans:     93695       19505       1.6654         no

average: 2.5886

time: 2.86sec

    The Artificial Corpus

file      size      packed size      bpb         corruption

a:         1           6           48             no
aaa:       100000      20          0.0016         no
alphabet:  100000      66          0.00528        no
random:    100000      88475       7.078          no

average: 13.7712

time: 531ms

    The Large Corpus

file      size      packed size      bpb         corruption

E.coli:    4638690     1130433     1.94957        no
bible:     4047392     844807      1.66983        no
word:      2473400     504129      1.63056        no

average: 1.74999

time: 5.266sec
Objects
  • compress_stream
  • conditioning_class
  • entropy_decoder
  • entropy_decoder_model
  • entropy_encoder
  • entropy_encoder_model
  • lz77_buffer
  • lzp_buffer

Benchmarks
  • kernel_1a
  • kernel_1b
  • kernel_1c
  • kernel_1da
  • kernel_1db
  • kernel_1ea
  • kernel_1eb
  • kernel_1ec
  • kernel_2a
  • kernel_3a
  • kernel_3b


dlib C++ Library - kernel_1ea

The Library
  • Algorithms
  • API Wrappers
  • Bayesian Nets
  • Compression
  • Containers
  • Graph Tools
  • Image Processing
  • Linear Algebra
  • Machine Learning
  • Metaprogramming
  • Miscellaneous
  • Networking
  • Optimization
  • Parsing

Help/Info
  • Dlib Blog
  • Examples: C++
    • 3D Point Cloud
    • Assignment Learning
    • Base64 Encoder
    • Bayesian Network From Disk
    • Bayesian Network GUI
    • Bayesian Network
    • Bridge
    • BSP
    • C-Support Vector Machine
    • Cmd Line Parser
    • Compress Stream
    • Config File Reader
    • Custom Trainers
    • Directory Navigation
    • Empirical Kernel Map
    • Face Detection
    • Face Landmark Detection
    • FHOG Feature Extraction
    • FHOG Object Detection
    • Graph Labeling
    • GUI
    • Hough Transform
    • HTTP Server
    • Image
    • IO Socket Streams
    • IO Streams Server
    • Kernel Centroid
    • Kernel K-Means Clustering
    • Kernel Ridge Regression
    • Kernel RLS Filtering
    • Kernel RLS Regression
    • KRR Classification
    • Learning to Track
    • Linear Assignment Problems
    • Linear Manifold Regularizer
    • Linear Model Predictive Control
    • Logger Advanced
    • Logger Custom Output
    • Logger
    • Matrix Expressions
    • Matrix
    • Member Function Pointer
    • Model Selection
    • Multiclass Classification
    • Multithreaded Object
    • Neural Network
    • Non-Linear Least Squares
    • Nu-Support Vector Machine
    • Numerical Integration
    • Object Detector Advanced
    • Object Detector
    • One Class Classifiers
    • Online SVM
    • Optimization
    • Parallel For Loops
    • Pipe 2
    • Pipe
    • Quantum Computing
    • Queue
    • Rank Features
    • Relevance Vector Classification
    • Relevance Vector Regression
    • Running Stats
    • Sequence Labeling
    • Sequence Segmentation
    • Sockets
    • Sockstreambuf
    • Sparse Vectors
    • SQLite
    • Std C++ Allocator
    • Structural Support Vector Machines
    • Support Vector Regression
    • SURF
    • SVM-Rank
    • Thread Function
    • Thread Pool
    • Threaded Object
    • Threads
    • Timer
    • Train Object Detector
    • Train Shape Predictor
    • Using Custom Kernels
    • Video Object Tracking
    • Webcam Face Pose Estimation
    • XML Parser
  • Examples: Python
    • Face Detector
    • Face Landmark Detection
    • find candidate object locations
    • Linear Assignment Problems
    • Sequence Segmenter
    • Structural Support Vector Machines
    • SVM-Rank
    • Train Object Detector
    • Train Shape Predictor
    • Video Object Tracking
  • FAQ
  • Forums
  • Home
  • How to compile
  • How to contribute
  • Index
  • Introduction
  • License
  • Python API
  • Suggested Books
  • Who uses dlib?

Current Release
  • Change Log
  • Release Notes
  • Version: 18.18

Last Modified:
Jun 22, 2008
kernel_1ea

    The Canterbury Corpus

file      size      packed size      bpb         corruption

text:      152089      40695       2.14059        no
play:      125179      37421       2.39152        no
html:      24603       6859        2.2303         no
Csrc:      11150       2792        2.00323        no
list:      3721        1084        2.33056        no
Excl:      1029744     156897      1.21892        no
tech:      426754      102805      1.9272         no
poem:      481861      136664      2.26894        no
fax:       513216      51109       0.796686       no
SPRC:      38240       12590       2.63389        no
man:       4227        1530        2.89567        no

average: 2.07614

time: 3.062sec

    The Calgary Corpus

file      size      packed size      bpb         corruption

bib:       111261      26039       1.87228        no
book1:     768771      218772      2.27659        no
book2:     610856      151985      1.99045        no
geo:       102400      59371       4.63836        no
news:      377109      115334      2.4467         no
obj1:      21504       9832        3.65774        no
obj2:      246814      75065       2.43309        no
paper1:    53161       15263       2.29687        no
paper2:    82199       23368       2.27429        no
pic:       513216      51109       0.796686       no
progc:     39611       11549       2.33248        no
progl:     71646       15297       1.70806        no
progp:     49379       10447       1.69254        no
trans:     93695       17677       1.50932        no

average: 2.28039

time: 4.172sec

    The Artificial Corpus

file      size      packed size      bpb         corruption

a:         1           7           56             no
aaa:       100000      17          0.00136        no
alphabet:  100000      65          0.0052         no
random:    100000      82599       6.60792        no

average: 15.6536

time: 672ms

    The Large Corpus

file      size      packed size      bpb         corruption

E.coli:    4638690     1130095     1.94899        no
bible:     4047392     848956      1.67803        no
word:      2473400     542983      1.75623        no

average: 1.79442

time: 6.516sec
Objects
  • compress_stream
  • conditioning_class
  • entropy_decoder
  • entropy_decoder_model
  • entropy_encoder
  • entropy_encoder_model
  • lz77_buffer
  • lzp_buffer

Benchmarks
  • kernel_1a
  • kernel_1b
  • kernel_1c
  • kernel_1da
  • kernel_1db
  • kernel_1ea
  • kernel_1eb
  • kernel_1ec
  • kernel_2a
  • kernel_3a
  • kernel_3b


dlib C++ Library - kernel_1eb

The Library
  • Algorithms
  • API Wrappers
  • Bayesian Nets
  • Compression
  • Containers
  • Graph Tools
  • Image Processing
  • Linear Algebra
  • Machine Learning
  • Metaprogramming
  • Miscellaneous
  • Networking
  • Optimization
  • Parsing

Help/Info
  • Dlib Blog
  • Examples: C++
    • 3D Point Cloud
    • Assignment Learning
    • Base64 Encoder
    • Bayesian Network From Disk
    • Bayesian Network GUI
    • Bayesian Network
    • Bridge
    • BSP
    • C-Support Vector Machine
    • Cmd Line Parser
    • Compress Stream
    • Config File Reader
    • Custom Trainers
    • Directory Navigation
    • Empirical Kernel Map
    • Face Detection
    • Face Landmark Detection
    • FHOG Feature Extraction
    • FHOG Object Detection
    • Graph Labeling
    • GUI
    • Hough Transform
    • HTTP Server
    • Image
    • IO Socket Streams
    • IO Streams Server
    • Kernel Centroid
    • Kernel K-Means Clustering
    • Kernel Ridge Regression
    • Kernel RLS Filtering
    • Kernel RLS Regression
    • KRR Classification
    • Learning to Track
    • Linear Assignment Problems
    • Linear Manifold Regularizer
    • Linear Model Predictive Control
    • Logger Advanced
    • Logger Custom Output
    • Logger
    • Matrix Expressions
    • Matrix
    • Member Function Pointer
    • Model Selection
    • Multiclass Classification
    • Multithreaded Object
    • Neural Network
    • Non-Linear Least Squares
    • Nu-Support Vector Machine
    • Numerical Integration
    • Object Detector Advanced
    • Object Detector
    • One Class Classifiers
    • Online SVM
    • Optimization
    • Parallel For Loops
    • Pipe 2
    • Pipe
    • Quantum Computing
    • Queue
    • Rank Features
    • Relevance Vector Classification
    • Relevance Vector Regression
    • Running Stats
    • Sequence Labeling
    • Sequence Segmentation
    • Sockets
    • Sockstreambuf
    • Sparse Vectors
    • SQLite
    • Std C++ Allocator
    • Structural Support Vector Machines
    • Support Vector Regression
    • SURF
    • SVM-Rank
    • Thread Function
    • Thread Pool
    • Threaded Object
    • Threads
    • Timer
    • Train Object Detector
    • Train Shape Predictor
    • Using Custom Kernels
    • Video Object Tracking
    • Webcam Face Pose Estimation
    • XML Parser
  • Examples: Python
    • Face Detector
    • Face Landmark Detection
    • find candidate object locations
    • Linear Assignment Problems
    • Sequence Segmenter
    • Structural Support Vector Machines
    • SVM-Rank
    • Train Object Detector
    • Train Shape Predictor
    • Video Object Tracking
  • FAQ
  • Forums
  • Home
  • How to compile
  • How to contribute
  • Index
  • Introduction
  • License
  • Python API
  • Suggested Books
  • Who uses dlib?

Current Release
  • Change Log
  • Release Notes
  • Version: 18.18

Last Modified:
Jun 22, 2008
kernel_1eb

    The Canterbury Corpus

file      size      packed size      bpb         corruption

text:      152089      40220       2.1156         no
play:      125179      37451       2.39344        no
html:      24603       6819        2.21729        no
Csrc:      11150       2770        1.98744        no
list:      3721        1085        2.33271        no
Excl:      1029744     158436      1.23088        no
tech:      426754      100243      1.87917        no
poem:      481861      136151      2.26042        no
fax:       513216      50374       0.785229       no
SPRC:      38240       12387       2.59142        no
man:       4227        1528        2.89189        no

average: 2.06232

time: 4.875sec

    The Calgary Corpus

file      size      packed size      bpb         corruption

bib:       111261      25279       1.81764        no
book1:     768771      216389      2.25179        no
book2:     610856      146986      1.92498        no
geo:       102400      58768       4.59125        no
news:      377109      109292      2.31852        no
obj1:      21504       9819        3.6529         no
obj2:      246814      72662       2.3552         no
paper1:    53161       15128       2.27656        no
paper2:    82199       23186       2.25657        no
pic:       513216      50374       0.785229       no
progc:     39611       11434       2.30926        no
progl:     71646       14712       1.64274        no
progp:     49379       10210       1.65414        no
trans:     93695       16885       1.4417         no

average: 2.23418

time: 5.421sec

    The Artificial Corpus

file      size      packed size      bpb         corruption

a:         1           7           56             no
aaa:       100000      17          0.00136        no
alphabet:  100000      64          0.00512        no
random:    100000      81881       6.55048        no

average: 15.6392

time: 907ms

    The Large Corpus

file      size      packed size      bpb         corruption

E.coli:    4638690     1129161     1.94738        no
bible:     4047392     794809      1.571          no
word:      2473400     454450      1.46988        no

average: 1.66275

time: 7.39sec
Objects
  • compress_stream
  • conditioning_class
  • entropy_decoder
  • entropy_decoder_model
  • entropy_encoder
  • entropy_encoder_model
  • lz77_buffer
  • lzp_buffer

Benchmarks
  • kernel_1a
  • kernel_1b
  • kernel_1c
  • kernel_1da
  • kernel_1db
  • kernel_1ea
  • kernel_1eb
  • kernel_1ec
  • kernel_2a
  • kernel_3a
  • kernel_3b


dlib C++ Library - kernel_1ec

The Library
  • Algorithms
  • API Wrappers
  • Bayesian Nets
  • Compression
  • Containers
  • Graph Tools
  • Image Processing
  • Linear Algebra
  • Machine Learning
  • Metaprogramming
  • Miscellaneous
  • Networking
  • Optimization
  • Parsing

Help/Info
  • Dlib Blog
  • Examples: C++
    • 3D Point Cloud
    • Assignment Learning
    • Base64 Encoder
    • Bayesian Network From Disk
    • Bayesian Network GUI
    • Bayesian Network
    • Bridge
    • BSP
    • C-Support Vector Machine
    • Cmd Line Parser
    • Compress Stream
    • Config File Reader
    • Custom Trainers
    • Directory Navigation
    • Empirical Kernel Map
    • Face Detection
    • Face Landmark Detection
    • FHOG Feature Extraction
    • FHOG Object Detection
    • Graph Labeling
    • GUI
    • Hough Transform
    • HTTP Server
    • Image
    • IO Socket Streams
    • IO Streams Server
    • Kernel Centroid
    • Kernel K-Means Clustering
    • Kernel Ridge Regression
    • Kernel RLS Filtering
    • Kernel RLS Regression
    • KRR Classification
    • Learning to Track
    • Linear Assignment Problems
    • Linear Manifold Regularizer
    • Linear Model Predictive Control
    • Logger Advanced
    • Logger Custom Output
    • Logger
    • Matrix Expressions
    • Matrix
    • Member Function Pointer
    • Model Selection
    • Multiclass Classification
    • Multithreaded Object
    • Neural Network
    • Non-Linear Least Squares
    • Nu-Support Vector Machine
    • Numerical Integration
    • Object Detector Advanced
    • Object Detector
    • One Class Classifiers
    • Online SVM
    • Optimization
    • Parallel For Loops
    • Pipe 2
    • Pipe
    • Quantum Computing
    • Queue
    • Rank Features
    • Relevance Vector Classification
    • Relevance Vector Regression
    • Running Stats
    • Sequence Labeling
    • Sequence Segmentation
    • Sockets
    • Sockstreambuf
    • Sparse Vectors
    • SQLite
    • Std C++ Allocator
    • Structural Support Vector Machines
    • Support Vector Regression
    • SURF
    • SVM-Rank
    • Thread Function
    • Thread Pool
    • Threaded Object
    • Threads
    • Timer
    • Train Object Detector
    • Train Shape Predictor
    • Using Custom Kernels
    • Video Object Tracking
    • Webcam Face Pose Estimation
    • XML Parser
  • Examples: Python
    • Face Detector
    • Face Landmark Detection
    • find candidate object locations
    • Linear Assignment Problems
    • Sequence Segmenter
    • Structural Support Vector Machines
    • SVM-Rank
    • Train Object Detector
    • Train Shape Predictor
    • Video Object Tracking
  • FAQ
  • Forums
  • Home
  • How to compile
  • How to contribute
  • Index
  • Introduction
  • License
  • Python API
  • Suggested Books
  • Who uses dlib?

Current Release
  • Change Log
  • Release Notes
  • Version: 18.18

Last Modified:
Jun 22, 2008
kernel_1ec

    The Canterbury Corpus

file      size      packed size      bpb         corruption

text:      152089      40367       2.12334        no
play:      125179      37785       2.41478        no
html:      24603       6828        2.22022        no
Csrc:      11150       2710        1.94439        no
list:      3721        1084        2.33056        no
Excl:      1029744     162760      1.26447        no
tech:      426754      100488      1.88376        no
poem:      481861      139110      2.30955        no
fax:       513216      50276       0.783701       no
SPRC:      38240       12219       2.55628        no
man:       4227        1533        2.90135        no

average: 2.06658

time: 5.484sec

    The Calgary Corpus

file      size      packed size      bpb         corruption

bib:       111261      25153       1.80858        no
book1:     768771      220128      2.2907         no
book2:     610856      146040      1.91259        no
geo:       102400      58737       4.58883        no
news:      377109      108774      2.30753        no
obj1:      21504       9823        3.65439        no
obj2:      246814      71148       2.30613        no
paper1:    53161       15116       2.27475        no
paper2:    82199       23346       2.27214        no
pic:       513216      50276       0.783701       no
progc:     39611       11351       2.29249        no
progl:     71646       14125       1.5772         no
progp:     49379       9966        1.61461        no
trans:     93695       16068       1.37194        no

average: 2.21826

time: 6.188sec

    The Artificial Corpus

file      size      packed size      bpb         corruption

a:         1           7           56             no
aaa:       100000      17          0.00136        no
alphabet:  100000      65          0.0052         no
random:    100000      81869       6.54952        no

average: 15.639

time: 1.109sec

    The Large Corpus

file      size      packed size      bpb         corruption

E.coli:    4638690     1160064     2.00068        no
bible:     4047392     760498      1.50319        no
word:      2473400     422419      1.36628        no

average: 1.62338

time: 11.203sec
Objects
  • compress_stream
  • conditioning_class
  • entropy_decoder
  • entropy_decoder_model
  • entropy_encoder
  • entropy_encoder_model
  • lz77_buffer
  • lzp_buffer

Benchmarks
  • kernel_1a
  • kernel_1b
  • kernel_1c
  • kernel_1da
  • kernel_1db
  • kernel_1ea
  • kernel_1eb
  • kernel_1ec
  • kernel_2a
  • kernel_3a
  • kernel_3b


dlib C++ Library - kernel_2a

The Library
  • Algorithms
  • API Wrappers
  • Bayesian Nets
  • Compression
  • Containers
  • Graph Tools
  • Image Processing
  • Linear Algebra
  • Machine Learning
  • Metaprogramming
  • Miscellaneous
  • Networking
  • Optimization
  • Parsing

Help/Info
  • Dlib Blog
  • Examples: C++
    • 3D Point Cloud
    • Assignment Learning
    • Base64 Encoder
    • Bayesian Network From Disk
    • Bayesian Network GUI
    • Bayesian Network
    • Bridge
    • BSP
    • C-Support Vector Machine
    • Cmd Line Parser
    • Compress Stream
    • Config File Reader
    • Custom Trainers
    • Directory Navigation
    • Empirical Kernel Map
    • Face Detection
    • Face Landmark Detection
    • FHOG Feature Extraction
    • FHOG Object Detection
    • Graph Labeling
    • GUI
    • Hough Transform
    • HTTP Server
    • Image
    • IO Socket Streams
    • IO Streams Server
    • Kernel Centroid
    • Kernel K-Means Clustering
    • Kernel Ridge Regression
    • Kernel RLS Filtering
    • Kernel RLS Regression
    • KRR Classification
    • Learning to Track
    • Linear Assignment Problems
    • Linear Manifold Regularizer
    • Linear Model Predictive Control
    • Logger Advanced
    • Logger Custom Output
    • Logger
    • Matrix Expressions
    • Matrix
    • Member Function Pointer
    • Model Selection
    • Multiclass Classification
    • Multithreaded Object
    • Neural Network
    • Non-Linear Least Squares
    • Nu-Support Vector Machine
    • Numerical Integration
    • Object Detector Advanced
    • Object Detector
    • One Class Classifiers
    • Online SVM
    • Optimization
    • Parallel For Loops
    • Pipe 2
    • Pipe
    • Quantum Computing
    • Queue
    • Rank Features
    • Relevance Vector Classification
    • Relevance Vector Regression
    • Running Stats
    • Sequence Labeling
    • Sequence Segmentation
    • Sockets
    • Sockstreambuf
    • Sparse Vectors
    • SQLite
    • Std C++ Allocator
    • Structural Support Vector Machines
    • Support Vector Regression
    • SURF
    • SVM-Rank
    • Thread Function
    • Thread Pool
    • Threaded Object
    • Threads
    • Timer
    • Train Object Detector
    • Train Shape Predictor
    • Using Custom Kernels
    • Video Object Tracking
    • Webcam Face Pose Estimation
    • XML Parser
  • Examples: Python
    • Face Detector
    • Face Landmark Detection
    • find candidate object locations
    • Linear Assignment Problems
    • Sequence Segmenter
    • Structural Support Vector Machines
    • SVM-Rank
    • Train Object Detector
    • Train Shape Predictor
    • Video Object Tracking
  • FAQ
  • Forums
  • Home
  • How to compile
  • How to contribute
  • Index
  • Introduction
  • License
  • Python API
  • Suggested Books
  • Who uses dlib?

Current Release
  • Change Log
  • Release Notes
  • Version: 18.18

Last Modified:
Jun 22, 2008
kernel_2a

    The Canterbury Corpus

file      size      packed size      bpb         corruption

text:      152089      55655       2.9275         no
play:      125179      49648       3.17293        no
html:      24603       8345        2.71349        no
Csrc:      11150       3514        2.52126        no
list:      3721        1379        2.96479        no
Excl:      1029744     72617       0.564156       no
tech:      426754      145403      2.72575        no
poem:      481861      196109      3.25586        no
fax:       513216      49740       0.775346       no
SPRC:      38240       13253       2.77259        no
man:       4227        1857        3.51455        no

average: 2.53711

time: 4.641sec

    The Calgary Corpus

file      size      packed size      bpb         corruption

bib:       111261      35687       2.566          no
book1:     768771      313140      3.2586         no
book2:     610856      210661      2.7589         no
geo:       102400      61070       4.77109        no
news:      377109      143307      3.04012        no
obj1:      21504       11004       4.09375        no
obj2:      246814      83289       2.69965        no
paper1:    53161       19433       2.9244         no
paper2:    82199       30671       2.98505        no
pic:       513216      49740       0.775346       no
progc:     39611       14142       2.85618        no
progl:     71646       17196       1.92011        no
progp:     49379       12045       1.95144        no
trans:     93695       19849       1.69478        no

average: 2.73539

time: 4.89sec

    The Artificial Corpus

file      size      packed size      bpb         corruption

a:         1           6           48             no
aaa:       100000      58          0.00464        no
alphabet:  100000      87          0.00696        no
random:    100000      77815       6.2252         no

average: 13.5592

time: 235ms

    The Large Corpus

file      size      packed size      bpb         corruption

E.coli:    4638690     1349400     2.32721        no
bible:     4047392     1206327     2.3844         no
word:      2473400     703195      2.27442        no

average: 2.32868

time: 8.75sec
Objects
  • compress_stream
  • conditioning_class
  • entropy_decoder
  • entropy_decoder_model
  • entropy_encoder
  • entropy_encoder_model
  • lz77_buffer
  • lzp_buffer

Benchmarks
  • kernel_1a
  • kernel_1b
  • kernel_1c
  • kernel_1da
  • kernel_1db
  • kernel_1ea
  • kernel_1eb
  • kernel_1ec
  • kernel_2a
  • kernel_3a
  • kernel_3b


dlib C++ Library - kernel_3a

The Library
  • Algorithms
  • API Wrappers
  • Bayesian Nets
  • Compression
  • Containers
  • Graph Tools
  • Image Processing
  • Linear Algebra
  • Machine Learning
  • Metaprogramming
  • Miscellaneous
  • Networking
  • Optimization
  • Parsing

Help/Info
  • Dlib Blog
  • Examples: C++
    • 3D Point Cloud
    • Assignment Learning
    • Base64 Encoder
    • Bayesian Network From Disk
    • Bayesian Network GUI
    • Bayesian Network
    • Bridge
    • BSP
    • C-Support Vector Machine
    • Cmd Line Parser
    • Compress Stream
    • Config File Reader
    • Custom Trainers
    • Directory Navigation
    • Empirical Kernel Map
    • Face Detection
    • Face Landmark Detection
    • FHOG Feature Extraction
    • FHOG Object Detection
    • Graph Labeling
    • GUI
    • Hough Transform
    • HTTP Server
    • Image
    • IO Socket Streams
    • IO Streams Server
    • Kernel Centroid
    • Kernel K-Means Clustering
    • Kernel Ridge Regression
    • Kernel RLS Filtering
    • Kernel RLS Regression
    • KRR Classification
    • Learning to Track
    • Linear Assignment Problems
    • Linear Manifold Regularizer
    • Linear Model Predictive Control
    • Logger Advanced
    • Logger Custom Output
    • Logger
    • Matrix Expressions
    • Matrix
    • Member Function Pointer
    • Model Selection
    • Multiclass Classification
    • Multithreaded Object
    • Neural Network
    • Non-Linear Least Squares
    • Nu-Support Vector Machine
    • Numerical Integration
    • Object Detector Advanced
    • Object Detector
    • One Class Classifiers
    • Online SVM
    • Optimization
    • Parallel For Loops
    • Pipe 2
    • Pipe
    • Quantum Computing
    • Queue
    • Rank Features
    • Relevance Vector Classification
    • Relevance Vector Regression
    • Running Stats
    • Sequence Labeling
    • Sequence Segmentation
    • Sockets
    • Sockstreambuf
    • Sparse Vectors
    • SQLite
    • Std C++ Allocator
    • Structural Support Vector Machines
    • Support Vector Regression
    • SURF
    • SVM-Rank
    • Thread Function
    • Thread Pool
    • Threaded Object
    • Threads
    • Timer
    • Train Object Detector
    • Train Shape Predictor
    • Using Custom Kernels
    • Video Object Tracking
    • Webcam Face Pose Estimation
    • XML Parser
  • Examples: Python
    • Face Detector
    • Face Landmark Detection
    • find candidate object locations
    • Linear Assignment Problems
    • Sequence Segmenter
    • Structural Support Vector Machines
    • SVM-Rank
    • Train Object Detector
    • Train Shape Predictor
    • Video Object Tracking
  • FAQ
  • Forums
  • Home
  • How to compile
  • How to contribute
  • Index
  • Introduction
  • License
  • Python API
  • Suggested Books
  • Who uses dlib?

Current Release
  • Change Log
  • Release Notes
  • Version: 18.18

Last Modified:
Jun 22, 2008
kernel_3a

    The Canterbury Corpus

file      size      packed size      bpb         corruption

text:      152089      118620      6.2395         no
play:      125179      103761      6.63121        no
html:      24603       14067       4.57408        no
Csrc:      11150       5805        4.16502        no
list:      3721        2142        4.60521        no
Excl:      1029744     390978      3.03748        no
tech:      426754      310347      5.81782        no
poem:      481861      435150      7.22449        no
fax:       513216      116298      1.81285        no
SPRC:      38240       23076       4.82762        no
man:       4227        3177        6.01278        no

average: 4.99528

time: 547ms

    The Calgary Corpus

file      size      packed size      bpb         corruption

bib:       111261      68949       4.95764        no
book1:     768771      683415      7.11177        no
book2:     610856      435186      5.69936        no
geo:       102400      105111      8.2118         no
news:      377109      266382      5.65103        no
obj1:      21504       15714       5.84598        no
obj2:      246814      139671      4.52717        no
paper1:    53161       37476       5.63962        no
paper2:    82199       63198       6.15073        no
pic:       513216      116298      1.81285        no
progc:     39611       25398       5.12948        no
progl:     71646       31905       3.56252        no
progp:     49379       20943       3.39302        no
trans:     93695       34056       2.90782        no

average: 5.04291

time: 610ms

    The Artificial Corpus

file      size      packed size      bpb         corruption

a:         1           9           72             no
aaa:       100000      3771        0.30168        no
alphabet:  100000      486         0.03888        no
random:    100000      112491      8.99928        no

average: 20.335

time: 47ms

    The Large Corpus

file      size      packed size      bpb         corruption

E.coli:    4638690     4752396     8.1961         no
bible:     4047392     2649303     5.23656        no
word:      2473400     1452177     4.69694        no

average: 6.0432

time: 2.5sec
Objects
  • compress_stream
  • conditioning_class
  • entropy_decoder
  • entropy_decoder_model
  • entropy_encoder
  • entropy_encoder_model
  • lz77_buffer
  • lzp_buffer

Benchmarks
  • kernel_1a
  • kernel_1b
  • kernel_1c
  • kernel_1da
  • kernel_1db
  • kernel_1ea
  • kernel_1eb
  • kernel_1ec
  • kernel_2a
  • kernel_3a
  • kernel_3b


dlib C++ Library - kernel_3b

The Library
  • Algorithms
  • API Wrappers
  • Bayesian Nets
  • Compression
  • Containers
  • Graph Tools
  • Image Processing
  • Linear Algebra
  • Machine Learning
  • Metaprogramming
  • Miscellaneous
  • Networking
  • Optimization
  • Parsing

Help/Info
  • Dlib Blog
  • Examples: C++
    • 3D Point Cloud
    • Assignment Learning
    • Base64 Encoder
    • Bayesian Network From Disk
    • Bayesian Network GUI
    • Bayesian Network
    • Bridge
    • BSP
    • C-Support Vector Machine
    • Cmd Line Parser
    • Compress Stream
    • Config File Reader
    • Custom Trainers
    • Directory Navigation
    • Empirical Kernel Map
    • Face Detection
    • Face Landmark Detection
    • FHOG Feature Extraction
    • FHOG Object Detection
    • Graph Labeling
    • GUI
    • Hough Transform
    • HTTP Server
    • Image
    • IO Socket Streams
    • IO Streams Server
    • Kernel Centroid
    • Kernel K-Means Clustering
    • Kernel Ridge Regression
    • Kernel RLS Filtering
    • Kernel RLS Regression
    • KRR Classification
    • Learning to Track
    • Linear Assignment Problems
    • Linear Manifold Regularizer
    • Linear Model Predictive Control
    • Logger Advanced
    • Logger Custom Output
    • Logger
    • Matrix Expressions
    • Matrix
    • Member Function Pointer
    • Model Selection
    • Multiclass Classification
    • Multithreaded Object
    • Neural Network
    • Non-Linear Least Squares
    • Nu-Support Vector Machine
    • Numerical Integration
    • Object Detector Advanced
    • Object Detector
    • One Class Classifiers
    • Online SVM
    • Optimization
    • Parallel For Loops
    • Pipe 2
    • Pipe
    • Quantum Computing
    • Queue
    • Rank Features
    • Relevance Vector Classification
    • Relevance Vector Regression
    • Running Stats
    • Sequence Labeling
    • Sequence Segmentation
    • Sockets
    • Sockstreambuf
    • Sparse Vectors
    • SQLite
    • Std C++ Allocator
    • Structural Support Vector Machines
    • Support Vector Regression
    • SURF
    • SVM-Rank
    • Thread Function
    • Thread Pool
    • Threaded Object
    • Threads
    • Timer
    • Train Object Detector
    • Train Shape Predictor
    • Using Custom Kernels
    • Video Object Tracking
    • Webcam Face Pose Estimation
    • XML Parser
  • Examples: Python
    • Face Detector
    • Face Landmark Detection
    • find candidate object locations
    • Linear Assignment Problems
    • Sequence Segmenter
    • Structural Support Vector Machines
    • SVM-Rank
    • Train Object Detector
    • Train Shape Predictor
    • Video Object Tracking
  • FAQ
  • Forums
  • Home
  • How to compile
  • How to contribute
  • Index
  • Introduction
  • License
  • Python API
  • Suggested Books
  • Who uses dlib?

Current Release
  • Change Log
  • Release Notes
  • Version: 18.18

Last Modified:
Jun 22, 2008
kernel_3b

    The Canterbury Corpus

file      size      packed size      bpb         corruption

text:      152089      111537      5.86693        no
play:      125179      101457      6.48396        no
html:      24603       13914       4.52433        no
Csrc:      11150       5760        4.13274        no
list:      3721        2160        4.64391        no
Excl:      1029744     407466      3.16557        no
tech:      426754      291483      5.46419        no
poem:      481861      417897      6.93805        no
fax:       513216      114138      1.77918        no
SPRC:      38240       23184       4.85021        no
man:       4227        3159        5.97871        no

average: 4.89343

time: 734ms

    The Calgary Corpus

file      size      packed size      bpb         corruption

bib:       111261      63729       4.58231        no
book1:     768771      655227      6.81844        no
book2:     610856      409392      5.36155        no
geo:       102400      108099      8.44523        no
news:      377109      259065      5.49581        no
obj1:      21504       15768       5.86607        no
obj2:      246814      138564      4.49128        no
paper1:    53161       35901       5.40261        no
paper2:    82199       60291       5.86781        no
pic:       513216      114138      1.77918        no
progc:     39611       24984       5.04587        no
progl:     71646       31113       3.47408        no
progp:     49379       20772       3.36532        no
trans:     93695       33093       2.82559        no

average: 4.9158

time: 907ms

    The Artificial Corpus

file      size      packed size      bpb         corruption

a:         1           9           72             no
aaa:       100000      3771        0.30168        no
alphabet:  100000      486         0.03888        no
random:    100000      112509      9.00072        no

average: 20.3353

time: 78ms

    The Large Corpus

file      size      packed size      bpb         corruption

E.coli:    4638690     4747257     8.18724        no
bible:     4047392     2466675     4.87558        no
word:      2473400     1301805     4.21058        no

average: 5.7578

time: 3.25sec
Objects
  • compress_stream
  • conditioning_class
  • entropy_decoder
  • entropy_decoder_model
  • entropy_encoder
  • entropy_encoder_model
  • lz77_buffer
  • lzp_buffer

Benchmarks
  • kernel_1a
  • kernel_1b
  • kernel_1c
  • kernel_1da
  • kernel_1db
  • kernel_1ea
  • kernel_1eb
  • kernel_1ec
  • kernel_2a
  • kernel_3a
  • kernel_3b


dlib C++ Library - Containers

The Library
  • Algorithms
  • API Wrappers
  • Bayesian Nets
  • Compression
  • Containers
  • Graph Tools
  • Image Processing
  • Linear Algebra
  • Machine Learning
  • Metaprogramming
  • Miscellaneous
  • Networking
  • Optimization
  • Parsing

Help/Info
  • Dlib Blog
  • Examples: C++
    • 3D Point Cloud
    • Assignment Learning
    • Base64 Encoder
    • Bayesian Network From Disk
    • Bayesian Network GUI
    • Bayesian Network
    • Bridge
    • BSP
    • C-Support Vector Machine
    • Cmd Line Parser
    • Compress Stream
    • Config File Reader
    • Custom Trainers
    • Directory Navigation
    • Empirical Kernel Map
    • Face Detection
    • Face Landmark Detection
    • FHOG Feature Extraction
    • FHOG Object Detection
    • Graph Labeling
    • GUI
    • Hough Transform
    • HTTP Server
    • Image
    • IO Socket Streams
    • IO Streams Server
    • Kernel Centroid
    • Kernel K-Means Clustering
    • Kernel Ridge Regression
    • Kernel RLS Filtering
    • Kernel RLS Regression
    • KRR Classification
    • Learning to Track
    • Linear Assignment Problems
    • Linear Manifold Regularizer
    • Linear Model Predictive Control
    • Logger Advanced
    • Logger Custom Output
    • Logger
    • Matrix Expressions
    • Matrix
    • Member Function Pointer
    • Model Selection
    • Multiclass Classification
    • Multithreaded Object
    • Neural Network
    • Non-Linear Least Squares
    • Nu-Support Vector Machine
    • Numerical Integration
    • Object Detector Advanced
    • Object Detector
    • One Class Classifiers
    • Online SVM
    • Optimization
    • Parallel For Loops
    • Pipe 2
    • Pipe
    • Quantum Computing
    • Queue
    • Rank Features
    • Relevance Vector Classification
    • Relevance Vector Regression
    • Running Stats
    • Sequence Labeling
    • Sequence Segmentation
    • Sockets
    • Sockstreambuf
    • Sparse Vectors
    • SQLite
    • Std C++ Allocator
    • Structural Support Vector Machines
    • Support Vector Regression
    • SURF
    • SVM-Rank
    • Thread Function
    • Thread Pool
    • Threaded Object
    • Threads
    • Timer
    • Train Object Detector
    • Train Shape Predictor
    • Using Custom Kernels
    • Video Object Tracking
    • Webcam Face Pose Estimation
    • XML Parser
  • Examples: Python
    • Face Detector
    • Face Landmark Detection
    • find candidate object locations
    • Linear Assignment Problems
    • Sequence Segmenter
    • Structural Support Vector Machines
    • SVM-Rank
    • Train Object Detector
    • Train Shape Predictor
    • Video Object Tracking
  • FAQ
  • Forums
  • Home
  • How to compile
  • How to contribute
  • Index
  • Introduction
  • License
  • Python API
  • Suggested Books
  • Who uses dlib?

Current Release
  • Change Log
  • Release Notes
  • Version: 18.18

Last Modified:
Sep 13, 2015
Containers

Many of these containers were inspired by the work of the Reusable Software Research Group at Ohio State. As such, many of the objects do not support copying in any form, only swapping is allowed. That is, when objects are added or removed from most of these containers they are swapped in and out, not copied.

This allows you to do things like have containers of containers of containers without encountering the overhead of the massive copying that would likely result if you did the same thing with the STL. It also means you can store objects that are not copyable inside these containers, which is not something you can do with the STL prior to C++11.

Note that it is assumed by these containers that swap() and operator< do not throw. They may not function correctly if this assumption is broken. Also note that the built in types (int, long, char, etc.) and std::string will not cause operator< or swap() to throw.

Note also that most of the containers inherit from the enumerable interface. Thus, all the member functions inherited from enumerable are defined in the enumerable class and their documentation is not repeated in each container's documentation. This includes the size() member function in each container.

Objects
  • any
  • any_decision_function
  • any_function
  • any_trainer
  • array
  • array2d
  • binary_search_tree
  • circular_buffer
  • directed_graph
  • graph
  • hash_map
  • hash_set
  • hash_table
  • map
  • queue
  • reference_counter
  • reference_wrapper
  • sequence
  • set
  • sliding_buffer
  • stack
  • static_map
  • static_set
  • std_vector_c
  • tuple
  • type_safe_union
  • unordered_pair

Smart Pointers
  • scoped_ptr
  • shared_ptr
  • shared_ptr_thread_safe
  • weak_ptr

Interfaces
  • enumerable
  • map_pair
  • remover
    • asc_pair_remover
    • asc_remover
    • pair_remover
    • remover

[top]

any

This object is basically a type-safe version of a void*. In particular, it is a container which can contain only one object but the object may be of any type.

It is somewhat like the type_safe_union except you don't have to declare the set of possible content types beforehand. So in some sense this is like a less type-strict version of the type_safe_union.

More Details...
#include <dlib/any.h>
[top]

any_decision_function

This object is a version of dlib::any that is restricted to containing elements which are some kind of function object with an operator() with the following signature: result_type operator()(const sample_type&) const

It is intended to be used to contain dlib::decision_function objects and other types which represent learned decision functions. It allows you to write code which contains and processes these decision functions without needing to know the specific types of decision functions used.

More Details...
#include <dlib/any.h>
[top]

any_function

This object is a version of dlib::any that is restricted to containing elements which are some kind of function or function object.
More Details...
#include <dlib/any.h>
[top]

any_trainer

This object is a version of dlib::any that is restricted to containing elements which are some kind of object with a .train() method compatible with the following signature:
 decision_function train(
      const std::vector<sample_type>& samples,
      const std::vector<scalar_type>& labels
   ) const
Where decision_function is a type capable of being stored in an any_decision_function object.

any_trainer is intended to be used to contain objects such as the svm_nu_trainer and other similar types which represent supervised machine learning algorithms. It allows you to write code which contains and processes these trainer objects without needing to know the specific types of trainer objects used.

More Details...
#include <dlib/any.h>
[top]

array

This object represents a 1-Dimensional array of objects.
More Details...
#include <dlib/array.h>
[top]

array2d

This object represents a 2-Dimensional array of objects.

C++ Example Programs: image_ex.cpp
More Details...
#include <dlib/array2d.h>
[top]

binary_search_tree

This object represents a data dictionary that is built on top of some kind of binary search tree.
More Details...
#include <dlib/binary_search_tree.h>

Implementations:
binary_search_tree_kernel_1:
This implementation is done using an AVL binary search tree. It uses the memory_manager for all memory allocations.
kernel_1a
is a typedef for binary_search_tree_kernel_1
kernel_1a_c
 is a typedef for kernel_1a that checks its preconditions.
binary_search_tree_kernel_2:
This implementation is done using a red-black binary search tree. It uses the memory_manager for all memory allocations.
kernel_2a
is a typedef for binary_search_tree_kernel_2
kernel_2a_c
 is a typedef for kernel_2a that checks its preconditions.
[top]

circular_buffer

This object represents a simple sliding buffer which can contain and arbitrary number of elements.
More Details...
#include <dlib/sliding_buffer.h>
[top]

directed_graph

This object represents a directed graph which is a set of nodes with directed edges connecting various nodes.
More Details...
#include <dlib/directed_graph.h>

Implementations:
directed_graph_kernel_1:
This is implemented using std::vector to contain all the nodes and edges.
kernel_1a
is a typedef for directed_graph_kernel_1
kernel_1a_c
 is a typedef for kernel_1a that checks its preconditions.
[top]

enumerable

This object is an abstract class which represents an interface for iterating over all the elements of a container.
More Details...
#include <dlib/interfaces/enumerable.h>
[top]

graph

This object represents a graph which is a set of nodes with undirected edges connecting various nodes.
More Details...
#include <dlib/graph.h>

Implementations:
graph_kernel_1:
This is implemented using std::vector to contain all the nodes and edges.
kernel_1a
is a typedef for graph_kernel_1
kernel_1a_c
 is a typedef for kernel_1a that checks its preconditions.
[top]

hash_map

This object represents a hashed mapping of items of type domain onto items of type range.
More Details...
#include <dlib/hash_map.h>

Implementations:
hash_map_kernel_1:
This implementation is done using a hash_table object. It uses the memory_manager for all memory allocations.
kernel_1a
is a typedef for hash_map_kernel_1 that uses hash_table_kernel_1a
kernel_1a_c
 is a typedef for kernel_1a that checks its preconditions.
kernel_1b
is a typedef for hash_map_kernel_1 that uses hash_table_kernel_2a
kernel_1b_c
 is a typedef for kernel_1b that checks its preconditions.
kernel_1c
is a typedef for hash_map_kernel_1 that uses hash_table_kernel_2b
kernel_1c_c
 is a typedef for kernel_1c that checks its preconditions.
[top]

hash_set

This object represents a hashed unordered and unaddressed collection of unique items.
More Details...
#include <dlib/hash_set.h>

Implementations:
hash_set_kernel_1:
This implementation is done using a hash_table object. It uses the memory_manager for all memory allocations.
kernel_1a
is a typedef for hash_set_kernel_1 that uses hash_table_kernel_1a
kernel_1a_c
 is a typedef for kernel_1a that checks its preconditions.
kernel_1b
is a typedef for hash_set_kernel_1 that uses hash_table_kernel_2a
kernel_1b_c
 is a typedef for kernel_1b that checks its preconditions.
kernel_1c
is a typedef for hash_set_kernel_1 that uses hash_table_kernel_2b
kernel_1c_c
 is a typedef for kernel_1c that checks its preconditions.
[top]

hash_table

This object represents a data dictionary that is built on top of some kind of hash table.
More Details...
#include <dlib/hash_table.h>

Implementations:
hash_table_kernel_1:
This implementation is done using singly linked lists as hashing buckets. It uses the memory_manager for all memory allocations.
kernel_1a
is a typedef for hash_table_kernel_1.
kernel_1a_c
 is a typedef for kernel_1a that checks its preconditions.
hash_table_kernel_2:
This implementation is done using binary_search_tree objects as hashing buckets. It uses the memory_manager for all memory allocations.
kernel_2a
is a typedef for hash_table_kernel_2 that uses binary_search_tree_kernel_1
kernel_2a_c
 is a typedef for kernel_2a that checks its preconditions.
kernel_2b
is a typedef for hash_table_kernel_2 that uses binary_search_tree_kernel_2
kernel_2b_c
 is a typedef for kernel_2b that checks its preconditions.
[top]

map

This object represents a mapping of items of type domain onto items of type range.
More Details...
#include <dlib/map.h>

Implementations:
map_kernel_1:
This is implemented using the binary_search_tree component. It uses the memory_manager for all memory allocations.
kernel_1a
is a typedef for map_kernel_1 that uses binary_search_tree_kernel_1
kernel_1a_c
 is a typedef for kernel_1a that checks its preconditions.
kernel_1b
is a typedef for map_kernel_1 that uses binary_search_tree_kernel_2
kernel_1b_c
 is a typedef for kernel_1b that checks its preconditions.
[top]

map_pair

This object is an abstract class which represents an interface for accessing a pair from a container such as the map, hash_table, etc.
More Details...
#include <dlib/interfaces/map_pair.h>
[top]

queue

This object represents a first in first out queue.

C++ Example Programs: queue_ex.cpp
More Details...
#include <dlib/queue.h>

Implementations:
queue_kernel_1:
This is implemented in the obvious way using a singly linked list. It does not use the memory_manager at all.
kernel_1a
is a typedef for queue_kernel_1
kernel_1a_c
 is a typedef for kernel_1a that checks its preconditions.
queue_kernel_2:
This is implemented using a singly linked list and each node in the list contains block_size (a template parameter) elements. It uses the memory_manager for all memory allocations.
kernel_2a
is a typedef for queue_kernel_2 with a block_size of 20
kernel_2a_c
 is a typedef for kernel_2a that checks its preconditions.
kernel_2b
is a typedef for queue_kernel_2 with a block_size of 100
kernel_2b_c
 is a typedef for kernel_2b that checks its preconditions.

Extensions to queue

queue_sort

This extension gives a queue the ability to sort its contents.

More Details...

Implementations:
queue_sort_1:
This is a version of the QuickSort algorithm.
sort_1a
is a typedef for queue_kernel_1a extended by queue_sort_1
sort_1a_c
 is a typedef for sort_1a that checks its preconditions.
sort_1b
is a typedef for queue_kernel_2a extended by queue_sort_1
sort_1b_c
 is a typedef for sort_1b that checks its preconditions.
sort_1c
is a typedef for queue_kernel_2b extended by queue_sort_1
sort_1c_c
 is a typedef for sort_1c that checks its preconditions.
[top]

reference_counter

This object represents a container for an object and provides reference counting capabilities for the object it contains.
More Details...
#include <dlib/reference_counter.h>

Implementations:
reference_counter_kernel_1:
This implementation is done using pointers in the obvious way.
kernel_1a
is a typedef for reference_counter_kernel_1
[top]

reference_wrapper

This is a simple object that just holds a reference to another object. It is useful because it can serve as a kind of "copyable reference".

C++ Example Programs: thread_function_ex.cpp
More Details...
#include <dlib/ref.h>
[top]

remover

This is a set of interfaces which gives the ability to remove all the items in a container without actually knowing what kind of container contains them.
More Details...
#include <dlib/interfaces/remover.h>
[top]

scoped_ptr

This is a implementation of the scoped_ptr class found in the Boost C++ library. It is a simple smart pointer class which guarantees that the pointer contained within it will always be deleted. The class does not permit copying and so does not do any kind of reference counting. Thus it is very simple and quite fast.
More Details...
#include <dlib/smart_pointers.h>
[top]

sequence

This object represents an ordered sequence of items, each item is associated with an integer value. The items are numbered from 0 to the number of items in the sequence minus 1.
More Details...
#include <dlib/sequence.h>

Implementations:
sequence_kernel_1:
This is implemented as an AVL binary search tree. Accessing(or adding or removing) an element always takes O(log n) time. It uses the memory_manager for all memory allocations.
kernel_1a
is a typedef for sequence_kernel_1
kernel_1a_c
 is a typedef for kernel_1a that checks its preconditions.
sequence_kernel_2:
This implementation is done using a doubly linked list in the shape of a ring. It will remember the last element accessed(or added or removed) and give O(1) access time to the elements just left and right of it. Aside from that, accessing(or adding or removing) a random element will take O(n) and in the worst case it will take time proportional to the size of the sequence/2.

It does not use the memory_manager at all.

kernel_2a
is a typedef for sequence_kernel_2
kernel_2a_c
 is a typedef for kernel_2a that checks its preconditions.

Extensions to sequence

sequence_compare

This extension gives sequences the ability to compare themselves using operator< and operator==. Thus they can be used in the other container classes that require this ability. (maps, sets, etc.)

More Details...

Implementations:
sequence_compare_1:
The implementation is obvious. Click on the sequence_compare_1 link if you want to see.
compare_1a
is a typedef for sequence_kernel_1a extended by sequence_compare_1
compare_1a_c
 is a typedef for compare_1a that checks its preconditions.
compare_1b
is a typedef for sequence_kernel_2a extended by sequence_compare_1
compare_1b_c
 is a typedef for compare_1b that checks its preconditions.
sequence_sort

This extension gives a sequence the ability to sort its contents.

More Details...

Implementations:
sequence_sort_1:
This is a version of the QuickSort algorithm and it sorts sequences of less than 30 elements with a selection sort. This implementation is fastest when used with sequence_kernel_2 and fairly slow when used with sequence_kernel_1
sort_1a
is a typedef for sequence_kernel_2a extended by sequence_sort_1
sort_1a_c
 is a typedef for sort_1a that checks its preconditions.
sequence_sort_2:
This is a version of the QuickSort algorithm. This implementation of sort is the best to use with sequence_kernel_1 objects but gives extremely poor performance with sequence_kernel_2 objects.
sort_2a
is a typedef for sequence_kernel_1a extended by sequence_sort_2
sort_2a_c
 is a typedef for sort_2a that checks its preconditions.
[top]

set

This object represents an unordered and unaddressed collection of unique items.
More Details...
#include <dlib/set.h>

Implementations:
set_kernel_1:
This is implemented using the binary_search_tree component. It uses the memory_manager for all memory allocations.
kernel_1a
is a typedef for set_kernel_1 that uses binary_search_tree_kernel_1
kernel_1a_c
 is a typedef for kernel_1a that checks its preconditions.
kernel_1b
is a typedef for set_kernel_1 that uses binary_search_tree_kernel_2
kernel_1b_c
 is a typedef for kernel_1b that checks its preconditions.

Extensions to set

set_compare

This extension gives sets the ability to compare themselves using operator< and operator==. Thus they can be used in the other container classes that require this ability. (maps, sets, etc.)

More Details...

Implementations:
set_compare_1:
The implementation is obvious. Click on the set_compare_1 link if you want to see.
compare_1a
is a typedef for set_kernel_1a extended by set_compare_1
compare_1a_c
 is a typedef for compare_1a that checks its preconditions.
compare_1b
is a typedef for set_kernel_1b extended by set_compare_1
compare_1b_c
 is a typedef for compare_1b that checks its preconditions.
[top]

shared_ptr

This object represents a reference counted smart pointer. Each shared_ptr contains a pointer to some object and when the last shared_ptr that points to the object is destructed or reset() then the object is guaranteed to be deleted.

This is an implementation of the std::tr1::shared_ptr template from the document ISO/IEC PDTR 19768, Proposed Draft Technical Report on C++ Library Extensions. The only deviation from that document is that this shared_ptr is declared inside the dlib namespace rather than std::tr1.

More Details...
#include <dlib/smart_pointers.h>
[top]

shared_ptr_thread_safe

This object represents a reference counted smart pointer just like shared_ptr except that it is threadsafe.

More Details...
#include <dlib/smart_pointers_thread_safe.h>
[top]

sliding_buffer

This object represents an array with the ability to rotate its contents left or right. Note that the size of this object is always a power of two. If you need arbitrary sized objects then use a circular_buffer.
More Details...
#include <dlib/sliding_buffer.h>

Implementations:
sliding_buffer_kernel_1:
This object is implemented using a C style array in the obvious way. See the code for details.
kernel_1a
is a typedef for sliding_buffer_kernel_1
kernel_1a_c
 is a typedef for kernel_1a that checks its preconditions.
[top]

stack

This object represents a last in first out stack.
More Details...
#include <dlib/stack.h>

Implementations:
stack_kernel_1:
This implementation is done in the obvious way using a singly linked list. It uses the memory_manager for all memory allocations.
kernel_1a
is a typedef for stack_kernel_1
kernel_1a_c
 is a typedef for kernel_1a that checks its preconditions.
[top]

static_map

This object represents a mapping of items of type domain onto items of type range. The difference between this object and the normal map object is that it does not support adding or removing individual objects from itself. This allows implementations to focus on using less memory and achieving faster searching.
More Details...
#include <dlib/static_map.h>

Implementations:
static_map_kernel_1:
This implementation is just a sorted array which can be searched using a binary search.
kernel_1a
is a typedef for static_map_kernel_1
kernel_1a_c
 is a typedef for kernel_1a that checks its preconditions.
[top]

static_set

This object represents an unordered and unaddressed collection of items. The difference between this object and the normal set object is that it does not support adding or removing individual objects from itself. This allows implementations to focus on using less memory and achieving faster searching.
More Details...
#include <dlib/static_set.h>

Implementations:
static_set_kernel_1:
This implementation is just a sorted array which can be searched using a binary search.
kernel_1a
is a typedef for static_set_kernel_1
kernel_1a_c
 is a typedef for kernel_1a that checks its preconditions.

Extensions to static_set

static_set_compare

This extension gives static_sets the ability to compare themselves using operator< and operator==. Thus they can be used in the other container classes that require this ability. (maps, static_sets, etc.)

More Details...

Implementations:
static_set_compare_1:
The implementation is obvious. Click on the static_set_compare_1 link if you want to see.
compare_1a
is a typedef for static_set_kernel_1a extended by static_set_compare_1
compare_1a_c
 is a typedef for compare_1a that checks its preconditions.
[top]

std_vector_c

This object is a simple wrapper around the std::vector object. It provides an identical interface but also checks the preconditions of each member function. That is, if you violate a requires clause the dlib::fatal_error exception is thrown.
More Details...
#include <dlib/stl_checked.h>
[top]

tuple

This is an implementation of a very simple templated container object. It contains between 0 and 31 objects where each object is listed explicitly in the tuple's template arguments.

Note that there is only one implementation of this object so there aren't any different kernels to choose from when you create instances of the tuple object. So for example, you could declare a tuple of 3 ints using the following statement: dlib::tuple<int,int,int> t;

More Details...
#include <dlib/tuple.h>
[top]

type_safe_union

This object is a type safe analogue of the classic C union object. The type_safe_union, unlike a union, can contain non-POD types such as std::string.

It is also implemented without performing any heap memory allocations and instead it stores everything on the stack.

C++ Example Programs: pipe_ex_2.cpp, bridge_ex.cpp
More Details...
#include <dlib/type_safe_union.h>
[top]

unordered_pair

This object is very similar to the std::pair struct except unordered_pair is only capable of representing an unordered set of two items rather than an ordered list of two items like std::pair.
More Details...
#include <dlib/unordered_pair.h>
[top]

weak_ptr

The weak_ptr class template stores a weak reference to an object that is already managed by a shared_ptr. To access the object, a weak_ptr can be converted to a shared_ptr using the member function lock().

This is an implementation of the std::tr1::weak_ptr template from the document ISO/IEC PDTR 19768, Proposed Draft Technical Report on C++ Library Extensions. The only deviation from that document is that this shared_ptr is declared inside the dlib namespace rather than std::tr1.

More Details...
#include <dlib/smart_pointers.h>


dlib C++ Library - any_abstract.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_AnY_ABSTRACT_H_
#ifdef DLIB_AnY_ABSTRACT_H_

#include <typeinfo>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class bad_any_cast : public std::bad_cast
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is the exception class used by the any object.
                It is used to indicate when someone attempts to cast an any
                object into a type which isn't contained in the any object.
        !*/

    public:
          virtual const char* what() const throw() { return "bad_any_cast"; }
    };

// ----------------------------------------------------------------------------------------

    class any
    {
        /*!
            INITIAL VALUE
                - is_empty() == true
                - for all T: contains<T>() == false

            WHAT THIS OBJECT REPRESENTS
                This object is basically a type-safe version of a void*.  In particular,
                it is a container which can contain only one object but the object may
                be of any type.

                It is somewhat like the type_safe_union except you don't have to declare
                the set of possible content types beforehand.  So in some sense this is
                like a less type-strict version of the type_safe_union.
        !*/

    public:

        any(
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        any (
            const any& item
        );
        /*!
            ensures
                - copies the state of item into *this.
                - Note that *this and item will contain independent copies of the
                  contents of item.  That is, this function performs a deep
                  copy and therefore does not result in *this containing
                  any kind of reference to item.
        !*/

        template < typename T >
        any (
            const T& item
        );
        /*!
            ensures
                - #contains<T>() == true
                - #cast_to<T>() == item
                  (i.e. a copy of item will be stored in *this)
        !*/

        void clear (
        );
        /*!
            ensures
                - #*this will have its default value.  I.e. #is_empty() == true
        !*/

        template <typename T>
        bool contains (
        ) const;
        /*!
            ensures
                - if (this object currently contains an object of type T) then
                    - returns true
                - else
                    - returns false
        !*/

        bool is_empty(
        ) const;
        /*!
            ensures
                - if (this object contains any kind of object) then
                    - returns false
                - else
                    - returns true
        !*/

        template <typename T>
        T& cast_to(
        );
        /*!
            ensures
                - if (contains<T>() == true) then
                    - returns a non-const reference to the object contained within *this
                - else
                    - throws bad_any_cast
        !*/

        template <typename T>
        const T& cast_to(
        ) const;
        /*!
            ensures
                - if (contains<T>() == true) then
                    - returns a const reference to the object contained within *this
                - else
                    - throws bad_any_cast
        !*/

        template <typename T>
        T& get(
        );
        /*!
            ensures
                - #is_empty() == false
                - #contains<T>() == true
                - if (contains<T>() == true)
                    - returns a non-const reference to the object contained in *this.
                - else
                    - Constructs an object of type T inside *this
                    - Any previous object stored in this any object is destructed and its
                      state is lost.
                    - returns a non-const reference to the newly created T object.
        !*/

        any& operator= (
            const any& item
        );
        /*!
            ensures
                - copies the state of item into *this.
                - Note that *this and item will contain independent copies of the
                  contents of item.  That is, this function performs a deep
                  copy and therefore does not result in *this containing
                  any kind of reference to item.
        !*/

        void swap (
            any& item
        );
        /*!
            ensures
                - swaps *this and item
                - does not invalidate pointers or references to the object contained
                  inside *this or item.  Moreover, a pointer or reference to the object in
                  *this will now refer to the contents of #item and vice versa.
        !*/

    };

// ----------------------------------------------------------------------------------------

    inline void swap (
        any& a,
        any& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    T& any_cast(
        any& a
    ) { return a.cast_to<T>(); }
    /*!
        ensures
            - returns a.cast_to<T>()
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    const T& any_cast(
        const any& a
    ) { return a.cast_to<T>(); }
    /*!
        ensures
            - returns a.cast_to<T>()
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_AnY_ABSTRACT_H_


dlib C++ Library - any_decision_function_abstract.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_AnY_DECISION_FUNCTION_ABSTRACT_H_
#ifdef DLIB_AnY_DECISION_FUNCTION_ABSTRACT_H_

#include "any_abstract.h"
#include "../algs.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename sample_type_,
        typename result_type_ = double
        >
    class any_decision_function
    {
        /*!
            INITIAL VALUE
                - is_empty() == true
                - for all T: contains<T>() == false

            WHAT THIS OBJECT REPRESENTS
                This object is a version of dlib::any that is restricted to containing
                elements which are some kind of function object with an operator() with
                the following signature:
                    result_type operator()(const sample_type&) const

                It is intended to be used to contain dlib::decision_function objects and
                other types which represent learned decision functions.  It allows you
                to write code which contains and processes these decision functions
                without needing to know the specific types of decision functions used.
        !*/

    public:

        typedef sample_type_ sample_type;
        typedef result_type_ result_type;
        typedef default_memory_manager mem_manager_type;

        any_decision_function(
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        any_decision_function (
            const any_decision_function& item
        );
        /*!
            ensures
                - copies the state of item into *this.
                - Note that *this and item will contain independent copies of the
                  contents of item.  That is, this function performs a deep
                  copy and therefore does not result in *this containing
                  any kind of reference to item.
        !*/

        template < typename T >
        any_decision_function (
            const T& item
        );
        /*!
            ensures
                - #contains<T>() == true
                - #cast_to<T>() == item
                  (i.e. a copy of item will be stored in *this)
        !*/

        void clear (
        );
        /*!
            ensures
                - #*this will have its default value.  I.e. #is_empty() == true
        !*/

        template <typename T>
        bool contains (
        ) const;
        /*!
            ensures
                - if (this object currently contains an object of type T) then
                    - returns true
                - else
                    - returns false
        !*/

        bool is_empty(
        ) const;
        /*!
            ensures
                - if (this object contains any kind of object) then
                    - returns false
                - else
                    - returns true
        !*/

        result_type operator() (
            const sample_type& item
        ) const;
        /*!
            requires
                - is_empty() == false
            ensures
                - Let F denote the function object contained within *this.  Then
                  this function performs:
                    return F(item)
        !*/

        template <typename T>
        T& cast_to(
        );
        /*!
            ensures
                - if (contains<T>() == true) then
                    - returns a non-const reference to the object contained within *this
                - else
                    - throws bad_any_cast
        !*/

        template <typename T>
        const T& cast_to(
        ) const;
        /*!
            ensures
                - if (contains<T>() == true) then
                    - returns a const reference to the object contained within *this
                - else
                    - throws bad_any_cast
        !*/

        template <typename T>
        T& get(
        );
        /*!
            ensures
                - #is_empty() == false
                - #contains<T>() == true
                - if (contains<T>() == true)
                    - returns a non-const reference to the object contained in *this.
                - else
                    - Constructs an object of type T inside *this
                    - Any previous object stored in this any_decision_function object is destructed and its
                      state is lost.
                    - returns a non-const reference to the newly created T object.
        !*/

        any_decision_function& operator= (
            const any_decision_function& item
        );
        /*!
            ensures
                - copies the state of item into *this.
                - Note that *this and item will contain independent copies of the
                  contents of item.  That is, this function performs a deep
                  copy and therefore does not result in *this containing
                  any kind of reference to item.
        !*/

        void swap (
            any_decision_function& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <
        typename sample_type,
        typename result_type
        >
    inline void swap (
        any_decision_function<sample_type,result_type>& a,
        any_decision_function<sample_type,result_type>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename sample_type,
        typename result_type
        >
    T& any_cast(
        any_decision_function<sample_type,result_type>& a
    ) { return a.cast_to<T>(); }
    /*!
        ensures
            - returns a.cast_to<T>()
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename sample_type,
        typename result_type
        >
    const T& any_cast(
        const any_decision_function<sample_type,result_type>& a
    ) { return a.cast_to<T>(); }
    /*!
        ensures
            - returns a.cast_to<T>()
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_AnY_DECISION_FUNCTION_ABSTRACT_H_


dlib C++ Library - any_function_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_AnY_FUNCTION_ABSTRACT_H_
#ifdef DLIB_AnY_FUNCTION_ABSTRACT_H_

#include "any_abstract.h"
#include "../algs.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename function_type
        >
    class any_function
    {
        /*!
            REQUIREMENTS ON function_type
                This type should be a function signature.  Some examples are:
                    void (int,int)  // a function returning nothing and taking two ints
                    void ()         // a function returning nothing and taking no arguments
                    char (double&)  // a function returning a char and taking a reference to a double

                The number of arguments in the function must be no greater than 10.

            INITIAL VALUE
                - is_empty() == true
                - for all T: contains<T>() == false

            WHAT THIS OBJECT REPRESENTS
                This object is a version of dlib::any that is restricted to containing
                elements which are some kind of function object with an operator() which
                matches the function signature defined by function_type.

                Here is an example:
                    #include <iostream>
                    #include <string>
                    #include "dlib/any.h"
                    using namespace std;
                    void print_message(string str) { cout << str << endl; }

                    int main()
                    {
                        dlib::any_function<void(string)> f;
                        f = print_message;
                        f("hello world"); // calls print_message("hello world")
                    }

                Note that any_function objects can be used to store general function
                objects (i.e. defined by a class with an overloaded operator()) in
                addition to regular global functions.
        !*/

    public:

        // This is the type of object returned by function_type functions.
        typedef result_type_for_function_type result_type;
        // Typedefs defining the argument types.  If an argument does not exist
        // then it is set to void.
        typedef type_of_first_argument_in_funct_type  arg1_type;
        typedef type_of_second_argument_in_funct_type arg2_type;
        ...
        typedef type_of_last_argument_in_funct_type   arg10_type;
        const static unsigned long num_args = total_number_of_non_void_arguments;

        any_function(
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        any_function (
            const any_function& item
        );
        /*!
            ensures
                - copies the state of item into *this.
                - Note that *this and item will contain independent copies of the
                  contents of item.  That is, this function performs a deep
                  copy and therefore does not result in *this containing
                  any kind of reference to item.
        !*/

        template < typename T >
        any_function (
            const T& item
        );
        /*!
            ensures
                - #contains<T>() == true
                - #cast_to<T>() == item
                  (i.e. a copy of item will be stored in *this)
        !*/

        void clear (
        );
        /*!
            ensures
                - #*this will have its default value.  I.e. #is_empty() == true
        !*/

        template <typename T>
        bool contains (
        ) const;
        /*!
            ensures
                - if (this object currently contains an object of type T) then
                    - returns true
                - else
                    - returns false
        !*/

        bool is_empty(
        ) const;
        /*!
            ensures
                - if (this object contains any kind of object) then
                    - returns false
                - else
                    - returns true
        !*/

        bool is_set (
        ) const;
        /*!
            ensures
                - returns !is_empty()
        !*/

        result_type operator() (
        ) const;
        /*!
            requires
                - is_empty() == false
                - the signature defined by function_type takes no arguments
            ensures
                - Let F denote the function object contained within *this.  Then
                  this function performs:
                    return F()
                  or if result_type is void then this function performs:
                    F()
        !*/

        result_type operator() (
            const arg1_type& a1
        ) const;
        /*!
            requires
                - is_empty() == false
                - the signature defined by function_type takes one argument
            ensures
                - Let F denote the function object contained within *this.  Then
                  this function performs:
                    return F(a1)
                  or if result_type is void then this function performs:
                    F(a1)
        !*/

        result_type operator() (
            const arg1_type& a1,
            const arg2_type& a2
        ) const;
        /*!
            requires
                - is_empty() == false
                - the signature defined by function_type takes two arguments
            ensures
                - Let F denote the function object contained within *this.  Then
                  this function performs:
                    return F(a1,a2)
                  or if result_type is void then this function performs:
                    F(a1,a2)
        !*/

        /* !!!!!!!!!  NOTE  !!!!!!!!!

           In addition to the above, operator() is defined for up to 10 arguments.
           They are not listed here because it would clutter the documentation.

           !!!!!!!!!  NOTE  !!!!!!!!!  */

        template <typename T>
        T& cast_to(
        );
        /*!
            ensures
                - if (contains<T>() == true) then
                    - returns a non-const reference to the object contained within *this
                - else
                    - throws bad_any_cast
        !*/

        template <typename T>
        const T& cast_to(
        ) const;
        /*!
            ensures
                - if (contains<T>() == true) then
                    - returns a const reference to the object contained within *this
                - else
                    - throws bad_any_cast
        !*/

        template <typename T>
        T& get(
        );
        /*!
            ensures
                - #is_empty() == false
                - #contains<T>() == true
                - if (contains<T>() == true)
                    - returns a non-const reference to the object contained in *this.
                - else
                    - Constructs an object of type T inside *this
                    - Any previous object stored in this any_function object is destructed and its
                      state is lost.
                    - returns a non-const reference to the newly created T object.
        !*/

        any_function& operator= (
            const any_function& item
        );
        /*!
            ensures
                - copies the state of item into *this.
                - Note that *this and item will contain independent copies of the
                  contents of item.  That is, this function performs a deep
                  copy and therefore does not result in *this containing
                  any kind of reference to item.
        !*/

        void swap (
            any_function& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <
        typename function_type
        >
    inline void swap (
        any_function<function_type>& a,
        any_function<function_type>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename function_type
        >
    T& any_cast(
        any_function<function_type>& a
    ) { return a.cast_to<T>(); }
    /*!
        ensures
            - returns a.cast_to<T>()
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename function_type
        >
    const T& any_cast(
        const any_function<function_type>& a
    ) { return a.cast_to<T>(); }
    /*!
        ensures
            - returns a.cast_to<T>()
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_AnY_FUNCTION_ABSTRACT_H_


dlib C++ Library - any_trainer_abstract.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_AnY_TRAINER_ABSTRACT_H_
#ifdef DLIB_AnY_TRAINER_ABSTRACT_H_

#include "any_abstract.h"
#include "../algs.h"
#include "any_decision_function_abstract.h"
#include <vector>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename sample_type_,
        typename scalar_type_ = double
        >
    class any_trainer
    {
        /*!
            INITIAL VALUE
                - is_empty() == true
                - for all T: contains<T>() == false

            WHAT THIS OBJECT REPRESENTS
                This object is a version of dlib::any that is restricted to containing
                elements which are some kind of object with a .train() method compatible
                with the following signature:

                    decision_function train(
                        const std::vector<sample_type>& samples,
                        const std::vector<scalar_type>& labels
                    ) const

                    Where decision_function is a type capable of being stored in an
                    any_decision_function<sample_type,scalar_type> object.

                any_trainer is intended to be used to contain objects such as the svm_nu_trainer
                and other similar types which represent supervised machine learning algorithms.
                It allows you to write code which contains and processes these trainer objects
                without needing to know the specific types of trainer objects used.
        !*/

    public:

        typedef sample_type_ sample_type;
        typedef scalar_type_ scalar_type;
        typedef default_memory_manager mem_manager_type;
        typedef any_decision_function<sample_type, scalar_type> trained_function_type;

        any_trainer(
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        any_trainer (
            const any_trainer& item
        );
        /*!
            ensures
                - copies the state of item into *this.
                - Note that *this and item will contain independent copies of the
                  contents of item.  That is, this function performs a deep
                  copy and therefore does not result in *this containing
                  any kind of reference to item.
        !*/

        template < typename T >
        any_trainer (
            const T& item
        );
        /*!
            ensures
                - #contains<T>() == true
                - #cast_to<T>() == item
                  (i.e. a copy of item will be stored in *this)
        !*/

        void clear (
        );
        /*!
            ensures
                - #*this will have its default value.  I.e. #is_empty() == true
        !*/

        template <typename T>
        bool contains (
        ) const;
        /*!
            ensures
                - if (this object currently contains an object of type T) then
                    - returns true
                - else
                    - returns false
        !*/

        bool is_empty(
        ) const;
        /*!
            ensures
                - if (this object contains any kind of object) then
                    - returns false
                - else
                    - returns true
        !*/

        trained_function_type train (
            const std::vector<sample_type>& samples,
            const std::vector<scalar_type>& labels
        ) const
        /*!
            requires
                - is_empty() == false
            ensures
                - Let TRAINER denote the object contained within *this.  Then
                  this function performs:
                    return TRAINER.train(samples, labels)
        !*/

        template <typename T>
        T& cast_to(
        );
        /*!
            ensures
                - if (contains<T>() == true) then
                    - returns a non-const reference to the object contained within *this
                - else
                    - throws bad_any_cast
        !*/

        template <typename T>
        const T& cast_to(
        ) const;
        /*!
            ensures
                - if (contains<T>() == true) then
                    - returns a const reference to the object contained within *this
                - else
                    - throws bad_any_cast
        !*/

        template <typename T>
        T& get(
        );
        /*!
            ensures
                - #is_empty() == false
                - #contains<T>() == true
                - if (contains<T>() == true)
                    - returns a non-const reference to the object contained in *this.
                - else
                    - Constructs an object of type T inside *this
                    - Any previous object stored in this any_trainer object is destructed and its
                      state is lost.
                    - returns a non-const reference to the newly created T object.
        !*/

        any_trainer& operator= (
            const any_trainer& item
        );
        /*!
            ensures
                - copies the state of item into *this.
                - Note that *this and item will contain independent copies of the
                  contents of item.  That is, this function performs a deep
                  copy and therefore does not result in *this containing
                  any kind of reference to item.
        !*/

        void swap (
            any_trainer& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <
        typename sample_type,
        typename scalar_type
        >
    inline void swap (
        any_trainer<sample_type,scalar_type>& a,
        any_trainer<sample_type,scalar_type>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename sample_type,
        typename scalar_type
        >
    T& any_cast(
        any_trainer<sample_type,scalar_type>& a
    ) { return a.cast_to<T>(); }
    /*!
        ensures
            - returns a.cast_to<T>()
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename sample_type,
        typename scalar_type
        >
    const T& any_cast(
        const any_trainer<sample_type,scalar_type>& a
    ) { return a.cast_to<T>(); }
    /*!
        ensures
            - returns a.cast_to<T>()
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_AnY_TRAINER_ABSTRACT_H_


dlib C++ Library - array_kernel_abstract.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_ARRAY_KERNEl_ABSTRACT_
#ifdef DLIB_ARRAY_KERNEl_ABSTRACT_

#include "../interfaces/enumerable.h"
#include "../serialize.h"
#include "../algs.h"

namespace dlib
{

    template <
        typename T,
        typename mem_manager = default_memory_manager
        >
    class array : public enumerable<T>
    {

        /*!
            REQUIREMENTS ON T
                T must have a default constructor.

            REQUIREMENTS ON mem_manager
                must be an implementation of memory_manager/memory_manager_kernel_abstract.h or
                must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or
                must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h
                mem_manager::type can be set to anything.

            POINTERS AND REFERENCES TO INTERNAL DATA
                front(), back(), swap(), max_size(), set_size(), and operator[]
                functions do not invalidate pointers or references to internal data.
                All other functions have no such guarantee.

            INITIAL VALUE
                size() == 0
                max_size() == 0

            ENUMERATION ORDER
                The enumerator will iterate over the elements of the array in the
                order (*this)[0], (*this)[1], (*this)[2], ...

            WHAT THIS OBJECT REPRESENTS
                This object represents an ordered 1-dimensional array of items,
                each item is associated with an integer value.  The items are
                numbered from 0 though size() - 1 and the operator[] functions
                run in constant time.

                Also note that unless specified otherwise, no member functions
                of this object throw exceptions.
        !*/

        public:

            typedef T type;
            typedef T value_type;
            typedef mem_manager mem_manager_type;

            array (
            );
            /*!
                ensures
                    - #*this is properly initialized
                throws
                    - std::bad_alloc or any exception thrown by T's constructor
            !*/

            explicit array (
                unsigned long new_size
            );
            /*!
                ensures
                    - #*this is properly initialized
                    - #size() == new_size
                    - #max_size() == new_size
                    - All elements of the array will have initial values for their type.
                throws
                    - std::bad_alloc or any exception thrown by T's constructor
            !*/

            ~array (
            );
            /*!
                ensures
                    - all memory associated with *this has been released
            !*/

            void clear (
            );
            /*!
                ensures
                    - #*this has its initial value
                throws
                    - std::bad_alloc or any exception thrown by T's constructor
                        if this exception is thrown then the array object is unusable
                        until clear() is called and succeeds
            !*/

            const T& operator[] (
                unsigned long pos
            ) const;
            /*!
                requires
                    - pos < size()
                ensures
                    - returns a const reference to the element at position pos
            !*/

            T& operator[] (
                unsigned long pos
            );
            /*!
                requires
                    - pos < size()
                ensures
                    - returns a non-const reference to the element at position pos
            !*/

            void set_size (
                unsigned long size
            );
            /*!
                requires
                    - size <= max_size()
                ensures
                    - #size() == size
                    - any element with index between 0 and size - 1 which was in the
                      array before the call to set_size() retains its value and index.
                      All other elements have undetermined (but valid for their type)
                      values.  (e.g. this object might buffer old T objects and reuse
                      them without reinitializing them between calls to set_size())
                    - #at_start() == true
                throws
                    - std::bad_alloc or any exception thrown by T's constructor
                        may throw this exception if there is not enough memory and
                        if it does throw then the call to set_size() has no effect
            !*/

            unsigned long max_size(
            ) const;
            /*!
                ensures
                    - returns the maximum size of *this
            !*/

            void set_max_size(
                unsigned long max
            );
            /*!
                ensures
                    - #max_size() == max
                    - #size() == 0
                    - #at_start() == true
                throws
                    - std::bad_alloc or any exception thrown by T's constructor
                        may throw this exception if there is not enough
                        memory and if it does throw then max_size() == 0
            !*/

            void swap (
                array<T>& item
            );
            /*!
                ensures
                    - swaps *this and item
            !*/

            void sort (
            );
            /*!
                requires
                    - T must be a type with that is comparable via operator<
                ensures
                    - for all elements in #*this the ith element is <= the i+1 element
                    - #at_start() == true
                throws
                    - std::bad_alloc or any exception thrown by T's constructor
                        data may be lost if sort() throws
            !*/

            void resize (
                unsigned long new_size
            );
            /*!
                ensures
                    - #size() == new_size
                    - #max_size() == max(new_size,max_size())
                    - for all i < size() && i < new_size:
                        - #(*this)[i] == (*this)[i]
                          (i.e. All the original elements of *this which were at index
                          values less than new_size are unmodified.)
                    - for all valid i >= size():
                        - #(*this)[i] has an undefined value
                          (i.e. any new elements of the array have an undefined value)
                throws
                    - std::bad_alloc or any exception thrown by T's constructor.
                       If an exception is thrown then it has no effect on *this.
            !*/

            const T& back (
            ) const;
            /*!
                requires
                    - size() != 0
                ensures
                    - returns a const reference to (*this)[size()-1]
            !*/

            T& back (
            );
            /*!
                requires
                    - size() != 0
                ensures
                    - returns a non-const reference to (*this)[size()-1]
            !*/

            void pop_back (
                T& item
            );
            /*!
                requires
                    - size() != 0
                ensures
                    - #size() == size() - 1
                    - swaps (*this)[size()-1] into item
                    - All elements with an index less than size()-1 are
                      unmodified by this operation.
            !*/

            void pop_back (
            );
            /*!
                requires
                    - size() != 0
                ensures
                    - #size() == size() - 1
                    - All elements with an index less than size()-1 are
                      unmodified by this operation.
            !*/

            void push_back (
                T& item
            );
            /*!
                ensures
                    - #size() == size()+1
                    - swaps item into (*this)[#size()-1]
                    - #back() == item
                    - #item has some undefined value (whatever happens to
                      get swapped out of the array)
                throws
                    - std::bad_alloc or any exception thrown by T's constructor.
                       If an exception is thrown then it has no effect on *this.
            !*/

            typedef T* iterator;
            typedef const T* const_iterator;

            iterator begin(
            );
            /*!
                ensures
                    - returns an iterator that points to the first element in this array or
                      end() if the array is empty.
            !*/

            const_iterator begin(
            ) const;
            /*!
                ensures
                    - returns a const iterator that points to the first element in this
                      array or end() if the array is empty.
            !*/

            iterator end(
            );
            /*!
                ensures
                    - returns an iterator that points to one past the end of the array.
            !*/

            const_iterator end(
            ) const;
            /*!
                ensures
                    - returns a const iterator that points to one past the end of the
                      array.
            !*/

        private:

            // restricted functions
            array(array<T>&);        // copy constructor
            array<T>& operator=(array<T>&);    // assignment operator

    };

    template <
        typename T
        >
    inline void swap (
        array<T>& a,
        array<T>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

    template <
        typename T
        >
    void serialize (
        const array<T>& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

    template <
        typename T
        >
    void deserialize (
        array<T>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

}

#endif // DLIB_ARRAY_KERNEl_ABSTRACT_


dlib C++ Library - array2d_kernel_abstract.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_ARRAY2D_KERNEl_ABSTRACT_
#ifdef DLIB_ARRAY2D_KERNEl_ABSTRACT_

#include "../interfaces/enumerable.h"
#include "../serialize.h"
#include "../algs.h"
#include "../geometry/rectangle_abstract.h"

namespace dlib
{

    template <
        typename T,
        typename mem_manager = default_memory_manager
        >
    class array2d : public enumerable<T>
    {

        /*!
            REQUIREMENTS ON T
                T must have a default constructor.

            REQUIREMENTS ON mem_manager
                must be an implementation of memory_manager/memory_manager_kernel_abstract.h or
                must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or
                must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h
                mem_manager::type can be set to anything.

            POINTERS AND REFERENCES TO INTERNAL DATA
                No member functions in this object will invalidate pointers
                or references to internal data except for the set_size()
                and clear() member functions.

            INITIAL VALUE
                nr() == 0
                nc() == 0

            ENUMERATION ORDER
                The enumerator will iterate over the elements of the array starting
                with row 0 and then proceeding to row 1 and so on.  Each row will be
                fully enumerated before proceeding on to the next row and the elements
                in a row will be enumerated beginning with the 0th column, then the 1st
                column and so on.

            WHAT THIS OBJECT REPRESENTS
                This object represents a 2-Dimensional array of objects of
                type T.

                Also note that unless specified otherwise, no member functions
                of this object throw exceptions.

                Finally, note that this object stores its data contiguously and in
                row major order.  Moreover, there is no padding at the end of each row.
                This means that its width_step() value is always equal to sizeof(type)*nc().
        !*/

    public:

        // ----------------------------------------

        typedef T type;
        typedef mem_manager mem_manager_type;

        // ----------------------------------------

        class row
        {
            /*!
                POINTERS AND REFERENCES TO INTERNAL DATA
                    No member functions in this object will invalidate pointers
                    or references to internal data.

                WHAT THIS OBJECT REPRESENTS
                    This object represents a row of Ts in an array2d object.
            !*/
        public:
            long nc (
            ) const;
            /*!
                ensures
                    - returns the number of columns in this row
            !*/

            const T& operator[] (
                long column
            ) const;
            /*!
                requires
                    - 0 <= column < nc()
                ensures
                    - returns a const reference to the T in the given column
            !*/

            T& operator[] (
                long column
            );
            /*!
                requires
                    - 0 <= column < nc()
                ensures
                    - returns a non-const reference to the T in the given column
            !*/

        private:
            // restricted functions
            row();
            row& operator=(row&);
        };

        // ----------------------------------------

        array2d (
        );
        /*!
            ensures
                - #*this is properly initialized
            throws
                - std::bad_alloc
        !*/

        array2d (
            long rows,
            long cols
        );
        /*!
            requires
                - rows >= 0 && cols >= 0
            ensures
                - #nc() == cols
                - #nr() == rows
                - #at_start() == true
                - all elements in this array have initial values for their type
            throws
                - std::bad_alloc
        !*/

        virtual ~array2d (
        );
        /*!
            ensures
                - all resources associated with *this has been released
        !*/

        void clear (
        );
        /*!
            ensures
                - #*this has an initial value for its type
        !*/

        long nc (
        ) const;
        /*!
            ensures
                - returns the number of elements there are in a row.  i.e. returns
                  the number of columns in *this
        !*/

        long nr (
        ) const;
        /*!
            ensures
                - returns the number of rows in *this
        !*/

        void set_size (
            long rows,
            long cols
        );
        /*!
            requires
                - rows >= 0 && cols >= 0
            ensures
                - #nc() == cols
                - #nr() == rows
                - #at_start() == true
                - if (the call to set_size() doesn't change the dimensions of this array) then
                    - all elements in this array retain their values from before this function was called
                - else
                    - all elements in this array have initial values for their type
            throws
                - std::bad_alloc
                    If this exception is thrown then #*this will have an initial
                    value for its type.
        !*/

        row operator[] (
            long row_index
        );
        /*!
            requires
                - 0 <= row_index < nr()
            ensures
                - returns a non-const row of nc() elements that represents the
                  given row_index'th row in *this.
        !*/

        const row operator[] (
            long row_index
        ) const;
        /*!
            requires
                - 0 <= row_index < nr()
            ensures
                - returns a const row of nc() elements that represents the
                  given row_index'th row in *this.
        !*/

        void swap (
            array2d& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/

        long width_step (
        ) const;
        /*!
            ensures
                - returns the size of one row of the image, in bytes.
                  More precisely, return a number N such that:
                  (char*)&item[0][0] + N == (char*)&item[1][0].
                - for dlib::array2d objects, the returned value
                  is always equal to sizeof(type)*nc().  However,
                  other objects which implement dlib::array2d style
                  interfaces might have padding at the ends of their
                  rows and therefore might return larger numbers.
                  An example of such an object is the dlib::cv_image.
        !*/

    private:

        // restricted functions
        array2d(array2d&);        // copy constructor
        array2d& operator=(array2d&);    // assignment operator

    };

    template <
        typename T,
        typename mem_manager
        >
    inline void swap (
        array2d<T,mem_manager>& a,
        array2d<T,mem_manager>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

    template <
        typename T,
        typename mem_manager
        >
    void serialize (
        const array2d<T,mem_manager>& item,
        std::ostream& out
    );
    /*!
        Provides serialization support.  Note that the serialization formats used by the
        dlib::matrix and dlib::array2d objects are compatible.  That means you can load the
        serialized data from one into another and it will work properly.
    !*/

    template <
        typename T,
        typename mem_manager
        >
    void deserialize (
        array2d<T,mem_manager>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

}

#endif // DLIB_ARRAY2D_KERNEl_ABSTRACT_


dlib C++ Library - binary_search_tree_kernel_abstract.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_BINARY_SEARCH_TREE_KERNEl_ABSTRACT_
#ifdef DLIB_BINARY_SEARCH_TREE_KERNEl_ABSTRACT_

#include "../interfaces/map_pair.h"
#include "../interfaces/enumerable.h"
#include "../interfaces/remover.h"
#include "../serialize.h"
#include "../algs.h"
#include <functional>

namespace dlib
{

    template <
        typename domain,
        typename range,
        typename mem_manager = default_memory_manager,
        typename compare = std::less<domain>
        >
    class binary_search_tree : public enumerable<map_pair<domain,range> >,
                               public asc_pair_remover<domain,range,compare>
    {

        /*!
            REQUIREMENTS ON domain
                domain must be comparable by compare where compare is a functor compatible with std::less and
                domain is swappable by a global swap() and
                domain must have a default constructor

            REQUIREMENTS ON range
                range is swappable by a global swap() and
                range must have a default constructor

            REQUIREMENTS ON mem_manager
                must be an implementation of memory_manager/memory_manager_kernel_abstract.h or
                must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or
                must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h
                mem_manager::type can be set to anything.

            POINTERS AND REFERENCES TO INTERNAL DATA
                swap(), count(), height(),  and operator[] functions
                do not invalidate pointers or references to internal data.

                position_enumerator() invalidates pointers or references to
                data returned by element() and only by element() (i.e. pointers and
                references returned by operator[] are still valid).

                All other functions have no such guarantees.

            INITIAL VALUE
                size() == 0
                height() == 0

            ENUMERATION ORDER
                The enumerator will iterate over the domain (and each associated
                range element) elements in ascending order according to the compare functor.
                (i.e. the elements are enumerated in sorted order)

            WHAT THIS OBJECT REPRESENTS
                this object represents a data dictionary that is built on top of some
                kind of binary search tree.  It maps objects of type domain to objects
                of type range.

                Also note that unless specified otherwise, no member functions
                of this object throw exceptions.

                NOTE:
                    definition of equivalent:
                    a is equivalent to b if
                    a < b == false and
                    b < a == false
        !*/

    public:

        typedef domain domain_type;
        typedef range range_type;
        typedef compare compare_type;
        typedef mem_manager mem_manager_type;

        binary_search_tree(
        );
        /*!
            ensures
                - #*this is properly initialized
            throws
                - std::bad_alloc or any exception thrown by domain's or range's
                  constructor.
        !*/

        virtual ~binary_search_tree(
        );
        /*!
            ensures
                - all memory associated with *this has been released
        !*/

        void clear(
        );
        /*!
            ensures
                - #*this has its initial value
            throws
                - std::bad_alloc or any exception thrown by domain's or range's
                  constructor.
                    if this exception is thrown then *this is unusable
                    until clear() is called and succeeds
        !*/

        short height (
        ) const;
        /*!
            ensures
                - returns the number of elements in the longest path from the root
                  of the tree to a leaf
        !*/

        unsigned long count (
            const domain& d
        ) const;
        /*!
            ensures
                - returns the number of elements in the domain of *this that are
                  equivalent to d
        !*/

        void add (
            domain& d,
            range& r
        );
        /*!
            requires
                - &d != &r (i.e. d and r cannot be the same variable)
            ensures
                - adds a mapping between d and r to *this
                - if (count(d) == 0) then
                    - #*(*this)[d] == r
                - else
                    - #(*this)[d] != 0
                - #d and #r have initial values for their types
                - #count(d) == count(d) + 1
                - #at_start() == true
                - #size() == size() + 1
            throws
                - std::bad_alloc or any exception thrown by domain's or range's
                  constructor.
                    if add() throws then it has no effect
        !*/

        void remove (
            const domain& d,
            domain& d_copy,
            range& r
        );
        /*!
            requires
                - (*this)[d] != 0
                - &d != &r (i.e. d and r cannot be the same variable)
                - &d != &d_copy (i.e. d and d_copy cannot be the same variable)
                - &r != &d_copy (i.e. r and d_copy cannot be the same variable)
            ensures
                - some element in the domain of *this that is equivalent to d has
                  been removed and swapped into #d_copy.  Additionally, its
                  associated range element has been removed and swapped into #r.
                - #count(d) == count(d) - 1
                - #size() == size() - 1
                - #at_start() == true
        !*/

        void destroy (
            const domain& d
        );
        /*!
            requires
                - (*this)[d] != 0
            ensures
                - an element in the domain of *this equivalent to d has been removed.
                  The element in the range of *this associated with d has also been
                  removed.
                - #count(d) == count(d) - 1
                - #size() == size() - 1
                - #at_start() == true
        !*/

        void remove_last_in_order (
            domain& d,
            range& r
        );
        /*!
            requires
                - size() > 0
            ensures
                - the last/biggest (according to the compare functor) element in the domain of *this has
                  been removed and swapped into #d.  The element in the range of *this
                  associated with #d has also been removed and swapped into #r.
                - #count(#d) == count(#d) - 1
                - #size() == size() - 1
                - #at_start() == true
        !*/

        void remove_current_element (
            domain& d,
            range& r
        );
        /*!
            requires
                - current_element_valid() == true
            ensures
                - the current element given by element() has been removed and swapped into d and r.
                - #d == element().key()
                - #r == element().value()
                - #count(#d) == count(#d) - 1
                - #size() == size() - 1
                - moves the enumerator to the next element.  If element() was the last
                  element in enumeration order then #current_element_valid() == false
                  and #at_start() == false.
        !*/

        void position_enumerator (
            const domain& d
        ) const;
        /*!
            ensures
                - #at_start() == false
                - if (count(d) > 0) then
                    - #element().key() == d
                - else if (there are any items in the domain of *this that are bigger than
                  d according to the compare functor) then
                    - #element().key() == the smallest item in the domain of *this that is
                      bigger than d according to the compare functor.
                - else
                    - #current_element_valid() == false
        !*/

        const range* operator[] (
            const domain& d
        ) const;
        /*!
            ensures
                - if (there is an element in the domain equivalent to d) then
                    - returns a pointer to an element in the range of *this that
                      is associated with an element in the domain of *this
                      equivalent to d.
                - else
                    - returns 0
        !*/

        range* operator[] (
            const domain& d
        );
        /*!
            ensures
                - if (there is an element in the domain equivalent to d) then
                    - returns a pointer to an element in the range of *this that
                      is associated with an element in the domain of *this
                      equivalent to d.
                - else
                    - returns 0
        !*/

        void swap (
            binary_search_tree& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/

    private:

        // restricted functions
        binary_search_tree(binary_search_tree&);
        binary_search_tree& operator=(binary_search_tree&);

    };

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    inline void swap (
        binary_search_tree<domain,range,mem_manager,compare>& a,
        binary_search_tree<domain,range,mem_manager,compare>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void deserialize (
        binary_search_tree<domain,range,mem_manager,compare>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/
}

#endif // DLIB_BINARY_SEARCH_TREE_KERNEl_ABSTRACT_


dlib C++ Library - circular_buffer_abstract.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_CIRCULAR_BuFFER_ABSTRACT_Hh_
#ifdef DLIB_CIRCULAR_BuFFER_ABSTRACT_Hh_

#include "../algs.h"
#include "../serialize.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    class circular_buffer
    {
        /*!
            REQUIREMENTS ON T
                T must have a default constructor and be copyable.

            POINTERS AND REFERENCES TO INTERNAL DATA
                swap(), size(), front(), back(), and operator[] functions do
                not invalidate pointers or references to internal data.
                All other functions have no such guarantee.

            INITIAL VALUE
                - size() == 0

            WHAT THIS OBJECT REPRESENTS
                This object is a circular buffer of objects of type T.  This means
                that when objects are pushed onto one of its ends it does not grow
                in size.  Instead, it shifts all elements over one to make room for
                the new element and the element at the opposing end falls off the
                buffer and is lost.
        !*/

    public:
        typedef default_memory_manager mem_manager_type;
        typedef T value_type;
        typedef T type;

        circular_buffer(
        );
        /*!
            ensures
                - #size() == 0
                - this object is properly initialized
        !*/

        void clear (
        );
        /*!
            ensures
                - this object has its initial value
                - #size() == 0
        !*/

        T& operator[] (
            unsigned long i
        ) const;
        /*!
            requires
                - i < size()
            ensures
                - returns a non-const reference to the i-th element of this circular buffer
        !*/

        const T& operator[] (
            unsigned long i
        ) const;
        /*!
            requires
                - i < size()
            ensures
                - returns a const reference to the i-th element of this circular buffer
        !*/

        void resize(
            unsigned long new_size
        );
        /*!
            ensures
                - #size() == new_size
        !*/

        void assign(
            unsigned long new_size,
            const T& value
        );
        /*!
            ensures
                - #size() == new_size
                - for all valid i:
                    - (*this)[i] == value
        !*/

        unsigned long size(
        ) const;
        /*!
            ensures
                - returns the number of elements in this circular buffer
        !*/

        T& front(
        );
        /*!
            requires
                - size() > 0
            ensures
                - returns a reference to (*this)[0]
        !*/

        const T& front(
        ) const;
        /*!
            requires
                - size() > 0
            ensures
                - returns a const reference to (*this)[0]
        !*/

        T& back(
        );
        /*!
            requires
                - size() > 0
            ensures
                - returns a reference to (*this)[size()-1]
        !*/

        const T& back(
        ) const;
        /*!
            requires
                - size() > 0
            ensures
                - returns a const reference to (*this)[size()-1]
        !*/

        void push_front(
            const T& value
        );
        /*!
            ensures
                - #size() == size()
                  (i.e. the size of this object does not change)
                - if (size() != 0) then
                    - #front() == value
                    - all items are shifted over such that,
                        - #(*this)[1] == (*this)[0]
                        - #(*this)[2] == (*this)[1]
                        - #(*this)[3] == (*this)[2]
                        - etc.
                        - back() is shifted out of the circular buffer
                - else
                    - This function has no effect on this object
        !*/

        void push_back(
            const T& value
        );
        /*!
            ensures
                - #size() == size()
                  (i.e. the size of this object does not change)
                - if (size() != 0) then
                    - #back() == value
                    - all items are shifted over such that,
                        - front() is shifted out of the circular buffer
                        - #(*this)[0] == (*this)[1]
                        - #(*this)[1] == (*this)[2]
                        - #(*this)[2] == (*this)[3]
                        - etc.
                - else
                    - This function has no effect on this object
        !*/

        void swap (
            circular_buffer& item
        );
        /*!
            ensures
                - swaps *this with item
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    void swap (
        circular_buffer<T>& a,
        circular_buffer<T>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

    template <
        typename T
        >
    void serialize (
        const circular_buffer<T>& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

    template <
        typename T
        >
    void deserialize (
        circular_buffer<T>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    const matrix_exp mat (
        const circular_buffer<T>& m
    );
    /*!
        ensures
            - returns a matrix R such that:
                - is_col_vector(R) == true
                - R.size() == m.size()
                - for all valid r:
                  R(r) == m[r]
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_CIRCULAR_BuFFER_ABSTRACT_Hh_


dlib C++ Library - directed_graph_kernel_abstract.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_DIRECTED_GRAPH_KERNEl_ABSTRACT_
#ifdef DLIB_DIRECTED_GRAPH_KERNEl_ABSTRACT_

#include "../serialize.h"
#include "../algs.h"
#include "../noncopyable.h"

namespace dlib
{

    template <
        typename T,
        typename E = char,
        typename mem_manager = default_memory_manager
        >
    class directed_graph : noncopyable
    {

        /*!
            REQUIREMENTS ON T
                T must be swappable by a global swap() and
                T must have a default constructor

            REQUIREMENTS ON E
                E must be swappable by a global swap() and
                E must have a default constructor

            REQUIREMENTS ON mem_manager
                must be an implementation of memory_manager/memory_manager_kernel_abstract.h or
                must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or
                must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h
                mem_manager::type can be set to anything.

            POINTERS AND REFERENCES TO INTERNAL DATA
                The only time pointers or references to nodes or edges become invalid is when
                they reference nodes or edges that have been removed from a graph.

            INITIAL VALUE
                number_of_nodes() == 0

            WHAT THIS OBJECT REPRESENTS
                This object represents a directed graph which is a set of nodes with directed
                edges connecting various nodes.

                In this object if there is a directed edge from a node A to a node B then I say
                that A is the parent of B and B is the child of A.

                Also note that unless specified otherwise, no member functions
                of this object throw exceptions.
        !*/

    public:

        typedef T type;
        typedef E edge_type;
        typedef mem_manager mem_manager_type;

        template <typename Tr, typename Er, typename MMr>
        struct rebind {
            typedef directed_graph<Tr,Er,MMr> other;
        };

        directed_graph(
        );
        /*!
            ensures
                - #*this is properly initialized
            throws
                - std::bad_alloc or any exception thrown by T's constructor.
        !*/

        virtual ~directed_graph(
        );
        /*!
            ensures
                - all resources associated with *this has been released
        !*/

        void clear(
        );
        /*!
            ensures
                - #*this has its initial value
            throws
                - std::bad_alloc or any exception thrown by T's constructor.
                  If this exception is thrown then *this is unusable
                  until clear() is called and succeeds
        !*/

        void set_number_of_nodes (
            unsigned long new_size
        );
        /*!
            ensures
                - #number_of_nodes() == new_size
                - for all i < new_size:
                    - number_of_parents(i) == 0
                    - number_of_children(i) == 0
            throws
                - std::bad_alloc or any exception thrown by T's constructor.
                  If this exception is thrown then this object reverts back
                  to its initial state.
        !*/

        unsigned long number_of_nodes (
        ) const;
        /*!
            ensures
                - returns the number of nodes in this graph
        !*/

        struct node_type
        {
            T data;
            typedef directed_graph graph_type;

            unsigned long index(
            ) const;
            /*!
                ensures
                    - let G be the graph that contains the node *this
                    - returns a number N such that G.node(N) == *this
                      (i.e. returns the index of this node in the graph)
            !*/

            unsigned long number_of_parents (
            ) const;
            /*!
                ensures
                    - returns the number of parents of this node
            !*/

            unsigned long number_of_children (
            ) const;
            /*!
                ensures
                    - returns the number of children of this node
            !*/

            const node_type& parent (
                unsigned long edge_index
            ) const;
            /*!
                requires
                    - edge_index < number_of_parents()
                ensures
                    - returns a const reference to the edge_index'th parent of *this
            !*/

            node_type& parent (
                unsigned long edge_index
            );
            /*!
                requires
                    - edge_index < number_of_parents()
                ensures
                    - returns a non-const reference to the edge_index'th parent of *this
            !*/

            const node_type& child (
                unsigned long edge_index
            ) const;
            /*!
                requires
                    - edge_index < number_of_children()
                ensures
                    - returns a const reference to the edge_index'th child of *this
            !*/

            node_type& child (
                unsigned long edge_index
            );
            /*!
                requires
                    - edge_index < number_of_children()
                ensures
                    - returns a non-const reference to the edge_index'th child of *this
            !*/

            const E& parent_edge (
                unsigned long edge_index
            ) const;
            /*!
                requires
                    - edge_index < number_of_parents()
                ensures
                    - returns a const reference to the edge_index'th edge data for the
                      edge connecting to node this->parent(edge_index)
            !*/

            E& parent_edge (
                unsigned long edge_index
            );
            /*!
                requires
                    - edge_index < number_of_parents()
                ensures
                    - returns a non-const reference to the edge_index'th edge data for the
                      edge connecting to node this->parent(edge_index)
            !*/

            const E& child_edge (
                unsigned long edge_index
            ) const;
            /*!
                requires
                    - edge_index < number_of_children()
                ensures
                    - returns a const reference to the edge_index'th edge data for the
                      edge connecting to node this->child(edge_index)
            !*/

            E& child_edge (
                unsigned long edge_index
            );
            /*!
                requires
                    - edge_index < number_of_children()
                ensures
                    - returns a non-const reference to the edge_index'th edge data for the
                      edge connecting to node this->child(edge_index)
            !*/
        };

        node_type& node (
            unsigned long index
        );
        /*!
            requires
                - index < number_of_nodes()
            ensures
                - returns a non-const reference to the node with the given index
        !*/

        const node_type& node (
            unsigned long index
        ) const;
        /*!
            requires
                - index < number_of_nodes()
            ensures
                - returns a const reference to the node with the given index
        !*/

        bool has_edge (
            unsigned long parent_node_index,
            unsigned long child_node_index
        ) const;
        /*!
            requires
                - parent_node_index < number_of_nodes()
                - child_node_index < number_of_nodes()
            ensures
                - if (there is an edge leading from node(parent_node_index) to
                  node(child_node_index)) then
                    - returns true
                - else
                    - returns false
        !*/

        void add_edge (
            unsigned long parent_node_index,
            unsigned long child_node_index
        );
        /*!
            requires
                - parent_node_index < number_of_nodes()
                - child_node_index < number_of_nodes()
                - has_edge(parent_node_index, child_node_index) == false
            ensures
                - #has_edge(parent_node_index, child_node_index) == true
            throws
                - std::bad_alloc
                  If this exception is thrown then this object reverts back
                  to its initial state.
        !*/

        void remove_edge (
            unsigned long parent_node_index,
            unsigned long child_node_index
        );
        /*!
            requires
                - parent_node_index < number_of_nodes()
                - child_node_index < number_of_nodes()
                - has_edge(parent_node_index, child_node_index) == true
            ensures
                - #has_edge(parent_node_index, child_node_index) == false
            throws
                - std::bad_alloc
                  If this exception is thrown then this object reverts back
                  to its initial state.
        !*/

        unsigned long add_node (
        );
        /*!
            ensures
                - does not change the index number of existing nodes
                - adds a node with index N == number_of_nodes() such that:
                    - #node(N).number_of_parents() == 0
                    - #node(N).number_of_children() == 0
                    - #number_of_nodes() == number_of_nodes() + 1
                    - returns N
            throws
                - std::bad_alloc or any exception thrown by T's constructor.
                  If this exception is thrown then this object reverts back
                  to its initial state.
        !*/

        void remove_node (
            unsigned long index
        );
        /*!
            requires
                - index < number_of_nodes()
            ensures
                - removes the node with the given index from the graph.
                - removes all edges linking the removed node to the rest
                  of the graph.
                - the remaining node indexes are remapped so that they remain
                  contiguous.  (This means that for all valid N, node(N) doesn't
                  necessarily reference the same node as #node(N))
                - #number_of_nodes() == number_of_nodes() - 1
            throws
                - std::bad_alloc or any exception thrown by T's constructor.
                  If this exception is thrown then this object reverts back
                  to its initial state.
        !*/

        void swap (
            directed_graph& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/

    };

    template <
        typename T,
        typename mem_manager
        >
    inline void swap (
        directed_graph<T,mem_manager>& a,
        directed_graph<T,mem_manager>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

    template <
        typename T,
        typename mem_manager
        >
    void serialize (
        const directed_graph<T,mem_manager>& item,
        std::ostream& out
    );
    /*!
        provides deserialization support
    !*/

    template <
        typename T,
        typename mem_manager
        >
    void deserialize (
        directed_graph<T,mem_manager>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

}

#endif // DLIB_DIRECTED_GRAPH_KERNEl_ABSTRACT_


dlib C++ Library - graph_kernel_abstract.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_GRAPH_KERNEl_ABSTRACT_
#ifdef DLIB_GRAPH_KERNEl_ABSTRACT_

#include "../serialize.h"
#include "../algs.h"
#include "../noncopyable.h"

namespace dlib
{

    template <
        typename T,
        typename E = char,
        typename mem_manager = default_memory_manager
        >
    class graph : noncopyable
    {

        /*!
            REQUIREMENTS ON T
                T must be swappable by a global swap() and
                T must have a default constructor

            REQUIREMENTS ON E
                E must be swappable by a global swap() and
                E must have a default constructor

            REQUIREMENTS ON mem_manager
                must be an implementation of memory_manager/memory_manager_kernel_abstract.h or
                must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or
                must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h
                mem_manager::type can be set to anything.

            POINTERS AND REFERENCES TO INTERNAL DATA
                The only time pointers or references to nodes or edges become invalid is when
                they reference nodes or edges that have been removed from a graph.

            INITIAL VALUE
                number_of_nodes() == 0

            WHAT THIS OBJECT REPRESENTS
                This object represents an undirected graph which is a set of nodes with undirected
                edges connecting various nodes.

                Also note that unless specified otherwise, no member functions
                of this object throw exceptions.
        !*/

    public:

        typedef T type;
        typedef E edge_type;
        typedef mem_manager mem_manager_type;

        graph(
        );
        /*!
            ensures
                - #*this is properly initialized
            throws
                - std::bad_alloc or any exception thrown by T's constructor.
        !*/

        virtual ~graph(
        );
        /*!
            ensures
                - all resources associated with *this has been released
        !*/

        void clear(
        );
        /*!
            ensures
                - #*this has its initial value
            throws
                - std::bad_alloc or any exception thrown by T's constructor.
                  If this exception is thrown then *this is unusable
                  until clear() is called and succeeds
        !*/

        void set_number_of_nodes (
            unsigned long new_size
        );
        /*!
            ensures
                - #number_of_nodes() == new_size
                - for all i < new_size:
                    - number_of_neighbors(i) == 0
            throws
                - std::bad_alloc or any exception thrown by T's constructor.
                  If this exception is thrown then this object reverts back
                  to its initial state.
        !*/

        unsigned long number_of_nodes (
        ) const;
        /*!
            ensures
                - returns the number of nodes in this graph
        !*/

        struct node_type
        {
            T data;
            typedef graph graph_type;

            unsigned long index(
            ) const;
            /*!
                ensures
                    - let G be the graph that contains the node *this
                    - returns a number N such that G.node(N) == *this
                      (i.e. returns the index of this node in the graph)
            !*/

            unsigned long number_of_neighbors (
            ) const;
            /*!
                ensures
                    - returns the number of nodes in this graph that are
                      adjacent to this node.  I.e. the number of nodes
                      that are directly connected to this node via an edge.
            !*/

            const node_type& neighbor (
                unsigned long edge_index
            ) const;
            /*!
                requires
                    - edge_index < number_of_neighbors()
                ensures
                    - returns a const reference to the edge_index'th neighbor of *this
            !*/

            node_type& neighbor (
                unsigned long edge_index
            );
            /*!
                requires
                    - edge_index < number_of_neighbors()
                ensures
                    - returns a non-const reference to the edge_index'th neighbor of *this
            !*/

            const E& edge (
                unsigned long edge_index
            ) const;
            /*!
                requires
                    - edge_index < number_of_neighbors()
                ensures
                    - returns a const reference to the edge_index'th edge data for the
                      edge connecting to neighbor this->neighbor(edge_index)
            !*/

            E& edge (
                unsigned long edge_index
            );
            /*!
                requires
                    - edge_index < number_of_neighbors()
                ensures
                    - returns a non-const reference to the edge_index'th edge data for the
                      edge connecting to neighbor this->neighbor(edge_index)
            !*/

        };

        node_type& node (
            unsigned long index
        );
        /*!
            requires
                - index < number_of_nodes()
            ensures
                - returns a non-const reference to the node with the given index
        !*/

        const node_type& node (
            unsigned long index
        ) const;
        /*!
            requires
                - index < number_of_nodes()
            ensures
                - returns a const reference to the node with the given index
        !*/

        bool has_edge (
            unsigned long node_index1,
            unsigned long node_index2
        ) const;
        /*!
            requires
                - node_index1 < number_of_nodes()
                - node_index2 < number_of_nodes()
            ensures
                - if (there is an edge connecting node(node_index1) and node(node_index2)) then
                    - returns true
                - else
                    - returns false
        !*/

        void add_edge (
            unsigned long node_index1,
            unsigned long node_index2
        );
        /*!
            requires
                - node_index1 < number_of_nodes()
                - node_index2 < number_of_nodes()
                - has_edge(node_index1, node_index2) == false
            ensures
                - #has_edge(node_index1, node_index2) == true
            throws
                - std::bad_alloc
                  If this exception is thrown then this object reverts back
                  to its initial state.
        !*/

        void remove_edge (
            unsigned long node_index1,
            unsigned long node_index2
        );
        /*!
            requires
                - node_index1 < number_of_nodes()
                - node_index2 < number_of_nodes()
                - has_edge(node_index1, node_index2) == true
            ensures
                - #has_edge(node_index1, node_index2) == false
            throws
                - std::bad_alloc
                  If this exception is thrown then this object reverts back
                  to its initial state.
        !*/

        unsigned long add_node (
        );
        /*!
            ensures
                - does not change the index number of existing nodes
                - adds a node with index N == number_of_nodes() such that:
                    - #node(N).number_of_neighbors() == 0
                    - #number_of_nodes() == number_of_nodes() + 1
                    - returns N
            throws
                - std::bad_alloc or any exception thrown by T's constructor.
                  If this exception is thrown then this object reverts back
                  to its initial state.
        !*/

        void remove_node (
            unsigned long index
        );
        /*!
            requires
                - index < number_of_nodes()
            ensures
                - removes the node with the given index from the graph.
                - removes all edges linking the removed node to the rest
                  of the graph.
                - the remaining node indexes are remapped so that they remain
                  contiguous.  (This means that for all valid N, node(N) doesn't
                  necessarily reference the same node as #node(N))
                - #number_of_nodes() == number_of_nodes() - 1
            throws
                - std::bad_alloc or any exception thrown by T's constructor.
                  If this exception is thrown then this object reverts back
                  to its initial state.
        !*/

        void swap (
            graph& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/

    };

    template <
        typename T,
        typename E,
        typename mem_manager
        >
    inline void swap (
        graph<T,E,mem_manager>& a,
        graph<T,E,mem_manager>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

    template <
        typename T,
        typename E,
        typename mem_manager
        >
    void serialize (
        const graph<T,E,mem_manager>& item,
        std::ostream& out
    );
    /*!
        provides deserialization support
    !*/

    template <
        typename T,
        typename E,
        typename mem_manager
        >
    void deserialize (
        graph<T,E,mem_manager>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

}

#endif // DLIB_GRAPH_KERNEl_ABSTRACT_


dlib C++ Library - hash_map_kernel_abstract.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_HASH_MAP_KERNEl_ABSTRACT_
#ifdef DLIB_HASH_MAP_KERNEl_ABSTRACT_

#include "../general_hash/general_hash.h"
#include "../interfaces/enumerable.h"
#include "../interfaces/remover.h"
#include "../interfaces/map_pair.h"
#include "../serialize.h"
#include "../algs.h"
#include <functional>

namespace dlib
{

    template <
        typename domain,
        typename range,
        unsigned long expnum,
        typename mem_manager = default_memory_manager,
        typename compare = std::less<T>
        >
    class hash_map : public enumerable<map_pair<domain,range> >,
                     public pair_remover<domain,range>
    {

        /*!
            REQUIREMENTS ON domain
                domain must be comparable by compare where compare is a functor compatible with std::less and
                domain must be hashable by general_hash
                (general_hash is defined in dlib/general_hash) and
                domain must be swappable by a global swap() and
                domain must have a default constructor

            REQUIREMENTS ON range
                range must be swappable by a global swap() and
                range must have a default constructor

            REQUIREMENTS ON expnum
                expnum < 32
                2^expnum is the number of buckets to hash items of type T into.
                Note that this is really just a suggestion to the hash table.
                Implementations are free to manage the table size however is most
                appropriate.

            REQUIREMENTS ON mem_manager
                must be an implementation of memory_manager/memory_manager_kernel_abstract.h or
                must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or
                must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h
                mem_manager::type can be set to anything.

            POINTERS AND REFERENCES TO INTERNAL DATA
                swap(), is_in_domain(), and operator[] functions do
                not invalidate pointers or references to internal data.
                All other functions have no such guarantees.

            INITIAL VALUE
                size() == 0

            ENUMERATION ORDER
                No order is specified.  Only that each element will be visited once
                and only once.

            WHAT THIS OBJECT REPRESENTS
                hash_map contains items of type domain and range

                This object is similar an array.  It maps items of type domain on to
                items of type range.

                Also note that unless specified otherwise, no member functions
                of this object throw exceptions.

                definition of equivalent:
                a is equivalent to b if
                a < b == false and
                b < a == false
        !*/

        public:

            typedef domain domain_type;
            typedef range range_type;
            typedef compare compare_type;
            typedef mem_manager mem_manager_type;

            hash_map(
            );
            /*!
                ensures
                    - #*this is properly initialized
                throws
                    - std::bad_alloc or any exception thrown by domain's or range's
                      constructor.
            !*/

            virtual ~hash_map(
            );
            /*!
                ensures
                    - all memory associated with *this has been released
            !*/

            void clear(
            );
            /*!
                ensures
                    - #*this has its initial value
                throws
                    - std::bad_alloc or any exception thrown by domain's or range's
                      constructor.
                        if this exception is thrown then *this is unusable
                        until clear() is called and succeeds
            !*/

            void add (
                domain& d,
                range& r
            );
            /*!
                requires
                    - &d != &r (i.e. d and r cannot be the same variable)
                    - is_in_domain(d)  == false
                ensures
                    - #is_in_domain(d) == true
                    - #operator[](d)   == r
                    - #d and #r have initial values for their types
                    - #size() == size() + 1
                    - #at_start() == true
                throws
                    - std::bad_alloc or any exception thrown by domain's or range's
                      constructor.
                        if add() throws then it has no effect
            !*/

            bool is_in_domain (
                const domain& d
            ) const;
            /*!
                ensures
                    - returns whether or not an element equivalent to d is in the
                      domain of *this
            !*/

            void remove (
                const domain& d,
                domain& d_copy,
                range& r
            );
            /*!
                requires
                    - &d != &r (i.e. d and r cannot be the same variable)
                    - &d != &d_copy (i.e. d and d_copy cannot be the same variable)
                    - &r != &d_copy (i.e. r and d_copy cannot be the same variable)
                    - is_in_domain(d) == true
                ensures
                    - #is_in_domain(d) == false
                    - #d_copy is equivalent to d
                    - the element in the range of *this associated with #d_copy has
                      been swapped into #r
                    - #size() == size() - 1
                    - #at_start() == true
            !*/

            void destroy (
                const domain& d
            );
            /*!
                requires
                    - is_in_domain(d) == true
                ensures
                    - #is_in_domain(d) == false
                    - #size() == size() - 1
                    - #at_start() == true
            !*/

            range& operator[] (
                const domain& d
            );
            /*!
                requires
                    - is_in_domain(d) == true
                ensures
                    - returns a non-const reference to the element in the range of *this
                      associated with the element equivalent to d
            !*/

            const range& operator[] (
                const domain& d
            ) const;
            /*!
                requires
                    - is_in_domain(d) == true
                ensures
                    - returns a const reference to the element in the range of *this
                      associated with the element equivalent to d
            !*/

            void swap (
                hash_map& item
            );
            /*!
                ensures
                    - swaps *this and item
            !*/

        private:

            // restricted functions
            hash_map(hash_map&);
            hash_map& operator=(hash_map&);
    };

    template <
        typename domain,
        typename range,
        unsigned long expnum,
        typename mem_manager,
        typename compare
        >
    inline void swap (
        hash_map<domain,range,expnum,mem_manager,compare>& a,
        hash_map<domain,range,expnum,mem_manager,compare>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

    template <
        typename domain,
        typename range,
        unsigned long expnum,
        typename mem_manager,
        typename compare
        >
    void deserialize (
        hash_map<domain,range,expnum,mem_manager,compare>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/
}

#endif // DLIB_HASH_MAP_KERNEl_ABSTRACT_


dlib C++ Library - hash_set_kernel_abstract.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_HASH_SET_KERNEl_ABSTRACT_
#ifdef DLIB_HASH_SET_KERNEl_ABSTRACT_

#include "../general_hash/general_hash.h"
#include "../interfaces/enumerable.h"
#include "../interfaces/remover.h"
#include "../serialize.h"
#include "../algs.h"
#include <functional>

namespace dlib
{

    template <
        typename T,
        unsigned long expnum,
        typename mem_manager = default_memory_manager,
        typename compare = std::less<T>
        >
    class hash_set : public enumerable<const T>,
                     public remover<T>
    {

        /*!
            REQUIREMENTS ON T
                domain must be comparable by compare where compare is a functor compatible with std::less and
                T must be hashable by general_hash
                (general_hash is defined in dlib/general_hash) and
                T must be swappable by a global swap() and
                T must have a default constructor

            REQUIREMENTS ON expnum
                expnum < 32
                2^expnum is the number of buckets to hash items of type T into.
                Note that this is really just a suggestion to the hash table.
                Implementations are free to manage the table size however is most
                appropriate.

            REQUIREMENTS ON mem_manager
                must be an implementation of memory_manager/memory_manager_kernel_abstract.h or
                must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or
                must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h
                mem_manager::type can be set to anything.

            POINTERS AND REFERENCES TO INTERNAL DATA
                swap() and is_member() functions do not invalidate
                pointers or references to internal data.
                All other functions have no such guarantee.

            INITIAL VALUE
                size() == 0

            ENUMERATION ORDER
                No order is specified.  Only that each element will be visited once
                and only once.

            WHAT THIS OBJECT REPRESENTS
                hash_set contains items of type T

                This object represents an unaddressed collection
                of items.  Every element in a hash_set is unique.

                Also note that unless specified otherwise, no member functions
                of this object throw exceptions.

                definition of equivalent:
                a is equivalent to b if
                a < b == false and
                b < a == false
        !*/

        public:

            typedef T type;
            typedef compare compare_type;
            typedef mem_manager mem_manager_type;

            hash_set(
            );
            /*!
                ensures
                    - #*this is properly initialized
                throws
                    - std::bad_alloc or any exception thrown by T's constructor
            !*/

            virtual ~hash_set(
            );
            /*!
                ensures
                    - all memory associated with *this has been released
            !*/

            void clear(
            );
            /*!
                ensures
                    - #*this has its initial value
                throws
                    - std::bad_alloc or any exception thrown by T's constructor
                        if this exception is thrown then *this is unusable
                        until clear() is called and succeeds
            !*/

            void add (
                T& item
            );
            /*!
                requires
                    - is_member(item) == false
                ensures
                    - #is_member(item) == true
                    - #item has an initial value for its type
                    - #size() == size() + 1
                    - #at_start() == true
                throws
                    - std::bad_alloc or any exception thrown by T's constructor
                        if add() throws then it has no effect
            !*/

            bool is_member (
                const T& item
            ) const;
            /*!
                ensures
                    - returns whether or not there is an element in *this equivalent
                      to item
            !*/

            void remove (
                const T& item,
                T& item_copy
            );
            /*!
                requires
                    - is_member(item) == true
                    - &item != &item_copy (i.e. item and item_copy cannot be the
                      same variable)
                ensures
                    - #is_member(item) == false
                    - the element in *this equivalent to item has been removed and
                      swapped into #item_copy
                    - #size() == size() - 1
                    - #at_start() == true
            !*/

            void destroy (
                const T& item
            );
            /*!
                requires
                    - is_member(item) == true
                ensures
                    - #is_member(item) == false
                    - #size() == size() - 1
                    - #at_start() == true
            !*/

            void swap (
                hash_set& item
            );
            /*!
                ensures
                    - swaps *this and item
            !*/

        private:

            // restricted functions
            hash_set(hash_set&);        // copy constructor
            hash_set& operator=(hash_set&);    // assignment operator

    };

    template <
        typename T,
        unsigned long expnum,
        typename mem_manager,
        typename compare
        >
    inline void swap (
        hash_set<T,expnum,mem_manager,compare>& a,
        hash_set<T,expnum,mem_manager,compare>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

    template <
        typename T,
        unsigned long expnum,
        typename mem_manager,
        typename compare
        >
    void deserialize (
        hash_set<T,expnum,mem_manager,compare>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/
}

#endif // DLIB_HASH_SET_KERNEl_ABSTRACT_


dlib C++ Library - hash_table_kernel_abstract.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_HASH_TABLE_KERNEl_ABSTRACT_
#ifdef DLIB_HASH_TABLE_KERNEl_ABSTRACT_

#include "../interfaces/map_pair.h"
#include "../general_hash/general_hash.h"
#include "../interfaces/enumerable.h"
#include "../interfaces/remover.h"
#include "../serialize.h"
#include "../algs.h"
#include <functional>

namespace dlib
{

    template <
        typename domain,
        typename range,
        typename mem_manager = default_memory_manager,
        typename compare = std::less<domain>
        >
    class hash_table : public enumerable<map_pair<domain,range> >,
                       public pair_remover<domain,range>
    {

        /*!
            REQUIREMENTS ON domain
                domain must be comparable by compare where compare is a functor compatible with std::less and
                domain must be hashable by general_hash
                (general_hash is defined in dlib/general_hash) and
                domain must be swappable by a global swap() and
                domain must have a default constructor

            REQUIREMENTS ON range
                range must be swappable by a global swap() and
                range must have a default constructor

            REQUIREMENTS ON mem_manager
                must be an implementation of memory_manager/memory_manager_kernel_abstract.h or
                must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or
                must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h
                mem_manager::type can be set to anything.

            POINTERS AND REFERENCES TO INTERNAL DATA
                swap(), count(), and operator[] functions do
                not invalidate pointers or references to internal data.
                All other functions have no such guarantee.

            INITIAL VALUE
                size() == 0

            ENUMERATION ORDER
                No order is specified.  Only that each element will be visited once
                and only once.

            WHAT THIS OBJECT REPRESENTS
                hash_table contains items of type T

                This object represents a data dictionary that is built on top of some
                kind of hash table.  The number of buckets in the hash table is
                defined by the constructor argument and is some power of 2.

                Also note that unless specified otherwise, no member functions
                of this object throw exceptions.

                NOTE:
                    definition of equivalent:
                    a is equivalent to b if
                    a < b == false and
                    b < a == false
        !*/

        public:

            typedef domain domain_type;
            typedef range range_type;
            typedef compare compare_type;
            typedef mem_manager mem_manager_type;

            explicit hash_table(
                unsigned long expnum
            );
            /*!
                requires
                    - expnum < 32
                ensures
                    - #*this is properly initialized
                    - #*this will use 2^expnum as a suggestion for the initial number
                      of buckets.
                throws
                    - std::bad_alloc or any exception thrown by domain's or range's
                      constructor.
            !*/

            virtual ~hash_table(
            );
            /*!
                ensures
                    - all memory associated with *this has been released
            !*/

            void clear(
            );
            /*!
                ensures
                    - #*this has its initial value
                throws
                    - std::bad_alloc or any exception thrown by domain's or range's
                      constructor.
                        if this exception is thrown then *this is unusable
                        until clear() is called and succeeds
            !*/

            unsigned long count (
                const domain& d
            ) const;
            /*!
                ensures
                    - returns the number of elements in the domain of *this that are
                      equivalent to d
            !*/

            void add (
                domain& d,
                range& r
            );
            /*!
                requires
                    - &d != &r (i.e. d and r cannot be the same variable)
                ensures
                    - adds a mapping between d and r to *this
                    - if (count(d) == 0) then
                        - #*(*this)[d] == r
                    - else
                        - #(*this)[d] != 0
                    - #d and #r have initial values for their types
                    - #count(d) == count(d) + 1
                    - #at_start() == true
                    - #size() == size() + 1
                throws
                    - std::bad_alloc or any exception thrown by domain's or range's
                      constructor.
                        if add() throws then it has no effect
            !*/

            void remove (
                const domain& d,
                domain& d_copy,
                range& r
            );
            /*!
                requires
                    - (*this)[d] != 0
                    - &d != &r (i.e. d and r cannot be the same variable)
                    - &d != &d_copy (i.e. d and d_copy cannot be the same variable)
                    - &r != &d_copy (i.e. r and d_copy cannot be the same variable)
                ensures
                    - some element in the domain of *this that is equivalent to d has
                      been removed and swapped into #d_copy.  Additionally, its
                      associated range element has been removed and swapped into #r.
                    - #count(d) = count(d) - 1
                    - #size() == size() - 1
                    - #at_start() == true
            !*/

            void destroy (
                const domain& d
            );
            /*!
                requires
                    - (*this)[d] != 0
                ensures
                    - an element in the domain of *this equivalent to d has been removed.
                      The element in the range of *this associated with d has also been
                      removed.
                    - #count(d) == count(d) - 1
                    - #size() == size() - 1
                    - #at_start() == true
            !*/

            const range* operator[] (
                const domain& d
            ) const;
            /*!
                ensures
                    - if (there is an element in the domain equivalent to d) then
                        - returns a pointer to an element in the range of *this that
                          is associated with an element in the domain of *this
                          equivalent to d.
                    - else
                        - returns 0
            !*/

            range* operator[] (
                const domain& d
            );
            /*!
                ensures
                    - if (there is an element in the domain equivalent to d) then
                        - returns a pointer to an element in the range of *this that
                          is associated with an element in the domain of *this
                          equivalent to d.
                    - else
                        - returns 0
            !*/

            void swap (
                hash_table& item
            );
            /*!
                ensures
                    - swaps *this and item
            !*/

        private:

            // restricted functions
            hash_table(hash_table&);
            hash_table& operator=(hash_table&);

    };

    template <
        typename domain,
        typename range,
        typename mem_manager
        >
    inline void swap (
        hash_table<domain,range,mem_manager>& a,
        hash_table<domain,range,mem_manager>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

    template <
        typename domain,
        typename range,
        typename mem_manager
        >
    void deserialize (
        hash_table<domain,range,mem_manager>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/
}

#endif // DLIB_HASH_TABLE_KERNEl_ABSTRACT_


dlib C++ Library - map_kernel_abstract.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_MAP_KERNEl_ABSTRACT_
#ifdef DLIB_MAP_KERNEl_ABSTRACT_

#include "../interfaces/map_pair.h"
#include "../interfaces/enumerable.h"
#include "../interfaces/remover.h"
#include "../serialize.h"
#include "../algs.h"
#include <functional>

namespace dlib
{

    template <
        typename domain,
        typename range,
        typename mem_manager = default_memory_manager,
        typename compare = std::less<domain>
        >
    class map : public enumerable<map_pair<domain,range> >,
                public asc_pair_remover<domain,range,compare>
    {

        /*!
            REQUIREMENTS ON domain
                domain must be comparable by compare where compare is a functor compatible with std::less and
                domain is swappable by a global swap() and
                domain must have a default constructor

            REQUIREMENTS ON range
                range is swappable by a global swap() and
                range must have a default constructor

            REQUIREMENTS ON mem_manager
                must be an implementation of memory_manager/memory_manager_kernel_abstract.h or
                must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or
                must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h
                mem_manager::type can be set to anything.

            POINTERS AND REFERENCES TO INTERNAL DATA
                swap(), is_in_domain(), and operator[] functions do not invalidate
                pointers or references to internal data.
                All other functions have no such guarantee.

            INITIAL VALUE
                size() == 0

            ENUMERATION ORDER
                The enumerator will iterate over the domain (and each associated
                range element) elements in ascending order according to the compare functor.
                (i.e. the elements are enumerated in sorted order)

            WHAT THIS OBJECT REPRESENTS
                map contains items of type domain and range

                This object is similar an array.  It maps items of type domain on to
                items of type range.

                Also note that unless specified otherwise, no member functions
                of this object throw exceptions.

                definition of equivalent:
                a is equivalent to b if
                a < b == false and
                b < a == false
        !*/

        public:

            typedef domain domain_type;
            typedef range range_type;
            typedef compare compare_type;
            typedef mem_manager mem_manager_type;

            map(
            );
            /*!
                ensures
                    - #*this is properly initialized
                throws
                    - std::bad_alloc or any exception thrown by domain's or range's
                      constructor.
            !*/

            virtual ~map(
            );
            /*!
                ensures
                    - all memory associated with *this has been released
            !*/

            void clear(
            );
            /*!
                ensures
                    - #*this has its initial value
                throws
                    - std::bad_alloc or any exception thrown by domain's or range's
                      constructor.
                        if this exception is thrown then *this is unusable
                        until clear() is called and succeeds
            !*/

            void add (
                domain& d,
                range& r
            );
            /*!
                requires
                    - &d != &r (i.e. d and r cannot be the same variable)
                    - is_in_domain(d)  == false
                ensures
                    - #is_in_domain(d) == true
                    - #operator[](d)   == r
                    - #d and #r have initial values for their types
                    - #size() == size() + 1
                    - #at_start() == true
                throws
                    - std::bad_alloc or any exception thrown by domain's or range's
                      constructor.
                        if add() throws then it has no effect
            !*/

            bool is_in_domain (
                const domain& d
            ) const;
            /*!
                ensures
                    - returns whether or not an element equivalent to d is in the
                      domain of *this
            !*/

            void remove (
                const domain& d,
                domain& d_copy,
                range& r
            );
            /*!
                requires
                    - &d != &r (i.e. d and r cannot be the same variable)
                    - &d != &d_copy (i.e. d and d_copy cannot be the same variable)
                    - &r != &d_copy (i.e. r and d_copy cannot be the same variable)
                    - is_in_domain(d) == true
                ensures
                    - #is_in_domain(d) == false
                    - #d_copy is equivalent to d
                    - the element in the range of *this associated with #d_copy has been
                      swapped into #r
                    - #size() == size() - 1
                    - #at_start() == true
            !*/

            void destroy (
                const domain& d
            );
            /*!
                requires
                    - is_in_domain(d) == true
                ensures
                    - #is_in_domain(d) == false
                    - #size() == size() - 1
                    - #at_start() == true
            !*/

            range& operator[] (
                const domain& d
            );
            /*!
                requires
                    - is_in_domain(d) == true
                ensures
                    - returns a non-const reference to the element in the range of *this
                      associated with the element equivalent to d
            !*/

            const range& operator[] (
                const domain& d
            ) const;
            /*!
                requires
                    - is_in_domain(d) == true
                ensures
                    - returns a const reference to the element in the range of *this
                      associated with the element equivalent to d
            !*/

            void swap (
                map& item
            );
            /*!
                ensures
                    - swaps *this and item
            !*/

        private:

            // restricted functions
            map(map&);        // copy constructor
            map& operator=(map&);    // assignment operator
    };

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    inline void swap (
        map<domain,range,mem_manager,compare>& a,
        map<domain,range,mem_manager,compare>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void deserialize (
        map<domain,range,mem_manager,compare>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/
}

#endif // DLIB_MAP_KERNEl_ABSTRACT_


dlib C++ Library - queue_kernel_abstract.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_QUEUE_KERNEl_ABSTRACT_
#ifdef DLIB_QUEUE_KERNEl_ABSTRACT_

#include "../interfaces/enumerable.h"
#include "../interfaces/remover.h"
#include "../serialize.h"
#include "../algs.h"

namespace dlib
{

    template <
        typename T,
        typename mem_manager = default_memory_manager
        >
    class queue : public enumerable<T>,
                  public remover<T>
    {

        /*!
            REQUIREMENTS ON T
                T must be swappable by a global swap()
                T must have a default constructor

            REQUIREMENTS ON mem_manager
                must be an implementation of memory_manager/memory_manager_kernel_abstract.h or
                must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or
                must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h
                mem_manager::type can be set to anything.

            POINTERS AND REFERENCES TO INTERNAL DATA
                swap() and current() functions do not invalidate pointers or
                references to internal data.
                All other functions have no such guarantee.

            INITIAL VALUE
                size() == 0

            ENUMERATION ORDER
                The enumerator will iterate over the elements in the queue in the
                same order they would be removed by repeated calls to dequeue().
                (e.g. current() would be the first element enumerated)

            WHAT THIS OBJECT REPRESENTS
                This is a first in first out queue containing items of type T

                e.g. if the queue is {b,c,d,e} and then 'a' is enqueued
                the queue becomes {a,b,c,d,e} and then calling dequeue takes e out
                making the queue {a,b,c,d}

                Also note that unless specified otherwise, no member functions
                of this object throw exceptions.
        !*/

        public:

            typedef T type;
            typedef mem_manager mem_manager_type;

            queue (
            );
            /*!
                ensures
                    - #*this is properly initialized
                throws
                    - std::bad_alloc or any exception thrown by T's constructor
            !*/

            virtual ~queue (
            );
            /*!
                ensures
                    - all memory associated with *this has been released
            !*/

            void clear(
            );
            /*!
                ensures
                    - #*this has its initial value
                throws
                    - std::bad_alloc or any exception thrown by T's constructor
                        if this exception is thrown then *this is unusable
                        until clear() is called and succeeds
            !*/

            void enqueue (
                T& item
            );
            /*!
                ensures
                    - item is now at the left end of #*this
                    - #item has an initial value for its type
                    - #size() == size() + 1
                    - #at_start() == true
                throws
                    - std::bad_alloc or any exception thrown by T's constructor
                        if enqueue() throws then it has no effect
            !*/

            void dequeue (
                T& item
            );
            /*!
                requires
                    - size() != 0
                ensures
                    - #size() == size() - 1
                    - the far right element of *this has been removed and swapped
                      into #item
                    - #at_start() == true
            !*/

            void cat (
                queue& item
            );
            /*!
                ensures
                    - item has been concatenated onto the left end of *this.
                      i.e. item.current() is attached onto the left end of *this and
                      the left most element in item will also be the left most item
                      in #*this
                    - #size() == size() + item.size()
                    - #item has its initial value
                    - #at_start() == true
                throws
                    - std::bad_alloc or any exception thrown by T's constructor
                        if cat() throws then the state of #item and *this is undefined
                        until clear() is successfully called on them.
            !*/

            T& current (
            );
            /*!
                requires
                    - size() != 0
                ensures
                    - returns a const reference to the next element to be dequeued.
                      i.e.  the right most element.
            !*/

            const T& current (
            ) const;
            /*!
                requires
                    - size() != 0
                ensures
                    - returns a non-const reference to the next element to be dequeued.
                      i.e.  the right most element.
            !*/

            void swap (
                queue& item
            );
            /*!
                ensures
                    - swaps *this and item
            !*/

        private:

            // restricted functions
            queue(queue&);        // copy constructor
            queue& operator=(queue&);    // assignment operator

    };

    template <
        typename T,
        typename mem_manager
        >
    inline void swap (
        queue<T,mem_manager>& a,
        queue<T,mem_manager>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

    template <
        typename T,
        typename mem_manager
        >
    void deserialize (
        queue<T,mem_manager>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/
}

#endif // DLIB_QUEUE_KERNEl_ABSTRACT_


dlib C++ Library - queue_sort_abstract.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_QUEUE_SORt_ABSTRACT_
#ifdef DLIB_QUEUE_SORt_ABSTRACT_

#include "queue_kernel_abstract.h"

namespace dlib
{

    template <
        typename queue_base
        >
    class queue_sort : public queue_base
    {

        /*!
            REQUIREMENTS ON QUEUE_BASE
                - is an implementation of queue/queue_kernel_abstract.h
                - queue_base::type must be a type with that is comparable via operator<

            POINTERS AND REFERENCES TO INTERNAL DATA
                sort() may invalidate pointers and references to internal data.

            WHAT THIS EXTENSION DOES FOR QUEUE
                This gives a queue the ability to sort its contents by calling sort().
        !*/

        public:

            void sort (
            );
            /*!
                ensures
                    - for all elements in #*this the ith element is <= the i+1 element
                    - #at_start() == true
                throws
                    - std::bad_alloc or any exception thrown by T's constructor
                        data may be lost if sort() throws
            !*/

            template <typename compare_type>
            void sort (
                const compare_type& compare
            );
            /*!
                ensures
                    - for all elements in #*this the ith element is <= the i+1 element
                    - uses compare(a,b) as the < operator.  So if compare(a,b) == true
                      then a comes before b in the resulting ordering.
                    - #at_start() == true
                throws
                    - std::bad_alloc or any exception thrown by T's constructor
                        data may be lost if sort() throws
            !*/
    };

    template <
        template queue_base
        >
    inline void swap (
        queue_sort<queue_base>& a,
        queue_sort<queue_base>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

}

#endif // DLIB_QUEUE_SORt_ABSTRACT_


dlib C++ Library - reference_counter_kernel_abstract.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_REFERENCE_COUNTER_KERNEl_ABSTRACT_
#ifdef DLIB_REFERENCE_COUNTER_KERNEl_ABSTRACT_

#include "../algs.h"

namespace dlib
{

    template <
        typename T,
        typename copy = copy_functor<T>
        >
    class reference_counter
    {

        /*!
            REQUIREMENTS ON T
                T must have a default constructor

            REQUIREMENTS ON copy
                it should be a function object that copies an object of type T. and
                it must have a default constructor and
                operator() should be overloaded as
                void operator()(const T& source, T& destination);
                copy may throw any exception

            POINTERS AND REFERENCES TO INTERNAL DATA
                swap() and access() functions do not invalidate pointers or
                references to internal data.
                All other functions have no such guarantee

            INITIAL VALUE
                reference_counter contains one object of type T and
                this object of type T has its initial value

            WHAT THIS OBJECT REPRESENTS
                This object represents a container for an object of type T and
                provides reference counting capabilities for the object it contains

                Also note that unless specified otherwise, no member functions
                of this object throw exceptions.

        !*/

        public:

            typedef T type;

            reference_counter (
            );
            /*!
                ensures
                    - #*this is properly initialized
                throws
                    - std::bad_alloc or any exception thrown by T's constructor
            !*/

            reference_counter (
                const reference_counter& item
            );
            /*!
                ensures
                    - #access() == item.access()
            !*/

            virtual ~reference_counter (
            );
            /*!
                ensures
                    - all memory associated with *this has been released
            !*/

            void clear (
            );
            /*!
                ensures
                    - #*this has its initial value
                throws
                    - std::bad_alloc or any exception thrown by T's constructor
                        if this exception is thrown then *this is unusable
                        until clear() is called and succeeds
            !*/

            T& modify (
            );
            /*!
                ensures
                    - returns a non-const reference to the item contained in *this
                    - the item is ok to modify.  i.e. there are no other references to it
                throws
                    - std::bad_alloc or any exception thrown by T's constructor
                        modify() may throw this exception if there are other references
                        to the item and there is not enough memory to copy it. If modify()
                        throws then it has no effect.
            !*/

            const T& access (
            ) const;
            /*!
                ensures
                    - returns a const reference to the item contained in *this
                    - there may be other references to to the item
            !*/

            reference_counter& operator= (
                const reference_counter& rhs
            );
            /*!
                ensures
                    - #access() == rhs.access()
            !*/

            void swap (
                reference_counter& item
            );
            /*!
                ensures
                    - swaps *this and item
            !*/

    };

    template <
        typename T,
        typename copy
        >
    inline void swap (
        reference_counter<T,copy>& a,
        reference_counter<T,copy>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

}

#endif // DLIB_REFERENCE_COUNTER_KERNEl_ABSTRACT_


dlib C++ Library - ref.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_REFERENCE_WRAPpER_H_
#define DLIB_REFERENCE_WRAPpER_H_

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template<
        typename T
        >
    class reference_wrapper
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is a simple object that just holds a reference to another object.
                It is useful because it can serve as a kind of "copyable reference".
        !*/

    public:
        typedef T type;

        explicit reference_wrapper(T& o) : obj(&o) {}

        operator T&()    const { return  *obj; }
        T& get()         const { return  *obj; }

    private:
        T* obj;
    };

// ----------------------------------------------------------------------------------------

    template <typename T>
    reference_wrapper<T> ref(
        T& obj
    ) { return reference_wrapper<T>(obj); }
    /*!
        ensures
            - returns a reference_wrapper that contains a reference to obj.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    reference_wrapper<T> ref(
        reference_wrapper<T> obj
    ) { return obj; }
    /*!
        ensures
            - returns the given reference_wrapper object without modification
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    reference_wrapper<const T> cref(
        const T& obj
    ) { return reference_wrapper<const T>(obj); }
    /*!
        ensures
            - returns a reference_wrapper that contains a constant reference to obj.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    reference_wrapper<const T> cref(
        reference_wrapper<T> obj
    ) { return cref(obj.get()); }
    /*!
        ensures
            - converts the given reference_wrapper into a reference_wrapper that contains a
              constant reference.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_REFERENCE_WRAPpER_H_


dlib C++ Library - sequence_kernel_abstract.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SEQUENCE_KERNEl_ABSTRACT_
#ifdef DLIB_SEQUENCE_KERNEl_ABSTRACT_

#include "../interfaces/enumerable.h"
#include "../interfaces/remover.h"
#include "../serialize.h"
#include "../algs.h"

namespace dlib
{
    template <
        typename T,
        typename mem_manager = default_memory_manager
        >
    class sequence : public enumerable<T>,
                     public remover<T>
    {

        /*!
            REQUIREMENTS ON T
                T must be swappable by a global swap() and
                T must have a default constructor

            REQUIREMENTS ON mem_manager
                must be an implementation of memory_manager/memory_manager_kernel_abstract.h or
                must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or
                must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h
                mem_manager::type can be set to anything.

            POINTERS AND REFERENCES TO INTERNAL DATA
                swap() and operator[] functions do not invalidate pointers or
                references to internal data.
                All other functions have no such guarantees.

            ENUMERATION ORDER
                The enumerator will iterate over the elements in the sequence from
                the 0th element to the (size()-1)th element.

            INITIAL VALUE
                size() == 0

            WHAT THIS OBJECT REPRESENTS
                sequence contains items of type T

                This object represents an ordered sequence of items, each item is
                associated with an integer value.
                The items are numbered from 0 to size()-1

                Also note that unless specified otherwise, no member functions
                of this object throw exceptions.
        !*/

        public:

            typedef T type;
            typedef mem_manager mem_manager_type;

            sequence (
            );
            /*!
                ensures
                    - #*this is properly initialized
                throws
                    - std::bad_alloc or any exception thrown by T's constructor
            !*/

            virtual ~sequence (
            );
            /*!
                ensures
                    - all memory associated with *this has been released
            !*/

            void clear (
            );
            /*!
                ensures
                    - #*this has its initial value
                throws
                    - std::bad_alloc or any exception thrown by T's constructor
                        if this exception is thrown then *this is unusable
                        until clear() is called and succeeds
            !*/

            void add (
                unsigned long pos,
                T& item
            );
            /*!
                requires
                    - pos <= size()
                ensures
                    - #size() == size() + 1
                    - #item has an initial value for its type
                    - #operator[](pos) == item
                      i.e. item has been inserted into *this between the elements which
                      were previously at position pos-1 and pos
                    - #at_start() == true
                throws
                    - std::bad_alloc or any exception thrown by T's constructor
                        if add() throws then it has no effect
            !*/

            void remove (
                unsigned long pos,
                T& item
            );
            /*!
                requires
                    - pos < size()
                ensures
                    - #size() == size() - 1
                    - the element at the position pos in *this has been removed and
                      swapped into #item
                    - #at_start() == true
            !*/

            void cat (
                sequence& item
            );
            /*!
                requires
                    - &item != this  (i.e. you can't concatenate a sequence onto itself)
                ensures
                    - item has been concatenated onto the end of *this
                      i.e. item[0] becomes (#*this)[size()], item[1]
                      becomes (#*this)[size()+1], etc.
                    - #size() == size() + item.size()
                    - #item has its initial value
                    - #at_start() == true
            !*/

            const T& operator[] (
                unsigned long pos
            ) const;
            /*!
                requires
                    - pos < size()
                ensures
                    - returns a const reference to the element at position pos
            !*/

            T& operator[] (
                unsigned long pos
            );
            /*!
                requires
                    - pos < size()
                ensures
                    - returns a non-const reference to the element at position pos
            !*/

            void swap (
                sequence& item
            );
            /*!
                ensures
                    - swaps *this and item
            !*/

        private:

            // restricted functions
            sequence(sequence&);        // copy constructor
            sequence& operator=(sequence&);    // assignment operator

    };

    template <
        typename T,
        typename mem_manager
        >
    inline void swap (
        sequence<T,mem_manager>& a,
        sequence<T,mem_manager>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

    template <
        typename T,
        typename mem_manager
        >
    void deserialize (
        sequence<T,mem_manager>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/
}

#endif // DLIB_SEQUENCE_KERNEl_ABSTRACT_


dlib C++ Library - sequence_sort_abstract.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SEQUENCE_SORt_ABSTRACT_
#ifdef DLIB_SEQUENCE_SORt_ABSTRACT_

#include "sequence_kernel_abstract.h"

namespace dlib
{

    template <
        typename seq_base
        >
    class sequence_sort : public seq_base
    {

        /*!
            REQUIREMENTS ON T
                T must implement operator< for its type

            REQUIREMENTS ON seq_base
                must be an implementation of sequence/sequence_kernel_abstract.h

            POINTERS AND REFERENCES TO INTERNAL DATA
                sort() may invalidate pointers and references to data members.

            WHAT THIS EXTENSION DOES FOR sequence
                this gives a sequence the ability to sort its contents by calling sort()
        !*/

    public:

        void sort (
        );
        /*!
            ensures
                - for all elements in #*this the ith element is <= the i+1 element
                - #at_start() == true
            throws
                - std::bad_alloc or any exception thrown by T's constructor
                    data may be lost if sort() throws
        !*/

    };

    template <
        typename seq_base
        >
    inline void swap (
        sequence_sort<seq_base>& a,
        sequence_sort<seq_base>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

}

#endif // DLIB_SEQUENCE_SORt_ABSTRACT_


dlib C++ Library - sequence_compare_abstract.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SEQUENCE_COMPARe_ABSTRACT_
#ifdef DLIB_SEQUENCE_COMPARe_ABSTRACT_

#include "sequence_kernel_abstract.h"

#include "../algs.h"

namespace dlib
{

    template <
        typename seq_base
        >
    class sequence_compare : public seq_base
    {

        /*!
            REQUIREMENTS ON T
                T must implement operator< for its type and
                T must implement operator== for its type

            REQUIREMENTS ON SEQUENCE_BASE
                must be an implementation of sequence/sequence_kernel_abstract.h

            POINTERS AND REFERENCES TO INTERNAL DATA
                operator== and operator< do not invalidate pointers or references to
                data members

            WHAT THIS EXTENSION DOES FOR sequence
                This gives a sequence the ability to compare itself to other
                sequences using the < and == operators.
        !*/

    public:

        bool operator< (
            const sequence_compare& rhs
        ) const;
        /*!
            ensures
                - returns true if there exists an integer j such that 0 <= j < size()
                  and for all integers i such that 0 <= i < j where it is true that
                  (*this)[i] <= rhs[i] and (*this)[j] < rhs[j]
                - returns false if there is no j that will satisfy the above conditions
        !*/

        bool operator== (
            const sequence_compare& rhs
        ) const;
        /*!
            ensures
                - returns true if for all i: (*this)[i] == rhs[i] else returns false
        !*/

    };

    template <
        typename seq_base
        >
    inline void swap (
        sequence_compare<seq_base>& a,
        sequence_compare<seq_base>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

}

#endif // DLIB_SEQUENCE_COMPARe_ABSTRACT_


dlib C++ Library - set_kernel_abstract.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SET_KERNEl_ABSTRACT_
#ifdef DLIB_SET_KERNEl_ABSTRACT_

#include "../interfaces/enumerable.h"
#include "../interfaces/remover.h"
#include "../serialize.h"
#include "../algs.h"
#include <functional>

namespace dlib
{

    template <
        typename T,
        typename mem_manager = default_memory_manager,
        typename compare = std::less<T>
        >
    class set : public enumerable<const T>,
                public asc_remover<T,compare>
    {

        /*!
            REQUIREMENTS ON T
                T must be comparable by compare where compare is a functor compatible with std::less and
                T must be swappable by a global swap() and
                T must have a default constructor

            REQUIREMENTS ON mem_manager
                must be an implementation of memory_manager/memory_manager_kernel_abstract.h or
                must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or
                must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h
                mem_manager::type can be set to anything.

            POINTERS AND REFERENCES TO INTERNAL DATA
                swap() and is_member() functions do not invalidate pointers
                or references to internal data.
                All other functions have no such guarantee.

            INITIAL VALUE
                size() == 0

            ENUMERATION ORDER
                The enumerator will iterate over the elements in the set in
                ascending order according to the compare functor.
                (i.e. the elements are enumerated in sorted order)

            WHAT THIS OBJECT REPRESENTS
                set contains items of type T

                This object represents an unaddressed collection of items.
                Every element in a set is unique.

                definition of equivalent:
                a is equivalent to b if
                a < b == false and
                b < a == false
        !*/

        public:

            typedef T type;
            typedef compare compare_type;
            typedef mem_manager mem_manager_type;

            set(
            );
            /*!
                ensures
                    - #*this is properly initialized
                throws
                    - std::bad_alloc or any exception thrown by T's constructor
            !*/

            virtual ~set(
            );
            /*!
                ensures
                    - all memory associated with *this has been released
            !*/

            void clear(
            );
            /*!
                ensures
                    - #*this has its initial value
                throws
                    - std::bad_alloc or any exception thrown by T's constructor
                        if this exception is thrown then *this is unusable
                        until clear() is called and succeeds
            !*/

            void add (
                T& item
            );
            /*!
                requires
                    - is_member(item) == false
                ensures
                    - #is_member(item) == true
                    - #item has an initial value for its type
                    - #size() == size() + 1
                    - #at_start() == true
                throws
                    - std::bad_alloc or any exception thrown by T's constructor
                        if add() throws then it has no effect
            !*/

            bool is_member (
                const T& item
            ) const;
            /*!
                ensures
                    - returns whether or not there is an element in *this equivalent to
                      item
            !*/

            void remove (
                const T& item,
                T& item_copy
            );
            /*!
                requires
                    - is_member(item) == true
                    - &item != &item_copy (i.e. item and item_copy cannot be the same
                      variable)
                ensures
                    - #is_member(item) == false
                    - the element in *this equivalent to item has been removed and
                      swapped into #item_copy
                    - #size() == size() - 1
                    - #at_start() == true
            !*/

            void destroy (
                const T& item
            );
            /*!
                requires
                    - is_member(item) == true
                ensures
                    - #is_member(item) == false
                    - #size() == size() - 1
                    - #at_start() == true
            !*/

            void swap (
                set& item
            );
            /*!
                ensures
                    - swaps *this and item
            !*/

        private:

            // restricted functions
            set(set&);        // copy constructor
            set& operator=(set&);    // assignment operator

    };

    template <
        typename T,
        typename mem_manager,
        typename compare
        >
    inline void swap (
        set<T,mem_manager,compare>& a,
        set<T,mem_manager,compare>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

    template <
        typename T,
        typename mem_manager,
        typename compare
        >
    void deserialize (
        set<T,mem_manager,compare>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/
}

#endif // DLIB_SET_KERNEl_ABSTRACT_


dlib C++ Library - set_compare_abstract.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SET_COMPARe_ABSTRACT_
#ifdef DLIB_SET_COMPARe_ABSTRACT_

#include "set_kernel_abstract.h"

#include "../algs.h"

namespace dlib
{

    template <
        typename set_base
        >
    class set_compare : public set_base
    {

        /*!
            REQUIREMENTS ON set_base
                must be an implementation of set/set_kernel_abstract.h

            POINTERS AND REFERENCES TO INTERNAL DATA
                operator== and operator< invalidate pointers or references to
                data members.

            WHAT THIS EXTENSION DOES FOR set
                This gives a set the ability to compare itself to other
                sets using the < and == operators.

                The < operator is conceptually weird for sets.  It is useful
                though because it allows you to make sets of sets since
                sets require that their containing type implement operator<.

                Also note that it is the case that for any two sets a and b
                if (a<b) == false and (b<a) == false then a == b.

                Also note that unless specified otherwise, no member functions
                of this object throw exceptions.

            NOTATION
                For the purposes of defining what these operators do I will
                use the operator[] to reference the elements of the sets.
                operator[] is defined to access the elements of the set in
                the same order they would be enumerated by the enumerable
                interface.
        !*/

        public:

            bool operator< (
                const set_compare& rhs
            ) const;
            /*!
                ensures
                    - #at_start() == true
                    - if (size() < rhs.size()) then
                        - returns true
                    - else if (size() > rhs.size()) then
                        - returns false
                    - else
                        - returns true if there exists an integer j such that 0 <= j < size()
                          and for all integers i such that 0 <= i < j where it is true that
                          (*this)[i] == rhs[i] and (*this)[j] < rhs[j]
                        - returns false if there is no j that will satisfy the above conditions.
            !*/

            bool operator== (
                const set_compare& rhs
            ) const;
            /*!
                ensures
                    - #at_start() == true
                    - returns true if *this and rhs contain the same elements.
                      returns false otherwise.
            !*/
    };

    template <
        typename set_base
        >
    inline void swap (
        set_compare<set_base>& a,
        set_compare<set_base>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

}

#endif // DLIB_SET_COMPARe_ABSTRACT_


dlib C++ Library - sliding_buffer_kernel_abstract.h

// Copyright (C) 2004  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SLIDING_BUFFER_KERNEl_ABSTRACT_
#ifdef DLIB_SLIDING_BUFFER_KERNEl_ABSTRACT_

#include "../algs.h"
#include "../interfaces/enumerable.h"
#include "../serialize.h"

namespace dlib
{

    template <
        typename T
        >
    class sliding_buffer : public enumerable<T>
    {
        /*!
            REQUIREMENTS ON T
                T must have a default constructor

            INITIAL VALUE
                size() == 0

            ENUMERATION ORDER
                The enumerator will iterate over the elements of the sliding_buffer in the
                order (*this)[0], (*this)[1], (*this)[2], ...

            WHAT THIS OBJECT REPRESENTS
                This object represents an array of T objects.  The main
                feature of this object is its ability to rotate its contents
                left or right.   An example will make it clear.

                suppose we have the following buffer (assuming T is a char):
                "some data!"    <-- the data in the buffer
                 9876543210     <-- the index numbers associated with each character

                applying rotate_left(2) to this buffer would give us
                "me data!so"
                 9876543210

                if instead of calling rotate_left we call rotate_right(3) instead we would have
                "ta!some da"
                 9876543210

                Also note that unless specified otherwise, no member functions
                of this object throw exceptions.
        !*/

    public:

        typedef T type;

        sliding_buffer (
        );
        /*!
            ensures
                - #*this is properly initialized
            throws
                - std::bad_alloc or any exception thrown by T's constructor.
        !*/

        virtual ~sliding_buffer (
        );
        /*!
            ensures
                - any resources associated with *this have been released
        !*/

        void clear(
        );
        /*!
            ensures
                - #*this has its initial value
            throws
                - std::bad_alloc or any exception thrown by T's constructor.
                    if this exception is thrown then #*this is unusable
                    until clear() is called and succeeds
        !*/

        void set_size (
            unsigned long exp_size
        );
        /*!
            requires
                - 0 < exp_size < 32
            ensures
                - #size() == 2^exp_size
                - the value of all elements in the buffer are undefined
                - #at_start() == true
            throws
                - std::bad_alloc or any exception thrown by T's constructor.
                    if this exception is thrown then #size() == 0
        !*/

        void rotate_left (
            unsigned long amount
        );
        /*!
            ensures
                - for all i where 0 <= i < size():
                  (#*this)[i] == (*this)[(i-amount)&(size()-1)]
                  i.e. rotates the contents of *this left by amount spaces
                - #at_start() == true
        !*/

        void rotate_right (
            unsigned long amount
        );
        /*!
            ensures
                - for all i where 0 <= i < size():
                  (#*this)[i] == (*this)[(i+amount)&(size()-1)]
                  i.e. rotates the contents of *this right by amount spaces
                - #at_start() == true
        !*/

        unsigned long get_element_id (
            unsigned long index
        ) const;
        /*!
            requires
                - index < size()
            ensures
                - returns an element id number that uniquely references the element at
                  the given index.  (you can use this id to locate the new position of
                  an element after the buffer has been rotated)
                - returned value is < size()
        !*/

        unsigned long get_element_index (
            unsigned long element_id
        ) const;
        /*!
            require
                - element_id < size()
            ensures
                - returns the index of the element with the given element_id.
                  ( (*this)[get_element_index(element_id)] will always refer to the same element
                  no matter where it has been rotated to)
                - returned value is < size()
        !*/

        const T& operator[] (
            unsigned long index
        ) const;
        /*!
            requires
                - index < size()
            ensures
                - returns a const reference to the element in *this at position index
        !*/

        T& operator[] (
            unsigned long index
        );
        /*!
            requires
                - index < size()
            ensures
                - returns a reference to the element in *this at position index
        !*/

        void swap (
            sliding_buffer<T>& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/

    private:

        // restricted functions
        sliding_buffer(sliding_buffer<T>&);        // copy constructor
        sliding_buffer<T>& operator=(sliding_buffer<T>&);    // assignment operator

    };

    template <
        typename T
        >
    void swap (
        sliding_buffer<T>& a,
        sliding_buffer<T>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

    template <
        typename T
        >
    void deserialize (
        sliding_buffer<T>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

}

#endif // DLIB_SLIDING_BUFFER_KERNEl_ABSTRACT_


dlib C++ Library - stack_kernel_abstract.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_STACK_KERNEl_ABSTRACT_
#ifdef DLIB_STACK_KERNEl_ABSTRACT_

#include "../interfaces/enumerable.h"
#include "../interfaces/remover.h"
#include "../serialize.h"
#include "../algs.h"

namespace dlib
{

    template <
        typename T,
        typename mem_manager = default_memory_manager
        >
    class stack : public enumerable<T>,
                  public remover<T>
    {

        /*!
            REQUIREMENTS ON T
                T must be swappable by a global swap() and
                T must have a default constructor

            REQUIREMENTS ON mem_manager
                must be an implementation of memory_manager/memory_manager_kernel_abstract.h or
                must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or
                must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h
                mem_manager::type can be set to anything.

            POINTERS AND REFERENCES TO INTERNAL DATA
                swap() and current() functions do not invalidate pointers
                or references to internal data.
                All other functions have no such guarantee.

            INITIAL VALUE
                size() == 0

            ENUMERATION ORDER
                The enumerator will iterate over the elements in the stack in the
                same order they would be removed in by repeated calls to pop().
                (e.g. current() would be the first element enumerated)

            WHAT THIS OBJECT REPRESENTS
                This is a last in first out stack containing items of type T.

                e.g. if the stack is {b,c,d,e} then a is put in
                the stack becomes {a,b,c,d,e} and then pop takes a back out
                returning the stack to {b,c,d,e}

                Also note that unless specified otherwise, no member functions
                of this object throw exceptions.
        !*/

        public:

            typedef T type;
            typedef mem_manager mem_manager_type;

            stack (
            );
            /*!
                ensures
                    - #*this is properly initialized
                throws
                    - std::bad_alloc or any exception thrown by T's constructor
            !*/

            virtual ~stack (
            );
            /*!
                ensures
                    - all memory associated with *this has been released
            !*/

            void clear(
            );
            /*!
                ensures
                    - #*this has its initial value
                throws
                    - std::bad_alloc or any exception thrown by T's constructor
                        if this exception is thrown then *this is unusable
                        until clear() is called and succeeds
            !*/

            void push (
                T& item
            );
            /*!
                ensures
                    - item has been swapped onto the top of the stack
                    - #current() == item
                    - #item has an initial value for its type
                    - #size() == size() + 1
                    - #at_start() == true
                throws
                    - std::bad_alloc or any exception thrown by T's constructor
                        if push() throws then it has no effect
            !*/

            void pop (
                T& item
            );
            /*!
                requires
                    - size() != 0
                ensures
                    - #size() == size() - 1
                    - #item   == current()
                      i.e. the top element of *this has been removed and swapped
                      into #item
                    - #at_start() == true
            !*/

            T& current (
            );
            /*!
                requires
                    - size() != 0
                ensures
                    - returns a const reference to the element at the top of *this
            !*/

            const T& current (
            ) const;
            /*!
                requires
                    - size() != 0
                ensures
                    - returns a non-const reference to the element at the top of *this
            !*/

            void swap (
                stack& item
            );
            /*!
                ensures
                    - swaps *this and item
            !*/

        private:

            // restricted functions
            stack(stack&);        // copy constructor
            stack& operator=(stack&);    // assignment operator

    };

    template <
        typename T,
        typename mem_manager
        >
    inline void swap (
        stack<T,mem_manager>& a,
        stack<T,mem_manager>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

    template <
        typename T,
        typename mem_manager
        >
    void deserialize (
        stack<T,mem_manager>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/
}

#endif // DLIB_STACK_KERNEl_ABSTRACT_


dlib C++ Library - static_map_kernel_abstract.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_STATIC_MAP_KERNEl_ABSTRACT_
#ifdef DLIB_STATIC_MAP_KERNEl_ABSTRACT_

#include "../interfaces/map_pair.h"
#include "../interfaces/enumerable.h"
#include "../interfaces/remover.h"
#include "../serialize.h"
#include <functional>

namespace dlib
{

    template <
        typename domain,
        typename range,
        typename compare = std::less<domain>
        >
    class static_map : public enumerable<map_pair<domain,range> >
    {

        /*!
            REQUIREMENTS ON domain
                domain must be comparable by compare where compare is a functor compatible with std::less and
                domain is swappable by a global swap() and
                domain must have a default constructor

            REQUIREMENTS ON range
                range is swappable by a global swap() and
                range must have a default constructor

            POINTERS AND REFERENCES TO INTERNAL DATA
                Only the destructor and load_from() will invalidate pointers or
                references to internal data.

            INITIAL VALUE
                size() == 0

            ENUMERATION ORDER
                The enumerator will iterate over the domain (and each associated
                range element) elements in ascending order according to the compare functor.
                (i.e. the elements are enumerated in sorted order)

            WHAT THIS OBJECT REPRESENTS
                static_map contains items of type domain and range

                This object is similar an array.  It maps items of type domain on to
                items of type range.

                Also note that unless specified otherwise, no member functions
                of this object throw exceptions.

            NOTE
                definition of equivalent:
                a is equivalent to b if
                a < b == false and
                b < a == false
        !*/

        public:

            typedef domain domain_type;
            typedef range range_type;
            typedef compare compare_type;

            static_map (
            );
            /*!
                ensures
                    - #*this is properly initialized
                throws
                    - std::bad_alloc or any exception thrown by domain's or range's
                      constructor.
            !*/

            virtual ~static_map(
            );
            /*!
                ensures
                    - all memory associated with *this has been released
            !*/

            void clear(
            );
            /*!
                ensures
                    - #*this has its initial value
                throws
                    - std::bad_alloc or any exception thrown by domain's or range's
                      constructor.
                        If this exception is thrown then #*this is unusable
                        until clear() is called and succeeds.
            !*/

            void load (
                pair_remover<domain,range>& source
            );
            /*!
                ensures
                    - #size() == source.size()
                    - #source.size() == 0
                    - all the pairs in source are removed and placed into #*this
                    - #at_start() == true
                throws
                    - std::bad_alloc or any exception thrown by domain's or range's
                      constructor.
                        If this exception is thrown then the call to load() will have
                        no effect on #*this.
            !*/

            const range* operator[] (
                const domain& d
            ) const;
            /*!
                ensures
                    - if (there is an element in the domain equivalent to d) then
                        - returns a pointer to an element in the range of *this that
                          is associated with an element in the domain of *this
                          equivalent to d.
                    - else
                        - returns 0
            !*/

            range* operator[] (
                const domain& d
            );
            /*!
                ensures
                    - if (there is an element in the domain equivalent to d) then
                        - returns a pointer to an element in the range of *this that
                          is associated with an element in the domain of *this
                          equivalent to d.
                    - else
                        - returns 0
            !*/

            void swap (
                static_map& item
            );
            /*!
                ensures
                    - swaps *this and item
            !*/

        private:

            // restricted functions
            static_map(static_map&);        // copy constructor
            static_map& operator=(static_map&);    // assignment operator
    };

    template <
        typename domain,
        typename range,
        typename compare
        >
    inline void swap (
        static_map<domain,range,compare>& a,
        static_map<domain,range,compare>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

    template <
        typename domain,
        typename range,
        typename compare
        >
    void deserialize (
        static_map<domain,range,compare>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/
}

#endif // DLIB_STATIC_MAP_KERNEl_ABSTRACT_


dlib C++ Library - static_set_kernel_abstract.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_STATIC_SET_KERNEl_ABSTRACT_
#ifdef DLIB_STATIC_SET_KERNEl_ABSTRACT_

#include "../interfaces/enumerable.h"
#include "../interfaces/remover.h"
#include "../serialize.h"
#include <functional>

namespace dlib
{

    template <
        typename T,
        typename compare = std::less<T>
        >
    class static_set : public enumerable<const T>
    {

        /*!
            REQUIREMENTS ON T
                T must be comparable by compare where compare is a functor compatible with std::less and
                T is swappable by a global swap() and
                T must have a default constructor

            POINTERS AND REFERENCES TO INTERNAL DATA
                Only the destructor will invalidate pointers or references
                to internal data.

            INITIAL VALUE
                size() == 0

            ENUMERATION ORDER
                The enumerator will iterate over the elements in the set in
                ascending order according to the compare functor.
                (i.e. the elements are enumerated in sorted order)

            WHAT THIS OBJECT REPRESENTS
                static_set contains items of type T

                This object represents an unaddressed collection of items.

                Also note that unless specified otherwise, no member functions
                of this object throw exceptions.

            NOTE
                definition of equivalent:
                a is equivalent to b if
                a < b == false and
                b < a == false
        !*/

        public:

            typedef T type;
            typedef compare compare_type;

            static_set (
            );
            /*!
                ensures
                    - #*this is properly initialized
                throws
                    - std::bad_alloc or any exception thrown by T's constructor.
            !*/

            virtual ~static_set(
            );
            /*!
                ensures
                    - all memory associated with *this has been released
            !*/

            void clear(
            );
            /*!
                ensures
                    - #*this has its initial value
                throws
                    - std::bad_alloc or any exception thrown by T's constructor.
                        If this exception is thrown then #*this is unusable
                        until clear() is called and succeeds.
            !*/

            void load (
                remover<T>& source
            );
            /*!
                ensures
                    - #size() == source.size()
                    - #source.size() == 0
                    - all the elements in source are removed and placed into #*this
                    - #at_start() == true
                throws
                    - std::bad_alloc or any exception thrown by T's constructor.
                        If this exception is thrown then the call to load() will have
                        no effect on #*this.
            !*/

            bool is_member (
                const T& item
            ) const;
            /*!
                ensures
                    - if (there is an item in *this equivalent to item) then
                        - returns true
                    - else
                        - returns false
            !*/

            void swap (
                static_set& item
            );
            /*!
                ensures
                    - swaps *this and item
            !*/

        private:

            // restricted functions
            static_set(static_set&);        // copy constructor
            static_set& operator=(static_set&);    // assignment operator
    };

    template <
        typename T,
        typename compare
        >
    inline void swap (
        static_set<T,compare>& a,
        static_set<T,compare>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

    template <
        typename T,
        typename compare
        >
    void deserialize (
        static_set<T,compare>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

}

#endif // DLIB_STATIC_SET_KERNEl_ABSTRACT_


dlib C++ Library - static_set_compare_abstract.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_STATIC_SET_COMPARe_ABSTRACT_
#ifdef DLIB_STATIC_SET_COMPARe_ABSTRACT_

#include "static_set_kernel_abstract.h"

#include "../algs.h"

namespace dlib
{

    template <
        typename static_set_base
        >
    class static_set_compare : public static_set_base
    {

        /*!
            REQUIREMENTS ON static_set_base
                must an implementation of static_set/static_set_kernel_abstract.h

            POINTERS AND REFERENCES TO INTERNAL DATA
                operator== and operator< invalidate pointers or references to
                data members.

            WHAT THIS EXTENSION DOES FOR static_set
                This gives a static_set the ability to compare itself to other
                static_sets using the < and == operators.

                The < operator is conceptually weird for sets.  It is useful
                though because it allows you to make sets of sets since
                sets require that their containing type implement operator<.

                Also note that it is the case that for any two sets a and b
                if (a<b) == false and (b<a) == false then a == b.

            NOTATION
                For the purposes of defining what these operators do I will
                use the operator[] to reference the elements of the static_sets.
                operator[] is defined to access the elements of the static_set in
                the same order they would be enumerated by the enumerable
                interface.
        !*/

        public:

            bool operator< (
                const static_set_compare& rhs
            ) const;
            /*!
                ensures
                    - #at_start() == true
                    - if (size() < rhs.size()) then
                        - returns true
                    - else if (size() > rhs.size()) then
                        - returns false
                    - else
                        - returns true if there exists an integer j such that 0 <= j < size()
                          and for all integers i such that 0 <= i < j where it is true that
                          (*this)[i] == rhs[i] and (*this)[j] < rhs[j]
                        - returns false if there is no j that will satisfy the above conditions.
            !*/

            bool operator== (
                const static_set_compare& rhs
            ) const;
            /*!
                ensures
                    - #at_start() == true
                    - returns true if *this and rhs contain the same elements.
                      returns false otherwise.
            !*/
    };

    template <
        typename static_set_base
        >
    inline void swap (
        static_set_compare<static_set_base>& a,
        static_set_compare<static_set_base>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

}

#endif // DLIB_STATIC_SET_COMPARe_ABSTRACT_


dlib C++ Library - std_vector_c_abstract.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_STD_VECTOr_C_ABSTRACT_H_
#ifdef DLIB_STD_VECTOr_C_ABSTRACT_H_

#include <vector>
#include <algorithm>
#include "../assert.h"

namespace dlib
{

    template <
        typename T,
        typename Allocator = std::allocator<T>
        >
    class std_vector_c : public std::vector<T,Allocator>
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is a simple wrapper around the std::vector object.  It
                provides an identical interface but also checks the preconditions of
                each member function.  That is, if you violate a requires
                clause the dlib::fatal_error exception is thrown.
        !*/

        typedef typename std::vector<T,Allocator> base_type;
    public:
        typedef typename Allocator::reference         reference;
        typedef typename Allocator::const_reference   const_reference;
        typedef typename base_type::iterator          iterator;
        typedef typename base_type::const_iterator    const_iterator;
        typedef typename base_type::size_type         size_type;
        typedef typename base_type::difference_type   difference_type;
        typedef T                                     value_type;
        typedef Allocator                             allocator_type;
        typedef typename Allocator::pointer           pointer;
        typedef typename Allocator::const_pointer     const_pointer;
        typedef std::reverse_iterator<iterator>       reverse_iterator;
        typedef std::reverse_iterator<const_iterator> const_reverse_iterator;

        explicit std_vector_c(
            const Allocator& alloc = Allocator()
        );
        /*!
            ensures
                - #get_allocator() == alloc
                - #size() == 0
        !*/

        explicit std_vector_c (
            size_type n,
            const T& value = T(),
            const Allocator& alloc = Allocator()
        );
        /*!
            ensures
                - #size() == n
                - #get_allocator() == alloc
                - for all valid i:
                    - (*this)[i] == value
        !*/

        template <typename InputIterator>
        std_vector_c (
            InputIterator first,
            InputIterator last,
            const Allocator& alloc = Allocator()
        );
        /*!
            ensures
                - #size() == std::distance(first,last)
                - #get_allocator() == alloc
                - std::equal(first, last, begin()) == true
        !*/

        std_vector_c(
            const std::vector<T,Allocator>& x
        );
        /*!
            ensures
                - #*this == x
        !*/

        std_vector_c<T,Allocator>& operator= (
            const std::vector<T,Allocator>& x
        );
        /*!
            ensures
                - #*this == x
                - returns #*this
        !*/

        template <typename InputIterator>
        void assign(
            InputIterator first,
            InputIterator last
        );
        /*!
            ensures
                - #size() == std::distance(first,last)
                - std::equal(first, last, begin()) == true
        !*/

        void assign(
            size_type n,
            const T& value
        );
        /*!
            ensures
                - #size() == n
                - for all valid i:
                    - (*this)[i] == value
        !*/

        allocator_type get_allocator(
        ) const;
        /*!
            ensures
                - returns the allocator used by this vector
        !*/

        iterator begin(
        );
        /*!
            ensures
                - if (size() > 0) then
                    - returns an iterator referring to the first element in
                      this container.
                - else
                    - returns end()
        !*/

        const_iterator begin(
        ) const;
        /*!
            ensures
                - if (size() > 0) then
                    - returns a const_iterator referring to the first element in
                      this container.
                - else
                    - returns end()
        !*/

        iterator end(
        );
        /*!
            ensures
                - returns an iterator that represents one past the end of
                  this container
        !*/

        const_iterator end(
        ) const;
        /*!
            ensures
                - returns an iterator that represents one past the end of
                  this container
        !*/

        reverse_iterator rbegin(
        );
        /*!
            ensures
                - returns std::reverse_iterator(end())
        !*/

        const_reverse_iterator rbegin(
        ) const;
        /*!
            ensures
                - returns std::reverse_iterator(end())
        !*/

        reverse_iterator rend(
        );
        /*!
            ensures
                - returns std::reverse_iterator(begin())
        !*/

        const_reverse_iterator rend(
        ) const;
        /*!
            ensures
                - returns std::reverse_iterator(begin())
        !*/

        size_type size(
        ) const;
        /*!
            ensures
                - returns end()-begin()
                  (i.e. returns the number of elements in this container)
        !*/

        size_type max_size(
        ) const;
        /*!
            ensures
                - returns the maximum number of elements this vector can contain
        !*/

        void resize(
            size_type sz,
            T c = T()
        );
        /*!
            ensures
                - #size() == sz
                - any element with index between 0 and sz - 1 which was in the
                  vector before the call to resize() retains its value and index.
                  All other elements have a value given by c.
        !*/

        size_type capacity(
        ) const;
        /*!
            ensures
                - returns the total number of elements that the vector can hold without
                  requiring reallocation.
        !*/

        bool empty(
        ) const;
        /*!
            ensures
                - if (size() == 0) then
                    - returns true
                - else
                    - returns false
        !*/

        void reserve(
            size_type n
        );
        /*!
            ensures
                - #capacity() >= n
        !*/

        const_reference at(
            size_type n
        ) const;
        /*!
            ensures
                - if (n < size()) then
                    - returns a const reference to (*this)[n]
                - else
                    - throws std::out_of_range
        !*/

        reference at(
            size_type n
        );
        /*!
            ensures
                - if (n < size()) then
                    - returns a reference to (*this)[n]
                - else
                    - throws std::out_of_range
        !*/

        void push_back(
            const T& x
        );
        /*!
            ensures
                - #size() == size() + 1
                - #back() == x
        !*/

        void swap(
            std_vector_c<T,Allocator>& x
        );
        /*!
            ensures
                - swaps the state of *this and x
        !*/

        void clear(
        );
        /*!
            ensures
                - #size() == 0
        !*/

        reference operator[](
            size_type n
        );
        /*!
            requires
                - n < size()
            ensures
                - returns a reference to the nth element of this container
        !*/

        const_reference operator[](
            size_type n
        ) const;
        /*!
            requires
                - n < size()
            ensures
                - returns a const reference to the nth element of this container
        !*/

        reference front(
        );
        /*!
            requires
                - size() > 0
            ensures
                - returns a reference to (*this)[0]
        !*/

        const_reference front(
        ) const;
        /*!
            requires
                - size() > 0
            ensures
                - returns a const reference to (*this)[0]
        !*/

        reference back(
        );
        /*!
            requires
                - size() > 0
            ensures
                - returns a reference to (*this)[size()-1]
        !*/

        const_reference back(
        ) const;
        /*!
            requires
                - size() > 0
            ensures
                - returns a const reference to (*this)[size()-1]
        !*/

        void pop_back(
        );
        /*!
            requires
                - size() > 0
            ensures
                - #size() == size() - 1
                - removes the last element in the vector but leaves the others
                  unmodified.
        !*/

        iterator insert(
            iterator position,
            const T& x
        );
        /*!
            requires
                - begin() <= position && position <= end()
                  (i.e. position references an element in this vector object)
            ensures
                - #size() == size() + 1
                - inserts a copy of x into *this before the given position
                - returns an iterator that points to the copy of x inserted
                  into *this
        !*/

        void insert(
            iterator position,
            size_type n,
            const T& x
        );
        /*!
            requires
                - begin() <= position && position <= end()
                  (i.e. position references an element in this vector object)
            ensures
                - #size() == size() + n
                - inserts n copies of x into *this before the given position
        !*/

        template <typename InputIterator>
        void insert(
            iterator position,
            InputIterator first,
            InputIterator last
        );
        /*!
            requires
                - begin() <= position && position <= end()
                  (i.e. position references an element in this vector object)
                - first and last are not iterators into *this
            ensures
                - #size() == size() + std::distance(last,first)
                - inserts copies of the range of elements [first,last) into *this
                  before the given position
        !*/

        iterator erase(
            iterator position
        );
        /*!
            requires
                - begin() <= position && position < end()
                  (i.e. position references an element in this vector object)
            ensures
                - #size() == size() - 1
                - removes the element in this vector referenced by position but
                  leaves all other elements in this vector unmodified.
                - if (position < end()-1) then
                    - returns an iterator referencing the element immediately
                      following *position prior to the erase.
                - else
                    - returns end()
        !*/

        iterator erase(
            iterator first,
            iterator last
        );
        /*!
            requires
                - begin() <= first && first <= last && last <= end()
                  (i.e. the range [first,last) must be inside this container )
            ensures
                - #size() == size() - (last-first)
                - removes the elements in this vector referenced by the
                  iterator range [first,last) but leaves all other elements
                  in this vector unmodified.
                - if (last < end()-1) then
                    - returns an iterator referencing the element immediately
                      following *last prior to the erase.
                - else
                    - returns end()
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <typename T, typename alloc>
    void serialize (
        const std_vector_c<T,alloc>& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T, typename alloc>
    void deserialize (
        std_vector_c<T, alloc>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_STD_VECTOr_C_ABSTRACT_H_


dlib C++ Library - tuple_abstract.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_TUPLe_ABSTRACT_H_
#ifdef DLIB_TUPLe_ABSTRACT_H_

#include "../algs.h"
#include "../serialize.h"
#include "tuple_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    struct null_type
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is the default type used as the default
                template argument to the tuple object's template arguments.

                Also note that it has no state associated with it.
        !*/
    };

    inline void serialize (
        const null_type& ,
        std::ostream&
    ){}
    inline void deserialize (
        null_type& ,
        std::istream&
    ){}
    /*!
        Serialization support is provided for null_type because in some cases
        it makes your code a little more concise and easier to deal with
        when using tuple objects and serialization.  The serialization literally
        does nothing though.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T0 = null_type,
        typename T1 = null_type,
        typename T2 = null_type,
        typename T3 = null_type,
           ...
        typename T31 = null_type
        >
    class tuple
    {
        /*!
            INITIAL VALUE
                Each object in the tuple is default initialized by its own constructor.
                The tuple object itself does not modify them or add any additional
                state.

            WHAT THIS OBJECT REPRESENTS
                This object represents a container of between 0 and 31 objects
                where the objects contained are specified in the template
                arguments.

            EXAMPLE
                We can declare a tuple that contains an int, a float, and a char like so:
                tuple<int,float,char> ex;

                Then we can access each of these by their index number.  The index number
                is just the order each type has in the template argument list.  So we have:
                ex.get<0>() = 5;     // assign the int the value 5
                ex.get<1>() = 3.14;  // assign the float the value 3.14
                ex.get<2>() = 'c';   // assign the char the value 'c'

                Also, since we only have one of each type in this example tuple we can
                unambiguously access each field in the tuple by their types.  So for
                example, we can use this syntax to access our fields:
                ex.get<int>()   // returns 5
                ex.get<float>() // returns 3.14
                ex.get<char>()  // returns 'c'

                We can also get the indexes of each of these fields like so:
                ex.index<int>()   // returns 0
                ex.index<float>() // returns 1
                ex.index<char>()  // returns 2
        !*/

    public:
        // the maximum number of items this tuple template can contain
        const static long max_fields = 32;

        template <long index>
        struct get_type
        {
            typedef (the type of the Tindex template argument) type;
        };

        template <long index>
        const get_type<index>::type& get (
        ) const;
        /*!
            requires
                - 0 <= index <= 31
            ensures
                - returns a const reference to the index(th) object contained
                  inside this tuple
        !*/

        template <long index>
        get_type<index>::type& get (
        );
        /*!
            requires
                - 0 <= index <= 31
            ensures
                - returns a non-const reference to the index(th) object contained
                  inside this tuple
        !*/

        template <typename Q>
        const long index (
        ) const;
        /*!
            requires
                - Q is a type of object contained in this tuple and there is
                  only one object of that type in the tuple
            ensures
                - returns the index of the object in this tuple with type Q
        !*/

        template <typename Q>
        const Q& get (
        ) const;
        /*!
            requires
                - Q is a type of object contained in this tuple and there is
                  only one object of that type in the tuple
            ensures
                - returns a const reference to the object in this tuple
                  with type Q
        !*/

        template <typename Q>
        Q& get (
        );
        /*!
            requires
                - Q is a type of object contained in this tuple and there is
                  only one object of that type in the tuple
            ensures
                - returns a non-const reference to the object in this tuple
                  with type Q
        !*/

        template <typename F>
        void for_each (
            F& funct
        );
        /*!
            requires
                - funct is a templated function object
            ensures
                - for each item X in this tuple that isn't a null_type object:
                    - calls funct(X);
        !*/

        template <typename F>
        void for_each (
            F& funct
        ) const;
        /*!
            requires
                - funct is a templated function object
            ensures
                - for each item X in this tuple that isn't a null_type object:
                    - calls funct(X);
        !*/

        template <typename F>
        void for_each (
            const F& funct
        );
        /*!
            requires
                - funct is a templated function object
            ensures
                - for each item X in this tuple that isn't a null_type object:
                    - calls funct(X);
        !*/

        template <typename F>
        void for_each (
            const F& funct
        ) const;
        /*!
            requires
                - funct is a templated function object
            ensures
                - for each item X in this tuple that isn't a null_type object:
                    - calls funct(X);
        !*/

        template <typename F>
        void for_index (
            F& funct,
            long idx
        );
        /*!
            requires
                - funct is a templated function object
                - 0 <= idx < max_fields && get_type<idx>::type != null_type
                  (i.e. idx must be the index of a non-null_type object in this tuple)
            ensures
                - calls funct(this->get<idx>());
        !*/

        template <typename F>
        void for_index (
            F& funct,
            long idx
        ) const;
        /*!
            requires
                - funct is a templated function object
                - 0 <= idx < max_fields && get_type<idx>::type != null_type
                  (i.e. idx must be the index of a non-null_type object in this tuple)
            ensures
                - calls funct(this->get<idx>());
        !*/

        template <typename F>
        void for_index (
            const F& funct,
            long idx
        );
        /*!
            requires
                - funct is a templated function object
                - 0 <= idx < max_fields && get_type<idx>::type != null_type
                  (i.e. idx must be the index of a non-null_type object in this tuple)
            ensures
                - calls funct(this->get<idx>());
        !*/

        template <typename F>
        void for_index (
            const F& funct,
            long idx
        ) const;
        /*!
            requires
                - funct is a templated function object
                - 0 <= idx < max_fields && get_type<idx>::type != null_type
                  (i.e. idx must be the index of a non-null_type object in this tuple)
            ensures
                - calls funct(this->get<idx>());
        !*/

        void swap (
            tuple& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/

        // -------------------------------------------------
        //        global functions for tuple objects
        // -------------------------------------------------

        friend void swap (
            tuple& a,
            tuple& b
        ) { a.swap(b); }
        /*!
            provides a global swap function
        !*/

        friend void serialize (
            const tuple& item,
            std::ostream& out
        );
        /*!
            provides serialization support
        !*/

        friend void deserialize (
            tuple& item,
            std::istream& in
        );
        /*!
            provides deserialization support
        !*/

    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_TUPLe_ABSTRACT_H_


dlib C++ Library - type_safe_union_kernel_abstract.h

// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_TYPE_SAFE_UNION_KERNEl_ABSTRACT_
#ifdef DLIB_TYPE_SAFE_UNION_KERNEl_ABSTRACT_

#include "../algs.h"
#include "../noncopyable.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class bad_type_safe_union_cast : public std::bad_cast
    {
        /*!
            This is the exception object thrown by type_safe_union::cast_to() if the
            type_safe_union does not contain the type of object being requested.
        !*/
    };

// ----------------------------------------------------------------------------------------

    template <
        typename T1,
        typename T2 = _void,  // _void indicates parameter not used.
        typename T3 = _void,
        typename T4 = _void,
        typename T5 = _void,
        typename T6 = _void,
        typename T7 = _void,
        typename T8 = _void,
        typename T9 = _void,
        typename T10 = _void,
        typename T11 = _void,
        typename T12 = _void,
        typename T13 = _void,
        typename T14 = _void,
        typename T15 = _void,
        typename T16 = _void,
        typename T17 = _void,
        typename T18 = _void,
        typename T19 = _void,
        typename T20 = _void
        >
    class type_safe_union : noncopyable
    {
        /*!
            REQUIREMENTS ON ALL TEMPLATE ARGUMENTS
                All template arguments must be default constructable and have
                a global swap.

            INITIAL VALUE
                - is_empty() == true
                - contains<U>() == false, for all possible values of U

            WHAT THIS OBJECT REPRESENTS
                This object is a type safe analogue of the classic C union object.
                The type_safe_union, unlike a union, can contain non-POD types such
                as std::string.

                For example:
                    union my_union
                    {
                        int a;
                        std::string b;   // Error, std::string isn't a POD
                    };

                    type_safe_union<int,std::string> my_type_safe_union;  // No error
        !*/

    public:

        typedef T1 type1;
        typedef T2 type2;
        typedef T3 type3;
        typedef T4 type4;
        typedef T5 type5;
        typedef T6 type6;
        typedef T7 type7;
        typedef T8 type8;
        typedef T9 type9;
        typedef T10 type10;
        typedef T11 type11;
        typedef T12 type12;
        typedef T13 type13;
        typedef T14 type14;
        typedef T15 type15;
        typedef T16 type16;
        typedef T17 type17;
        typedef T18 type18;
        typedef T19 type19;
        typedef T20 type20;

        type_safe_union(
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        template <typename T>
        type_safe_union (
            const T& item
        );
        /*!
            requires
                - T must be one of the types given to this object's template arguments
            ensures
                - this object is properly initialized
                - #get<T>() == item
                  (i.e. this object will contain a copy of item)
        !*/

        ~type_safe_union(
        );
        /*!
            ensures
                - all resources associated with this object have been freed
        !*/

        template <typename T>
        static int get_type_id (
        );
        /*!
           ensures
              - if (T is the same type as one of the template arguments) then
                 - returns a number indicating which template argument it is.
                   (e.g. if T is the same type as T3 then this function returns 3)
               - else
                  - returns -1
        !*/

        template <typename T>
        bool contains (
        ) const;
        /*!
            ensures
                - if (this type_safe_union currently contains an object of type T) then
                    - returns true
                - else
                    - returns false
        !*/

        bool is_empty (
        ) const;
        /*!
            ensures
                - if (this type_safe_union currently contains any object at all) then
                    - returns true
                - else
                    - returns false
        !*/

        template <typename T>
        void apply_to_contents (
            T& obj
        );
        /*!
            requires
                - obj is a function object capable of operating on all the types contained
                  in this type_safe_union.  I.e.  obj(this->get<U>()) must be a valid
                  expression for all the possible U types.
            ensures
                - if (is_empty() == false) then
                    - Let U denote the type of object currently contained in this type_safe_union
                    - calls obj(this->get<U>())
                    - The object returned by this->get<U>() will be non-const
        !*/

        template <typename T>
        void apply_to_contents (
            const T& obj
        );
        /*!
            requires
                - obj is a function object capable of operating on all the types contained
                  in this type_safe_union.  I.e.  obj(this->get<U>()) must be a valid
                  expression for all the possible U types.
            ensures
                - if (is_empty() == false) then
                    - Let U denote the type of object currently contained in this type_safe_union
                    - calls obj(this->get<U>())
                    - The object returned by this->get<U>() will be non-const
        !*/

        template <typename T>
        void apply_to_contents (
            T& obj
        ) const;
        /*!
            requires
                - obj is a function object capable of operating on all the types contained
                  in this type_safe_union.  I.e.  obj(this->get<U>()) must be a valid
                  expression for all the possible U types.
            ensures
                - if (is_empty() == false) then
                    - Let U denote the type of object currently contained in this type_safe_union
                    - calls obj(this->get<U>())
                    - The object returned by this->get<U>() will be const
        !*/

        template <typename T>
        void apply_to_contents (
            const T& obj
        ) const;
        /*!
            requires
                - obj is a function object capable of operating on all the types contained
                  in this type_safe_union.  I.e.  obj(this->get<U>()) must be a valid
                  expression for all the possible U types.
            ensures
                - if (is_empty() == false) then
                    - Let U denote the type of object currently contained in this type_safe_union
                    - calls obj(this->get<U>())
                    - The object returned by this->get<U>() will be const
        !*/

        template <typename T>
        T& get(
        );
        /*!
            requires
                - T must be one of the types given to this object's template arguments
            ensures
                - #is_empty() == false
                - #contains<T>() == true
                - if (contains<T>() == true)
                    - returns a non-const reference to the object contained in this type_safe_union.
                - else
                    - Constructs an object of type T inside *this
                    - Any previous object stored in this type_safe_union is destructed and its
                      state is lost.
                    - returns a non-const reference to the newly created T object.
        !*/

        template <typename T>
        const T& cast_to (
        ) const;
        /*!
            requires
                - T must be one of the types given to this object's template arguments
            ensures
                - if (contains<T>() == true) then
                    - returns a const reference to the object contained in this type_safe_union.
                - else
                    - throws bad_type_safe_union_cast
        !*/

        template <typename T>
        T& cast_to (
        );
        /*!
            requires
                - T must be one of the types given to this object's template arguments
            ensures
                - if (contains<T>() == true) then
                    - returns a non-const reference to the object contained in this type_safe_union.
                - else
                    - throws bad_type_safe_union_cast
        !*/

        template <typename T>
        type_safe_union& operator= (
            const T& item
        );
        /*!
            requires
                - T must be one of the types given to this object's template arguments
            ensures
                - #get<T>() == item
                  (i.e. this object will contain a copy of item)
                - returns *this
        !*/

        void swap (
            type_safe_union& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/

    };

// ----------------------------------------------------------------------------------------

    template < ...  >
    inline void swap (
        type_safe_union<...>& a,
        type_safe_union<...>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

// ----------------------------------------------------------------------------------------

    template < ... >
    void serialize (
        const type_safe_union<...>& item,
        std::ostream& out
    );
    /*!
        provides serialization support

        Note that type_safe_union objects are serialized as follows:
         - if (item.is_empty()) then
            - perform: serialize(0, out)
         - else
            - perform: serialize(item.get_type_id<type_of_object_in_item>(), out);
                       serialize(item.get<type_of_object_in_item>(), out);
    !*/

    template < ...  >
    void deserialize (
        type_safe_union<...>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_TYPE_SAFE_UNION_KERNEl_ABSTRACT_


dlib C++ Library - unordered_pair.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_UNORDERED_PAiR_Hh_
#define DLIB_UNORDERED_PAiR_Hh_

#include "serialize.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    struct unordered_pair
    {
        /*!
            REQUIREMENTS ON T
                T must be default constructable, copyable, and comparable using
                operator < and ==

            WHAT THIS OBJECT REPRESENTS
                This object is very similar to the std::pair struct except unordered_pair
                is only capable of representing an unordered set of two items rather than
                an ordered list of two items like std::pair.

                This is best illustrated by example.  Suppose we have the following
                five variables:
                    std::pair<int,int> p1(1, 5), p2(5,1);
                    unordered_pair<int> up1(1,5), up2(5,1), up3(6,7);

                Then it is the case that:
                    up1 == up2
                    up1 != up3
                    p1 != p2

               So the unordered_pair doesn't care about the order of the arguments.
               In this case, up1 and up2 are both equivalent.

        !*/

        typedef T type;
        typedef T first_type;
        typedef T second_type;

        const T first;
        const T second;

        unordered_pair() : first(), second()
        /*!
            ensures
                - #first and #second are default initialized
        !*/ {}

        unordered_pair(
            const T& a,
            const T& b
        ) :
            first( a < b ? a : b),
            second(a < b ? b : a)
        /*!
            ensures
                - #first <= #second
                - #first and #second contain copies of the items a and b.
        !*/ {}

        template <typename U>
        unordered_pair (
            const unordered_pair <U>& p
        ) :
            first(p.first),
            second(p.second)
        /*!
            ensures
                - #*this is a copy of p
        !*/ {}

        unordered_pair& operator= (
            const unordered_pair& item
        )
        /*!
            ensures
                - #*this == item
        !*/
        {
            const_cast<T&>(first) = item.first;
            const_cast<T&>(second) = item.second;
            return *this;
        }
    };

// ----------------------------------------------------------------------------------------

    template <typename T>
    bool operator==(const unordered_pair<T>& a, const unordered_pair <T>& b)
    {
        return a.first == b.first && a.second == b.second;
    }

    template <typename T>
    bool operator!=(const unordered_pair<T>& a, const unordered_pair <T>& b)
    {
        return !(a == b);
    }

    template <typename T>
    bool operator<(const unordered_pair<T>& a, const unordered_pair<T>& b)
    {
        return (a.first < b.first || (!(b.first < a.first) && a.second < b.second));
    }

    template <typename T>
    bool operator>(const unordered_pair<T>& a, const unordered_pair <T>& b)
    {
        return b < a;
    }

    template <typename T>
    bool operator<=(const unordered_pair<T>& a, const unordered_pair <T>& b)
    {
        return !(b < a);
    }

    template <typename T>
    bool operator>=(const unordered_pair<T>& a, const unordered_pair <T>& b)
    {
        return !(a < b);
    }

    template <typename T>
    unordered_pair<T> make_unordered_pair (const T& a, const T& b)
    {
        return unordered_pair<T>(a,b);
    }

// ----------------------------------------------------------------------------------------

    template <typename T>
    void serialize (
        const unordered_pair<T>& item,
        std::ostream& out
    )
    {
        try
        {
            serialize(item.first,out);
            serialize(item.second,out);
        }
        catch (serialization_error& e)
        { throw serialization_error(e.info + "\n   while serializing object of type unordered_pair"); }
    }

    template <typename T>
    void deserialize (
        unordered_pair<T>& item,
        std::istream& in
    )
    {
        try
        {
            T a, b;
            deserialize(a,in);
            deserialize(b,in);
            item = make_unordered_pair(a,b);
        }
        catch (serialization_error& e)
        { throw serialization_error(e.info + "\n   while deserializing object of type unordered_pair"); }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_UNORDERED_PAiR_Hh_


dlib C++ Library - scoped_ptr_abstract.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SCOPED_PTr_ABSTRACT_
#ifdef DLIB_SCOPED_PTr_ABSTRACT_

#include "../noncopyable.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <typename T>
    struct default_deleter
    {
        void operator() (
            T* item
        ) const;
        /*!
            ensures
                - if (T is an array type (e.g. int[])) then
                    - performs "delete [] item;"
                - else
                    - performs "delete item;"
        !*/
    };

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename deleter = default_deleter<T>
        >
    class scoped_ptr : noncopyable
    {
        /*!
            REQUIREMENTS ON deleter
                Must be a function object that performs deallocation of a pointer
                of type T.  For example, see the default_deleter type defined above.
                It must also not throw when constructed or when performing a delete.

            INITIAL VALUE
                defined by constructor

            WHAT THIS OBJECT REPRESENTS
                This is a smart pointer class inspired by the implementation of the scoped_ptr
                class found in the Boost C++ library.  So this is a simple smart pointer
                class which guarantees that the pointer contained within it will always be
                deleted.

                The class does not permit copying and so does not do any kind of
                reference counting.  Thus it is very simply and quite fast.

                Note that this class allows you to use pointers to arrays as well as
                pointers to single items.  To let it know that it is supposed to point
                to an array you have to declare it using the bracket syntax.  Consider
                the following examples:

                    // This is how you make a scoped pointer to a single thing
                    scoped_ptr<int> single_item(new int);

                    // This is how you can use a scoped pointer to contain array pointers.
                    // Note the use of [].  This ensures that the proper version of delete
                    // is called.
                    scoped_ptr<int[]> array_of_ints(new int[50]);
        !*/

    public:
        typedef T element_type;
        typedef deleter deleter_type;

        explicit scoped_ptr (
            T* p = 0
        );
        /*!
            ensures
                - #get() == p
        !*/

        ~scoped_ptr(
        );
        /*!
            ensures
                - if (get() != 0) then
                    - calls deleter()(get())
                      (i.e. uses the deleter type to delete the pointer that is
                      contained in this scoped pointer)
        !*/

        void reset (
            T* p = 0
        );
        /*!
            ensures
                - if (get() != 0) then
                    - calls deleter()(get())
                      (i.e. uses the deleter type to delete the pointer that is
                      contained in this scoped pointer)
                - #get() == p
                  (i.e. makes this object contain a pointer to p instead of whatever it
                  used to contain)
        !*/

        T& operator*(
        ) const;
        /*!
            requires
                - get() != 0
                - T is NOT an array type (e.g. not int[])
            ensures
                - returns a reference to *get()
        !*/

        T* operator->(
        ) const;
        /*!
            requires
                - get() != 0
                - T is NOT an array type (e.g. not int[])
            ensures
                - returns the pointer contained in this object
        !*/

        T& operator[](
            unsigned long idx
        ) const;
        /*!
            requires
                - get() != 0
                - T is an array type (e.g. int[])
            ensures
                - returns get()[idx]
        !*/

        T* get(
        ) const;
        /*!
            ensures
                - returns the pointer contained in this object
        !*/

        operator bool(
        ) const;
        /*!
            ensures
                - returns get() != 0
        !*/

        void swap(
            scoped_ptr& b
        );
        /*!
            ensures
                - swaps *this and item
        !*/
    };

    template <
        typename T
        >
    void swap(
        scoped_ptr<T>& a,
        scoped_ptr<T>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/
}

#endif // DLIB_SCOPED_PTr_ABSTRACT_


dlib C++ Library - shared_ptr_abstract.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SHARED_PTr_ABSTRACT_
#ifdef DLIB_SHARED_PTr_ABSTRACT_

#include "weak_ptr_abstract.h"
#include <exception>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class bad_weak_ptr: public std::exception {}

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    class shared_ptr
    {
        /*!
            INITIAL VALUE
                defined by constructors

            WHAT THIS OBJECT REPRESENTS
                This object represents a reference counted smart pointer.  Each shared_ptr
                contains a pointer to some object and when the last shared_ptr that points
                to the object is destructed or reset() then the object is guaranteed to be
                deleted.

                This is an implementation of the std::tr1::shared_ptr template from the
                document ISO/IEC PDTR 19768, Proposed Draft Technical Report on C++
                Library Extensions.  The only deviation from that document is that this
                shared_ptr is declared inside the dlib namespace rather than std::tr1.

            THREAD SAFETY
                This object is not thread safe.  Especially so since it is
                reference counted.  So you should take care to not have two shared_ptr
                objects in different threads that point to the same object.

                If you want a thread safe version of this object you should use the
                dlib::shared_ptr_thread_safe object instead.
        !*/

    public:

        typedef T element_type;

        shared_ptr(
        );
        /*!
            ensures
                - #get() == 0
                - #use_count() == 0
        !*/

        template<typename Y>
        explicit shared_ptr(
            Y* p
        );
        /*!
            requires
                - p is convertible to a T* type pointer
                - p can be deleted by calling "delete p;" and doing so will not throw exceptions
                - p != 0
            ensures
                - #get() == p
                - #use_count() == 1
                - #*this object owns the pointer p
            throws
                - std::bad_alloc
                  if this exception is thrown then "delete p;" is called
        !*/

        template<typename Y, typename D>
        shared_ptr(
            Y* p,
            const D& d
        );
        /*!
            requires
                - p is convertible to a T* type pointer
                - D is copy constructable (and the copy constructor of D doesn't throw)
                - p can be deleted by calling "d(p);" and doing so will not throw exceptions
                - p != 0
            ensures
                - #get() == p
                - #use_count() == 1
                - #*this object owns the pointer p
            throws
                - std::bad_alloc
                  if this exception is thrown then "d(p);" is called
        !*/

        shared_ptr(
            const shared_ptr& r
        );
        /*!
            ensures
                - #get() == #r.get()
                - #use_count() == #r.use_count()
                - If r is empty, constructs an empty shared_ptr object; otherwise, constructs
                  a shared_ptr object that shares ownership with r.
        !*/

        template<typename Y>
        shared_ptr(
            const shared_ptr<Y>& r
        );
        /*!
            requires
                - Y* is convertible to T*
            ensures
                - #get() == #r.get()
                - #use_count() == #r.use_count()
                - If r is empty, constructs an empty shared_ptr object; otherwise, constructs
                  a shared_ptr object that shares ownership with r.
        !*/

        template<typename Y>
        explicit shared_ptr(
            const weak_ptr<Y>& r
        );
        /*!
            requires
                - Y* is convertible to T*
            ensures
                - #get() == #r.get()
                - #use_count() == #r.use_count()
                - If r is empty, constructs an empty shared_ptr object; otherwise, constructs
                  a shared_ptr object that shares ownership with r.
            throws
                - bad_weak_ptr
                  this exception is thrown if r.expired() == true
        !*/

        template<typename Y>
        explicit shared_ptr(
            std::auto_ptr<Y>& r
        );
        /*!
            requires
                - p.get() != 0
                - p.release() is convertible to a T* type pointer
                - p.release() can be deleted by calling "delete p.release();" and doing so will not throw exceptions
            ensures
                - #get() == p.release()
                - #use_count() == 1
                - #r.get() == 0
                - #*this object owns the pointer p.release()
            throws
                - std::bad_alloc
        !*/

        ~shared_ptr(
        );
        /*!
            ensures
                - if (use_count() > 1)
                    - this object destroys itself but otherwise has no effect (i.e.
                      the pointer get() is still valid and shared between the remaining
                      shared_ptr objects)
                - else if (use_count() == 1)
                    - deletes the pointer get() by calling delete (or using the deleter passed
                      to the constructor if one was passed in)
                - else
                    - in this case get() == 0 so there is nothing to do so nothing occurs
        !*/

        shared_ptr& operator= (
            const shared_ptr& r
        );
        /*!
            ensures
                - equivalent to shared_ptr(r).swap(*this).
                - returns #*this
        !*/

        template<typename Y>
        shared_ptr& operator= (
            const shared_ptr<Y>& r
        );
        /*!
            requires
                - Y* is convertible to T*
            ensures
                - equivalent to shared_ptr(r).swap(*this).
                - returns #*this
        !*/

        template<typename Y>
        shared_ptr& operator= (
            std::auto_ptr<Y>& r
        );
        /*!
            requires
                - p.get() != 0
                - p.release() is convertible to a T* type pointer
                - p.release() can be deleted by calling "delete p.release();" and doing so will not throw exceptions
            ensures
                - equivalent to shared_ptr(r).swap(*this).
                - returns #*this
        !*/

        void reset(
        );
        /*!
            ensures
                - equivalent to shared_ptr().swap(*this)
        !*/

        template<typename Y>
        void reset(
            Y* p
        );
        /*!
            requires
                - p is convertible to a T* type pointer
                - p can be deleted by calling "delete p;" and doing so will not throw exceptions
                - p != 0
            ensures
                - equivalent to shared_ptr(p).swap(*this)
        !*/

        template<typename Y, typename D>
        void reset(
            Y* p,
            const D& d
        );
        /*!
            requires
                - p is convertible to a T* type pointer
                - D is copy constructable (and the copy constructor of D doesn't throw)
                - p can be deleted by calling "d(p);" and doing so will not throw exceptions
                - p != 0
            ensures
                - equivalent to shared_ptr(p,d).swap(*this)
        !*/

        T* get(
        ) const;
        /*!
            ensures
                - returns the stored pointer
        !*/

        T& operator*(
        ) const;
        /*!
            requires
                - get() != 0
            ensures
                - returns a reference to *get()
        !*/

        T* operator->(
        ) const;
        /*!
            requires
                - get() != 0
            ensures
                - returns get()
        !*/

        bool unique(
        ) const;
        /*!
            ensures
                - returns (use_count() == 1)
        !*/

        long use_count(
        ) const;
        /*!
            ensures
                - The number of shared_ptr objects, *this included, that share ownership with *this, or 0 when *this
                  is empty.
        !*/

        operator bool(
        ) const;
        /*!
            ensures
                - returns (get() != 0)
        !*/

        void swap(
            shared_ptr& b
        );
        /*!
            ensures
                - swaps *this and item
        !*/

    };

// ----------------------------------------------------------------------------------------

    template<typename T, typename U>
    bool operator== (
        const shared_ptr<T>& a,
        const shared_ptr<U>& b
    );
    /*!
        ensures
            - returns a.get() == b.get()
    !*/

    template<typename T, typename U>
    bool operator!= (
        const shared_ptr<T>& a,
        const shared_ptr<U>& b
    ) { return a.get() != b.get(); }
    /*!
        ensures
            - returns a.get() != b.get()
    !*/

    template<typename T, typename U>
    bool operator< (
        const shared_ptr<T>& a,
        const shared_ptr<U>& b
    );
    /*!
        ensures
            - Defines an operator< on shared_ptr types appropriate for use in the associative
              containers.
    !*/

    template<typename T>
    void swap(
        shared_ptr<T>& a,
        shared_ptr<T>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

    template<typename T, typename U>
    shared_ptr<T> static_pointer_cast(
        const shared_ptr<U>& r
    );
    /*!
        - if (r.get() == 0) then
            - returns shared_ptr<T>()
        - else
            - returns a shared_ptr<T> object that stores static_cast<T*>(r.get()) and shares
              ownership with r.
    !*/

    template<typename T, typename U>
    shared_ptr<T> const_pointer_cast(
        const shared_ptr<U>& r
    );
    /*!
        - if (r.get() == 0) then
            - returns shared_ptr<T>()
        - else
            - returns a shared_ptr<T> object that stores const_cast<T*>(r.get()) and shares
              ownership with r.
    !*/

    template<typename T, typename U>
    shared_ptr<T> dynamic_pointer_cast(
        const shared_ptr<U>& r
    );
    /*!
        ensures
            - if (dynamic_cast<T*>(r.get()) returns a nonzero value) then
                - returns a shared_ptr<T> object that stores a copy of
                  dynamic_cast<T*>(r.get()) and shares ownership with r
            - else
                - returns an empty shared_ptr<T> object.
    !*/

    template<typename E, typename T, typename Y>
    std::basic_ostream<E, T> & operator<< (
        std::basic_ostream<E, T> & os,
        const shared_ptr<Y>& p
    );
    /*!
        ensures
            - performs os << p.get()
            - returns os
    !*/

    template<typename D, typename T>
    D* get_deleter(
        const shared_ptr<T>& p
    );
    /*!
        ensures
            - if (*this owns a deleter d of type cv-unqualified D) then
                - returns &d
            - else
                - returns 0
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SHARED_PTr_ABSTRACT_


dlib C++ Library - shared_ptr_thread_safe_abstract.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SHARED_PTr_THREAD_SAFE_ABSTRACT_
#ifdef DLIB_SHARED_PTr_THREAD_SAFE_ABSTRACT_

#include <exception>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    class shared_ptr_thread_safe
    {
        /*!
            INITIAL VALUE
                defined by constructors

            WHAT THIS OBJECT REPRESENTS
                This object represents a reference counted smart pointer.  Each shared_ptr_thread_safe
                contains a pointer to some object and when the last shared_ptr_thread_safe that points
                to the object is destructed or reset() then the object is guaranteed to be
                deleted.

                This is an implementation of the std::tr1::shared_ptr template from the
                document ISO/IEC PDTR 19768, Proposed Draft Technical Report on C++
                Library Extensions.  The only deviation from that document is that this
                shared_ptr_thread_safe is declared inside the dlib namespace rather than std::tr1,
                this one is explicitly thread safe, and there isn't a corresponding weak_ptr.

            THREAD SAFETY
                This is a version of the shared_ptr object that can be used to share pointers
                across more than one thread.  Note however, that individual instances of this object
                must still have access to them serialized by a mutex lock if they are to be modified
                by more than one thread.  But if you have two different shared_ptr_thread_safe objects
                that both point to the same thing from different threads then you are safe.
        !*/

    public:

        typedef T element_type;

        shared_ptr_thread_safe(
        );
        /*!
            ensures
                - #get() == 0
                - #use_count() == 0
        !*/

        template<typename Y>
        explicit shared_ptr_thread_safe(
            Y* p
        );
        /*!
            requires
                - p is convertible to a T* type pointer
                - p can be deleted by calling "delete p;" and doing so will not throw exceptions
                - p != 0
            ensures
                - #get() == p
                - #use_count() == 1
                - #*this object owns the pointer p
            throws
                - std::bad_alloc
                  if this exception is thrown then "delete p;" is called
        !*/

        template<typename Y, typename D>
        shared_ptr_thread_safe(
            Y* p,
            const D& d
        );
        /*!
            requires
                - p is convertible to a T* type pointer
                - D is copy constructable (and the copy constructor of D doesn't throw)
                - p can be deleted by calling "d(p);" and doing so will not throw exceptions
                - p != 0
            ensures
                - #get() == p
                - #use_count() == 1
                - #*this object owns the pointer p
            throws
                - std::bad_alloc
                  if this exception is thrown then "d(p);" is called
        !*/

        shared_ptr_thread_safe(
            const shared_ptr_thread_safe& r
        );
        /*!
            ensures
                - #get() == #r.get()
                - #use_count() == #r.use_count()
                - If r is empty, constructs an empty shared_ptr_thread_safe object; otherwise, constructs
                  a shared_ptr_thread_safe object that shares ownership with r.
        !*/

        template<typename Y>
        shared_ptr_thread_safe(
            const shared_ptr_thread_safe<Y>& r
        );
        /*!
            requires
                - Y* is convertible to T*
            ensures
                - #get() == #r.get()
                - #use_count() == #r.use_count()
                - If r is empty, constructs an empty shared_ptr_thread_safe object; otherwise, constructs
                  a shared_ptr_thread_safe object that shares ownership with r.
        !*/

        template<typename Y>
        explicit shared_ptr_thread_safe(
            std::auto_ptr<Y>& r
        );
        /*!
            requires
                - p.get() != 0
                - p.release() is convertible to a T* type pointer
                - p.release() can be deleted by calling "delete p.release();" and doing so will not throw exceptions
            ensures
                - #get() == p.release()
                - #use_count() == 1
                - #r.get() == 0
                - #*this object owns the pointer p.release()
            throws
                - std::bad_alloc
        !*/

        ~shared_ptr_thread_safe(
        );
        /*!
            ensures
                - if (use_count() > 1)
                    - this object destroys itself but otherwise has no effect (i.e.
                      the pointer get() is still valid and shared between the remaining
                      shared_ptr_thread_safe objects)
                - else if (use_count() == 1)
                    - deletes the pointer get() by calling delete (or using the deleter passed
                      to the constructor if one was passed in)
                - else
                    - in this case get() == 0 so there is nothing to do so nothing occurs
        !*/

        shared_ptr_thread_safe& operator= (
            const shared_ptr_thread_safe& r
        );
        /*!
            ensures
                - equivalent to shared_ptr_thread_safe(r).swap(*this).
                - returns #*this
        !*/

        template<typename Y>
        shared_ptr_thread_safe& operator= (
            const shared_ptr_thread_safe<Y>& r
        );
        /*!
            requires
                - Y* is convertible to T*
            ensures
                - equivalent to shared_ptr_thread_safe(r).swap(*this).
                - returns #*this
        !*/

        template<typename Y>
        shared_ptr_thread_safe& operator= (
            std::auto_ptr<Y>& r
        );
        /*!
            requires
                - p.get() != 0
                - p.release() is convertible to a T* type pointer
                - p.release() can be deleted by calling "delete p.release();" and doing so will not throw exceptions
            ensures
                - equivalent to shared_ptr_thread_safe(r).swap(*this).
                - returns #*this
        !*/

        void reset(
        );
        /*!
            ensures
                - equivalent to shared_ptr_thread_safe().swap(*this)
        !*/

        template<typename Y>
        void reset(
            Y* p
        );
        /*!
            requires
                - p is convertible to a T* type pointer
                - p can be deleted by calling "delete p;" and doing so will not throw exceptions
                - p != 0
            ensures
                - equivalent to shared_ptr_thread_safe(p).swap(*this)
        !*/

        template<typename Y, typename D>
        void reset(
            Y* p,
            const D& d
        );
        /*!
            requires
                - p is convertible to a T* type pointer
                - D is copy constructable (and the copy constructor of D doesn't throw)
                - p can be deleted by calling "d(p);" and doing so will not throw exceptions
                - p != 0
            ensures
                - equivalent to shared_ptr_thread_safe(p,d).swap(*this)
        !*/

        T* get(
        ) const;
        /*!
            ensures
                - returns the stored pointer
        !*/

        T& operator*(
        ) const;
        /*!
            requires
                - get() != 0
            ensures
                - returns a reference to *get()
        !*/

        T* operator->(
        ) const;
        /*!
            requires
                - get() != 0
            ensures
                - returns get()
        !*/

        bool unique(
        ) const;
        /*!
            ensures
                - returns (use_count() == 1)
        !*/

        long use_count(
        ) const;
        /*!
            ensures
                - The number of shared_ptr_thread_safe objects, *this included, that share ownership with *this, or 0 when *this
                  is empty.
        !*/

        operator bool(
        ) const;
        /*!
            ensures
                - returns (get() != 0)
        !*/

        void swap(
            shared_ptr_thread_safe& b
        );
        /*!
            ensures
                - swaps *this and item
        !*/

    };

// ----------------------------------------------------------------------------------------

    template<typename T, typename U>
    bool operator== (
        const shared_ptr_thread_safe<T>& a,
        const shared_ptr_thread_safe<U>& b
    );
    /*!
        ensures
            - returns a.get() == b.get()
    !*/

    template<typename T, typename U>
    bool operator!= (
        const shared_ptr_thread_safe<T>& a,
        const shared_ptr_thread_safe<U>& b
    ) { return a.get() != b.get(); }
    /*!
        ensures
            - returns a.get() != b.get()
    !*/

    template<typename T, typename U>
    bool operator< (
        const shared_ptr_thread_safe<T>& a,
        const shared_ptr_thread_safe<U>& b
    );
    /*!
        ensures
            - Defines an operator< on shared_ptr_thread_safe types appropriate for use in the associative
              containers.
    !*/

    template<typename T>
    void swap(
        shared_ptr_thread_safe<T>& a,
        shared_ptr_thread_safe<T>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

    template<typename T, typename U>
    shared_ptr_thread_safe<T> static_pointer_cast(
        const shared_ptr_thread_safe<U>& r
    );
    /*!
        - if (r.get() == 0) then
            - returns shared_ptr_thread_safe<T>()
        - else
            - returns a shared_ptr_thread_safe<T> object that stores static_cast<T*>(r.get()) and shares
              ownership with r.
    !*/

    template<typename T, typename U>
    shared_ptr_thread_safe<T> const_pointer_cast(
        const shared_ptr_thread_safe<U>& r
    );
    /*!
        - if (r.get() == 0) then
            - returns shared_ptr_thread_safe<T>()
        - else
            - returns a shared_ptr_thread_safe<T> object that stores const_cast<T*>(r.get()) and shares
              ownership with r.
    !*/

    template<typename T, typename U>
    shared_ptr_thread_safe<T> dynamic_pointer_cast(
        const shared_ptr_thread_safe<U>& r
    );
    /*!
        ensures
            - if (dynamic_cast<T*>(r.get()) returns a nonzero value) then
                - returns a shared_ptr_thread_safe<T> object that stores a copy of
                  dynamic_cast<T*>(r.get()) and shares ownership with r
            - else
                - returns an empty shared_ptr_thread_safe<T> object.
    !*/

    template<typename E, typename T, typename Y>
    std::basic_ostream<E, T> & operator<< (
        std::basic_ostream<E, T> & os,
        const shared_ptr_thread_safe<Y>& p
    );
    /*!
        ensures
            - performs os << p.get()
            - returns os
    !*/

    template<typename D, typename T>
    D* get_deleter(
        const shared_ptr_thread_safe<T>& p
    );
    /*!
        ensures
            - if (*this owns a deleter d of type cv-unqualified D) then
                - returns &d
            - else
                - returns 0
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SHARED_PTr_THREAD_SAFE_ABSTRACT_


dlib C++ Library - weak_ptr_abstract.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_WEAK_PTr_ABSTRACT_
#ifdef DLIB_WEAK_PTr_ABSTRACT_

#include "shared_ptr_abstract.h"

namespace dlib {

    template <
        typename T
        >
    class weak_ptr
    {

        /*!
            INITIAL VALUE
                defined by constructor

            WHAT THIS OBJECT REPRESENTS
                The weak_ptr class template stores a weak reference to an object that is
                already managed by a shared_ptr. To access the object, a weak_ptr can
                be converted to a shared_ptr using the member function lock().

                This is an implementation of the std::tr1::weak_ptr template from the
                document ISO/IEC PDTR 19768, Proposed Draft Technical Report on C++
                Library Extensions.  The only deviation from that document is that this
                shared_ptr is declared inside the dlib namespace rather than std::tr1.
        !*/

    public:
        typedef T element_type;

        weak_ptr(
        );
        /*!
            ensures
                - #use_count() == 0
                - creates an empty weak_ptr
        !*/

        template<typename Y>
        weak_ptr(
            const shared_ptr<Y>& r
        );
        /*!
            requires
                - Y* must be convertible to T*
            ensures
                - if (r is empty) then
                    - constructs an empty weak_ptr object
                - else
                    - constructs a weak_ptr object that shares ownership with r and
                      stores a copy of the pointer stored in r.
                - #use_count() == #r.use_count()
        !*/

        weak_ptr(
            const weak_ptr& r
        );
        /*!
            ensures
                - if (r is empty) then
                    - constructs an empty weak_ptr object
                - else
                    - constructs a weak_ptr object that shares ownership with r and
                      stores a copy of the pointer stored in r.
                - #use_count() == #r.use_count()
        !*/

        template<typename Y>
        weak_ptr(
            const weak_ptr<Y>& r
        );
        /*!
            requires
                - Y* must be convertible to T*
            ensures
                - if (r is empty) then
                    - constructs an empty weak_ptr object
                - else
                    - constructs a weak_ptr object that shares ownership with r and
                      stores a copy of the pointer stored in r.
                - #use_count() == #r.use_count()
        !*/

        ~weak_ptr(
        );
        /*!
            ensures
                - destroys this weak_ptr object but has no effect on the object its
                  stored pointer points to.
        !*/

        weak_ptr& operator= (
            const weak_ptr& r
        );
        /*!
            ensures
                - equivalent to weak_ptr(r).swap(*this)
        !*/

        template<typename Y>
        weak_ptr& operator= (
            const weak_ptr<Y>& r
        );
        /*!
            requires
                - Y* must be convertible to T*
            ensures
                - equivalent to weak_ptr(r).swap(*this)
        !*/

        template<typename Y>
        weak_ptr& operator=(
            const shared_ptr<Y>& r
        );
        /*!
            requires
                - Y* must be convertible to T*
            ensures
                - equivalent to weak_ptr(r).swap(*this)
        !*/

        long use_count(
        ) const;
        /*!
            ensures
                - if (*this is empty) then
                    - returns 0
                - else
                    - returns the number of shared_ptr instances that share ownership
                      with *this
        !*/

        bool expired(
        ) const;
        /*!
            ensures
                - returns (use_count() == 0)
        !*/

        shared_ptr<T> lock(
        ) const;
        /*!
            ensures
                - if (expired()) then
                    - returns shared_ptr<T>()
                - else
                    - returns shared_ptr<T>(*this)
        !*/

        void reset(
        );
        /*!
            ensures
                - equivalent to weak_ptr().swap(*this)
        !*/

        void swap(
            weak_ptr<T>& b
        );
        /*!
            ensures
                - swaps *this and item
        !*/

    };

    template<typename T, typename U>
    bool operator< (
        const weak_ptr<T>& a,
        const weak_ptr<U>& b
    );
    /*!
        ensures
            - Defines an operator< on shared_ptr types appropriate for use in the associative
              containers.
    !*/

    template<typename T>
    void swap(
        weak_ptr<T>& a,
        weak_ptr<T> & b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/
}

#endif // DLIB_WEAK_PTr_ABSTRACT_


dlib C++ Library - enumerable.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ENUMERABLe_INTERFACE_
#define DLIB_ENUMERABLe_INTERFACE_

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    class enumerable
    {
        /*!
            POINTERS AND REFERENCES TO INTERNAL DATA
                - if (at_start()) then
                    - all pointers and references to data returned via element() are
                      invalid.
                - calling move_next() or reset() invalidates pointers and references to
                  data returned via element() and only data returned via element().
                - calling at_start(), current_element_valid(), size(), or element()
                  does NOT invalidate pointers or references to any internal data.

            INITIAL VALUE
                current_element_valid() == false
                at_start() == true

            WHAT THIS OBJECT REPRESENTS
                This object represent an interface for iterating through the
                elements in a container.  It starts out one before the first element
                in the container.

                EXAMPLE:  The following loops though all elements in the container
                          and prints them to cout.

                    container.reset();
                    while(container.move_next()) {
                        cout << container.element();
                    }
        !*/

    public:
        typedef T type;

        inline virtual ~enumerable(
        ) = 0;

        virtual bool at_start (
        ) const = 0;
        /*!
            ensures
                - returns true if *this represents one position before the first element
                  in the container (this would also make the current element invalid)
                  else returns false
        !*/

        virtual void reset (
        ) const = 0;
        /*!
            ensures
                - #current_element_valid() == false
                - #at_start() == true
        !*/

        virtual bool current_element_valid (
        ) const = 0;
        /*!
            ensures
                - returns true if we are currently at a valid element else
                  returns false
        !*/

        virtual const T& element (
        ) const = 0;
        /*!
            requires
                - current_element_valid() == true
            ensures
                - returns a const reference to the current element
        !*/

        virtual T& element (
        ) = 0;
        /*!
            requires
                - current_element_valid() == true
            ensures
                - returns a non-const reference to the current element
        !*/

        virtual bool move_next (
        ) const = 0;
        /*!
            ensures
                - moves to the next element.  i.e. #element() will now
                  return the next element in the container
                - the return value will be equal to #current_element_valid()
                - #at_start() == false

                - returns true if there is another element
                - returns false if there are no more elements in the container
        !*/

        virtual unsigned long size (
        ) const = 0;
        /*!
            ensures
                - returns the number of elements in *this
        !*/

    protected:

        // restricted functions
        enumerable& operator=(const enumerable&) {return *this;} // no assignment operator

    };

    // destructor does nothing
    template <typename T>
    enumerable<T>::~enumerable() {}

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_ENUMERABLe_INTERFACE_


dlib C++ Library - map_pair.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MAP_PAIr_INTERFACE_
#define DLIB_MAP_PAIr_INTERFACE_

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename T1,
        typename T2
        >
    class map_pair
    {
        /*!
            POINTERS AND REFERENCES TO INTERNAL DATA
                None of the functions in map_pair will invalidate
                pointers or references to internal data when called.

            WHAT THIS OBJECT REPRESENTS
                this object is used to return the key/value pair used in the
                map and hash_map containers when using the enumerable interface.

                note that the enumerable interface is defined in
                interfaces/enumerable.h
        !*/

    public:
        typedef T1 key_type;
        typedef T2 value_type;

        virtual ~map_pair(
        )=0;

        virtual const T1& key(
        ) const =0;
        /*!
            ensures
                - returns a const reference to the key
        !*/

        virtual const T2& value(
        ) const =0;
        /*!
            ensures
                - returns a const reference to the value associated with key
        !*/

        virtual T2& value(
        )=0;
        /*!
            ensures
                - returns a non-const reference to the value associated with key
        !*/

    protected:

        // restricted functions
        map_pair<T1,T2>& operator=(const map_pair<T1,T2>&) {return *this;} // no assignment operator

    };

    // destructor does nothing
    template <typename T1,typename T2>
    map_pair<T1,T2>::~map_pair () {}

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MAP_PAIr_INTERFACE_


dlib C++ Library - remover.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_REMOVER_KERNEl_INTERFACE_
#define DLIB_REMOVER_KERNEl_INTERFACE_

#include <functional>

namespace dlib
{

    template <
        typename T
        >
    class remover
    {

        /*!
            REQUIREMENTS ON T
                T is swappable by a global swap() and
                T must have a default constructor

            POINTERS AND REFERENCES TO INTERNAL DATA
                The size() function does not invalidate pointers or
                references to internal data.  All other functions have no such
                guarantee.

            WHAT THIS OBJECT REPRESENTS
                This object represents some generalized interface for removing
                single items from container classes.
        !*/

        public:
            typedef T type;

            virtual ~remover(
            );
            /*!
                ensures
                    - all resources associated with *this have been released.
            !*/

            virtual void remove_any (
                T& item
            ) = 0;
            /*!
                requires
                    - size() != 0
                ensures
                    - #size() == size() - 1
                    - removes an element from *this and swaps it into item.
                    - if (*this implements the enumerable interface) then
                        - #at_start() == true
            !*/

            virtual unsigned long size (
            ) const = 0;
            /*!
                ensures
                    - returns the number of elements in *this
            !*/

        protected:

            // restricted functions
            remover& operator=(const remover&) {return *this;}    // assignment operator
    };

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename compare
        >
    class asc_remover : public remover<T>
    {
        /*!
            REQUIREMENTS ON T
                T is swappable by a global swap() and
                T must have a default constructor and
                T must be comparable by compare where compare is a functor compatible with std::less

            WHAT THIS OBJECT REPRESENTS
                This object represents the same thing as remover except
                that remove_any() will remove elements in ascending order
                according to the compare functor.
        !*/
    public:
        typedef compare compare_type;

    protected:
        // restricted functions
        asc_remover& operator=(const asc_remover&) {return *this;}    // assignment operator
    };

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range
        >
    class pair_remover
    {

        /*!
            REQUIREMENTS ON domain
                domain is swappable by a global swap() and
                domain must have a default constructor

            REQUIREMENTS ON range
                range is swappable by a global swap() and
                range must have a default constructor

            POINTERS AND REFERENCES TO INTERNAL DATA
                The size() function does not invalidate pointers or
                references to internal data.  All other functions have no such
                guarantee.

            WHAT THIS OBJECT REPRESENTS
                This object represents some generalized interface for removing
                pairs from container classes which enforce some kind of pairing on
                the elements that they contain.
        !*/

        public:
            typedef domain domain_type;
            typedef range range_type;

            virtual ~pair_remover(
            );
            /*!
                ensures
                    - all resources associated with *this have been released.
            !*/

            virtual void remove_any (
                domain& d,
                range& r
            ) = 0;
            /*!
                requires
                    - &d != &r (i.e. d and r cannot be the same variable)
                    - size() != 0
                ensures
                    - #size() == size() - 1
                    - removes an element from the domain of *this and swaps it
                      into d.
                    - removes the element in *this's range that is associated
                      with #d and swaps it into r.
                    - if (*this implements the enumerable interface) then
                        - #at_start() == true
            !*/

            virtual unsigned long size (
            ) const = 0;
            /*!
                ensures
                    - returns the number of elements in *this
            !*/

        protected:

            // restricted functions
            pair_remover& operator=(const pair_remover&) {return *this;}    // assignment operator

    };

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename compare
        >
    class asc_pair_remover : public pair_remover<domain,range>
    {
        /*!
            REQUIREMENTS ON domain
                domain is swappable by a global swap() and
                domain must have a default constructor and
                domain must be comparable by compare where compare is a functor compatible with std::less

            REQUIREMENTS ON range
                range is swappable by a global swap() and
                range must have a default constructor

            WHAT THIS OBJECT REPRESENTS
                This object represents the same thing as pair_remover except
                that remove_any() will remove domain elements in ascending
                order according to the compare functor.
        !*/
    public:
        typedef compare compare_type;

    protected:
        // restricted functions
        asc_pair_remover& operator=(const asc_pair_remover&) {return *this;}    // assignment operator
    };

// ----------------------------------------------------------------------------------------

    // destructor does nothing
    template <typename T>
    remover<T>::~remover() {}

    // destructor does nothing
    template <typename domain, typename range>
    pair_remover<domain,range>::~pair_remover() {}

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_REMOVER_KERNEl_INTERFACE_


dlib C++ Library - Graph Tools

The Library
  • Algorithms
  • API Wrappers
  • Bayesian Nets
  • Compression
  • Containers
  • Graph Tools
  • Image Processing
  • Linear Algebra
  • Machine Learning
  • Metaprogramming
  • Miscellaneous
  • Networking
  • Optimization
  • Parsing

Help/Info
  • Dlib Blog
  • Examples: C++
    • 3D Point Cloud
    • Assignment Learning
    • Base64 Encoder
    • Bayesian Network From Disk
    • Bayesian Network GUI
    • Bayesian Network
    • Bridge
    • BSP
    • C-Support Vector Machine
    • Cmd Line Parser
    • Compress Stream
    • Config File Reader
    • Custom Trainers
    • Directory Navigation
    • Empirical Kernel Map
    • Face Detection
    • Face Landmark Detection
    • FHOG Feature Extraction
    • FHOG Object Detection
    • Graph Labeling
    • GUI
    • Hough Transform
    • HTTP Server
    • Image
    • IO Socket Streams
    • IO Streams Server
    • Kernel Centroid
    • Kernel K-Means Clustering
    • Kernel Ridge Regression
    • Kernel RLS Filtering
    • Kernel RLS Regression
    • KRR Classification
    • Learning to Track
    • Linear Assignment Problems
    • Linear Manifold Regularizer
    • Linear Model Predictive Control
    • Logger Advanced
    • Logger Custom Output
    • Logger
    • Matrix Expressions
    • Matrix
    • Member Function Pointer
    • Model Selection
    • Multiclass Classification
    • Multithreaded Object
    • Neural Network
    • Non-Linear Least Squares
    • Nu-Support Vector Machine
    • Numerical Integration
    • Object Detector Advanced
    • Object Detector
    • One Class Classifiers
    • Online SVM
    • Optimization
    • Parallel For Loops
    • Pipe 2
    • Pipe
    • Quantum Computing
    • Queue
    • Rank Features
    • Relevance Vector Classification
    • Relevance Vector Regression
    • Running Stats
    • Sequence Labeling
    • Sequence Segmentation
    • Sockets
    • Sockstreambuf
    • Sparse Vectors
    • SQLite
    • Std C++ Allocator
    • Structural Support Vector Machines
    • Support Vector Regression
    • SURF
    • SVM-Rank
    • Thread Function
    • Thread Pool
    • Threaded Object
    • Threads
    • Timer
    • Train Object Detector
    • Train Shape Predictor
    • Using Custom Kernels
    • Video Object Tracking
    • Webcam Face Pose Estimation
    • XML Parser
  • Examples: Python
    • Face Detector
    • Face Landmark Detection
    • find candidate object locations
    • Linear Assignment Problems
    • Sequence Segmenter
    • Structural Support Vector Machines
    • SVM-Rank
    • Train Object Detector
    • Train Shape Predictor
    • Video Object Tracking
  • FAQ
  • Forums
  • Home
  • How to compile
  • How to contribute
  • Index
  • Introduction
  • License
  • Python API
  • Suggested Books
  • Who uses dlib?

Current Release
  • Change Log
  • Release Notes
  • Version: 18.18

Last Modified:
Sep 13, 2015
Graph Tools

In dlib, there are two types of graph representations. On the one hand, there are graphs based on an object which encapsulates the whole graph, such as the graph and directed_graph objects. On the other hand, there are graphs which are represented as simple vectors of edges. In this case, we use vectors of sample_pair or ordered_sample_pair objects for undirected and directed graphs respectively.

Graph Object Based Graphs
  • copy_graph
  • copy_graph_structure
  • create_join_tree
  • create_moral_graph
  • edge
  • find_connected_nodes
  • graph_contains_directed_cycle
  • graph_contains_length_one_cycle
  • graph_contains_undirected_cycle
  • graph_has_symmetric_edges
  • graph_is_connected
  • is_clique
  • is_join_tree
  • is_maximal_clique
  • triangulate_graph_and_find_cliques

Creating Edge List Based Graphs
  • Distance Functions
    • cosine_distance
    • negative_dot_product_distance
    • squared_euclidean_distance
  • find_approximate_k_nearest_neighbors
  • find_k_nearest_neighbors
  • find_k_nearest_neighbors_lsh
  • find_percent_shortest_edges_randomly
  • ordered_sample_pair
  • sample_pair

Using Edge List Based Graphs
  • contains_duplicate_pairs
  • convert_unordered_to_ordered
  • find_neighbor_ranges
  • is_ordered_by_index
  • max_index_plus_one
  • order_by_descending_distance
  • order_by_distance
  • order_by_distance_and_index
  • order_by_index
  • remove_duplicate_edges
  • remove_long_edges
  • remove_percent_longest_edges
  • remove_percent_shortest_edges
  • remove_short_edges
  • use_gaussian_weights
  • use_weights_of_one

[top]

contains_duplicate_pairs

This function checks if a std::vector of sample_pair or ordered_sample_pair objects contains any edge more than once.
More Details...
#include <dlib/graph_utils.h>
[top]

convert_unordered_to_ordered

This function takes a graph, defined by a vector of sample_pair objects and converts it into the equivalent graph defined by a vector of ordered_sample_pair objects.
More Details...
#include <dlib/graph_utils.h>
[top]

copy_graph

This function takes a graph or directed_graph and makes a copy of it.
More Details...
#include <dlib/graph_utils.h>
[top]

copy_graph_structure

This function takes a graph or directed_graph and copies its structure to another graph or directed_graph object. The only restriction is that you can't copy the structure of a graph into a directed_graph. The three other possible combinations are allowed however.
More Details...
#include <dlib/graph_utils.h>
[top]

cosine_distance

This is a simple function object that computes cosine of the angle between two vectors.
More Details...
#include <dlib/graph_utils.h>
[top]

create_join_tree

This function takes a graph object and creates a join tree for that graph. Or in other words, this function finds a tree decomposition of the given graph.
More Details...
#include <dlib/graph_utils.h>
[top]

create_moral_graph

This function takes a directed_graph and returns the moralized version of the graph in the form of a graph object.
More Details...
#include <dlib/graph_utils.h>
[top]

edge

This function takes a graph or directed_graph object and a pair of indices. It returns a reference to the edge object between the two nodes with the given indices.
More Details...
#include <dlib/graph_utils.h>
[top]

find_approximate_k_nearest_neighbors

This function is a simple approximate form of find_k_nearest_neighbors. Instead of checking all possible edges it randomly samples a large number of them and then performs exact k-nearest-neighbors on that randomly selected subset.
More Details...
#include <dlib/graph_utils.h>
[top]

find_connected_nodes

This function takes a node from a graph or directed_graph object and a set of unsigned longs. It finds all the nodes in the given graph that are connected to the given node by an undirected path and returns them in the set (also note that the original query node is also returned in this set).
More Details...
#include <dlib/graph_utils.h>
[top]

find_k_nearest_neighbors

This is a function which finds all the k nearest neighbors of a set of points and outputs the result as a vector of sample_pair objects. It takes O(n^2) time where n is the number of data samples. A faster approximate version is provided by find_approximate_k_nearest_neighbors and find_k_nearest_neighbors_lsh.
More Details...
#include <dlib/graph_utils.h>
[top]

find_k_nearest_neighbors_lsh

This function is a simple approximate form of find_k_nearest_neighbors. It uses locality sensitive hashing to speed up the nearest neighbor computation and is also capable of using a multi-core CPU.
More Details...
#include <dlib/graph_utils_threaded.h>
[top]

find_neighbor_ranges

This function takes a graph, defined by a vector of ordered_sample_pair objects, and finds the ranges that contain the edges for each node in the graph. The output therefore lets you easily locate the neighbors of any node in the graph.
More Details...
#include <dlib/graph_utils.h>
[top]

find_percent_shortest_edges_randomly

This function is a simple approximate form of find_k_nearest_neighbors. Instead of checking all possible edges it randomly samples a large number of them and then returns the best ones.

C++ Example Programs: linear_manifold_regularizer_ex.cpp
More Details...
#include <dlib/graph_utils.h>
[top]

graph_contains_directed_cycle

This function checks a directed_graph for directed cycles.
More Details...
#include <dlib/graph_utils.h>
[top]

graph_contains_length_one_cycle

This function takes a graph or directed_graph object and returns true if and only if the graph contains a node that has an edge that links back to itself.
More Details...
#include <dlib/graph_utils.h>
[top]

graph_contains_undirected_cycle

This function checks a directed_graph for undirected cycles.
More Details...
#include <dlib/graph_utils.h>
[top]

graph_has_symmetric_edges

This function checks if a directed_graph has a pair of nodes with just one edge between them. If so then it does not have symmetric edges.
More Details...
#include <dlib/graph_utils.h>
[top]

graph_is_connected

This function takes a graph or directed_graph object and determines if the graph is connected. That is, it returns true if and only if there is an undirected path between any two nodes in the given graph.
More Details...
#include <dlib/graph_utils.h>
[top]

is_clique

This function takes a graph and a set of node index values and checks if the specified set of nodes is a clique in the graph.
More Details...
#include <dlib/graph_utils.h>
[top]

is_join_tree

This function takes two graph objects and checks if the second of the two graphs is a valid join tree (aka tree decomposition) of the first graph.
More Details...
#include <dlib/graph_utils.h>
[top]

is_maximal_clique

This function takes a graph and a set of node index values and checks if the specified set of nodes is a maximal clique in the graph.
More Details...
#include <dlib/graph_utils.h>
[top]

is_ordered_by_index

This function checks if a vector of sample_pair or ordered_sample_pair objects is in sorted order according to their index values.
More Details...
#include <dlib/graph_utils.h>
[top]

max_index_plus_one

This function finds the number that is one greater than the largest index value in a std::vector of sample_pair or ordered_sample_pair objects. Therefore, it is useful for finding out how many nodes are in an edge list graph (assuming the graph contains all node indices from 0 to the largest index indicated by an edge).
More Details...
#include <dlib/graph_utils.h>
[top]

negative_dot_product_distance

This is a simple function object that computes -dot(v1,v2) for two vectors v1 and v2.
More Details...
#include <dlib/graph_utils.h>
[top]

ordered_sample_pair

This object is intended to represent an edge in a directed graph which has data samples at its vertices. Therefore, it is the directed version of sample_pair.
More Details...
#include <dlib/graph_utils.h>
[top]

order_by_descending_distance

This function provides a total ordering of sample_pair or ordered_sample_pair objects that causes pairs with largest distance to be the first in a sorted list. This function can be used with std::sort().
More Details...
#include <dlib/graph_utils.h>
[top]

order_by_distance

This function provides a total ordering of sample_pair or ordered_sample_pair objects that causes pairs with smallest distance to be the first in a sorted list. This function can be used with std::sort().
More Details...
#include <dlib/graph_utils.h>
[top]

order_by_distance_and_index

This function provides a total ordering of sample_pair or ordered_sample_pair objects that causes pairs with smallest distance to be the first in a sorted list but also orders samples with equal distances according to order_by_index(). This function can be used with std::sort().
More Details...
#include <dlib/graph_utils.h>
[top]

order_by_index

This function provides a total ordering of sample_pair or ordered_sample_pair objects that will cause pairs that represent the same edge to be adjacent when sorted. So for example, this function can be used with std::sort() to first sort a sequence of sample_pair objects and then find duplicate edges.
More Details...
#include <dlib/graph_utils.h>
[top]

remove_duplicate_edges

This is a simple function for removing duplicate edges (i.e. edges that compare equal according to ==) from a vector of sample_pair or ordered_sample_pair objects.
More Details...
#include <dlib/graph_utils.h>
[top]

remove_long_edges

This is a simple function for removing edges with a large distance value from a vector of sample_pair or ordered_sample_pair objects.
More Details...
#include <dlib/graph_utils.h>
[top]

remove_percent_longest_edges

This is a simple function for removing edges with a large distance value from a vector of sample_pair or ordered_sample_pair objects.
More Details...
#include <dlib/graph_utils.h>
[top]

remove_percent_shortest_edges

This is a simple function for removing edges with a small distance value from a vector of sample_pair or ordered_sample_pair objects.
More Details...
#include <dlib/graph_utils.h>
[top]

remove_short_edges

This is a simple function for removing edges with a small distance value from a vector of sample_pair or ordered_sample_pair objects.
More Details...
#include <dlib/graph_utils.h>
[top]

sample_pair

This object is intended to represent an edge in an undirected graph which has data samples at its vertices. Therefore, it is the undirected version of ordered_sample_pair.

C++ Example Programs: linear_manifold_regularizer_ex.cpp
More Details...
#include <dlib/graph_utils.h>
[top]

squared_euclidean_distance

This is a simple function object that computes squared euclidean distance between two matrix objects.

C++ Example Programs: linear_manifold_regularizer_ex.cpp
More Details...
#include <dlib/graph_utils.h>
[top]

triangulate_graph_and_find_cliques

This function takes a graph and turns it into a chordal graph. It also returns a set that contains all the cliques present in the chordal graph.
More Details...
#include <dlib/graph_utils.h>
[top]

use_gaussian_weights

This is a simple function object that takes a single argument which should be an object similar to sample_pair.

C++ Example Programs: linear_manifold_regularizer_ex.cpp
More Details...
#include <dlib/graph_utils.h>
[top]

use_weights_of_one

This is a simple function object that takes a single argument and always returns 1
More Details...
#include <dlib/graph_utils.h>


dlib C++ Library - graph_utils_abstract.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_GRAPH_UTILs_ABSTRACT_
#ifdef DLIB_GRAPH_UTILs_ABSTRACT_

#include "../directed_graph.h"
#include "../algs.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    typename T::edge_type& edge(
        T& g,
        unsigned long i,
        unsigned long j
    );
    /*!
        requires
            - T is an implementation of graph/graph_kernel_abstract.h
            - g.has_edge(i,j)
        ensures
            - returns a reference to the edge data for the edge connecting nodes i and j
              (i.e. returns g.node(i).edge(x) such that g.node(i).neighbor(x).index() == j)
    !*/

    template <
        typename T
        >
    typename const T::edge_type& edge(
        const T& g,
        unsigned long i,
        unsigned long j
    );
    /*!
        requires
            - T is an implementation of graph/graph_kernel_abstract.h
            - g.has_edge(i,j)
        ensures
            - returns a const reference to the edge data for the edge connecting nodes i and j
              (i.e. returns g.node(i).edge(x) such that g.node(i).neighbor(x).index() == j)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    typename T::edge_type& edge(
        T& g,
        unsigned long parent_idx,
        unsigned long child_idx
    );
    /*!
        requires
            - T is an implementation of directed_graph/directed_graph_kernel_abstract.h
            - g.has_edge(parent_idx,child_idx)
        ensures
            - returns a reference to the edge data for the directed edge connecting parent
              node g.node(parent_idx) to child node g.node(child_idx).
    !*/

    template <
        typename T
        >
    typename const T::edge_type& edge(
        const T& g,
        unsigned long parent_idx,
        unsigned long child_idx
    );
    /*!
        requires
            - T is an implementation of directed_graph/directed_graph_kernel_abstract.h
            - g.has_edge(parent_idx,child_idx)
        ensures
            - returns a const reference to the edge data for the directed edge connecting
              parent node g.node(parent_idx) to child node g.node(child_idx).
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    bool graph_has_symmetric_edges (
        const T& graph
    );
    /*!
        requires
            - T is an implementation of directed_graph/directed_graph_kernel_abstract.h
        ensures
            - if (All nodes have either 0 edges between them or 2 edges between them.
              That is, if there is an edge pointing from node A to node B then there is
              also an edge from B to A) then
                - returns true
            - else
                - returns false
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    bool graph_contains_directed_cycle (
        const T& graph
    );
    /*!
        requires
            - T is an implementation of directed_graph/directed_graph_kernel_abstract.h
        ensures
            - if (there is a directed cycle in the given graph) then
                - returns true
            - else
                - returns false
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    bool graph_contains_undirected_cycle (
        const T& graph
    );
    /*!
        requires
            - T is an implementation of directed_graph/directed_graph_kernel_abstract.h or
              T is an implementation of graph/graph_kernel_abstract.h
        ensures
            - if (there is an undirected cycle in the given graph) then
                - returns true
            - else
                - returns false
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    bool graph_contains_length_one_cycle (
        const T& graph
    );
    /*!
        requires
            - T is an implementation of directed_graph/directed_graph_kernel_abstract.h or
              T is an implementation of graph/graph_kernel_abstract.h
        ensures
            - if (it is the case that graph.has_edge(i,i) == true for some i) then
                - returns true
            - else
                - returns false
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename src_type,
        typename dest_type
        >
    void copy_graph_structure (
        const src_type& src,
        dest_type& dest
    );
    /*!
        requires
            - src_type is an implementation of directed_graph/directed_graph_kernel_abstract.h or
              src_type is an implementation of graph/graph_kernel_abstract.h
            - dest_type is an implementation of directed_graph/directed_graph_kernel_abstract.h or
              dest_type is an implementation of graph/graph_kernel_abstract.h
            - dest_type is not a directed_graph when src_type is a graph
        ensures
            - this function copies the graph structure from src into dest
            - #dest.number_of_nodes() == src.number_of_nodes()
            - for all valid i: #dest.node(i).item has an initial value for its type
            - for all valid i and j:
                - if (src.has_edge(i,j) == true) then
                    - #dest.has_edge(i,j) == true
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename src_type,
        typename dest_type
        >
    void copy_graph (
        const src_type& src,
        dest_type& dest
    );
    /*!
        requires
            - src_type is an implementation of directed_graph/directed_graph_kernel_abstract.h or
              src_type is an implementation of graph/graph_kernel_abstract.h
            - dest_type is an implementation of directed_graph/directed_graph_kernel_abstract.h or
              dest_type is an implementation of graph/graph_kernel_abstract.h
            - src_type and dest_type are both the same kind of graph.  That is, they
              are either both directed or both undirected.
            - the node and edge data in the graphs are copyable via operator=().
        ensures
            - #dest is a complete duplicate of src.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename directed_graph_type,
        typename graph_type
        >
    void create_moral_graph (
        const directed_graph_type& g,
        graph_type& moral_graph
    );
    /*!
        requires
            - directed_graph_type is an implementation of directed_graph/directed_graph_kernel_abstract.h
            - graph_type is an implementation of graph/graph_kernel_abstract.h
            - graph_contains_directed_cycle(g) == false
        ensures
            - #moral_graph == the moralized version of the directed graph g
            - #moral_graph.number_of_nodes() == g.number_of_nodes()
            - for all valid i and j:
                - if (g.has_edge(i,j) == true) then
                    - #moral_graph.has_edge(i,j) == true
                      (i.e. all the edges that are in g are also in moral_graph)
            - for all valid i:
                - for all pairs p1 and p2 such that p1 != p2 and g.node(p1) and g.node(p2) are both
                  parents of node g.node(i):
                    - #moral_graph.has_edge(p1,p2) == true
                      (i.e. all the parents of a node are connected in the moral graph)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename S
        >
    void find_connected_nodes (
        const T& n,
        S& visited
    );
    /*!
        requires
            - T is a node_type from an implementation of directed_graph/directed_graph_kernel_abstract.h or
              T is a node_type from an implementation of graph/graph_kernel_abstract.h
            - S is an implementation of set/set_kernel_abstract.h
        ensures
            - let G be the graph that contains node n
            - #visited.is_member(n.index()) == true
            - for all i such that there is an undirected path from n to G.node(i):
                - #visited.is_member(i) == true
            - for all i such that visited.is_member(i):
                - #visited.is_member(i) == true
                  (i.e. this function doesn't remove anything from visited.  So if
                  it contains stuff when you call this function then it will still
                  contain those things once the function ends)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    bool graph_is_connected (
        const T& g
    );
    /*!
        requires
            - T is an implementation of directed_graph/directed_graph_kernel_abstract.h or
              T is an implementation of graph/graph_kernel_abstract.h
        ensures
            - every node in g has an undirected path to every other node in g.
              I.e. g is a connected graph
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename graph_type,
        typename sets_of_int
        >
    bool is_clique (
        const graph_type& g,
        const sets_of_int& clique
    );
    /*!
        requires
            - graph_type is an implementation of graph/graph_kernel_abstract.h
            - sets_of_int is an implementation of set/set_kernel_abstract.h
              and it contains unsigned long objects.
            - graph_contains_length_one_cycle(g) == false
            - for all x such that clique.is_member(x):
                - x < g.number_of_nodes()
        ensures
            - if (it is true that for all i and j such that clique.is_member(i) and
              clique.is_member(j) then g.has_edge(i,j) == true) then
                - returns true
            - else
                - returns false
            - if (clique.size() == 0) then
                - returns true
                  (this is just a special case of the above condition)
            - else
                - returns false
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename graph_type,
        typename sets_of_int
        >
    bool is_maximal_clique (
        const graph_type& g,
        const sets_of_int& clique
    );
    /*!
        requires
            - graph_type is an implementation of graph/graph_kernel_abstract.h
            - sets_of_int is an implementation of set/set_kernel_abstract.h
              and it contains unsigned long objects.
            - graph_contains_length_one_cycle(g) == false
            - for all x such that clique.is_member(x):
                - x < g.number_of_nodes()
            - is_clique(g,clique) == true
        ensures
            - if (there is no x such that clique.is_member(x) == false
              and g.has_edge(i,x) for all i such that cliques.is_member(i)) then
                - returns true
            - else
                - returns false
            - if (clique.size() == 0) then
                - returns true
                  (this is just a special case of the above condition)
            - else
                - returns false
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename graph_type,
        typename set_of_sets_of_int
        >
    void triangulate_graph_and_find_cliques (
        graph_type& g,
        set_of_sets_of_int& cliques
    );
    /*!
        requires
            - graph_type is an implementation of graph/graph_kernel_abstract.h
            - set_of_sets_of_int is an implementation of set/set_kernel_abstract.h
              and it contains another set object which is comparable by operator< and
              itself contains unsigned long objects.
              (e.g. set<set<unsigned long>::compare_1a>::kernel_1a)
            - graph_contains_length_one_cycle(g) == false
            - graph_is_connected(g) == true
        ensures
            - #g.number_of_nodes() == g.number_of_nodes()
            - all this function does to g is add edges to it until g becomes a
              chordal graph where a chordal graph is a graph where each cycle
              in the graph of 4 or more nodes has an edge joining two nodes
              that are not adjacent in the cycle.
            - #cliques.size() == the number of maximal cliques in the graph #g
            - for all valid sets S such that #cliques.is_member(S):
                - for all valid integers i and j such that S.is_member(i) == true
                  and S.is_member(j) == true and i != j:
                    - #g.has_edge(i,j) == true
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename graph_type,
        typename join_tree_type
        >
    bool is_join_tree (
        const graph_type& g,
        const join_tree_type& join_tree
    );
    /*!
        requires
            - graph_type is an implementation of directed_graph/directed_graph_kernel_abstract.h or
              graph_type is an implementation of graph/graph_kernel_abstract.h
            - join_tree_type is an implementation of graph/graph_kernel_abstract.h
            - join_tree_type::type is an implementation of set/set_compare_abstract.h and
              this set type contains unsigned long objects.
            - join_tree_type::edge_type is an implementation of set/set_compare_abstract.h and
              this set type contains unsigned long objects.
            - graph_contains_length_one_cycle(g) == false
            - graph_is_connected(g) == true
        ensures
            - if (join_tree is a valid join tree of graph g.  That is, join_tree is a
              tree decomposition of g) then
                - returns true
            - else
                - returns false

            - a join tree of graph g is defined as follows:
                - graph_contains_undirected_cycle(join_tree) == false
                - graph_is_connected(join_tree) == true
                - for all valid i:
                    - join_tree.node(i).item == a non-empty set containing node indexes
                      from g.  That is, this set contains all the nodes from g that are
                      in this cluster in the join tree
                - for all valid i and j such that i and j are both < join_tree.number_of_nodes()
                    - let X be the set of numbers that is contained in both join_tree.node(i).item
                      and join_tree.node(j).item
                    - It is the case that all nodes on the unique path between join_tree.node(i)
                      and join_tree.node(j) contain the numbers from X in their sets.
                    - edge(join_tree,i,j) == a set containing the intersection of
                      join_tree.node(i).item and join_tree.node(j).item
                - the node index for every node in g appears in some node in join_tree at
                  least once.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename graph_type,
        typename join_tree_type
        >
    void create_join_tree (
        const graph_type& g,
        join_tree_type& join_tree
    );
    /*!
        requires
            - graph_type is an implementation of graph/graph_kernel_abstract.h
            - join_tree_type is an implementation of graph/graph_kernel_abstract.h
            - join_tree_type::type is an implementation of set/set_compare_abstract.h and
              this set type contains unsigned long objects.
            - join_tree_type::edge_type is an implementation of set/set_compare_abstract.h and
              this set type contains unsigned long objects.
            - graph_contains_length_one_cycle(g) == false
            - graph_is_connected(g) == true
        ensures
            - #is_join_tree(g, join_tree) == true
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_GRAPH_UTILs_ABSTRACT_


dlib C++ Library - function_objects_abstract.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_MR_FUNCTION_ObJECTS_ABSTRACT_Hh_
#ifdef DLIB_MR_FUNCTION_ObJECTS_ABSTRACT_Hh_

#include "../matrix.h"
#include <cmath>
#include "../svm/sparse_vector_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    struct squared_euclidean_distance
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is a simple function object that computes squared euclidean distance
                between two dlib::matrix objects.

            THREAD SAFETY
                This object has no mutable members.  Therefore, it is safe to call
                operator() on a single instance of this object simultaneously from multiple
                threads.
        !*/

        squared_euclidean_distance (
        );
        /*!
            ensures
                - #lower == 0
                - #upper == std::numeric_limits<double>::infinity()
        !*/

        squared_euclidean_distance (
            const double l,
            const double u
        );
        /*!
            ensures
                - #lower == l
                - #upper == u
        !*/

        const double lower;
        const double upper;

        template <typename sample_type>
        double operator() (
            const sample_type& a,
            const sample_type& b
        ) const;
        /*!
            requires
                - sample_type should be a kind of dlib::matrix
            ensures
                - let LEN = length_squared(a-b)
                - if (lower <= LEN <= upper) then
                    - returns LEN
                - else
                    - returns std::numeric_limits<double>::infinity()
        !*/
    };

// ----------------------------------------------------------------------------------------

    struct cosine_distance
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is a simple function object that computes the cosine of the angle
                between two vectors and returns 1 - this quantity.   Moreover, this object
                works for both sparse and dense vectors.

            THREAD SAFETY
                This object has no mutable members.  Therefore, it is safe to call
                operator() on a single instance of this object simultaneously from multiple
                threads.
        !*/

        template <typename sample_type>
        double operator() (
            const sample_type& a,
            const sample_type& b
        ) const;
        /*!
            requires
                - sample_type is a dense vector (e.g. a dlib::matrix) or a sparse
                  vector as defined at the top of dlib/svm/sparse_vector_abstract.h
            ensures
                - let theta = the angle between a and b.
                - returns 1 - cos(theta)
                  (e.g. this function returns 0 when a and b have an angle of 0 between
                  each other, 1 if they have a 90 degree angle, and a maximum of 2 if the
                  vectors have a 180 degree angle between each other).
                - zero length vectors are considered to have angles of 0 between all other
                  vectors.
        !*/
    };

// ----------------------------------------------------------------------------------------

    struct negative_dot_product_distance
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is a simple function object that computes the dot product between two
                vectors and returns the negation of this value.  Moreover, this object
                works for both sparse and dense vectors.

            THREAD SAFETY
                This object has no mutable members.  Therefore, it is safe to call
                operator() on a single instance of this object simultaneously from multiple
                threads.
        !*/

        template <typename sample_type>
        double operator() (
            const sample_type& a,
            const sample_type& b
        ) const;
        /*!
            requires
                - sample_type is a dense vector (e.g. a dlib::matrix) or a sparse
                  vector as defined at the top of dlib/svm/sparse_vector_abstract.h
            ensures
                - returns -dot(a,b)
        !*/
    };

// ----------------------------------------------------------------------------------------

    struct use_weights_of_one
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is a simple function object that takes a single argument
                and always returns 1

            THREAD SAFETY
                This object has no mutable members.  Therefore, it is safe to call
                operator() on a single instance of this object simultaneously from multiple
                threads.
        !*/

        template <typename edge_type>
        double operator() (
            const edge_type&
        ) const;
        /*!
            ensures
                - returns 1
        !*/
    };

// ----------------------------------------------------------------------------------------

    struct use_gaussian_weights
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is a simple function object that takes a single argument
                which should be an object similar to dlib::sample_pair.

            THREAD SAFETY
                This object has no mutable members.  Therefore, it is safe to call
                operator() on a single instance of this object simultaneously from multiple
                threads.
        !*/

        use_gaussian_weights (
        );
        /*!
            ensures
                - #gamma == 0.1
        !*/

        use_gaussian_weights (
            double g
        );
        /*!
            ensures
                - #gamma == g
        !*/

        double gamma;

        template <typename edge_type>
        double operator() (
            const edge_type& e
        ) const;
        /*!
            requires
                - e.distance() must be a valid expression that returns a number
                  (e.g. edge_type might be dlib::sample_pair)
            ensures
                - returns std::exp(-gamma*e.distance());
        !*/
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MR_FUNCTION_ObJECTS_ABSTRACT_Hh_


dlib C++ Library - edge_list_graphs_abstract.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_EDGE_LIST_GrAPHS_ABSTRACT_Hh_
#ifdef DLIB_EDGE_LIST_GrAPHS_ABSTRACT_Hh_

#include <vector>
#include "../string.h"
#include "sample_pair_abstract.h"
#include "ordered_sample_pair_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type,
        typename distance_function_type,
        typename alloc,
        typename T
        >
    void find_percent_shortest_edges_randomly (
        const vector_type& samples,
        const distance_function_type& dist_funct,
        const double percent,
        const unsigned long num,
        const T& random_seed,
        std::vector<sample_pair, alloc>& out
    );
    /*!
        requires
            - 0 < percent <= 1
            - num > 0
            - random_seed must be convertible to a string by dlib::cast_to_string()
            - dist_funct(samples[i], samples[j]) must be a valid expression that evaluates
              to a floating point number
        ensures
            - This function randomly samples the space of pairs of integers between
              0 and samples.size()-1 inclusive.  For each of these pairs, (i,j), a
              sample_pair is created as follows:
                sample_pair(i, j, dist_funct(samples[i], samples[j]))
              num such sample_pair objects are generated, duplicates and pairs with distance
              values == infinity are removed, and then the top percent of them with the
              smallest distance are stored into out.
            - #out.size() <= num*percent
            - contains_duplicate_pairs(#out) == false
            - for all valid i:
                - #out[i].distance() == dist_funct(samples[#out[i].index1()], samples[#out[i].index2()])
                - #out[i].distance() < std::numeric_limits<double>::infinity()
            - random_seed is used to seed the random number generator used by this
              function.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type,
        typename distance_function_type,
        typename alloc,
        typename T
        >
    void find_approximate_k_nearest_neighbors (
        const vector_type& samples,
        const distance_function_type& dist_funct,
        const unsigned long k,
        const unsigned long num,
        const T& random_seed,
        std::vector<sample_pair, alloc>& out
    );
    /*!
        requires
            - k > 0
            - num > 0
            - random_seed must be convertible to a string by dlib::cast_to_string()
            - dist_funct(samples[i], samples[j]) must be a valid expression that evaluates
              to a floating point number
        ensures
            - This function computes an approximate form of k nearest neighbors. As num grows
              larger the output of this function converges to the output of the
              find_k_nearest_neighbors() function defined below.
            - Specifically, this function randomly samples the space of pairs of integers between
              0 and samples.size()-1 inclusive.  For each of these pairs, (i,j), a
              sample_pair is created as follows:
                sample_pair(i, j, dist_funct(samples[i], samples[j]))
              num such sample_pair objects are generated and then exact k-nearest-neighbors
              is performed amongst these sample_pairs and the results are stored into #out.
              Note that samples with an infinite distance between them are considered to
              be not connected at all.
            - contains_duplicate_pairs(#out) == false
            - for all valid i:
                - #out[i].distance() == dist_funct(samples[#out[i].index1()], samples[#out[i].index2()])
                - #out[i].distance() < std::numeric_limits<double>::infinity()
            - random_seed is used to seed the random number generator used by this
              function.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type,
        typename distance_function_type,
        typename alloc
        >
    void find_k_nearest_neighbors (
        const vector_type& samples,
        const distance_function_type& dist_funct,
        const unsigned long k,
        std::vector<sample_pair, alloc>& out
    );
    /*!
        requires
            - k > 0
            - dist_funct(samples[i], samples[j]) must be a valid expression that evaluates
              to a floating point number
        ensures
            - #out == a set of sample_pair objects that represent all the k nearest
              neighbors in samples according to the given distance function dist_funct.
              Note that samples with an infinite distance between them are considered to
              be not connected at all.
            - for all valid i:
                - #out[i].distance() == dist_funct(samples[#out[i].index1()], samples[#out[i].index2()])
                - #out[i].distance() < std::numeric_limits<double>::infinity()
            - contains_duplicate_pairs(#out) == false
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type
        >
    bool contains_duplicate_pairs (
        const vector_type& pairs
    );
    /*!
        requires
            - vector_type == a type with an interface compatible with std::vector and it
              must in turn contain objects with an interface compatible with
              dlib::sample_pair or dlib::ordered_sample_pair.
        ensures
            - if (pairs contains any elements that are equal according to operator==) then
                - returns true
            - else
                - returns false
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type
        >
    unsigned long max_index_plus_one (
        const vector_type& pairs
    );
    /*!
        requires
            - vector_type == a type with an interface compatible with std::vector and it
              must in turn contain objects with an interface compatible with
              dlib::sample_pair or dlib::ordered_sample_pair.
        ensures
            - if (pairs.size() == 0) then
                - returns 0
            - else
                - returns a number N such that:
                    - for all i:  pairs[i].index1()   <  N && pairs[i].index2()   <  N
                    - for some j: pairs[j].index1()+1 == N || pairs[j].index2()+1 == N
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type
        >
    void remove_long_edges (
        vector_type& pairs,
        double distance_threshold
    );
    /*!
        requires
            - vector_type == a type with an interface compatible with std::vector and it
              must in turn contain objects with an interface compatible with
              dlib::sample_pair or dlib::ordered_sample_pair.
        ensures
            - Removes all elements of pairs that have a distance value greater than the
              given threshold.
            - #pairs.size() <= pairs.size()
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type
        >
    void remove_short_edges (
        vector_type& pairs,
        double distance_threshold
    );
    /*!
        requires
            - vector_type == a type with an interface compatible with std::vector and it
              must in turn contain objects with an interface compatible with
              dlib::sample_pair or dlib::ordered_sample_pair.
        ensures
            - Removes all elements of pairs that have a distance value less than the
              given threshold.
            - #pairs.size() <= pairs.size()
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type
        >
    void remove_percent_longest_edges (
        vector_type& pairs,
        double percent
    );
    /*!
        requires
            - 0 <= percent < 1
            - vector_type == a type with an interface compatible with std::vector and it
              must in turn contain objects with an interface compatible with
              dlib::sample_pair or dlib::ordered_sample_pair.
        ensures
            - Removes the given upper percentage of the longest edges in pairs.  I.e.
              this function removes the long edges from pairs.
            - #pairs.size() == (1-percent)*pairs.size()
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type
        >
    void remove_percent_shortest_edges (
        vector_type& pairs,
        double percent
    );
    /*!
        requires
            - 0 <= percent < 1
            - vector_type == a type with an interface compatible with std::vector and it
              must in turn contain objects with an interface compatible with
              dlib::sample_pair or dlib::ordered_sample_pair.
        ensures
            - Removes the given upper percentage of the shortest edges in pairs.  I.e.
              this function removes the short edges from pairs.
            - #pairs.size() == (1-percent)*pairs.size()
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type
        >
    void remove_duplicate_edges (
        vector_type& pairs
    );
    /*!
        requires
            - vector_type == a type with an interface compatible with std::vector and it
              must in turn contain objects with an interface compatible with
              dlib::sample_pair or dlib::ordered_sample_pair.
        ensures
            - Removes any duplicate edges from pairs.  That is, for all elements of pairs,
              A and B, such that A == B, only one of A or B will be in pairs after this
              function terminates.
            - #pairs.size() <= pairs.size()
            - is_ordered_by_index(#pairs) == true
            - contains_duplicate_pairs(#pairs) == false
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type
        >
    bool is_ordered_by_index (
        const vector_type& edges
    );
    /*!
        requires
            - vector_type == a type with an interface compatible with std::vector and it
              must in turn contain objects with an interface compatible with
              dlib::sample_pair or dlib::ordered_sample_pair.
        ensures
            - returns true if and only if the contents of edges are in sorted order
              according to order_by_index().  That is, we return true if calling
              std::stable_sort(edges.begin(), edges.end(), &order_by_index<T>) would not
              change the ordering of elements of edges.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename alloc1,
        typename alloc2
        >
    void find_neighbor_ranges (
        const std::vector<ordered_sample_pair,alloc1>& edges,
        std::vector<std::pair<unsigned long, unsigned long>,alloc2>& neighbors
    );
    /*!
        requires
            - is_ordered_by_index(edges) == true
              (i.e. edges is sorted so that all the edges for a particular node are grouped
              together)
        ensures
            - This function takes a graph, represented by its list of edges, and finds the
              ranges that contain the edges for each node in the graph.  In particular,
              #neighbors[i] will tell you which edges correspond to the ith node in the
              graph.
            - #neighbors.size() == max_index_plus_one(edges)
              (i.e. neighbors will have an entry for each node in the graph defined by the
              list of edges)
            - for all valid i:
                - all elements of edges such that their index1() value == i are in the
                  range [neighbors[i].first, neighbors[i].second).  That is, for all k such
                  that neighbors[i].first <= k < neighbors[i].second:
                    - edges[k].index1() == i.
                    - all edges outside this range have an index1() value != i
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename alloc1,
        typename alloc2
        >
    void convert_unordered_to_ordered (
        const std::vector<sample_pair,alloc1>& edges,
        std::vector<ordered_sample_pair,alloc2>& out_edges
    );
    /*!
        ensures
            - interprets edges a defining an undirected graph.
            - This function populates out_edges with a directed graph that represents the
              same graph as the one in edges.  In particular, this means that for all valid
              i we have the following:
                - if (edges[i].index1() != edges[i].index2()) then
                    - #out_edges contains two edges corresponding to edges[i].  They
                      represent the two directions of this edge.  The distance value from
                      edges[i] is also copied into the output edges.
                - else
                    - #out_edges contains one edge corresponding to edges[i] since this is
                      a self edge.  The distance value from edges[i] is also copied into
                      the output edge.
            - max_index_plus_one(edges) == max_index_plus_one(#out_edges)
              (i.e. both graphs have the same number of nodes)
            - In all but the most trivial cases, we will have is_ordered_by_index(#out_edges) == false
            - contains_duplicate_pairs(#out_edges) == contains_duplicate_pairs(edges)
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_EDGE_LIST_GrAPHS_ABSTRACT_Hh_


dlib C++ Library - ordered_sample_pair_abstract.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_ORDERED_SAMPLE_PaIR_ABSTRACT_Hh_
#ifdef DLIB_ORDERED_SAMPLE_PaIR_ABSTRACT_Hh_

#include <limits>
#include "../serialize.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class ordered_sample_pair
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is intended to represent an edge in a directed graph which has
                data samples at its vertices.  So it contains two integers (index1 and
                index2) which represent the identifying indices of the samples at the ends
                of an edge.

                This object also contains a double which can be used for any purpose.
        !*/

    public:
        ordered_sample_pair(
        );
        /*!
            ensures
                - #index1() == 0
                - #index2() == 0
                - #distance() == 1
        !*/

        ordered_sample_pair (
            const unsigned long idx1,
            const unsigned long idx2
        );
        /*!
            ensures
                - #index1() == idx1
                - #index2() == idx2
                - #distance() == 1
        !*/

        ordered_sample_pair (
            const unsigned long idx1,
            const unsigned long idx2,
            const double dist
        );
        /*!
            ensures
                - #index1() == idx1
                - #index2() == idx2
                - #distance() == dist
        !*/

        const unsigned long& index1 (
        ) const;
        /*!
            ensures
                - returns the first index value stored in this object
        !*/

        const unsigned long& index2 (
        ) const;
        /*!
            ensures
                - returns the second index value stored in this object
        !*/

        const double& distance (
        ) const;
        /*!
            ensures
                - returns the floating point number stored in this object
        !*/

    };

// ----------------------------------------------------------------------------------------

    inline bool operator == (
        const ordered_sample_pair& a,
        const ordered_sample_pair& b
    );
    /*!
        ensures
            - returns a.index1() == b.index1() && a.index2() == b.index2();
              I.e. returns true if a and b both represent the same pair and false otherwise.
              Note that the distance field is not involved in this comparison.
    !*/

    inline bool operator != (
        const ordered_sample_pair& a,
        const ordered_sample_pair& b
    );
    /*!
        ensures
            - returns !(a == b)
    !*/

// ----------------------------------------------------------------------------------------

    inline void serialize (
        const ordered_sample_pair& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

    inline void deserialize (
        ordered_sample_pair& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_ORDERED_SAMPLE_PaIR_ABSTRACT_Hh_


dlib C++ Library - sample_pair_abstract.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SAMPLE_PaIR_ABSTRACT_Hh_
#ifdef DLIB_SAMPLE_PaIR_ABSTRACT_Hh_

#include <limits>
#include "../serialize.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class sample_pair
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is intended to represent an edge in an undirected graph
                which has data samples at its vertices.  So it contains two integers
                (index1 and index2) which represent the identifying indices of
                the samples at the ends of an edge.  Note that this object enforces
                the constraint that index1 <= index2.  This has the effect of
                making the edges undirected since a sample_pair is incapable
                of representing a single edge in more than one way.  That is,
                sample_pair(i,j) == sample_pair(j,i) for any value of i and j.

                This object also contains a double which can be used for any purpose.
        !*/

    public:
        sample_pair(
        );
        /*!
            ensures
                - #index1() == 0
                - #index2() == 0
                - #distance() == 1
        !*/

        sample_pair (
            const unsigned long idx1,
            const unsigned long idx2
        );
        /*!
            ensures
                - #index1() == min(idx1,idx2)
                - #index2() == max(idx1,idx2)
                - #distance() == 1
        !*/

        sample_pair (
            const unsigned long idx1,
            const unsigned long idx2,
            const double dist
        );
        /*!
            ensures
                - #index1() == min(idx1,idx2)
                - #index2() == max(idx1,idx2)
                - #distance() == dist
        !*/

        const unsigned long& index1 (
        ) const;
        /*!
            ensures
                - returns the first index value stored in this object
        !*/

        const unsigned long& index2 (
        ) const;
        /*!
            ensures
                - returns the second index value stored in this object
        !*/

        const double& distance (
        ) const;
        /*!
            ensures
                - returns the floating point number stored in this object
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <typename T>
    bool order_by_index (
        const T& a,
        const T& b
    ) { return a.index1() < b.index1() || (a.index1() == b.index1() && a.index2() < b.index2()); }
    /*!
        requires
            - T is a type with an interface compatible with sample_pair.
        ensures
            - provides a total ordering of sample_pair objects that will cause pairs that are
              equal to be adjacent when sorted.  So for example, this function can be used
              with std::sort() to first sort a sequence of sample_pair objects and then
              find duplicate edges.
    !*/

    template <typename T>
    bool order_by_distance (
        const T& a,
        const T& b
    ) { return a.distance() < b.distance(); }
    /*!
        requires
            - T is a type with an interface compatible with sample_pair.
        ensures
            - provides a total ordering of sample_pair objects that causes pairs with
              smallest distance to be the first in a sorted list.  This function can be
              used with std::sort().
    !*/

    template <typename T>
    bool order_by_descending_distance (
        const T& a,
        const T& b
    ) { return a.distance() > b.distance(); }
    /*!
        requires
            - T is a type with an interface compatible with sample_pair.
        ensures
            - provides a total ordering of sample_pair objects that causes pairs with
              largest distance to be the first in a sorted list.  This function can be
              used with std::sort().
    !*/

    template <typename T>
    bool order_by_distance_and_index (
        const T& a,
        const T& b
    ) { return a.distance() < b.distance() || (a.distance() == b.distance() && order_by_index(a,b)); }
    /*!
        requires
            - T is a type with an interface compatible with sample_pair.
        ensures
            - provides a total ordering of sample_pair objects that causes pairs with
              smallest distance to be the first in a sorted list but also orders samples
              with equal distances according to order_by_index().  This function can be
              used with std::sort().
    !*/

// ----------------------------------------------------------------------------------------

    inline bool operator == (
        const sample_pair& a,
        const sample_pair& b
    );
    /*!
        ensures
            - returns a.index1() == b.index1() && a.index2() == b.index2();
              I.e. returns true if a and b both represent the same pair and false otherwise.
              Note that the distance field is not involved in this comparison.
    !*/

    inline bool operator != (
        const sample_pair& a,
        const sample_pair& b
    );
    /*!
        ensures
            - returns !(a == b)
    !*/

// ----------------------------------------------------------------------------------------

    inline void serialize (
        const sample_pair& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

    inline void deserialize (
        sample_pair& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SAMPLE_PaIR_ABSTRACT_Hh_


dlib C++ Library - Image Processing

The Library
  • Algorithms
  • API Wrappers
  • Bayesian Nets
  • Compression
  • Containers
  • Graph Tools
  • Image Processing
  • Linear Algebra
  • Machine Learning
  • Metaprogramming
  • Miscellaneous
  • Networking
  • Optimization
  • Parsing

Help/Info
  • Dlib Blog
  • Examples: C++
    • 3D Point Cloud
    • Assignment Learning
    • Base64 Encoder
    • Bayesian Network From Disk
    • Bayesian Network GUI
    • Bayesian Network
    • Bridge
    • BSP
    • C-Support Vector Machine
    • Cmd Line Parser
    • Compress Stream
    • Config File Reader
    • Custom Trainers
    • Directory Navigation
    • Empirical Kernel Map
    • Face Detection
    • Face Landmark Detection
    • FHOG Feature Extraction
    • FHOG Object Detection
    • Graph Labeling
    • GUI
    • Hough Transform
    • HTTP Server
    • Image
    • IO Socket Streams
    • IO Streams Server
    • Kernel Centroid
    • Kernel K-Means Clustering
    • Kernel Ridge Regression
    • Kernel RLS Filtering
    • Kernel RLS Regression
    • KRR Classification
    • Learning to Track
    • Linear Assignment Problems
    • Linear Manifold Regularizer
    • Linear Model Predictive Control
    • Logger Advanced
    • Logger Custom Output
    • Logger
    • Matrix Expressions
    • Matrix
    • Member Function Pointer
    • Model Selection
    • Multiclass Classification
    • Multithreaded Object
    • Neural Network
    • Non-Linear Least Squares
    • Nu-Support Vector Machine
    • Numerical Integration
    • Object Detector Advanced
    • Object Detector
    • One Class Classifiers
    • Online SVM
    • Optimization
    • Parallel For Loops
    • Pipe 2
    • Pipe
    • Quantum Computing
    • Queue
    • Rank Features
    • Relevance Vector Classification
    • Relevance Vector Regression
    • Running Stats
    • Sequence Labeling
    • Sequence Segmentation
    • Sockets
    • Sockstreambuf
    • Sparse Vectors
    • SQLite
    • Std C++ Allocator
    • Structural Support Vector Machines
    • Support Vector Regression
    • SURF
    • SVM-Rank
    • Thread Function
    • Thread Pool
    • Threaded Object
    • Threads
    • Timer
    • Train Object Detector
    • Train Shape Predictor
    • Using Custom Kernels
    • Video Object Tracking
    • Webcam Face Pose Estimation
    • XML Parser
  • Examples: Python
    • Face Detector
    • Face Landmark Detection
    • find candidate object locations
    • Linear Assignment Problems
    • Sequence Segmenter
    • Structural Support Vector Machines
    • SVM-Rank
    • Train Object Detector
    • Train Shape Predictor
    • Video Object Tracking
  • FAQ
  • Forums
  • Home
  • How to compile
  • How to contribute
  • Index
  • Introduction
  • License
  • Python API
  • Suggested Books
  • Who uses dlib?

Current Release
  • Change Log
  • Release Notes
  • Version: 18.18

Last Modified:
Sep 13, 2015
Image Processing

This page documents the functionality present in this library that deals with the management and manipulation of images. One thing to note is that there is no explicit image object. Instead, everything deals with array2d objects that contain various kinds of pixels or user defined generic image objects.

Pixel Types

Most image handling routines in dlib will accept images containing any pixel type. This is made possible by defining a traits class, pixel_traits, for each possible pixel type. This traits class enables image processing routines to determine how to handle each kind of pixel and therefore only pixels which have a pixel_traits definition may be used. The following list defines all the pixel types which come with pixel_traits definitions.
  • RGB
      There are two RGB pixel types in dlib, rgb_pixel and bgr_pixel. Each defines a 24bit RGB pixel type. The bgr_pixel is identical to rgb_pixel except that it lays the color channels down in memory in BGR order rather than RGB order and is therefore useful for interfacing with other image processing tools which expect this format (e.g. OpenCV).
  • RGB Alpha
      The rgb_alpha_pixel is an 8bit per channel RGB pixel with an 8bit alpha channel.
  • HSI
      The hsi_pixel is a 24bit pixel which represents a point in the Hue Saturation Intensity (HSI) color space.
  • Grayscale
      Any built in scalar type may be used as a grayscale pixel type. For example, unsigned char, int, double, etc.

Object Detection

If you want to create object detectors then try the scan_fhog_pyramid tool first. It is quite easy to use and train and will, in many cases, give excellent results.

Pixels
  • assign_pixel
  • assign_pixel_intensity
  • bgr_pixel
  • get_pixel_intensity
  • hsi_pixel
  • pixel_traits
  • rgb_alpha_pixel
  • rgb_pixel

Image I/O
  • jpeg_loader
  • load_bmp
  • load_dng
  • load_image
  • load_jpeg
  • load_png
  • png_loader
  • save_bmp
  • save_dng
  • save_jpeg
  • save_png

Object Detection
  • correlation_tracker
  • evaluate_detectors
  • find_candidate_object_locations
  • find_points_above_thresh
  • full_object_detection
  • get_frontal_face_detector
  • object_detector
  • remove_unobtainable_rectangles
  • Scan Image Pyramid Tools
    • compute_box_dimensions
    • create_grid_detection_template
    • create_overlapped_2x2_detection_template
    • create_single_box_detection_template
    • determine_object_boxes
    • setup_grid_detection_templates
    • setup_grid_detection_templates_verbose
  • scan_fhog_pyramid
  • scan_image
  • scan_image_boxes
  • scan_image_custom
  • scan_image_movable_parts
  • scan_image_pyramid
  • setup_hashed_features
  • test_box_overlap

Feature Extraction
  • binned_vector_feature_image
  • extract_fhog_features
  • extract_highdim_face_lbp_descriptors
  • extract_histogram_descriptors
  • extract_uniform_lbp_descriptors
  • fine_hog_image
  • get_surf_points
  • hashed_feature_image
  • hog_image
  • make_uniform_lbp_image
  • nearest_neighbor_feature_image
  • poly_image
  • randomly_sample_image_features
  • shape_predictor
  • SURF Tools
    • compute_dominant_angle
    • compute_surf_descriptor
    • draw_surf_points
    • get_interest_points
    • haar_x
    • haar_y
    • hessian_pyramid
    • interest_point
    • surf_point

Edges and Thresholds
  • auto_threshold_image
  • edge_orientation
  • hough_transform
  • hysteresis_threshold
  • sobel_edge_detector
  • suppress_non_maximum_edges
  • threshold_image

Morphology
  • binary_close
  • binary_complement
  • binary_difference
  • binary_dilation
  • binary_erosion
  • binary_intersection
  • binary_open
  • binary_union
  • label_connected_blobs
  • segment_image
  • skeleton

Filtering
  • float_spatially_filter_image_separable
  • gaussian_blur
  • max_filter
  • separable_3x3_filter_block_grayscale
  • separable_3x3_filter_block_rgb
  • spatially_filter_image
  • spatially_filter_image_separable
  • spatially_filter_image_separable_down
  • sum_filter
  • sum_filter_assign

Scaling and Rotating
  • add_image_left_right_flips
  • add_image_rotations
  • extract_image_chips
  • flip_image_dataset_left_right
  • flip_image_left_right
  • flip_image_up_down
  • interpolate_bilinear
  • interpolate_nearest_neighbor
  • interpolate_quadratic
  • pyramid_disable
  • pyramid_down
  • pyramid_up
  • resize_image
  • rotate_image
  • rotate_image_dataset
  • sub_image
  • transform_image
  • upsample_image_dataset

Visualization
  • draw_fhog
  • draw_line
  • draw_rectangle
  • draw_solid_circle
  • draw_surf_points
  • fill_rect
  • heatmap
  • jet
  • randomly_color_image
  • render_face_detections
  • tile_images

Miscellaneous
  • assign_all_pixels
  • assign_border_pixels
  • assign_image
  • assign_image_scaled
  • cv_image
  • equalize_histogram
  • get_histogram
  • integral_image
  • integral_image_generic
  • toMat
  • zero_border_pixels

[top]

add_image_left_right_flips

This routine takes a set of images and bounding boxes within those images and doubles the size of the dataset by adding left/right flipped copies of each image as well as the corresponding bounding boxes. Therefore, this function is useful if you are training and object detector and your objects have a left/right symmetry.

C++ Example Programs: fhog_object_detector_ex.cpp
More Details...
#include <dlib/image_transforms.h>
[top]

add_image_rotations

This routine takes a set of images and bounding boxes within those images and grows the dataset by computing many different rotations of each image. It will also adjust the positions of the bounding boxes so that they still fall on the same objects in each rotated image.
More Details...
#include <dlib/image_transforms.h>
[top]

assign_all_pixels

This global function assigns all the pixels in an image a specific value.
More Details...
#include <dlib/image_transforms.h>
[top]

assign_border_pixels

This global function assigns all the pixels in the border of an image to a specific value.
More Details...
#include <dlib/image_transforms.h>
[top]

assign_image

This global function copies one image into another and performs any necessary color space conversions to make it work right.
More Details...
#include <dlib/image_transforms.h>
[top]

assign_image_scaled

This global function copies one image into another and performs any necessary color space conversions to make it work right. Additionally, if the dynamic range of the source image is too big to fit into the destination image then it will attempt to perform the appropriate scaling.
More Details...
#include <dlib/image_transforms.h>
[top]

assign_pixel

assign_pixel() is a templated function that can assign any pixel type to another pixel type. It will perform whatever conversion is necessary to make the assignment work. (E.g. color to grayscale conversion)
More Details...
#include <dlib/pixel.h>
[top]

assign_pixel_intensity

assign_pixel_intensity() is a templated function that can change the intensity of a pixel. So if the pixel in question is a grayscale pixel then it simply assigns that pixel the given value. However, if the pixel is not a grayscale pixel then it converts the pixel to the HSI color space and sets the I channel to the given intensity and then converts this HSI value back to the original pixel's color space.
More Details...
#include <dlib/pixel.h>
[top]

auto_threshold_image

This global function performs a simple binary thresholding on an image. Instead of taking a user supplied threshold it computes one from the image using k-means clustering.
More Details...
#include <dlib/image_transforms.h>
[top]

bgr_pixel

This is a simple struct that represents a BGR colored graphical pixel.

The difference between this object and the rgb_pixel is just that this struct lays its pixels down in memory in BGR order rather than RGB order. You only care about this if you are doing something like using the cv_image object to map an OpenCV image into a more object oriented form.

More Details...
#include <dlib/pixel.h>
[top]

binary_close

This global function performs a morphological closing on an image.
More Details...
#include <dlib/image_transforms.h>
[top]

binary_complement

This global function computes the complement of a binary image.
More Details...
#include <dlib/image_transforms.h>
[top]

binary_difference

This global function computes the difference of two binary images.
More Details...
#include <dlib/image_transforms.h>
[top]

binary_dilation

This global function performs the morphological operation of dilation on an image.
More Details...
#include <dlib/image_transforms.h>
[top]

binary_erosion

This global function performs the morphological operation of erosion on an image.
More Details...
#include <dlib/image_transforms.h>
[top]

binary_intersection

This global function computes the intersection of two binary images.
More Details...
#include <dlib/image_transforms.h>
[top]

binary_open

This global function performs a morphological opening on an image.
More Details...
#include <dlib/image_transforms.h>
[top]

binary_union

This global function computes the union of two binary images.
More Details...
#include <dlib/image_transforms.h>
[top]

binned_vector_feature_image

This object is a tool for performing image feature extraction. In particular, it wraps another image feature extractor and converts the wrapped image feature vectors into a high dimensional sparse vector. For example, if the lower level feature extractor outputs the vector [3,4,5] and this vector is hashed into the second bin of four bins then the output sparse vector is:
[0,0,0,0, 3,4,5,1, 0,0,0,0, 0,0,0,0].
That is, the output vector has a dimensionality that is equal to the number of hash bins times the dimensionality of the lower level vector plus one. The value in the extra dimension concatenated onto the end of the vector is always a constant value of of 1 and serves as a bias value. This means that, if there are N hash bins, these vectors are capable of representing N different linear functions, each operating on the vectors that fall into their corresponding hash bin.

The following feature extractors can be wrapped by the binned_vector_feature_image:
  • hog_image
  • fine_hog_image
  • poly_image

More Details...
#include <dlib/image_keypoint.h>
[top]

compute_box_dimensions

This function is a tool for computing a rectangle with a particular width/height ratio and area.
More Details...
#include <dlib/image_processing.h>
[top]

compute_dominant_angle

Computes and returns the dominant angle (i.e. the angle of the dominant gradient) at a given point and scale in an image. This function is part of the main processing of the SURF algorithm.
More Details...
#include <dlib/image_keypoint.h>
[top]

compute_surf_descriptor

Computes the 64 dimensional SURF descriptor vector of a box centered at a given center point, tilted at a given angle, and sized according to a given scale.
More Details...
#include <dlib/image_keypoint.h>
[top]

correlation_tracker

This is a tool for tracking moving objects in a video stream. You give it the bounding box of an object in the first frame and it attempts to track the object in the box from frame to frame.

This tool is an implementation of the method described in the following paper:

Danelljan, Martin, et al. "Accurate scale estimation for robust visual tracking." Proceedings of the British Machine Vision Conference BMVC. 2014.

C++ Example Programs: video_tracking_ex.cpp
Python Example Programs: correlation_tracker.py
More Details...
#include <dlib/image_processing.h>
[top]

create_grid_detection_template

This function is a tool for creating a detection template usable by the scan_image_pyramid object. This particular function creates a detection template with a grid of feature extraction regions.
More Details...
#include <dlib/image_processing.h>
[top]

create_overlapped_2x2_detection_template

This function is a tool for creating a detection template usable by the scan_image_pyramid object. This particular function creates a detection template with four overlapping feature extraction regions.
More Details...
#include <dlib/image_processing.h>
[top]

create_single_box_detection_template

This function is a tool for creating a detection template usable by the scan_image_pyramid object. This particular function creates a detection template with exactly one feature extraction region.
More Details...
#include <dlib/image_processing.h>
[top]

cv_image

This object is meant to be used as a simple wrapper around the OpenCV IplImage struct or Mat object. Using this class template you can turn an OpenCV image into something that looks like a normal dlib style image object.

So you should be able to use cv_image objects with many of the image processing functions in dlib as well as the GUI tools for displaying images on the screen.

Note that you can do the reverse conversion, from dlib to OpenCV, using the toMat routine.

C++ Example Programs: webcam_face_pose_ex.cpp
More Details...
#include <dlib/opencv.h>
[top]

determine_object_boxes

The scan_image_pyramid object represents a sliding window classifier system. For it to work correctly it needs to be given a set of object boxes which define the size and shape of each sliding window and these windows need to be able to match the sizes and shapes of targets the user wishes to detect. Therefore, the determine_object_boxes() routine is a tool for computing a set of object boxes which can meet this requirement.
More Details...
#include <dlib/image_processing.h>
[top]

draw_fhog

This function takes a FHOG feature map which was created by extract_fhog_features and converts it into an image suitable for display on the screen. In particular, we draw all the hog cells into a grayscale image in a way that shows the magnitude and orientation of the gradient energy in each cell.

C++ Example Programs: fhog_ex.cpp, fhog_object_detector_ex.cpp
More Details...
#include <dlib/image_transforms.h>
[top]

draw_line

This global function draws a line on an image.
More Details...
#include <dlib/image_transforms.h>
[top]

draw_rectangle

This global function draws a rectangle on an image.
More Details...
#include <dlib/image_transforms.h>
[top]

draw_solid_circle

This global function draws a solid circle on an image.
More Details...
#include <dlib/image_transforms.h>
[top]

draw_surf_points

This routine adds a bunch of surf_point objects onto an image_window object so they can be visualized.

C++ Example Programs: surf_ex.cpp
More Details...
#include <dlib/image_keypoint/draw_surf_points.h>
[top]

edge_orientation

This global function takes horizontal and vertical gradient magnitude values and returns the orientation of the gradient.
More Details...
#include <dlib/image_transforms.h>
[top]

equalize_histogram

This global function performs histogram equalization on an image.
More Details...
#include <dlib/image_transforms.h>
[top]

evaluate_detectors

This function allows you to efficiently run a bunch of scan_fhog_pyramid based object_detectors over an image. Importantly, this function is faster than running each detector individually because it computes the HOG features only once and then reuses them for each detector.

C++ Example Programs: fhog_object_detector_ex.cpp
More Details...
#include <dlib/image_processing.h>
[top]

extract_fhog_features

This function implements the HOG feature extraction method described in the paper:
Object Detection with Discriminatively Trained Part Based Models by P. Felzenszwalb, R. Girshick, D. McAllester, D. Ramanan in IEEE Transactions on Pattern Analysis and Machine Intelligence, Vol. 32, No. 9, Sep. 2010
This means that it takes an input image and outputs Felzenszwalb's 31 dimensional version of HOG features.

C++ Example Programs: fhog_ex.cpp
More Details...
#include <dlib/image_transforms.h>
[top]

extract_highdim_face_lbp_descriptors

This function extracts the high-dimensional LBP feature described in the paper:
Blessing of Dimensionality: High-dimensional Feature and Its Efficient Compression for Face Verification by Dong Chen, Xudong Cao, Fang Wen, and Jian Sun

More Details...
#include <dlib/image_transforms.h>
[top]

extract_histogram_descriptors

This function extracts histograms of pixel values from a set of windows in an image and returns the histograms.
More Details...
#include <dlib/image_transforms.h>
[top]

extract_image_chips

This function extracts "chips" from an image. That is, it takes a list of rectangular sub-windows (i.e. chips) within an image and extracts those sub-windows, storing each into its own image. It also allows the user to specify the scale and rotation for the chip.
More Details...
#include <dlib/image_transforms.h>
[top]

extract_uniform_lbp_descriptors

Extracts histograms of uniform local-binary-patterns from an image. The histograms are from densely tiled windows that do not overlap and cover all of the image. We use the idea of uniform LBPs from the paper:
Face Description with Local Binary Patterns: Application to Face Recognition by Ahonen, Hadid, and Pietikainen.

More Details...
#include <dlib/image_transforms.h>
[top]

fill_rect

This global function draws a solid rectangle on an image.
More Details...
#include <dlib/image_transforms.h>
[top]

find_candidate_object_locations

This function takes an input image and generates a set of candidate rectangles which are expected to bound any objects in the image. It does this by running a version of the segment_image routine on the image and then reports rectangles containing each of the segments as well as rectangles containing unions of adjacent segments. The basic idea is described in the paper:
Segmentation as Selective Search for Object Recognition by Koen E. A. van de Sande, et al.
Note that this function deviates from what is described in the paper slightly. See the code for details.

Python Example Programs: find_candidate_object_locations.py
More Details...
#include <dlib/image_transforms.h>
[top]

find_points_above_thresh

This routine finds all points in an image with a pixel value above a threshold. It also has the ability to produce an efficient random subsample of such points if the number of them is very large.
More Details...
#include <dlib/image_processing.h>
[top]

fine_hog_image

This object is a version of the hog_image that allows you to extract HOG features at a finer resolution.
More Details...
#include <dlib/image_keypoint.h>
[top]

flip_image_dataset_left_right

This routine takes a set of images and bounding boxes within those images and mirrors the entire dataset left to right. This means that all images are flipped left to right and the bounding boxes are adjusted so that they still sit on top of the same visual objects in the new flipped images.
More Details...
#include <dlib/image_transforms.h>
[top]

flip_image_left_right

This is a routine which can flip an image from left to right. (e.g. as if viewed through a mirror).
More Details...
#include <dlib/image_transforms.h>
[top]

flip_image_up_down

This routine flips an image upside down.
More Details...
#include <dlib/image_transforms.h>
[top]

float_spatially_filter_image_separable

This global function performs spatial filtering on an image with a user supplied separable filter. It is optimized to work only on float valued images with float valued filters.
More Details...
#include <dlib/image_transforms.h>
[top]

full_object_detection

This object represents the location of an object in an image along with the positions of each of its constituent parts.
More Details...
#include <dlib/image_processing.h>
[top]

gaussian_blur

This global function blurs an image by convolving it with a Gaussian filter.
More Details...
#include <dlib/image_transforms.h>
[top]

get_frontal_face_detector

This function returns an object_detector that is configured to find human faces that are looking more or less towards the camera. It is created using the scan_fhog_pyramid object.

C++ Example Programs: face_detection_ex.cpp, webcam_face_pose_ex.cpp
Python Example Programs: face_detector.py,
More Details...
#include <dlib/image_processing/frontal_face_detector.h>
[top]

get_histogram

This global function computes an image's histogram and returns it in the form of a column or row matrix object.
More Details...
#include <dlib/image_transforms.h>
[top]

get_interest_points

This function extracts interest points from a hessian_pyramid.
More Details...
#include <dlib/image_keypoint.h>
[top]

get_pixel_intensity

get_pixel_intensity() is a templated function that returns the grayscale intensity of a pixel. If the pixel isn't a grayscale pixel then it converts the pixel to grayscale and returns that value.
More Details...
#include <dlib/pixel.h>
[top]

get_surf_points

This function runs the complete SURF algorithm on an input image and returns the points it found. For a description of what exactly the SURF algorithm does you should read the following paper:
SURF: Speeded Up Robust Features By Herbert Bay, Tinne Tuytelaars, and Luc Van Gool

Also note that there are numerous flavors of the SURF algorithm you can put together using the functions in dlib. The get_surf_points() function is just an example of one way you might do so.

C++ Example Programs: surf_ex.cpp
More Details...
#include <dlib/image_keypoint.h>
[top]

haar_x

This is a function that operates on an integral_image and allows you to compute the response of a Haar wavelet oriented along the X axis.
More Details...
#include <dlib/image_transforms.h>
[top]

haar_y

This is a function that operates on an integral_image and allows you to compute the response of a Haar wavelet oriented along the Y axis.
More Details...
#include <dlib/image_transforms.h>
[top]

hashed_feature_image

This object is a tool for performing image feature extraction. In particular, it wraps another image feature extractor and converts the wrapped image feature vectors into sparse indicator vectors. It does this by hashing each feature vector and then returns a new vector which is zero everywhere except for the position determined by the hash.

The following feature extractors can be wrapped by the hashed_feature_image:
  • hog_image
  • fine_hog_image
  • poly_image

C++ Example Programs: object_detector_ex.cpp, train_object_detector.cpp
More Details...
#include <dlib/image_keypoint.h>
[top]

heatmap

Converts a grayscale image into a heatmap. This is useful if you want to display a grayscale image with more than 256 values. In particular, this function uses the following color mapping:

C++ Example Programs: image_ex.cpp
More Details...
#include <dlib/image_transforms.h>
[top]

hessian_pyramid

This object represents an image pyramid where each level in the pyramid holds determinants of Hessian matrices for the original input image. This object can be used to find stable interest points in an image.

This object is an implementation of the fast Hessian pyramid as described in the paper:
SURF: Speeded Up Robust Features By Herbert Bay, Tinne Tuytelaars, and Luc Van Gool
This implementation was also influenced by the very well documented OpenSURF library and its corresponding description of how the fast Hessian algorithm functions:
Notes on the OpenSURF Library by Christopher Evans

More Details...
#include <dlib/image_keypoint.h>
[top]

hog_image

This object is a tool for performing the image feature extraction algorithm described in the following paper:
Histograms of Oriented Gradients for Human Detection by Navneet Dalal and Bill Triggs

C++ Example Programs: object_detector_ex.cpp, train_object_detector.cpp
More Details...
#include <dlib/image_keypoint.h>
[top]

hough_transform

This object is a tool for computing the line finding version of the Hough transform given some kind of edge detection image as input. It also allows the edge pixels to be weighted such that higher weighted edge pixels contribute correspondingly more to the output of the Hough transform, allowing stronger edges to create correspondingly stronger line detections in the final Hough transform.

C++ Example Programs: hough_transform_ex.cpp
More Details...
#include <dlib/image_transforms.h>
[top]

hsi_pixel

This is a simple struct that represents an HSI colored graphical pixel.
More Details...
#include <dlib/pixel.h>
[top]

hysteresis_threshold

This global function performs hysteresis thresholding on an image.
More Details...
#include <dlib/image_transforms.h>
[top]

integral_image

This is a specialization of the integral_image_generic template for the case where sums of pixel values should be represented with longs. E.g. if you use 8bit pixels in your original images then this is the appropriate kind of integral image to use with them.
More Details...
#include <dlib/image_transforms.h>
[top]

integral_image_generic

This object is an alternate way of representing image data that allows for very fast computations of sums of pixels in rectangular regions. To use this object you load it with a normal image and then you can use the get_sum_of_area() member function to compute sums of pixels in a given area in constant time.
More Details...
#include <dlib/image_transforms.h>
[top]

interest_point

This is a simple struct used to represent the interest points returned by the get_interest_points function.
More Details...
#include <dlib/image_keypoint.h>
[top]

interpolate_bilinear

This object is a tool for performing bilinear interpolation on an image.
More Details...
#include <dlib/image_transforms.h>
[top]

interpolate_nearest_neighbor

This object is a tool for performing nearest neighbor interpolation on an image.
More Details...
#include <dlib/image_transforms.h>
[top]

interpolate_quadratic

This object is a tool for performing quadratic interpolation on an image.
More Details...
#include <dlib/image_transforms.h>
[top]

jet

Converts a grayscale image into an image using the jet color scheme. This is useful if you want to display a grayscale image with more than 256 values. In particular, this function uses the following color mapping:

More Details...
#include <dlib/image_transforms.h>
[top]

jpeg_loader

This object loads a JPEG image file into an array2d of pixels.

Note that you must define DLIB_JPEG_SUPPORT if you want to use this object. You must also set your build environment to link to the libjpeg library. However, if you use CMake and dlib's default CMakeLists.txt file then it will get setup automatically.

More Details...
#include <dlib/image_io.h>
[top]

label_connected_blobs

This function labels each of the connected blobs in an image with a unique integer label.
More Details...
#include <dlib/image_transforms.h>
[top]

load_bmp

This global function loads a MS Windows BMP file into an array2d of pixels.
More Details...
#include <dlib/image_io.h>
[top]

load_dng

This global function loads a dlib DNG file (a lossless compressed image format) into an array2d of pixels.
More Details...
#include <dlib/image_io.h>
[top]

load_image

This global function takes a file name, looks at its extension, and then loads it into an array2d of pixels using the appropriate image loading routine. The supported types are BMP, PNG, JPEG, and the dlib DNG file format.

Note that you can only load PNG and JPEG files if you link against libpng and libjpeg respectively.

C++ Example Programs: image_ex.cpp
More Details...
#include <dlib/image_io.h>
[top]

load_jpeg

This function loads a JPEG image file into an array2d of pixels.

Note that you must define DLIB_JPEG_SUPPORT if you want to use this object. You must also set your build environment to link to the libjpeg library. However, if you use CMake and dlib's default CMakeLists.txt file then it will get setup automatically.

More Details...
#include <dlib/image_io.h>
[top]

load_png

This function loads a Portable Network Graphics (PNG) image file into an array2d of pixels.

Note that you must define DLIB_PNG_SUPPORT if you want to use this object. You must also set your build environment to link to the libpng library. However, if you use CMake and dlib's default CMakeLists.txt file then it will get setup automatically.

More Details...
#include <dlib/image_io.h>
[top]

make_uniform_lbp_image

This function extracts the uniform local-binary-pattern feature at every pixel of an image and stores the output in a new image object. We use the idea of uniform LBPs from the paper:
Face Description with Local Binary Patterns: Application to Face Recognition by Ahonen, Hadid, and Pietikainen.

More Details...
#include <dlib/image_transforms.h>
[top]

max_filter

This function slides a rectangle over an input image and outputs a new image which contains the maximum valued pixel found inside the rectangle at each position in the input image.
More Details...
#include <dlib/image_transforms.h>
[top]

nearest_neighbor_feature_image

This object is a tool for performing image feature extraction. In particular, it wraps another image feature extractor and converts the wrapped image feature vectors into sparse indicator vectors. It does this by finding the nearest neighbor for each feature vector and returning an indicator vector that is zero everywhere except for the position indicated by the nearest neighbor.

The following feature extractors can be wrapped by the nearest_neighbor_feature_image:
  • hog_image
  • fine_hog_image
  • poly_image

More Details...
#include <dlib/image_keypoint.h>
[top]

object_detector

This object is a tool for detecting the positions of objects in an image. In particular, it is a simple container to aggregate an instance of an image scanner object (either scan_fhog_pyramid, scan_image_pyramid, scan_image_boxes, or scan_image_custom), the weight vector needed by one of these image scanners, and finally an instance of test_box_overlap. The test_box_overlap object is used to perform non-max suppression on the output of the image scanner object.

Note that you can use the structural_object_detection_trainer to learn the parameters of an object_detector. See the example programs for an introduction.

C++ Example Programs: fhog_object_detector_ex.cpp, face_detection_ex.cpp, object_detector_ex.cpp, object_detector_advanced_ex.cpp, train_object_detector.cpp
Python Example Programs: face_detector.py, train_object_detector.py
More Details...
#include <dlib/image_processing.h>
[top]

pixel_traits

As the name implies, this is a traits class for pixel types. It allows you to determine what sort of pixel type you are dealing with.
More Details...
#include <dlib/pixel.h>
[top]

png_loader

This object loads a Portable Network Graphics (PNG) image file into an array2d of pixels.

Note that you must define DLIB_PNG_SUPPORT if you want to use this object. You must also set your build environment to link to the libpng library. However, if you use CMake and dlib's default CMakeLists.txt file then it will get setup automatically.

More Details...
#include <dlib/image_io.h>
[top]

poly_image

This object is a tool for extracting local feature descriptors from an image. In particular, it fits polynomials to local pixel patches and allows you to query the coefficients of these polynomials.
More Details...
#include <dlib/image_keypoint.h>
[top]

pyramid_disable

This object downsamples an image at a ratio of infinity to 1. That means it always outputs an image of size zero. This is useful because it can be supplied to routines which take a pyramid_down function object and it will essentially disable pyramid processing. This way, a pyramid oriented function can be turned into a regular routine which processes just the original undownsampled image.
More Details...
#include <dlib/image_transforms.h>
[top]

pyramid_down

This is a simple function object to help create image pyramids. It downsamples an image by a ratio of N to N-1 where N is supplied by the user as a template argument.
More Details...
#include <dlib/image_transforms.h>
[top]

pyramid_up

This routine upsamples an image. In particular, it takes a pyramid_down object (or an object with a compatible interface) as an argument and performs an upsampling which is the inverse of the supplied pyramid_down object.
More Details...
#include <dlib/image_transforms.h>
[top]

randomly_color_image

Randomly generates a mapping from gray level pixel values to the RGB pixel space and then uses this mapping to create a colored version an image.

This function is useful for displaying the results of some image segmentation. For example, the output of label_connected_blobs or segment_image.

More Details...
#include <dlib/image_transforms.h>
[top]

randomly_sample_image_features

Given a feature extractor such as the hog_image, this routine selects a random subsample of local image feature vectors from a set of images.
More Details...
#include <dlib/statistics.h>
[top]

remove_unobtainable_rectangles

Recall that the scan_image_pyramid and scan_image_boxes objects can't produce all possible rectangles as object detections since they only consider a limited subset of all possible object positions. Therefore, when training an object detector that uses these tools you must make sure the training data does not contain any object locations that are unobtainable by the image scanning model. The remove_unobtainable_rectangles() routine is a tool to filter out these unobtainable rectangles from the training.
More Details...
#include <dlib/image_processing.h>
[top]

render_face_detections

This function takes a set of full_object_detections which represent human faces annotated with 68 facial landmarks (according to the iBUG 300-W scheme) and converts them into a form suitable for display on an image_window.

For example, it will take the output of a shape_predictor that uses this facial landmarking scheme and will produce visualizations like this:

C++ Example Programs: face_landmark_detection_ex.cpp, webcam_face_pose_ex.cpp
More Details...
#include <dlib/image_processing/render_face_detections.h>
[top]

resize_image

This is a routine capable of resizing or stretching an image.
More Details...
#include <dlib/image_transforms.h>
[top]

rgb_alpha_pixel

This is a simple struct that represents an RGB colored graphical pixel with an alpha channel.
More Details...
#include <dlib/pixel.h>
[top]

rgb_pixel

This is a simple struct that represents an RGB colored graphical pixel.
More Details...
#include <dlib/pixel.h>
[top]

rotate_image

This is a routine for rotating an image.
More Details...
#include <dlib/image_transforms.h>
[top]

rotate_image_dataset

This routine takes a set of images and bounding boxes within those images and rotates the entire dataset by a user specified angle. This means that all images are rotated and the bounding boxes are adjusted so that they still sit on top of the same visual objects in the new rotated images.
More Details...
#include <dlib/image_transforms.h>
[top]

save_bmp

This global function saves an image as a MS Windows BMP file.

This routine can save images containing any type of pixel. However, it will convert all color pixels into rgb_pixel and grayscale pixels into uint8 type before saving to disk.

More Details...
#include <dlib/image_io.h>
[top]

save_dng

This global function saves an image as a dlib DNG file (a lossless compressed image format).

This routine can save images containing any type of pixel. However, the DNG format can natively store only the following pixel types: rgb_pixel, hsi_pixel, rgb_alpha_pixel, uint8, uint16, float, and double. All other pixel types will be converted into one of these types as appropriate before being saved to disk.

More Details...
#include <dlib/image_io.h>
[top]

save_jpeg

This global function writes an image to disk as a JPEG file.

Note that you must define DLIB_JPEG_SUPPORT if you want to use this function. You must also set your build environment to link to the libjpeg library. However, if you use CMake and dlib's default CMakeLists.txt file then it will get setup automatically.

This routine can save images containing any type of pixel. However, save_jpeg() can only natively store the following pixel types: rgb_pixel and uint8. All other pixel types will be converted into one of these types as appropriate before being saved to disk.

More Details...
#include <dlib/image_io.h>
[top]

save_png

This global function writes an image to disk as a PNG (Portable Network Graphics) file.

Note that you must define DLIB_PNG_SUPPORT if you want to use this function. You must also set your build environment to link to the libpng library. However, if you use CMake and dlib's default CMakeLists.txt file then it will get setup automatically.

This routine can save images containing any type of pixel. However, save_png() can only natively store the following pixel types: rgb_pixel, rgb_alpha_pixel, uint8, and uint16. All other pixel types will be converted into one of these types as appropriate before being saved to disk.

More Details...
#include <dlib/image_io.h>
[top]

scan_fhog_pyramid

This object is a tool for running a fixed sized sliding window classifier over an image pyramid. In particular, it slides a linear classifier over a HOG pyramid as discussed in the paper:
Histograms of Oriented Gradients for Human Detection by Navneet Dalal and Bill Triggs, CVPR 2005
However, we augment the method slightly to use the version of HOG features from:
Object Detection with Discriminatively Trained Part Based Models by P. Felzenszwalb, R. Girshick, D. McAllester, D. Ramanan IEEE Transactions on Pattern Analysis and Machine Intelligence, Vol. 32, No. 9, Sep. 2010
Since these HOG features have been shown to give superior performance.

C++ Example Programs: fhog_object_detector_ex.cpp
Python Example Programs: train_object_detector.py
More Details...
#include <dlib/image_processing.h>
[top]

scan_image

This global function is a tool for sliding a set of rectangles over an image space and finding the locations where the sum of pixels in the rectangles exceeds a threshold. It is useful for implementing certain kinds of sliding window classifiers.
More Details...
#include <dlib/image_processing.h>
[top]

scan_image_boxes

This object is a tool for running a classifier over an image with the goal of localizing each object present. The localization is in the form of the bounding box around each object of interest.

Unlike the scan_image_pyramid object which scans a fixed sized window over an image pyramid, the scan_image_boxes tool allows you to define your own list of "candidate object locations" which should be evaluated. This is simply a list of rectangle objects which might contain objects of interest. The scan_image_boxes object will then evaluate the classifier at each of these locations and return the subset of rectangles which appear to have objects in them.

This object can also be understood as a general tool for implementing the spatial pyramid models described in the paper:
Beyond Bags of Features: Spatial Pyramid Matching for Recognizing Natural Scene Categories by Svetlana Lazebnik, Cordelia Schmid, and Jean Ponce

The following feature extractors can be used with the scan_image_boxes object:
  • hashed_feature_image
  • binned_vector_feature_image
  • nearest_neighbor_feature_image

More Details...
#include <dlib/image_processing.h>
[top]

scan_image_custom

This object is a tool for running a classifier over an image with the goal of localizing each object present. The localization is in the form of the bounding box around each object of interest.

Unlike the scan_image_pyramid and scan_image_boxes objects, this image scanner delegates all the work of constructing the object feature vector to a user supplied feature extraction object. That is, scan_image_custom simply asks the supplied feature extractor what boxes in the image we should investigate and then asks the feature extractor for the complete feature vector for each box. That is, scan_image_custom does not apply any kind of pyramiding or other higher level processing to the features coming out of the feature extractor. That means that when you use scan_image_custom it is completely up to you to define the feature vector used with each image box.

More Details...
#include <dlib/image_processing.h>
[top]

scan_image_movable_parts

This global function is a tool for sliding a set of rectangles over an image space and finding the locations where the sum of pixels in the rectangles exceeds a threshold. It is useful for implementing certain kinds of sliding window classifiers. The behavior of this routine is similar to scan_image except that it can also handle movable parts in addition to rigidly placed parts within the sliding window.
More Details...
#include <dlib/image_processing.h>
[top]

scan_image_pyramid

This object is a tool for running a sliding window classifier over an image pyramid. This object can also be understood as a general tool for implementing the spatial pyramid models described in the paper:
Beyond Bags of Features: Spatial Pyramid Matching for Recognizing Natural Scene Categories by Svetlana Lazebnik, Cordelia Schmid, and Jean Ponce
It also includes the ability to represent movable part models.

The following feature extractors can be used with the scan_image_pyramid object:
  • hashed_feature_image
  • binned_vector_feature_image
  • nearest_neighbor_feature_image

C++ Example Programs: object_detector_ex.cpp, object_detector_advanced_ex.cpp
More Details...
#include <dlib/image_processing.h>
[top]

segment_image

Attempts to segment an image into regions which have some visual consistency to them. In particular, this function implements the algorithm described in the paper:
Efficient Graph-Based Image Segmentation by Felzenszwalb and Huttenlocher.

More Details...
#include <dlib/image_transforms.h>
[top]

separable_3x3_filter_block_grayscale

This routine filters part of an image with a user supplied 3x3 separable filter. The output is a grayscale sub-image.
More Details...
#include <dlib/image_transforms.h>
[top]

separable_3x3_filter_block_rgb

This routine filters part of an image with a user supplied 3x3 separable filter. The output is a RGB sub-image.
More Details...
#include <dlib/image_transforms.h>
[top]

setup_grid_detection_templates

This routine uses determine_object_boxes to obtain a set of object boxes and then adds them to a scan_image_pyramid object as detection templates. It also uses create_grid_detection_template to create each feature extraction region. Therefore, the detection templates will extract features from a regular grid inside each object box.
More Details...
#include <dlib/image_processing.h>
[top]

setup_grid_detection_templates_verbose

This function is identical to setup_grid_detection_templates except that it also outputs information regarding the selected detection templates to standard out.

C++ Example Programs: object_detector_ex.cpp, train_object_detector.cpp
More Details...
#include <dlib/image_processing.h>
[top]

setup_hashed_features

This is a tool for configuring the hashed_feature_image or binned_vector_feature_image object with a random projection hash.

C++ Example Programs: object_detector_ex.cpp, train_object_detector.cpp
More Details...
#include <dlib/image_processing.h>
[top]

shape_predictor

This object is a tool that takes in an image region containing some object and outputs a set of point locations that define the pose of the object. The classic example of this is human face pose prediction, where you take an image of a human face as input and are expected to identify the locations of important facial landmarks such as the corners of the mouth and eyes, tip of the nose, and so forth. For example, here is the output of dlib's 68-face-landmark shape_predictor on an image from the HELEN dataset:

To create useful instantiations of this object you need to use the shape_predictor_trainer object to train a shape_predictor using a set of training images, each annotated with shapes you want to predict. To do this, the shape_predictor_trainer uses the state-of-the-art method from the paper:
One Millisecond Face Alignment with an Ensemble of Regression Trees by Vahid Kazemi and Josephine Sullivan, CVPR 2014

C++ Example Programs: face_landmark_detection_ex.cpp, train_shape_predictor_ex.cpp, webcam_face_pose_ex.cpp
Python Example Programs: train_shape_predictor.py, face_landmark_detection.py
More Details...
#include <dlib/image_processing.h>
[top]

skeleton

This function computes the skeletonization of an image. That is, given a binary image, we progressively thin the binary blobs until only a single pixel wide skeleton of the original blobs remains.
More Details...
#include <dlib/image_transforms.h>
[top]

sobel_edge_detector

This global function performs spatial filtering on an image using the sobel edge detection filters.

C++ Example Programs: image_ex.cpp
More Details...
#include <dlib/image_transforms.h>
[top]

spatially_filter_image

This global function performs spatial filtering on an image with a user supplied filter.
More Details...
#include <dlib/image_transforms.h>
[top]

spatially_filter_image_separable

This global function performs spatial filtering on an image with a user supplied separable filter.
More Details...
#include <dlib/image_transforms.h>
[top]

spatially_filter_image_separable_down

This global function performs spatial filtering on an image with a user supplied separable filter. Additionally, it produces a downsampled output.
More Details...
#include <dlib/image_transforms.h>
[top]

sub_image

This function returns a lightweight sub-image of another image. In particular, the returned sub-image simply holds a pointer to the original image, meaning there is no overhead for using or creating the sub-image.
More Details...
#include <dlib/image_transforms.h>
[top]

sum_filter

This function slides a rectangle over an input image and adds the sum of pixel values in each rectangle location to another image.
More Details...
#include <dlib/image_transforms.h>
[top]

sum_filter_assign

This function slides a rectangle over an input image and outputs a new image which contains the sum of pixels inside the rectangle at each position in the input image.
More Details...
#include <dlib/image_transforms.h>
[top]

suppress_non_maximum_edges

This global function performs non-maximum suppression on a gradient image.

C++ Example Programs: image_ex.cpp
More Details...
#include <dlib/image_transforms.h>
[top]

surf_point

This is a simple struct used to represent the SURF points returned by the get_surf_points function.

C++ Example Programs: surf_ex.cpp
More Details...
#include <dlib/image_keypoint.h>
[top]

test_box_overlap

This object is a simple function object for determining if two rectangles overlap.
More Details...
#include <dlib/image_processing.h>
[top]

threshold_image

This global function performs a simple binary thresholding on an image with a user supplied threshold.
More Details...
#include <dlib/image_transforms.h>
[top]

tile_images

This function takes an array of images and tiles them into a single large square image and returns this new big tiled image. Therefore, it is a useful method to visualize many small images at once.
More Details...
#include <dlib/image_transforms.h>
[top]

toMat

This routine converts a dlib style image into an instance of OpenCV's cv::Mat object. This is done by setting up the Mat object to point to the same memory as the dlib image.

Note that you can do the reverse conversion, from OpenCV to dlib, using the cv_image object.

More Details...
#include <dlib/opencv.h>
[top]

transform_image

This routine is a tool for transforming images using some kind of point mapping function (e.g. point_transform_affine) and pixel interpolation tool (e.g. interpolate_quadratic). An example application of this routine is for image rotation. Indeed, it is how rotate_image is implemented.
More Details...
#include <dlib/image_transforms.h>
[top]

upsample_image_dataset

This routine takes a set of images and bounding boxes within those images and upsamples the entire dataset. This means that all images are upsampled and the bounding boxes are adjusted so that they still sit on top of the same visual objects in the new images.
More Details...
#include <dlib/image_transforms.h>
[top]

zero_border_pixels

This global function zeros the pixels on the border of an image.
More Details...
#include <dlib/image_transforms.h>


dlib C++ Library - pixel.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_PIXEl_
#define DLIB_PIXEl_

#include <iostream>
#include "serialize.h"
#include <cmath>
#include "algs.h"
#include "uintn.h"
#include <limits>
#include <complex>
#include "enable_if.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    /*!
        This file contains definitions of pixel objects and related classes and
        functionality.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    struct pixel_traits;
    /*!
        WHAT THIS OBJECT REPRESENTS
            As the name implies, this is a traits class for pixel types.
            It defines the properties of a pixel.

        This traits class will define the following public static members:
            - bool grayscale
            - bool rgb
            - bool rgb_alpha
            - bool hsi

            - bool has_alpha

            - long num

            - basic_pixel_type
            - basic_pixel_type min()
            - basic_pixel_type max()
            - is_unsigned

        The above public constants are subject to the following constraints:
            - only one of grayscale, rgb, rgb_alpha, or hsi is true
            - if (rgb == true) then
                - The type T will be a struct with 3 public members of type
                  unsigned char named "red" "green" and "blue".
                - This type of pixel represents the RGB color space.
                - num == 3
                - has_alpha == false
                - basic_pixel_type == unsigned char
                - min() == 0
                - max() == 255
                - is_unsigned == true
            - if (rgb_alpha == true) then
                - The type T will be a struct with 4 public members of type
                  unsigned char named "red" "green" "blue" and "alpha".
                - This type of pixel represents the RGB color space with
                  an alpha channel where an alpha of 0 represents a pixel
                  that is totally transparent and 255 represents a pixel
                  with maximum opacity.
                - num == 4
                - has_alpha == true
                - basic_pixel_type == unsigned char
                - min() == 0
                - max() == 255
                - is_unsigned == true
            - else if (hsi == true) then
                - The type T will be a struct with 3 public members of type
                  unsigned char named "h" "s" and "i".
                - This type of pixel represents the HSI color space.
                - num == 3
                - has_alpha == false
                - basic_pixel_type == unsigned char
                - min() == 0
                - max() == 255
                - is_unsigned == true
            - else
                - grayscale == true
                - This type of pixel represents a grayscale color space.  T
                  will be some kind of basic scalar type such as unsigned int.
                - num == 1
                - has_alpha == false
                - basic_pixel_type == T
                - min() == the minimum obtainable value of objects of type T
                - max() == the maximum obtainable value of objects of type T
                - is_unsigned is true if min() == 0 and false otherwise
    !*/

// ----------------------------------------------------------------------------------------

    struct rgb_pixel
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is a simple struct that represents an RGB colored graphical pixel.
        !*/

        rgb_pixel (
        ) {}

        rgb_pixel (
            unsigned char red_,
            unsigned char green_,
            unsigned char blue_
        ) : red(red_), green(green_), blue(blue_) {}

        unsigned char red;
        unsigned char green;
        unsigned char blue;
    };

// ----------------------------------------------------------------------------------------

    struct bgr_pixel
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is a simple struct that represents an BGR colored graphical pixel.
                (the reason it exists in addition to the rgb_pixel is so you can lay
                it down on top of a memory region that organizes its color data in the
                BGR format and still be able to read it)
        !*/

        bgr_pixel (
        ) {}

        bgr_pixel (
            unsigned char blue_,
            unsigned char green_,
            unsigned char red_
        ) : blue(blue_), green(green_), red(red_) {}

        unsigned char blue;
        unsigned char green;
        unsigned char red;
    };

// ----------------------------------------------------------------------------------------

    struct rgb_alpha_pixel
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is a simple struct that represents an RGB colored graphical pixel
                with an alpha channel.
        !*/

        rgb_alpha_pixel (
        ) {}

        rgb_alpha_pixel (
            unsigned char red_,
            unsigned char green_,
            unsigned char blue_,
            unsigned char alpha_
        ) : red(red_), green(green_), blue(blue_), alpha(alpha_) {}

        unsigned char red;
        unsigned char green;
        unsigned char blue;
        unsigned char alpha;
    };

// ----------------------------------------------------------------------------------------

    struct hsi_pixel
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is a simple struct that represents an HSI colored graphical pixel.
        !*/

        hsi_pixel (
        ) {}

        hsi_pixel (
            unsigned char h_,
            unsigned char s_,
            unsigned char i_
        ) : h(h_), s(s_), i(i_) {}

        unsigned char h;
        unsigned char s;
        unsigned char i;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename P1,
        typename P2
        >
    inline void assign_pixel (
        P1& dest,
        const P2& src
    );
    /*!
        requires
            - pixel_traits<P1> must be defined
            - pixel_traits<P2> must be defined
        ensures
            - if (P1 and P2 are the same type of pixel) then
                - simply copies the value of src into dest.  In other words,
                  dest will be identical to src after this function returns.
            - else if (P1 and P2 are not the same type of pixel) then
                - assigns pixel src to pixel dest and does any necessary color space
                  conversions.
                - When converting from a grayscale color space with more than 255 values the
                  pixel intensity is saturated at pixel_traits<P1>::max() or pixel_traits<P1>::min()
                  as appropriate.
                - if (the dest pixel has an alpha channel and the src pixel doesn't) then
                    - #dest.alpha == 255
                - else if (the src pixel has an alpha channel but the dest pixel doesn't) then
                    - #dest == the original dest value blended with the src value according
                      to the alpha channel in src.
                      (i.e.  #dest == src*(alpha/255) + dest*(1-alpha/255))
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename P
        >
    inline typename pixel_traits<P>::basic_pixel_type get_pixel_intensity (
        const P& src
    );
    /*!
        requires
            - pixel_traits<P> must be defined
        ensures
            - if (pixel_traits<P>::grayscale == true) then
                - returns src
            - else
                - converts src to grayscale and returns the resulting value.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename P,
        typename T
        >
    inline void assign_pixel_intensity (
        P& dest,
        const T& new_intensity
    );
    /*!
        requires
            - pixel_traits<P> must be defined
            - pixel_traits<T> must be defined
        ensures
            - This function changes the intensity of the dest pixel. So if the pixel in
              question is a grayscale pixel then it simply assigns that pixel with the
              value of get_pixel_intensity(new_intensity).  However, if the pixel is not
              a grayscale pixel then it converts the pixel to the HSI color space and sets
              the I channel to the given intensity and then converts this HSI value back to
              the original pixel's color space.
            - Note that we don't necessarily have #get_pixel_intensity(dest) == get_pixel_intensity(new_intensity)
              due to vagaries of how converting to and from HSI works out.
            - if (the dest pixel has an alpha channel) then
                - #dest.alpha == dest.alpha
    !*/

// ----------------------------------------------------------------------------------------

    inline void serialize (
        const rgb_pixel& item,
        std::ostream& out
    );
    /*!
        provides serialization support for the rgb_pixel struct
    !*/

// ----------------------------------------------------------------------------------------

    inline void deserialize (
        rgb_pixel& item,
        std::istream& in
    );
    /*!
        provides deserialization support for the rgb_pixel struct
    !*/

// ----------------------------------------------------------------------------------------

    inline void serialize (
        const bgr_pixel& item,
        std::ostream& out
    );
    /*!
        provides serialization support for the bgr_pixel struct
    !*/

// ----------------------------------------------------------------------------------------

    inline void deserialize (
        bgr_pixel& item,
        std::istream& in
    );
    /*!
        provides deserialization support for the bgr_pixel struct
    !*/

// ----------------------------------------------------------------------------------------

    inline void serialize (
        const rgb_alpha_pixel& item,
        std::ostream& out
    );
    /*!
        provides serialization support for the rgb_alpha_pixel struct
    !*/

// ----------------------------------------------------------------------------------------

    inline void deserialize (
        rgb_alpha_pixel& item,
        std::istream& in
    );
    /*!
        provides deserialization support for the rgb_alpha_pixel struct
    !*/

// ----------------------------------------------------------------------------------------

    inline void serialize (
        const hsi_pixel& item,
        std::ostream& out
    );
    /*!
        provides serialization support for the hsi_pixel struct
    !*/

// ----------------------------------------------------------------------------------------

    inline void deserialize (
        hsi_pixel& item,
        std::istream& in
    );
    /*!
        provides deserialization support for the hsi_pixel struct
    !*/

// ----------------------------------------------------------------------------------------

    template <>
    struct pixel_traits<rgb_pixel>
    {
        const static bool rgb  = true;
        const static bool rgb_alpha  = false;
        const static bool grayscale = false;
        const static bool hsi = false;
        const static long num = 3;
        typedef unsigned char basic_pixel_type;
        static basic_pixel_type min() { return 0;}
        static basic_pixel_type max() { return 255;}
        const static bool is_unsigned = true;
        const static bool has_alpha = false;
    };

// ----------------------------------------------------------------------------------------

    template <>
    struct pixel_traits<bgr_pixel>
    {
        const static bool rgb  = true;
        const static bool rgb_alpha  = false;
        const static bool grayscale = false;
        const static bool hsi = false;
        const static long num = 3;
        typedef unsigned char basic_pixel_type;
        static basic_pixel_type min() { return 0;}
        static basic_pixel_type max() { return 255;}
        const static bool is_unsigned = true;
        const static bool has_alpha = false;
    };

// ----------------------------------------------------------------------------------------

    template <>
    struct pixel_traits<rgb_alpha_pixel>
    {
        const static bool rgb  = false;
        const static bool rgb_alpha  = true;
        const static bool grayscale = false;
        const static bool hsi = false;
        const static long num = 4;
        typedef unsigned char basic_pixel_type;
        static basic_pixel_type min() { return 0;}
        static basic_pixel_type max() { return 255;}
        const static bool is_unsigned = true;
        const static bool has_alpha = true;
    };

// ----------------------------------------------------------------------------------------

    template <>
    struct pixel_traits<hsi_pixel>
    {
        const static bool rgb  = false;
        const static bool rgb_alpha  = false;
        const static bool grayscale = false;
        const static bool hsi = true;
        const static long num = 3;
        typedef unsigned char basic_pixel_type;
        static basic_pixel_type min() { return 0;}
        static basic_pixel_type max() { return 255;}
        const static bool is_unsigned = true;
        const static bool has_alpha = false;
    };

// ----------------------------------------------------------------------------------------

    template <typename T>
    struct grayscale_pixel_traits
    {
        const static bool rgb  = false;
        const static bool rgb_alpha  = false;
        const static bool grayscale = true;
        const static bool hsi = false;
        const static long num = 1;
        const static bool has_alpha = false;
        typedef T basic_pixel_type;
        static basic_pixel_type min() { return std::numeric_limits<T>::min();}
        static basic_pixel_type max() { return std::numeric_limits<T>::max();}
        const static bool is_unsigned = is_unsigned_type<T>::value;
    };

    template <> struct pixel_traits<unsigned char>  : public grayscale_pixel_traits<unsigned char> {};
    template <> struct pixel_traits<unsigned short> : public grayscale_pixel_traits<unsigned short> {};
    template <> struct pixel_traits<unsigned int>   : public grayscale_pixel_traits<unsigned int> {};
    template <> struct pixel_traits<unsigned long>  : public grayscale_pixel_traits<unsigned long> {};

    template <> struct pixel_traits<char>           : public grayscale_pixel_traits<char> {};
    template <> struct pixel_traits<signed char>    : public grayscale_pixel_traits<signed char> {};
    template <> struct pixel_traits<short>          : public grayscale_pixel_traits<short> {};
    template <> struct pixel_traits<int>            : public grayscale_pixel_traits<int> {};
    template <> struct pixel_traits<long>           : public grayscale_pixel_traits<long> {};

    template <> struct pixel_traits<int64>          : public grayscale_pixel_traits<int64> {};
    template <> struct pixel_traits<uint64>         : public grayscale_pixel_traits<uint64> {};

// ----------------------------------------------------------------------------------------

    template <typename T>
    struct float_grayscale_pixel_traits
    {
        const static bool rgb  = false;
        const static bool rgb_alpha  = false;
        const static bool grayscale = true;
        const static bool hsi = false;
        const static long num = 1;
        const static bool has_alpha = false;
        typedef T basic_pixel_type;
        static basic_pixel_type min() { return -std::numeric_limits<T>::max();}
        static basic_pixel_type max() { return std::numeric_limits<T>::max();}
        const static bool is_unsigned = false;
    };

    template <> struct pixel_traits<float>          : public float_grayscale_pixel_traits<float> {};
    template <> struct pixel_traits<double>         : public float_grayscale_pixel_traits<double> {};
    template <> struct pixel_traits<long double>    : public float_grayscale_pixel_traits<long double> {};

    // These are here mainly so you can easily copy images into complex arrays.  This is
    // useful when you want to do a FFT on an image or some similar operation.
    template <> struct pixel_traits<std::complex<float> > :       public float_grayscale_pixel_traits<float> {};
    template <> struct pixel_traits<std::complex<double> > :      public float_grayscale_pixel_traits<double> {};
    template <> struct pixel_traits<std::complex<long double> > : public float_grayscale_pixel_traits<long double> {};

// ----------------------------------------------------------------------------------------

    // The following is a bunch of conversion stuff for the assign_pixel function.

    namespace assign_pixel_helpers
    {

    // -----------------------------
        // all the same kind

        template < typename P >
        typename enable_if_c<pixel_traits<P>::grayscale>::type
        assign(P& dest, const P& src)
        {
            dest = src;
        }

    // -----------------------------

        template <typename T>
        typename unsigned_type<T>::type make_unsigned (
            const T& val
        ) { return static_cast<typename unsigned_type<T>::type>(val); }

        inline float make_unsigned(const float& val) { return val; }
        inline double make_unsigned(const double& val) { return val; }
        inline long double make_unsigned(const long double& val) { return val; }

        template <typename T, typename P>
        typename enable_if_c<pixel_traits<T>::is_unsigned == pixel_traits<P>::is_unsigned, bool>::type less_or_equal_to_max (
            const P& p
        )
        /*!
            ensures
                - returns true if p is <= max value of T
        !*/
        {
            return p <= pixel_traits<T>::max();
        }

        template <typename T, typename P>
        typename enable_if_c<pixel_traits<T>::is_unsigned && !pixel_traits<P>::is_unsigned, bool>::type less_or_equal_to_max (
            const P& p
        )
        {
            if (p <= 0)
                return true;
            else if (make_unsigned(p) <= pixel_traits<T>::max())
                return true;
            else
                return false;
        }

        template <typename T, typename P>
        typename enable_if_c<!pixel_traits<T>::is_unsigned && pixel_traits<P>::is_unsigned, bool>::type less_or_equal_to_max (
            const P& p
        )
        {
            return p <= make_unsigned(pixel_traits<T>::max());
        }

    // -----------------------------

        template <typename T, typename P>
        typename enable_if_c<pixel_traits<P>::is_unsigned, bool >::type greater_or_equal_to_min (
            const P&
        ) { return true; }
        /*!
            ensures
                - returns true if p is >= min value of T
        !*/

        template <typename T, typename P>
        typename enable_if_c<!pixel_traits<P>::is_unsigned && pixel_traits<T>::is_unsigned, bool >::type greater_or_equal_to_min (
            const P& p
        )
        {
            return p >= 0;
        }

        template <typename T, typename P>
        typename enable_if_c<!pixel_traits<P>::is_unsigned && !pixel_traits<T>::is_unsigned, bool >::type greater_or_equal_to_min (
            const P& p
        )
        {
            return p >= pixel_traits<T>::min();
        }
    // -----------------------------

        template < typename P1, typename P2 >
        typename enable_if_c<pixel_traits<P1>::grayscale && pixel_traits<P2>::grayscale>::type
        assign(P1& dest, const P2& src)
        {
            /*
                The reason for these weird comparison functions is to avoid getting compiler
                warnings about comparing signed types to unsigned and stuff like that.
            */

            if (less_or_equal_to_max<P1>(src))
                if (greater_or_equal_to_min<P1>(src))
                    dest = static_cast<P1>(src);
                else
                    dest = pixel_traits<P1>::min();
            else
                dest = pixel_traits<P1>::max();
        }

    // -----------------------------
    // -----------------------------
    // -----------------------------

        template < typename P1, typename P2 >
        typename enable_if_c<pixel_traits<P1>::rgb && pixel_traits<P2>::rgb>::type
        assign(P1& dest, const P2& src)
        {
            dest.red = src.red;
            dest.green = src.green;
            dest.blue = src.blue;
        }

        template < typename P1, typename P2 >
        typename enable_if_c<pixel_traits<P1>::rgb_alpha && pixel_traits<P2>::rgb_alpha>::type
        assign(P1& dest, const P2& src)
        {
            dest.red = src.red;
            dest.green = src.green;
            dest.blue = src.blue;
            dest.alpha = src.alpha;
        }

        template < typename P1, typename P2 >
        typename enable_if_c<pixel_traits<P1>::hsi && pixel_traits<P2>::hsi>::type
        assign(P1& dest, const P2& src)
        {
            dest.h = src.h;
            dest.s = src.s;
            dest.i = src.i;
        }

    // -----------------------------
        // dest is a grayscale

        template < typename P1, typename P2 >
        typename enable_if_c<pixel_traits<P1>::grayscale && pixel_traits<P2>::rgb>::type
        assign(P1& dest, const P2& src)
        {
            const unsigned int temp = ((static_cast<unsigned int>(src.red) +
                                        static_cast<unsigned int>(src.green) +
                                        static_cast<unsigned int>(src.blue))/3);
            assign_pixel(dest, temp);
        }

        template < typename P1, typename P2 >
        typename enable_if_c<pixel_traits<P1>::grayscale && pixel_traits<P2>::rgb_alpha>::type
        assign(P1& dest, const P2& src)
        {

            const unsigned char avg = static_cast<unsigned char>((static_cast<unsigned int>(src.red) +
                                                                  static_cast<unsigned int>(src.green) +
                                                                  static_cast<unsigned int>(src.blue))/3);

            if (src.alpha == 255)
            {
                assign_pixel(dest, avg);
            }
            else
            {
                // perform this assignment using fixed point arithmetic:
                // dest = src*(alpha/255) + dest*(1 - alpha/255);
                // dest = src*(alpha/255) + dest*1 - dest*(alpha/255);
                // dest = dest*1 + src*(alpha/255) - dest*(alpha/255);
                // dest = dest*1 + (src - dest)*(alpha/255);
                // dest += (src - dest)*(alpha/255);

                int temp = avg;
                // copy dest into dest_copy using assign_pixel to avoid potential
                // warnings about implicit float to int warnings.
                int dest_copy;
                assign_pixel(dest_copy, dest);

                temp -= dest_copy;

                temp *= src.alpha;

                temp /= 255;

                assign_pixel(dest, temp+dest_copy);
            }
        }

        template < typename P1, typename P2 >
        typename enable_if_c<pixel_traits<P1>::grayscale && pixel_traits<P2>::hsi>::type
        assign(P1& dest, const P2& src)
        {
            assign_pixel(dest, src.i);
        }

    // -----------------------------

        struct HSL
        {
            double h;
            double s;
            double l;
        };

        struct COLOUR
        {
            double r;
            double g;
            double b;
        };

        /*
            I found this excellent bit of code for dealing with HSL spaces at
            http://local.wasp.uwa.edu.au/~pbourke/colour/hsl/
        */
        /*
            Calculate HSL from RGB
            Hue is in degrees
            Lightness is between 0 and 1
            Saturation is between 0 and 1
        */
        inline HSL RGB2HSL(COLOUR c1)
        {
            double themin,themax,delta;
            HSL c2;
            using namespace std;

            themin = std::min(c1.r,std::min(c1.g,c1.b));
            themax = std::max(c1.r,std::max(c1.g,c1.b));
            delta = themax - themin;
            c2.l = (themin + themax) / 2;
            c2.s = 0;
            if (c2.l > 0 && c2.l < 1)
                c2.s = delta / (c2.l < 0.5 ? (2*c2.l) : (2-2*c2.l));
            c2.h = 0;
            if (delta > 0) {
                if (themax == c1.r && themax != c1.g)
                    c2.h += (c1.g - c1.b) / delta;
                if (themax == c1.g && themax != c1.b)
                    c2.h += (2 + (c1.b - c1.r) / delta);
                if (themax == c1.b && themax != c1.r)
                    c2.h += (4 + (c1.r - c1.g) / delta);
                c2.h *= 60;
            }
            return(c2);
        }

        /*
            Calculate RGB from HSL, reverse of RGB2HSL()
            Hue is in degrees
            Lightness is between 0 and 1
            Saturation is between 0 and 1
        */
        inline COLOUR HSL2RGB(HSL c1)
        {
            COLOUR c2,sat,ctmp;
            using namespace std;

            if (c1.h < 120) {
                sat.r = (120 - c1.h) / 60.0;
                sat.g = c1.h / 60.0;
                sat.b = 0;
            } else if (c1.h < 240) {
                sat.r = 0;
                sat.g = (240 - c1.h) / 60.0;
                sat.b = (c1.h - 120) / 60.0;
            } else {
                sat.r = (c1.h - 240) / 60.0;
                sat.g = 0;
                sat.b = (360 - c1.h) / 60.0;
            }
            sat.r = std::min(sat.r,1.0);
            sat.g = std::min(sat.g,1.0);
            sat.b = std::min(sat.b,1.0);

            ctmp.r = 2 * c1.s * sat.r + (1 - c1.s);
            ctmp.g = 2 * c1.s * sat.g + (1 - c1.s);
            ctmp.b = 2 * c1.s * sat.b + (1 - c1.s);

            if (c1.l < 0.5) {
                c2.r = c1.l * ctmp.r;
                c2.g = c1.l * ctmp.g;
                c2.b = c1.l * ctmp.b;
            } else {
                c2.r = (1 - c1.l) * ctmp.r + 2 * c1.l - 1;
                c2.g = (1 - c1.l) * ctmp.g + 2 * c1.l - 1;
                c2.b = (1 - c1.l) * ctmp.b + 2 * c1.l - 1;
            }

            return(c2);
        }

    // -----------------------------
        // dest is a color rgb_pixel

        template < typename P1 >
        typename enable_if_c<pixel_traits<P1>::rgb>::type
        assign(P1& dest, const unsigned char& src)
        {
            dest.red = src;
            dest.green = src;
            dest.blue = src;
        }

        template < typename P1, typename P2 >
        typename enable_if_c<pixel_traits<P1>::rgb && pixel_traits<P2>::grayscale>::type
        assign(P1& dest, const P2& src)
        {
            unsigned char p;
            assign_pixel(p, src);
            dest.red = p;
            dest.green = p;
            dest.blue = p;
        }

        template < typename P1, typename P2 >
        typename enable_if_c<pixel_traits<P1>::rgb && pixel_traits<P2>::rgb_alpha>::type
        assign(P1& dest, const P2& src)
        {
            if (src.alpha == 255)
            {
                dest.red = src.red;
                dest.green = src.green;
                dest.blue = src.blue;
            }
            else
            {
                // perform this assignment using fixed point arithmetic:
                // dest = src*(alpha/255) + dest*(1 - alpha/255);
                // dest = src*(alpha/255) + dest*1 - dest*(alpha/255);
                // dest = dest*1 + src*(alpha/255) - dest*(alpha/255);
                // dest = dest*1 + (src - dest)*(alpha/255);
                // dest += (src - dest)*(alpha/255);

                unsigned int temp_r = src.red;
                unsigned int temp_g = src.green;
                unsigned int temp_b = src.blue;

                temp_r -= dest.red;
                temp_g -= dest.green;
                temp_b -= dest.blue;

                temp_r *= src.alpha;
                temp_g *= src.alpha;
                temp_b *= src.alpha;

                temp_r >>= 8;
                temp_g >>= 8;
                temp_b >>= 8;

                dest.red += static_cast<unsigned char>(temp_r&0xFF);
                dest.green += static_cast<unsigned char>(temp_g&0xFF);
                dest.blue += static_cast<unsigned char>(temp_b&0xFF);
            }
        }

        template < typename P1, typename P2 >
        typename enable_if_c<pixel_traits<P1>::rgb && pixel_traits<P2>::hsi>::type
        assign(P1& dest, const P2& src)
        {
            COLOUR c;
            HSL h;
            h.h = src.h;
            h.h = h.h/255.0*360;
            h.s = src.s/255.0;
            h.l = src.i/255.0;
            c = HSL2RGB(h);

            dest.red = static_cast<unsigned char>(c.r*255.0 + 0.5);
            dest.green = static_cast<unsigned char>(c.g*255.0 + 0.5);
            dest.blue = static_cast<unsigned char>(c.b*255.0 + 0.5);
        }

    // -----------------------------
    // dest is a color rgb_alpha_pixel

        template < typename P1 >
        typename enable_if_c<pixel_traits<P1>::rgb_alpha>::type
        assign(P1& dest, const unsigned char& src)
        {
            dest.red = src;
            dest.green = src;
            dest.blue = src;
            dest.alpha = 255;
        }

        template < typename P1, typename P2 >
        typename enable_if_c<pixel_traits<P1>::rgb_alpha && pixel_traits<P2>::grayscale>::type
        assign(P1& dest, const P2& src)
        {
            unsigned char p;
            assign_pixel(p, src);

            dest.red = p;
            dest.green = p;
            dest.blue = p;
            dest.alpha = 255;
        }

        template < typename P1, typename P2 >
        typename enable_if_c<pixel_traits<P1>::rgb_alpha && pixel_traits<P2>::rgb>::type
        assign(P1& dest, const P2& src)
        {
            dest.red = src.red;
            dest.green = src.green;
            dest.blue = src.blue;
            dest.alpha = 255;
        }

        template < typename P1, typename P2 >
        typename enable_if_c<pixel_traits<P1>::rgb_alpha && pixel_traits<P2>::hsi>::type
        assign(P1& dest, const P2& src)
        {
            COLOUR c;
            HSL h;
            h.h = src.h;
            h.h = h.h/255.0*360;
            h.s = src.s/255.0;
            h.l = src.i/255.0;
            c = HSL2RGB(h);

            dest.red = static_cast<unsigned char>(c.r*255.0 + 0.5);
            dest.green = static_cast<unsigned char>(c.g*255.0 + 0.5);
            dest.blue = static_cast<unsigned char>(c.b*255.0 + 0.5);
            dest.alpha = 255;
        }

    // -----------------------------
        // dest is an hsi pixel

        template < typename P1>
        typename enable_if_c<pixel_traits<P1>::hsi>::type
        assign(P1& dest, const unsigned char& src)
        {
            dest.h = 0;
            dest.s = 0;
            dest.i = src;
        }

        template < typename P1, typename P2 >
        typename enable_if_c<pixel_traits<P1>::hsi && pixel_traits<P2>::grayscale>::type
        assign(P1& dest, const P2& src)
        {
            dest.h = 0;
            dest.s = 0;
            assign_pixel(dest.i, src);
        }

        template < typename P1, typename P2 >
        typename enable_if_c<pixel_traits<P1>::hsi && pixel_traits<P2>::rgb>::type
        assign(P1& dest, const P2& src)
        {
            COLOUR c1;
            HSL c2;
            c1.r = src.red/255.0;
            c1.g = src.green/255.0;
            c1.b = src.blue/255.0;
            c2 = RGB2HSL(c1);

            dest.h = static_cast<unsigned char>(c2.h/360.0*255.0 + 0.5);
            dest.s = static_cast<unsigned char>(c2.s*255.0 + 0.5);
            dest.i = static_cast<unsigned char>(c2.l*255.0 + 0.5);
        }

        template < typename P1, typename P2 >
        typename enable_if_c<pixel_traits<P1>::hsi && pixel_traits<P2>::rgb_alpha>::type
        assign(P1& dest, const P2& src)
        {
            rgb_pixel temp;
            // convert target hsi pixel to rgb
            assign_pixel_helpers::assign(temp,dest);

            // now assign the rgb_alpha value to our temp rgb pixel
            assign_pixel_helpers::assign(temp,src);

            // now we can just go assign the new rgb value to the
            // hsi pixel
            assign_pixel_helpers::assign(dest,temp);
        }

    }

    // -----------------------------

    template < typename P1, typename P2 >
    inline void assign_pixel (
        P1& dest,
        const P2& src
    ) { assign_pixel_helpers::assign(dest,src); }

// ----------------------------------------------------------------------------------------

    template <
        typename P,
        typename T
        >
    inline typename enable_if_c<pixel_traits<P>::grayscale>::type assign_pixel_intensity_helper (
        P& dest,
        const T& new_intensity
    )
    {
        assign_pixel(dest, new_intensity);
    }

    template <
        typename P,
        typename T
        >
    inline typename enable_if_c<pixel_traits<P>::grayscale == false&&
                                pixel_traits<P>::has_alpha>::type assign_pixel_intensity_helper (
        P& dest,
        const T& new_intensity
    )
    {
        hsi_pixel p;
        const unsigned long old_alpha = dest.alpha;
        dest.alpha = 255;
        rgb_pixel temp;
        assign_pixel(temp, dest); // put dest into an rgb_pixel to avoid the somewhat complicated assign_pixel(hsi,rgb_alpha).
        assign_pixel(p,temp);
        assign_pixel(p.i, new_intensity);
        assign_pixel(dest,p);
        dest.alpha = old_alpha;
    }

    template <
        typename P,
        typename T
        >
    inline typename enable_if_c<pixel_traits<P>::grayscale == false&&
                                pixel_traits<P>::has_alpha == false>::type assign_pixel_intensity_helper (
        P& dest,
        const T& new_intensity
    )
    {
        hsi_pixel p;
        assign_pixel(p,dest);
        assign_pixel(p.i, new_intensity);
        assign_pixel(dest,p);
    }

    template <
        typename P,
        typename T
        >
    inline void assign_pixel_intensity (
        P& dest,
        const T& new_intensity
    )
    {
        assign_pixel_intensity_helper(dest, new_intensity);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename P
        >
    inline typename enable_if_c<pixel_traits<P>::grayscale, P>::type get_pixel_intensity_helper (
        const P& src
    )
    {
        return src;
    }

    template <
        typename P
        >
    inline typename enable_if_c<pixel_traits<P>::grayscale == false&&
                                pixel_traits<P>::has_alpha,
                                typename pixel_traits<P>::basic_pixel_type>::type get_pixel_intensity_helper (
        const P& src
    )
    {
        P temp = src;
        temp.alpha = 255;
        typename pixel_traits<P>::basic_pixel_type p;
        assign_pixel(p,temp);
        return p;
    }

    template <
        typename P
        >
    inline typename enable_if_c<pixel_traits<P>::grayscale == false&&
                                pixel_traits<P>::has_alpha == false,
                                typename pixel_traits<P>::basic_pixel_type>::type get_pixel_intensity_helper (
        const P& src
    )
    {
        typename pixel_traits<P>::basic_pixel_type p;
        assign_pixel(p,src);
        return p;
    }

    template <
        typename P
        >
    inline typename pixel_traits<P>::basic_pixel_type get_pixel_intensity (
        const P& src
    )
    {
        return get_pixel_intensity_helper(src);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    inline void serialize (
        const rgb_alpha_pixel& item,
        std::ostream& out
    )
    {
        try
        {
            serialize(item.red,out);
            serialize(item.green,out);
            serialize(item.blue,out);
            serialize(item.alpha,out);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while serializing object of type rgb_alpha_pixel");
        }
    }

// ----------------------------------------------------------------------------------------

    inline void deserialize (
        rgb_alpha_pixel& item,
        std::istream& in
    )
    {
        try
        {
            deserialize(item.red,in);
            deserialize(item.green,in);
            deserialize(item.blue,in);
            deserialize(item.alpha,in);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while deserializing object of type rgb_alpha_pixel");
        }
    }

// ----------------------------------------------------------------------------------------

    inline void serialize (
        const rgb_pixel& item,
        std::ostream& out
    )
    {
        try
        {
            serialize(item.red,out);
            serialize(item.green,out);
            serialize(item.blue,out);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while serializing object of type rgb_pixel");
        }
    }

// ----------------------------------------------------------------------------------------

    inline void deserialize (
        rgb_pixel& item,
        std::istream& in
    )
    {
        try
        {
            deserialize(item.red,in);
            deserialize(item.green,in);
            deserialize(item.blue,in);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while deserializing object of type rgb_pixel");
        }
    }

// ----------------------------------------------------------------------------------------

    inline void serialize (
        const bgr_pixel& item,
        std::ostream& out
    )
    {
        try
        {
            serialize(item.blue,out);
            serialize(item.green,out);
            serialize(item.red,out);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while serializing object of type bgr_pixel");
        }
    }

// ----------------------------------------------------------------------------------------

    inline void deserialize (
        bgr_pixel& item,
        std::istream& in
    )
    {
        try
        {
            deserialize(item.blue,in);
            deserialize(item.green,in);
            deserialize(item.red,in);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while deserializing object of type bgr_pixel");
        }
    }

// ----------------------------------------------------------------------------------------

    inline void serialize (
        const hsi_pixel& item,
        std::ostream& out
    )
    {
        try
        {
            serialize(item.h,out);
            serialize(item.s,out);
            serialize(item.i,out);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while serializing object of type hsi_pixel");
        }
    }

// ----------------------------------------------------------------------------------------

    inline void deserialize (
        hsi_pixel& item,
        std::istream& in
    )
    {
        try
        {
            deserialize(item.h,in);
            deserialize(item.s,in);
            deserialize(item.i,in);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while deserializing object of type hsi_pixel");
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_PIXEl_


dlib C++ Library - jpeg_loader_abstract.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net), Nils Labugt
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_JPEG_IMPORT_ABSTRACT
#ifdef DLIB_JPEG_IMPORT_ABSTRACT

#include "image_loader_abstract.h"
#include "../algs.h"
#include "../pixel.h"
#include "../dir_nav.h"
#include "../image_processing/generic_image.h"

namespace dlib
{

    class jpeg_loader : noncopyable
    {
        /*!
            INITIAL VALUE
                Defined by the constructors

            WHAT THIS OBJECT REPRESENTS
                This object represents a class capable of loading JPEG image files.
                Once an instance of it is created to contain a JPEG file from
                disk you can obtain the image stored in it via get_image().
        !*/

    public:

        jpeg_loader(
            const char* filename
        );
        /*!
            ensures
                - loads the JPEG file with the given file name into this object
            throws
                - std::bad_alloc
                - image_load_error
                  This exception is thrown if there is some error that prevents
                  us from loading the given JPEG file.
        !*/

        jpeg_loader(
            const std::string& filename
        );
        /*!
            ensures
                - loads the JPEG file with the given file name into this object
            throws
                - std::bad_alloc
                - image_load_error
                  This exception is thrown if there is some error that prevents
                  us from loading the given JPEG file.
        !*/

        jpeg_loader(
            const dlib::file& f
        );
        /*!
            ensures
                - loads the JPEG file with the given file name into this object
            throws
                - std::bad_alloc
                - image_load_error
                  This exception is thrown if there is some error that prevents
                  us from loading the given JPEG file.
        !*/

        ~jpeg_loader(
        );
        /*!
            ensures
                - all resources associated with *this has been released
        !*/

        bool is_gray(
        ) const;
        /*!
            ensures
                - if (this object contains a grayscale image) then
                    - returns true
                - else
                    - returns false
        !*/

        bool is_rgb(
        ) const;
        /*!
            ensures
                - if (this object contains a 3 channel RGB image) then
                    - returns true
                - else
                    - returns false
        !*/

        template<
            typename image_type
            >
        void get_image(
            image_type& img
        ) const;
        /*!
            requires
                - image_type == an image object that implements the interface defined in
                  dlib/image_processing/generic_image.h
            ensures
                - loads the JPEG image stored in this object into img
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    void load_jpeg (
        image_type& image,
        const std::string& file_name
    );
    /*!
        requires
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
        ensures
            - performs: jpeg_loader(file_name).get_image(image);
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_JPEG_IMPORT_ABSTRACT


dlib C++ Library - image_loader_abstract.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_IMAGE_LOADEr_ABSTRACT_
#ifdef DLIB_IMAGE_LOADEr_ABSTRACT_

#include <iosfwd>
#include "../algs.h"
#include "../pixel.h"
#include "../image_processing/generic_image.h"

namespace dlib
{
    class image_load_error : public dlib::error
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is an exception used to indicate a failure to load an image.
                Its type member variable will be set to EIMAGE_LOAD.
        !*/
    };

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    void load_bmp (
        image_type& image,
        std::istream& in
    );
    /*!
        requires
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
        ensures
            - #image == the image of the MS Windows BMP file that was available
              in the input stream in.
            - #image[0][0] will be the upper left corner of the image
            - #image[image.nr()-1][image.nc()-1] will be the lower right
              corner of the image
            - Performs any color space conversion necessary to convert the
              BMP image data into the pixel type used by the given image
              object.
        throws
            - image_load_error
                This exception is thrown if there is an error that prevents us
                from loading the image.  If this exception is thrown then
                #image will have an initial value for its type.
            - std::bad_alloc
                If this exception is thrown then #image will have an initial
                value for its type.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    void load_bmp (
        image_type& image,
        const std::string& file_name
    );
    /*!
        requires
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
        ensures
            - opens the file indicated by file_name with an input file stream named fin
              and performs:
              load_bmp(image,fin);
    !*/

// ----------------------------------------------------------------------------------------

    /*!
        dlib dng file format:
            This is a file format I created for this library.  It is a lossless
            compressed image format that is similar to the PNG format but uses
            the dlib PPM compression algorithms instead of the DEFLATE algorithm.
    !*/

    template <
        typename image_type
        >
    void load_dng (
        image_type& image,
        std::istream& in
    );
    /*!
        requires
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
        ensures
            - #image == the image of the dlib dng file that was available
              in the input stream in.
            - #image[0][0] will be the upper left corner of the image
            - #image[image.nr()-1][image.nc()-1] will be the lower right
              corner of the image
            - Performs any color space conversion necessary to convert the
              dng image data into the pixel type used by the given image
              object.
        throws
            - image_load_error
                This exception is thrown if there is an error that prevents us
                from loading the image.  If this exception is thrown then
                #image will have an initial value for its type.
            - std::bad_alloc
                If this exception is thrown then #image will have an initial
                value for its type.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    void load_dng (
        image_type& image,
        const std::string& file_name
    );
    /*!
        requires
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
        ensures
            - opens the file indicated by file_name with an input file stream named fin
              and performs:
              load_dng(image,fin);
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_IMAGE_LOADEr_ABSTRACT_


dlib C++ Library - load_image_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net), Nils Labugt
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_LOAd_IMAGE_ABSTRACT_
#ifdef DLIB_LOAd_IMAGE_ABSTRACT_

#include "load_image_abstract.h"
#include "../string.h"
#include "../image_processing/generic_image.h"

namespace dlib
{
    template <typename image_type>
    void load_image (
        image_type& image,
        const std::string& file_name
    );
    /*!
        requires
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
        ensures
            - This function looks at the file extensions and file headers to try and figure
              out what kind of image format is inside the given file.  It then calls one of
              load_png(), load_jpeg(), load_bmp(), or load_dng() as appropriate and stores
              the resulting image into #image.
        throws
            - image_load_error
                This exception is thrown if there is some error that prevents
                us from loading the given image file.
    !*/

}

#endif // DLIB_LOAd_IMAGE_ABSTRACT_


dlib C++ Library - png_loader_abstract.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net), Nils Labugt
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_PNG_IMPORT_ABSTRACT
#ifdef DLIB_PNG_IMPORT_ABSTRACT

#include "image_loader_abstract.h"
#include "../algs.h"
#include "../pixel.h"
#include "../dir_nav.h"
#include "../image_processing/generic_image.h"

namespace dlib
{

    class png_loader : noncopyable
    {
        /*!
            INITIAL VALUE
                Defined by the constructors

            WHAT THIS OBJECT REPRESENTS
                This object represents a class capable of loading PNG image files.
                Once an instance of it is created to contain a PNG file from
                disk you can obtain the image stored in it via get_image().
        !*/

    public:

        png_loader(
            const char* filename
        );
        /*!
            ensures
                - loads the PNG file with the given file name into this object
            throws
                - std::bad_alloc
                - image_load_error
                  This exception is thrown if there is some error that prevents
                  us from loading the given PNG file.
        !*/

        png_loader(
            const std::string& filename
        );
        /*!
            ensures
                - loads the PNG file with the given file name into this object
            throws
                - std::bad_alloc
                - image_load_error
                  This exception is thrown if there is some error that prevents
                  us from loading the given PNG file.
        !*/

        png_loader(
            const dlib::file& f
        );
        /*!
            ensures
                - loads the PNG file with the given file name into this object
            throws
                - std::bad_alloc
                - image_load_error
                  This exception is thrown if there is some error that prevents
                  us from loading the given PNG file.
        !*/

        ~png_loader(
        );
        /*!
            ensures
                - all resources associated with *this has been released
        !*/

        bool is_gray(
        ) const;
        /*!
            ensures
                - if (this object contains a grayscale image without an alpha channel) then
                    - returns true
                - else
                    - returns false
        !*/

        bool is_graya(
        ) const;
        /*!
            ensures
                - if (this object contains a grayscale image with an alpha channel) then
                    - returns true
                - else
                    - returns false
        !*/

        bool is_rgb(
        ) const;
        /*!
            ensures
                - if (this object contains a 3 channel RGB image) then
                    - returns true
                - else
                    - returns false
        !*/

        bool is_rgba(
        ) const;
        /*!
            ensures
                - if (this object contains a 4 channel RGB alpha image) then
                    - returns true
                - else
                    - returns false
        !*/

        unsigned int bit_depth (
        ) const;
        /*!
            ensures
                - returns the number of bits per channel in the image contained by this
                  object.  The possible values are 8 or 16.
        !*/

        template<
            typename image_type
            >
        void get_image(
            image_type& img
        ) const;
        /*!
            requires
                - image_type == an image object that implements the interface defined in
                  dlib/image_processing/generic_image.h
            ensures
                - loads the PNG image stored in this object into img
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    void load_png (
        image_type& image,
        const std::string& file_name
    );
    /*!
        requires
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
        ensures
            - performs: png_loader(file_name).get_image(image);
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_PNG_IMPORT_ABSTRACT


dlib C++ Library - image_saver_abstract.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_IMAGE_SAVEr_ABSTRACT_
#ifdef DLIB_IMAGE_SAVEr_ABSTRACT_

#include <iosfwd>
#include "../algs.h"
#include "../pixel.h"
#include "../image_processing/generic_image.h"

namespace dlib
{
    class image_save_error : public dlib::error
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is an exception used to indicate a failure to save an image.
                Its type member variable will be set to EIMAGE_SAVE.
        !*/
    };

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    void save_bmp (
        const image_type& image,
        std::ostream& out
    );
    /*!
        requires
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h or any kind of matrix expression.
        ensures
            - writes the image to the out stream in the Microsoft Windows BMP format.
            - image[0][0] will be in the upper left corner of the image.
            - image[image.nr()-1][image.nc()-1] will be in the lower right
              corner of the image.
            - This routine can save images containing any type of pixel. However, it
              will convert all color pixels into rgb_pixel and grayscale pixels into
              uint8 type before saving to disk.
        throws
            - image_save_error
                This exception is thrown if there is an error that prevents us
                from saving the image.
            - std::bad_alloc
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    void save_bmp (
        const image_type& image,
        const std::string& file_name
    );
    /*!
        requires
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h or any kind of matrix expression.
        ensures
            - opens the file indicated by file_name with an output file stream named fout
              and performs:
              save_bmp(image,fout);
    !*/

// ----------------------------------------------------------------------------------------

    /*!
        dlib dng file format:
            This is a file format I created for this library.  It is a lossless
            compressed image format that is similar to the PNG format but uses
            the dlib PPM compression algorithms instead of the DEFLATE algorithm.
    !*/

    template <
        typename image_type
        >
    void save_dng (
        const image_type& image,
        std::ostream& out
    );
    /*!
        requires
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h or any kind of matrix expression.
        ensures
            - writes the image to the out stream in the dlib dng format.
            - image[0][0] will be in the upper left corner of the image.
            - image[image.nr()-1][image.nc()-1] will be in the lower right
              corner of the image.
            - This routine can save images containing any type of pixel.  However, the DNG
              format can natively store only the following pixel types: rgb_pixel,
              hsi_pixel, rgb_alpha_pixel, uint8, uint16, float, and double.
              All other pixel types will be converted into one of these types as
              appropriate before being saved to disk.
        throws
            - image_save_error
                This exception is thrown if there is an error that prevents us
                from saving the image.
            - std::bad_alloc
    !*/

// ----------------------------------------------------------------------------------------

    template <typename image_type>
    void save_dng (
        const image_type& image,
        const std::string& file_name
    );
    /*!
        requires
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h or any kind of matrix expression.
        ensures
            - opens the file indicated by file_name with an output file stream named fout
              and performs:
              save_dng(image,fout);
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_IMAGE_SAVEr_ABSTRACT_


dlib C++ Library - save_jpeg_abstract.h

// Copyright (C) 2014  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SAVE_JPEG_ABSTRACT_Hh_
#ifdef DLIB_SAVE_JPEG_ABSTRACT_Hh_

#include "../image_processing/generic_image.h"
#include "../pixel.h"
#include <string>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    void save_jpeg (
        const image_type& img,
        const std::string& filename,
        int quality = 75
    );
    /*!
        requires
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h or a matrix expression
            - image.size() != 0
            - 0 <= quality <= 100
        ensures
            - writes the image to the file indicated by file_name in the JPEG format.
            - image[0][0] will be in the upper left corner of the image.
            - image[image.nr()-1][image.nc()-1] will be in the lower right corner of the
              image.
            - This routine can save images containing any type of pixel.  However,
              save_jpeg() can only natively store rgb_pixel and uint8 pixel types.  All
              other pixel types will be converted into one of these types as appropriate
              before being saved to disk.
            - The quality value determines how lossy the compression is.  Larger quality
              values result in larger output images but the images will look better.
        throws
            - image_save_error
                This exception is thrown if there is an error that prevents us from saving
                the image.
            - std::bad_alloc
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SAVE_JPEG_ABSTRACT_Hh_


dlib C++ Library - save_png_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SAVE_PnG_ABSTRACT_
#ifdef DLIB_SAVE_PnG_ABSTRACT_

#include "../pixel.h"
#include "../image_processing/generic_image.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    void save_png (
        const image_type& image,
        const std::string& file_name
    );
    /*!
        requires
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h or a matrix expression
            - image.size() != 0
        ensures
            - writes the image to the file indicated by file_name in the PNG (Portable Network Graphics)
              format.
            - image[0][0] will be in the upper left corner of the image.
            - image[image.nr()-1][image.nc()-1] will be in the lower right
              corner of the image.
            - This routine can save images containing any type of pixel.  However, save_png() can
              only natively store the following pixel types: rgb_pixel, rgb_alpha_pixel, uint8,
              and uint16.  All other pixel types will be converted into one of these types as
              appropriate before being saved to disk.
        throws
            - image_save_error
                This exception is thrown if there is an error that prevents us from saving
                the image.
            - std::bad_alloc
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SAVE_PnG_ABSTRACT_


dlib C++ Library - correlation_tracker_abstract.h

// Copyright (C) 2015  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_CORRELATION_TrACKER_ABSTRACT_H_
#ifdef DLIB_CORRELATION_TrACKER_ABSTRACT_H_

#include "../geometry/drectangle_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class correlation_tracker
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is a tool for tracking moving objects in a video stream.  You give it
                the bounding box of an object in the first frame and it attempts to track the
                object in the box from frame to frame.

                This tool is an implementation of the method described in the following paper:
                    Danelljan, Martin, et al. "Accurate scale estimation for robust visual
                    tracking." Proceedings of the British Machine Vision Conference BMVC. 2014.
        !*/

    public:

        correlation_tracker (
        );
        /*!
            ensures
                - #get_position().is_empty() == true
        !*/

        template <
            typename image_type
            >
        void start_track (
            const image_type& img,
            const drectangle& p
        );
        /*!
            requires
                - image_type == an image object that implements the interface defined in
                  dlib/image_processing/generic_image.h
                - p.is_empty() == false
            ensures
                - This object will start tracking the thing inside the bounding box in the
                  given image.  That is, if you call update() with subsequent video frames
                  then it will try to keep track of the position of the object inside p.
                - #get_position() == p
        !*/

        drectangle get_position (
        ) const;
        /*!
            ensures
                - returns the predicted position of the object under track.
        !*/

        template <
            typename image_type
            >
        double update (
            const image_type& img,
            const drectangle& guess
        );
        /*!
            requires
                - image_type == an image object that implements the interface defined in
                  dlib/image_processing/generic_image.h
                - get_position().is_empty() == false
                  (i.e. you must have started tracking by calling start_track())
            ensures
                - When searching for the object in img, we search in the area around the
                  provided guess.
                - #get_position() == the new predicted location of the object in img.  This
                  location will be a copy of guess that has been translated and scaled
                  appropriately based on the content of img so that it, hopefully, bounds
                  the object in img.
                - Returns the peak to side-lobe ratio.  This is a number that measures how
                  confident the tracker is that the object is inside #get_position().
                  Larger values indicate higher confidence.
        !*/

        template <
            typename image_type
            >
        double update (
            const image_type& img
        );
        /*!
            requires
                - image_type == an image object that implements the interface defined in
                  dlib/image_processing/generic_image.h
                - get_position().is_empty() == false
                  (i.e. you must have started tracking by calling start_track())
            ensures
                - performs: return update(img, get_position())
        !*/

    };
}

#endif // DLIB_CORRELATION_TrACKER_ABSTRACT_H_


dlib C++ Library - scan_fhog_pyramid_abstract.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SCAN_fHOG_PYRAMID_ABSTRACT_Hh_
#ifdef DLIB_SCAN_fHOG_PYRAMID_ABSTRACT_Hh_

#include <vector>
#include "../image_transforms/fhog_abstract.h"
#include "object_detector_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename feature_extractor_type
        >
    matrix<unsigned char> draw_fhog (
        const object_detector<scan_fhog_pyramid<Pyramid_type,feature_extractor_type> >& detector,
        const unsigned long weight_index = 0,
        const long cell_draw_size = 15
    );
    /*!
        requires
            - cell_draw_size > 0
            - weight_index < detector.num_detectors()
            - detector.get_w(weight_index).size() >= detector.get_scanner().get_num_dimensions()
              (i.e. the detector must have been populated with a HOG filter)
        ensures
            - Converts the HOG filters in the given detector (specifically, the filters in
              detector.get_w(weight_index)) into an image suitable for display on the
              screen.  In particular, we draw all the HOG cells into a grayscale image in a
              way that shows the magnitude and orientation of the gradient energy in each
              cell.  The resulting image is then returned.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename feature_extractor_type
        >
    unsigned long num_separable_filters (
        const object_detector<scan_fhog_pyramid<Pyramid_type,feature_extractor_type> >& detector,
        const unsigned long weight_index = 0
    );
    /*!
        requires
            - weight_index < detector.num_detectors()
            - detector.get_w(weight_index).size() >= detector.get_scanner().get_num_dimensions()
              (i.e. the detector must have been populated with a HOG filter)
        ensures
            - Returns the number of separable filters necessary to represent the HOG
              filters in the given detector's weight_index'th filter.  This is the filter
              defined by detector.get_w(weight_index).
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename feature_extractor_type
        >
    object_detector<scan_fhog_pyramid<Pyramid_type,feature_extractor_type> > threshold_filter_singular_values (
        const object_detector<scan_fhog_pyramid<Pyramid_type,feature_extractor_type> >& detector,
        double thresh,
        const unsigned long weight_index = 0
    );
    /*!
        requires
            - thresh >= 0
            - weight_index < detector.num_detectors()
            - detector.get_w(weight_index).size() >= detector.get_scanner().get_num_dimensions()
              (i.e. the detector must have been populated with a HOG filter)
        ensures
            - Removes all components of the filters in the given detector that have
              singular values that are smaller than the given threshold.  Therefore, this
              function allows you to control how many separable filters are in a detector.
              In particular, as thresh gets larger the quantity
              num_separable_filters(threshold_filter_singular_values(detector,thresh,weight_index),weight_index)
              will generally get smaller and therefore give a faster running detector.
              However, note that at some point a large enough thresh will drop too much
              information from the filters and their accuracy will suffer.
            - returns the updated detector
    !*/

// ----------------------------------------------------------------------------------------

    class default_fhog_feature_extractor
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                The scan_fhog_pyramid object defined below is primarily meant to be used
                with the feature extraction technique implemented by extract_fhog_features().
                This technique can generally be understood as taking an input image and
                outputting a multi-planed output image of floating point numbers that
                somehow describe the image contents.  Since there are many ways to define
                how this feature mapping is performed, the scan_fhog_pyramid allows you to
                replace the extract_fhog_features() method with a customized method of your
                choosing.  To do this you implement a class with the same interface as
                default_fhog_feature_extractor.

                Therefore, the point of default_fhog_feature_extractor is two fold.  First,
                it provides the default FHOG feature extraction method used by scan_fhog_pyramid.
                Second, it serves to document the interface you need to implement to define
                your own custom HOG style feature extraction.
        !*/

    public:

        rectangle image_to_feats (
            const rectangle& rect,
            int cell_size,
            int filter_rows_padding,
            int filter_cols_padding
        ) const { return image_to_fhog(rect, cell_size, filter_rows_padding, filter_cols_padding); }
        /*!
            requires
                - cell_size > 0
                - filter_rows_padding > 0
                - filter_cols_padding > 0
            ensures
                - Maps a rectangle from the coordinates in an input image to the corresponding
                  area in the output feature image.
        !*/

        rectangle feats_to_image (
            const rectangle& rect,
            int cell_size,
            int filter_rows_padding,
            int filter_cols_padding
        ) const { return fhog_to_image(rect, cell_size, filter_rows_padding, filter_cols_padding); }
        /*!
            requires
                - cell_size > 0
                - filter_rows_padding > 0
                - filter_cols_padding > 0
            ensures
                - Maps a rectangle from the coordinates of the hog feature image back to
                  the input image.
                - Mapping from feature space to image space is an invertible
                  transformation.  That is, for any rectangle R we have:
                    R == image_to_feats(feats_to_image(R,cell_size,filter_rows_padding,filter_cols_padding),
                                                         cell_size,filter_rows_padding,filter_cols_padding).
        !*/

        template <
            typename image_type
            >
        void operator()(
            const image_type& img,
            dlib::array<array2d<float> >& hog,
            int cell_size,
            int filter_rows_padding,
            int filter_cols_padding
        ) const { extract_fhog_features(img,hog,cell_size,filter_rows_padding,filter_cols_padding); }
        /*!
            requires
                - image_type == is an implementation of array2d/array2d_kernel_abstract.h
                - img contains some kind of pixel type.
                  (i.e. pixel_traits<typename image_type::type> is defined)
            ensures
                - Extracts FHOG features by calling extract_fhog_features().  The results are
                  stored into #hog.  Note that if you are implementing your own feature extractor you can
                  pretty much do whatever you want in terms of feature extraction so long as the following
                  conditions are met:
                    - #hog.size() == get_num_planes()
                    - Each image plane in of #hog has the same dimensions.
                    - for all valid i, r, and c:
                        - #hog[i][r][c] == a feature value describing the image content centered at the
                          following pixel location in img:
                            feats_to_image(point(c,r),cell_size,filter_rows_padding,filter_cols_padding)
        !*/

        inline unsigned long get_num_planes (
        ) const { return 31; }
        /*!
            ensures
                - returns the number of planes in the hog image output by the operator()
                  method.
        !*/
    };

    inline void serialize   (const default_fhog_feature_extractor&, std::ostream&) {}
    inline void deserialize (default_fhog_feature_extractor&, std::istream&) {}
    /*!
        Provides serialization support.  Note that there is no state in the default hog
        feature extractor so these functions do nothing.  But if you define a custom
        feature extractor then make sure you remember to serialize any state in your
        feature extractor.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename Feature_extractor_type = default_fhog_feature_extractor
        >
    class scan_fhog_pyramid : noncopyable
    {
        /*!
            REQUIREMENTS ON Pyramid_type
                - Must be one of the pyramid_down objects defined in
                  dlib/image_transforms/image_pyramid_abstract.h or an object with a
                  compatible interface

            REQUIREMENTS ON Feature_extractor_type
                - Must be a type with an interface compatible with the
                  default_fhog_feature_extractor.

            INITIAL VALUE
                - get_padding()   == 1
                - get_cell_size() == 8
                - get_detection_window_width()   == 64
                - get_detection_window_height()  == 64
                - get_max_pyramid_levels()       == 1000
                - get_min_pyramid_layer_width()  == 64
                - get_min_pyramid_layer_height() == 64
                - get_nuclear_norm_regularization_strength() == 0

            WHAT THIS OBJECT REPRESENTS
                This object is a tool for running a fixed sized sliding window classifier
                over an image pyramid.  In particular,  it slides a linear classifier over
                a HOG pyramid as discussed in the paper:
                    Histograms of Oriented Gradients for Human Detection by Navneet Dalal
                    and Bill Triggs, CVPR 2005
                However, we augment the method slightly to use the version of HOG features
                from:
                    Object Detection with Discriminatively Trained Part Based Models by
                    P. Felzenszwalb, R. Girshick, D. McAllester, D. Ramanan
                    IEEE Transactions on Pattern Analysis and Machine Intelligence, Vol. 32, No. 9, Sep. 2010
                Since these HOG features have been shown to give superior performance.

            THREAD SAFETY
                Concurrent access to an instance of this object is not safe and should be
                protected by a mutex lock except for the case where you are copying the
                configuration (via copy_configuration()) of a scan_fhog_pyramid object to
                many other threads.  In this case, it is safe to copy the configuration of
                a shared object so long as no other operations are performed on it.
        !*/

    public:
        typedef matrix<double,0,1> feature_vector_type;
        typedef Pyramid_type pyramid_type;
        typedef Feature_extractor_type feature_extractor_type;

        scan_fhog_pyramid (
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        explicit scan_fhog_pyramid (
            const feature_extractor_type& fe
        );
        /*!
            ensures
                - this object is properly initialized
                - #get_feature_extractor() == fe
        !*/

        template <
            typename image_type
            >
        void load (
            const image_type& img
        );
        /*!
            requires
                - image_type == is an implementation of array2d/array2d_kernel_abstract.h
                - img contains some kind of pixel type.
                  (i.e. pixel_traits<typename image_type::type> is defined)
            ensures
                - #is_loaded_with_image() == true
                - This object is ready to run a classifier over img to detect object
                  locations.  Call detect() to do this.
        !*/

        const feature_extractor_type& get_feature_extractor(
        ) const;
        /*!
            ensures
                - returns a const reference to the feature extractor used by this object.
        !*/

        bool is_loaded_with_image (
        ) const;
        /*!
            ensures
                - returns true if this object has been loaded with an image to process and
                  false otherwise.
        !*/

        void copy_configuration (
            const scan_fhog_pyramid& item
        );
        /*!
            ensures
                - Copies all the state information of item into *this, except for state
                  information populated by load().  More precisely, given two scan_fhog_pyramid
                  objects S1 and S2, the following sequence of instructions should always
                  result in both of them having the exact same state:
                    S2.copy_configuration(S1);
                    S1.load(img);
                    S2.load(img);
        !*/

        void set_detection_window_size (
            unsigned long window_width,
            unsigned long window_height
        );
        /*!
            requires
                - window_width > 0
                - window_height > 0
            ensures
                - When detect() is called, this object scans a window that is of the given
                  width and height (in pixels) over each layer in an image pyramid.  This
                  means that the rectangle detections which come out of detect() will have
                  a width to height ratio approximately equal to window_width/window_height
                  and will be approximately window_width*window_height pixels in area or
                  larger.  Therefore, the smallest object that can be detected is roughly
                  window_width by window_height pixels in size.
                - #get_detection_window_width() == window_width
                - #get_detection_window_height() == window_height
                - Since we use a HOG feature representation, the detection procedure works
                  as follows:
                    Step 1. Make an image pyramid.
                    Step 2. Convert each layer of the image pyramid into a multi-planed HOG "image".
                    (the number of bands is given by get_feature_extractor().get_num_planes())
                    Step 3. Scan a linear classifier over each HOG image in the pyramid.
                  Moreover, the HOG features quantize the input image into a grid of cells,
                  each cell being get_cell_size() by get_cell_size() pixels in size.  So
                  when we scan the object detector over the pyramid we are scanning an
                  appropriately sized window over these smaller quantized HOG features.  In
                  particular, the size of the window we scan over the HOG feature pyramid
                  is #get_fhog_window_width() by #get_fhog_window_height() HOG cells in
                  size.
                - #is_loaded_with_image() == false
        !*/

        unsigned long get_detection_window_width (
        ) const;
        /*!
            ensures
                - returns the width, in pixels, of the detection window that is scanned
                  over the image when detect() is called.
        !*/

        inline unsigned long get_detection_window_height (
        ) const;
        /*!
            ensures
                - returns the height, in pixels, of the detection window that is scanned
                  over the image when detect() is called.
        !*/

        unsigned long get_fhog_window_width (
        ) const;
        /*!
            ensures
                - Returns the width of the HOG scanning window in terms of HOG cell blocks.
                  Note that this is a function of get_detection_window_width(), get_cell_size(),
                  and get_padding() and is therefore not something you set directly.
                - #get_fhog_window_width() is approximately equal to the number of HOG cells
                  that fit into get_detection_window_width() pixels plus 2*get_padding()
                  since we include additional padding around each window to add context.
        !*/

        unsigned long get_fhog_window_height (
        ) const;
        /*!
            ensures
                - Returns the height of the HOG scanning window in terms of HOG cell blocks.
                  Note that this is a function of get_detection_window_height(), get_cell_size(),
                  and get_padding() and is therefore not something you set directly.
                - #get_fhog_window_height() is approximately equal to the number of HOG cells
                  that fit into get_detection_window_height() pixels plus 2*get_padding()
                  since we include additional padding around each window to add context.
        !*/

        void set_padding (
            unsigned long new_padding
        );
        /*!
            ensures
                - #get_padding() == new_padding
                - #is_loaded_with_image() == false
        !*/

        unsigned long get_padding (
        ) const;
        /*!
            ensures
                - The HOG windows scanned over the HOG pyramid can include additional HOG
                  cells outside the detection window.  This can help add context and
                  improve detection accuracy.  This function returns the number of extra
                  HOG cells added onto the border of the HOG windows which are scanned by
                  detect().
        !*/

        unsigned long get_cell_size (
        ) const;
        /*!
            ensures
                - Returns the size of the HOG cells.  Each HOG cell is square and contains
                  get_cell_size()*get_cell_size() pixels.
        !*/

        void set_cell_size (
            unsigned long new_cell_size
        );
        /*!
            requires
                - new_cell_size > 0
            ensures
                - #get_cell_size() == new_cell_size
                - #is_loaded_with_image() == false
        !*/

        inline long get_num_dimensions (
        ) const;
        /*!
            ensures
                - returns get_fhog_window_width()*get_fhog_window_height()*get_feature_extractor().get_num_planes()
                  (i.e. The number of features is equal to the size of the HOG window times
                  the number of planes output by the feature extractor. )
        !*/

        inline unsigned long get_num_detection_templates (
        ) const { return 1; }
        /*!
            ensures
                - returns 1.  Note that this function is here only for compatibility with
                  the scan_image_pyramid object.  Notionally, its return value indicates
                  that a scan_fhog_pyramid object is always ready to detect objects once
                  an image has been loaded.
        !*/

        inline unsigned long get_num_movable_components_per_detection_template (
        ) const { return 0; }
        /*!
            ensures
                - returns 0.  Note that this function is here only for compatibility with
                  the scan_image_pyramid object.  Its return value means that this object
                  does not support using movable part models.
        !*/

        unsigned long get_max_pyramid_levels (
        ) const;
        /*!
            ensures
                - returns the maximum number of image pyramid levels this object will use.
                  Note that #get_max_pyramid_levels() == 1 indicates that no image pyramid
                  will be used at all.  That is, only the original image will be processed
                  and no lower scale versions will be created.
        !*/

        void set_max_pyramid_levels (
            unsigned long max_levels
        );
        /*!
            requires
                - max_levels > 0
            ensures
                - #get_max_pyramid_levels() == max_levels
        !*/

        void set_min_pyramid_layer_size (
            unsigned long width,
            unsigned long height
        );
        /*!
            requires
                - width > 0
                - height > 0
            ensures
                - #get_min_pyramid_layer_width() == width
                - #get_min_pyramid_layer_height() == height
        !*/

        inline unsigned long get_min_pyramid_layer_width (
        ) const;
        /*!
            ensures
                - returns the smallest allowable width of an image in the image pyramid.
                  All pyramids will always include the original input image, however, no
                  pyramid levels will be created which have a width smaller than the
                  value returned by this function.
        !*/

        inline unsigned long get_min_pyramid_layer_height (
        ) const;
        /*!
            ensures
                - returns the smallest allowable height of an image in the image pyramid.
                  All pyramids will always include the original input image, however, no
                  pyramid levels will be created which have a height smaller than the
                  value returned by this function.
        !*/

        fhog_filterbank build_fhog_filterbank (
            const feature_vector_type& weights
        ) const;
        /*!
            requires
                - weights.size() >= get_num_dimensions()
            ensures
                - Creates and then returns a fhog_filterbank object FB such that:
                    - FB.get_num_dimensions() == get_num_dimensions()
                    - FB.get_filters() == the values in weights unpacked into get_feature_extractor().get_num_planes() filters.
                    - FB.num_separable_filters() == the number of separable filters necessary to
                      represent all the filters in FB.get_filters().
        !*/

        class fhog_filterbank
        {
            /*!
                WHAT THIS OBJECT REPRESENTS
                    This object represents a HOG filter bank.  That is, the classifier that is
                    slid over a HOG pyramid is a set of get_feature_extractor().get_num_planes()
                    linear filters, each get_fhog_window_width() rows by get_fhog_window_height()
                    columns in size.  This object contains that set of filters.
            !*/

        public:
            long get_num_dimensions(
            ) const;
            /*!
                ensures
                    - Returns the total number of values in the filters.
            !*/

            const std::vector<matrix<float> >& get_filters(
            ) const;
            /*!
                ensures
                    - returns the set of HOG filters in this object.
            !*/

            unsigned long num_separable_filters(
            ) const;
            /*!
                ensures
                    - returns the number of separable filters necessary to represent all
                      the filters in get_filters().
            !*/
        };

        void detect (
            const fhog_filterbank& w,
            std::vector<std::pair<double, rectangle> >& dets,
            const double thresh
        ) const;
        /*!
            requires
                - w.get_num_dimensions() == get_num_dimensions()
                - is_loaded_with_image() == true
            ensures
                - Scans the HOG filter defined by w over the HOG pyramid that was populated
                  by the last call to load() and stores all object detections into #dets.
                - for all valid i:
                    - #dets[i].second == The object box which produced this detection.  This rectangle gives
                      the location of the detection.  Note that the rectangle will have been converted back into
                      the original image input space.  That is, if this detection was made at a low level in the
                      image pyramid then the object box will have been automatically mapped up the pyramid layers
                      to the original image space.  Or in other words, if you plot #dets[i].second on top of the
                      image given to load() it will show up in the right place.
                    - #dets[i].first == The score for this detection.  This value is equal to dot(w, feature vector
                      for this sliding window location).
                    - #dets[i].first >= thresh
                - #dets will be sorted in descending order. (i.e.  #dets[i].first >= #dets[j].first for all i, and j>i)
                - Elements of w beyond index get_num_dimensions()-1 are ignored.  I.e. only the first
                  get_num_dimensions() are used.
                - Note that no form of non-max suppression is performed.  If a window has a score >= thresh
                  then it is reported in #dets.
        !*/

        void detect (
            const feature_vector_type& w,
            std::vector<std::pair<double, rectangle> >& dets,
            const double thresh
        ) const;
        /*!
            requires
                - w.size() >= get_num_dimensions()
                - is_loaded_with_image() == true
            ensures
                - performs: detect(build_fhog_filterbank(w), dets, thresh)
        !*/

        void get_feature_vector (
            const full_object_detection& obj,
            feature_vector_type& psi
        ) const;
        /*!
            requires
                - obj.num_parts() == 0
                - is_loaded_with_image() == true
                - psi.size() >= get_num_dimensions()
                  (i.e. psi must have preallocated its memory before this function is called)
            ensures
                - This function allows you to determine the feature vector used for an
                  object detection output from detect().  Note that this vector is
                  added to psi.  Note also that you can use get_full_object_detection() to
                  convert a rectangle from detect() into the needed full_object_detection.
                - The dimensionality of the vector added to psi is get_num_dimensions().  This
                  means that elements of psi after psi(get_num_dimensions()-1) are not modified.
                - Since scan_fhog_pyramid only searches a limited set of object locations,
                  not all possible rectangles can be output by detect().  So in the case
                  where obj.get_rect() could not arise from a call to detect(), this
                  function will map obj.get_rect() to the nearest possible rectangle and
                  then add the feature vector for the mapped rectangle into #psi.
                - get_best_matching_rect(obj.get_rect()) == the rectangle obj.get_rect()
                  gets mapped to for feature extraction.
        !*/

        full_object_detection get_full_object_detection (
            const rectangle& rect,
            const feature_vector_type& w
        ) const;
        /*!
            ensures
                - returns full_object_detection(rect)
                  (This function is here only for compatibility with the scan_image_pyramid
                  object)
        !*/

        const rectangle get_best_matching_rect (
            const rectangle& rect
        ) const;
        /*!
            ensures
                - Since scan_fhog_pyramid only searches a limited set of object locations,
                  not all possible rectangles can be represented.  Therefore, this function
                  allows you to supply a rectangle and obtain the nearest possible
                  candidate object location rectangle.
        !*/

        double get_nuclear_norm_regularization_strength (
        ) const;
        /*!
            ensures
                - If the number of separable filters in a fhog_filterbank is small then the
                  filter bank can be scanned over an image much faster than a normal set of
                  filters.  Therefore, this object provides the option to encourage
                  machine learning methods that learn a HOG filter bank (i.e.
                  structural_object_detection_trainer) to select filter banks that have
                  this beneficial property.  In particular, the value returned by
                  get_nuclear_norm_regularization_strength() is a multiplier on a nuclear
                  norm regularizer which will encourage the selection of filters that use a
                  small number of separable components.  Larger values encourage tend to
                  give a smaller number of separable filters.
                - if (get_nuclear_norm_regularization_strength() == 0) then
                    - This feature is disabled
                - else
                    - A nuclear norm regularizer will be added when
                      structural_object_detection_trainer is used to learn a HOG filter
                      bank.  Note that this can make the training process take
                      significantly longer (but can result in faster object detectors).
        !*/

        void set_nuclear_norm_regularization_strength (
            double strength
        );
        /*!
            requires
                - strength >= 0
            ensures
                - #get_nuclear_norm_regularization_strength() == strength
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <typename T>
    void serialize (
        const scan_fhog_pyramid<T>& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    void deserialize (
        scan_fhog_pyramid<T>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename pyramid_type,
        typename image_type
        >
    void evaluate_detectors (
        const std::vector<object_detector<scan_fhog_pyramid<pyramid_type>>>& detectors,
        const image_type& img,
        std::vector<rect_detection>& dets,
        const double adjust_threshold = 0
    );
    /*!
        requires
            - image_type == is an implementation of array2d/array2d_kernel_abstract.h
            - img contains some kind of pixel type.
              (i.e. pixel_traits<typename image_type::type> is defined)
        ensures
            - This function runs each of the provided object_detector objects over img and
              stores the resulting detections into #dets.  Importantly, this function is
              faster than running each detector individually because it computes the HOG
              features only once and then reuses them for each detector.  However, it is
              important to note that this speedup is only possible if all the detectors use
              the same cell_size parameter that determines how HOG features are computed.
              If different cell_size values are used then this function will not be any
              faster than running the detectors individually.
            - This function applies non-max suppression individually to the output of each
              detector.  Therefore, the output is the same as if you ran each detector
              individually and then concatenated the results.
            - To be precise, this function performs object detection on the given image and
              stores the detected objects into #dets.  In particular, we will have that:
                - #dets is sorted such that the highest confidence detections come first.
                  E.g. element 0 is the best detection, element 1 the next best, and so on.
                - #dets.size() == the number of detected objects.
                - #dets[i].detection_confidence == The strength of the i-th detection.
                  Larger values indicate that the detector is more confident that #dets[i]
                  is a correct detection rather than being a false alarm.  Moreover, the
                  detection_confidence is equal to the detection value output by the
                  scanner minus the threshold value stored at the end of the weight vector.
                - #dets[i].rect == the bounding box for the i-th detection.
                - The detection #dets[i].rect was produced by detectors[#dets[i].weight_index].
            - The detection threshold is adjusted by having adjust_threshold added to it.
              Therefore, an adjust_threshold value > 0 makes detecting objects harder while
              a negative value makes it easier.  Moreover, the following will be true for
              all valid i:
                - #dets[i].detection_confidence >= adjust_threshold
              This means that, for example, you can obtain the maximum possible number of
              detections by setting adjust_threshold equal to negative infinity.
            - This function is threadsafe in the sense that multiple threads can call
              evaluate_detectors() with the same instances of detectors and img without
              requiring a mutex lock.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename pyramid_type,
        typename image_type
        >
    std::vector<rectangle> evaluate_detectors (
        const std::vector<object_detector<scan_fhog_pyramid<pyramid_type>>>& detectors,
        const image_type& img,
        const double adjust_threshold = 0
    );
    /*!
        requires
            - image_type == is an implementation of array2d/array2d_kernel_abstract.h
            - img contains some kind of pixel type.
              (i.e. pixel_traits<typename image_type::type> is defined)
        ensures
            - This function just calls the above evaluate_detectors() routine and copies
              the output dets into a vector<rectangle> object and returns it.  Therefore,
              this function is provided for convenience.
            - This function is threadsafe in the sense that multiple threads can call
              evaluate_detectors() with the same instances of detectors and img without
              requiring a mutex lock.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SCAN_fHOG_PYRAMID_ABSTRACT_Hh_


dlib C++ Library - segment_image_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SEGMENT_ImAGE_ABSTRACT_Hh_
#ifdef DLIB_SEGMENT_ImAGE_ABSTRACT_Hh_

#include <vector>
#include "../matrix.h"
#include "../image_processing/generic_image.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type
        >
    void segment_image (
        const in_image_type& in_img,
        out_image_type& out_img,
        const double k = 200,
        const unsigned long min_size = 10
    );
    /*!
        requires
            - in_image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - out_image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - in_image_type can contain any pixel type with a pixel_traits specialization
              or a dlib matrix object representing a row or column vector.
            - out_image_type must contain an unsigned integer pixel type.
            - is_same_object(in_img, out_img) == false
        ensures
            - Attempts to segment in_img into regions which have some visual consistency to
              them.  In particular, this function implements the algorithm described in the
              paper: Efficient Graph-Based Image Segmentation by Felzenszwalb and Huttenlocher.
            - #out_img.nr() == in_img.nr()
            - #out_img.nc() == in_img.nc()
            - for all valid r and c:
                - #out_img[r][c] == an integer value indicating the identity of the segment
                  containing the pixel in_img[r][c].
            - The k parameter is a measure used to influence how large the segment regions
              will be.  Larger k generally results in larger segments being produced.  For
              a deeper discussion of the k parameter you should consult the above
              referenced paper.
            - min_size is a lower bound on the size of the output segments.  That is, it is
              guaranteed that all output segments will have at least min_size pixels in
              them (unless the whole image contains fewer than min_size pixels, in this
              case the entire image will be put into a single segment).
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename EXP
        >
    void find_candidate_object_locations (
        const in_image_type& in_img,
        std::vector<rectangle>& rects,
        const matrix_exp<EXP>& kvals = linspace(50, 200, 3),
        const unsigned long min_size = 20,
        const unsigned long max_merging_iterations = 50
    );
    /*!
        requires
            - in_image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - is_vector(kvals) == true
            - kvals.size() > 0
        ensures
            - This function takes an input image and generates a set of candidate
              rectangles which are expected to bound any objects in the image.  It does
              this by running a version of the segment_image() routine on the image and
              then reports rectangles containing each of the segments as well as rectangles
              containing unions of adjacent segments.  The basic idea is described in the
              paper:
                  Segmentation as Selective Search for Object Recognition by Koen E. A. van de Sande, et al.
              Note that this function deviates from what is described in the paper slightly.
              See the code for details.
            - The basic segmentation is performed kvals.size() times, each time with the k
              parameter (see segment_image() and the Felzenszwalb paper for details on k)
              set to a different value from kvals.
            - When doing the basic segmentations prior to any box merging, we discard all
              rectangles that have an area < min_size.  Therefore, all outputs and
              subsequent merged rectangles are built out of rectangles that contain at
              least min_size pixels.  Note that setting min_size to a smaller value than
              you might otherwise be interested in using can be useful since it allows a
              larger number of possible merged boxes to be created.
            - There are max_merging_iterations rounds of neighboring blob merging.
              Therefore, this parameter has some effect on the number of output rectangles
              you get, with larger values of the parameter giving more output rectangles.
            - This function appends the output rectangles into #rects.  This means that any
              rectangles in rects before this function was called will still be in there
              after it terminates.  Note further that #rects will not contain any duplicate
              rectangles.  That is, for all valid i and j where i != j it will be true
              that:
                - #rects[i] != rects[j]
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename alloc
        >
    void remove_duplicates (
        std::vector<rectangle,alloc>& rects
    );
    /*!
        ensures
            - This function finds any duplicate rectangles in rects and removes the extra
              instances.  This way, the result is that rects contains only unique rectangle
              instances.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SEGMENT_ImAGE_ABSTRACT_Hh_


dlib C++ Library - scan_image_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SCAN_iMAGE_ABSTRACT_Hh_
#ifdef DLIB_SCAN_iMAGE_ABSTRACT_Hh_

#include <vector>
#include <utility>
#include "../algs.h"
#include "../image_processing/generic_image.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename image_array_type
        >
    bool all_images_same_size (
        const image_array_type& images
    );
    /*!
        requires
            - image_array_type       == an implementation of array/array_kernel_abstract.h
            - image_array_type::type == an image object that implements the interface
              defined in dlib/image_processing/generic_image.h
        ensures
            - if (all elements of images have the same dimensions (i.e.
              for all i and j: get_rect(images[i]) == get_rect(images[j]))) then
                - returns true
            - else
                - returns false
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_array_type
        >
    double sum_of_rects_in_images (
        const image_array_type& images,
        const std::vector<std::pair<unsigned int, rectangle> >& rects,
        const point& position
    );
    /*!
        requires
            - image_array_type             == an implementation of array/array_kernel_abstract.h
            - image_array_type::type       == an image object that implements the interface
              defined in dlib/image_processing/generic_image.h.  Moreover, these objects must
              contain a scalar pixel type (e.g. int rather than rgb_pixel)
            - all_images_same_size(images) == true
            - for all valid i: rects[i].first < images.size()
              (i.e. all the rectangles must reference valid elements of images)
        ensures
            - returns the sum of the pixels inside the given rectangles.  To be precise,
              let RECT_SUM[i] = sum of pixels inside the rectangle translate_rect(rects[i].second, position)
              from the image images[rects[i].first].  Then this function returns the
              sum of RECT_SUM[i] for all the valid values of i.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_array_type
        >
    double sum_of_rects_in_images_movable_parts (
        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 point& position
    );
    /*!
        requires
            - image_array_type             == an implementation of array/array_kernel_abstract.h
            - image_array_type::type       == an image object that implements the interface
              defined in dlib/image_processing/generic_image.h.  Moreover, these objects must
              contain a scalar pixel type (e.g. int rather than rgb_pixel)
            - all_images_same_size(images) == true
            - center(window) == point(0,0)
            - for all valid i:
                - fixed_rects[i].first < images.size()
                  (i.e. all the rectangles must reference valid elements of images)
            - for all valid i:
                - movable_rects[i].first < images.size()
                  (i.e. all the rectangles must reference valid elements of images)
                - center(movable_rects[i].second) == point(0,0)
        ensures
            - returns the sum of the pixels inside fixed_rects as well as the sum of the pixels
              inside movable_rects when these latter rectangles are placed at their highest
              scoring locations inside the given window.  To be precise:
                - let RECT_SUM(r,x) = sum of pixels inside the rectangle translate_rect(r.second, x)
                  from the image images[r.first].
                - let WIN_MAX(i) = The maximum value of RECT_SUM(movable_rects[i],X) when maximizing
                  over all the X such that translate_rect(window,position).contains(X) == true.

                - let TOTAL_FIXED   == sum over all elements R in fixed_rects of: RECT_SUM(R,position)
                - let TOTAL_MOVABLE == sum over all valid i of: max(WIN_MAX(i), 0)

              Then this function returns TOTAL_FIXED + TOTAL_MOVABLE.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    void find_points_above_thresh (
        std::vector<std::pair<double, point> >& dets,
        const image_type& img,
        const double thresh,
        const unsigned long max_dets
    );
    /*!
        requires
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h.  Moreover, these it must contain a
              scalar pixel type (e.g. int rather than rgb_pixel)
        ensures
            - #dets == a list of points from img which had pixel values >= thresh.
            - Specifically, we have:
                - #dets.size() <= max_dets
                  (note that dets is cleared before new detections are added by find_points_above_thresh())
                - for all valid i:
                    - #dets[i].first == img[#dets[i].second.y()][#dets[i].second.x()]
                      (i.e. the first field contains the value of the pixel at this detection location)
                    - #dets[i].first >= thresh
            - if (there are more than max_dets locations that pass the above threshold test) then
                - #dets == a random subsample of all the locations which passed the threshold
                  test.
            - else
                - #dets == all the points which passed the threshold test.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_array_type
        >
    void scan_image (
        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
    );
    /*!
        requires
            - image_array_type             == an implementation of array/array_kernel_abstract.h
            - image_array_type::type       == an image object that implements the interface
              defined in dlib/image_processing/generic_image.h.  Moreover, these objects must
              contain a scalar pixel type (e.g. int rather than rgb_pixel)
            - images.size() > 0
            - rects.size() > 0
            - all_images_same_size(images) == true
            - for all valid i: rects[i].first < images.size()
              (i.e. all the rectangles must reference valid elements of images)
        ensures
            - slides the set of rectangles over the image space and reports the locations
              which give a sum bigger than thresh.
            - Specifically, we have:
                - #dets.size() <= max_dets
                  (note that dets is cleared before new detections are added by scan_image())
                - for all valid i:
                    - #dets[i].first == sum_of_rects_in_images(images,rects,#dets[i].second) >= thresh
            - if (there are more than max_dets locations that pass the threshold test) then
                - #dets == a random subsample of all the locations which passed the threshold
                  test.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_array_type
        >
    void 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 max_dets
    );
    /*!
        requires
            - image_array_type             == an implementation of array/array_kernel_abstract.h
            - image_array_type::type       == an image object that implements the interface
              defined in dlib/image_processing/generic_image.h.  Moreover, these objects must
              contain a scalar pixel type (e.g. int rather than rgb_pixel)
            - images.size() > 0
            - all_images_same_size(images) == true
            - center(window) == point(0,0)
            - window.area() > 0
            - for all valid i:
                - fixed_rects[i].first < images.size()
                  (i.e. all the rectangles must reference valid elements of images)
            - for all valid i:
                - movable_rects[i].first < images.size()
                  (i.e. all the rectangles must reference valid elements of images)
                - center(movable_rects[i].second) == point(0,0)
                - movable_rects[i].second.area() > 0
        ensures
            - Scans the given window over the images and reports the locations with a score bigger
              than thresh.
            - Specifically, we have:
                - #dets.size() <= max_dets
                  (note that dets is cleared before new detections are added by scan_image_movable_parts())
                - for all valid i:
                    - #dets[i].first == sum_of_rects_in_images_movable_parts(images,
                                                                             window,
                                                                             fixed_rects,
                                                                             movable_rects,
                                                                             #dets[i].second) >= thresh
            - if (there are more than max_dets locations that pass the above threshold test) then
                - #dets == a random subsample of all the locations which passed the threshold
                  test.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SCAN_iMAGE_ABSTRACT_Hh_


dlib C++ Library - full_object_detection_abstract.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_FULL_OBJECT_DeTECTION_ABSTRACT_Hh_
#ifdef DLIB_FULL_OBJECT_DeTECTION_ABSTRACT_Hh_

#include <vector>
#include "../geometry.h"
#include "../serialize.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    const static point OBJECT_PART_NOT_PRESENT(0x7FFFFFFF,
                                               0x7FFFFFFF);

// ----------------------------------------------------------------------------------------

    class full_object_detection
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object represents the location of an object in an image along with the
                positions of each of its constituent parts.
        !*/

    public:

        full_object_detection(
            const rectangle& rect,
            const std::vector<point>& parts
        );
        /*!
            ensures
                - #get_rect() == rect
                - #num_parts() == parts.size()
                - for all valid i:
                    - part(i) == parts[i]
        !*/

        full_object_detection(
        );
        /*!
            ensures
                - #get_rect().is_empty() == true
                - #num_parts() == 0
        !*/

        explicit full_object_detection(
            const rectangle& rect
        );
        /*!
            ensures
                - #get_rect() == rect
                - #num_parts() == 0
        !*/

        const rectangle& get_rect(
        ) const;
        /*!
            ensures
                - returns the rectangle that indicates where this object is.  In general,
                  this should be the bounding box for the object.
        !*/

        rectangle& get_rect(
        );
        /*!
            ensures
                - returns the rectangle that indicates where this object is.  In general,
                  this should be the bounding box for the object.
        !*/

        unsigned long num_parts(
        ) const;
        /*!
            ensures
                - returns the number of parts in this object.
        !*/

        const point& part(
            unsigned long idx
        ) const;
        /*!
            requires
                - idx < num_parts()
            ensures
                - returns the location of the center of the idx-th part of this object.
                  Note that it is valid for a part to be "not present".  This is indicated
                  when the return value of part() is equal to OBJECT_PART_NOT_PRESENT.
                  This is useful for modeling object parts that are not always observed.
        !*/

        point& part(
            unsigned long idx
        );
        /*!
            requires
                - idx < num_parts()
            ensures
                - returns the location of the center of the idx-th part of this object.
                  Note that it is valid for a part to be "not present".  This is indicated
                  when the return value of part() is equal to OBJECT_PART_NOT_PRESENT.
                  This is useful for modeling object parts that are not always observed.
        !*/
    };

// ----------------------------------------------------------------------------------------

    void serialize (
        const full_object_detection& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

    void deserialize (
        full_object_detection& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// ----------------------------------------------------------------------------------------

    bool all_parts_in_rect (
        const full_object_detection& obj
    );
    /*!
        ensures
            - returns true if all the parts in obj are contained within obj.get_rect().
              That is, returns true if and only if, for all valid i, the following is
              always true:
                obj.get_rect().contains(obj.part(i)) == true || obj.part(i) == OBJECT_PART_NOT_PRESENT
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_FULL_OBJECT_DeTECTION_ABSTRACT_Hh_


dlib C++ Library - frontal_face_detector_abstract.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_FRONTAL_FACE_DETECTOr_ABSTRACT_Hh_
#ifdef DLIB_FRONTAL_FACE_DETECTOr_ABSTRACT_Hh_

#include "object_detector_abstract.h"
#include "scan_fhog_pyramid_abstract.h"
#include "../image_transforms/image_pyramid_abstract.h"

namespace dlib
{
    typedef object_detector<scan_fhog_pyramid<pyramid_down<6> > > frontal_face_detector;

    frontal_face_detector get_frontal_face_detector(
    );
    /*!
        ensures
            - returns an object_detector that is configured to find human faces that are
              looking more or less towards the camera.
    !*/

}

#endif // DLIB_FRONTAL_FACE_DETECTOr_ABSTRACT_Hh_


dlib C++ Library - object_detector_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_OBJECT_DeTECTOR_ABSTRACT_Hh_
#ifdef DLIB_OBJECT_DeTECTOR_ABSTRACT_Hh_

#include "../geometry.h"
#include <vector>
#include "box_overlap_testing_abstract.h"
#include "full_object_detection_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    struct rect_detection
    {
        double detection_confidence;
        unsigned long weight_index;
        rectangle rect;
    };

    struct full_detection
    {
        double detection_confidence;
        unsigned long weight_index;
        full_object_detection rect;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename image_scanner_type_
        >
    class object_detector
    {
        /*!
            REQUIREMENTS ON image_scanner_type_
                image_scanner_type_ must be an implementation of
                dlib/image_processing/scan_image_pyramid_abstract.h or
                dlib/image_processing/scan_fhog_pyramid.h or
                dlib/image_processing/scan_image_custom.h or
                dlib/image_processing/scan_image_boxes_abstract.h

            WHAT THIS OBJECT REPRESENTS
                This object is a tool for detecting the positions of objects in an image.
                In particular, it is a simple container to aggregate an instance of an image
                scanner (i.e. scan_image_pyramid, scan_fhog_pyramid, scan_image_custom, or
                scan_image_boxes), the weight vector needed by one of these image scanners,
                and finally an instance of test_box_overlap.  The test_box_overlap object
                is used to perform non-max suppression on the output of the image scanner
                object.

                Note further that this object can contain multiple weight vectors.  In this
                case, it will run the image scanner multiple times, once with each of the
                weight vectors.  Then it will aggregate the results from all runs, perform
                non-max suppression and then return the results.  Therefore, the object_detector
                can also be used as a container for a set of object detectors that all use
                the same image scanner but different weight vectors.  This is useful since
                the object detection procedure has two parts.  A loading step where the
                image is loaded into the scanner, then a detect step which uses the weight
                vector to locate objects in the image.  Since the loading step is independent
                of the weight vector it is most efficient to run multiple detectors by
                performing one load into a scanner followed by multiple detect steps.  This
                avoids unnecessarily loading the same image into the scanner multiple times.
        !*/
    public:
        typedef image_scanner_type_ image_scanner_type;
        typedef typename image_scanner_type::feature_vector_type feature_vector_type;

        object_detector (
        );
        /*!
            ensures
                - This detector won't generate any detections when
                  presented with an image.
                - #num_detectors() == 0
        !*/

        object_detector (
            const object_detector& item
        );
        /*!
            ensures
                - #*this is a copy of item
                - #get_scanner() == item.get_scanner()
                  (note that only the "configuration" of item.get_scanner() is copied.
                  I.e. the copy is done using copy_configuration())
        !*/

        object_detector (
            const image_scanner_type& scanner,
            const test_box_overlap& overlap_tester,
            const feature_vector_type& w
        );
        /*!
            requires
                - w.size() == scanner.get_num_dimensions() + 1
                - scanner.get_num_detection_templates() > 0
            ensures
                - When the operator() member function is called it will
                  invoke scanner.detect(w,dets,w(w.size()-1)), suppress
                  overlapping detections, and then report the results.
                - when #*this is used to detect objects, the set of
                  output detections will never contain any overlaps
                  with respect to overlap_tester.  That is, for all
                  pairs of returned detections A and B, we will always
                  have: overlap_tester(A,B) == false
                - #get_w() == w
                - #get_overlap_tester() == overlap_tester
                - #get_scanner() == scanner
                  (note that only the "configuration" of scanner is copied.
                  I.e. the copy is done using copy_configuration())
                - #num_detectors() == 1
        !*/

        object_detector (
            const image_scanner_type& scanner,
            const test_box_overlap& overlap_tester,
            const std::vector<feature_vector_type>& w
        );
        /*!
            requires
                - for all valid i:
                    - w[i].size() == scanner.get_num_dimensions() + 1
                - scanner.get_num_detection_templates() > 0
                - w.size() > 0
            ensures
                - When the operator() member function is called it will invoke
                  get_scanner().detect(w[i],dets,w[i](w[i].size()-1)) for all valid i.  Then it
                  will take all the detections output by the calls to detect() and suppress
                  overlapping detections, and finally report the results.
                - when #*this is used to detect objects, the set of output detections will
                  never contain any overlaps with respect to overlap_tester.  That is, for
                  all pairs of returned detections A and B, we will always have:
                    overlap_tester(A,B) == false
                - for all valid i:
                    - #get_w(i) == w[i]
                - #num_detectors() == w.size()
                - #get_overlap_tester() == overlap_tester
                - #get_scanner() == scanner
                  (note that only the "configuration" of scanner is copied.
                  I.e. the copy is done using copy_configuration())
        !*/

        explicit object_detector (
            const std::vector<object_detector>& detectors
        );
        /*!
            requires
                - detectors.size() != 0
                - All the detectors must use compatibly configured scanners.  That is, it
                  must make sense for the weight vector from one detector to be used with
                  the scanner from any other.
                - for all valid i:
                    - detectors[i].get_scanner().get_num_dimensions() == detectors[0].get_scanner().get_num_dimensions()
                      (i.e. all the detectors use scanners that use the same kind of feature vectors.)
            ensures
                - Very much like the above constructor, this constructor takes all the
                  given detectors and packs them into #*this.  That is, invoking operator()
                  on #*this will run all the detectors, perform non-max suppression, and
                  then report the results.
                - When #*this is used to detect objects, the set of output detections will
                  never contain any overlaps with respect to overlap_tester.  That is, for
                  all pairs of returned detections A and B, we will always have:
                    overlap_tester(A,B) == false
                - #num_detectors() == The sum of detectors[i].num_detectors() for all valid i.
                - #get_overlap_tester() == detectors[0].get_overlap_tester()
                - #get_scanner() == detectors[0].get_scanner()
                  (note that only the "configuration" of scanner is copied.  I.e. the copy
                  is done using copy_configuration())
        !*/

        unsigned long num_detectors (
        ) const;
        /*!
            ensures
                - returns the number of weight vectors in this object.  Since each weight
                  vector logically represents an object detector, this returns the number
                  of object detectors contained in this object.
        !*/

        const feature_vector_type& get_w (
            unsigned long idx = 0
        ) const;
        /*!
            requires
                - idx < num_detectors
            ensures
                - returns the idx-th weight vector loaded into this object.  All the weight vectors
                  have the same dimension and logically each represents a different detector.
        !*/

        const test_box_overlap& get_overlap_tester (
        ) const;
        /*!
            ensures
                - returns the overlap tester used by this object
        !*/

        const image_scanner_type& get_scanner (
        ) const;
        /*!
            ensures
                - returns the image scanner used by this object.
        !*/

        object_detector& operator= (
            const object_detector& item
        );
        /*!
            ensures
                - #*this is a copy of item
                - #get_scanner() == item.get_scanner()
                  (note that only the "configuration" of item.get_scanner() is
                  copied.  I.e. the copy is done using copy_configuration())
                - returns #*this
        !*/

        template <
            typename image_type
            >
        void operator() (
            const image_type& img,
            std::vector<rect_detection>& dets,
            double adjust_threshold = 0
        );
        /*!
            requires
                - img == an object which can be accepted by image_scanner_type::load()
            ensures
                - Performs object detection on the given image and stores the detected
                  objects into #dets.  In particular, we will have that:
                    - #dets is sorted such that the highest confidence detections come
                      first.  E.g. element 0 is the best detection, element 1 the next
                      best, and so on.
                    - #dets.size() == the number of detected objects.
                    - #dets[i].detection_confidence == The strength of the i-th detection.
                      Larger values indicate that the detector is more confident that
                      #dets[i] is a correct detection rather than being a false alarm.
                      Moreover, the detection_confidence is equal to the detection value
                      output by the scanner minus the threshold value stored at the end of
                      the weight vector in get_w(#dets[i].weight_index).
                    - #dets[i].weight_index == the index for the weight vector that
                      generated this detection.
                    - #dets[i].rect == the bounding box for the i-th detection.
                - #get_scanner() will have been loaded with img. Therefore, you can call
                  #get_scanner().get_feature_vector() to obtain the feature vectors or
                  #get_scanner().get_full_object_detection() to get the
                  full_object_detections for the resulting object detection boxes.
                - The detection threshold is adjusted by having adjust_threshold added to
                  it.  Therefore, an adjust_threshold value > 0 makes detecting objects
                  harder while a negative value makes it easier.  Moreover, the following
                  will be true for all valid i:
                    - #dets[i].detection_confidence >= adjust_threshold
                  This means that, for example, you can obtain the maximum possible number
                  of detections by setting adjust_threshold equal to negative infinity.
        !*/

        template <
            typename image_type
            >
        void operator() (
            const image_type& img,
            std::vector<full_detection>& dets,
            double adjust_threshold = 0
        );
        /*!
            requires
                - img == an object which can be accepted by image_scanner_type::load()
            ensures
                - This function is identical to the above operator() routine, except that
                  it outputs full_object_detections instead of rectangles.  This means that
                  the output includes part locations.  In particular, calling this function
                  is the same as calling the above operator() routine and then using
                  get_scanner().get_full_object_detection() to resolve all the rectangles
                  into full_object_detections.  Therefore, this version of operator() is
                  simply a convenience function for performing this set of operations.
        !*/

        template <
            typename image_type
            >
        std::vector<rectangle> operator() (
            const image_type& img,
            const adjust_threshold = 0
        );
        /*!
            requires
                - img == an object which can be accepted by image_scanner_type::load()
            ensures
                - This function is identical to the above operator() routine, except that
                  it returns a std::vector<rectangle> which contains just the bounding
                  boxes of all the detections.
        !*/

        template <
            typename image_type
            >
        void operator() (
            const image_type& img,
            std::vector<std::pair<double, rectangle> >& dets,
            double adjust_threshold = 0
        );
        /*!
            requires
                - img == an object which can be accepted by image_scanner_type::load()
            ensures
                - performs object detection on the given image and stores the
                  detected objects into #dets.  In particular, we will have that:
                    - #dets is sorted such that the highest confidence detections
                      come first.  E.g. element 0 is the best detection, element 1
                      the next best, and so on.
                    - #dets.size() == the number of detected objects.
                    - #dets[i].first gives the "detection confidence", of the i-th
                      detection.  This is the detection value output by the scanner minus
                      the threshold value stored at the end of the weight vector in get_w().
                    - #dets[i].second == the bounding box for the i-th detection.
                - #get_scanner() will have been loaded with img. Therefore, you can call
                  #get_scanner().get_feature_vector() to obtain the feature vectors or
                  #get_scanner().get_full_object_detection() to get the
                  full_object_detections for the resulting object detection boxes.
                - The detection threshold is adjusted by having adjust_threshold added to
                  it.  Therefore, an adjust_threshold value > 0 makes detecting objects
                  harder while a negative value makes it easier.  Moreover, the following
                  will be true for all valid i:
                    - #dets[i].first >= adjust_threshold
                  This means that, for example, you can obtain the maximum possible number
                  of detections by setting adjust_threshold equal to negative infinity.
        !*/

        template <
            typename image_type
            >
        void operator() (
            const image_type& img,
            std::vector<std::pair<double, full_object_detection> >& dets,
            double adjust_threshold = 0
        );
        /*!
            requires
                - img == an object which can be accepted by image_scanner_type::load()
            ensures
                - This function is identical to the above operator() routine, except that
                  it outputs full_object_detections instead of rectangles.  This means that
                  the output includes part locations.  In particular, calling this function
                  is the same as calling the above operator() routine and then using
                  get_scanner().get_full_object_detection() to resolve all the rectangles
                  into full_object_detections.  Therefore, this version of operator() is
                  simply a convenience function for performing this set of operations.
        !*/

        template <
            typename image_type
            >
        void operator() (
            const image_type& img,
            std::vector<full_object_detection>& dets,
            double adjust_threshold = 0
        );
        /*!
            requires
                - img == an object which can be accepted by image_scanner_type::load()
            ensures
                - This function is identical to the above operator() routine, except that
                  it doesn't include a double valued score.  That is, it just outputs the
                  full_object_detections.
        !*/
    };

// ----------------------------------------------------------------------------------------

    template <typename T>
    void serialize (
        const object_detector<T>& item,
        std::ostream& out
    );
    /*!
        provides serialization support.  Note that this function only saves the
        configuration part of item.get_scanner().  That is, we use the scanner's
        copy_configuration() function to get a copy of the scanner that doesn't contain any
        loaded image data and we then save just the configuration part of the scanner.
        This means that any serialized object_detectors won't remember any images they have
        processed but will otherwise contain all their state and be able to detect objects
        in new images.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    void deserialize (
        object_detector<T>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_OBJECT_DeTECTOR_ABSTRACT_Hh_


dlib C++ Library - remove_unobtainable_rectangles_abstract.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_REMOVE_UnOBTAINABLE_RECTANGLES_ABSTRACT_Hh_
#ifdef DLIB_REMOVE_UnOBTAINABLE_RECTANGLES_ABSTRACT_Hh_

#include "scan_image_pyramid_abstract.h"
#include "scan_image_boxes_abstract.h"
#include "scan_image_custom_abstract.h"
#include "scan_fhog_pyramid_abstract.h"
#include "../svm/structural_object_detection_trainer_abstract.h"
#include "../geometry.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename image_scanner_type,
        typename image_array_type
        >
    std::vector<std::vector<rectangle> > remove_unobtainable_rectangles (
        const structural_object_detection_trainer<image_scanner_type>& trainer,
        const image_array_type& images,
        std::vector<std::vector<rectangle> >& object_locations
    );
    /*!
        requires
            - image_scanner_type must be either scan_image_boxes, scan_image_pyramid,
              scan_image_custom, or scan_fhog_pyramid.
            - images.size() == object_locations.size()
        ensures
            - Recall that the image scanner objects can't produce all possible rectangles
              as object detections since they only consider a limited subset of all possible
              object positions.  Moreover, the structural_object_detection_trainer requires
              its input training data to not contain any object positions which are unobtainable
              by its scanner object.  Therefore, remove_unobtainable_rectangles() is a tool
              to filter out these unobtainable rectangles from the training data before giving
              it to a structural_object_detection_trainer.
            - This function interprets object_locations[i] as the set of object positions for
              image[i], for all valid i.
            - In particular, this function removes unobtainable rectangles from object_locations
              and also returns a vector V such that:
                - V.size() == object_locations.size()
                - for all valid i:
                    - V[i] == the set of rectangles removed from object_locations[i]
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_REMOVE_UnOBTAINABLE_RECTANGLES_ABSTRACT_Hh_


dlib C++ Library - detection_template_tools_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_DETECTION_TEMPlATE_TOOLS_ABSTRACT_Hh_
#ifdef DLIB_DETECTION_TEMPlATE_TOOLS_ABSTRACT_Hh_

#include "../geometry.h"
#include <utility>
#include <vector>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    rectangle compute_box_dimensions (
        const double width_to_height_ratio,
        const double area
    );
    /*!
        requires
            - area > 0
            - width_to_height_ratio > 0
        ensures
            - returns a rectangle with the given area and width_to_height_ratio.
            - In particular, returns a rectangle R such that:
                - R.area() == area (to within integer precision)
                - R.width()/R.height() == width_to_height_ratio (to within integer precision)
                - center(R) == point(0,0)
    !*/

// ----------------------------------------------------------------------------------------

    std::vector<rectangle> create_single_box_detection_template (
        const rectangle& object_box
    );
    /*!
        ensures
            - returns a vector that contains only object_box.
            - In particular, returns a vector V such that:
                - V.size() == 1
                - V[0] == object_box
    !*/

// ----------------------------------------------------------------------------------------

    std::vector<rectangle> create_overlapped_2x2_detection_template (
        const rectangle& object_box
    );
    /*!
        ensures
            - Divides object_box up into four overlapping regions, the
              top half, bottom half, left half, and right half.  These
              four rectangles are returned inside a std::vector.
            - In particular, returns a vector V such that:
                - V.size() == 4
                - V[0] == top half of object_box
                - V[1] == bottom half of object_box
                - V[2] == left half of object_box
                - V[3] == right half of object_box
                - for all valid i: object_box.contains(V[i]) == true
    !*/

// ----------------------------------------------------------------------------------------

    std::vector<rectangle> create_grid_detection_template (
        const rectangle& object_box,
        unsigned int cells_x,
        unsigned int cells_y
    );
    /*!
        requires
            - cells_x > 0
            - cells_y > 0
        ensures
            - Divides object_box up into a grid and returns a vector
              containing all the rectangles corresponding to elements
              of the grid.  Moreover, the grid will be cells_x elements
              wide and cells_y elements tall.
            - In particular, returns a vector V such that:
                - V.size() == cells_x*cells_y
                - for all valid i:
                    - object_box.contains(V[i]) == true
                    - V[i] == The rectangle corresponding to the ith grid
                      element.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_DETECTION_TEMPlATE_TOOLS_ABSTRACT_Hh_


dlib C++ Library - scan_image_pyramid_tools_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SCAN_IMaGE_PYRAMID_TOOLS_ABSTRACT_Hh_
#ifdef DLIB_SCAN_IMaGE_PYRAMID_TOOLS_ABSTRACT_Hh_

#include "scan_image_pyramid_abstract.h"
#include <vector>
#include "../geometry.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename image_scanner_type
        >
    std::vector<rectangle> determine_object_boxes (
        const image_scanner_type& scanner,
        const std::vector<rectangle>& rects,
        double min_match_score
    );
    /*!
        requires
            - 0 < min_match_score <= 1
            - image_scanner_type == an implementation of the scan_image_pyramid
              object defined in dlib/image_processing/scan_image_pyramid_tools_abstract.h
        ensures
            - returns a set of object boxes which, when used as detection templates with
              the given scanner, can attain at least min_match_score alignment with every
              element of rects.  Note that the alignment between two rectangles A and B is
              defined as:
                (A.intersect(B).area())/(double)(A+B).area()
            - Only elements of rects which are not already well matched by the scanner are
              considered.  That is, if the scanner already has some detection templates in
              it then the contents of rects will be checked against those detection
              templates and elements with a match better than min_match_score are ignore.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_scanner_type
        >
    std::vector<rectangle> determine_object_boxes (
        const image_scanner_type& scanner,
        const std::vector<std::vector<rectangle> >& rects,
        double min_match_score
    );
    /*!
        requires
            - 0 < min_match_score <= 1
            - image_scanner_type == an implementation of the scan_image_pyramid
              object defined in dlib/image_processing/scan_image_pyramid_tools_abstract.h
        ensures
            - copies all rectangles in rects into a std::vector<rectangle> object, call it
              R.  Then this function returns determine_object_boxes(scanner,R,min_match_score).
              That is, it just called the version of determine_object_boxes() defined above
              and returns the results.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_scanner_type
        >
    void setup_grid_detection_templates (
        image_scanner_type& scanner,
        const std::vector<std::vector<rectangle> >& rects,
        unsigned int cells_x,
        unsigned int cells_y,
        double min_match_score = 0.75
    );
    /*!
        requires
            - cells_x > 0
            - cells_y > 0
            - 0 < min_match_score <= 1
            - image_scanner_type == an implementation of the scan_image_pyramid
              object defined in dlib/image_processing/scan_image_pyramid_tools_abstract.h
        ensures
            - uses determine_object_boxes(scanner,rects,min_match_score) to obtain a set of
              object boxes and then adds them to the given scanner object as detection templates.
              Also uses create_grid_detection_template(object_box, cells_x, cells_y) to create
              each feature extraction region.  Therefore, the detection templates will extract
              features from a regular grid inside each object box.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_scanner_type
        >
    void setup_grid_detection_templates_verbose (
        image_scanner_type& scanner,
        const std::vector<std::vector<rectangle> >& rects,
        unsigned int cells_x,
        unsigned int cells_y,
        double min_match_score = 0.75
    );
    /*!
        requires
            - cells_x > 0
            - cells_y > 0
            - 0 < min_match_score <= 1
            - image_scanner_type == an implementation of the scan_image_pyramid
              object defined in dlib/image_processing/scan_image_pyramid_tools_abstract.h
        ensures
            - this function is identical to setup_grid_detection_templates() except
              that it also outputs the selected detection templates to standard out.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SCAN_IMaGE_PYRAMID_TOOLS_ABSTRACT_Hh_


dlib C++ Library - scan_image_boxes_abstract.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SCAN_IMAGE_bOXES_ABSTRACT_Hh_
#ifdef DLIB_SCAN_IMAGE_bOXES_ABSTRACT_Hh_

#include "../matrix.h"
#include "../geometry.h"
#include "../image_processing.h"
#include "../array2d.h"
#include "full_object_detection_abstract.h"
#include "../image_transforms/segment_image_abstract.h"
#include <vector>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class default_box_generator
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is a function object that takes in an image and outputs a set of
                candidate object locations.  It is also the default box generator used by
                the scan_image_boxes object defined below.
        !*/

    public:

        template <typename image_type>
        void operator() (
            const image_type& img,
            std::vector<rectangle>& rects
        ) const
        /*!
            ensures
                - #rects == the set of candidate object locations which should be searched
                  inside img.  That is, these are the rectangles which might contain
                  objects of interest within the given image.
        !*/
        {
            rects.clear();
            find_candidate_object_locations(img, rects);
        }
    };

    inline void serialize  (const default_box_generator&, std::ostream& ) {}
    inline void deserialize(      default_box_generator&, std::istream& ) {}
    /*!
        ensures
            - provides serialization support.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename Feature_extractor_type,
        typename Box_generator = default_box_generator
        >
    class scan_image_boxes : noncopyable
    {
        /*!
            REQUIREMENTS ON Feature_extractor_type
                - must be an object with an interface compatible with the hashed_feature_image
                  object defined in dlib/image_keypoint/hashed_feature_image_abstract.h or
                  with the nearest_neighbor_feature_image object defined in
                  dlib/image_keypoint/nearest_neighbor_feature_image_abstract.h

            REQUIREMENTS ON Box_generator
                - must be an object with an interface compatible with the
                  default_box_generator object defined at the top of this file.

            INITIAL VALUE
                - get_num_spatial_pyramid_levels() == 3
                - is_loaded_with_image() == false

            WHAT THIS OBJECT REPRESENTS
                This object is a tool for running a classifier over an image with the goal
                of localizing each object present.  The localization is in the form of the
                bounding box around each object of interest.

                Unlike the scan_image_pyramid object which scans a fixed sized window over
                an image pyramid, the scan_image_boxes tool allows you to define your own
                list of "candidate object locations" which should be evaluated.  This is
                simply a list of rectangle objects which might contain objects of interest.
                The scan_image_boxes object will then evaluate the classifier at each of
                these locations and return the subset of rectangles which appear to have
                objects in them.  The candidate object location generation is provided by
                the Box_generator that is passed in as a template argument.

                This object can also be understood as a general tool for implementing the
                spatial pyramid models described in the paper:
                    Beyond Bags of Features: Spatial Pyramid Matching for Recognizing
                    Natural Scene Categories by Svetlana Lazebnik, Cordelia Schmid,
                    and Jean Ponce

                The classifiers used by this object have three parts:
                   1. The underlying feature extraction provided by Feature_extractor_type
                      objects, which associate a vector with each location in an image.

                   2. A rule for extracting a feature vector from a candidate object
                      location.  In this object we use the spatial pyramid matching method.
                      This means we cut an object's detection window into a set of "feature
                      extraction regions" and extract a bag-of-words vector from each
                      before finally concatenating them to form the final feature vector
                      representing the entire object window.  The set of feature extraction
                      regions can be configured by the user by calling
                      set_num_spatial_pyramid_levels().  To be a little more precise, the
                      feature vector for a candidate object window is defined as follows:
                        - Let N denote the number of feature extraction zones.
                        - Let M denote the dimensionality of the vectors output by
                          Feature_extractor_type objects.
                        - Let F(i) == the M dimensional vector which is the sum of all
                          vectors given by our Feature_extractor_type object inside the
                          i-th feature extraction zone.  So this is notionally a
                          bag-of-words vector from the i-th zone.
                        - Then the feature vector for an object window is an M*N
                          dimensional vector [F(1) F(2) F(3) ... F(N)] (i.e. it is a
                          concatenation of the N vectors).  This feature vector can be
                          thought of as a collection of N bags-of-words, each bag coming
                          from a spatial location determined by one of the feature
                          extraction zones.

                   3. A weight vector and a threshold value.  The dot product between the
                      weight vector and the feature vector for a candidate object location
                      gives the score of the location.  If this score is greater than the
                      threshold value then the candidate object location is output as a
                      detection.

            THREAD SAFETY
                Concurrent access to an instance of this object is not safe and should be
                protected by a mutex lock except for the case where you are copying the
                configuration (via copy_configuration()) of a scan_image_boxes object to
                many other threads.  In this case, it is safe to copy the configuration of
                a shared object so long as no other operations are performed on it.
        !*/

    public:

        typedef matrix<double,0,1> feature_vector_type;

        typedef Feature_extractor_type feature_extractor_type;
        typedef Box_generator box_generator;

        scan_image_boxes (
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        template <
            typename image_type
            >
        void load (
            const image_type& img
        );
        /*!
            requires
                - image_type must be a type with the following properties:
                    - image_type objects can be loaded into Feature_extractor_type
                      objects via Feature_extractor_type::load().
                    - image_type objects can be passed to the first argument of
                      Box_generator::operator()
            ensures
                - #is_loaded_with_image() == true
                - This object is ready to run a classifier over img to detect object
                  locations.  Call detect() to do this.
        !*/

        bool is_loaded_with_image (
        ) const;
        /*!
            ensures
                - returns true if this object has been loaded with an image to process and
                  false otherwise.
        !*/

        const feature_extractor_type& get_feature_extractor (
        ) const;
        /*!
            ensures
                - returns a const reference to the feature_extractor_type object used
                  internally for local feature extraction.
        !*/

        void copy_configuration(
            const feature_extractor_type& fe
        );
        /*!
            ensures
                - This function performs the equivalent of
                  get_feature_extractor().copy_configuration(fe) (i.e. this function allows
                  you to configure the parameters of the underlying feature extractor used
                  by a scan_image_boxes object)
        !*/

        void copy_configuration(
            const box_generator& bg
        );
        /*!
            ensures
                - #get_box_generator() == bg
                  (i.e. this function allows you to configure the parameters of the
                  underlying box generator used by a scan_image_boxes object)
        !*/

        const box_generator& get_box_generator (
        ) const;
        /*!
            ensures
                - returns the box_generator used by this object to generate candidate
                  object locations.
        !*/

        void copy_configuration (
            const scan_image_boxes& item
        );
        /*!
            ensures
                - Copies all the state information of item into *this, except for state
                  information populated by load().  More precisely, given two scan_image_boxes
                  objects S1 and S2, the following sequence of instructions should always
                  result in both of them having the exact same state:
                    S2.copy_configuration(S1);
                    S1.load(img);
                    S2.load(img);
        !*/

        long get_num_dimensions (
        ) const;
        /*!
            ensures
                - returns the number of dimensions in the feature vector for a candidate
                  object location.  This value is the dimensionality of the underlying
                  feature vectors produced by Feature_extractor_type times the number of
                  feature extraction regions used.  Note that the number of feature
                  extraction regions used is a function of
                  get_num_spatial_pyramid_levels().
        !*/

        unsigned long get_num_spatial_pyramid_levels (
        ) const;
        /*!
            ensures
                - returns the number of layers in the spatial pyramid.  For example, if
                  this function returns 1 then it means we use a simple bag-of-words
                  representation over the whole object window.  If it returns 2 then it
                  means the feature representation is the concatenation of 5 bag-of-words
                  vectors, one from the entire object window and 4 others from 4 different
                  parts of the object window.  If it returns 3 then there are 1+4+16
                  bag-of-words vectors concatenated together in the feature representation,
                  and so on.
        !*/

        void set_num_spatial_pyramid_levels (
            unsigned long levels
        );
        /*!
            requires
                - levels > 0
            ensures
                - #get_num_spatial_pyramid_levels() == levels
        !*/

        void detect (
            const feature_vector_type& w,
            std::vector<std::pair<double, rectangle> >& dets,
            const double thresh
        ) const;
        /*!
            requires
                - w.size() >= get_num_dimensions()
                - is_loaded_with_image() == true
            ensures
                - Scans over all the candidate object locations as discussed in the WHAT
                  THIS OBJECT REPRESENTS section and stores all detections into #dets.
                - for all valid i:
                    - #dets[i].second == The candidate object location which produced this
                      detection.  This rectangle gives the location of the detection.
                    - #dets[i].first == The score for this detection.  This value is equal
                      to dot(w, feature vector for this candidate object location).
                    - #dets[i].first >= thresh
                - #dets will be sorted in descending order.
                  (i.e.  #dets[i].first >= #dets[j].first for all i, and j>i)
                - Elements of w beyond index get_num_dimensions()-1 are ignored.  I.e. only
                  the first get_num_dimensions() are used.
                - Note that no form of non-max suppression is performed.  If a locations
                  has a score >= thresh then it is reported in #dets.
        !*/

        void get_feature_vector (
            const full_object_detection& obj,
            feature_vector_type& psi
        ) const;
        /*!
            requires
                - obj.num_parts() == 0
                - is_loaded_with_image() == true
                - psi.size() >= get_num_dimensions()
                  (i.e. psi must have preallocated its memory before this function is called)
            ensures
                - This function allows you to determine the feature vector used for a
                  candidate object location output from detect().  Note that this vector is
                  added to psi.  Note also that you must use get_full_object_detection() to
                  convert a rectangle from detect() into the needed full_object_detection.
                - The dimensionality of the vector added to psi is get_num_dimensions().  This
                  means that elements of psi after psi(get_num_dimensions()-1) are not modified.
                - Since scan_image_boxes only searches a limited set of object locations,
                  not all possible rectangles can be output by detect().  So in the case
                  where obj.get_rect() could not arise from a call to detect(), this
                  function will map obj.get_rect() to the nearest possible rectangle and
                  then add the feature vector for the mapped rectangle into #psi.
                - get_best_matching_rect(obj.get_rect()) == the rectangle obj.get_rect()
                  gets mapped to for feature extraction.
        !*/

        full_object_detection get_full_object_detection (
            const rectangle& rect,
            const feature_vector_type& w
        ) const;
        /*!
            ensures
                - returns full_object_detection(rect)
                  (This function is here only for compatibility with the scan_image_pyramid
                  object)
        !*/

        const rectangle get_best_matching_rect (
            const rectangle& rect
        ) const;
        /*!
            requires
                - is_loaded_with_image() == true
            ensures
                - Since scan_image_boxes only searches a limited set of object locations,
                  not all possible rectangles can be represented.  Therefore, this function
                  allows you to supply a rectangle and obtain the nearest possible
                  candidate object location rectangle.
        !*/

        unsigned long get_num_detection_templates (
        ) const { return 1; }
        /*!
            ensures
                - returns 1.  Note that this function is here only for compatibility with
                  the scan_image_pyramid object.  Notionally, its return value indicates
                  that a scan_image_boxes object is always ready to detect objects once
                  an image has been loaded.
        !*/

        unsigned long get_num_movable_components_per_detection_template (
        ) const { return 0; }
        /*!
            ensures
                - returns 0.  Note that this function is here only for compatibility with
                  the scan_image_pyramid object.  Its return value means that this object
                  does not support using movable part models.
        !*/
    };

// ----------------------------------------------------------------------------------------

    template <
        typename Feature_extractor_type,
        typename Box_generator
        >
    void serialize (
        const scan_image_boxes<Feature_extractor_type,Box_generator>& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

    template <
        typename Feature_extractor_type,
        typename Box_generator
        >
    void deserialize (
        scan_image_boxes<Feature_extractor_type,Box_generator>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SCAN_IMAGE_bOXES_ABSTRACT_Hh_


dlib C++ Library - scan_image_custom_abstract.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SCAN_IMAGE_CuSTOM_ABSTRACT_Hh_
#ifdef DLIB_SCAN_IMAGE_CuSTOM_ABSTRACT_Hh_

#include <vector>
#include "../matrix.h"
#include "../geometry.h"
#include "../image_processing/full_object_detection_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class example_feature_extractor
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object defines the interface a feature extractor must implement if it
                is to be used with the scan_image_custom object defined at the bottom of
                this file.

                In this case, the purpose of a feature extractor is to associated a
                complete feature vector with each rectangle in an image.  In particular,
                each rectangle is scored by taking the dot product between this feature
                vector and a weight vector.  If this score is greater than a threshold then
                the rectangle is output as a detection.
        !*/

    public:

        template <
            typename image_type
            >
        void load (
            const image_type& image,
            std::vector<rectangle>& candidate_objects
        );
        /*!
            ensures
                - Loads the given image into this feature extractor.  This means that
                  subsequent calls to get_feature_vector() will return the feature vector
                  corresponding to locations in the image given to load().
                - #candidate_objects == a set of bounding boxes in the given image that
                  might contain objects of interest.  These are the locations that will be
                  checked for the presents of objects when this feature extractor is used
                  with the scan_image_custom object.

        !*/

        void copy_configuration (
            const feature_extractor& item
        );
        /*!
            ensures
                - Copies all the state information of item into *this, except for state
                  information populated by load().  More precisely, given two
                  feature extractor objects S1 and S2, the following sequence of
                  instructions should always result in both of them having the exact same
                  state:
                    S2.copy_configuration(S1);
                    S1.load(img, temp);
                    S2.load(img, temp);
        !*/

        unsigned long get_num_dimensions (
        ) const;
        /*!
            ensures
                - returns the dimensionality of the feature vectors output by this object.
        !*/

        void get_feature_vector (
            const rectangle& obj,
            matrix<double,0,1>& psi
        ) const;
        /*!
            requires
                - psi.size() >= get_num_dimensions()
                  (i.e. psi must have preallocated its memory before this function is called)
            ensures
                - This function computes the feature vector associated with the given rectangle
                  in obj.  This rectangle is interpreted as a bounding box within the last image
                  given to this->load() and a feature vector describing that bounding box is
                  output into psi.
                - The feature vector is added into psi.  That is, it does not overwrite the
                  previous contents of psi, but instead, it adds the vector to psi.
                - The dimensionality of the vector added to psi is get_num_dimensions().  This
                  means that elements of psi after psi(get_num_dimensions()-1) are not modified.
                - #psi.size() == psi.size()
                  (i.e. this function does not change the size of the psi vector)
        !*/

        double compute_object_score (
            const matrix<double,0,1>& w,
            const rectangle& obj
        ) const;
        /*!
            requires
                - w.size() >= get_num_dimensions()
            ensures
                - This function returns the dot product between the feature vector for
                  object box obj and the given w vector.  That is, this function computes
                  the same number as the following code snippet:
                     matrix<double,0,1> psi(w.size());
                     psi = 0;
                     get_feature_vector(obj, psi);
                     return dot(psi, w);
                  The point of the compute_object_score() routine is to compute this dot
                  product in a much more efficient way than directly calling
                  get_feature_vector() and dot().  Therefore, compute_object_score() is an
                  optional function.  If you can't think of a faster way to compute these
                  scores then do not implement compute_object_score() and the
                  scan_image_custom object will simply compute these scores for you.
                  However, it is often the case that there is something clever you can do
                  to make this computation faster.  If that is the case, then you can
                  provide an implementation of this function with your feature extractor
                  and then scan_image_custom will use it instead of using the default
                  calculation method shown in the above code snippet.
        !*/

    };

// ----------------------------------------------------------------------------------------

    void serialize(
        const feature_extractor& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

    void deserialize(
        feature_extractor& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename Feature_extractor_type
        >
    class scan_image_custom : noncopyable
    {
        /*!
            REQUIREMENTS ON Feature_extractor_type
                - must be an object with an interface compatible with the
                  example_feature_extractor defined at the top of this file.

            INITIAL VALUE
                - is_loaded_with_image() == false

            WHAT THIS OBJECT REPRESENTS
                This object is a tool for running a classifier over an image with the goal
                of localizing each object present.  The localization is in the form of the
                bounding box around each object of interest.

                Unlike the scan_image_pyramid and scan_image_boxes objects, this image
                scanner delegates all the work of constructing the object feature vector to
                its Feature_extractor_type template argument.  That is, scan_image_custom
                simply asks the supplied feature extractor what boxes in the image we
                should investigate and then asks the feature extractor for the complete
                feature vector for each box.  That is, scan_image_custom does not apply any
                kind of pyramiding or other higher level processing to the features coming
                out of the feature extractor.  That means that when you use
                scan_image_custom it is completely up to you to define the feature vector
                used with each image box.

            THREAD SAFETY
                Concurrent access to an instance of this object is not safe and should be
                protected by a mutex lock except for the case where you are copying the
                configuration (via copy_configuration()) of a scan_image_custom object to
                many other threads.  In this case, it is safe to copy the configuration of
                a shared object so long as no other operations are performed on it.
        !*/

    public:

        typedef matrix<double,0,1> feature_vector_type;
        typedef Feature_extractor_type feature_extractor_type;

        scan_image_custom (
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        template <
            typename image_type
            >
        void load (
            const image_type& img
        );
        /*!
            requires
                - image_type must be a type with the following properties:
                    - image_type objects can be loaded into Feature_extractor_type
                      objects via Feature_extractor_type::load().
            ensures
                - #is_loaded_with_image() == true
                - Calls get_feature_extractor().load() on the given image.  That is, we
                  will have loaded the image into the feature extractor in this
                  scan_image_custom object.  We will also have stored the candidate
                  object locations generated by the feature extractor and will scan
                  over them when this->detect() is called.
                - This object is ready to run a classifier over img to detect object
                  locations.  Call detect() to do this.
        !*/

        bool is_loaded_with_image (
        ) const;
        /*!
            ensures
                - returns true if this object has been loaded with an image to process and
                  false otherwise.
        !*/

        const feature_extractor_type& get_feature_extractor (
        ) const;
        /*!
            ensures
                - returns a const reference to the feature_extractor_type object used
                  internally for local feature extraction.
        !*/

        void copy_configuration(
            const feature_extractor_type& fe
        );
        /*!
            ensures
                - This function performs the equivalent of
                  get_feature_extractor().copy_configuration(fe) (i.e. this function allows
                  you to configure the parameters of the underlying feature extractor used
                  by a scan_image_custom object)
        !*/

        void copy_configuration (
            const scan_image_custom& item
        );
        /*!
            ensures
                - Copies all the state information of item into *this, except for state
                  information populated by load().  More precisely, given two
                  scan_image_custom objects S1 and S2, the following sequence of
                  instructions should always result in both of them having the exact same
                  state:
                    S2.copy_configuration(S1);
                    S1.load(img);
                    S2.load(img);
        !*/

        long get_num_dimensions (
        ) const;
        /*!
            ensures
                - returns the number of dimensions in the feature vector for a candidate
                  object location.  That is, this function returns get_feature_extractor().get_num_dimensions().
        !*/

        void detect (
            const feature_vector_type& w,
            std::vector<std::pair<double, rectangle> >& dets,
            const double thresh
        ) const;
        /*!
            requires
                - w.size() >= get_num_dimensions()
                - is_loaded_with_image() == true
            ensures
                - Scans over all the candidate object locations produced by the feature
                  extractor during image loading and stores all detections into #dets.
                - for all valid i:
                    - #dets[i].second == The candidate object location which produced this
                      detection.  This rectangle gives the location of the detection.
                    - #dets[i].first == The score for this detection.  This value is equal
                      to dot(w, feature vector for this candidate object location).
                    - #dets[i].first >= thresh
                - #dets will be sorted in descending order.
                  (i.e.  #dets[i].first >= #dets[j].first for all i, and j>i)
                - Elements of w beyond index get_num_dimensions()-1 are ignored.  I.e. only
                  the first get_num_dimensions() are used.
                - Note that no form of non-max suppression is performed.  If a locations
                  has a score >= thresh then it is reported in #dets.
        !*/

        void get_feature_vector (
            const full_object_detection& obj,
            feature_vector_type& psi
        ) const;
        /*!
            requires
                - obj.num_parts() == 0
                - is_loaded_with_image() == true
                - psi.size() >= get_num_dimensions()
                  (i.e. psi must have preallocated its memory before this function is called)
            ensures
                - This function allows you to determine the feature vector used for a
                  candidate object location output from detect().  Note that this vector is
                  added to psi.  Note also that you must use get_full_object_detection() to
                  convert a rectangle from detect() into the needed full_object_detection.
                - The dimensionality of the vector added to psi is get_num_dimensions().  This
                  means that elements of psi after psi(get_num_dimensions()-1) are not modified.
                - Since scan_image_custom only searches a limited set of object locations,
                  not all possible rectangles can be output by detect().  So in the case
                  where obj.get_rect() could not arise from a call to detect(), this
                  function will map obj.get_rect() to the nearest possible rectangle and
                  then add the feature vector for the mapped rectangle into #psi.
                - get_best_matching_rect(obj.get_rect()) == the rectangle obj.get_rect()
                  gets mapped to for feature extraction.
        !*/

        full_object_detection get_full_object_detection (
            const rectangle& rect,
            const feature_vector_type& w
        ) const;
        /*!
            ensures
                - returns full_object_detection(rect)
                  (This function is here only for compatibility with the scan_image_pyramid
                  object)
        !*/

        const rectangle get_best_matching_rect (
            const rectangle& rect
        ) const;
        /*!
            requires
                - is_loaded_with_image() == true
            ensures
                - Since scan_image_custom only searches a limited set of object locations,
                  not all possible rectangles can be represented.  Therefore, this function
                  allows you to supply a rectangle and obtain the nearest possible
                  candidate object location rectangle.
        !*/

        unsigned long get_num_detection_templates (
        ) const { return 1; }
        /*!
            ensures
                - returns 1.  Note that this function is here only for compatibility with
                  the scan_image_pyramid object.  Notionally, its return value indicates
                  that a scan_image_custom object is always ready to detect objects once an
                  image has been loaded.
        !*/

        unsigned long get_num_movable_components_per_detection_template (
        ) const { return 0; }
        /*!
            ensures
                - returns 0.  Note that this function is here only for compatibility with
                  the scan_image_pyramid object.  Its return value means that this object
                  does not support using movable part models.
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <typename T>
    void serialize (
        const scan_image_custom<T>& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

    template <typename T>
    void deserialize (
        scan_image_custom<T>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SCAN_IMAGE_CuSTOM_ABSTRACT_Hh_


dlib C++ Library - scan_image_pyramid_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SCAN_IMaGE_PYRAMID_ABSTRACT_Hh_
#ifdef DLIB_SCAN_IMaGE_PYRAMID_ABSTRACT_Hh_

#include "../matrix.h"
#include "../geometry.h"
#include "../image_processing.h"
#include "../array2d.h"
#include <vector>
#include "full_object_detection_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename Feature_extractor_type
        >
    class scan_image_pyramid : noncopyable
    {
        /*!
            REQUIREMENTS ON Pyramid_type
                - must be one of the pyramid_down objects defined in
                  dlib/image_transforms/image_pyramid_abstract.h or an object with
                  a compatible interface

            REQUIREMENTS ON Feature_extractor_type
                - must be an object with an interface compatible with the hashed_feature_image
                  object defined in dlib/image_keypoint/hashed_feature_image_abstract.h or
                  with the nearest_neighbor_feature_image object defined in
                  dlib/image_keypoint/nearest_neighbor_feature_image_abstract.h

            INITIAL VALUE
                - get_num_detection_templates() == 0
                - is_loaded_with_image() == false
                - get_max_detections_per_template() == 10000
                - get_max_pyramid_levels() == 1000
                - get_min_pyramid_layer_width() == 20
                - get_min_pyramid_layer_height() == 20

            WHAT THIS OBJECT REPRESENTS
                This object is a tool for running a sliding window classifier over
                an image pyramid.  This object can also be understood as a general
                tool for implementing the spatial pyramid models described in the paper:
                    Beyond Bags of Features: Spatial Pyramid Matching for Recognizing
                    Natural Scene Categories by Svetlana Lazebnik, Cordelia Schmid,
                    and Jean Ponce
                It also includes the ability to represent movable part models.

                The sliding window classifiers used by this object have three parts:
                   1. The underlying feature extraction provided by Feature_extractor_type
                      objects, which associate a vector with each location in an image.

                   2. A detection template.  This is a rectangle which defines the shape of a
                      sliding window (i.e. the object_box), as well as a set of rectangular feature
                      extraction regions inside it.  This set of regions defines the spatial
                      structure of the overall feature extraction within a sliding window.  In
                      particular, each location of a sliding window has a feature vector
                      associated with it.  This feature vector is defined as follows:
                        - Let N denote the number of feature extraction zones.
                        - Let M denote the dimensionality of the vectors output by Feature_extractor_type
                          objects.
                        - Let F(i) == the M dimensional vector which is the sum of all vectors
                          given by our Feature_extractor_type object inside the i-th feature extraction
                          zone.
                        - Then the feature vector for a sliding window is an M*N dimensional vector
                          [F(1) F(2) F(3) ... F(N)] (i.e. it is a concatenation of the N vectors).
                          This feature vector can be thought of as a collection of N "bags of features",
                          each bag coming from a spatial location determined by one of the rectangular
                          feature extraction zones.

                   3. A weight vector and a threshold value.  The dot product between the weight
                      vector and the feature vector for a sliding window location gives the score
                      of the window.  If this score is greater than the threshold value then the
                      window location is output as a detection.

                Finally, the sliding window classifiers described above are applied to every level of
                an image pyramid.  Moreover, some of the feature extraction zones are allowed to move
                freely within the object box.  This means that when we are sliding the classifier over
                an image, some feature extraction zones are stationary (i.e. always in the same place
                relative to the object box) while others are allowed to move anywhere within the object
                box.  In particular, the movable regions are placed at the locations that maximize the
                score of the classifier.  Note further that each of the movable feature extraction
                zones must pass a threshold test for it to be included.  That is, if the score that a
                movable zone would contribute to the overall score for a sliding window location is not
                positive then that zone is not included in the feature vector (i.e.  its part of the
                feature vector is set to zero.  This way the length of the feature vector stays
                constant).  This movable region construction allows us to represent objects with parts
                that move around relative to the object box.  For example, a human has hands but they
                aren't always in the same place relative to a person's bounding box.

            THREAD SAFETY
                Concurrent access to an instance of this object is not safe and should be protected
                by a mutex lock except for the case where you are copying the configuration
                (via copy_configuration()) of a scan_image_pyramid object to many other threads.
                In this case, it is safe to copy the configuration of a shared object so long
                as no other operations are performed on it.
        !*/
    public:

        typedef matrix<double,0,1> feature_vector_type;

        typedef Pyramid_type pyramid_type;
        typedef Feature_extractor_type feature_extractor_type;

        scan_image_pyramid (
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        template <
            typename image_type
            >
        void load (
            const image_type& img
        );
        /*!
            requires
                - image_type must be a type with the following properties:
                    - image_type is default constructable.
                    - image_type is swappable by the global swap() function.
                    - image_type logically represents some kind of image and therefore its
                      number of rows and columns can be queried via num_rows(img) and
                      num_columns(img) respectively.
                    - image_type objects can be loaded into Feature_extractor_type
                      objects via Feature_extractor_type::load().
                    - image_type objects can be used with Pyramid_type.  That is,
                      if pyr is an object of type Pyramid_type while img1 and img2
                      are objects of image_type, then pyr(img1,img2) should be
                      a valid expression which downsamples img1 into img2.
            ensures
                - #is_loaded_with_image() == true
                - This object is ready to run sliding window classifiers over img.  Call
                  detect() to do this.
        !*/

        bool is_loaded_with_image (
        ) const;
        /*!
            ensures
                - returns true if this object has been loaded with an image to process
                  and false otherwise.
        !*/

        const feature_extractor_type& get_feature_extractor (
        ) const;
        /*!
            ensures
                - returns a const reference to the feature_extractor_type object used
                  internally for local feature extraction.
        !*/

        void copy_configuration(
            const feature_extractor_type& fe
        );
        /*!
            ensures
                - This function performs the equivalent of
                  get_feature_extractor().copy_configuration(fe) (i.e. this function allows
                  you to configure the parameters of the underlying feature extractor used
                  by a scan_image_pyramid object)
        !*/

        void copy_configuration (
            const scan_image_pyramid& item
        );
        /*!
            ensures
                - copies all the state information of item into *this, except for state
                  information populated by load().  More precisely, given two scan_image_pyramid
                  objects S1 and S2, the following sequence of instructions should always
                  result in both of them having the exact same state.
                    S2.copy_configuration(S1);
                    S1.load(img);
                    S2.load(img);
        !*/

        void add_detection_template (
            const rectangle& object_box,
            const std::vector<rectangle>& stationary_feature_extraction_regions,
            const std::vector<rectangle>& movable_feature_extraction_regions
        );
        /*!
            requires
                - center(object_box) == point(0,0)
                - for all valid i:
                    - center(movable_feature_extraction_regions[i]) == point(0,0)
                - if (get_num_detection_templates() > 0) then
                    - get_num_stationary_components_per_detection_template() == stationary_feature_extraction_regions.size()
                    - get_num_movable_components_per_detection_template() == movable_feature_extraction_regions.size()
                      (i.e. if you already have detection templates in this object, then
                      any new detection template must declare a consistent number of
                      feature extraction regions)
            ensures
                - Adds another detection template to this object.  In particular, object_box
                  defines the size and shape of a sliding window while stationary_feature_extraction_regions
                  and movable_feature_extraction_regions defines the locations for feature extraction as
                  discussed in the WHAT THIS OBJECT REPRESENTS section above.  Note also that the locations of
                  the stationary feature extraction regions are relative to the object_box.
                - #get_num_detection_templates() == get_num_detection_templates() + 1
                - The order of rectangles in stationary_feature_extraction_regions and
                  movable_feature_extraction_regions matters.  Recall that each rectangle
                  gets its own set of features.  So given two different templates, their
                  i-th rectangles will both share the same part of the weight vector (i.e. the w
                  supplied to detect()).  So there should be some reasonable correspondence
                  between the rectangle ordering in different detection templates.  For,
                  example, different detection templates should place corresponding feature
                  extraction regions in roughly the same part of the object_box.
                - #get_num_stationary_components_per_detection_template() = stationary_feature_extraction_regions.size()
                - #get_num_movable_components_per_detection_template()    = movable_feature_extraction_regions.size()
        !*/

        void add_detection_template (
            const rectangle& object_box,
            const std::vector<rectangle>& stationary_feature_extraction_regions
        );
        /*!
            ensures
                - calls add_detection_template(object_box, stationary_feature_extraction_regions, empty_list)
                  where empty_list is a vector of size 0.  I.e. this function is just a convenience
                  routine for adding detection templates with no movable regions.
        !*/

        unsigned long get_num_detection_templates (
        ) const;
        /*!
            ensures
                - returns the number of detection templates in this object
        !*/

        unsigned long get_num_stationary_components_per_detection_template (
        ) const;
        /*!
            requires
                - get_num_detection_templates() > 0
            ensures
                - A detection template is a rectangle which defines the shape of a sliding
                  window (the object_box), as well as a set of rectangles which define
                  feature extraction zones.  This function returns the number of stationary
                  feature extraction zones in the detection templates used by this object.
        !*/

        unsigned long get_num_movable_components_per_detection_template (
        ) const;
        /*!
            requires
                - get_num_detection_templates() > 0
            ensures
                - A detection template is a rectangle which defines the shape of a sliding
                  window (the object_box), as well as a set of rectangles which define
                  feature extraction zones.  This function returns the number of movable
                  feature extraction zones in the detection templates used by this object.
        !*/

        unsigned long get_num_components_per_detection_template (
        ) const;
        /*!
            requires
                - get_num_detection_templates() > 0
            ensures
                - returns the total number of feature extraction zones in the detection
                  templates used by this object.  That is, returns the following:
                    - get_num_movable_components_per_detection_template() +
                      get_num_stationary_components_per_detection_template()
        !*/

        long get_num_dimensions (
        ) const;
        /*!
            requires
                - get_num_detection_templates() > 0
            ensures
                - returns the number of dimensions in the feature vector for a sliding window
                  location.  This value is the dimensionality of the underlying feature vectors
                  produced by Feature_extractor_type times (get_num_stationary_components_per_detection_template() +
                  get_num_movable_components_per_detection_template()).
        !*/

        unsigned long get_max_pyramid_levels (
        ) const;
        /*!
            ensures
                - returns the maximum number of image pyramid levels this object will use.
                  Note that #get_max_pyramid_levels() == 1 indicates that no image pyramid
                  will be used at all.  That is, only the original image will be processed
                  and no lower scale versions will be created.
        !*/

        void set_max_pyramid_levels (
            unsigned long max_levels
        );
        /*!
            requires
                - max_levels > 0
            ensures
                - #get_max_pyramid_levels() == max_levels
        !*/

        void set_min_pyramid_layer_size (
            unsigned long width,
            unsigned long height
        );
        /*!
            requires
                - width > 0
                - height > 0
            ensures
                - #get_min_pyramid_layer_width() == width
                - #get_min_pyramid_layer_height() == height
        !*/

        inline unsigned long get_min_pyramid_layer_width (
        ) const;
        /*!
            ensures
                - returns the smallest allowable width of an image in the image pyramid.
                  All pyramids will always include the original input image, however, no
                  pyramid levels will be created which have a width smaller than the
                  value returned by this function.
        !*/

        inline unsigned long get_min_pyramid_layer_height (
        ) const;
        /*!
            ensures
                - returns the smallest allowable height of an image in the image pyramid.
                  All pyramids will always include the original input image, however, no
                  pyramid levels will be created which have a height smaller than the
                  value returned by this function.
        !*/

        unsigned long get_max_detections_per_template (
        ) const;
        /*!
            ensures
                - For each image pyramid layer and detection template, this object scans a sliding
                  window classifier over an image and produces a number of detections.  This
                  function returns a number which defines a hard upper limit on the number of
                  detections allowed by a single scan.  This means that the total number of
                  possible detections produced by detect() is get_max_detections_per_template()*
                  get_num_detection_templates()*(number of image pyramid layers).  Additionally,
                  if the maximum number of detections is reached during a scan then this object
                  will return a random subsample of all detections which are above the detection
                  threshold.
        !*/

        void set_max_detections_per_template (
            unsigned long max_dets
        );
        /*!
            requires
                - max_dets > 0
            ensures
                - #get_max_detections_per_template() == max_dets
        !*/

        void detect (
            const feature_vector_type& w,
            std::vector<std::pair<double, rectangle> >& dets,
            const double thresh
        ) const;
        /*!
            requires
                - w.size() >= get_num_dimensions()
                - is_loaded_with_image() == true
                - get_num_detection_templates() > 0
            ensures
                - Scans all the detection templates over all pyramid layers as discussed in the
                  WHAT THIS OBJECT REPRESENTS section and stores all detections into #dets.
                - for all valid i:
                    - #dets[i].second == The object box which produced this detection.  This rectangle gives
                      the location of the detection.  Note that the rectangle will have been converted back into
                      the original image input space.  That is, if this detection was made at a low level in the
                      image pyramid then the object box will have been automatically mapped up the pyramid layers
                      to the original image space.  Or in other words, if you plot #dets[i].second on top of the
                      image given to load() it will show up in the right place.
                    - #dets[i].first == The score for this detection.  This value is equal to dot(w, feature vector
                      for this sliding window location).
                    - #dets[i].first >= thresh
                - #dets will be sorted in descending order. (i.e.  #dets[i].first >= #dets[j].first for all i, and j>i)
                - Elements of w beyond index get_num_dimensions()-1 are ignored.  I.e. only the first
                  get_num_dimensions() are used.
                - Note that no form of non-max suppression is performed.  If a window has a score >= thresh
                  then it is reported in #dets (assuming the limit imposed by get_max_detections_per_template() hasn't
                  been reached).
        !*/

        const rectangle get_best_matching_rect (
            const rectangle& rect
        ) const;
        /*!
            requires
                - get_num_detection_templates() > 0
            ensures
                - Since scan_image_pyramid is a sliding window classifier system, not all possible rectangles
                  can be represented.  Therefore, this function allows you to supply a rectangle and obtain the
                  nearest possible sliding window rectangle.
        !*/

        void get_feature_vector (
            const full_object_detection& obj,
            feature_vector_type& psi
        ) const;
        /*!
            requires
                - all_parts_in_rect(obj) == true
                - obj.num_parts() == get_num_movable_components_per_detection_template()
                - is_loaded_with_image() == true
                - get_num_detection_templates() > 0
                - psi.size() >= get_num_dimensions()
                  (i.e. psi must have preallocated its memory before this function is called)
            ensures
                - This function allows you to determine the feature vector used for a
                  sliding window location.  Note that this vector is added to psi.  Note
                  also that you must use get_full_object_detection() to convert a rect from
                  detect() into the needed full_object_detection.
                - The dimensionality of the vector added to psi is get_num_dimensions().  This
                  means that elements of psi after psi(get_num_dimensions()-1) are not modified.
                - Since scan_image_pyramid is a sliding window classifier system, not all
                  possible rectangles can be output by detect().  So in the case where
                  obj.get_rect() could not arise from a call to detect(), this function
                  will map obj.get_rect() to the nearest possible object box and then add
                  the feature vector for the mapped rectangle into #psi.
                - get_best_matching_rect(obj.get_rect()) == the rectangle obj.get_rect()
                  gets mapped to for feature extraction.
        !*/

        full_object_detection get_full_object_detection (
            const rectangle& rect,
            const feature_vector_type& w
        ) const;
        /*!
            requires
                - w.size() >= get_num_dimensions()
                - is_loaded_with_image() == true
                - get_num_detection_templates() > 0
            ensures
                - This function allows you to determine the full_object_detection
                  corresponding to a sliding window location.  Note that the detect()
                  routine doesn't return the locations of the movable parts in a detected
                  object.  Therefore, if you are using any movable parts in your model you
                  must use get_full_object_detection() to find out where the movable parts
                  were detected.  To do this, you supply the w and detected rectangle.
                  Then the corresponding fully populated full_object_detection will be
                  returned.
                - returns a full_object_detection, OBJ, such that:
                    - OBJ.get_rect() == rect
                    - OBJ.num_parts() == get_num_movable_components_per_detection_template()
                    - OBJ.part(i) == the location of the i-th movable part inside this detection,
                      or OBJECT_PART_NOT_PRESENT if the part was not found.
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename Feature_extractor_type
        >
    void serialize (
        const scan_image_pyramid<Pyramid_type,Feature_extractor_type>& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

    template <
        typename Pyramid_type,
        typename Feature_extractor_type
        >
    void deserialize (
        scan_image_pyramid<Pyramid_type,Feature_extractor_type>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SCAN_IMaGE_PYRAMID_ABSTRACT_Hh_


dlib C++ Library - setup_hashed_features_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SETUP_HAShED_FEATURES_ABSTRACT_Hh_
#ifdef DLIB_SETUP_HAShED_FEATURES_ABSTRACT_Hh_

#include "scan_image_pyramid_abstract.h"
#include "scan_image_boxes_abstract.h"
#include "../lsh/projection_hash_abstract.h"
#include "../image_keypoint/hashed_feature_image_abstract.h"
#include "../image_keypoint/binned_vector_feature_image_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class image_hash_construction_failure : public error
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is the exception object used by the routines in this file.
        !*/
    };

// ----------------------------------------------------------------------------------------

    template <
        typename image_scanner
        >
    void use_uniform_feature_weights (
        image_scanner& scanner
    );
    /*!
        requires
            - image_scanner should be either scan_image_pyramid or scan_image_boxes and
              should use the hashed_feature_image as its local feature extractor.
        ensures
            - #scanner.get_feature_extractor().uses_uniform_feature_weights() == true
              (i.e. Make the scanner's feature extractor use the uniform feature weighting
              scheme)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_scanner
        >
    void use_relative_feature_weights (
        image_scanner& scanner
    );
    /*!
        requires
            - image_scanner should be either scan_image_pyramid or scan_image_boxes and
              should use the hashed_feature_image as its local feature extractor.
        ensures
            - #scanner.get_feature_extractor().uses_uniform_feature_weights() == false
              (i.e. Make the scanner's feature extractor use the relative feature weighting
              scheme)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_array,
        typename pyramid,
        typename feature_extractor
        template <typename fe, typename hash> class feature_image
        >
    void setup_hashed_features (
        scan_image_pyramid<pyramid, feature_image<feature_extractor, projection_hash> >& scanner,
        const image_array& images,
        const feature_extractor& fe,
        int bits,
        unsigned long num_samples = 200000
    );
    /*!
        requires
            - 0 < bits <= 32
            - num_samples > 1
            - images.size() > 0
            - it must be valid to pass images[0] into scanner.load().
              (also, image_array must be an implementation of dlib/array/array_kernel_abstract.h)
            - feature_image == must be either hashed_feature_image, binned_vector_feature_image,
              or a type with a compatible interface.
        ensures
            - Creates a projection_hash suitable for hashing the feature vectors produced by
              fe and then configures scanner to use this hash function.
            - The hash function will map vectors into integers in the range [0, pow(2,bits))
            - The hash function will be setup so that it hashes a random sample of num_samples
              vectors from fe such that each bin ends up with roughly the same number of
              elements in it.
        throws
            - image_hash_construction_failure
              This exception is thrown if there is a problem creating the projection_hash.
              This should only happen the images are so small they contain less than 2
              feature vectors.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_array,
        typename pyramid,
        typename feature_extractor
        template <typename fe, typename hash> class feature_image
        >
    void setup_hashed_features (
        scan_image_pyramid<pyramid, feature_image<feature_extractor, projection_hash> >& scanner,
        const image_array& images,
        int bits,
        unsigned long num_samples = 200000
    );
    /*!
        requires
            - 0 < bits <= 32
            - num_samples > 1
            - images.size() > 0
            - it must be valid to pass images[0] into scanner.load().
              (also, image_array must be an implementation of dlib/array/array_kernel_abstract.h)
            - feature_image == must be either hashed_feature_image, binned_vector_feature_image,
              or a type with a compatible interface.
        ensures
            - performs: setup_hashed_features(scanner, images, feature_extractor(), bits, num_samples)
        throws
            - image_hash_construction_failure
              This exception is thrown if there is a problem creating the projection_hash.
              This should only happen the images are so small they contain less than 2
              feature vectors.
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename image_array,
        typename feature_extractor,
        template <typename fe, typename hash> class feature_image
        typename box_generator
        >
    void setup_hashed_features (
        scan_image_boxes<feature_image<feature_extractor, projection_hash>,box_generator>& scanner,
        const image_array& images,
        const feature_extractor& fe,
        int bits,
        unsigned long num_samples = 200000
    );
    /*!
        requires
            - 0 < bits <= 32
            - num_samples > 1
            - images.size() > 0
            - it must be valid to pass images[0] into scanner.load().
              (also, image_array must be an implementation of dlib/array/array_kernel_abstract.h)
            - feature_image == must be either hashed_feature_image, binned_vector_feature_image,
              or a type with a compatible interface.
        ensures
            - Creates a projection_hash suitable for hashing the feature vectors produced by
              fe and then configures scanner to use this hash function.
            - The hash function will map vectors into integers in the range [0, pow(2,bits))
            - The hash function will be setup so that it hashes a random sample of num_samples
              vectors from fe such that each bin ends up with roughly the same number of
              elements in it.
        throws
            - image_hash_construction_failure
              This exception is thrown if there is a problem creating the projection_hash.
              This should only happen the images are so small they contain less than 2
              feature vectors.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_array,
        typename feature_extractor,
        template <typename fe, typename hash> class feature_image
        typename box_generator
        >
    void setup_hashed_features (
        scan_image_boxes<feature_image<feature_extractor, projection_hash>,box_generator>& scanner,
        const image_array& images,
        int bits,
        unsigned long num_samples = 200000
    );
    /*!
        requires
            - 0 < bits <= 32
            - num_samples > 1
            - images.size() > 0
            - it must be valid to pass images[0] into scanner.load().
              (also, image_array must be an implementation of dlib/array/array_kernel_abstract.h)
            - feature_image == must be either hashed_feature_image, binned_vector_feature_image,
              or a type with a compatible interface.
        ensures
            - performs: setup_hashed_features(scanner, images, feature_extractor(), bits, num_samples)
        throws
            - image_hash_construction_failure
              This exception is thrown if there is a problem creating the projection_hash.
              This should only happen the images are so small they contain less than 2
              feature vectors.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SETUP_HAShED_FEATURES_ABSTRACT_Hh_


dlib C++ Library - box_overlap_testing_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_BOX_OVERlAP_TESTING_ABSTRACT_Hh_
#ifdef DLIB_BOX_OVERlAP_TESTING_ABSTRACT_Hh_

#include "../geometry.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class test_box_overlap
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is a simple function object for determining if two rectangles
                overlap.

            THREAD SAFETY
                Concurrent access to an instance of this object is safe provided that
                only const member functions are invoked.  Otherwise, access must be
                protected by a mutex lock.
        !*/

    public:
        test_box_overlap (
        );
        /*!
            ensures
                - #get_match_thresh()   == 0.5
                - #get_overlap_thresh() == 1.0
        !*/

        explicit test_box_overlap (
            double match_thresh,
            double overlap_thresh = 1.0
        );
        /*!
            requires
                - 0 <= match_thresh <= 1
                - 0 <= overlap_thresh <= 1
            ensures
                - #get_match_thresh() == match_thresh
                - #get_overlap_thresh() == overlap_thresh
        !*/

        bool operator() (
            const dlib::rectangle& a,
            const dlib::rectangle& b
        ) const;
        /*!
            ensures
                - returns true if a and b overlap "enough". This is defined precisely below.
                - if (a.intersect(b).area()/(a+b).area() > get_match_thresh() ||
                      a.intersect(b).area()/a.area()     > get_overlap_thresh() ||
                      a.intersect(b).area()/b.area()     > get_overlap_thresh() ) then
                    - returns true
                - else
                    - returns false
        !*/

        double get_match_thresh (
        ) const;
        /*!
            ensures
                - returns the threshold used to determine if two rectangles match.
                  Note that the match score varies from 0 to 1 and only becomes 1
                  when two rectangles are identical.

        !*/

        double get_overlap_thresh (
        ) const;
        /*!
            ensures
                - returns the threshold used to determine if two rectangles overlap.  This
                  value is the percent of a rectangle's area covered by another rectangle.

        !*/

    };

// ----------------------------------------------------------------------------------------

    void serialize (
        const test_box_overlap& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

    void deserialize (
        test_box_overlap& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// ----------------------------------------------------------------------------------------

    test_box_overlap find_tight_overlap_tester (
        const std::vector<std::vector<rectangle> >& rects
    );
    /*!
        ensures
            - This function finds the most restrictive test_box_overlap object possible
              that is consistent with the given set of sets of rectangles.
            - To be precise, this function finds and returns a test_box_overlap object
              TBO such that:
                - TBO.get_match_thresh() and TBO.get_overlap_thresh() are as small
                  as possible such that the following conditions are satisfied.
                - for all valid i:
                    - for all distinct rectangles A and B in rects[i]:
                        - TBO(A,B) == false
    !*/

// ----------------------------------------------------------------------------------------

    bool overlaps_any_box (
        const test_box_overlap& tester,
        const std::vector<rectangle>& rects,
        const rectangle& rect
    );
    /*!
        ensures
            - returns true if rect overlaps any box in rects and false otherwise.  Overlap
              is determined based on the given tester object.
    !*/

// ----------------------------------------------------------------------------------------

    bool overlaps_any_box (
        const std::vector<rectangle>& rects,
        const rectangle& rect
    );
    /*!
        ensures
            - returns overlaps_any_box(test_box_overlap(), rects, rect)
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_BOX_OVERlAP_TESTING_ABSTRACT_Hh_


dlib C++ Library - binned_vector_feature_image_abstract.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_BINNED_VECTOR_FEATUrES_ABSTRACT_Hh_
#ifdef DLIB_BINNED_VECTOR_FEATUrES_ABSTRACT_Hh_

#include "../lsh/projection_hash_abstract.h"
#include <vector>
#include "../matrix.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type_ = projection_hash
        >
    class binned_vector_feature_image : noncopyable
    {
        /*!
            REQUIREMENTS ON feature_extractor
                - must be an object with an interface compatible with dlib::hog_image

            REQUIREMENTS ON hash_function_type_
                - must be an object with an interface compatible with projection_hash

            INITIAL VALUE
                 - size() == 0

            WHAT THIS OBJECT REPRESENTS
                This object is a tool for performing image feature extraction.  In
                particular, it wraps another image feature extractor and converts the
                wrapped image feature vectors into a high dimensional sparse vector.  For
                example, if the lower level feature extractor outputs the vector [3,4,5]
                and this vector is hashed into the second bin of four bins then the output
                sparse vector is:
                    [0,0,0,0, 3,4,5,1, 0,0,0,0, 0,0,0,0].
                That is, the output vector has a dimensionality that is equal to the number
                of hash bins times the dimensionality of the lower level vector plus one.
                The value in the extra dimension concatenated onto the end of the vector is
                always a constant value of of 1 and serves as a bias value.  This means
                that, if there are N hash bins, these vectors are capable of representing N
                different linear functions, each operating on the vectors that fall into
                their corresponding hash bin.

            THREAD SAFETY
                Concurrent access to an instance of this object is not safe and should be
                protected by a mutex lock except for the case where you are copying the
                configuration (via copy_configuration()) of a binned_vector_feature_image
                object to many other threads.  In this case, it is safe to copy the
                configuration of a shared object so long as no other operations are
                performed on it.

            NOTATION
                let BASE_FE denote the base feature_extractor object contained inside the
                binned_vector_feature_image.
        !*/

    public:

        typedef feature_extractor feature_extractor_type;
        typedef hash_function_type_ hash_function_type;
        typedef std::vector<std::pair<unsigned int,double> > descriptor_type;

        binned_vector_feature_image (
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        void clear (
        );
        /*!
            ensures
                - this object will have its initial value
        !*/

        void set_hash (
            const hash_function_type& hash
        );
        /*!
            ensures
                - #get_hash() == hash
        !*/

        const hash_function_type& get_hash (
        ) const;
        /*!
            ensures
                - returns the hash function used by this object to hash
                  base feature vectors into integers.
        !*/

        void copy_configuration (
            const feature_extractor& item
        );
        /*!
            ensures
                - performs BASE_FE.copy_configuration(item)
        !*/

        void copy_configuration (
            const binned_vector_feature_image& item
        );
        /*!
            ensures
                - copies all the state information of item into *this, except for state
                  information populated by load().  More precisely, given two binned_vector_feature_image
                  objects H1 and H2, the following sequence of instructions should always
                  result in both of them having the exact same state.
                    H2.copy_configuration(H1);
                    H1.load(img);
                    H2.load(img);
        !*/

        template <
            typename image_type
            >
        void load (
            const image_type& img
        );
        /*!
            requires
                - image_type == any type that can be supplied to feature_extractor::load()
            ensures
                - performs BASE_FE.load(img)
                  i.e. does feature extraction.  The features can be accessed using
                  operator() as defined below.
        !*/

        unsigned long size (
        ) const;
        /*!
            ensures
                - returns BASE_FE.size()
        !*/

        long nr (
        ) const;
        /*!
            ensures
                - returns BASE_FE.nr()
        !*/

        long nc (
        ) const;
        /*!
            ensures
                - returns BASE_FE.nc()
        !*/

        long get_num_dimensions (
        ) const;
        /*!
            ensures
                - returns the dimensionality of the feature vectors returned by operator().
                  In this case, this is the number of hash bins times the dimensionality of
                  the features produced by BASE_FE plus one.  That is, this function
                  returns get_hash().num_hash_bins()*(BASE_FE.get_num_dimensions()+1)
        !*/

        const descriptor_type& operator() (
            long row,
            long col
        ) const;
        /*!
            requires
                - 0 <= row < nr()
                - 0 <= col < nc()
                - It must be legal to evaluate expressions of the form: get_hash()(BASE_FE(row,col))
                  (e.g. the hash function must be properly configured to process the feature
                  vectors produced by the base feature extractor)
            ensures
                - hashes BASE_FE(row,col) and returns the resulting sparse vector.  In
                  particular, we return a vector that is a copy of BASE_FE(row,col) that
                  has been shifted into the part of the sparse vector indicated by the hash
                  function.  It will also have a constant bias value of 1 appended to it.
                - To be precise, this function returns a sparse vector V such that:
                    - V.size() == BASE_FE.get_num_dimensions()+1
                    - let IDX = get_hash()(BASE_FE(row,col))
                    - for i where 0 <= i < BASE_FE.get_num_dimensions():
                        - V[i].first == IDX*(BASE_FE.get_num_dimensions()+1) + i
                        - V[i].second == BASE_FE(row,col)(i)
                    - V[BASE_FE.get_num_dimensions()].first == IDX*(BASE_FE.get_num_dimensions()+1) + BASE_FE.get_num_dimensions()
                    - V[BASE_FE.get_num_dimensions()].second == 1
        !*/

        const rectangle get_block_rect (
            long row,
            long col
        ) const;
        /*!
            ensures
                - returns BASE_FE.get_block_rect(row,col)
                  I.e. returns a rectangle that tells you what part of the original image is associated
                  with a particular feature vector.
        !*/

        const point image_to_feat_space (
            const point& p
        ) const;
        /*!
            ensures
                - returns BASE_FE.image_to_feat_space(p)
                  I.e. Each local feature is extracted from a certain point in the input image.
                  This function returns the identity of the local feature corresponding
                  to the image location p.  Or in other words, let P == image_to_feat_space(p),
                  then (*this)(P.y(),P.x()) == the local feature closest to, or centered at,
                  the point p in the input image.  Note that some image points might not have
                  corresponding feature locations.  E.g. border points or points outside the
                  image.  In these cases the returned point will be outside get_rect(*this).
        !*/

        const rectangle image_to_feat_space (
            const rectangle& rect
        ) const;
        /*!
            ensures
                - returns BASE_FE.image_to_feat_space(rect)
                  I.e. returns rectangle(image_to_feat_space(rect.tl_corner()), image_to_feat_space(rect.br_corner()));
                  (i.e. maps a rectangle from image space to feature space)
        !*/

        const point feat_to_image_space (
            const point& p
        ) const;
        /*!
            ensures
                - returns BASE_FE.feat_to_image_space(p)
                  I.e. returns the location in the input image space corresponding to the center
                  of the local feature at point p.  In other words, this function computes
                  the inverse of image_to_feat_space().  Note that it may only do so approximately,
                  since more than one image location might correspond to the same local feature.
                  That is, image_to_feat_space() might not be invertible so this function gives
                  the closest possible result.
        !*/

        const rectangle feat_to_image_space (
            const rectangle& rect
        ) const;
        /*!
            ensures
                - returns BASE_FE.feat_to_image_space(rect)
                  I.e. return rectangle(feat_to_image_space(rect.tl_corner()), feat_to_image_space(rect.br_corner()));
                  (i.e. maps a rectangle from feature space to image space)
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename U
        >
    void serialize (
        const binned_vector_feature_image<T,U>& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename U
        >
    void deserialize (
        binned_vector_feature_image<T,U>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_BINNED_VECTOR_FEATUrES_ABSTRACT_Hh_


dlib C++ Library - fhog_abstract.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_fHOG_ABSTRACT_Hh_
#ifdef DLIB_fHOG_ABSTRACT_Hh_

#include "../matrix/matrix_abstract.h"
#include "../array2d/array2d_kernel_abstract.h"
#include "../array/array_kernel_abstract.h"
#include "../image_processing/generic_image.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename image_type,
        typename T,
        typename mm
        >
    void extract_fhog_features(
        const image_type& img,
        array2d<matrix<T,31,1>,mm>& hog,
        int cell_size = 8,
        int filter_rows_padding = 1,
        int filter_cols_padding = 1
    );
    /*!
        requires
            - cell_size > 0
            - filter_rows_padding > 0
            - filter_cols_padding > 0
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - T should be float or double
        ensures
            - This function implements the HOG feature extraction method described in
              the paper:
                Object Detection with Discriminatively Trained Part Based Models by
                P. Felzenszwalb, R. Girshick, D. McAllester, D. Ramanan
                IEEE Transactions on Pattern Analysis and Machine Intelligence, Vol. 32, No. 9, Sep. 2010
              This means that it takes an input image img and outputs Felzenszwalb's
              31 dimensional version of HOG features, which are stored into #hog.
            - The input image is broken into cells that are cell_size by cell_size pixels
              and within each cell we compute a 31 dimensional FHOG vector.  This vector
              describes the gradient structure within the cell.
            - A common task is to convolve each channel of the hog image with a linear
              filter.  This is made more convenient if the contents of #hog includes extra
              rows and columns of zero padding along the borders.  This extra padding
              allows for more efficient convolution code since the code does not need to
              perform expensive boundary checking.  Therefore, you can set
              filter_rows_padding and filter_cols_padding to indicate the size of the
              filter you wish to use and this function will ensure #hog has the appropriate
              extra zero padding along the borders.  In particular, it will include the
              following extra padding:
                - (filter_rows_padding-1)/2 extra rows of zeros on the top of #hog.
                - (filter_cols_padding-1)/2 extra columns of zeros on the left of #hog.
                - filter_rows_padding/2 extra rows of zeros on the bottom of #hog.
                - filter_cols_padding/2 extra columns of zeros on the right of #hog.
              Therefore, the extra padding is done such that functions like
              spatially_filter_image() apply their filters to the entire content containing
              area of a hog image (note that you should use the following planar version of
              extract_fhog_features() instead of the interlaced version if you want to use
              spatially_filter_image() on a hog image).
            - #hog.nr() == max(round(img.nr()/(double)cell_size)-2,0) + filter_rows_padding-1.
            - #hog.nc() == max(round(img.nc()/(double)cell_size)-2,0) + filter_cols_padding-1.
              (i.e.  Each output dimension is roughly 1/cell_size the original size but
              there is a one cell_size border all around the image that is lost and then we
              add on any additional padding that is requested.)
            - for all valid r and c:
                - #hog[r][c] == the FHOG vector describing the cell centered at the pixel location
                  fhog_to_image(point(c,r),cell_size,filter_rows_padding,filter_cols_padding) in img.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type,
        typename T,
        typename mm1,
        typename mm2
        >
    void extract_fhog_features(
        const image_type& img,
        dlib::array<array2d<T,mm1>,mm2>& hog,
        int cell_size = 8,
        int filter_rows_padding = 1,
        int filter_cols_padding = 1
    );
    /*!
        requires
            - cell_size > 0
            - filter_rows_padding > 0
            - filter_cols_padding > 0
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - T should be float or double
        ensures
            - This function is identical to the above extract_fhog_features() routine
              except that it outputs the results in a planar format rather than the
              interlaced format used above.  That is, each element of the hog vector is
              placed into one of 31 images inside #hog.  To be precise, if vhog is the
              output of the above interlaced version of extract_fhog_features() then we
              will have, for all valid r and c:
                - #hog[i][r][c] == vhog[r][c](i)
                  (where 0 <= i < 31)
            - #hog.size() == 31
            - for all valid i:
                - #hog[i].nr() == hog[0].nr()
                - #hog[i].nc() == hog[0].nc()
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    matrix<double,0,1> extract_fhog_features(
        const image_type& img,
        int cell_size = 8,
        int filter_rows_padding = 1,
        int filter_cols_padding = 1
    );
    /*!
        requires
            - cell_size > 0
            - filter_rows_padding > 0
            - filter_cols_padding > 0
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
        ensures
            - This function calls the above extract_fhog_features() routine and simply
              packages the entire output into a dlib::matrix.  The matrix is constructed
              using the planar version of extract_fhog_features() and then each output
              plane is converted into a column vector and subsequently all 31 column
              vectors are concatenated together and returned.
            - Each plane is converted into a column vector using reshape_to_column_vector(),
              and is therefore represented in row major order inside the returned vector.
            - If H is the array<array2d<double>> object output by the planar
              extract_fhog_features() then the returned vector is composed by concatenating
              H[0], then H[1], then H[2], and so on in ascending index order.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type,
        typename T
        >
    void extract_fhog_features(
        const image_type& img,
        matrix<T,0,1>& feats,
        int cell_size = 8,
        int filter_rows_padding = 1,
        int filter_cols_padding = 1
    );
    /*!
        requires
            - cell_size > 0
            - filter_rows_padding > 0
            - filter_cols_padding > 0
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - T is float, double, or long double
        ensures
            - This function is identical to the above version of extract_fhog_features()
              that returns a matrix<double,0,1> except that it returns the matrix here
              through a reference argument instead of returning it by value.
    !*/

// ----------------------------------------------------------------------------------------

    inline point image_to_fhog (
        point p,
        int cell_size = 8,
        int filter_rows_padding = 1,
        int filter_cols_padding = 1
    );
    /*!
        requires
            - cell_size > 0
            - filter_rows_padding > 0
            - filter_cols_padding > 0
        ensures
            - When using extract_fhog_features(), each FHOG cell is extracted from a
              certain region in the input image.  image_to_fhog() returns the identity of
              the FHOG cell containing the image pixel at location p.  Or in other words,
              let P == image_to_fhog(p) and hog be a FHOG feature map output by
              extract_fhog_features(), then hog[P.y()][P.x()] == the FHOG vector/cell
              containing the point p in the input image.  Note that some image points
              might not have corresponding feature locations.  E.g. border points or points
              outside the image.  In these cases the returned point will be outside the
              input image.
            - Note that you should use the same values of cell_size, filter_rows_padding,
              and filter_cols_padding that you used with extract_fhog_features().
    !*/

// ----------------------------------------------------------------------------------------

    inline rectangle image_to_fhog (
        const rectangle& rect,
        int cell_size = 8,
        int filter_rows_padding = 1,
        int filter_cols_padding = 1
    );
    /*!
        requires
            - cell_size > 0
            - filter_rows_padding > 0
            - filter_cols_padding > 0
        ensures
            - maps a rectangle from image space to fhog space.  In particular this function returns:
              rectangle(image_to_fhog(rect.tl_corner(),cell_size,filter_rows_padding,filter_cols_padding),
                        image_to_fhog(rect.br_corner(),cell_size,filter_rows_padding,filter_cols_padding))
    !*/

// ----------------------------------------------------------------------------------------

    inline point fhog_to_image (
        point p,
        int cell_size = 8,
        int filter_rows_padding = 1,
        int filter_cols_padding = 1
    );
    /*!
        requires
            - cell_size > 0
            - filter_rows_padding > 0
            - filter_cols_padding > 0
        ensures
            - Maps a pixel in a FHOG image (produced by extract_fhog_features()) back to the
              corresponding original input pixel.  Note that since FHOG images are
              spatially downsampled by aggregation into cells the mapping is not totally
              invertible.  Therefore, the returned location will be the center of the cell
              in the original image that contained the FHOG vector at position p.  Moreover,
              cell_size, filter_rows_padding, and filter_cols_padding should be set to the
              values used by the call to extract_fhog_features().
            - Mapping from fhog space to image space is an invertible transformation.  That
              is, for any point P we have P == image_to_fhog(fhog_to_image(P,cell_size,filter_rows_padding,filter_cols_padding),
                                                             cell_size,filter_rows_padding,filter_cols_padding).
    !*/

// ----------------------------------------------------------------------------------------

    inline rectangle fhog_to_image (
        const rectangle& rect,
        int cell_size = 8,
        int filter_rows_padding = 1,
        int filter_cols_padding = 1
    );
    /*!
        requires
            - cell_size > 0
            - filter_rows_padding > 0
            - filter_cols_padding > 0
        ensures
            - maps a rectangle from fhog space to image space.  In particular this function returns:
              rectangle(fhog_to_image(rect.tl_corner(),cell_size,filter_rows_padding,filter_cols_padding),
                        fhog_to_image(rect.br_corner(),cell_size,filter_rows_padding,filter_cols_padding))
            - Mapping from fhog space to image space is an invertible transformation.  That
              is, for any rectangle R we have R == image_to_fhog(fhog_to_image(R,cell_size,filter_rows_padding,filter_cols_padding),
                                                                 cell_size,filter_rows_padding,filter_cols_padding).
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mm1,
        typename mm2
        >
    matrix<unsigned char> draw_fhog(
        const dlib::array<array2d<T,mm1>,mm2>& hog,
        const long cell_draw_size = 15
    );
    /*!
        requires
            - cell_draw_size > 0
            - hog.size() == 31
        ensures
            - Interprets hog as a FHOG feature map output by extract_fhog_features() and
              converts it into an image suitable for display on the screen.  In particular,
              we draw all the hog cells into a grayscale image in a way that shows the
              magnitude and orientation of the gradient energy in each cell.  The result is
              then returned.
            - The size of the cells in the output image will be rendered as cell_draw_size
              pixels wide and tall.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    matrix<unsigned char> draw_fhog (
        const std::vector<matrix<T> >& hog,
        const long cell_draw_size = 15
    );
    /*!
        requires
            - cell_draw_size > 0
            - hog.size() == 31
        ensures
            - This function just converts the given hog object into an array<array2d<T>>
              and passes it to the above draw_fhog() routine and returns the results.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mm
        >
    matrix<unsigned char> draw_fhog(
        const array2d<matrix<T,31,1>,mm>& hog,
        const long cell_draw_size = 15
    );
    /*!
        requires
            - cell_draw_size > 0
        ensures
            - Interprets hog as a FHOG feature map output by extract_fhog_features() and
              converts it into an image suitable for display on the screen.  In particular,
              we draw all the hog cells into a grayscale image in a way that shows the
              magnitude and orientation of the gradient energy in each cell.  The result is
              then returned.
            - The size of the cells in the output image will be rendered as cell_draw_size
              pixels wide and tall.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_fHOG_ABSTRACT_Hh_


dlib C++ Library - lbp_abstract.h

// Copyright (C) 2014  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_LBP_ABSTRACT_Hh_
#ifdef DLIB_LBP_ABSTRACT_Hh_

#include "../image_processing/generic_image.h"
#include "../pixel.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename image_type,
        typename image_type2
        >
    void make_uniform_lbp_image (
        const image_type& img,
        image_type2& lbp
    );
    /*!
        requires
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - image_type2 == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - image_type2 should contain a grayscale pixel type such as unsigned char.
        ensures
            - #lbp.nr() == img.nr()
            - #lbp.nc() == img.nc()
            - This function extracts the uniform local-binary-pattern feature at every pixel
              and stores it into #lbp.  In particular, we have the following for all valid
              r and c:
                - #lbp[r][c] == the uniform LBP for the 3x3 pixel window centered on img[r][c].
                  In particular, this is a value in the range 0 to 58 inclusive.
            - We use the idea of uniform LBPs from the paper:
                Face Description with Local Binary Patterns: Application to Face Recognition
                by Ahonen, Hadid, and Pietikainen.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type,
        typename T
        >
    void extract_histogram_descriptors (
        const image_type& img,
        const point& loc,
        std::vector<T>& histograms,
        const unsigned int cell_size = 10,
        const unsigned int block_size = 4,
        const unsigned int max_val = 58
    );
    /*!
        requires
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - image_type contains unsigned char valued pixels.
            - T is some scalar type like int or double
            - All pixel values in img are <= max_val
            - cell_size >= 1
            - block_size >= 1
            - max_val < 256
        ensures
            - This function extracts histograms of pixel values from block_size*block_size
              windows in the area in img immediately around img[loc.y()][loc.x()].  The
              histograms are appended onto the end of #histograms.  Each window is
              cell_size pixels wide and tall.  Moreover, the windows do not overlap.
            - #histograms.size() == histograms.size() + block_size*block_size*(max_val+1)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type,
        typename T
        >
    void extract_uniform_lbp_descriptors (
        const image_type& img,
        std::vector<T>& feats,
        const unsigned int cell_size = 10
    );
    /*!
        requires
            - cell_size >= 1
            - T is some scalar type like int or double
        ensures
            - Extracts histograms of uniform local-binary-patterns from img.  The
              histograms are from densely tiled windows that are cell_size pixels wide and
              tall.  The windows do not overlap and cover all of img.
            - #feats.size() == 59*(number of windows that fit into img)
              (i.e. #feats contains the LBP histograms)
            - We will have taken the square root of all the histogram elements.  That is,
              #feats[i] is the square root of the number of LBPs that appeared in its
              corresponding window.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type,
        typename T
        >
    void extract_highdim_face_lbp_descriptors (
        const image_type& img,
        const full_object_detection& det,
        std::vector<T>& feats
    );
    /*!
        requires
            - T is some scalar type like int or double
            - det.num_parts() == 68
        ensures
            - This function extracts the high-dimensional LBP feature described in the
              paper:
                Blessing of Dimensionality: High-dimensional Feature and Its Efficient
                Compression for Face Verification by Dong Chen, Xudong Cao, Fang Wen, and
                Jian Sun
            - #feats == the high-dimensional LBP descriptor.  It is the concatenation of
              many LBP histograms, each extracted from different scales and from different
              windows around different face landmarks.  We also take the square root of
              each histogram element before storing it into #feats.
            - #feats.size() == 99120
            - This function assumes img has already been aligned and normalized to a
              standard size.
            - This function assumes det contains a human face detection with face parts
              annotated using the annotation scheme from the iBUG 300-W face landmark
              dataset.  This means that det.part(i) gives the locations of different face
              landmarks according to the iBUG 300-W annotation scheme.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_LBP_ABSTRACT_Hh_


dlib C++ Library - fine_hog_image_abstract.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_FINE_HOG_IMaGE_ABSTRACT_Hh_
#ifdef DLIB_FINE_HOG_IMaGE_ABSTRACT_Hh_

#include "../array2d.h"
#include "../matrix.h"
#include "hog_abstract.h"

namespace dlib
{
    template <
        unsigned long cell_size_,
        unsigned long block_size_,
        unsigned long pixel_stride_,
        unsigned char num_orientation_bins_,
        int           gradient_type_
        >
    class fine_hog_image : noncopyable
    {
        /*!
            REQUIREMENTS ON TEMPLATE PARAMETERS
                - cell_size_ > 1
                - block_size_ > 0
                - pixel_stride_ > 0
                - num_orientation_bins_ > 0
                - gradient_type_ == hog_signed_gradient or hog_unsigned_gradient

            INITIAL VALUE
                 - size() == 0

            WHAT THIS OBJECT REPRESENTS
                This object is a version of the hog_image that allows you to extract HOG
                features at a finer resolution.  The hog_image can only extract HOG features
                cell_size_ pixels apart.  However, this object, the fine_hog_image can
                extract HOG features from every pixel location.

                The template arguments to this class have the same meaning as they do for
                the hog_image, except for pixel_stride_.  This controls the stepping between
                HOG extraction locations.  A value of 1 indicates HOG features should be
                extracted from every pixel location.  A value of 2 indicates every other pixel
                location, etc.

                Finally, note that the interpolation used by this object is equivalent
                to using hog_angle_interpolation with hog_image.

            THREAD SAFETY
                Concurrent access to an instance of this object is not safe and should be protected
                by a mutex lock except for the case where you are copying the configuration
                (via copy_configuration()) of a fine_hog_image object to many other threads.
                In this case, it is safe to copy the configuration of a shared object so long
                as no other operations are performed on it.
        !*/

    public:

        const static unsigned long cell_size = cell_size_;
        const static unsigned long block_size = block_size_;
        const static unsigned long pixel_stride = pixel_stride_;
        const static unsigned long num_orientation_bins = num_orientation_bins_;
        const static int           gradient_type = gradient_type_;

        const static long min_size = cell_size*block_size+2;

        typedef matrix<double, block_size*block_size*num_orientation_bins, 1> descriptor_type;

        fine_hog_image (
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        void clear (
        );
        /*!
            ensures
                - this object will have its initial value
        !*/

        void copy_configuration (
            const fine_hog_image&
        );
        /*!
            ensures
                - copies all the state information of item into *this, except for state
                  information populated by load().  More precisely, given two fine_hog_image
                  objects H1 and H2, the following sequence of instructions should always
                  result in both of them having the exact same state.
                    H2.copy_configuration(H1);
                    H1.load(img);
                    H2.load(img);
        !*/

        template <
            typename image_type
            >
        inline void load (
            const image_type& img
        );
        /*!
            requires
                - image_type is a dlib::matrix or something convertible to a matrix
                  via mat()
                - pixel_traits<typename image_traits<image_type>::pixel_type>::has_alpha == false
            ensures
                - if (img.nr() < min_size || img.nc() < min_size) then
                    - the image is too small so we don't compute anything on it
                    - #size() == 0
                - else
                    - generates a HOG image from the given image.
                    - #size() > 0
        !*/

        inline void unload(
        );
        /*!
            ensures
                - #nr() == 0
                - #nc() == 0
                - clears only the state information which is populated by load().  For
                  example, let H be a fine_hog_image object.  Then consider the two
                  sequences of instructions:
                    Sequence 1:
                        H.load(img);
                        H.unload();
                        H.load(img);

                    Sequence 2:
                        H.load(img);
                  Both sequence 1 and sequence 2 should have the same effect on H.
        !*/

        inline unsigned long size (
        ) const;
        /*!
            ensures
                - returns nr()*nc()
        !*/

        inline long nr (
        ) const;
        /*!
            ensures
                - returns the number of rows in this HOG image
        !*/

        inline long nc (
        ) const;
        /*!
            ensures
                - returns the number of columns in this HOG image
        !*/

        long get_num_dimensions (
        ) const;
        /*!
            ensures
                - returns the number of dimensions in the feature vectors generated by
                  this object.
                - In particular, returns the value block_size*block_size*num_orientation_bins
        !*/

        inline const descriptor_type& operator() (
            long row,
            long col
        ) const;
        /*!
            requires
                - 0 <= row < nr()
                - 0 <= col < nc()
            ensures
                - returns the descriptor for the HOG block at the given row and column.  This descriptor
                  will include information from a window that is located at get_block_rect(row,col) in
                  the original image given to load().
                - The returned descriptor vector will have get_num_dimensions() elements.
        !*/

        const rectangle get_block_rect (
            long row,
            long col
        ) const;
        /*!
            ensures
                - returns a rectangle that tells you what part of the original image is associated
                  with a particular HOG block.  That is, what part of the input image is associated
                  with (*this)(row,col).
                - The returned rectangle will be cell_size*block_size pixels wide and tall.
        !*/

        const point image_to_feat_space (
            const point& p
        ) const;
        /*!
            ensures
                - Each local feature is extracted from a certain point in the input image.
                  This function returns the identity of the local feature corresponding
                  to the image location p.  Or in other words, let P == image_to_feat_space(p),
                  then (*this)(P.y(),P.x()) == the local feature closest to, or centered at,
                  the point p in the input image.  Note that some image points might not have
                  corresponding feature locations.  E.g. border points or points outside the
                  image.  In these cases the returned point will be outside get_rect(*this).
        !*/

        const rectangle image_to_feat_space (
            const rectangle& rect
        ) const;
        /*!
            ensures
                - returns rectangle(image_to_feat_space(rect.tl_corner()), image_to_feat_space(rect.br_corner()));
                  (i.e. maps a rectangle from image space to feature space)
        !*/

        const point feat_to_image_space (
            const point& p
        ) const;
        /*!
            ensures
                - returns the location in the input image space corresponding to the center
                  of the local feature at point p.  In other words, this function computes
                  the inverse of image_to_feat_space().  Note that it may only do so approximately,
                  since more than one image location might correspond to the same local feature.
                  That is, image_to_feat_space() might not be invertible so this function gives
                  the closest possible result.
        !*/

        const rectangle feat_to_image_space (
            const rectangle& rect
        ) const;
        /*!
            ensures
                - return rectangle(feat_to_image_space(rect.tl_corner()), feat_to_image_space(rect.br_corner()));
                  (i.e. maps a rectangle from feature space to image space)
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <
        unsigned long T1,
        unsigned long T2,
        unsigned long T3,
        unsigned char T4,
        int           T5
        >
    void serialize (
        const fine_hog_image<T1,T2,T3,T4,T5>& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

    template <
        unsigned long T1,
        unsigned long T2,
        unsigned long T3,
        unsigned char T4,
        int           T5
        >
    void deserialize (
        fine_hog_image<T1,T2,T3,T4,T5>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_FINE_HOG_IMaGE_ABSTRACT_Hh_


dlib C++ Library - surf_abstract.h

// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SURf_ABSTRACT_H_
#ifdef DLIB_SURf_ABSTRACT_H_

#include "hessian_pyramid_abstract.h"
#include "../geometry/vector_abstract.h"
#include "../matrix/matrix_abstract.h"
#include "../image_processing/generic_image.h"

namespace dlib
{
    /*
        The functions in this file implement the components of the SURF algorithm
        for extracting scale invariant feature descriptors from images.

        For the full story on what this algorithm does and how it works
        you should refer to the following papers.

        This is the original paper which introduced the algorithm:
            SURF: Speeded Up Robust Features
            By Herbert Bay, Tinne Tuytelaars, and Luc Van Gool

        This paper provides a nice detailed overview of how the algorithm works:
            Notes on the OpenSURF Library by Christopher Evans
    */

// ----------------------------------------------------------------------------------------

    double gaussian (
        double x,
        double y,
        double sig
    );
    /*!
        requires
            - sig > 0
        ensures
            - computes and returns the value of a 2D Gaussian function with mean 0
              and standard deviation sig at the given (x,y) point.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename integral_image_type, typename T>
    double compute_dominant_angle (
        const integral_image_type& img,
        const dlib::vector<T,2>& center,
        const double& scale
    );
    /*!
        requires
            - integral_image_type == an object such as dlib::integral_image or another
              type that implements the interface defined in image_transforms/integral_image_abstract.h
            - scale > 0
            - get_rect(img).contains(centered_rect(center, 17*scale, 17*scale)) == true
              (i.e. center can't be within 17*scale pixels of the edge of the image)
        ensures
            - computes and returns the dominant angle (i.e. the angle of the dominant gradient)
              at the given center point and scale in img.
            - The returned angle is in radians.  Specifically, if the angle is described by
              a vector vect then the angle is exactly the value of std::atan2(vect.y(), vect.x())
    !*/

// ----------------------------------------------------------------------------------------

    template <typename integral_image_type, typename T, typename MM, typename L>
    void compute_surf_descriptor (
        const integral_image_type& img,
        const dlib::vector<T,2>& center,
        const double scale,
        const double angle,
        matrix<double,64,1,MM,L>& des
    )
    /*!
        requires
            - integral_image_type == an object such as dlib::integral_image or another
              type that implements the interface defined in image_transforms/integral_image_abstract.h
            - scale > 0
            - get_rect(img).contains(centered_rect(center, 32*scale, 32*scale)) == true
              (i.e. center can't be within 32*scale pixels of the edge of the image)
        ensures
            - computes the 64 dimensional SURF descriptor vector of a box centered
              at the given center point, tilted at an angle determined by the given
              angle, and sized according to the given scale.
            - #des == the computed SURF descriptor vector extracted from the img object.
            - The angle is measured in radians and measures the degree of counter-clockwise
              rotation around the center point.  This is the same kind of rotation as is
              performed by the dlib::rotate_point() function.
    !*/

// ----------------------------------------------------------------------------------------

    struct surf_point
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object represents a detected SURF point.  The meanings of
                its fields are defined below in the get_surf_points() function.
        !*/

        interest_point p;
        matrix<double,64,1> des;
        double angle;
    };

// ----------------------------------------------------------------------------------------

    void serialize (
        const surf_point& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

    void deserialize (
        surf_point& item,
        std::istream& in
    );
    /*!
        provides serialization support
    !*/

// ----------------------------------------------------------------------------------------

    template <typename image_type>
    const std::vector<surf_point> get_surf_points (
        const image_type& img,
        long max_points = 10000,
        double detection_threshold = 30.0
    );
    /*!
        requires
            - max_points > 0
            - detection_threshold >= 0
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - Let P denote the type of pixel in img, then we require:
                - pixel_traits<P>::has_alpha == false
        ensures
            - This function runs the complete SURF algorithm on the given input image and
              returns the points it found.
            - returns a vector V such that:
                - V.size() <= max_points
                - for all valid i:
                    - V[i] == a SURF point found in the given input image img
                    - V[i].p == the interest_point extracted from the hessian pyramid for this
                      SURF point.
                    - V[i].des == the SURF descriptor for this point (calculated using
                      compute_surf_descriptor())
                    - V[i].angle == the angle of the SURF box at this point (calculated using
                      compute_dominant_angle())
                    - V[i].p.score >= detection_threshold
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SURf_ABSTRACT_H_


dlib C++ Library - hashed_feature_image_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_HASHED_IMAGE_FEATUrES_ABSTRACT_Hh_
#ifdef DLIB_HASHED_IMAGE_FEATUrES_ABSTRACT_Hh_

#include "../lsh/projection_hash_abstract.h"
#include <vector>
#include "../matrix.h"
#include "../statistics.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type_ = projection_hash
        >
    class hashed_feature_image : noncopyable
    {
        /*!
            REQUIREMENTS ON feature_extractor
                - must be an object with an interface compatible with dlib::hog_image

            REQUIREMENTS ON hash_function_type_
                - must be an object with an interface compatible with projection_hash

            INITIAL VALUE
                 - size() == 0
                 - uses_uniform_feature_weights() == false

            WHAT THIS OBJECT REPRESENTS
                This object is a tool for performing image feature extraction.  In
                particular, it wraps another image feature extractor and converts the
                wrapped image feature vectors into sparse indicator vectors.  It does this
                by hashing each feature vector into the range [0, get_num_dimensions()-1]
                and then returns a new vector which is zero everywhere except for the
                position determined by the hash.

            THREAD SAFETY
                Concurrent access to an instance of this object is not safe and should be protected
                by a mutex lock except for the case where you are copying the configuration
                (via copy_configuration()) of a hashed_feature_image object to many other threads.
                In this case, it is safe to copy the configuration of a shared object so long
                as no other operations are performed on it.

            NOTATION
                let BASE_FE denote the base feature_extractor object contained inside
                the hashed_feature_image.
        !*/

    public:

        typedef feature_extractor feature_extractor_type;
        typedef hash_function_type_ hash_function_type;
        typedef std::vector<std::pair<unsigned int,double> > descriptor_type;

        hashed_feature_image (
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        void clear (
        );
        /*!
            ensures
                - this object will have its initial value
        !*/

        void set_hash (
            const hash_function_type& hash
        );
        /*!
            ensures
                - #get_hash() == hash
        !*/

        const hash_function_type& get_hash (
        ) const;
        /*!
            ensures
                - returns the hash function used by this object to hash
                  base feature vectors into integers.
        !*/

        void copy_configuration (
            const feature_extractor& item
        );
        /*!
            ensures
                - performs BASE_FE.copy_configuration(item)
        !*/

        void copy_configuration (
            const hashed_feature_image& item
        );
        /*!
            ensures
                - copies all the state information of item into *this, except for state
                  information populated by load().  More precisely, given two hashed_feature_image
                  objects H1 and H2, the following sequence of instructions should always
                  result in both of them having the exact same state.
                    H2.copy_configuration(H1);
                    H1.load(img);
                    H2.load(img);
        !*/

        template <
            typename image_type
            >
        void load (
            const image_type& img
        );
        /*!
            requires
                - image_type == any type that can be supplied to feature_extractor::load()
            ensures
                - performs BASE_FE.load(img)
                  i.e. does feature extraction.  The features can be accessed using
                  operator() as defined below.
        !*/

        unsigned long size (
        ) const;
        /*!
            ensures
                - returns BASE_FE.size()
        !*/

        long nr (
        ) const;
        /*!
            ensures
                - returns BASE_FE.nr()
        !*/

        long nc (
        ) const;
        /*!
            ensures
                - returns BASE_FE.nc()
        !*/

        long get_num_dimensions (
        ) const;
        /*!
            ensures
                - returns the dimensionality of the feature vectors returned by operator().
                  In this case, this is the number of hash bins.  That is, get_hash().num_hash_bins()
        !*/

        void use_relative_feature_weights (
        );
        /*!
            ensures
                - #uses_uniform_feature_weights() == false
        !*/

        void use_uniform_feature_weights (
        );
        /*!
            ensures
                - #uses_uniform_feature_weights() == true
        !*/

        bool uses_uniform_feature_weights (
        ) const;
        /*!
            ensures
                - returns true if this object weights each feature with a value of 1 and
                  false if it uses a weighting of 1/N where N is the number of occurrences
                  of the feature in an image (note that we normalize N so that it is
                  invariant to the size of the image given to load()).
        !*/

        const descriptor_type& operator() (
            long row,
            long col
        ) const;
        /*!
            requires
                - 0 <= row < nr()
                - 0 <= col < nc()
                - It must be legal to evaluate expressions of the form: get_hash()(BASE_FE(row,col))
                  (e.g. the hash function must be properly configured to process the feature
                  vectors produced by the base feature extractor)
            ensures
                - hashes BASE_FE(row,col) and returns the resulting indicator vector.
                - To be precise, this function returns a sparse vector V such that:
                    - V.size() == 1
                    - V[0].first == get_hash()(BASE_FE(row,col))
                    - if (uses_uniform_feature_weights()) then
                        - V[0].second == 1
                    - else
                        - V[0].second == 1/N where N is the number of times a feature in
                          hash bin V[0].first was observed in the image given to load().
                          Note that we scale all the counts so that they are invariant to
                          the size of the image.
        !*/

        const rectangle get_block_rect (
            long row,
            long col
        ) const;
        /*!
            ensures
                - returns BASE_FE.get_block_rect(row,col)
                  I.e. returns a rectangle that tells you what part of the original image is associated
                  with a particular feature vector.
        !*/

        const point image_to_feat_space (
            const point& p
        ) const;
        /*!
            ensures
                - returns BASE_FE.image_to_feat_space(p)
                  I.e. Each local feature is extracted from a certain point in the input image.
                  This function returns the identity of the local feature corresponding
                  to the image location p.  Or in other words, let P == image_to_feat_space(p),
                  then (*this)(P.y(),P.x()) == the local feature closest to, or centered at,
                  the point p in the input image.  Note that some image points might not have
                  corresponding feature locations.  E.g. border points or points outside the
                  image.  In these cases the returned point will be outside get_rect(*this).
        !*/

        const rectangle image_to_feat_space (
            const rectangle& rect
        ) const;
        /*!
            ensures
                - returns BASE_FE.image_to_feat_space(rect)
                  I.e. returns rectangle(image_to_feat_space(rect.tl_corner()), image_to_feat_space(rect.br_corner()));
                  (i.e. maps a rectangle from image space to feature space)
        !*/

        const point feat_to_image_space (
            const point& p
        ) const;
        /*!
            ensures
                - returns BASE_FE.feat_to_image_space(p)
                  I.e. returns the location in the input image space corresponding to the center
                  of the local feature at point p.  In other words, this function computes
                  the inverse of image_to_feat_space().  Note that it may only do so approximately,
                  since more than one image location might correspond to the same local feature.
                  That is, image_to_feat_space() might not be invertible so this function gives
                  the closest possible result.
        !*/

        const rectangle feat_to_image_space (
            const rectangle& rect
        ) const;
        /*!
            ensures
                - returns BASE_FE.feat_to_image_space(rect)
                  I.e. return rectangle(feat_to_image_space(rect.tl_corner()), feat_to_image_space(rect.br_corner()));
                  (i.e. maps a rectangle from feature space to image space)
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename U
        >
    void serialize (
        const hashed_feature_image<T,U>& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename U
        >
    void deserialize (
        hashed_feature_image<T,U>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_HASHED_IMAGE_FEATUrES_ABSTRACT_Hh_


dlib C++ Library - hog_abstract.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_HoG_ABSTRACT_Hh_
#ifdef DLIB_HoG_ABSTRACT_Hh_

#include "../algs.h"
#include "../matrix.h"
#include "../array2d.h"
#include "../geometry.h"
#include <cmath>

namespace dlib
{
    enum
    {
        hog_no_interpolation,
        hog_angle_interpolation,
        hog_full_interpolation,
        hog_signed_gradient,
        hog_unsigned_gradient
    };

    template <
        unsigned long cell_size_,
        unsigned long block_size_,
        unsigned long cell_stride_,
        unsigned long num_orientation_bins_,
        int           gradient_type_,
        int           interpolation_type_
        >
    class hog_image : noncopyable
    {
        /*!
            REQUIREMENTS ON TEMPLATE PARAMETERS
                - cell_size_ > 1
                - block_size_ > 0
                - cell_stride_ > 0
                - num_orientation_bins_ > 0
                - gradient_type_ == hog_signed_gradient or hog_unsigned_gradient
                - interpolation_type_ == hog_no_interpolation, hog_angle_interpolation, or
                                         hog_full_interpolation

            INITIAL VALUE
                 - size() == 0

            WHAT THIS OBJECT REPRESENTS
                This object is a tool for performing the image feature extraction algorithm
                described in the following paper:
                    Histograms of Oriented Gradients for Human Detection
                    by Navneet Dalal and Bill Triggs

                To summarize the technique, this object tiles non-overlapping cells over an
                image.  Each of these cells is a box that is cell_size by cell_size pixels
                in size.  Each cell contains an array of size num_orientation_bins.  The array
                in a cell is used to store a histogram of all the edge orientations contained
                within the cell's image region.

                Once the grid of cells and their histograms has been computed (via load())
                you can obtain descriptors for each "block" in the image.  A block is just a
                group of cells and blocks are allowed to overlap.  Each block is square and
                made up of block_size*block_size cells.  So when you call operator()(r,c)
                what you obtain is a vector that is just a bunch of cell histograms that
                have been concatenated (and length normalized).

                The template arguments control the various parameters of this algorithm.

                The interpolation_type parameter controls the amount of interpolation
                that happens during the creation of the edge orientation histograms.  It
                varies from no interpolation at all to full spatial and angle interpolation.

                Angle interpolation means that an edge doesn't just go into its nearest
                histogram bin but instead gets interpolated into its two nearest neighbors.
                Similarly, spatial interpolation means that an edge doesn't just go into
                the cell it is in but it also contributes to nearby cells depending on how
                close they are.

                The gradient_type parameter controls how edge orientations are measured.
                Consider the following ASCII art:
                    signed gradients:           unsigned gradients:
                           /\                           |
                           ||                           |
                       <---  ---->                ------+------
                           ||                           |
                           \/                           |

                An image is full of gradients caused by edges between objects.  The direction
                of a gradient is determined by which end of it has pixels of highest intensity.
                So for example, suppose you had a picture containing black and white stripes.
                Then the magnitude of the gradient at each point in the image tells you if you
                are on the edge of a stripe and the gradient's orientation tells you which
                direction you have to move get into the white stripe.

                Signed gradients preserve this direction information while unsigned gradients
                do not.  An unsigned gradient will only tell you the orientation of the stripe
                but not which direction leads to the white stripe.

                Finally, the cell_stride parameter controls how much overlap you get between
                blocks.  The maximum amount of overlap is obtained when cell_stride == 1.
                At the other extreme, you would have no overlap if cell_stride == block_size.

            THREAD SAFETY
                Concurrent access to an instance of this object is not safe and should be protected
                by a mutex lock except for the case where you are copying the configuration
                (via copy_configuration()) of a hog_image object to many other threads.
                In this case, it is safe to copy the configuration of a shared object so long
                as no other operations are performed on it.
        !*/

    public:

        const static unsigned long cell_size = cell_size_;
        const static unsigned long block_size = block_size_;
        const static unsigned long cell_stride = cell_stride_;
        const static unsigned long num_orientation_bins = num_orientation_bins_;
        const static int           gradient_type = gradient_type_;
        const static int           interpolation_type = interpolation_type_;

        const static long min_size = cell_size*block_size+2;

        typedef matrix<double, block_size*block_size*num_orientation_bins, 1> descriptor_type;

        hog_image (
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        void clear (
        );
        /*!
            ensures
                - this object will have its initial value
        !*/

        void copy_configuration (
            const hog_image& item
        );
        /*!
            ensures
                - copies all the state information of item into *this, except for state
                  information populated by load().  More precisely, given two hog_image
                  objects H1 and H2, the following sequence of instructions should always
                  result in both of them having the exact same state.
                    H2.copy_configuration(H1);
                    H1.load(img);
                    H2.load(img);
        !*/

        template <
            typename image_type
            >
        inline void load (
            const image_type& img
        );
        /*!
            requires
                - image_type is a dlib::matrix or something convertible to a matrix
                  via mat().
                - pixel_traits<typename image_traits<image_type>::pixel_type>::has_alpha == false
            ensures
                - if (img.nr() < min_size || img.nc() < min_size) then
                    - the image is too small so we don't compute anything on it
                    - #size() == 0
                - else
                    - generates a HOG image from the given image.
                    - #size() > 0
        !*/

        inline void unload (
        );
        /*!
            ensures
                - #nr() == 0
                - #nc() == 0
                - clears only the state information which is populated by load().  For
                  example, let H be a hog_image object.  Then consider the two sequences
                  of instructions:
                    Sequence 1:
                        H.load(img);
                        H.unload();
                        H.load(img);

                    Sequence 2:
                        H.load(img);
                  Both sequence 1 and sequence 2 should have the same effect on H.
        !*/

        inline unsigned long size (
        ) const;
        /*!
            ensures
                - returns nr()*nc()
        !*/

        inline long nr (
        ) const;
        /*!
            ensures
                - returns the number of rows in this HOG image
        !*/

        inline long nc (
        ) const;
        /*!
            ensures
                - returns the number of columns in this HOG image
        !*/

        long get_num_dimensions (
        ) const;
        /*!
            ensures
                - returns the number of dimensions in the feature vectors generated by
                  this object.
                - In particular, returns the value block_size*block_size*num_orientation_bins
        !*/

        inline const descriptor_type& operator() (
            long row,
            long col
        ) const;
        /*!
            requires
                - 0 <= row < nr()
                - 0 <= col < nc()
            ensures
                - returns the descriptor for the HOG block at the given row and column.  This descriptor
                  will include information from a window that is located at get_block_rect(row,col) in
                  the original image given to load().
                - The returned descriptor vector will have get_num_dimensions() elements.
        !*/

        const rectangle get_block_rect (
            long row,
            long col
        ) const;
        /*!
            ensures
                - returns a rectangle that tells you what part of the original image is associated
                  with a particular HOG block.  That is, what part of the input image is associated
                  with (*this)(row,col).
                - The returned rectangle will be cell_size*block_size pixels wide and tall.
        !*/

        const point image_to_feat_space (
            const point& p
        ) const;
        /*!
            ensures
                - Each local feature is extracted from a certain point in the input image.
                  This function returns the identity of the local feature corresponding
                  to the image location p.  Or in other words, let P == image_to_feat_space(p),
                  then (*this)(P.y(),P.x()) == the local feature closest to, or centered at,
                  the point p in the input image.  Note that some image points might not have
                  corresponding feature locations.  E.g. border points or points outside the
                  image.  In these cases the returned point will be outside get_rect(*this).
        !*/

        const rectangle image_to_feat_space (
            const rectangle& rect
        ) const;
        /*!
            ensures
                - returns rectangle(image_to_feat_space(rect.tl_corner()), image_to_feat_space(rect.br_corner()));
                  (i.e. maps a rectangle from image space to feature space)
        !*/

        const point feat_to_image_space (
            const point& p
        ) const;
        /*!
            ensures
                - returns the location in the input image space corresponding to the center
                  of the local feature at point p.  In other words, this function computes
                  the inverse of image_to_feat_space().  Note that it may only do so approximately,
                  since more than one image location might correspond to the same local feature.
                  That is, image_to_feat_space() might not be invertible so this function gives
                  the closest possible result.
        !*/

        const rectangle feat_to_image_space (
            const rectangle& rect
        ) const;
        /*!
            ensures
                - return rectangle(feat_to_image_space(rect.tl_corner()), feat_to_image_space(rect.br_corner()));
                  (i.e. maps a rectangle from feature space to image space)
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <
        unsigned long T1,
        unsigned long T2,
        unsigned long T3,
        unsigned long T4,
        int           T5,
        int           T6
        >
    void serialize (
        const hog_image<T1,T2,T3,T4,T5,T6>& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

    template <
        unsigned long T1,
        unsigned long T2,
        unsigned long T3,
        unsigned long T4,
        int           T5,
        int           T6
        >
    void deserialize (
        hog_image<T1,T2,T3,T4,T5,T6>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_HoG_ABSTRACT_Hh_


dlib C++ Library - nearest_neighbor_feature_image_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_NEAREST_NEIGHBOR_FeATURE_IMAGE_ABSTRACT_Hh_
#ifdef DLIB_NEAREST_NEIGHBOR_FeATURE_IMAGE_ABSTRACT_Hh_

#include <vector>
#include "../algs.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    class nearest_neighbor_feature_image : noncopyable
    {
        /*!
            REQUIREMENTS ON feature_extractor
                - must be an object with an interface compatible with dlib::hog_image

            INITIAL VALUE
                 - size() == 0
                 - get_num_dimensions() == 0

            WHAT THIS OBJECT REPRESENTS
                This object is a tool for performing image feature extraction.  In
                particular, it wraps another image feature extractor and converts
                the wrapped image feature vectors into sparse indicator vectors.  It does
                this by finding the nearest neighbor for each feature vector and returning an
                indicator vector that is zero everywhere except for the position indicated by
                the nearest neighbor.

            THREAD SAFETY
                Concurrent access to an instance of this object is not safe and should be protected
                by a mutex lock except for the case where you are copying the configuration
                (via copy_configuration()) of a nearest_neighbor_feature_image object to many other
                threads.  In this case, it is safe to copy the configuration of a shared object so
                long as no other operations are performed on it.

            NOTATION
                let BASE_FE denote the base feature_extractor object contained inside
                the nearest_neighbor_feature_image.
        !*/

    public:

        typedef std::vector<std::pair<unsigned int,double> > descriptor_type;

        nearest_neighbor_feature_image (
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        void clear (
        );
        /*!
            ensures
                - this object will have its initial value
        !*/

        void copy_configuration (
            const feature_extractor& item
        );
        /*!
            ensures
                - performs BASE_FE.copy_configuration(item)
        !*/

        void copy_configuration (
            const nearest_neighbor_feature_image& item
        );
        /*!
            ensures
                - copies all the state information of item into *this, except for state
                  information populated by load().  More precisely, given two
                  nearest_neighbor_feature_image objects H1 and H2, the following sequence
                  of instructions should always result in both of them having the exact
                  same state.
                    H2.copy_configuration(H1);
                    H1.load(img);
                    H2.load(img);
        !*/

        template <
            typename image_type
            >
        inline void load (
            const image_type& img
        );
        /*!
            requires
                - image_type == any type that can be supplied to feature_extractor::load()
            ensures
                - performs BASE_FE.load(img)
                  i.e. does feature extraction.  The features can be accessed using
                  operator() as defined below.
        !*/

        inline unsigned long size (
        ) const;
        /*!
            ensures
                - returns BASE_FE.size()
        !*/

        inline long nr (
        ) const;
        /*!
            ensures
                - returns BASE_FE.nr()
        !*/

        inline long nc (
        ) const;
        /*!
            ensures
                - returns BASE_FE.nc()
        !*/

        inline long get_num_dimensions (
        ) const;
        /*!
            ensures
                - returns the dimensionality of the feature vectors returned by operator().
                  In this case, this is the number of basis elements.  That is, it is the number
                  of vectors given to the set_basis() member function.
        !*/

        template <typename vector_type>
        void set_basis (
            const vector_type& new_basis
        );
        /*!
            ensures
                - #get_num_dimensions() == new_basis.size()
                - The operator() member function defined below will use new_basis to
                  determine nearest neighbors.
        !*/

        inline const descriptor_type& operator() (
            long row,
            long col
        ) const;
        /*!
            requires
                - 0 <= row < nr()
                - 0 <= col < nc()
                - get_num_dimensions() > 0
            ensures
                - determines which basis element is nearest to BASE_FE(row,col) and returns a sparse
                  indicator vector identifying the nearest neighbor.
                - To be precise, this function returns a sparse vector V such that:
                    - V.size() == 1
                    - V[0].first == The basis element index for the basis vector nearest to BASE_FE(row,col).
                      "nearness" is determined using Euclidean distance.
                    - V[0].second == 1
        !*/

        inline const rectangle get_block_rect (
            long row,
            long col
        ) const;
        /*!
            ensures
                - returns BASE_FE.get_block_rect(row,col)
                  I.e. returns a rectangle that tells you what part of the original image is associated
                  with a particular feature vector.
        !*/

        inline const point image_to_feat_space (
            const point& p
        ) const;
        /*!
            ensures
                - returns BASE_FE.image_to_feat_space(p)
                  I.e. Each local feature is extracted from a certain point in the input image.
                  This function returns the identity of the local feature corresponding
                  to the image location p.  Or in other words, let P == image_to_feat_space(p),
                  then (*this)(P.y(),P.x()) == the local feature closest to, or centered at,
                  the point p in the input image.  Note that some image points might not have
                  corresponding feature locations.  E.g. border points or points outside the
                  image.  In these cases the returned point will be outside get_rect(*this).
        !*/

        inline const rectangle image_to_feat_space (
            const rectangle& rect
        ) const;
        /*!
            ensures
                - returns BASE_FE.image_to_feat_space(rect)
                  I.e. returns rectangle(image_to_feat_space(rect.tl_corner()), image_to_feat_space(rect.br_corner()));
                  (i.e. maps a rectangle from image space to feature space)
        !*/

        inline const point feat_to_image_space (
            const point& p
        ) const;
        /*!
            ensures
                - returns BASE_FE.feat_to_image_space(p)
                  I.e. returns the location in the input image space corresponding to the center
                  of the local feature at point p.  In other words, this function computes
                  the inverse of image_to_feat_space().  Note that it may only do so approximately,
                  since more than one image location might correspond to the same local feature.
                  That is, image_to_feat_space() might not be invertible so this function gives
                  the closest possible result.
        !*/

        inline const rectangle feat_to_image_space (
            const rectangle& rect
        ) const;
        /*!
            ensures
                - returns BASE_FE.feat_to_image_space(rect)
                  I.e. return rectangle(feat_to_image_space(rect.tl_corner()), feat_to_image_space(rect.br_corner()));
                  (i.e. maps a rectangle from feature space to image space)
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <typename T>
    void serialize (
        const nearest_neighbor_feature_image<T>& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

    template <typename T>
    void deserialize (
        nearest_neighbor_feature_image<T>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_NEAREST_NEIGHBOR_FeATURE_IMAGE_ABSTRACT_Hh_


dlib C++ Library - poly_image_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_POLY_ImAGE_ABSTRACT_Hh_
#ifdef DLIB_POLY_ImAGE_ABSTRACT_Hh_

#include "../algs.h"
#include "../matrix.h"
#include "../geometry/rectangle_abstract.h"
#include <cmath>
#include "../image_processing/generic_image.h"

namespace dlib
{
    template <
        long Downsample
        >
    class poly_image : noncopyable
    {
        /*!
            REQUIREMENTS ON TEMPLATE PARAMETERS
                - Downsample >= 1

            WHAT THIS OBJECT REPRESENTS
                This object is a tool for extracting local feature descriptors from an image.
                In particular, it fits polynomials to local pixel patches and allows you to
                query the coefficients of these polynomials.  Additionally, the coefficients
                may be intensity normalized by dividing them by the constant term of the fitted
                polynomial and then the constant term is discarded.

                Finally, the user can specify a downsampling rate.  If the template argument
                Downsample is set to 1 then feature extraction is performed at every pixel of
                an input image (except for a small area around the image border).  However,
                if Downsample is set to 2 then feature extraction is only performed at every
                other pixel location.  More generally, if Downsample is set to N then feature
                extraction is performed only every N pixels.

            THREAD SAFETY
                Concurrent access to an instance of this object is not safe and should be protected
                by a mutex lock except for the case where you are copying the configuration
                (via copy_configuration()) of a poly_image object to many other threads.
                In this case, it is safe to copy the configuration of a shared object so long
                as no other operations are performed on it.
        !*/

    public:

        typedef matrix<double, 0, 1> descriptor_type;
        const static long downsample = Downsample;

        poly_image (
        );
        /*!
            ensures
                - #get_order() == 3
                - #get_window_size() == 13
                - #size() == 0
                - #uses_normalization() == true
                - #is_rotationally_invariant() == false
        !*/

        poly_image(
            long order,
            long window_size,
            bool normalization = true,
            bool rotation_invariance = false
        );
        /*!
            requires
                - 1 <= order <= 6
                - window_size >= 3 && window_size is odd
            ensures
                - #get_order() == order
                - #get_window_size() == window_size
                - #size() == 0
                - #uses_normalization() == normalization
                - #is_rotationally_invariant() == rotation_invariance
        !*/

        void clear (
        );
        /*!
            ensures
                - this object will have its initial value
        !*/

        void setup (
            long order,
            long window_size
        );
        /*!
            requires
                - 1 <= order <= 6
                - window_size >= 3 && window_size is odd
            ensures
                - #get_order() == order
                - #get_window_size() == window_size
        !*/

        long get_order (
        ) const;
        /*!
            ensures
                - returns the order of the polynomial that will be fitted to
                  each local pixel patch during feature extraction.
        !*/

        long get_window_size (
        ) const;
        /*!
            ensures
                - returns the size of the window used for local feature extraction.
                  This is the width and height of the window in pixels.
        !*/

        bool uses_normalization (
        ) const;
        /*!
            ensures
                - returns true if the polynomial coefficients are intensity normalized
                  and false otherwise.
        !*/

        void set_uses_normalization (
            bool normalization
        );
        /*!
            ensures
                - #uses_normalization() == normalization
        !*/

        bool is_rotationally_invariant (
        );
        /*!
            ensures
                - returns true if the feature extractor will adjust the output so that it
                  is rotationally invariant.  This is done by rotating each patch such that
                  the gradient vector always points in the same direction.
        !*/

        void set_is_rotationally_invariant (
            bool rotation_invariance
        );
        /*!
            ensures
                - #is_rotationally_invariant() == rotation_invariance
        !*/

        void copy_configuration (
            const poly_image& item
        );
        /*!
            ensures
                - copies all the state information of item into *this, except for state
                  information populated by load().  More precisely, given two poly_image
                  objects H1 and H2, the following sequence of instructions should always
                  result in both of them having the exact same state.
                    H2.copy_configuration(H1);
                    H1.load(img);
                    H2.load(img);
        !*/

        template <
            typename image_type
            >
        inline void load (
            const image_type& img
        );
        /*!
            requires
                - image_type == an image object that implements the interface defined in
                  dlib/image_processing/generic_image.h
                - pixel_traits<typename image_traits<image_type>::pixel_type>::has_alpha == false
            ensures
                - Performs the feature extraction described in the WHAT THIS OBJECT REPRESENTS
                  section above.  This means after load() finishes you can call (*this)(row,col)
                  to obtain the polynomial coefficients for an order get_order() polynomial which
                  was fitted to the image patch get_block_rect(row,col).
                - #size() > 0
        !*/

        void unload(
        );
        /*!
            ensures
                - #nr() == 0
                - #nc() == 0
                - clears only the state information which is populated by load().  For
                  example, let H be a poly_image object.  Then consider the two sequences
                  of instructions:
                    Sequence 1:
                        H.load(img);
                        H.unload();
                        H.load(img);

                    Sequence 2:
                        H.load(img);
                  Both sequence 1 and sequence 2 should have the same effect on H.
        !*/

        inline unsigned long size (
        ) const;
        /*!
            ensures
                - returns nr()*nc()
        !*/

        inline long nr (
        ) const;
        /*!
            ensures
                - returns the number of rows in this polynomial feature image
        !*/

        inline long nc (
        ) const;
        /*!
            ensures
                - returns the number of columns in this polynomial feature image
        !*/

        long get_num_dimensions (
        ) const;
        /*!
            ensures
                - returns the number of dimensions in the feature vectors generated by
                  this object.
                - In this case, this will be the number of coefficients in an order
                  get_order() polynomial, except for the constant term of the polynomial
                  if uses_normalization() == true.
        !*/

        inline const descriptor_type& operator() (
            long row,
            long col
        ) const;
        /*!
            requires
                - 0 <= row < nr()
                - 0 <= col < nc()
            ensures
                - returns the descriptor for the polynomial filtering block at the given row and column.
                  This vector will contain the polynomial coefficients for a polynomial fitted to the
                  image patch located at get_block_rect(row,col) in the original image given to load().
                - The returned descriptor vector will have get_num_dimensions() elements.
        !*/

        const rectangle get_block_rect (
            long row,
            long col
        ) const;
        /*!
            ensures
                - returns a rectangle that tells you what part of the original image is associated
                  with a particular polynomial filter block.  That is, what part of the input image
                  is associated with (*this)(row,col).
                - The returned rectangle will be get_window_size() pixels wide and tall.
        !*/

        const point image_to_feat_space (
            const point& p
        ) const;
        /*!
            ensures
                - Each local feature is extracted from a certain point in the input image.
                  This function returns the identity of the local feature corresponding
                  to the image location p.  Or in other words, let P == image_to_feat_space(p),
                  then (*this)(P.y(),P.x()) == the local feature closest to, or centered at,
                  the point p in the input image.  Note that some image points might not have
                  corresponding feature locations.  E.g. border points or points outside the
                  image.  In these cases the returned point will be outside get_rect(*this).
        !*/

        const rectangle image_to_feat_space (
            const rectangle& rect
        ) const;
        /*!
            ensures
                - returns rectangle(image_to_feat_space(rect.tl_corner()), image_to_feat_space(rect.br_corner()));
                  (i.e. maps a rectangle from image space to feature space)
        !*/

        const point feat_to_image_space (
            const point& p
        ) const;
        /*!
            ensures
                - returns the location in the input image space corresponding to the center
                  of the local feature at point p.  In other words, this function computes
                  the inverse of image_to_feat_space().  Note that it may only do so approximately,
                  since more than one image location might correspond to the same local feature.
                  That is, image_to_feat_space() might not be invertible so this function gives
                  the closest possible result.
        !*/

        const rectangle feat_to_image_space (
            const rectangle& rect
        ) const;
        /*!
            ensures
                - return rectangle(feat_to_image_space(rect.tl_corner()), feat_to_image_space(rect.br_corner()));
                  (i.e. maps a rectangle from feature space to image space)
        !*/
    };

// ----------------------------------------------------------------------------------------

    template <
        long downsample
        >
    void serialize (
        const poly_image<downsample>& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

    template <
        long downsample
        >
    void deserialize (
        poly_image<downsample>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_POLY_ImAGE_ABSTRACT_Hh_


dlib C++ Library - image_feature_sampling_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_IMAGE_FEATURE_SaMPLING_ABSTRACT_Hh_
#ifdef DLIB_IMAGE_FEATURE_SaMPLING_ABSTRACT_Hh_

#include "random_subset_selector_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename image_array_type,
        typename feature_extractor_type,
        typename pyramid_type
        >
    random_subset_selector<typename feature_extractor_type::descriptor_type> randomly_sample_image_features (
        const image_array_type& images,
        const pyramid_type& pyr,
        const feature_extractor_type& fe,
        unsigned long num
    );
    /*!
        requires
            - pyramid_type == a type compatible with the image pyramid objects defined
              in dlib/image_transforms/image_pyramid_abstract.h
            - feature_extractor_type == a local image feature extractor type such as the
              dlib::hog_image
            - image_array_type == an implementation of dlib/array/array_kernel_abstract.h
              and it must contain image objects which can be passed to pyr() and fe.load()
              and are swappable by global swap().
        ensures
            - creates an image pyramid for each image in images and performs feature
              extraction on each pyramid level.  Then selects a random subsample of at
              most num local feature vectors and returns it.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_IMAGE_FEATURE_SaMPLING_ABSTRACT_Hh_


dlib C++ Library - shape_predictor_abstract.h

// Copyright (C) 2014  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SHAPE_PREDICToR_ABSTRACT_H_
#ifdef DLIB_SHAPE_PREDICToR_ABSTRACT_H_

#include "full_object_detection_abstract.h"
#include "../matrix.h"
#include "../geometry.h"
#include "../pixel.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class shape_predictor
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is a tool that takes in an image region containing some object
                and outputs a set of point locations that define the pose of the object.
                The classic example of this is human face pose prediction, where you take
                an image of a human face as input and are expected to identify the
                locations of important facial landmarks such as the corners of the mouth
                and eyes, tip of the nose, and so forth.

                To create useful instantiations of this object you need to use the
                shape_predictor_trainer object defined below to train a shape_predictor
                using a set of training images, each annotated with shapes you want to
                predict.

            THREAD SAFETY
                No synchronization is required when using this object.  In particular, a
                single instance of this object can be used from multiple threads at the
                same time.
        !*/

    public:

        shape_predictor (
        );
        /*!
            ensures
                - #num_parts() == 0
                - #num_features() == 0
        !*/

        unsigned long num_parts (
        ) const;
        /*!
            ensures
                - returns the number of parts in the shapes predicted by this object.
        !*/

        unsigned long num_features (
        ) const;
        /*!
            ensures
                - Returns the dimensionality of the feature vector output by operator().
                  This number is the total number of trees in this object times the number
                  of leaves on each tree.
        !*/

        template <typename image_type, typename T, typename U>
        full_object_detection operator()(
            const image_type& img,
            const rectangle& rect,
            std::vector<std::pair<T,U> >& feats
        ) const;
        /*!
            requires
                - image_type == an image object that implements the interface defined in
                  dlib/image_processing/generic_image.h
                - T is some unsigned integral type (e.g. unsigned int).
                - U is any scalar type capable of storing the value 1 (e.g. float).
            ensures
                - Runs the shape prediction algorithm on the part of the image contained in
                  the given bounding rectangle.  So it will try and fit the shape model to
                  the contents of the given rectangle in the image.  For example, if there
                  is a human face inside the rectangle and you use a face landmarking shape
                  model then this function will return the locations of the face landmarks
                  as the parts.  So the return value is a full_object_detection DET such
                  that:
                    - DET.get_rect() == rect
                    - DET.num_parts() == num_parts()
                    - for all valid i:
                        - DET.part(i) == the location in img for the i-th part of the shape
                          predicted by this object.
                - #feats == a sparse vector that records which leaf each tree used to make
                  the shape prediction.   Moreover, it is an indicator vector, Therefore,
                  for all valid i:
                    - #feats[i].second == 1
                  Further, #feats is a vector from the space of num_features() dimensional
                  vectors.  The output shape positions can be represented as the dot
                  product between #feats and a weight vector.  Therefore, #feats encodes
                  all the information from img that was used to predict the returned shape
                  object.
        !*/

        template <typename image_type>
        full_object_detection operator()(
            const image_type& img,
            const rectangle& rect
        ) const;
        /*!
            requires
                - image_type == an image object that implements the interface defined in
                  dlib/image_processing/generic_image.h
            ensures
                - Calling this function is equivalent to calling (*this)(img, rect, ignored)
                  where the 3d argument is discarded.
        !*/

    };

    void serialize (const shape_predictor& item, std::ostream& out);
    void deserialize (shape_predictor& item, std::istream& in);
    /*!
        provides serialization support
    !*/

// ----------------------------------------------------------------------------------------

    class shape_predictor_trainer
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is a tool for training shape_predictors based on annotated training
                images.  Its implementation uses the algorithm described in:
                    One Millisecond Face Alignment with an Ensemble of Regression Trees
                    by Vahid Kazemi and Josephine Sullivan, CVPR 2014

        !*/

    public:

        shape_predictor_trainer (
        );
        /*!
            ensures
                - #get_cascade_depth() == 10
                - #get_tree_depth() == 4
                - #get_num_trees_per_cascade_level() == 500
                - #get_nu() == 0.1
                - #get_oversampling_amount() == 20
                - #get_feature_pool_size() == 400
                - #get_lambda() == 0.1
                - #get_num_test_splits() == 20
                - #get_feature_pool_region_padding() == 0
                - #get_random_seed() == ""
                - This object will not be verbose
        !*/

        unsigned long get_cascade_depth (
        ) const;
        /*!
            ensures
                - returns the number of cascades created when you train a model.  This
                  means that the total number of trees in the learned model is equal to
                  get_cascade_depth()*get_num_trees_per_cascade_level().
        !*/

        void set_cascade_depth (
            unsigned long depth
        );
        /*!
            requires
                - depth > 0
            ensures
                - #get_cascade_depth() == depth
        !*/

        unsigned long get_tree_depth (
        ) const;
        /*!
            ensures
                - returns the depth of the trees used in the cascade.  In particular, there
                  are pow(2,get_tree_depth()) leaves in each tree.
        !*/

        void set_tree_depth (
            unsigned long depth
        );
        /*!
            requires
                - depth > 0
            ensures
                - #get_tree_depth() == depth
        !*/

        unsigned long get_num_trees_per_cascade_level (
        ) const;
        /*!
            ensures
                - returns the number of trees created for each cascade.  This means that
                  the total number of trees in the learned model is equal to
                  get_cascade_depth()*get_num_trees_per_cascade_level().
        !*/

        void set_num_trees_per_cascade_level (
            unsigned long num
        );
        /*!
            requires
                - num > 0
            ensures
                - #get_num_trees_per_cascade_level() == num
        !*/

        double get_nu (
        ) const;
        /*!
            ensures
                - returns the regularization parameter.  Larger values of this parameter
                  will cause the algorithm to fit the training data better but may also
                  cause overfitting.
        !*/

        void set_nu (
            double nu
        );
        /*!
            requires
                - 0 < nu <= 1
            ensures
                - #get_nu() == nu
        !*/

        std::string get_random_seed (
        ) const;
        /*!
            ensures
                - returns the random seed used by the internal random number generator.
                  Since this algorithm is a random forest style algorithm it relies on a
                  random number generator for generating the trees.  So each setting of the
                  random seed will produce slightly different outputs.
        !*/

        void set_random_seed (
            const std::string& seed
        );
        /*!
            ensures
                - #get_random_seed() == seed
        !*/

        unsigned long get_oversampling_amount (
        ) const;
        /*!
            ensures
                - You give annotated images to this object as training examples.  You
                  can effectively increase the amount of training data by adding in each
                  training example multiple times but with a randomly selected deformation
                  applied to it.  That is what this parameter controls.  That is, if you
                  supply N training samples to train() then the algorithm runs internally
                  with N*get_oversampling_amount() training samples.  So the bigger this
                  parameter the better (excepting that larger values make training take
                  longer).  In terms of the Kazemi paper, this parameter is the number of
                  randomly selected initial starting points sampled for each training
                  example.
        !*/

        void set_oversampling_amount (
            unsigned long amount
        );
        /*!
            requires
                - amount > 0
            ensures
                - #get_oversampling_amount() == amount
        !*/

        unsigned long get_feature_pool_size (
        ) const;
        /*!
            ensures
                - At each level of the cascade we randomly sample get_feature_pool_size()
                  pixels from the image.  These pixels are used to generate features for
                  the random trees.  So in general larger settings of this parameter give
                  better accuracy but make the algorithm run slower.
        !*/

        void set_feature_pool_size (
            unsigned long size
        );
        /*!
            requires
                - size > 1
            ensures
                - #get_feature_pool_size() == size
        !*/

        double get_feature_pool_region_padding (
        ) const;
        /*!
            ensures
                - When we randomly sample the pixels for the feature pool we do so in a box
                  fit around the provided training landmarks.  By default, this box is the
                  tightest box that contains the landmarks (i.e. this is what happens when
                  get_feature_pool_region_padding()==0).  However, you can expand or shrink
                  the size of the pixel sampling region by setting a different value of
                  get_feature_pool_region_padding().

                  To explain this precisely, for a padding of 0 we say that the pixels are
                  sampled from a box of size 1x1.  The padding value is added to each side
                  of the box.  So a padding of 0.5 would cause the algorithm to sample
                  pixels from a box that was 2x2, effectively multiplying the area pixels
                  are sampled from by 4.  Similarly, setting the padding to -0.2 would
                  cause it to sample from a box 0.6x0.6 in size.
        !*/

        void set_feature_pool_region_padding (
            double padding
        );
        /*!
            ensures
                - #get_feature_pool_region_padding() == padding
        !*/

        double get_lambda (
        ) const;
        /*!
            ensures
                - To decide how to split nodes in the regression trees the algorithm looks
                  at pairs of pixels in the image.  These pixel pairs are sampled randomly
                  but with a preference for selecting pixels that are near each other.
                  get_lambda() controls this "nearness" preference.  In particular, smaller
                  values of get_lambda() will make the algorithm prefer to select pixels
                  close together and larger values of get_lambda() will make it care less
                  about picking nearby pixel pairs.

                  Note that this is the inverse of how it is defined in the Kazemi paper.
                  For this object, you should think of lambda as "the fraction of the
                  bounding box will we traverse to find a neighboring pixel".  Nominally,
                  this is normalized between 0 and 1.  So reasonable settings of lambda are
                  values in the range 0 < lambda < 1.
        !*/

        void set_lambda (
            double lambda
        );
        /*!
            requires
                - lambda > 0
            ensures
                - #get_lambda() == lambda
        !*/

        unsigned long get_num_test_splits (
        ) const;
        /*!
            ensures
                - When generating the random trees we randomly sample get_num_test_splits()
                  possible split features at each node and pick the one that gives the best
                  split.  Larger values of this parameter will usually give more accurate
                  outputs but take longer to train.
        !*/

        void set_num_test_splits (
            unsigned long num
        );
        /*!
            requires
                - num > 0
            ensures
                - #get_num_test_splits() == num
        !*/

        void be_verbose (
        );
        /*!
            ensures
                - This object will print status messages to standard out so that a
                  user can observe the progress of the algorithm.
        !*/

        void be_quiet (
        );
        /*!
            ensures
                - This object will not print anything to standard out
        !*/

        template <typename image_array>
        shape_predictor train (
            const image_array& images,
            const std::vector<std::vector<full_object_detection> >& objects
        ) const;
        /*!
            requires
                - image_array is a dlib::array of image objects where each image object
                  implements the interface defined in dlib/image_processing/generic_image.h
                - images.size() == objects.size()
                - images.size() > 0
                - for some i: objects[i].size() != 0
                  (i.e. there has to be at least one full_object_detection in the training set)
                - for all valid p, there must exist i and j such that:
                  objects[i][j].part(p) != OBJECT_PART_NOT_PRESENT.
                  (i.e. You can't define a part that is always set to OBJECT_PART_NOT_PRESENT.)
                - for all valid i,j,k,l:
                    - objects[i][j].num_parts() == objects[k][l].num_parts()
                      (i.e. all objects must agree on the number of parts)
                    - objects[i][j].num_parts() > 0
            ensures
                - This object will try to learn to predict the locations of an object's parts
                  based on the object bounding box (i.e.  full_object_detection::get_rect())
                  and the image pixels in that box.  That is, we will try to learn a
                  shape_predictor, SP, such that:
                    SP(images[i], objects[i][j].get_rect()) == objects[i][j]
                  This learned SP object is then returned.
                - Not all parts are required to be observed for all objects.  So if you
                  have training instances with missing parts then set the part positions
                  equal to OBJECT_PART_NOT_PRESENT and this algorithm will basically ignore
                  those missing parts.
        !*/
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename image_array
        >
    double test_shape_predictor (
        const shape_predictor& sp,
        const image_array& images,
        const std::vector<std::vector<full_object_detection> >& objects,
        const std::vector<std::vector<double> >& scales
    );
    /*!
        requires
            - image_array is a dlib::array of image objects where each image object
              implements the interface defined in dlib/image_processing/generic_image.h
            - images.size() == objects.size()
            - for all valid i and j:
                - objects[i][j].num_parts() == sp.num_parts()
            - if (scales.size() != 0) then
                - There must be a scale value for each full_object_detection in objects.
                  That is, it must be the case that:
                    - scales.size() == objects.size()
                    - for all valid i:
                        - scales[i].size() == objects[i].size()
        ensures
            - Tests the given shape_predictor by running it on each of the given objects and
              checking how well it recovers the part positions.  In particular, for all
              valid i and j we perform:
                sp(images[i], objects[i][j].get_rect())
              and compare the result with the truth part positions in objects[i][j].  We
              then return the average distance (measured in pixels) between a predicted
              part location and its true position.
            - Note that any parts in objects that are set to OBJECT_PART_NOT_PRESENT are
              simply ignored.
            - if (scales.size() != 0) then
                - Each time we compute the distance between a predicted part location and
                  its true location in objects[i][j] we divide the distance by
                  scales[i][j].  Therefore, if you want the reported error to be the
                  average pixel distance then give an empty scales vector, but if you want
                  the returned value to be something else like the average distance
                  normalized by some feature of each object (e.g. the interocular distance)
                  then you can supply those normalizing values via scales.
    !*/

    template <
        typename image_array
        >
    double test_shape_predictor (
        const shape_predictor& sp,
        const image_array& images,
        const std::vector<std::vector<full_object_detection> >& objects
    );
    /*!
        requires
            - image_array is a dlib::array of image objects where each image object
              implements the interface defined in dlib/image_processing/generic_image.h
            - images.size() == objects.size()
            - for all valid i and j:
                - objects[i][j].num_parts() == sp.num_parts()
        ensures
            - returns test_shape_predictor(sp, images, objects, no_scales) where no_scales
              is an empty vector.  So this is just a convenience function for calling the
              above test_shape_predictor() routine without a scales argument.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SHAPE_PREDICToR_ABSTRACT_H_


dlib C++ Library - draw_surf_points_abstract.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_DRAW_SURf_POINTS_ABSTRACT_H_
#ifdef DLIB_DRAW_SURf_POINTS_ABSTRACT_H_

#include "surf_abstract.h"
#include "../gui_widgets.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    void draw_surf_points (
        image_window& win,
        const std::vector<surf_point>& sp
    );
    /*!
        ensures
            - draws all the SURF points in sp onto the given image_window.  They
              are drawn as overlay circles with extra lines to indicate the rotation
              of the SURF descriptor.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_DRAW_SURf_POINTS_ABSTRACT_H_


dlib C++ Library - hessian_pyramid_abstract.h

// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_HESSIAN_PYRAMId_ABSTRACT_Hh_
#ifdef DLIB_HESSIAN_PYRAMId_ABSTRACT_Hh_

#include "../image_transforms/integral_image_abstract.h"
#include "../noncopyable.h"
#include <vector>

namespace dlib
{

    class hessian_pyramid : noncopyable
    {
        /*!
            INITIAL VALUE
                - octaves() == 0
                - intervals() == 0

            WHAT THIS OBJECT REPRESENTS
                This object represents an image pyramid where each level in the
                pyramid holds determinants of Hessian matrices for the original
                input image.  This object can be used to find stable interest
                points in an image.  For further details consult the following
                papers.

                This object is an implementation of the fast Hessian pyramid
                as described in the paper:
                   SURF: Speeded Up Robust Features
                   By Herbert Bay, Tinne Tuytelaars, and Luc Van Gool

                This implementation was also influenced by the very well documented
                OpenSURF library and its corresponding description of how the fast
                Hessian algorithm functions:
                    Notes on the OpenSURF Library
                    Christopher Evans
        !*/
    public:

        template <typename integral_image_type>
        void build_pyramid (
            const integral_image_type& img,
            long num_octaves,
            long num_intervals,
            long initial_step_size
        );
        /*!
            requires
                - num_octaves > 0
                - num_intervals > 0
                - initial_step_size > 0
                - integral_image_type == an object such as dlib::integral_image or another
                  type that implements the interface defined in image_transforms/integral_image_abstract.h
            ensures
                - #get_step_size(0) == initial_step_size
                - #octaves() == num_octaves
                - #intervals() == num_intervals
                - creates a Hessian pyramid from the given input image.
        !*/

        long octaves (
        ) const;
        /*!
            ensures
                - returns the number of octaves in this pyramid
        !*/

        long intervals (
        ) const;
        /*!
            ensures
                - returns the number of intervals in this pyramid
        !*/

        long get_border_size (
            long interval
        ) const;
        /*!
            requires
                - 0 <= interval < intervals()
            ensures
                - Each interval of the pyramid has a certain sized border region where we
                  can't compute the Hessian values since they are too close to the edge
                  of the input image.  This function returns the size of that border.
        !*/

        long get_step_size (
            long octave
        ) const;
        /*!
            requires
                - 0 <= octave < octaves()
            ensures
                - Each octave has a step size value.  This value determines how many
                  input image pixels separate each pixel in the given pyramid octave.
                  As the octave gets larger (i.e. as it goes to the top of the pyramid) the
                  step size gets bigger and thus the pyramid narrows.
        !*/

        long nr (
            long octave
        ) const;
        /*!
            requires
                - 0 <= octave < octaves()
            ensures
                - returns the number of rows there are per layer in the given
                  octave of pyramid
        !*/

        long nc (
            long octave
        ) const;
        /*!
            requires
                - 0 <= octave < octaves()
            ensures
                - returns the number of columns there are per layer in the given
                  octave of pyramid
        !*/

        double get_value (
            long octave,
            long interval,
            long r,
            long c
        ) const;
        /*!
            requires
                - 0 <= octave < octaves()
                - 0 <= interval < intervals()
                - Let BS == get_border_size(interval): then
                    - BS <= r < nr(octave)-BS
                    - BS <= c < nc(octave)-BS
            ensures
                - returns the determinant of the Hessian from the given octave and interval
                  of the pyramid.  The specific point sampled at this pyramid level is
                  the one that corresponds to the input image point (point(r,c)*get_step_size(octave)).
        !*/

        double get_laplacian (
            long octave,
            long interval,
            long r,
            long c
        ) const;
        /*!
            requires
                - 0 <= octave < octaves()
                - 0 <= interval < intervals()
                - Let BS == get_border_size(interval): then
                    - BS <= r < nr(octave)-BS
                    - BS <= c < nc(octave)-BS
            ensures
                - returns the sign of the laplacian for the given octave and interval
                  of the pyramid.  The specific point sampled at this pyramid level is
                  the one that corresponds to the input image point (point(r,c)*get_step_size(octave)).
                - The laplacian is the trace of the Hessian at the given point.  So this
                  function returns either +1 or -1 depending on this number's sign.  This
                  value can be used to distinguish bright blobs on dark backgrounds from
                  the reverse.
        !*/

    };

// ----------------------------------------------------------------------------------------

    struct interest_point
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object contains the interest points found using the
                hessian_pyramid object.  Its fields have the following
                meanings:
                    - center == the x/y location of the center of the interest point
                      (in image space coordinates.  y gives the row and x gives the
                      column in the image)
                    - scale == the scale at which the point was detected.  This is a number
                      >= 1.  If it is 1 then it means the interest point was detected at
                      the lowest scale in the image pyramid.  Larger numbers indicate that
                      the interest point is from high up in the image pyramid.  For
                      example, a scale of 4 would mean the interest point was located at a
                      point in the pyramid where the image had been shrunk by a factor of 4.
                    - score == the determinant of the Hessian for the interest point
                    - laplacian == the sign of the laplacian for the interest point
        !*/

        interest_point() : scale(0), score(0), laplacian(0) {}

        dlib::vector<double,2> center;
        double scale;
        double score;
        double laplacian;

        bool operator < (const interest_point& p) const { return score < p.score; }
        /*!
            This function is here so you can sort interest points according to
            their scores
        !*/
    };

// ----------------------------------------------------------------------------------------

    void serialize (
        const interest_point& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

    void deserialize (
        interest_point& item,
        std::istream& in
    );
    /*!
        provides serialization support
    !*/

// ----------------------------------------------------------------------------------------

    template <typename Alloc>
    void get_interest_points (
        const hessian_pyramid& pyr,
        double threshold,
        std::vector<interest_point,Alloc>& result_points
    )
    /*!
        requires
            - threshold >= 0
        ensures
            - extracts interest points from the pyramid pyr and stores them into
              result_points (note that result_points is cleared before these new interest
              points are added to it).
            - Only interest points with determinant values in the pyramid larger than
              threshold are output.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif  // DLIB_HESSIAN_PYRAMId_ABSTRACT_Hh_


dlib C++ Library - integral_image_abstract.h

// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_INTEGRAL_IMAGe_ABSTRACT_
#ifdef DLIB_INTEGRAL_IMAGe_ABSTRACT_

#include "../geometry/rectangle_abstract.h"
#include "../array2d/array2d_kernel_abstract.h"
#include "../pixel.h"
#include "../noncopyable.h"
#include "../image_processing/generic_image.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    class integral_image_generic : noncopyable
    {
        /*!
            REQUIREMENTS ON T
                T should be a built in scalar type.  Moreover, it should
                be capable of storing sums of whatever kind of pixel
                you will be dealing with.

            INITIAL VALUE
                - nr() == 0
                - nc() == 0

            WHAT THIS OBJECT REPRESENTS
                This object is an alternate way of representing image data
                that allows for very fast computations of sums of pixels in
                rectangular regions.  To use this object you load it with a
                normal image and then you can use the get_sum_of_area()
                function to compute sums of pixels in a given area in
                constant time.
        !*/
    public:
        typedef T value_type;

        const long nr(
        ) const;
        /*!
            ensures
                - returns the number of rows in this integral image object
        !*/

        const long nc(
        ) const;
        /*!
            ensures
                - returns the number of columns in this integral image object
        !*/

        template <typename image_type>
        void load (
            const image_type& img
        );
        /*!
            requires
                - image_type == an image object that implements the interface defined in
                  dlib/image_processing/generic_image.h
                - Let P denote the type of pixel in img, then we require:
                    - pixel_traits<P>::has_alpha == false
            ensures
                - #nr() == img.nr()
                - #nc() == img.nc()
                - #*this will now contain an "integral image" representation of the
                  given input image.
        !*/

        value_type get_sum_of_area (
            const rectangle& rect
        ) const;
        /*!
            requires
                - rect.is_empty() == false
                - get_rect(*this).contains(rect) == true
                  (i.e. rect must not be outside the integral image)
            ensures
                - Let O denote the image this integral image was generated from.
                  Then this function returns sum(subm(mat(O),rect)).
                  That is, this function returns the sum of the pixels in O that
                  are contained within the given rectangle.
        !*/

        void swap(
            integral_image_generic& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/

    };

// ----------------------------------------------------------------------------------------

    template < typename T >
    void swap (
        integral_image_generic<T>& a,
        integral_image_generic<T>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

// ----------------------------------------------------------------------------------------

    typedef integral_image_generic<long> integral_image;

// ----------------------------------------------------------------------------------------

    template <typename integral_image_type>
    typename integral_image_type::value_type haar_x (
        const integral_image_type& img,
        const point& p,
        long width
    )
    /*!
        requires
            - get_rect(img).contains(centered_rect(p,width,width)) == true
            - integral_image_type == a type that implements the integral_image_generic
              interface defined above
        ensures
            - returns the response of a Haar wavelet centered at the point p
              with the given width.  The wavelet is oriented along the X axis
              and has the following shape:
                ----++++
                ----++++
                ----++++
                ----++++
              That is, the wavelet is square and computes the sum of pixels on the
              right minus the sum of pixels on the left.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename integral_image_type>
    typename integral_image_type::value_type haar_y (
        const integral_image_type& img,
        const point& p,
        long width
    )
    /*!
        requires
            - get_rect(img).contains(centered_rect(p,width,width)) == true
            - integral_image_type == a type that implements the integral_image_generic
              interface defined above
        ensures
            - returns the response of a Haar wavelet centered at the point p
              with the given width in the given image.  The wavelet is oriented
              along the Y axis and has the following shape:
                --------
                --------
                ++++++++
                ++++++++
              That is, the wavelet is square and computes the sum of pixels on the
              bottom minus the sum of pixels on the top.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_INTEGRAL_IMAGe_ABSTRACT_


dlib C++ Library - thresholding_abstract.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_THRESHOLDINg_ABSTRACT_
#ifdef DLIB_THRESHOLDINg_ABSTRACT_

#include "../pixel.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    const unsigned char on_pixel = 255;
    const unsigned char off_pixel = 0;

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type
        >
    void threshold_image (
        const in_image_type& in_img,
        out_image_type& out_img,
        typename pixel_traits<typename image_traits<in_image_type>::pixel_type>::basic_pixel_type thresh
    );
    /*!
        requires
            - in_image_type == is an implementation of array2d/array2d_kernel_abstract.h
            - out_image_type == is an implementation of array2d/array2d_kernel_abstract.h
            - pixel_traits<typename image_traits<out_image_type>::pixel_type>::grayscale == true
            - pixel_traits<typename image_traits<in_image_type>::pixel_type>::has_alpha == false
            - pixel_traits<typename image_traits<out_image_type>::pixel_type>::has_alpha == false
        ensures
            - #out_img == the thresholded version of in_img (in_img is converted to a grayscale
              intensity image if it is color).  Pixels in in_img with grayscale values >= thresh
              have an output value of on_pixel and all others have a value of off_pixel.
            - #out_img.nc() == in_img.nc()
            - #out_img.nr() == in_img.nr()
    !*/

    template <
        typename image_type
        >
    void threshold_image (
        image_type& img,
        typename pixel_traits<typename image_traits<image_type>::pixel_type>::basic_pixel_type thresh
    );
    /*!
        requires
            - it is valid to call threshold_image(img,img,thresh);
        ensures
            - calls threshold_image(img,img,thresh);
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type
        >
    void auto_threshold_image (
        const in_image_type& in_img,
        out_image_type& out_img
    );
    /*!
        requires
            - in_image_type == is an implementation of array2d/array2d_kernel_abstract.h
            - out_image_type == is an implementation of array2d/array2d_kernel_abstract.h
            - pixel_traits<typename image_traits<in_image_type>::pixel_type>::max() <= 65535
            - pixel_traits<typename image_traits<in_image_type>::pixel_type>::has_alpha   == false
            - pixel_traits<typename image_traits<in_image_type>::pixel_type>::is_unsigned == true
            - pixel_traits<typename image_traits<out_image_type>::pixel_type>::grayscale  == true
            - pixel_traits<typename image_traits<out_image_type>::pixel_type>::has_alpha  == false
            - pixel_traits<typename image_traits<out_image_type>::pixel_type>::is_unsigned == true
        ensures
            - #out_img == the thresholded version of in_img (in_img is converted to a grayscale
              intensity image if it is color).  Pixels in in_img with grayscale values >= thresh
              have an output value of on_pixel and all others have a value of off_pixel.
            - The thresh value used is determined by performing a k-means clustering
              on the input image histogram with a k of 2.  The point between the two
              means found is used as the thresh value.
            - #out_img.nc() == in_img.nc()
            - #out_img.nr() == in_img.nr()
    !*/

    template <
        typename image_type
        >
    void auto_threshold_image (
        image_type& img
    );
    /*!
        requires
            - it is valid to call auto_threshold_image(img,img);
        ensures
            - calls auto_threshold_image(img,img);
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type
        >
    void hysteresis_threshold (
        const in_image_type& in_img,
        out_image_type& out_img,
        typename pixel_traits<typename image_traits<in_image_type>::pixel_type>::basic_pixel_type lower_thresh,
        typename pixel_traits<typename image_traits<in_image_type>::pixel_type>::basic_pixel_type upper_thresh
    );
    /*!
        requires
            - in_image_type == is an implementation of array2d/array2d_kernel_abstract.h
            - out_image_type == is an implementation of array2d/array2d_kernel_abstract.h
            - pixel_traits<typename image_traits<out_image_type>::pixel_type>::grayscale == true
            - pixel_traits<typename image_traits<in_image_type>::pixel_type>::has_alpha == false
            - pixel_traits<typename image_traits<out_image_type>::pixel_type>::has_alpha == false
            - lower_thresh <= upper_thresh
            - is_same_object(in_img, out_img) == false
        ensures
            - #out_img == the hysteresis thresholded version of in_img (in_img is converted to a
              grayscale intensity image if it is color). Pixels in in_img with grayscale
              values >= upper_thresh have an output value of on_pixel and all others have a
              value of off_pixel unless they are >= lower_thresh and are connected to a pixel
              with a value >= upper_thresh, in which case they have a value of on_pixel.  Here
              pixels are connected if there is a path between them composed of pixels that
              would receive an output of on_pixel.
            - #out_img.nc() == in_img.nc()
            - #out_img.nr() == in_img.nr()
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_THRESHOLDINg_ABSTRACT_


dlib C++ Library - edge_detector_abstract.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_EDGE_DETECTOr_ABSTRACT_
#ifdef DLIB_EDGE_DETECTOr_ABSTRACT_

#include "../pixel.h"
#include "../image_processing/generic_image.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    inline char edge_orientation (
        const T& x,
        const T& y
    );
    /*!
        ensures
            - returns the orientation of the line drawn from the origin to the point (x,y).
              The orientation is represented pictorially using the four ascii
              characters /,|,\, and -.
            - if (the line is horizontal) then
                returns '-'
            - if (the line is vertical) then
                returns '|'
            - if (the line is diagonal with a positive slope) then
                returns '/'
            - if (the line is diagonal with a negative slope) then
                returns '\\'
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type
        >
    void sobel_edge_detector (
        const in_image_type& in_img,
        out_image_type& horz,
        out_image_type& vert
    );
    /*!
        requires
            - in_image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - out_image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - out_image_type must use signed grayscale pixels
            - is_same_object(in_img,horz) == false
            - is_same_object(in_img,vert) == false
            - is_same_object(horz,vert) == false
        ensures
            - Applies the sobel edge detector to the given input image and stores the resulting
              edge detections in the horz and vert images
            - #horz.nr() == in_img.nr()
            - #horz.nc() == in_img.nc()
            - #vert.nr() == in_img.nr()
            - #vert.nc() == in_img.nc()
            - for all valid r and c:
                - #horz[r][c] == the magnitude of the horizontal gradient at the point in_img[r][c]
                - #vert[r][c] == the magnitude of the vertical gradient at the point in_img[r][c]
                - edge_orientation(#vert[r][c], #horz[r][c]) == the edge direction at this point in
                  the image
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type
        >
    void suppress_non_maximum_edges (
        const in_image_type& horz,
        const in_image_type& vert,
        out_image_type& out_img
    );
    /*!
        requires
            - in_image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - out_image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - horz.nr() == vert.nr()
            - horz.nc() == vert.nc()
            - is_same_object(out_img, horz) == false
            - is_same_object(out_img, vert) == false
            - image_traits<in_image_type>::pixel_type == A signed scalar type (e.g. int, double, etc.)
        ensures
            - #out_img.nr() = horz.nr()
            - #out_img.nc() = horz.nc()
            - let edge_strength(r,c) == sqrt(pow(horz[r][c],2) + pow(vert[r][c],2))
              (i.e. The Euclidean norm of the gradient)
            - for all valid r and c:
                - if (edge_strength(r,c) is at a maximum with respect to its 2 neighboring
                  pixels along the line given by edge_orientation(vert[r][c],horz[r][c])) then
                    - performs assign_pixel(#out_img[r][c], edge_strength(r,c))
                - else
                    - performs assign_pixel(#out_img[r][c], 0)
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_EDGE_DETECTOr_ABSTRACT_


dlib C++ Library - hough_transform_abstract.h

// Copyright (C) 2014  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_HOUGH_tRANSFORM_ABSTRACT_Hh_
#ifdef DLIB_HOUGH_tRANSFORM_ABSTRACT_Hh_

#include "../geometry.h"
#include "../image_processing/generic_image.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class hough_transform
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is a tool for computing the line finding version of the Hough
                transform given some kind of edge detection image as input.  It also allows
                the edge pixels to be weighted such that higher weighted edge pixels
                contribute correspondingly more to the output of the Hough transform,
                allowing stronger edges to create correspondingly stronger line detections
                in the final Hough transform.

            THREAD SAFETY
                It is safe for multiple threads to make concurrent accesses to this object
                without synchronization.
        !*/

    public:

        explicit hough_transform (
            unsigned long size_
        );
        /*!
            requires
                - size_ > 0
            ensures
                - This object will compute Hough transforms that are size_ by size_ pixels.
                  This is in terms of both the Hough accumulator array size as well as the
                  input image size.
                - #size() == size_
        !*/

        unsigned long size(
        ) const;
        /*!
            ensures
                - returns the size of the Hough transforms generated by this object.  In
                  particular, this object creates Hough transform images that are size() by
                  size() pixels in size.
        !*/

        long nr(
        ) const;
        /*!
            ensures
                - returns size()
        !*/

        long nc(
        ) const;
        /*!
            ensures
                - returns size()
        !*/

        std::pair<point, point> get_line (
            const point& p
        ) const;
        /*!
            requires
                - rectangle(0,0,size()-1,size()-1).contains(p) == true
                  (i.e. p must be a point inside the Hough accumulator array)
            ensures
                - returns the line segment in the original image space corresponding
                  to Hough transform point p.
                - The returned points are inside rectangle(0,0,size()-1,size()-1).
        !*/

        template <
            typename image_type
            >
        point get_best_hough_point (
            const point& p,
            const image_type& himg
        );
        /*!
            requires
                - image_type == an image object that implements the interface defined in
                  dlib/image_processing/generic_image.h and it must contain grayscale pixels.
                - himg.nr() == size()
                - himg.nc() == size()
                - rectangle(0,0,size()-1,size()-1).contains(p) == true
            ensures
                - This function interprets himg as a Hough image and p as a point in the
                  original image space.  Given this, it finds the maximum scoring line that
                  passes though p.  That is, it checks all the Hough accumulator bins in
                  himg corresponding to lines though p and returns the location with the
                  largest score.
                - returns a point X such that get_rect(himg).contains(X) == true
        !*/

        template <
            typename in_image_type,
            typename out_image_type
            >
        void operator() (
            const in_image_type& img,
            const rectangle& box,
            out_image_type& himg
        ) const;
        /*!
            requires
                - in_image_type == an image object that implements the interface defined in
                  dlib/image_processing/generic_image.h and it must contain grayscale pixels.
                - out_image_type == an image object that implements the interface defined in
                  dlib/image_processing/generic_image.h and it must contain grayscale pixels.
                - box.width() == size()
                - box.height() == size()
            ensures
                - Computes the Hough transform of the part of img contained within box.
                  In particular, we do a grayscale version of the Hough transform where any
                  non-zero pixel in img is treated as a potential component of a line and
                  accumulated into the Hough accumulator #himg.  However, rather than
                  adding 1 to each relevant accumulator bin we add the value of the pixel
                  in img to each Hough accumulator bin.  This means that, if all the
                  pixels in img are 0 or 1 then this routine performs a normal Hough
                  transform.  However, if some pixels have larger values then they will be
                  weighted correspondingly more in the resulting Hough transform.
                - #himg.nr() == size()
                - #himg.nc() == size()
                - #himg is the Hough transform of the part of img contained in box.  Each
                  point in #himg corresponds to a line in the input box.  In particular,
                  the line for #himg[y][x] is given by get_line(point(x,y)).  Also, when
                  viewing the #himg image, the x-axis gives the angle of the line and the
                  y-axis the distance of the line from the center of the box.
        !*/

    };
}

#endif // DLIB_HOUGH_tRANSFORM_ABSTRACT_Hh_


dlib C++ Library - morphological_operations_abstract.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_MORPHOLOGICAL_OPERATIONs_ABSTRACT_
#ifdef DLIB_MORPHOLOGICAL_OPERATIONs_ABSTRACT_

#include "../pixel.h"
#include "thresholding_abstract.h"
#include "../image_processing/generic_image.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type,
        long M,
        long N
        >
    void binary_dilation (
        const in_image_type& in_img,
        out_image_type& out_img,
        const unsigned char (&structuring_element)[M][N]
    );
    /*!
        requires
            - in_image_type and out_image_type are image objects that implement the
              interface defined in dlib/image_processing/generic_image.h
            - in_img must contain a grayscale pixel type.
            - both in_img and out_img must contain pixels with no alpha channel.
              (i.e. pixel_traits::has_alpha==false for their pixels)
            - is_same_object(in_img,out_img) == false
            - M % 2 == 1  (i.e. M must be odd)
            - N % 2 == 1  (i.e. N must be odd)
            - all pixels in in_img are set to either on_pixel or off_pixel
              (i.e. it must be a binary image)
            - all pixels in structuring_element are set to either on_pixel or off_pixel
              (i.e. it must be a binary image)
        ensures
            - Does a binary dilation of in_img using the given structuring element and
              stores the result in out_img.
            - #out_img.nc() == in_img.nc()
            - #out_img.nr() == in_img.nr()
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type,
        long M,
        long N
        >
    void binary_erosion (
        const in_image_type& in_img,
        out_image_type& out_img,
        const unsigned char (&structuring_element)[M][N]
    );
    /*!
        requires
            - in_image_type and out_image_type are image objects that implement the
              interface defined in dlib/image_processing/generic_image.h
            - in_img must contain a grayscale pixel type.
            - both in_img and out_img must contain pixels with no alpha channel.
              (i.e. pixel_traits::has_alpha==false for their pixels)
            - is_same_object(in_img,out_img) == false
            - M % 2 == 1  (i.e. M must be odd)
            - N % 2 == 1  (i.e. N must be odd)
            - all pixels in in_img are set to either on_pixel or off_pixel
              (i.e. it must be a binary image)
            - all pixels in structuring_element are set to either on_pixel or off_pixel
              (i.e. it must be a binary image)
        ensures
            - Does a binary erosion of in_img using the given structuring element and
              stores the result in out_img.
            - #out_img.nc() == in_img.nc()
            - #out_img.nr() == in_img.nr()
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type,
        long M,
        long N
        >
    void binary_open (
        const in_image_type& in_img,
        out_image_type& out_img,
        const unsigned char (&structuring_element)[M][N],
        const unsigned long iter = 1
    );
    /*!
        requires
            - in_image_type and out_image_type are image objects that implement the
              interface defined in dlib/image_processing/generic_image.h
            - in_img must contain a grayscale pixel type.
            - both in_img and out_img must contain pixels with no alpha channel.
              (i.e. pixel_traits::has_alpha==false for their pixels)
            - is_same_object(in_img,out_img) == false
            - M % 2 == 1  (i.e. M must be odd)
            - N % 2 == 1  (i.e. N must be odd)
            - all pixels in in_img are set to either on_pixel or off_pixel
              (i.e. it must be a binary image)
            - all pixels in structuring_element are set to either on_pixel or off_pixel
              (i.e. it must be a binary image)
        ensures
            - Does a binary open of in_img using the given structuring element and
              stores the result in out_img.  Specifically, iter iterations of binary
              erosion are applied and then iter iterations of binary dilation.
            - #out_img.nc() == in_img.nc()
            - #out_img.nr() == in_img.nr()
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type,
        long M,
        long N
        >
    void binary_close (
        const in_image_type& in_img,
        out_image_type& out_img,
        const unsigned char (&structuring_element)[M][N],
        const unsigned long iter = 1
    );
    /*!
        requires
            - in_image_type and out_image_type are image objects that implement the
              interface defined in dlib/image_processing/generic_image.h
            - in_img must contain a grayscale pixel type.
            - both in_img and out_img must contain pixels with no alpha channel.
              (i.e. pixel_traits::has_alpha==false for their pixels)
            - is_same_object(in_img,out_img) == false
            - M % 2 == 1  (i.e. M must be odd)
            - N % 2 == 1  (i.e. N must be odd)
            - all pixels in in_img are set to either on_pixel or off_pixel
              (i.e. it must be a binary image)
            - all pixels in structuring_element are set to either on_pixel or off_pixel
              (i.e. it must be a binary image)
        ensures
            - Does a binary close of in_img using the given structuring element and
              stores the result in out_img.  Specifically, iter iterations of binary
              dilation are applied and then iter iterations of binary erosion.
            - #out_img.nc() == in_img.nc()
            - #out_img.nr() == in_img.nr()
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type1,
        typename in_image_type2,
        typename out_image_type
        >
    void binary_intersection (
        const in_image_type1& in_img1,
        const in_image_type2& in_img2,
        out_image_type& out_img
    );
    /*!
        requires
            - in_image_type1, in_image_type2, and out_image_type are image objects that
              implement the interface defined in dlib/image_processing/generic_image.h
            - in_img1 and in_img2 must contain grayscale pixel types.
            - in_img1, in_img2, and out_img must contain pixels with no alpha channel.
              (i.e. pixel_traits::has_alpha==false for their pixels)
            - all pixels in in_img1 and in_img2 are set to either on_pixel or off_pixel
              (i.e. they must be binary images)
            - in_img1.nc() == in_img2.nc()
            - in_img1.nr() == in_img2.nr()
        ensures
            - #out_img == the binary intersection of in_img1 and in_img2.  (i.e. All
              the pixels that are set to on_pixel in both in_img1 and in_img2 will be set
              to on_pixel in #out_img.  All other pixels will be set to off_pixel)
            - #out_img.nc() == in_img.nc()
            - #out_img.nr() == in_img.nr()
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type1,
        typename in_image_type2,
        typename out_image_type
        >
    void binary_union (
        const in_image_type1& in_img1,
        const in_image_type2& in_img2,
        out_image_type& out_img
    );
    /*!
        requires
            - in_image_type1, in_image_type2, and out_image_type are image objects that
              implement the interface defined in dlib/image_processing/generic_image.h
            - in_img1 and in_img2 must contain grayscale pixel types.
            - in_img1, in_img2, and out_img must contain pixels with no alpha channel.
              (i.e. pixel_traits::has_alpha==false for their pixels)
            - all pixels in in_img1 and in_img2 are set to either on_pixel or off_pixel
              (i.e. they must be binary images)
            - in_img1.nc() == in_img2.nc()
            - in_img1.nr() == in_img2.nr()
        ensures
            - #out_img == the binary union of in_img1 and in_img2.  (i.e. All
              the pixels that are set to on_pixel in in_img1 and/or in_img2 will be set
              to on_pixel in #out_img.  All other pixels will be set to off_pixel)
            - #out_img.nc() == in_img.nc()
            - #out_img.nr() == in_img.nr()
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type1,
        typename in_image_type2,
        typename out_image_type
        >
    void binary_difference (
        const in_image_type1& in_img1,
        const in_image_type2& in_img2,
        out_image_type& out_img
    );
    /*!
        requires
            - in_image_type1, in_image_type2, and out_image_type are image objects that
              implement the interface defined in dlib/image_processing/generic_image.h
            - in_img1 and in_img2 must contain grayscale pixel types.
            - in_img1, in_img2, and out_img must contain pixels with no alpha channel.
              (i.e. pixel_traits::has_alpha==false for their pixels)
            - all pixels in in_img1 and in_img2 are set to either on_pixel or off_pixel
              (i.e. they must be binary images)
            - in_img1.nc() == in_img2.nc()
            - in_img1.nr() == in_img2.nr()
        ensures
            - #out_img == the binary difference of in_img1 and in_img2.  (i.e. #out_img
              will be a copy of in_img1 except that any pixels in in_img2 that are set to
              on_pixel will be set to off_pixel)
            - #out_img.nc() == in_img.nc()
            - #out_img.nr() == in_img.nr()
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type
        >
    void binary_complement (
        const in_image_type& in_img,
        out_image_type& out_img
    );
    /*!
        requires
            - in_image_type and out_image_type are image objects that implement the
              interface defined in dlib/image_processing/generic_image.h
            - in_img must contain a grayscale pixel type.
            - both in_img and out_img must contain pixels with no alpha channel.
              (i.e. pixel_traits::has_alpha==false for their pixels)
            - all pixels in in_img are set to either on_pixel or off_pixel
              (i.e. it must be a binary image)
        ensures
            - #out_img == the binary complement of in_img.  (i.e. For each pixel in
              in_img, if it is on_pixel then it will be set to off_pixel in #out_img and
              if it was off_pixel in in_img then it will be on_pixel in #out_img)
            - #out_img.nc() == in_img.nc()
            - #out_img.nr() == in_img.nr()
    !*/

    template <
        typename image_type
        >
    void binary_complement (
        image_type& img
    );
    /*!
        requires
            - it must be valid to call binary_complement(img,img);
        ensures
            - calls binary_complement(img,img);
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    void skeleton(
        image_type& img
    );
    /*!
        requires
            - image_type is an object that implement the interface defined in
              dlib/image_processing/generic_image.h
            - img must contain a grayscale pixel type.
            - all pixels in img are set to either on_pixel or off_pixel.
              (i.e. it must be a binary image)
        ensures
            - This function computes the skeletonization of img and stores the result in
              #img.  That is, given a binary image, we progressively thin the binary blobs
              (composed of on_pixel values) until only a single pixel wide skeleton of the
              original blobs remains.
            - #img.nc() == img.nc()
            - #img.nr() == img.nr()
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MORPHOLOGICAL_OPERATIONs_ABSTRACT_


dlib C++ Library - label_connected_blobs_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_LABEL_CONNeCTED_BLOBS_ABSTRACT_H_
#ifdef DLIB_LABEL_CONNeCTED_BLOBS_ABSTRACT_H_

#include "../geometry.h"
#include <vector>
#include "../image_processing/generic_image.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    struct neighbors_8
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is a pixel neighborhood generating functor for
                use with the label_connected_blobs() routine defined below.
        !*/

        void operator() (
            const point& p,
            std::vector<point>& neighbors
        ) const;
        /*!
            ensures
                - adds the 8 neighboring pixels surrounding p into neighbors
        !*/
    };

    struct neighbors_4
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is a pixel neighborhood generating functor for
                use with the label_connected_blobs() routine defined below.
        !*/

        void operator() (
            const point& p,
            std::vector<point>& neighbors
        ) const;
        /*!
            ensures
                - adds the 4 neighboring pixels of p into neighbors.  These
                  are the ones immediately to the left, top, right, and bottom.
        !*/
    };

// ----------------------------------------------------------------------------------------

    struct connected_if_both_not_zero
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is a pixel connection testing functor for use
                with the label_connected_blobs() routine defined below.
        !*/

        template <typename image_view_type>
        bool operator() (
            const image_view_type& img,
            const point& a,
            const point& b
        ) const
        {
            return (img[a.y()][a.x()] != 0 && img[b.y()][b.x()] != 0);
        }
    };

    struct connected_if_equal
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is a pixel connection testing functor for use
                with the label_connected_blobs() routine defined below.
        !*/

        template <typename image_view_type>
        bool operator() (
            const image_view_type& img,
            const point& a,
            const point& b
        ) const
        {
            return (img[a.y()][a.x()] == img[b.y()][b.x()]);
        }
    };

// ----------------------------------------------------------------------------------------

    struct zero_pixels_are_background
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is a background testing functor for use
                with the label_connected_blobs() routine defined below.
        !*/

        template <typename image_view_type>
        bool operator() (
            const image_view_type& img,
            const point& p
        ) const
        {
            return img[p.y()][p.x()] == 0;
        }

    };

    struct nothing_is_background
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is a background testing functor for use
                with the label_connected_blobs() routine defined below.
        !*/

        template <typename image_view_type>
        bool operator() (
            const image_view_type&,
            const point&
        ) const
        {
            return false;
        }

    };

// ----------------------------------------------------------------------------------------

    template <
        typename image_type,
        typename label_image_type,
        typename background_functor_type,
        typename neighbors_functor_type,
        typename connected_functor_type
        >
    unsigned long label_connected_blobs (
        const image_type& img,
        const background_functor_type& is_background,
        const neighbors_functor_type&  get_neighbors,
        const connected_functor_type&  is_connected,
        label_image_type& label_img
    );
    /*!
        requires
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - label_image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h and it must contain integer pixels.
            - is_background(img, point(c,r)) is a legal expression that evaluates to a bool.
            - is_connected(img, point(c,r), point(c2,r2)) is a legal expression that
              evaluates to a bool.
            - get_neighbors(point(c,r), neighbors) is a legal expression where neighbors
              is of type std::vector<point>.
            - is_same_object(img, label_img) == false
        ensures
            - This function labels each of the connected blobs in img with a unique integer
              label.
            - An image can be thought of as a graph where pixels A and B are connected if
              and only if the following two statements are satisfied:
                - is_connected(img,A,B) == true
                - get_neighbors(A, neighbors) results in neighbors containing B or
                  get_neighbors(B, neighbors) results in neighbors containing A.
              Then this function can be understood as labeling all the connected components
              of this pixel graph such that all pixels in a component get the same label while
              pixels in different components get different labels.  Note that there is a
              special "background" component determined by is_background().  Any pixels which
              are "background" always get a blob id of 0 regardless of any other considerations.
            - #label_img.nr() == img.nr()
            - #label_img.nc() == img.nc()
            - for all valid r and c:
                - #label_img[r][c] == the blob label number for pixel img[r][c].
                - #label_img[r][c] >= 0
                - if (is_background(img, point(c,r))) then
                    - #label_img[r][c] == 0
                - else
                    - #label_img[r][c] != 0
            - if (img.size() != 0) then
                - returns max(mat(#label_img))+1
                  (i.e. returns a number one greater than the maximum blob id number,
                  this is the number of blobs found.)
            - else
                - returns 0
            - blob labels are contiguous, therefore, the number returned by this function is
              the number of blobs in the image (including the background blob).
            - It is guaranteed that is_connected() and is_background() will never be
              called with points outside the image.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_LABEL_CONNeCTED_BLOBS_ABSTRACT_H_


dlib C++ Library - spatial_filtering_abstract.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SPATIAL_FILTERINg_ABSTRACT_
#ifdef DLIB_SPATIAL_FILTERINg_ABSTRACT_

#include "../pixel.h"
#include "../matrix.h"
#include "../image_processing/generic_image.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type,
        typename EXP,
        typename T
        >
    rectangle spatially_filter_image (
        const in_image_type& in_img,
        out_image_type& out_img,
        const matrix_exp<EXP>& filter,
        T scale = 1,
        bool use_abs = false,
        bool add_to = false
    );
    /*!
        requires
            - in_image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - out_image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - in_img and out_img do not contain pixels with an alpha channel.  That is,
              pixel_traits::has_alpha is false for the pixels in these objects.
            - is_same_object(in_img, out_img) == false
            - T must be some scalar type
            - filter.size() != 0
            - scale != 0
            - if (in_img doesn't contain grayscale pixels) then
                - use_abs == false && add_to == false
                  (i.e. You can only use the use_abs and add_to options with grayscale images)
        ensures
            - Applies the given spatial filter to in_img and stores the result in out_img (i.e.
              cross-correlates in_img with filter).  Also divides each resulting pixel by scale.
            - The intermediate filter computations will be carried out using variables of type EXP::type.
              This is whatever scalar type is used inside the filter matrix.
            - Pixel values are stored into out_img using the assign_pixel() function and therefore
              any applicable color space conversion or value saturation is performed.  Note that if
              add_to is true then the filtered output value will be added to out_img rather than
              overwriting the original value.
            - if (in_img doesn't contain grayscale pixels) then
                - The filter is applied to each color channel independently.
            - if (use_abs == true) then
                - pixel values after filtering that are < 0 are converted to their absolute values.
            - The filter is applied such that it's centered over the pixel it writes its
              output into.  For centering purposes, we consider the center element of the
              filter to be filter(filter.nr()/2,filter.nc()/2).  This means that the filter
              that writes its output to a pixel at location point(c,r) and is W by H (width
              by height) pixels in size operates on exactly the pixels in the rectangle
              centered_rect(point(c,r),W,H) within in_img.
            - Pixels close enough to the edge of in_img to not have the filter still fit
              inside the image are always set to zero.
            - #out_img.nc() == in_img.nc()
            - #out_img.nr() == in_img.nr()
            - returns a rectangle which indicates what pixels in #out_img are considered
              non-border pixels and therefore contain output from the filter.
            - if (use_abs == false && all images and filers contain float types) then
                - This function will use SIMD instructions and is particularly fast.  So if
                  you can use this form of the function it can give a decent speed boost.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type,
        typename EXP1,
        typename EXP2,
        typename T
        >
    rectangle spatially_filter_image_separable (
        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 = 1,
        bool use_abs = false,
        bool add_to = false
    );
    /*!
        requires
            - in_image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - out_image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - in_img and out_img do not contain pixels with an alpha channel.  That is,
              pixel_traits::has_alpha is false for the pixels in these objects.
            - is_same_object(in_img, out_img) == false
            - T must be some scalar type
            - scale != 0
            - row_filter.size() != 0
            - col_filter.size() != 0
            - is_vector(row_filter) == true
            - is_vector(col_filter) == true
            - if (in_img doesn't contain grayscale pixels) then
                - use_abs == false && add_to == false
                  (i.e. You can only use the use_abs and add_to options with grayscale images)
        ensures
            - Applies the given separable spatial filter to in_img and stores the result in out_img.
              Also divides each resulting pixel by scale.  Calling this function has the same
              effect as calling the regular spatially_filter_image() routine with a filter,
              FILT, defined as follows:
                - FILT(r,c) == col_filter(r)*row_filter(c)
            - The intermediate filter computations will be carried out using variables of type EXP1::type.
              This is whatever scalar type is used inside the row_filter matrix.
            - Pixel values are stored into out_img using the assign_pixel() function and therefore
              any applicable color space conversion or value saturation is performed.  Note that if
              add_to is true then the filtered output value will be added to out_img rather than
              overwriting the original value.
            - if (in_img doesn't contain grayscale pixels) then
                - The filter is applied to each color channel independently.
            - if (use_abs == true) then
                - pixel values after filtering that are < 0 are converted to their absolute values
            - The filter is applied such that it's centered over the pixel it writes its
              output into.  For centering purposes, we consider the center element of the
              filter to be FILT(col_filter.size()/2,row_filter.size()/2).  This means that
              the filter that writes its output to a pixel at location point(c,r) and is W
              by H (width by height) pixels in size operates on exactly the pixels in the
              rectangle centered_rect(point(c,r),W,H) within in_img.
            - Pixels close enough to the edge of in_img to not have the filter still fit
              inside the image are always set to zero.
            - #out_img.nc() == in_img.nc()
            - #out_img.nr() == in_img.nr()
            - returns a rectangle which indicates what pixels in #out_img are considered
              non-border pixels and therefore contain output from the filter.
            - if (use_abs == false && all images and filers contain float types) then
                - This function will use SIMD instructions and is particularly fast.  So if
                  you can use this form of the function it can give a decent speed boost.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type,
        typename EXP1,
        typename EXP2
        >
    rectangle float_spatially_filter_image_separable (
        const in_image_type& in_img,
        out_image_type& out_img,
        const matrix_exp<EXP1>& row_filter,
        const matrix_exp<EXP2>& col_filter,
        out_image_type& scratch,
        bool add_to = false
    );
    /*!
        requires
            - in_image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - out_image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - in_img, out_img, row_filter, and col_filter must all contain float type elements.
            - is_same_object(in_img, out_img) == false
            - row_filter.size() != 0
            - col_filter.size() != 0
            - is_vector(row_filter) == true
            - is_vector(col_filter) == true
        ensures
            - This function is identical to the above spatially_filter_image_separable()
              function except that it can only be invoked on float images with float
              filters.  In fact, spatially_filter_image_separable() invokes
              float_spatially_filter_image_separable() in those cases.  So why is
              float_spatially_filter_image_separable() in the public API?  The reason is
              because the separable filtering routines internally allocate an image each
              time they are called.  If you want to avoid this memory allocation then you
              can call float_spatially_filter_image_separable() and provide the scratch
              image as input.  This allows you to reuse the same scratch image for many
              calls to float_spatially_filter_image_separable() and thereby avoid having it
              allocated and freed for each call.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type,
        typename EXP1,
        typename EXP2,
        typename T
        >
    rectangle spatially_filter_image_separable_down (
        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 = 1,
        bool use_abs = false,
        bool add_to = false
    );
    /*!
        requires
            - in_image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - out_image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - in_img and out_img do not contain pixels with an alpha channel.  That is,
              pixel_traits::has_alpha is false for the pixels in these objects.
            - out_img contains grayscale pixels.
            - is_same_object(in_img, out_img) == false
            - T must be some scalar type
            - scale != 0
            - is_vector(row_filter) == true
            - is_vector(col_filter) == true
            - row_filter.size() % 2 == 1  (i.e. must be odd)
            - col_filter.size() % 2 == 1  (i.e. must be odd)
            - downsample > 0
        ensures
            - This function is equivalent to calling
              spatially_filter_image_separable(in_img,out_img,row_filter,col_filter,scale,use_abs,add_to)
              and then downsampling the output image by a factor of downsample.  Therefore,
              we will have that:
                - #out_img.nr() == ceil((double)in_img.nr()/downsample)
                - #out_img.nc() == ceil((double)in_img.nc()/downsample)
                - #out_img[r][c] == filtered pixel corresponding to in_img[r*downsample][c*downsample]
            - returns a rectangle which indicates what pixels in #out_img are considered
              non-border pixels and therefore contain output from the filter.
            - Note that the first row and column of non-zero padded data are the following
                - first_row == ceil(floor(col_filter.size()/2.0)/downsample)
                - first_col == ceil(floor(row_filter.size()/2.0)/downsample)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        long NR,
        long NC,
        typename T,
        typename U,
        typename in_image_type
        >
    inline void separable_3x3_filter_block_grayscale (
        T (&block)[NR][NC],
        const in_image_type& img,
        const long& r,
        const long& c,
        const U& fe1,
        const U& fm,
        const U& fe2
    );
    /*!
        requires
            - in_image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - T and U should be scalar types
            - shrink_rect(get_rect(img),1).contains(c,r)
            - shrink_rect(get_rect(img),1).contains(c+NC-1,r+NR-1)
        ensures
            - Filters the image in the sub-window of img defined by a rectangle
              with its upper left corner at (c,r) and lower right at (c+NC-1,r+NR-1).
            - The output of the filter is stored in #block.  Note that img will be
              interpreted as a grayscale image.
            - The filter used is defined by the separable filter [fe1 fm fe2].  So the
              spatial filter is thus:
                fe1*fe1  fe1*fm  fe2*fe1
                fe1*fm   fm*fm   fe2*fm
                fe1*fe2  fe2*fm  fe2*fe2
    !*/

// ----------------------------------------------------------------------------------------

    template <
        long NR,
        long NC,
        typename T,
        typename U,
        typename in_image_type
        >
    inline void separable_3x3_filter_block_rgb (
        T (&block)[NR][NC],
        const in_image_type& img,
        const long& r,
        const long& c,
        const U& fe1,
        const U& fm,
        const U& fe2
    );
    /*!
        requires
            - in_image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - img must contain RGB pixels, that is pixel_traits::rgb == true for the pixels
              in img.
            - T should be a struct with .red .green and .blue members.
            - U should be a scalar type
            - shrink_rect(get_rect(img),1).contains(c,r)
            - shrink_rect(get_rect(img),1).contains(c+NC-1,r+NR-1)
        ensures
            - Filters the image in the sub-window of img defined by a rectangle
              with its upper left corner at (c,r) and lower right at (c+NC-1,r+NR-1).
            - The output of the filter is stored in #block.  Note that the filter is applied
              to each color component independently.
            - The filter used is defined by the separable filter [fe1 fm fe2].  So the
              spatial filter is thus:
                fe1*fe1  fe1*fm  fe2*fe1
                fe1*fm   fm*fm   fe2*fm
                fe1*fe2  fe2*fm  fe2*fe2
    !*/

// ----------------------------------------------------------------------------------------

    inline double gaussian (
        double x,
        double sigma
    );
    /*!
        requires
            - sigma > 0
        ensures
            - computes and returns the value of a 1D Gaussian function with mean 0
              and standard deviation sigma at the given x value.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    matrix<T,0,1> create_gaussian_filter (
        double sigma,
        int size
    );
    /*!
        requires
            - sigma > 0
            - size > 0
            - size is an odd number
        ensures
            - returns a separable Gaussian filter F such that:
                - is_vector(F) == true
                - F.size() == size
                - F is suitable for use with the spatially_filter_image_separable() routine
                  and its use with this function corresponds to running a Gaussian filter
                  of sigma width over an image.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type
        >
    rectangle gaussian_blur (
        const in_image_type& in_img,
        out_image_type& out_img,
        double sigma = 1,
        int max_size = 1001
    );
    /*!
        requires
            - in_image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - out_image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - in_img and out_img do not contain pixels with an alpha channel.  That is,
              pixel_traits::has_alpha is false for the pixels in these objects.
            - is_same_object(in_img, out_img) == false
            - sigma > 0
            - max_size > 0
            - max_size is an odd number
        ensures
            - Filters in_img with a Gaussian filter of sigma width.  The actual spatial filter will
              be applied to pixel blocks that are at most max_size wide and max_size tall (note that
              this function will automatically select a smaller block size as appropriate).  The
              results are stored into #out_img.
            - Pixel values are stored into out_img using the assign_pixel() function and therefore
              any applicable color space conversion or value saturation is performed.
            - if (in_img doesn't contain grayscale pixels) then
                - The filter is applied to each color channel independently.
            - Pixels close enough to the edge of in_img to not have the filter still fit
              inside the image are set to zero.
            - #out_img.nc() == in_img.nc()
            - #out_img.nr() == in_img.nr()
            - returns a rectangle which indicates what pixels in #out_img are considered
              non-border pixels and therefore contain output from the filter.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type1,
        typename image_type2
        >
    void sum_filter (
        const image_type1& img,
        image_type2& out,
        const rectangle& rect
    );
    /*!
        requires
            - out.nr() == img.nr()
            - out.nc() == img.nc()
            - image_type1 == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h and it must contain grayscale pixels.
            - image_type2 == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h and it must contain grayscale pixels.
            - is_same_object(img,out) == false
        ensures
            - for all valid r and c:
                - let SUM(r,c) == sum of pixels from img which are inside the rectangle
                  translate_rect(rect, point(c,r)).
                - #out[r][c] == out[r][c] + SUM(r,c)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type1,
        typename image_type2
        >
    void sum_filter_assign (
        const image_type1& img,
        image_type2& out,
        const rectangle& rect
    );
    /*!
        requires
            - image_type1 == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h and it must contain grayscale pixels.
            - image_type2 == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h and it must contain grayscale pixels.
            - is_same_object(img,out) == false
        ensures
            - #out.nr() == img.nr()
            - #out.nc() == img.nc()
            - for all valid r and c:
                - let SUM(r,c) == sum of pixels from img which are inside the rectangle
                  translate_rect(rect, point(c,r)).
                - #out[r][c] == SUM(r,c)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type1,
        typename image_type2
        >
    void max_filter (
        image_type1& img,
        image_type2& out,
        const long width,
        const long height,
        const typename image_traits<image_type1>::pixel_type& thresh
    );
    /*!
        requires
            - out.nr() == img.nr()
            - out.nc() == img.nc()
            - image_type1 == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h and it must contain grayscale pixels.
            - image_type2 == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h and it must contain grayscale pixels.
            - is_same_object(img,out) == false
            - width > 0 && height > 0
        ensures
            - for all valid r and c:
                - let MAX(r,c) == maximum of pixels from img which are inside the rectangle
                  centered_rect(point(c,r), width, height)
                - if (MAX(r,c) >= thresh)
                    - #out[r][c] == out[r][c] + MAX(r,c)
                - else
                    - #out[r][c] == out[r][c] + thresh
            - Does not change the size of img.
            - Uses img as scratch space.  Therefore, the pixel values in img will have
              been modified by this function.  That is, max_filter() destroys the contents
              of img.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SPATIAL_FILTERINg_ABSTRACT_


dlib C++ Library - interpolation_abstract.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_INTERPOlATION_ABSTRACT_
#ifdef DLIB_INTERPOlATION_ABSTRACT_

#include "../pixel.h"
#include "../image_processing/full_object_detection_abstract.h"
#include "../image_processing/generic_image.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class interpolate_nearest_neighbor
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is a tool for performing nearest neighbor interpolation
                on an image.
        !*/

    public:

        template <
            typename image_view_type,
            typename pixel_type
            >
        bool operator() (
            const image_view_type& img,
            const dlib::point& p,
            pixel_type& result
        ) const;
        /*!
            requires
                - image_view_type == an image_view or const_image_view object.
                - pixel_traits<typename image_view_type::pixel_type>::has_alpha == false
                - pixel_traits<pixel_type> is defined
            ensures
                - if (p is located inside img) then
                    - #result == img[p.y()][p.x()]
                      (This assignment is done using assign_pixel(#result, img[p.y()][p.x()]),
                      therefore any necessary color space conversion will be performed)
                    - returns true
                - else
                    - returns false
        !*/

    };

// ----------------------------------------------------------------------------------------

    class interpolate_bilinear
    {

        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is a tool for performing bilinear interpolation
                on an image.  This is performed by looking at the 4 pixels
                nearest to a point and deriving an interpolated value from them.
        !*/

    public:

        template <
            typename T,
            typename image_view_type,
            typename pixel_type
            >
        bool operator() (
            const image_view_type& img,
            const dlib::vector<T,2>& p,
            pixel_type& result
        ) const;
        /*!
            requires
                - image_view_type == an image_view or const_image_view object
                - pixel_traits<typename image_view_type::pixel_type>::has_alpha == false
                - pixel_traits<pixel_type> is defined
            ensures
                - if (there is an interpolatable image location at point p in img) then
                    - #result == the interpolated pixel value from img at point p.
                    - assign_pixel() will be used to write to #result, therefore any
                      necessary color space conversion will be performed.
                    - returns true
                    - if img contains RGB pixels then the interpolation will be in color.
                      Otherwise, the interpolation will be performed in a grayscale mode.
                - else
                    - returns false
        !*/
    };

// ----------------------------------------------------------------------------------------

    class interpolate_quadratic
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is a tool for performing quadratic interpolation
                on an image.  This is performed by looking at the 9 pixels
                nearest to a point and deriving an interpolated value from them.
        !*/

    public:

        template <
            typename T,
            typename image_view_type,
            typename pixel_type
            >
        bool operator() (
            const image_view_type& img,
            const dlib::vector<T,2>& p,
            pixel_type& result
        ) const;
        /*!
            requires
                - image_view_type == an image_view or const_image_view object.
                - pixel_traits<typename image_view_type::pixel_type>::has_alpha == false
                - pixel_traits<pixel_type> is defined
            ensures
                - if (there is an interpolatable image location at point p in img) then
                    - #result == the interpolated pixel value from img at point p
                    - assign_pixel() will be used to write to #result, therefore any
                      necessary color space conversion will be performed.
                    - returns true
                    - if img contains RGB pixels then the interpolation will be in color.
                      Otherwise, the interpolation will be performed in a grayscale mode.
                - else
                    - returns false
        !*/
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class black_background
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is a function object which simply sets a pixel
                to have a black value.
        !*/

    public:
        template <typename pixel_type>
        void operator() ( pixel_type& p) const { assign_pixel(p, 0); }
    };

// ----------------------------------------------------------------------------------------

    class white_background
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is a function object which simply sets a pixel
                to have a white value.
        !*/

    public:
        template <typename pixel_type>
        void operator() ( pixel_type& p) const { assign_pixel(p, 255); }
    };

// ----------------------------------------------------------------------------------------

    class no_background
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is a function object which does nothing.  It is useful
                when used with the transform_image() routine defined below
                if no modification of uninterpolated output pixels is desired.
        !*/
    public:
        template <typename pixel_type>
        void operator() ( pixel_type& ) const { }
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename image_type1,
        typename image_type2,
        typename interpolation_type,
        typename point_mapping_type,
        typename background_type
        >
    void transform_image (
        const image_type1& in_img,
        image_type2& out_img,
        const interpolation_type& interp,
        const point_mapping_type& map_point,
        const background_type& set_background,
        const rectangle& area
    );
    /*!
        requires
            - image_type1 == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - image_type2 == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - interpolation_type == interpolate_nearest_neighbor, interpolate_bilinear,
              interpolate_quadratic, or a type with a compatible interface.
            - map_point should be a function which takes dlib::vector<T,2> objects and
              returns dlib::vector<T,2> objects.  An example is point_transform_affine.
            - set_background should be a function which can take a single argument of
              type image_traits<image_type2>::pixel_type.  Examples are black_background,
              white_background, and no_background.
            - get_rect(out_img).contains(area) == true
            - is_same_object(in_img, out_img) == false
        ensures
            - The map_point function defines a mapping from pixels in out_img to pixels
              in in_img.  transform_image() uses this mapping, along with the supplied
              interpolation routine interp, to fill the region of out_img defined by
              area with an interpolated copy of in_img.
            - This function does not change the size of out_img.
            - Only pixels inside the region defined by area in out_img are modified.
            - For all locations r and c such that area.contains(c,r) but have no corresponding
              locations in in_img:
                - set_background(out_img[r][c]) is invoked
                  (i.e. some parts of out_img might correspond to areas outside in_img and
                  therefore can't supply interpolated values.  In these cases, these
                  pixels can be assigned a value by the supplied set_background() routine)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type1,
        typename image_type2,
        typename interpolation_type,
        typename point_mapping_type,
        typename background_type
        >
    void transform_image (
        const image_type1& in_img,
        image_type2& out_img,
        const interpolation_type& interp,
        const point_mapping_type& map_point,
        const background_type& set_background
    );
    /*!
        requires
            - image_type1 == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - image_type2 == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - interpolation_type == interpolate_nearest_neighbor, interpolate_bilinear,
              interpolate_quadratic, or a type with a compatible interface.
            - map_point should be a function which takes dlib::vector<T,2> objects and
              returns dlib::vector<T,2> objects.  An example is point_transform_affine.
            - set_background should be a function which can take a single argument of
              type image_traits<image_type2>::pixel_type.  Examples are black_background, white_background,
              and no_background.
            - is_same_object(in_img, out_img) == false
        ensures
            - performs:
              transform_image(in_img, out_img, interp, map_point, set_background, get_rect(out_img));
              (i.e. runs transform_image() on the entire out_img)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type1,
        typename image_type2,
        typename interpolation_type,
        typename point_mapping_type
        >
    void transform_image (
        const image_type1& in_img,
        image_type2& out_img,
        const interpolation_type& interp,
        const point_mapping_type& map_point
    );
    /*!
        requires
            - image_type1 == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - image_type2 == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - interpolation_type == interpolate_nearest_neighbor, interpolate_bilinear,
              interpolate_quadratic, or a type with a compatible interface.
            - map_point should be a function which takes dlib::vector<T,2> objects and
              returns dlib::vector<T,2> objects.  An example is point_transform_affine.
            - is_same_object(in_img, out_img) == false
        ensures
            - performs:
              transform_image(in_img, out_img, interp, map_point, black_background(), get_rect(out_img));
              (i.e. runs transform_image() on the entire out_img and sets non-interpolated
              pixels to black)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type1,
        typename image_type2,
        typename interpolation_type
        >
    point_transform_affine rotate_image (
        const image_type1& in_img,
        image_type2& out_img,
        double angle,
        const interpolation_type& interp
    );
    /*!
        requires
            - image_type1 == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - image_type2 == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - interpolation_type == interpolate_nearest_neighbor, interpolate_bilinear,
              interpolate_quadratic, or a type with a compatible interface.
            - is_same_object(in_img, out_img) == false
        ensures
            - #out_img == a copy of in_img which has been rotated angle radians counter clockwise.
              The rotation is performed with respect to the center of the image.
            - Parts of #out_img which have no corresponding locations in in_img are set to black.
            - uses the supplied interpolation routine interp to perform the necessary
              pixel interpolation.
            - returns a transformation object that maps points in in_img into their corresponding
              location in #out_img.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type1,
        typename image_type2
        >
    point_transform_affine rotate_image (
        const image_type1& in_img,
        image_type2& out_img,
        double angle
    );
    /*!
        requires
            - image_type1 == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - image_type2 == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - pixel_traits<typename image_traits<image_type1>::pixel_type>::has_alpha == false
            - is_same_object(in_img, out_img) == false
        ensures
            - #out_img == a copy of in_img which has been rotated angle radians counter clockwise.
              The rotation is performed with respect to the center of the image.
            - Parts of #out_img which have no corresponding locations in in_img are set to black.
            - uses the interpolate_quadratic object to perform the necessary pixel interpolation.
            - returns a transformation object that maps points in in_img into their corresponding
              location in #out_img.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type1,
        typename image_type2,
        typename interpolation_type
        >
    void resize_image (
        const image_type1& in_img,
        image_type2& out_img,
        const interpolation_type& interp
    );
    /*!
        requires
            - image_type1 == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - image_type2 == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - interpolation_type == interpolate_nearest_neighbor, interpolate_bilinear,
              interpolate_quadratic, or a type with a compatible interface.
            - is_same_object(in_img, out_img) == false
        ensures
            - #out_img == A copy of in_img which has been stretched so that it
              fits exactly into out_img.
            - The size of out_img is not modified.  I.e.
                - #out_img.nr() == out_img.nr()
                - #out_img.nc() == out_img.nc()
            - uses the supplied interpolation routine interp to perform the necessary
              pixel interpolation.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type1,
        typename image_type2
        >
    void resize_image (
        const image_type1& in_img,
        image_type2& out_img
    );
    /*!
        requires
            - image_type1 == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - image_type2 == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - pixel_traits<typename image_traits<image_type1>::pixel_type>::has_alpha == false
            - is_same_object(in_img, out_img) == false
        ensures
            - #out_img == A copy of in_img which has been stretched so that it
              fits exactly into out_img.
            - The size of out_img is not modified.  I.e.
                - #out_img.nr() == out_img.nr()
                - #out_img.nc() == out_img.nc()
            - Uses the bilinear interpolation to perform the necessary pixel interpolation.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type1,
        typename image_type2
        >
    point_transform_affine flip_image_left_right (
        const image_type1& in_img,
        image_type2& out_img
    );
    /*!
        requires
            - image_type1 == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - image_type2 == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - is_same_object(in_img, out_img) == false
        ensures
            - #out_img.nr() == in_img.nr()
            - #out_img.nc() == in_img.nc()
            - #out_img == a copy of in_img which has been flipped from left to right.
              (i.e. it is flipped as if viewed though a mirror)
            - returns a transformation object that maps points in in_img into their
              corresponding location in #out_img.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_array_type,
        typename T
        >
    void add_image_left_right_flips (
        image_array_type& images,
        std::vector<std::vector<T> >& objects
    );
    /*!
        requires
            - image_array_type == a dlib::array or std::vector of image objects that each
              implement the interface defined in dlib/image_processing/generic_image.h
            - T == rectangle or full_object_detection
            - images.size() == objects.size()
        ensures
            - This function computes all the left/right flips of the contents of images and
              then appends them onto the end of the images array.  It also finds the
              left/right flips of the rectangles in objects and similarly appends them into
              objects.  That is, we assume objects[i] is the set of bounding boxes in
              images[i] and we flip the bounding boxes so that they still bound the same
              objects in the new flipped images.
            - #images.size() == images.size()*2
            - #objects.size() == objects.size()*2
            - All the original elements of images and objects are left unmodified.  That
              is, this function only appends new elements to each of these containers.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_array_type,
        typename T,
        typename U
        >
    void add_image_left_right_flips (
        image_array_type& images,
        std::vector<std::vector<T> >& objects,
        std::vector<std::vector<U> >& objects2
    );
    /*!
        requires
            - image_array_type == a dlib::array or std::vector of image objects that each
              implement the interface defined in dlib/image_processing/generic_image.h
            - images.size() == objects.size()
            - images.size() == objects2.size()
            - T == rectangle or full_object_detection
            - U == rectangle or full_object_detection
        ensures
            - This function computes all the left/right flips of the contents of images and
              then appends them onto the end of the images array.  It also finds the
              left/right flips of the rectangles in objects and objects2 and similarly
              appends them into objects and objects2 respectively.  That is, we assume
              objects[i] is the set of bounding boxes in images[i] and we flip the bounding
              boxes so that they still bound the same objects in the new flipped images.
              We similarly flip the boxes in objects2.
            - #images.size()   == images.size()*2
            - #objects.size()  == objects.size()*2
            - #objects2.size() == objects2.size()*2
            - All the original elements of images, objects, and objects2 are left unmodified.
              That is, this function only appends new elements to each of these containers.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_array_type,
        typename EXP,
        typename T,
        typename U
        >
    void add_image_rotations (
        const matrix_exp<EXP>& angles,
        image_array_type& images,
        std::vector<std::vector<T> >& objects,
        std::vector<std::vector<U> >& objects2
    );
    /*!
        requires
            - image_array_type == a dlib::array or std::vector of image objects that each
              implement the interface defined in dlib/image_processing/generic_image.h
            - is_vector(angles) == true
            - angles.size() > 0
            - images.size() == objects.size()
            - images.size() == objects2.size()
            - T == rectangle or full_object_detection
            - U == rectangle or full_object_detection
        ensures
            - This function computes angles.size() different rotations of all the given
              images and then replaces the contents of images with those rotations of the
              input dataset.  We will also adjust the rectangles inside objects and
              objects2 so that they still bound the same objects in the new rotated images.
              That is, we assume objects[i] and objects2[i] are bounding boxes for things
              in images[i].  So we will adjust the positions of the boxes in objects and
              objects2 accordingly.
            - The elements of angles are interpreted as angles in radians and we will
              rotate the images around their center using the values in angles.  Moreover,
              the rotation is done counter clockwise.
            - #images.size()   == images.size()*angles.size()
            - #objects.size()  == objects.size()*angles.size()
            - #objects2.size() == objects2.size()*angles.size()
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_array_type,
        typename EXP,
        typename T
        >
    void add_image_rotations (
        const matrix_exp<EXP>& angles,
        image_array_type& images,
        std::vector<std::vector<T> >& objects
    );
    /*!
        requires
            - image_array_type == a dlib::array or std::vector of image objects that each
              implement the interface defined in dlib/image_processing/generic_image.h
            - is_vector(angles) == true
            - angles.size() > 0
            - images.size() == objects.size()
            - T == rectangle or full_object_detection
        ensures
            - This function is identical to the add_image_rotations() define above except
              that it doesn't have objects2 as an argument.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_array_type
        >
    void flip_image_dataset_left_right (
        image_array_type& images,
        std::vector<std::vector<rectangle> >& objects
    );
    /*!
        requires
            - image_array_type == a dlib::array or std::vector of image objects that each
              implement the interface defined in dlib/image_processing/generic_image.h
            - images.size() == objects.size()
        ensures
            - This function replaces each image in images with the left/right flipped
              version of the image.  Therefore, #images[i] will contain the left/right
              flipped version of images[i].  It also flips all the rectangles in objects so
              that they still bound the same visual objects in each image.
            - #images.size() == image.size()
            - #objects.size() == objects.size()
            - for all valid i:
                #objects[i].size() == objects[i].size()
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_array_type
        >
    void flip_image_dataset_left_right (
        image_array_type& images,
        std::vector<std::vector<rectangle> >& objects,
        std::vector<std::vector<rectangle> >& objects2
    );
    /*!
        requires
            - image_array_type == a dlib::array or std::vector of image objects that each
              implement the interface defined in dlib/image_processing/generic_image.h
            - images.size() == objects.size()
            - images.size() == objects2.size()
        ensures
            - This function replaces each image in images with the left/right flipped
              version of the image.  Therefore, #images[i] will contain the left/right
              flipped version of images[i].  It also flips all the rectangles in objects
              and objects2 so that they still bound the same visual objects in each image.
            - #images.size() == image.size()
            - #objects.size() == objects.size()
            - #objects2.size() == objects2.size()
            - for all valid i:
                #objects[i].size() == objects[i].size()
            - for all valid i:
                #objects2[i].size() == objects2[i].size()
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename pyramid_type,
        typename image_array_type
        >
    void upsample_image_dataset (
        image_array_type& images,
        std::vector<std::vector<rectangle> >& objects
    );
    /*!
        requires
            - image_array_type == a dlib::array or std::vector of image objects that each
              implement the interface defined in dlib/image_processing/generic_image.h
            - images.size() == objects.size()
        ensures
            - This function replaces each image in images with an upsampled version of that
              image.  Each image is upsampled using pyramid_up() and the given
              pyramid_type.  Therefore, #images[i] will contain the larger upsampled
              version of images[i].  It also adjusts all the rectangles in objects so that
              they still bound the same visual objects in each image.
            - #images.size() == image.size()
            - #objects.size() == objects.size()
            - for all valid i:
                #objects[i].size() == objects[i].size()
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename pyramid_type,
        typename image_array_type,
        >
    void upsample_image_dataset (
        image_array_type& images,
        std::vector<std::vector<rectangle> >& objects,
        std::vector<std::vector<rectangle> >& objects2
    );
    /*!
        requires
            - image_array_type == a dlib::array or std::vector of image objects that each
              implement the interface defined in dlib/image_processing/generic_image.h
            - images.size() == objects.size()
            - images.size() == objects2.size()
        ensures
            - This function replaces each image in images with an upsampled version of that
              image.  Each image is upsampled using pyramid_up() and the given
              pyramid_type.  Therefore, #images[i] will contain the larger upsampled
              version of images[i].  It also adjusts all the rectangles in objects and
              objects2 so that they still bound the same visual objects in each image.
            - #images.size() == image.size()
            - #objects.size() == objects.size()
            - #objects2.size() == objects2.size()
            - for all valid i:
                #objects[i].size() == objects[i].size()
            - for all valid i:
                #objects2[i].size() == objects2[i].size()
    !*/

// ----------------------------------------------------------------------------------------

    template <typename image_array_type>
    void rotate_image_dataset (
        double angle,
        image_array_type& images,
        std::vector<std::vector<rectangle> >& objects
    );
    /*!
        requires
            - image_array_type == a dlib::array or std::vector of image objects that each
              implement the interface defined in dlib/image_processing/generic_image.h
            - images.size() == objects.size()
        ensures
            - This function replaces each image in images with a rotated version of that
              image.  In particular, each image is rotated using
              rotate_image(original,rotated,angle).  Therefore, the images are rotated
              angle radians counter clockwise around their centers. That is, #images[i]
              will contain the rotated version of images[i].  It also adjusts all
              the rectangles in objects so that they still bound the same visual objects in
              each image.
            - All the rectangles will still have the same sizes and aspect ratios after
              rotation.  They will simply have had their positions adjusted so they still
              fall on the same objects.
            - #images.size() == image.size()
            - #objects.size() == objects.size()
            - for all valid i:
                #objects[i].size() == objects[i].size()
    !*/

// ----------------------------------------------------------------------------------------

    template <typename image_array_type>
    void rotate_image_dataset (
        double angle,
        image_array_type& images,
        std::vector<std::vector<rectangle> >& objects,
        std::vector<std::vector<rectangle> >& objects2
    );
    /*!
        requires
            - image_array_type == a dlib::array or std::vector of image objects that each
              implement the interface defined in dlib/image_processing/generic_image.h
            - images.size() == objects.size()
            - images.size() == objects2.size()
        ensures
            - This function replaces each image in images with a rotated version of that
              image.  In particular, each image is rotated using
              rotate_image(original,rotated,angle).  Therefore, the images are rotated
              angle radians counter clockwise around their centers. That is, #images[i]
              will contain the rotated version of images[i].  It also adjusts all
              the rectangles in objects and objects2 so that they still bound the same
              visual objects in each image.
            - All the rectangles will still have the same sizes and aspect ratios after
              rotation.  They will simply have had their positions adjusted so they still
              fall on the same objects.
            - #images.size() == image.size()
            - #objects.size() == objects.size()
            - #objects2.size() == objects2.size()
            - for all valid i:
                #objects[i].size() == objects[i].size()
            - for all valid i:
                #objects2[i].size() == objects2[i].size()
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type1,
        typename image_type2
        >
    void flip_image_up_down (
        const image_type1& in_img,
        image_type2& out_img
    );
    /*!
        requires
            - image_type1 == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - image_type2 == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - is_same_object(in_img, out_img) == false
        ensures
            - #out_img.nr() == in_img.nr()
            - #out_img.nc() == in_img.nc()
            - #out_img == a copy of in_img which has been flipped upside down.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type1,
        typename image_type2,
        typename pyramid_type,
        typename interpolation_type
        >
    void pyramid_up (
        const image_type1& in_img,
        image_type2& out_img,
        const pyramid_type& pyr,
        const interpolation_type& interp
    );
    /*!
        requires
            - image_type1 == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - image_type2 == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - pyramid_type == a type compatible with the image pyramid objects defined
              in dlib/image_transforms/image_pyramid_abstract.h
            - interpolation_type == interpolate_nearest_neighbor, interpolate_bilinear,
              interpolate_quadratic, or a type with a compatible interface.
            - is_same_object(in_img, out_img) == false
        ensures
            - This function inverts the downsampling transformation performed by pyr().
              In particular, it attempts to make an image, out_img, which would result
              in in_img when downsampled with pyr().
            - #out_img == An upsampled copy of in_img.  In particular, downsampling
              #out_img 1 time with pyr() should result in a final image which looks like
              in_img.
            - Uses the supplied interpolation routine interp to perform the necessary
              pixel interpolation.
            - Note that downsampling an image with pyr() and then upsampling it with
              pyramid_up() will not necessarily result in a final image which is
              the same size as the original.  This is because the exact size of the
              original image cannot be determined based on the downsampled image.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type1,
        typename image_type2,
        typename pyramid_type
        >
    void pyramid_up (
        const image_type1& in_img,
        image_type2& out_img,
        const pyramid_type& pyr
    );
    /*!
        requires
            - image_type1 == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - image_type2 == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - pyramid_type == a type compatible with the image pyramid objects defined
              in dlib/image_transforms/image_pyramid_abstract.h
            - is_same_object(in_img, out_img) == false
        ensures
            - performs: pyramid_up(in_img, out_img, pyr, interpolate_bilinear());
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type,
        typename pyramid_type
        >
    void pyramid_up (
        image_type& img,
        const pyramid_type& pyr
    );
    /*!
        requires
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - pyramid_type == a type compatible with the image pyramid objects defined
              in dlib/image_transforms/image_pyramid_abstract.h
        ensures
            - Performs an in-place version of pyramid_up() on the given image.  In
              particular, this function is equivalent to:
                pyramid_up(img, temp, pyr);
                temp.swap(img);
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    void pyramid_up (
        image_type& img
    );
    /*!
        requires
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
        ensures
            - performs: pyramid_up(img, pyramid_down<2>());
              (i.e. it upsamples the given image and doubles it in size.)
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    struct chip_dims
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is a simple tool for passing in a pair of row and column values to the
                chip_details constructor.
        !*/

        chip_dims (
            unsigned long rows_,
            unsigned long cols_
        ) : rows(rows_), cols(cols_) { }

        unsigned long rows;
        unsigned long cols;
    };

// ----------------------------------------------------------------------------------------

    struct chip_details
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object describes where an image chip is to be extracted from within
                another image.  In particular, it specifies that the image chip is
                contained within the rectangle this->rect and that prior to extraction the
                image should be rotated counter-clockwise by this->angle radians.  Finally,
                the extracted chip should have this->rows rows and this->cols columns in it
                regardless of the shape of this->rect.  This means that the extracted chip
                will be stretched to fit via bilinear interpolation when necessary.
        !*/

        chip_details(
        );
        /*!
            ensures
                - #rect.is_empty() == true
                - #size() == 0
                - #angle == 0
                - #rows == 0
                - #cols == 0
        !*/

        chip_details(
            const drectangle& rect_
        );
        /*!
            ensures
                - #rect == rect_
                - #size() == rect_.area()
                - #angle == 0
                - #rows == rect_.height()
                - #cols == rect_.width()
        !*/

        chip_details(
            const rectangle& rect_
        );
        /*!
            ensures
                - #rect == rect_
                - #size() == rect_.area()
                - #angle == 0
                - #rows == rect_.height()
                - #cols == rect_.width()
        !*/

        chip_details(
            const drectangle& rect_,
            unsigned long size_
        );
        /*!
            ensures
                - #rect == rect_
                - #size() == size_
                - #angle == 0
                - #rows and #cols is set such that the total size of the chip is as close
                  to size_ as possible but still matches the aspect ratio of rect_.
                - As long as size_ and the aspect ratio of of rect_ stays constant then
                  #rows and #cols will always have the same values.  This means that, for
                  example, if you want all your chips to have the same dimensions then
                  ensure that size_ is always the same and also that rect_ always has the
                  same aspect ratio.  Otherwise the calculated values of #rows and #cols
                  may be different for different chips.  Alternatively, you can use the
                  chip_details constructor below that lets you specify the exact values for
                  rows and cols.
        !*/

        chip_details(
            const drectangle& rect_,
            unsigned long size_,
            double angle_
        );
        /*!
            ensures
                - #rect == rect_
                - #size() == size_
                - #angle == angle_
                - #rows and #cols is set such that the total size of the chip is as close
                  to size_ as possible but still matches the aspect ratio of rect_.
                - As long as size_ and the aspect ratio of of rect_ stays constant then
                  #rows and #cols will always have the same values.  This means that, for
                  example, if you want all your chips to have the same dimensions then
                  ensure that size_ is always the same and also that rect_ always has the
                  same aspect ratio.  Otherwise the calculated values of #rows and #cols
                  may be different for different chips.  Alternatively, you can use the
                  chip_details constructor below that lets you specify the exact values for
                  rows and cols.
        !*/

        chip_details(
            const drectangle& rect_,
            const chip_dims& dims
        );
        /*!
            ensures
                - #rect == rect_
                - #size() == dims.rows*dims.cols
                - #angle == 0
                - #rows == dims.rows
                - #cols == dims.cols
        !*/

        chip_details(
            const drectangle& rect_,
            const chip_dims& dims,
            double angle_
        );
        /*!
            ensures
                - #rect == rect_
                - #size() == dims.rows*dims.cols
                - #angle == angle_
                - #rows == dims.rows
                - #cols == dims.cols
        !*/

        template <typename T>
        chip_details(
            const std::vector<dlib::vector<T,2> >& chip_points,
            const std::vector<dlib::vector<T,2> >& img_points,
            const chip_dims& dims
        );
        /*!
            requires
                - chip_points.size() == img_points.size()
                - chip_points.size() >= 2
            ensures
                - The chip will be extracted such that the pixel locations chip_points[i]
                  in the chip are mapped to img_points[i] in the original image by a
                  similarity transform.  That is, if you know the pixelwize mapping you
                  want between the chip and the original image then you use this function
                  of chip_details constructor to define the mapping.
                - #rows == dims.rows
                - #cols == dims.cols
                - #size() == dims.rows*dims.cols
                - #rect and #angle are computed based on the given size of the output chip
                  (specified by dims) and the similarity transform between the chip and
                  image (specified by chip_points and img_points).
        !*/

        inline unsigned long size() const { return rows*cols; }
        /*!
            ensures
                - returns the number of pixels in this chip.  This is just rows*cols.
        !*/

        drectangle rect;
        double angle;
        unsigned long rows;
        unsigned long cols;
    };

// ----------------------------------------------------------------------------------------

    point_transform_affine get_mapping_to_chip (
        const chip_details& details
    );
    /*!
        ensures
            - returns a transformation that maps from the pixels in the original image
              to the pixels in the cropped image defined by the given details object.
    !*/

// ----------------------------------------------------------------------------------------

    full_object_detection map_det_to_chip (
        const full_object_detection& det,
        const chip_details& details
    );
    /*!
        ensures
            - Maps the given detection into the pixel space of the image chip defined by
              the given details object.  That is, this function returns an object D such
              that:
                - D.get_rect() == a box that bounds the same thing in the image chip as
                  det.get_rect() bounds in the original image the chip is extracted from.
                - for all valid i:
                    - D.part(i) == the location in the image chip corresponding to
                      det.part(i) in the original image.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type1,
        typename image_type2
        >
    void extract_image_chips (
        const image_type1& img,
        const std::vector<chip_details>& chip_locations,
        dlib::array<image_type2>& chips
    );
    /*!
        requires
            - image_type1 == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - image_type2 == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - pixel_traits<typename image_traits<image_type1>::pixel_type>::has_alpha == false
            - for all valid i:
                - chip_locations[i].rect.is_empty() == false
                - chip_locations[i].size() != 0
        ensures
            - This function extracts "chips" from an image.  That is, it takes a list of
              rectangular sub-windows (i.e. chips) within an image and extracts those
              sub-windows, storing each into its own image.  It also scales and rotates the
              image chips according to the instructions inside each chip_details object.
            - #chips == the extracted image chips
            - #chips.size() == chip_locations.size()
            - for all valid i:
                - #chips[i] == The image chip extracted from the position
                  chip_locations[i].rect in img.
                - #chips[i].nr() == chip_locations[i].rows
                - #chips[i].nc() == chip_locations[i].cols
                - The image will have been rotated counter-clockwise by
                  chip_locations[i].angle radians, around the center of
                  chip_locations[i].rect, before the chip was extracted.
            - Any pixels in an image chip that go outside img are set to 0 (i.e. black).
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type1,
        typename image_type2
        >
    void extract_image_chip (
        const image_type1& img,
        const chip_details& chip_location,
        image_type2& chip
    );
    /*!
        ensures
            - This function simply calls extract_image_chips() with a single chip location
              and stores the single output chip into #chip.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    struct sub_image_proxy
    {
        /*!
            REQUIREMENTS ON image_type
                - image_type == an image object that implements the interface defined in
                  dlib/image_processing/generic_image.h

            WHAT THIS OBJECT REPRESENTS
                This is a lightweight image object for referencing a subwindow of an image.
                It implements the generic image interface and can therefore be used with
                any function that expects a generic image, excepting that you cannot change
                the size of a sub_image_proxy.

                Note that it only stores a pointer to the image data given to its
                constructor and therefore does not perform a copy.  Moreover, this means
                that an instance of this object becomes invalid after the underlying image
                data it references is destroyed.
        !*/
        sub_image_proxy (
            T& img,
            const rectangle& rect
        );
        /*!
            ensures
                - This object is an image that represents the part of img contained within
                  rect.  If rect is larger than img then rect is cropped so that it does
                  not go outside img.
        !*/
    };

    template <
        typename image_type
        >
    sub_image_proxy<image_type> sub_image (
        image_type& img,
        const rectangle& rect
    );
    /*!
        requires
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
        ensures
            - returns sub_image_proxy<image_type>(img,rect)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    struct const_sub_image_proxy
    {
        /*!
            REQUIREMENTS ON image_type
                - image_type == an image object that implements the interface defined in
                  dlib/image_processing/generic_image.h

            WHAT THIS OBJECT REPRESENTS
                This object is just like sub_image_proxy except that it does not allow the
                pixel data to be modified.
        !*/
        const_sub_image_proxy (
            const T& img,
            const rectangle& rect
        );
        /*!
            ensures
                - This object is an image that represents the part of img contained within
                  rect.  If rect is larger than img then rect is cropped so that it does
                  not go outside img.
        !*/
    };

    template <
        typename image_type
        >
    const const_sub_image_proxy<image_type> sub_image (
        const image_type& img,
        const rectangle& rect
    );
    /*!
        requires
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
        ensures
            - returns const_sub_image_proxy<image_type>(img,rect)
    !*/

// ----------------------------------------------------------------------------------------

    chip_details get_face_chip_details (
        const full_object_detection& det,
        const unsigned long size = 200,
        const double padding = 0.2
    );
    /*!
        requires
            - det.num_parts() == 68
            - size > 0
            - padding >= 0
        ensures
            - This function assumes det contains a human face detection with face parts
              annotated using the annotation scheme from the iBUG 300-W face landmark
              dataset.  Given these assumptions, it creates a chip_details object that will
              extract a copy of the face that has been rotated upright, centered, and
              scaled to a standard size when given to extract_image_chip().
            - The extracted chips will have size rows and columns in them.
            - if padding == 0 then the chip will be closely cropped around the face.
              Setting larger padding values will result a looser cropping.  In particular,
              a padding of 0.5 would double the width of the cropped area, a value of 1
              would triple it, and so forth.
    !*/

// ----------------------------------------------------------------------------------------

    std::vector<chip_details> get_face_chip_details (
        const std::vector<full_object_detection>& dets,
        const unsigned long size = 200,
        const double padding = 0.2
    );
    /*!
        requires
            - for all valid i:
                - det[i].num_parts() == 68
            - size > 0
            - padding >= 0
        ensures
            - This function is identical to the version of get_face_chip_details() defined
              above except that it creates and returns an array of chip_details objects,
              one for each input full_object_detection.
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

}

#endif // DLIB_INTERPOlATION_ABSTRACT_


dlib C++ Library - image_pyramid_abstract.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_IMAGE_PYRaMID_ABSTRACT_Hh_
#ifdef DLIB_IMAGE_PYRaMID_ABSTRACT_Hh_

#include "../pixel.h"
#include "../array2d.h"
#include "../geometry.h"
#include "../image_processing/generic_image.h"

namespace dlib
{

    template <
        unsigned int N
        >
    class pyramid_down : noncopyable
    {
        /*!
            REQUIREMENTS ON N
                N > 0

            WHAT THIS OBJECT REPRESENTS
                This is a simple functor to help create image pyramids.  In particular, it
                downsamples images at a ratio of N to N-1.

                Note that setting N to 1 means that this object functions like
                pyramid_disable (defined at the bottom of this file).

                WARNING, when mapping rectangles from one layer of a pyramid
                to another you might end up with rectangles which extend slightly
                outside your images.  This is because points on the border of an
                image at a higher pyramid layer might correspond to points outside
                images at lower layers.  So just keep this in mind.  Note also
                that it's easy to deal with.  Just say something like this:
                    rect = rect.intersect(get_rect(my_image)); // keep rect inside my_image
        !*/
    public:

        template <
            typename in_image_type,
            typename out_image_type
            >
        void operator() (
            const in_image_type& original,
            out_image_type& down
        ) const;
        /*!
            requires
                - is_same_object(original, down) == false
                - in_image_type == an image object that implements the interface defined in
                  dlib/image_processing/generic_image.h
                - out_image_type == an image object that implements the interface defined in
                  dlib/image_processing/generic_image.h
                - for both pixel types P in the input and output images, we require:
                    - pixel_traits<P>::has_alpha == false
            ensures
                - #down will contain an image that is roughly (N-1)/N times the size of the
                  original image.
                - If both input and output images contain RGB pixels then the downsampled image will
                  be in color.  Otherwise, the downsampling will be performed in a grayscale mode.
                - The location of a point P in original image will show up at point point_down(P)
                  in the #down image.
                - Note that some points on the border of the original image might correspond to
                  points outside the #down image.
        !*/

        template <
            typename image_type
            >
        void operator() (
            image_type& img
        ) const;
        /*!
            requires
                - image_type == an image object that implements the interface defined in
                  dlib/image_processing/generic_image.h
                - pixel_traits<typename image_traits<image_type>::pixel_type>::has_alpha == false
            ensures
                - This function downsamples the given image and stores the results in #img.
                  In particular, it is equivalent to performing:
                    (*this)(img, temp);
                    swap(img, temp);
        !*/

    // -------------------------------

        template <typename T>
        vector<double,2> point_down (
            const vector<T,2>& p
        ) const;
        /*!
            ensures
                - interprets p as a point in a parent image and returns the
                  point in a downsampled image which corresponds to p.
                - This function is the inverse of point_up().  I.e. for a point P:
                  point_down(point_up(P)) == P
        !*/

        template <typename T>
        vector<double,2> point_up (
            const vector<T,2>& p
        ) const;
        /*!
            ensures
                - interprets p as a point in a downsampled image and returns the
                  point in a parent image which corresponds to p.
                - This function is the inverse of point_down().  I.e. for a point P:
                  point_up(point_down(P)) == P
        !*/

        drectangle rect_down (
            const drectangle& rect
        ) const;
        /*!
            ensures
                - returns drectangle(point_down(rect.tl_corner()), point_down(rect.br_corner()));
                  (i.e. maps rect into a downsampled)
        !*/

        drectangle rect_up (
            const drectangle& rect
        ) const;
        /*!
            ensures
                - returns drectangle(point_up(rect.tl_corner()), point_up(rect.br_corner()));
                  (i.e. maps rect into a parent image)
        !*/

    // -------------------------------

        template <typename T>
        vector<double,2> point_down (
            const vector<T,2>& p,
            unsigned int levels
        ) const;
        /*!
            ensures
                - applies point_down() to p levels times and returns the result.
                  (i.e. point_down(p,2) == point_down(point_down(p)),
                        point_down(p,1) == point_down(p),
                        point_down(p,0) == p,  etc. )
        !*/

        template <typename T>
        vector<double,2> point_up (
            const vector<T,2>& p,
            unsigned int levels
        ) const;
        /*!
            ensures
                - applies point_up() to p levels times and returns the result.
                  (i.e. point_up(p,2) == point_up(point_up(p)),
                        point_up(p,1) == point_up(p),
                        point_up(p,0) == p,  etc. )
        !*/

        drectangle rect_down (
            const drectangle& rect,
            unsigned int levels
        ) const;
        /*!
            ensures
                - returns drectangle(point_down(rect.tl_corner(),levels), point_down(rect.br_corner(),levels));
                  (i.e. Basically applies rect_down() to rect levels times and returns the result.)
        !*/

        drectangle rect_up (
            const drectangle& rect,
            unsigned int levels
        ) const;
        /*!
            ensures
                - returns drectangle(point_up(rect.tl_corner(),levels), point_up(rect.br_corner(),levels));
                  (i.e. Basically applies rect_up() to rect levels times and returns the result.)
        !*/

    };

// ----------------------------------------------------------------------------------------

    class pyramid_disable : noncopyable
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is a function object with an interface identical to pyramid_down (defined
                at the top of this file) except that it downsamples images at a ratio of infinity
                to 1.  That means it always outputs images of size 0 regardless of the size
                of the inputs.

                This is useful because it can be supplied to routines which take a pyramid_down
                function object and it will essentially disable pyramid processing.  This way,
                a pyramid oriented function can be turned into a regular routine which processes
                just the original undownsampled image.
        !*/
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_IMAGE_PYRaMID_ABSTRACT_Hh_


dlib C++ Library - draw_abstract.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_DRAW_IMAGe_ABSTRACT
#ifdef DLIB_DRAW_IMAGe_ABSTRACT

#include "../matrix.h"
#include "../image_processing/generic_image.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename image_type,
        typename pixel_type
        >
    void draw_line (
        image_type& img,
        const point& p1,
        const point& p2,
        const pixel_type& val
    );
    /*!
        requires
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
        ensures
            - #img.nr() == img.nr() && #img.nc() == img.nc()
              (i.e. the dimensions of the input image are not changed)
            - for all valid r and c that are on the line between point p1 and p2:
                - performs assign_pixel(img[r][c], val)
                  (i.e. it draws the line from p1 to p2 onto the image)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type,
        typename pixel_type
        >
    void draw_line (
        long x1,
        long y1,
        long x2,
        long y2,
        image_type& img,
        const pixel_type& val
    );
    /*!
        requires
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
        ensures
            - performs draw_line(img, point(x1,y1), point(x2,y2), val)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type,
        typename pixel_type
        >
    void draw_rectangle (
        image_type& img,
        const rectangle& rect,
        const pixel_type& val,
        unsigned int thickness = 1
    );
    /*!
        requires
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - pixel_traits<pixel_type> is defined
        ensures
            - Draws the given rectangle onto the image img.  It does this by calling
              draw_line() four times to draw the four sides of the rectangle.
            - The rectangle is drawn with the color given by val.
            - The drawn rectangle will have edges that are thickness pixels wide.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type,
        typename pixel_type
        >
    void draw_solid_circle (
        image_type& img,
        const dpoint& center_point,
        double radius,
        const pixel_type& pixel
    );
    /*!
        requires
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - pixel_traits<pixel_type> is defined
        ensures
            - Draws a fully filled in circle onto image that is centered at center_point
              and has the given radius.  The circle will be filled by assigning the given
              pixel value to each element of the circle.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type,
        typename pixel_type
        >
    void fill_rect (
        image_type& img,
        const rectangle& rect,
        const pixel_type& pixel
    );
    /*!
        requires
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - pixel_traits<pixel_type> is defined
        ensures
            - fills the area defined by rect in the given image with the given pixel value.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_array_type
        >
    matrix<typename image_traits<typename image_array_type::value_type>::pixel_type> tile_images (
        const image_array_type& images
    );
    /*!
        requires
            - image_array_type is a dlib::array of image objects where each image object
              implements the interface defined in dlib/image_processing/generic_image.h
        ensures
            - This function takes the given images and tiles them into a single large
              square image and returns this new big tiled image.  Therefore, it is a useful
              method to visualize many small images at once.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_DRAW_IMAGe_ABSTRACT


dlib C++ Library - colormaps_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_RANDOMLY_COlOR_IMAGE_ABSTRACT_Hh_
#ifdef DLIB_RANDOMLY_COlOR_IMAGE_ABSTRACT_Hh_

#include "../hash.h"
#include "../pixel.h"
#include "../matrix.h"
#include "../image_processing/generic_image.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    const matrix_exp randomly_color_image (
        const image_type& img
    );
    /*!
        requires
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h, or something convertible to a matrix
              via mat().
        ensures
            - randomly generates a mapping from gray level pixel values
              to the RGB pixel space and then uses this mapping to create
              a colored version of img.  Returns a matrix which represents
              this colored version of img.
            - black pixels in img will remain black in the output image.
            - The returned matrix will have the same dimensions as img.
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    rgb_pixel colormap_heat (
        double value,
        double min_val,
        double max_val
    );
    /*!
        ensures
            - Maps value to a color.  In particular, we use a heatmap color scheme where
              values <= min_val are black and larger values become more red, then yellow,
              and then white as they approach max_val.
    !*/

    template <
        typename image_type
        >
    const matrix_exp heatmap (
        const image_type& img,
        double max_val,
        double min_val = 0
    );
    /*!
        requires
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h, or something convertible to a matrix
              via mat().
        ensures
            - Interprets img as a grayscale image and returns a new matrix which represents
              a colored version of img.  In particular, the colormap is defined by
              colormap_heat().
            - The returned matrix will have the same dimensions as img.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    const matrix_exp heatmap (
        const image_type& img
    );
    /*!
        requires
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h, or something convertible to a matrix
              via mat().
        ensures
            - returns heatmap(img, max(mat(img)), min(mat(img)))
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    rgb_pixel colormap_jet (
        double value,
        double min_val,
        double max_val
    );
    /*!
        ensures
            - Maps value to a color.  In particular, we use a jet color scheme where
              values <= min_val are dark blue and larger values become light blue, then
              yellow, and then finally red as they approach max_val.
    !*/

    template <
        typename image_type
        >
    const matrix_exp jet (
        const image_type& img,
        double max_val,
        double min_val = 0
    );
    /*!
        requires
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h, or something convertible to a matrix
              via mat().
        ensures
            - Interprets img as a grayscale image and returns a new matrix which represents
              a colored version of img.  In particular, the colormap is defined by
              colormap_jet().
            - The returned matrix will have the same dimensions as img.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    const matrix_exp jet (
        const image_type& img
    );
    /*!
        requires
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h, or something convertible to a matrix
              via mat().
        ensures
            - returns jet(img, max(mat(img)), min(mat(img)))
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

}

#endif // DLIB_RANDOMLY_COlOR_IMAGE_ABSTRACT_Hh_


dlib C++ Library - render_face_detections_abstract.h

// Copyright (C) 2014  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_RENDER_FACE_DeTECTIONS_ABSTRACT_H_
#ifdef DLIB_RENDER_FACE_DeTECTIONS_ABSTRACT_H_

#include "full_object_detection_abstract.h"
#include "../gui_widgets.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    inline std::vector<image_window::overlay_line> render_face_detections (
        const std::vector<full_object_detection>& dets,
        const rgb_pixel color = rgb_pixel(0,255,0)
    );
    /*!
        requires
            - for all valid i:
                - dets[i].num_parts() == 68
        ensures
            - Interprets the given objects as face detections with parts annotated using
              the iBUG face landmark scheme.  We then return a set of overlay lines that
              will draw the objects onto the screen in a way that properly draws the
              outline of the face features defined by the part locations.
            - returns a vector with dets.size() elements, each containing the lines
              necessary to render a face detection from dets.
    !*/

// ----------------------------------------------------------------------------------------

    inline std::vector<image_window::overlay_line> render_face_detections (
        const full_object_detection& det,
        const rgb_pixel color = rgb_pixel(0,255,0)
    );
    /*!
        requires
            - det.num_parts() == 68
        ensures
            - This function is identical to the above render_face_detections() routine
              except that it takes just a single full_object_detection instead of a
              std::vector of them.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_RENDER_FACE_DeTECTIONS_ABSTRACT_H_


dlib C++ Library - assign_image_abstract.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_ASSIGN_IMAGe_ABSTRACT
#ifdef DLIB_ASSIGN_IMAGe_ABSTRACT

#include "../pixel.h"
#include "../image_processing/generic_image.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename dest_image_type,
        typename src_image_type
        >
    void assign_image (
        dest_image_type& dest_img,
        const src_image_type& src_img
    );
    /*!
        requires
            - src_image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h or any object convertible to a matrix
              via mat().
            - dest_image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h or an image_view.
        ensures
            - #dest_img.nc() == src_img.nc()
            - #dest_img.nr() == src_img.nr()
            - for all valid r and c:
                - performs assign_pixel(#dest_img[r][c],src_img[r][c])
                  (i.e. copies the src image to dest image)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename dest_image_type,
        typename src_image_type
        >
    void assign_image_scaled (
        dest_image_type& dest_img,
        const src_image_type& src_img,
        const double thresh = 4
    );
    /*!
        requires
            - src_image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h or any object convertible to a matrix
              via mat().
            - dest_image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h or an image_view.
            - thresh > 0
        ensures
            - #dest_img.nc() == src_img.nc()
            - #dest_img.nr() == src_img.nr()
            - if (dest_img's pixels have a wide enough dynamic range to contain all the
              pixels in src_img.  (Note that dynamic range is determined by the min() and
              max() pixel_traits properties)) then
                - performs: assign_image(dest_img, src_img)
                  (i.e. in this case, no scaling is performed.  Just a normal color space
                  conversion and copy )
            - else
                - #dest_img will be converted to a grayscale image
                - scales the contents of src_img into the dynamic range of dest_img and then
                  assigns the result into dest_img.  The thresh parameter is used to filter
                  source pixel values which are outliers.  These outliers will saturate
                  at the edge of the destination image's dynamic range.
                - Specifically, for all valid r and c:
                    - scales get_pixel_intensity(src_img[r][c]) into the dynamic range
                      of the dest_img.  This is done by computing the mean and standard
                      deviation of src_img. Call the mean M and the standard deviation
                      D.  Then the scaling from src_img to dest_img is performed using
                      the following mapping:
                        let SRC_UPPER  = min(M + thresh*D, max(mat(src_img)))
                        let SRC_LOWER  = max(M - thresh*D, min(mat(src_img)))
                        let DEST_UPPER = pixel_traits<image_traits<dest_image_type>::pixel_type>::max()
                        let DEST_LOWER = pixel_traits<image_traits<dest_image_type>::pixel_type>::min()

                        MAPPING: [SRC_LOWER, SRC_UPPER] -> [DEST_LOWER, DEST_UPPER]

                      Where this mapping is a linear mapping of values from the left range
                      into the right range of values.  Source pixel values outside the left
                      range are modified to be at the appropriate end of the range.

                      The scaled pixel is then stored in dest_img[r][c].
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename dest_image_type,
        typename src_pixel_type
        >
    void assign_all_pixels (
        dest_image_type& dest_img,
        const src_pixel_type& src_pixel
    );
    /*!
        requires
            - dest_image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h or an image_view.
            - pixel_traits<src_pixel_type> is defined
        ensures
            - #dest_img.nc() == dest_img.nc()
            - #dest_img.nr() == dest_img.nr()
              (i.e. the size of dest_img isn't changed by this function)
            - for all valid r and c:
                - performs assign_pixel(#dest_img[r][c],src_pixel)
                  (i.e. assigns the src pixel to every pixel in the dest image)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    void assign_border_pixels (
        image_type& img,
        long x_border_size,
        long y_border_size,
        const typename image_traits<image_type>::pixel_type& p
    );
    /*!
        requires
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h or an image_view
            - x_border_size >= 0
            - y_border_size >= 0
        ensures
            - #img.nc() == img.nc()
            - #img.nr() == img.nr()
              (i.e. the size of img isn't changed by this function)
            - for all valid r such that r+y_border_size or r-y_border_size gives an invalid row
                - for all valid c such that c+x_border_size or c-x_border_size gives an invalid column
                    - performs assign_pixel(#img[r][c],p)
                      (i.e. assigns the given pixel to every pixel in the border of img)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    void zero_border_pixels (
        image_type& img,
        long x_border_size,
        long y_border_size
    );
    /*!
        requires
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h or an image_view
            - x_border_size >= 0
            - y_border_size >= 0
        ensures
            - #img.nc() == img.nc()
            - #img.nr() == img.nr()
              (i.e. the size of img isn't changed by this function)
            - for all valid r such that r+y_border_size or r-y_border_size gives an invalid row
                - for all valid c such that c+x_border_size or c-x_border_size gives an invalid column
                    - performs assign_pixel(#img[r][c], 0 )
                      (i.e. assigns 0 to every pixel in the border of img)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    void zero_border_pixels (
        image_type& img,
        rectangle inside
    );
    /*!
        requires
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h or an image_view
        ensures
            - #img.nc() == img.nc()
            - #img.nr() == img.nr()
              (i.e. the size of img isn't changed by this function)
            - All the pixels in img that are not contained inside the inside rectangle
              given to this function are set to 0.  That is, anything not "inside" is on
              the border and set to 0.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_ASSIGN_IMAGe_ABSTRACT


dlib C++ Library - cv_image_abstract.h

// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_OPENCV_IMAGE_AbSTRACT_H_
#ifdef DLIB_OPENCV_IMAGE_AbSTRACT_H_

#include <opencv2/core/core.hpp>
#include <opencv2/core/types_c.h>
#include "../algs.h"
#include "../pixel.h"

namespace dlib
{

    template <
        typename pixel_type
        >
    class cv_image
    {
        /*!
            REQUIREMENTS ON pixel_type
                pixel_type just needs to be something that matches the pixel memory
                layout of whatever OpenCV image you are going to use with this object.
                For example, you might use unsigned char or bgr_pixel depending
                on what you needed.

            WHAT THIS OBJECT REPRESENTS
                This object is meant to be used as a simple wrapper around the OpenCV
                IplImage struct or Mat object.  Using this class template you can turn
                an OpenCV image into something that looks like a normal dlib style
                image object.

                So you should be able to use cv_image objects with many of the image
                processing functions in dlib as well as the GUI tools for displaying
                images on the screen.

                Note that this object does NOT take ownership of the image data you
                give to it.  This means it is up to you to make sure the OpenCV image
                is properly freed at some point.  This also means that an instance of
                this object can only be used as long as the OpenCV image it references
                remains valid, since a cv_image just points to the OpenCV image's
                memory directly.
        !*/

    public:
        typedef pixel_type type;
        typedef default_memory_manager mem_manager_type;

        cv_image (
            const IplImage* img
        );
        /*!
            requires
                - img->dataOrder == 0
                  (i.e. Only interleaved color channels are supported with cv_image)
                - (img->depth&0xFF)/8*img->nChannels == sizeof(pixel_type)
                  (i.e. The size of the pixel_type needs to match the size of the pixels
                  inside the OpenCV image)
            ensures
                - #nr() == img->height
                  #nc() == img->width
                - using the operator[] on this object you will be able to access the pixels
                  inside this OpenCV image.
        !*/

        cv_image (
            const IplImage img
        );
        /*!
            requires
                - img.dataOrder == 0
                  (i.e. Only interleaved color channels are supported with cv_image)
                - (img.depth&0xFF)/8*img.nChannels == sizeof(pixel_type)
                  (i.e. The size of the pixel_type needs to match the size of the pixels
                  inside the OpenCV image)
            ensures
                - #nr() == img.height
                  #nc() == img.width
                - using the operator[] on this object you will be able to access the pixels
                  inside this OpenCV image.
        !*/

        cv_image (
            const cv::Mat img
        );
        /*!
            requires
                - img.depth() == cv::DataType<pixel_traits<pixel_type>::basic_pixel_type>::depth
                  (i.e. The pixel_type template argument needs to match the type of pixel
                  used inside the OpenCV image)
                - img.channels() == pixel_traits<pixel_type>::num
                  (i.e. the number of channels in the pixel_type needs to match the number of
                  channels in the OpenCV image)
            ensures
                - #nr() == img.rows
                - #nc() == img.cols
                - using the operator[] on this object you will be able to access the pixels
                  inside this OpenCV image.
        !*/

        cv_image(
        );
        /*!
            ensures
                - #nr() == 0
                - #nc() == 0
        !*/

        ~cv_image (
        );
        /*!
            ensures
                - This function does nothing.  e.g. It doesn't delete the OpenCV
                  image used by this cv_image object
        !*/

        long nr(
        ) const;
        /*!
            ensures
                - returns the number of rows in this image
        !*/

        long nc(
        ) const;
        /*!
            ensures
                - returns the number of columns in this image
        !*/

        unsigned long size (
        ) const;
        /*!
            ensures
                - returns nr()*nc()
                  (i.e. returns the number of pixels in this image)
        !*/

        inline pixel_type* operator[] (
            const long row
        );
        /*!
            requires
                - 0 <= row < nr()
            ensures
                - returns a pointer to the first pixel in the given row
                  of this image
        !*/

        inline const pixel_type* operator[] (
            const long row
        ) const;
        /*!
            requires
                - 0 <= row < nr()
            ensures
                - returns a pointer to the first pixel in the given row
                  of this image
        !*/

        cv_image& operator= (
            const cv_image& item
        );
        /*!
            ensures
                - #*this is an identical copy of item
                - returns #*this
        !*/

        cv_image& operator=(
            const IplImage* img
        );
        /*!
            requires
                - img->dataOrder == 0
                  (i.e. Only interleaved color channels are supported with cv_image)
                - (img->depth&0xFF)/8*img->nChannels == sizeof(pixel_type)
                  (i.e. The size of the pixel_type needs to match the size of the pixels
                  inside the OpenCV image)
            ensures
                - #nr() == img->height
                  #nc() == img->width
                - using the operator[] on this object you will be able to access the pixels
                  inside this OpenCV image.
                - returns #*this
        !*/

        cv_image& operator=(
            const IplImage img
        );
        /*!
            requires
                - img->dataOrder == 0
                  (i.e. Only interleaved color channels are supported with cv_image)
                - (img->depth&0xFF)/8*img->nChannels == sizeof(pixel_type)
                  (i.e. The size of the pixel_type needs to match the size of the pixels
                  inside the OpenCV image)
            ensures
                - #nr() == img->height
                  #nc() == img->width
                - using the operator[] on this object you will be able to access the pixels
                  inside this OpenCV image.
                - returns #*this
        !*/

        cv_image& operator=(
            const cv::Mat img
        );
        /*!
            requires
                - img.depth() == cv::DataType<pixel_traits<pixel_type>::basic_pixel_type>::depth
                  (i.e. The pixel_type template argument needs to match the type of pixel
                  used inside the OpenCV image)
                - img.channels() == pixel_traits<pixel_type>::num
                  (i.e. the number of channels in the pixel_type needs to match the number of
                  channels in the OpenCV image)
            ensures
                - #nr() == img.rows
                - #nc() == img.cols
                - using the operator[] on this object you will be able to access the pixels
                  inside this OpenCV image.
                - returns #*this
        !*/

        long width_step (
        ) const;
        /*!
            ensures
                - returns the size of one row of the image, in bytes.
                  More precisely, return a number N such that:
                  (char*)&item[0][0] + N == (char*)&item[1][0].
        !*/
    };

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    const matrix_exp mat (
        const cv_image<T>& img
    );
    /*!
        ensures
            - returns a matrix R such that:
                - R.nr() == img.nr()
                - R.nc() == img.nc()
                - for all valid r and c:
                  R(r, c) == img[r][c]
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_OPENCV_IMAGE_AbSTRACT_H_


dlib C++ Library - equalize_histogram_abstract.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_EQUALIZE_HISTOGRAm_ABSTRACT_
#ifdef DLIB_EQUALIZE_HISTOGRAm_ABSTRACT_

#include "../pixel.h"
#include "../matrix.h"
#include "../image_processing/generic_image.h"

namespace dlib
{

// ---------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type
        >
    void equalize_histogram (
        const in_image_type& in_img,
        out_image_type& out_img
    );
    /*!
        requires
            - in_image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - out_image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - Let pixel_type be the type of pixel in either input or output images, then we
              must have:
                - pixel_traits<pixel_type>::has_alpha == false
                - pixel_traits<pixel_type>::is_unsigned == true
            - For the input image pixel type, we have the additional requirement that:
                - pixel_traits<pixel_type>::max() <= 65535
        ensures
            - #out_img == the histogram equalized version of in_img
            - #out_img.nc() == in_img.nc()
            - #out_img.nr() == in_img.nr()
    !*/

    template <
        typename image_type
        >
    void equalize_histogram (
        image_type& img
    );
    /*!
        requires
            - it is valid to call equalize_histogram(img,img)
        ensures
            - calls equalize_histogram(img,img);
    !*/

// ---------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        long R,
        long C,
        typename MM
        >
    void get_histogram (
        const in_image_type& in_img,
        matrix<unsigned long,R,C,MM>& hist
    );
    /*!
        requires
            - in_image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h
            - Let pixel_type denote the type of pixel in in_img, then we must have:
                - pixel_traits<pixel_type>::is_unsigned == true
                - pixel_traits<pixel_type>::max() <= 65535
            - hist must be capable of representing a column vector of length
              pixel_traits<typename in_image_type>::max(). I.e. if R and C are nonzero
              then they must be values that don't conflict with the previous sentence.
        ensures
            - #hist.size() == pixel_traits<typename in_image_type>::max()
            - #hist.nc() == 1 || #hist.nr() == 1 (i.e. hist is either a row or column vector)
            - #hist == the histogram for in_img.  I.e. it is the case that for all
              valid i:
                - hist(i) == the number of times a pixel with intensity i appears
                  in in_img
    !*/

// ---------------------------------------------------------------------------------------

}

#endif // DLIB_EQUALIZE_HISTOGRAm_ABSTRACT_


dlib C++ Library - to_open_cv_abstract.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_TO_OPEN_Cv_ABSTRACTh_
#ifdef DLIB_TO_OPEN_Cv_ABSTRACTh_

#include <opencv2/core/core.hpp>
#include "../pixel.h"

namespace dlib
{
    template <
        typename image_type
        >
    cv::Mat toMat (
        image_type& img
    );
    /*!
        requires
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h or a dlib::matrix object which uses a
              row_major_layout.
            - pixel_traits is defined for the contents of img.
        ensures
            - returns an OpenCV Mat object which represents the same image as img.  This
              is done by setting up the Mat object to point to the same memory as img.
              Therefore, the returned Mat object is valid only as long as pointers
              to the pixels in img remain valid.
    !*/
}

#endif // DLIB_TO_OPEN_Cv_ABSTRACTh_


dlib C++ Library - Linear Algebra

The Library
  • Algorithms
  • API Wrappers
  • Bayesian Nets
  • Compression
  • Containers
  • Graph Tools
  • Image Processing
  • Linear Algebra
  • Machine Learning
  • Metaprogramming
  • Miscellaneous
  • Networking
  • Optimization
  • Parsing

Help/Info
  • Dlib Blog
  • Examples: C++
    • 3D Point Cloud
    • Assignment Learning
    • Base64 Encoder
    • Bayesian Network From Disk
    • Bayesian Network GUI
    • Bayesian Network
    • Bridge
    • BSP
    • C-Support Vector Machine
    • Cmd Line Parser
    • Compress Stream
    • Config File Reader
    • Custom Trainers
    • Directory Navigation
    • Empirical Kernel Map
    • Face Detection
    • Face Landmark Detection
    • FHOG Feature Extraction
    • FHOG Object Detection
    • Graph Labeling
    • GUI
    • Hough Transform
    • HTTP Server
    • Image
    • IO Socket Streams
    • IO Streams Server
    • Kernel Centroid
    • Kernel K-Means Clustering
    • Kernel Ridge Regression
    • Kernel RLS Filtering
    • Kernel RLS Regression
    • KRR Classification
    • Learning to Track
    • Linear Assignment Problems
    • Linear Manifold Regularizer
    • Linear Model Predictive Control
    • Logger Advanced
    • Logger Custom Output
    • Logger
    • Matrix Expressions
    • Matrix
    • Member Function Pointer
    • Model Selection
    • Multiclass Classification
    • Multithreaded Object
    • Neural Network
    • Non-Linear Least Squares
    • Nu-Support Vector Machine
    • Numerical Integration
    • Object Detector Advanced
    • Object Detector
    • One Class Classifiers
    • Online SVM
    • Optimization
    • Parallel For Loops
    • Pipe 2
    • Pipe
    • Quantum Computing
    • Queue
    • Rank Features
    • Relevance Vector Classification
    • Relevance Vector Regression
    • Running Stats
    • Sequence Labeling
    • Sequence Segmentation
    • Sockets
    • Sockstreambuf
    • Sparse Vectors
    • SQLite
    • Std C++ Allocator
    • Structural Support Vector Machines
    • Support Vector Regression
    • SURF
    • SVM-Rank
    • Thread Function
    • Thread Pool
    • Threaded Object
    • Threads
    • Timer
    • Train Object Detector
    • Train Shape Predictor
    • Using Custom Kernels
    • Video Object Tracking
    • Webcam Face Pose Estimation
    • XML Parser
  • Examples: Python
    • Face Detector
    • Face Landmark Detection
    • find candidate object locations
    • Linear Assignment Problems
    • Sequence Segmenter
    • Structural Support Vector Machines
    • SVM-Rank
    • Train Object Detector
    • Train Shape Predictor
    • Video Object Tracking
  • FAQ
  • Forums
  • Home
  • How to compile
  • How to contribute
  • Index
  • Introduction
  • License
  • Python API
  • Suggested Books
  • Who uses dlib?

Current Release
  • Change Log
  • Release Notes
  • Version: 18.18

Last Modified:
Oct 22, 2015
Linear Algebra

This page documents the core linear algebra tools included in dlib. In particular, the three most important objects in this part of the library are the matrix, vector, and rectangle. All the other tools on this page are functions for manipulating these three objects. A good example and introduction can be found in the matrix example program.

Most of the linear algebra tools deal with dense matrices. However, there is also a limited amount of support for working with sparse matrices and vectors. In particular, the dlib tools represent sparse vectors using the containers in the C++ STL. For details, see the notes at the top of dlib/svm/sparse_vector_abstract.h.

Finally, note that all the dense matrix tools can be obtained by #including <dlib/matrix.h> while the sparse vector tools can be obtained by #including <dlib/sparse_vector.h>. The geometry tools can be used by #including <dlib/geometry.h>.

Dense Matrix Tools
  • Basic Math Operators
    • abs
    • acos
    • asin
    • atan
    • ceil
    • complex_matrix
    • conj
    • cos
    • cosh
    • cubed
    • exp
    • floor
    • imag
    • log10
    • log
    • normalize
    • norm
    • pow
    • real
    • reciprocal
    • reciprocal_max
    • round
    • round_zeros
    • sigmoid
    • sinh
    • sin
    • sqrt
    • squared
    • tanh
    • tan
  • Conversions
    • mat
    • matrix_cast
    • pixel_to_vector
    • vector_to_pixel
  • Linear Algebra
    • chol
    • cholesky_decomposition
    • det
    • diag
    • diagm
    • dot
    • eigenvalue_decomposition
    • inv
    • inv_lower_triangular
    • inv_upper_triangular
    • length
    • length_squared
    • lowerm
    • lu_decomposition
    • orthogonalize
    • pinv
    • qr_decomposition
    • real_eigenvalues
    • svd2
    • svd3
    • svd
    • svd_fast
    • trace
    • trans
    • upperm
  • matrix
  • Other Utilities
    • cartesian_product
    • clamp
    • const_temp_matrix
    • conv
    • conv_same
    • conv_valid
    • csv
    • equal
    • fft
    • flip
    • fliplr
    • flipud
    • hash
    • identity_matrix
    • ifft
    • is_col_vector
    • is_finite
    • is_row_vector
    • is_vector
    • join_cols
    • join_rows
    • linpiece
    • linspace
    • logspace
    • lowerbound
    • make_symmetric
    • ones_matrix
    • pointwise_multiply
    • removerc
    • remove_col
    • remove_row
    • reshape
    • reshape_to_column_vector
    • rotate
    • rsort_columns
    • scale_columns
    • scale_rows
    • set_all_elements
    • sort_columns
    • symmetric_matrix_cache
    • tensor_product
    • tmp
    • uniform_matrix
    • upperbound
    • xcorr
    • xcorr_same
    • xcorr_valid
    • zeros_matrix
  • Statistics
    • covariance
    • find_min_and_max
    • gaussian_randm
    • index_of_max
    • index_of_min
    • max
    • max_point
    • max_point_interpolated
    • mean
    • min
    • min_point
    • prod
    • randm
    • stddev
    • sum
    • sum_cols
    • sum_rows
    • variance
  • Sub Matrix Expressions
    • colm
    • range
    • rowm
    • set_colm
    • set_ptrm
    • set_rowm
    • set_subm
    • subm

2D/3D Geometry
  • border_enumerator
  • camera_transform
  • center
  • centered_rect
  • clip_line_to_rectangle
  • dcenter
  • distance_to_line
  • distance_to_rect_edge
  • drectangle
  • find_affine_transform
  • find_projective_transform
  • find_similarity_transform
  • get_rect
  • grow_rect
  • move_rect
  • nearest_point
  • point
  • point_rotator
  • point_transform
  • point_transform_affine
  • point_transform_affine3d
  • point_transform_projective
  • rectangle
  • resize_rect
  • resize_rect_height
  • resize_rect_width
  • rotate_around_x
  • rotate_around_y
  • rotate_around_z
  • rotate_point
  • rotation_matrix
  • set_aspect_ratio
  • shrink_rect
  • translate_point
  • translate_rect
  • vector

Sparse Vector Tools
  • add
  • add_to
  • assign
  • distance
  • distance_squared
  • dot
  • length
  • length_squared
  • make_sparse_vector
  • make_sparse_vector_inplace
  • max
  • max_index_plus_one
  • min
  • scale_by
  • sparse_matrix_vector_multiply
  • sparse_to_dense
  • subtract
  • subtract_from

[top]

border_enumerator

This object is an enumerator over the border points of a rectangle.
More Details...
#include <dlib/geometry.h>
[top]

camera_transform

This object maps 3D points into the image plane of a camera. Therefore, you can use it to compute 2D representations of 3D data from the point of view of some camera in 3D space.
More Details...
#include <dlib/geometry.h>
[top]

center

Returns the center point of a rectangle.
More Details...
#include <dlib/geometry.h>
[top]

centered_rect

There are various overloads of this function but the basic idea is that it returns a rectangle with a given width and height and centered about a given point.
More Details...
#include <dlib/geometry.h>
[top]

clip_line_to_rectangle

This function takes a rectangle and a line segment and returns the part of the line segment that is entirely contained within the rectangle.
More Details...
#include <dlib/geometry.h>
[top]

dcenter

Returns the center point of a rectangle. This is a version of center() which returns a double version of the point rather than one which uses integers to represent the result. Therefore, it is slightly more accurate.
More Details...
#include <dlib/geometry.h>
[top]

distance_to_line

This function takes a line and a point and returns the distance from the line to the point.
More Details...
#include <dlib/geometry.h>
[top]

distance_to_rect_edge

This function takes a rectangle and a point and returns the Manhattan distance between the rectangle's edge and the point.
More Details...
#include <dlib/geometry.h>
[top]

drectangle

This object represents a rectangular region inside a Cartesian coordinate system. It is very similar to the rectangle except that it uses double variables instead of longs to represent the location of the rectangle. Therefore, it can position rectangles with sub-pixel accuracy.
More Details...
#include <dlib/geometry.h>
[top]

find_affine_transform

This is a routine that takes in two sets of points and finds the best affine transformation that maps between them.
More Details...
#include <dlib/geometry.h>
[top]

find_projective_transform

This is a routine that takes in two sets of points and finds the best projective transformation that maps between them.
More Details...
#include <dlib/geometry.h>
[top]

find_similarity_transform

This is a routine that takes in two sets of points and finds the best affine transformation that maps between them. However, it considers only rotations, translations, and uniform scale changes in finding the mapping. Therefore, it finds a similarity transformation rather than a general affine transform.
More Details...
#include <dlib/geometry.h>
[top]

get_rect

This is a simple template function that returns a rectangle representing the size of a 2D container (e.g. matrix or array2d).
More Details...
#include <dlib/geometry.h>
[top]

grow_rect

This function takes a rectangle object, grows its borders by a given amount, and returns the result.
More Details...
#include <dlib/geometry.h>
[top]

mat

This is a set of simple functions that take objects like std::vector or array2d and convert them into matrix objects. Note that the conversion is done using template expressions so there is no runtime cost associated with calling mat().
More Details...
#include <dlib/matrix.h>
[top]

matrix

This is a 2D matrix object that enables you to write code that deals with matrices using a simple syntax similar to what can be written in MATLAB. It is implemented using the expression templates technique which allows it to eliminate the temporary matrix objects that would normally be returned from expressions such as M = A+B+C+D; Normally each invocation of the + operator would construct and return a temporary matrix object but using this technique we can avoid creating all these temporary objects and receive a large speed boost.

This object is also capable of using BLAS and LAPACK libraries such as ATLAS or the Intel MKL when available. To enable BLAS support all you have to do is #define DLIB_USE_BLAS and then make sure you link your application with your BLAS library. Similarly, to enable LAPACK support just #define DLIB_USE_LAPACK and link to your LAPACK library. Finally, the use of BLAS and LAPACK is transparent to the user, that is, the dlib matrix object uses BLAS and LAPACK internally to optimize various operations while still allowing the user to use a simple MATLAB like syntax.

Note that the cmake files that come with dlib will automatically link with ATLAS or the Intel MKL if they are installed. So using cmake makes this easy, but by no means are you required to use cmake or the dlib cmake files.

It is also worth noting that all the preconditions of every function related to the matrix object are checked by DLIB_ASSERT statements and thus can be enabled by #defining ENABLE_ASSERTS or DEBUG. Doing this will cause your program to run slower but should catch any usage errors.

C++ Example Programs: matrix_ex.cpp, matrix_expressions_ex.cpp
More Details...
#include <dlib/matrix.h>

Extensions to matrix

matrix_la

This extension contains linear algebra functions to calculate QR, LU, Cholesky, eigenvalue, and singular value decompositions. It also contains a few other miscellaneous functions that solve systems of equations or calculate values derived from the above decompositions.

More Details...
matrix_math_functions

This extension contains mathematical functions that operate on each element of a matrix independently.

More Details...
matrix_sub_expressions

This extension contains a number of functions for dealing with sub-matrices.

More Details...
matrix_utilities

This extension contains miscellaneous utility functions for manipulating matrix objects.

More Details...
[top]

move_rect

This function takes a rectangle and moves it so that it's upper left corner occupies the given location.
More Details...
#include <dlib/geometry.h>
[top]

nearest_point

This function takes a rectangle and a point and returns the point in the given rectangle that is nearest to the given point.
More Details...
#include <dlib/geometry.h>
[top]

point

This object represents a point inside a Cartesian coordinate system. Note that a point is simply a typedef for a vector that is 2D and uses longs to represent coordinate values.
More Details...
#include <dlib/geometry.h>
[top]

point_rotator

This is an object that rotates a 2D vector or point object about the origin.
More Details...
#include <dlib/geometry.h>
[top]

point_transform

This is an object that rotates a 2D vector or point object about the origin and then adds a displacement vector.
More Details...
#include <dlib/geometry.h>
[top]

point_transform_affine

This is an object that applies a 2D affine transformation to a vector or point. Note that you can use find_affine_transform to easily create affine transforms from sets of point correspondences.
More Details...
#include <dlib/geometry.h>
[top]

point_transform_affine3d

This is an object that applies a 3D affine transformation to a vector.
More Details...
#include <dlib/geometry.h>
[top]

point_transform_projective

This is an object that applies a projective transformation to a vector or point. Note that you can use find_projective_transform to easily create projective transforms from sets of point correspondences.
More Details...
#include <dlib/geometry.h>
[top]

rectangle

This object represents a rectangular region inside a Cartesian coordinate system. It allows you to easily represent and manipulate rectangles.
More Details...
#include <dlib/geometry.h>
[top]

resize_rect

This function takes a rectangle and returns a new rectangle with the given size but with the same upper left corner as the original rectangle.
More Details...
#include <dlib/geometry.h>
[top]

resize_rect_height

This function takes a rectangle and returns a new rectangle with the given height but otherwise with the same edge points as the original rectangle.
More Details...
#include <dlib/geometry.h>
[top]

resize_rect_width

This function takes a rectangle and returns a new rectangle with the given width but otherwise with the same edge points as the original rectangle.
More Details...
#include <dlib/geometry.h>
[top]

rotate_around_x

This is a method for creating a point_transform_affine3d that rotates points around the x-axis.
More Details...
#include <dlib/geometry.h>
[top]

rotate_around_y

This is a method for creating a point_transform_affine3d that rotates points around the y-axis.
More Details...
#include <dlib/geometry.h>
[top]

rotate_around_z

This is a method for creating a point_transform_affine3d that rotates points around the z-axis.
More Details...
#include <dlib/geometry.h>
[top]

rotate_point

This is a function that rotates a 2D vector or point object about a given point.
More Details...
#include <dlib/geometry.h>
[top]

rotation_matrix

This is a method for creating 2D rotation matrices.
More Details...
#include <dlib/geometry.h>
[top]

set_aspect_ratio

This function reshapes a rectangle so that it has a user specified aspect ratio.
More Details...
#include <dlib/geometry.h>
[top]

shrink_rect

This function takes a rectangle object, shrinks its borders by a given amount, and returns the result.
More Details...
#include <dlib/geometry.h>
[top]

sparse_to_dense

This is a set of simple functions that take sparse vectors and converts them into equivalent dense vectors.
More Details...
#include <dlib/sparse_vector.h>
[top]

translate_point

This is a method for creating a point_transform_affine3d that just translates points.
More Details...
#include <dlib/geometry.h>
[top]

translate_rect

This function takes a rectangle and moves it by a given number of units along the x and y axis relative to where it was before the move.
More Details...
#include <dlib/geometry.h>
[top]

vector

This object represents a two or three dimensional vector.

If you want to work with general N-dimensional column vectors then you should the matrix object. In particular, you should usually use a matrix with this type: dlib::matrix<double,0,1>.

More Details...
#include <dlib/geometry.h>


dlib C++ Library - matrix_math_functions_abstract.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_MATRIx_MATH_FUNCTIONS_ABSTRACT_
#ifdef DLIB_MATRIx_MATH_FUNCTIONS_ABSTRACT_

#include "matrix_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                          Exponential Functions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    const matrix_exp exp (
        const matrix_exp& m
    );
    /*!
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m
                - R has the same dimensions as m
                - for all valid r and c:
                  R(r,c) == std::exp(m(r,c))
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp log10 (
        const matrix_exp& m
    );
    /*!
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m
                - R has the same dimensions as m
                - for all valid r and c:
                  R(r,c) == std::log10(m(r,c))
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp log (
        const matrix_exp& m
    );
    /*!
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m
                - R has the same dimensions as m
                - for all valid r and c:
                  R(r,c) == std::log(m(r,c))
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp sqrt (
        const matrix_exp& m
    );
    /*!
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m
                - R has the same dimensions as m
                - for all valid r and c:
                  R(r,c) == sqrt(m(r,c))
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    const matrix_exp pow (
        const matrix_exp& m,
        const T& e
    );
    /*!
        requires
            - matrix_exp::type == float, double, or long double
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m
                - R has the same dimensions as m
                - for all valid r and c:
                  R(r,c) == pow(m(r,c),e)
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    const matrix_exp pow (
        const T& b,
        const matrix_exp& m
    );
    /*!
        requires
            - matrix_exp::type == float, double, or long double
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m
                - R has the same dimensions as m
                - for all valid r and c:
                  R(r,c) == pow(b, m(r,c))
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp squared (
        const matrix_exp& m
    );
    /*!
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m
                - R has the same dimensions as m
                - for all valid r and c:
                  R(r,c) == m(r,c)*m(r,c)
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp cubed (
        const matrix_exp& m
    );
    /*!
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m
                - R has the same dimensions as m
                - for all valid r and c:
                  R(r,c) == m(r,c)*m(r,c)*m(r,c)
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                               Miscellaneous
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    const matrix_exp sign (
        const matrix_exp& m
    );
    /*!
        ensures
            - returns a matrix that tells the sign of each element in m. In particular:
              returns a matrix R such that:
                - R::type == the same type that was in m
                - R has the same dimensions as m
                - for all valid r and c:
                    - if (m(r,c) >= 0) then
                        - R(r,c) == +1
                    - else
                        - R(r,c) == -1
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp sigmoid (
        const matrix_exp& m
    );
    /*!
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m
                - R has the same dimensions as m
                - for all valid r and c:
                  R(r,c) == 1/(1 + exp(-m(r,c)))
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp abs (
        const matrix_exp& m
    );
    /*!
        ensures
            - returns a matrix R such that:
                - if (m contains std::complex<T> objects) then
                    - R::type == T
                - else
                    - R::type == the same type that was in m
                - R has the same dimensions as m
                - for all valid r and c:
                  R(r,c) == std::abs(m(r,c))
                  (note that if m is complex then std::abs(val) performs sqrt(std::norm(val))
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp reciprocal (
        const matrix_exp& m
    );
    /*!
        requires
            - matrix_exp::type == float, double, long double, std::complex<float>,
              std::complex<double>, or std::complex<long double>
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m
                - R has the same dimensions as m
                - for all valid r and c:
                    - if (m(r,c) != 0) then
                        - R(r,c) == 1.0/m(r,c)
                    - else
                        - R(r,c) == 0
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp reciprocal_max (
        const matrix_exp& m
    );
    /*!
        requires
            - matrix_exp::type == float, double, long double
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m
                - R has the same dimensions as m
                - for all valid r and c:
                    - if (m(r,c) != 0) then
                        - R(r,c) == 1.0/m(r,c)
                    - else
                        - R(r,c) == std::numeric_limits<R::type>::max()
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp normalize (
        const matrix_exp& m
    );
    /*!
        requires
            - matrix_exp::type == float, double, or long double
        ensures
            - if (sqrt(sum(squared(m))) != 0) then
                - returns m/sqrt(sum(squared(m)))
            - else
                - returns m
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                          Rounding numbers one way or another
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    const matrix_exp round (
        const matrix_exp& m
    );
    /*!
        requires
            - is_built_in_scalar_type<matrix_exp::type>::value == true
              (i.e. m must contain a type like int, float, double, long, etc.)
        ensures
            - if (m contains integers) then
                - returns m unmodified
            - else
                - returns a matrix R such that:
                    - R::type == the same type that was in m
                    - R has the same dimensions as m
                    - for all valid r and c:
                      R(r,c) == m(r,c) rounded to the nearest integral value
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp ceil (
        const matrix_exp& m
    );
    /*!
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m
                - R has the same dimensions as m
                - for all valid r and c:
                  R(r,c) == std::ceil(m(r,c))
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp floor (
        const matrix_exp& m
    );
    /*!
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m
                - R has the same dimensions as m
                - for all valid r and c:
                  R(r,c) == std::floor(m(r,c))
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp round_zeros (
        const matrix_exp& m
    );
    /*!
        requires
            - is_built_in_scalar_type<matrix_exp::type>::value == true
              (i.e. m must contain a type like int, float, double, long, etc.)
        ensures
            - if (m contains integers) then
                - returns m unmodified
            - else
                - returns a matrix R such that:
                    - R::type == the same type that was in m
                    - R has the same dimensions as m
                    - let eps == 10*std::numeric_limits<matrix_exp::type>::epsilon()
                    - for all valid r and c:
                        - if (abs(m(r,c)) >= eps) then
                            - R(r,c) == m(r,c)
                        - else
                            - R(r,c) == 0
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp round_zeros (
        const matrix_exp& m,
        matrix_exp::type eps
    );
    /*!
        requires
            - is_built_in_scalar_type<matrix_exp::type>::value == true
              (i.e. m must contain a type like int, float, double, long, etc.)
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m
                - R has the same dimensions as m
                - for all valid r and c:
                    - if (abs(m(r,c)) >= eps) then
                        - R(r,c) == m(r,c)
                    - else
                        - R(r,c) == 0
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                              Complex number utility functions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    const matrix_exp conj (
        const matrix_exp& m
    );
    /*!
        requires
            - matrix_exp::type == std::complex<T>
        ensures
            - returns a matrix R such that:
                - R::type == std::complex<T>
                - R has the same dimensions as m
                - for all valid r and c:
                  R(r,c) == std::conj(m(r,c))
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp norm (
        const matrix_exp& m
    );
    /*!
        requires
            - matrix_exp::type == std::complex<T>
        ensures
            - returns a matrix R such that:
                - R::type == T
                - R has the same dimensions as m
                - for all valid r and c:
                  R(r,c) == std::norm(m(r,c))
                  (note that std::norm(val) == val.real()*val.real() + val.imag()*val.imag())
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp imag (
        const matrix_exp& m
    );
    /*!
        requires
            - matrix_exp::type == std::complex<T>
        ensures
            - returns a matrix R such that:
                - R::type == T
                - R has the same dimensions as m
                - for all valid r and c:
                  R(r,c) == std::imag(m(r,c))
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp real (
        const matrix_exp& m
    );
    /*!
        requires
            - matrix_exp::type == std::complex<T>
        ensures
            - returns a matrix R such that:
                - R::type == T
                - R has the same dimensions as m
                - for all valid r and c:
                  R(r,c) == std::real(m(r,c))
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp complex_matrix (
        const matrix_exp& real_part
    );
    /*!
        ensures
            - returns a matrix R such that:
                - R::type == std::complex<T> where T is whatever type real_part used.
                - R has the same dimensions as real_part.
                - for all valid r and c:
                  R(r,c) == std::complex(real_part(r,c), 0)
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp complex_matrix (
        const matrix_exp& real_part,
        const matrix_exp& imag_part
    );
    /*!
        requires
            - real_part.nr() == imag_part.nr()
            - real_part.nc() == imag_part.nc()
            - real_part and imag_part both contain the same type of element
        ensures
            - returns a matrix R such that:
                - R::type == std::complex<T> where T is whatever type real_part and imag_part used.
                - R has the same dimensions as real_part and imag_part
                - for all valid r and c:
                  R(r,c) == std::complex(real_part(r,c),imag_part(r,c))
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                              Trigonometric Functions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    const matrix_exp sin (
        const matrix_exp& m
    );
    /*!
        requires
            - matrix_exp::type == float, double, or long double
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m
                - R has the same dimensions as m
                - for all valid r and c:
                  R(r,c) == std::sin(m(r,c))
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp cos (
        const matrix_exp& m
    );
    /*!
        requires
            - matrix_exp::type == float, double, or long double
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m
                - R has the same dimensions as m
                - for all valid r and c:
                  R(r,c) == std::cos(m(r,c))
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp tan (
        const matrix_exp& m
    );
    /*!
        requires
            - matrix_exp::type == float, double, or long double
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m
                - R has the same dimensions as m
                - for all valid r and c:
                  R(r,c) == std::tan(m(r,c))
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp asin (
        const matrix_exp& m
    );
    /*!
        requires
            - matrix_exp::type == float, double, or long double
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m
                - R has the same dimensions as m
                - for all valid r and c:
                  R(r,c) == std::asin(m(r,c))
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp acos (
        const matrix_exp& m
    );
    /*!
        requires
            - matrix_exp::type == float, double, or long double
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m
                - R has the same dimensions as m
                - for all valid r and c:
                  R(r,c) == std::acos(m(r,c))
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp atan (
        const matrix_exp& m
    );
    /*!
        requires
            - matrix_exp::type == float, double, or long double
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m
                - R has the same dimensions as m
                - for all valid r and c:
                  R(r,c) == std::atan(m(r,c))
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp sinh (
        const matrix_exp& m
    );
    /*!
        requires
            - matrix_exp::type == float, double, or long double
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m
                - R has the same dimensions as m
                - for all valid r and c:
                  R(r,c) == std::sinh(m(r,c))
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp cosh (
        const matrix_exp& m
    );
    /*!
        requires
            - matrix_exp::type == float, double, or long double
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m
                - R has the same dimensions as m
                - for all valid r and c:
                  R(r,c) == std::cosh(m(r,c))
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp tanh (
        const matrix_exp& m
    );
    /*!
        requires
            - matrix_exp::type == float, double, or long double
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m
                - R has the same dimensions as m
                - for all valid r and c:
                  R(r,c) == std::tanh(m(r,c))
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MATRIx_MATH_FUNCTIONS_ABSTRACT_


dlib C++ Library - matrix_mat_abstract.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_MATRIx_MAT_ABSTRACT_Hh_
#ifdef DLIB_MATRIx_MAT_ABSTRACT_Hh_

#include "matrix_abstract.h"
#inclue <vector>
#include "../array/array_kernel_abstract.h"
#include "../array2d/array2d_kernel_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename EXP
        >
    const matrix_exp<EXP>& mat (
        const matrix_exp<EXP>& m
    );
    /*!
        ensures
            - returns m
              (i.e. this function just returns the input matrix without any modifications)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    const matrix_exp mat (
        const image_type& img
    );
    /*!
        requires
            - image_type == an image object that implements the interface defined in
              dlib/image_processing/generic_image.h or image_type is a image_view or
              const_image_view object.
        ensures
            - This function converts any kind of generic image object into a dlib::matrix
              expression.  Therefore, it is capable of converting objects like dlib::array2d
              of dlib::cv_image.
            - returns a matrix R such that:
                - R.nr() == array.nr()
                - R.nc() == array.nc()
                - for all valid r and c:
                  R(r, c) == array[r][c]
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename MM
        >
    const matrix_exp mat (
        const array<T,MM>& m
    );
    /*!
        ensures
            - returns a matrix R such that:
                - is_col_vector(R) == true
                - R.size() == m.size()
                - for all valid r:
                  R(r) == m[r]
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename value_type,
        typename alloc
        >
    const matrix_exp mat (
        const std::vector<value_type,alloc>& vector
    );
    /*!
        ensures
            - returns a matrix R such that:
                - is_col_vector(R) == true
                - R.size() == vector.size()
                - for all valid r:
                  R(r) == vector[r]
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename value_type,
        typename alloc
        >
    const matrix_exp mat (
        const std_vector_c<value_type,alloc>& vector
    );
    /*!
        ensures
            - returns a matrix R such that:
                - is_col_vector(R) == true
                - R.size() == vector.size()
                - for all valid r:
                  R(r) == vector[r]
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    const matrix_exp mat (
        const T* ptr,
        long nr
    );
    /*!
        requires
            - nr > 0
            - ptr == a pointer to at least nr T objects
        ensures
            - returns a matrix M such that:
                - M.nr() == nr
                - m.nc() == 1
                - for all valid i:
                  M(i) == ptr[i]
            - Note that the returned matrix doesn't take "ownership" of
              the pointer and thus will not delete or free it.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    const matrix_exp mat (
        const T* ptr,
        long nr,
        long nc
    );
    /*!
        requires
            - nr > 0
            - nc > 0
            - ptr == a pointer to at least nr*nc T objects
        ensures
            - returns a matrix M such that:
                - M.nr() == nr
                - m.nc() == nc
                - for all valid r and c:
                  M(r,c) == ptr[r*nc + c]
                  (i.e. the pointer is interpreted as a matrix laid out in memory
                  in row major order)
            - Note that the returned matrix doesn't take "ownership" of
              the pointer and thus will not delete or free it.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    const matrix_exp mat (
        const ::arma::Mat<T>& m
    );
    /*!
        ensures
            - Converts a matrix from the Armadillo library into a dlib matrix.
            - returns a matrix R such that:
                - R.nr() == m.n_rows
                - R.nc() == m.n_cols
                - for all valid r:
                  R(r,c) == m(r,c)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename _Scalar,
        int _Rows,
        int _Cols,
        int _Options,
        int _MaxRows,
        int _MaxCols
        >
    const matrix_exp mat (
        const ::Eigen::Matrix<_Scalar,_Rows,_Cols,_Options,_MaxRows,_MaxCols>& m
    );
    /*!
        ensures
            - Converts a matrix from the Eigen library into a dlib matrix.
            - returns a matrix R such that:
                - R.nr() == m.rows()
                - R.nc() == m.cols()
                - for all valid r:
                  R(r,c) == m(r,c)
    !*/

// ----------------------------------------------------------------------------------------

    matrix<double,1,1>      mat (double value);
    matrix<float,1,1>       mat (float value);
    matrix<long double,1,1> mat (long double value);
    /*!
        ensures
            - Converts a scalar into a matrix containing just that scalar and returns the
              results.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MATRIx_MAT_ABSTRACT_Hh_


dlib C++ Library - matrix_utilities_abstract.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_MATRIx_UTILITIES_ABSTRACT_
#ifdef DLIB_MATRIx_UTILITIES_ABSTRACT_

#include "matrix_abstract.h"
#include <complex>
#include "../pixel.h"
#include "../geometry/rectangle.h"
#inclue <vector>

namespace dlib
{

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                                   Simple matrix utilities
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    const matrix_exp diag (
        const matrix_exp& m
    );
    /*!
        ensures
            - returns a column vector R that contains the elements from the diagonal
              of m in the order R(0)==m(0,0), R(1)==m(1,1), R(2)==m(2,2) and so on.
    !*/

    template <typename EXP>
    struct diag_exp
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This struct allows you to determine the type of matrix expression
                object returned from the diag() function.  An example makes its
                use clear:

                template <typename EXP>
                void do_something( const matrix_exp<EXP>& mat)
                {
                    // d is a matrix expression that aliases mat.
                    typename diag_exp<EXP>::type d = diag(mat);

                    // Print the diagonal of mat.  So we see that by using
                    // diag_exp we can save the object returned by diag() in
                    // a local variable.
                    cout << d << endl;

                    // Note that you can only save the return value of diag() to
                    // a local variable if the argument to diag() has a lifetime
                    // beyond the diag() expression.  The example shown above is
                    // OK but the following would result in undefined behavior:
                    typename diag_exp<EXP>::type bad = diag(mat + mat);
                }
        !*/
        typedef type_of_expression_returned_by_diag type;
    };

// ----------------------------------------------------------------------------------------

    const matrix_exp diagm (
        const matrix_exp& m
    );
    /*!
        requires
            - is_vector(m) == true
              (i.e. m is a row or column matrix)
        ensures
            - returns a square matrix M such that:
                - diag(M) == m
                - non diagonal elements of M are 0
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp trans (
        const matrix_exp& m
    );
    /*!
        ensures
            - returns the transpose of the matrix m
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_type::type dot (
        const matrix_exp& m1,
        const matrix_exp& m2
    );
    /*!
        requires
            - is_vector(m1) == true
            - is_vector(m2) == true
            - m1.size() == m2.size()
            - m1.size() > 0
        ensures
            - returns the dot product between m1 and m2. That is, this function
              computes and returns the sum, for all i, of m1(i)*m2(i).
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp lowerm (
        const matrix_exp& m
    );
    /*!
        ensures
            - returns a matrix M such that:
                - M::type == the same type that was in m
                - M has the same dimensions as m
                - M is the lower triangular part of m.  That is:
                    - if (r >= c) then
                        - M(r,c) == m(r,c)
                    - else
                        - M(r,c) == 0
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp lowerm (
        const matrix_exp& m,
        const matrix_exp::type scalar_value
    );
    /*!
        ensures
            - returns a matrix M such that:
                - M::type == the same type that was in m
                - M has the same dimensions as m
                - M is the lower triangular part of m except that the diagonal has
                  been set to scalar_value.  That is:
                    - if (r > c) then
                        - M(r,c) == m(r,c)
                    - else if (r == c) then
                        - M(r,c) == scalar_value
                    - else
                        - M(r,c) == 0
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp upperm (
        const matrix_exp& m
    );
    /*!
        ensures
            - returns a matrix M such that:
                - M::type == the same type that was in m
                - M has the same dimensions as m
                - M is the upper triangular part of m.  That is:
                    - if (r <= c) then
                        - M(r,c) == m(r,c)
                    - else
                        - M(r,c) == 0
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp upperm (
        const matrix_exp& m,
        const matrix_exp::type scalar_value
    );
    /*!
        ensures
            - returns a matrix M such that:
                - M::type == the same type that was in m
                - M has the same dimensions as m
                - M is the upper triangular part of m except that the diagonal has
                  been set to scalar_value.  That is:
                    - if (r < c) then
                        - M(r,c) == m(r,c)
                    - else if (r == c) then
                        - M(r,c) == scalar_value
                    - else
                        - M(r,c) == 0
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp make_symmetric (
        const matrix_exp& m
    );
    /*!
        requires
            - m.nr() == m.nc()
              (i.e. m must be a square matrix)
        ensures
            - returns a matrix M such that:
                - M::type == the same type that was in m
                - M has the same dimensions as m
                - M is a symmetric matrix, that is, M == trans(M) and
                  it is constructed from the lower triangular part of m.  Specifically,
                  we have:
                    - lowerm(M) == lowerm(m)
                    - upperm(M) == trans(lowerm(m))
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        long NR,
        long NC,
        T val
        >
    const matrix_exp uniform_matrix (
    );
    /*!
        requires
            - NR > 0 && NC > 0
        ensures
            - returns an NR by NC matrix with elements of type T and all set to val.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        long NR,
        long NC
        >
    const matrix_exp uniform_matrix (
        const T& val
    );
    /*!
        requires
            - NR > 0 && NC > 0
        ensures
            - returns an NR by NC matrix with elements of type T and all set to val.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    const matrix_exp uniform_matrix (
        long nr,
        long nc,
        const T& val
    );
    /*!
        requires
            - nr >= 0 && nc >= 0
        ensures
            - returns an nr by nc matrix with elements of type T and all set to val.
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp ones_matrix (
        const matrix_exp& mat
    );
    /*!
        requires
            - mat.nr() >= 0 && mat.nc() >= 0
        ensures
            - Let T denote the type of element in mat. Then this function
              returns uniform_matrix<T>(mat.nr(), mat.nc(), 1)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    const matrix_exp ones_matrix (
        long nr,
        long nc
    );
    /*!
        requires
            - nr >= 0 && nc >= 0
        ensures
            - returns uniform_matrix<T>(nr, nc, 1)
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp zeros_matrix (
        const matrix_exp& mat
    );
    /*!
        requires
            - mat.nr() >= 0 && mat.nc() >= 0
        ensures
            - Let T denote the type of element in mat. Then this function
              returns uniform_matrix<T>(mat.nr(), mat.nc(), 0)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    const matrix_exp zeros_matrix (
        long nr,
        long nc
    );
    /*!
        requires
            - nr >= 0 && nc >= 0
        ensures
            - returns uniform_matrix<T>(nr, nc, 0)
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp identity_matrix (
        const matrix_exp& mat
    );
    /*!
        requires
            - mat.nr() == mat.nc()
        ensures
            - returns an identity matrix with the same dimensions as mat and
              containing the same type of elements as mat.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    const matrix_exp identity_matrix (
        long N
    );
    /*!
        requires
            - N > 0
        ensures
            - returns an N by N identity matrix with elements of type T.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        long N
        >
    const matrix_exp identity_matrix (
    );
    /*!
        requires
            - N > 0
        ensures
            - returns an N by N identity matrix with elements of type T.
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp linspace (
        double start,
        double end,
        long num
    );
    /*!
        requires
            - num >= 0
        ensures
            - returns a matrix M such that:
                - M::type == double
                - is_row_vector(M) == true
                - M.size() == num
                - M == a row vector with num linearly spaced values beginning with start
                  and stopping with end.
                - M(num-1) == end
                - if (num > 1) then
                    - M(0) == start
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp logspace (
        double start,
        double end,
        long num
    );
    /*!
        requires
            - num >= 0
        ensures
            - returns a matrix M such that:
                - M::type == double
                - is_row_vector(M) == true
                - M.size() == num
                - M == a row vector with num logarithmically spaced values beginning with
                  10^start and stopping with 10^end.
                  (i.e. M == pow(10, linspace(start, end, num)))
                - M(num-1) == 10^end
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp linpiece (
        const double val,
        const matrix_exp& joints
    );
    /*!
        requires
            - is_vector(joints) == true
            - joints.size() >= 2
            - for all valid i < j:
                - joints(i) < joints(j)
        ensures
            - linpiece() is useful for creating piecewise linear functions of val.  For
              example, if w is a parameter vector then you can represent a piecewise linear
              function of val as: f(val) = dot(w, linpiece(val, linspace(0,100,5))).  In
              this case, f(val) is piecewise linear on the intervals [0,25], [25,50],
              [50,75], [75,100].  Moreover, w(i) defines the derivative of f(val) in the
              i-th interval.  Finally, outside the interval [0,100] f(val) has a derivative
              of zero and f(0) == 0.
            - To be precise, this function returns a column vector L such that:
                - L.size() == joints.size()-1
                - is_col_vector(L) == true
                - L contains the same type of elements as joints.
                - for all valid i:
                - if (joints(i) < val)
                    - L(i) == min(val,joints(i+1)) - joints(i)
                - else
                    - L(i) == 0
    !*/

// ----------------------------------------------------------------------------------------

    template <
        long R,
        long C
        >
    const matrix_exp rotate (
        const matrix_exp& m
    );
    /*!
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m
                - R has the same dimensions as m
                - for all valid r and c:
                  R( (r+R)%m.nr() , (c+C)%m.nc() ) == m(r,c)
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp fliplr (
        const matrix_exp& m
    );
    /*!
        ensures
            - flips the matrix m from left to right and returns the result.
              I.e. reverses the order of the columns.
            - returns a matrix M such that:
                - M::type == the same type that was in m
                - M has the same dimensions as m
                - for all valid r and c:
                  M(r,c) == m(r, m.nc()-c-1)
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp flipud (
        const matrix_exp& m
    );
    /*!
        ensures
            - flips the matrix m from up to down and returns the result.
              I.e. reverses the order of the rows.
            - returns a matrix M such that:
                - M::type == the same type that was in m
                - M has the same dimensions as m
                - for all valid r and c:
                  M(r,c) == m(m.nr()-r-1, c)
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp flip (
        const matrix_exp& m
    );
    /*!
        ensures
            - flips the matrix m from up to down and left to right and returns the
              result.  I.e. returns flipud(fliplr(m)).
            - returns a matrix M such that:
                - M::type == the same type that was in m
                - M has the same dimensions as m
                - for all valid r and c:
                  M(r,c) == m(m.nr()-r-1, m.nc()-c-1)
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp reshape (
        const matrix_exp& m,
        long rows,
        long cols
    );
    /*!
        requires
            - m.size() == rows*cols
            - rows > 0
            - cols > 0
        ensures
            - returns a matrix M such that:
                - M.nr() == rows
                - M.nc() == cols
                - M.size() == m.size()
                - for all valid r and c:
                    - let IDX = r*cols + c
                    - M(r,c) == m(IDX/m.nc(), IDX%m.nc())

            - i.e. The matrix m is reshaped into a new matrix of rows by cols
              dimension.  Additionally, the elements of m are laid into M in row major
              order.
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp reshape_to_column_vector (
        const matrix_exp& m
    );
    /*!
        ensures
            - returns a matrix M such that:
                - is_col_vector(M) == true
                - M.size() == m.size()
                - for all valid r and c:
                    - m(r,c) == M(r*m.nc() + c)

            - i.e. The matrix m is reshaped into a column vector.  Note that
              the elements are pulled out in row major order.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        long R,
        long C
        >
    const matrix_exp removerc (
        const matrix_exp& m
    );
    /*!
        requires
            - m.nr() > R >= 0
            - m.nc() > C >= 0
        ensures
            - returns a matrix M such that:
                - M.nr() == m.nr() - 1
                - M.nc() == m.nc() - 1
                - M == m with its R row and C column removed
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp removerc (
        const matrix_exp& m,
        long R,
        long C
    );
    /*!
        requires
            - m.nr() > R >= 0
            - m.nc() > C >= 0
        ensures
            - returns a matrix M such that:
                - M.nr() == m.nr() - 1
                - M.nc() == m.nc() - 1
                - M == m with its R row and C column removed
    !*/

// ----------------------------------------------------------------------------------------

    template <
        long R
        >
    const matrix_exp remove_row (
        const matrix_exp& m
    );
    /*!
        requires
            - m.nr() > R >= 0
        ensures
            - returns a matrix M such that:
                - M.nr() == m.nr() - 1
                - M.nc() == m.nc()
                - M == m with its R row removed
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp remove_row (
        const matrix_exp& m,
        long R
    );
    /*!
        requires
            - m.nr() > R >= 0
        ensures
            - returns a matrix M such that:
                - M.nr() == m.nr() - 1
                - M.nc() == m.nc()
                - M == m with its R row removed
    !*/

// ----------------------------------------------------------------------------------------

    template <
        long C
        >
    const matrix_exp remove_col (
        const matrix_exp& m
    );
    /*!
        requires
            - m.nc() > C >= 0
        ensures
            - returns a matrix M such that:
                - M.nr() == m.nr()
                - M.nc() == m.nc() - 1
                - M == m with its C column removed
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp remove_col (
        const matrix_exp& m,
        long C
    );
    /*!
        requires
            - m.nc() > C >= 0
        ensures
            - returns a matrix M such that:
                - M.nr() == m.nr()
                - M.nc() == m.nc() - 1
                - M == m with its C column removed
    !*/

// ----------------------------------------------------------------------------------------

    template <
       typename target_type
       >
    const matrix_exp matrix_cast (
        const matrix_exp& m
    );
    /*!
        ensures
            - returns a matrix R where for all valid r and c:
              R(r,c) == static_cast<target_type>(m(r,c))
              also, R has the same dimensions as m.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        long NR,
        long NC,
        typename MM,
        typename U,
        typename L
        >
    void set_all_elements (
        matrix<T,NR,NC,MM,L>& m,
        U value
    );
    /*!
        ensures
            - for all valid r and c:
              m(r,c) == value
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp::matrix_type tmp (
        const matrix_exp& m
    );
    /*!
        ensures
            - returns a temporary matrix object that is a copy of m.
              (This allows you to easily force a matrix_exp to fully evaluate)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        long NR,
        long NC,
        typename MM,
        typename L
        >
    uint32 hash (
        const matrix<T,NR,NC,MM,L>& item,
        uint32 seed = 0
    );
    /*!
        requires
            - T is a standard layout type (e.g. a POD type like int, float,
              or a simple struct).
        ensures
            - returns a 32bit hash of the data stored in item.
            - Each value of seed results in a different hash function being used.
              (e.g. hash(item,0) should generally not be equal to hash(item,1))
            - uses the murmur_hash3() routine to compute the actual hash.
            - Note that if the memory layout of the elements in item change between
              hardware platforms then hash() will give different outputs.  If you want
              hash() to always give the same output for the same input then you must
              ensure that elements of item always have the same layout in memory.
              Typically this means using fixed width types and performing byte swapping
              to account for endianness before passing item to hash().
    !*/

// ----------------------------------------------------------------------------------------

    // if matrix_exp contains non-complex types (e.g. float, double)
    bool equal (
        const matrix_exp& a,
        const matrix_exp& b,
        const matrix_exp::type epsilon = 100*std::numeric_limits<matrix_exp::type>::epsilon()
    );
    /*!
        ensures
            - if (a and b don't have the same dimensions) then
                - returns false
            - else if (there exists an r and c such that abs(a(r,c)-b(r,c)) > epsilon) then
                - returns false
            - else
                - returns true
    !*/

// ----------------------------------------------------------------------------------------

    // if matrix_exp contains std::complex types
    bool equal (
        const matrix_exp& a,
        const matrix_exp& b,
        const matrix_exp::type::value_type epsilon = 100*std::numeric_limits<matrix_exp::type::value_type>::epsilon()
    );
    /*!
        ensures
            - if (a and b don't have the same dimensions) then
                - returns false
            - else if (there exists an r and c such that abs(real(a(r,c)-b(r,c))) > epsilon
              or abs(imag(a(r,c)-b(r,c))) > epsilon) then
                - returns false
            - else
                - returns true
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp pointwise_multiply (
        const matrix_exp& a,
        const matrix_exp& b
    );
    /*!
        requires
            - a.nr() == b.nr()
            - a.nc() == b.nc()
            - a and b both contain the same type of element (one or both
              can also be of type std::complex so long as the underlying type
              in them is the same)
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in a and b.
                - R has the same dimensions as a and b.
                - for all valid r and c:
                  R(r,c) == a(r,c) * b(r,c)
    !*/

    const matrix_exp pointwise_multiply (
        const matrix_exp& a,
        const matrix_exp& b,
        const matrix_exp& c
    );
    /*!
        performs pointwise_multiply(a,pointwise_multiply(b,c));
    !*/

    const matrix_exp pointwise_multiply (
        const matrix_exp& a,
        const matrix_exp& b,
        const matrix_exp& c,
        const matrix_exp& d
    );
    /*!
        performs pointwise_multiply(pointwise_multiply(a,b),pointwise_multiply(c,d));
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp join_rows (
        const matrix_exp& a,
        const matrix_exp& b
    );
    /*!
        requires
            - a.nr() == b.nr() || a.size() == 0 || b.size() == 0
            - a and b both contain the same type of element
        ensures
            - This function joins two matrices together by concatenating their rows.
            - returns a matrix R such that:
                - R::type == the same type that was in a and b.
                - R.nr() == a.nr() == b.nr()
                - R.nc() == a.nc() + b.nc()
                - for all valid r and c:
                    - if (c < a.nc()) then
                        - R(r,c) == a(r,c)
                    - else
                        - R(r,c) == b(r, c-a.nc())
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp join_cols (
        const matrix_exp& a,
        const matrix_exp& b
    );
    /*!
        requires
            - a.nc() == b.nc() || a.size() == 0 || b.size() == 0
            - a and b both contain the same type of element
        ensures
            - This function joins two matrices together by concatenating their columns.
            - returns a matrix R such that:
                - R::type == the same type that was in a and b.
                - R.nr() == a.nr() + b.nr()
                - R.nc() == a.nc() == b.nc()
                - for all valid r and c:
                    - if (r < a.nr()) then
                        - R(r,c) == a(r,c)
                    - else
                        - R(r,c) == b(r-a.nr(), c)
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp tensor_product (
        const matrix_exp& a,
        const matrix_exp& b
    );
    /*!
        requires
            - a and b both contain the same type of element
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in a and b.
                - R.nr() == a.nr() * b.nr()
                - R.nc() == a.nc() * b.nc()
                - for all valid r and c:
                  R(r,c) == a(r/b.nr(), c/b.nc()) * b(r%b.nr(), c%b.nc())
                - I.e. R is the tensor product of matrix a with matrix b
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp cartesian_product (
        const matrix_exp& A,
        const matrix_exp& B
    );
    /*!
        requires
            - A and B both contain the same type of element
        ensures
            - Think of A and B as sets of column vectors.  Then this function
              returns a matrix that contains a set of column vectors that is
              the Cartesian product of the sets A and B.  That is, the resulting
              matrix contains every possible combination of vectors from both A and
              B.
            - returns a matrix R such that:
                - R::type == the same type that was in A and B.
                - R.nr() == A.nr() + B.nr()
                - R.nc() == A.nc() * B.nc()
                - Each column of R is the concatenation of a column vector
                  from A with a column vector from B.
                - for all valid r and c:
                    - if (r < A.nr()) then
                        - R(r,c) == A(r, c/B.nc())
                    - else
                        - R(r,c) == B(r-A.nr(), c%B.nc())
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp scale_columns (
        const matrix_exp& m,
        const matrix_exp& v
    );
    /*!
        requires
            - is_vector(v) == true
            - v.size() == m.nc()
            - m and v both contain the same type of element
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m and v.
                - R has the same dimensions as m.
                - for all valid r and c:
                  R(r,c) == m(r,c) * v(c)
                - i.e. R is the result of multiplying each of m's columns by
                  the corresponding scalar in v.

            - Note that this function is identical to the expression m*diagm(v).
              That is, the * operator is overloaded for this case and will invoke
              scale_columns() automatically as appropriate.
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp scale_rows (
        const matrix_exp& m,
        const matrix_exp& v
    );
    /*!
        requires
            - is_vector(v) == true
            - v.size() == m.nr()
            - m and v both contain the same type of element
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m and v.
                - R has the same dimensions as m.
                - for all valid r and c:
                  R(r,c) == m(r,c) * v(r)
                - i.e. R is the result of multiplying each of m's rows by
                  the corresponding scalar in v.

            - Note that this function is identical to the expression diagm(v)*m.
              That is, the * operator is overloaded for this case and will invoke
              scale_rows() automatically as appropriate.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    void sort_columns (
        matrix<T>& m,
        matrix<T>& v
    );
    /*!
        requires
            - is_col_vector(v) == true
            - v.size() == m.nc()
            - m and v both contain the same type of element
        ensures
            - the dimensions for m and v are not changed
            - sorts the columns of m according to the values in v.
              i.e.
                - #v == the contents of v but in sorted order according to
                  operator<.  So smaller elements come first.
                - Let #v(new(i)) == v(i) (i.e. new(i) is the index element i moved to)
                - colm(#m,new(i)) == colm(m,i)
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    void rsort_columns (
        matrix<T>& m,
        matrix<T>& v
    );
    /*!
        requires
            - is_col_vector(v) == true
            - v.size() == m.nc()
            - m and v both contain the same type of element
        ensures
            - the dimensions for m and v are not changed
            - sorts the columns of m according to the values in v.
              i.e.
                - #v == the contents of v but in sorted order according to
                  operator>.  So larger elements come first.
                - Let #v(new(i)) == v(i) (i.e. new(i) is the index element i moved to)
                - colm(#m,new(i)) == colm(m,i)
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp::type length_squared (
        const matrix_exp& m
    );
    /*!
        requires
            - is_vector(m) == true
        ensures
            - returns sum(squared(m))
              (i.e. returns the square of the length of the vector m)
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp::type length (
        const matrix_exp& m
    );
    /*!
        requires
            - is_vector(m) == true
        ensures
            - returns sqrt(sum(squared(m)))
              (i.e. returns the length of the vector m)
            - if (m contains integer valued elements) then
                - The return type is a double that represents the length.  Therefore, the
                  return value of length() is always represented using a floating point
                  type.
    !*/

// ----------------------------------------------------------------------------------------

    bool is_row_vector (
        const matrix_exp& m
    );
    /*!
        ensures
            - if (m.nr() == 1) then
                - return true
            - else
                - returns false
    !*/

    bool is_col_vector (
        const matrix_exp& m
    );
    /*!
        ensures
            - if (m.nc() == 1) then
                - return true
            - else
                - returns false
    !*/

    bool is_vector (
        const matrix_exp& m
    );
    /*!
        ensures
            - if (is_row_vector(m) || is_col_vector(m)) then
                - return true
            - else
                - returns false
    !*/

// ----------------------------------------------------------------------------------------

    bool is_finite (
        const matrix_exp& m
    );
    /*!
        ensures
            - returns true if all the values in m are finite values and also not any kind
              of NaN value.
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                      Thresholding relational operators
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <typename S>
    const matrix_exp operator< (
        const matrix_exp& m,
        const S& s
    );
    /*!
        requires
            - is_built_in_scalar_type<S>::value == true
            - is_built_in_scalar_type<matrix_exp::type>::value == true
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m.
                - R has the same dimensions as m.
                - for all valid r and c:
                    - if (m(r,c) < s) then
                        - R(r,c) == 1
                    - else
                        - R(r,c) == 0
                - i.e. R is a binary matrix of all 1s or 0s.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename S>
    const matrix_exp operator< (
        const S& s,
        const matrix_exp& m
    );
    /*!
        requires
            - is_built_in_scalar_type<S>::value == true
            - is_built_in_scalar_type<matrix_exp::type>::value == true
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m.
                - R has the same dimensions as m.
                - for all valid r and c:
                    - if (s < m(r,c)) then
                        - R(r,c) == 1
                    - else
                        - R(r,c) == 0
                - i.e. R is a binary matrix of all 1s or 0s.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename S>
    const matrix_exp operator<= (
        const matrix_exp& m,
        const S& s
    );
    /*!
        requires
            - is_built_in_scalar_type<S>::value == true
            - is_built_in_scalar_type<matrix_exp::type>::value == true
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m.
                - R has the same dimensions as m.
                - for all valid r and c:
                    - if (m(r,c) <= s) then
                        - R(r,c) == 1
                    - else
                        - R(r,c) == 0
                - i.e. R is a binary matrix of all 1s or 0s.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename S>
    const matrix_exp operator<= (
        const S& s,
        const matrix_exp& m
    );
    /*!
        requires
            - is_built_in_scalar_type<S>::value == true
            - is_built_in_scalar_type<matrix_exp::type>::value == true
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m.
                - R has the same dimensions as m.
                - for all valid r and c:
                    - if (s <= m(r,c)) then
                        - R(r,c) == 1
                    - else
                        - R(r,c) == 0
                - i.e. R is a binary matrix of all 1s or 0s.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename S>
    const matrix_exp operator> (
        const matrix_exp& m,
        const S& s
    );
    /*!
        requires
            - is_built_in_scalar_type<S>::value == true
            - is_built_in_scalar_type<matrix_exp::type>::value == true
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m.
                - R has the same dimensions as m.
                - for all valid r and c:
                    - if (m(r,c) > s) then
                        - R(r,c) == 1
                    - else
                        - R(r,c) == 0
                - i.e. R is a binary matrix of all 1s or 0s.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename S>
    const matrix_exp operator> (
        const S& s,
        const matrix_exp& m
    );
    /*!
        requires
            - is_built_in_scalar_type<S>::value == true
            - is_built_in_scalar_type<matrix_exp::type>::value == true
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m.
                - R has the same dimensions as m.
                - for all valid r and c:
                    - if (s > m(r,c)) then
                        - R(r,c) == 1
                    - else
                        - R(r,c) == 0
                - i.e. R is a binary matrix of all 1s or 0s.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename S>
    const matrix_exp operator>= (
        const matrix_exp& m,
        const S& s
    );
    /*!
        requires
            - is_built_in_scalar_type<S>::value == true
            - is_built_in_scalar_type<matrix_exp::type>::value == true
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m.
                - R has the same dimensions as m.
                - for all valid r and c:
                    - if (m(r,c) >= s) then
                        - R(r,c) == 1
                    - else
                        - R(r,c) == 0
                - i.e. R is a binary matrix of all 1s or 0s.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename S>
    const matrix_exp operator>= (
        const S& s,
        const matrix_exp& m
    );
    /*!
        requires
            - is_built_in_scalar_type<S>::value == true
            - is_built_in_scalar_type<matrix_exp::type>::value == true
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m.
                - R has the same dimensions as m.
                - for all valid r and c:
                    - if (s >= m(r,c)) then
                        - R(r,c) == 1
                    - else
                        - R(r,c) == 0
                - i.e. R is a binary matrix of all 1s or 0s.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename S>
    const matrix_exp operator== (
        const matrix_exp& m,
        const S& s
    );
    /*!
        requires
            - is_built_in_scalar_type<S>::value == true
            - is_built_in_scalar_type<matrix_exp::type>::value == true
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m.
                - R has the same dimensions as m.
                - for all valid r and c:
                    - if (m(r,c) == s) then
                        - R(r,c) == 1
                    - else
                        - R(r,c) == 0
                - i.e. R is a binary matrix of all 1s or 0s.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename S>
    const matrix_exp operator== (
        const S& s,
        const matrix_exp& m
    );
    /*!
        requires
            - is_built_in_scalar_type<S>::value == true
            - is_built_in_scalar_type<matrix_exp::type>::value == true
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m.
                - R has the same dimensions as m.
                - for all valid r and c:
                    - if (s == m(r,c)) then
                        - R(r,c) == 1
                    - else
                        - R(r,c) == 0
                - i.e. R is a binary matrix of all 1s or 0s.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename S>
    const matrix_exp operator!= (
        const matrix_exp& m,
        const S& s
    );
    /*!
        requires
            - is_built_in_scalar_type<S>::value == true
            - is_built_in_scalar_type<matrix_exp::type>::value == true
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m.
                - R has the same dimensions as m.
                - for all valid r and c:
                    - if (m(r,c) != s) then
                        - R(r,c) == 1
                    - else
                        - R(r,c) == 0
                - i.e. R is a binary matrix of all 1s or 0s.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename S>
    const matrix_exp operator!= (
        const S& s,
        const matrix_exp& m
    );
    /*!
        requires
            - is_built_in_scalar_type<S>::value == true
            - is_built_in_scalar_type<matrix_exp::type>::value == true
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m.
                - R has the same dimensions as m.
                - for all valid r and c:
                    - if (s != m(r,c)) then
                        - R(r,c) == 1
                    - else
                        - R(r,c) == 0
                - i.e. R is a binary matrix of all 1s or 0s.
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                              Statistics
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    const matrix_exp::type min (
        const matrix_exp& m
    );
    /*!
        requires
            - m.size() > 0
        ensures
            - returns the value of the smallest element of m.  If m contains complex
              elements then the element returned is the one with the smallest norm
              according to std::norm().
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp::type max (
        const matrix_exp& m
    );
    /*!
        requires
            - m.size() > 0
        ensures
            - returns the value of the biggest element of m.  If m contains complex
              elements then the element returned is the one with the largest norm
              according to std::norm().
    !*/

// ----------------------------------------------------------------------------------------

    void find_min_and_max (
        const matrix_exp& m,
        matrix_exp::type& min_val,
        matrix_exp::type& max_val
    );
    /*!
        requires
            - m.size() > 0
        ensures
            - #min_val == min(m)
            - #max_val == max(m)
            - This function computes both the min and max in just one pass
              over the elements of the matrix m.
    !*/

// ----------------------------------------------------------------------------------------

    long index_of_max (
        const matrix_exp& m
    );
    /*!
        requires
            - is_vector(m) == true
            - m.size() > 0
        ensures
            - returns the index of the largest element in m.
              (i.e. m(index_of_max(m)) == max(m))
    !*/

// ----------------------------------------------------------------------------------------

    long index_of_min (
        const matrix_exp& m
    );
    /*!
        requires
            - is_vector(m) == true
            - m.size() > 0
        ensures
            - returns the index of the smallest element in m.
              (i.e. m(index_of_min(m)) == min(m))
    !*/

// ----------------------------------------------------------------------------------------

    point max_point (
        const matrix_exp& m
    );
    /*!
        requires
            - m.size() > 0
        ensures
            - returns the location of the maximum element of the array, that is, if the
              returned point is P then it will be the case that: m(P.y(),P.x()) == max(m).
    !*/

// ----------------------------------------------------------------------------------------

    dlib::vector<double,2> max_point_interpolated (
        const matrix_exp& m
    );
    /*!
        requires
            - m.size() > 0
        ensures
            - Like max_point(), this function finds the location in m with the largest
              value.  However, we additionally use some quadratic interpolation to find the
              location of the maximum point with sub-pixel accuracy.  Therefore, the
              returned point is equal to max_point(m) + some small sub-pixel delta.
    !*/

// ----------------------------------------------------------------------------------------

    point min_point (
        const matrix_exp& m
    );
    /*!
        requires
            - m.size() > 0
        ensures
            - returns the location of the minimum element of the array, that is, if the
              returned point is P then it will be the case that: m(P.y(),P.x()) == min(m).
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp::type sum (
        const matrix_exp& m
    );
    /*!
        ensures
            - returns the sum of all elements in m
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp sum_rows (
        const matrix_exp& m
    );
    /*!
        requires
            - m.size() > 0
        ensures
            - returns a row matrix that contains the sum of all the rows in m.
            - returns a matrix M such that
                - M::type == the same type that was in m
                - M.nr() == 1
                - M.nc() == m.nc()
                - for all valid i:
                    - M(i) == sum(colm(m,i))
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp sum_cols (
        const matrix_exp& m
    );
    /*!
        requires
            - m.size() > 0
        ensures
            - returns a column matrix that contains the sum of all the columns in m.
            - returns a matrix M such that
                - M::type == the same type that was in m
                - M.nr() == m.nr()
                - M.nc() == 1
                - for all valid i:
                    - M(i) == sum(rowm(m,i))
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp::type prod (
        const matrix_exp& m
    );
    /*!
        ensures
            - returns the results of multiplying all elements of m together.
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp::type mean (
        const matrix_exp& m
    );
    /*!
        ensures
            - returns the mean of all elements in m.
              (i.e. returns sum(m)/(m.nr()*m.nc()))
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp::type variance (
        const matrix_exp& m
    );
    /*!
        ensures
            - returns the unbiased sample variance of all elements in m
              (i.e. 1.0/(m.nr()*m.nc() - 1)*(sum of all pow(m(i,j) - mean(m),2)))
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp::type stddev (
        const matrix_exp& m
    );
    /*!
        ensures
            - returns sqrt(variance(m))
    !*/

// ----------------------------------------------------------------------------------------

    const matrix covariance (
        const matrix_exp& m
    );
    /*!
        requires
            - matrix_exp::type == a dlib::matrix object
            - is_col_vector(m) == true
            - m.size() > 1
            - for all valid i, j:
                - is_col_vector(m(i)) == true
                - m(i).size() > 0
                - m(i).size() == m(j).size()
                - i.e. m contains only column vectors and all the column vectors
                  have the same non-zero length
        ensures
            - returns the unbiased sample covariance matrix for the set of samples
              in m.
              (i.e. 1.0/(m.nr()-1)*(sum of all (m(i) - mean(m))*trans(m(i) - mean(m))))
            - the returned matrix will contain elements of type matrix_exp::type::type.
            - the returned matrix will have m(0).nr() rows and columns.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename rand_gen>
    const matrix<double> randm(
        long nr,
        long nc,
        rand_gen& rnd
    );
    /*!
        requires
            - nr >= 0
            - nc >= 0
            - rand_gen == an object that implements the rand/rand_float_abstract.h interface
        ensures
            - generates a random matrix using the given rnd random number generator
            - returns a matrix M such that
                - M::type == double
                - M.nr() == nr
                - M.nc() == nc
                - for all valid i, j:
                    - M(i,j) == a random number such that 0 <= M(i,j) < 1
    !*/

// ----------------------------------------------------------------------------------------

    inline const matrix<double> randm(
        long nr,
        long nc
    );
    /*!
        requires
            - nr >= 0
            - nc >= 0
        ensures
            - generates a random matrix using std::rand()
            - returns a matrix M such that
                - M::type == double
                - M.nr() == nr
                - M.nc() == nc
                - for all valid i, j:
                    - M(i,j) == a random number such that 0 <= M(i,j) < 1
    !*/

// ----------------------------------------------------------------------------------------

    inline const matrix_exp gaussian_randm (
        long nr,
        long nc,
        unsigned long seed = 0
    );
    /*!
        requires
            - nr >= 0
            - nc >= 0
        ensures
            - returns a matrix with its values filled with 0 mean unit variance Gaussian
              random numbers.
            - Each setting of the seed results in a different random matrix.
            - The returned matrix is lazily evaluated using the expression templates
              technique.  This means that the returned matrix doesn't take up any memory
              and is only an expression template.  The values themselves are computed on
              demand using the gaussian_random_hash() routine.
            - returns a matrix M such that
                - M::type == double
                - M.nr() == nr
                - M.nc() == nc
                - for all valid i, j:
                    - M(i,j) == gaussian_random_hash(i,j,seed)
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                                 Pixel and Image Utilities
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename P
        >
    const matrix_exp pixel_to_vector (
        const P& pixel
    );
    /*!
        requires
            - pixel_traits<P> must be defined
        ensures
            - returns a matrix M such that:
                - M::type == T
                - M::NC == 1
                - M::NR == pixel_traits<P>::num
                - if (pixel_traits<P>::grayscale) then
                    - M(0) == pixel
                - if (pixel_traits<P>::rgb) then
                    - M(0) == pixel.red
                    - M(1) == pixel.green
                    - M(2) == pixel.blue
                - if (pixel_traits<P>::hsi) then
                    - M(0) == pixel.h
                    - M(1) == pixel.s
                    - M(2) == pixel.i
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename P
        >
    void vector_to_pixel (
        P& pixel,
        const matrix_exp& vector
    );
    /*!
        requires
            - vector::NR == pixel_traits<P>::num
            - vector::NC == 1
              (i.e. you have to use a statically dimensioned vector)
        ensures
            - if (pixel_traits<P>::grayscale) then
                - pixel == M(0)
            - if (pixel_traits<P>::rgb) then
                - pixel.red   == M(0)
                - pixel.green == M(1)
                - pixel.blue  == M(2)
            - if (pixel_traits<P>::hsi) then
                - pixel.h == M(0)
                - pixel.s == M(1)
                - pixel.i == M(2)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        long lower,
        long upper
        >
    const matrix_exp clamp (
        const matrix_exp& m
    );
    /*!
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m
                - R has the same dimensions as m
                - for all valid r and c:
                    - if (m(r,c) > upper) then
                        - R(r,c) == upper
                    - else if (m(r,c) < lower) then
                        - R(r,c) == lower
                    - else
                        - R(r,c) == m(r,c)
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp clamp (
        const matrix_exp& m,
        const matrix_exp::type& lower,
        const matrix_exp::type& upper
    );
    /*!
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m
                - R has the same dimensions as m
                - for all valid r and c:
                    - if (m(r,c) > upper) then
                        - R(r,c) == upper
                    - else if (m(r,c) < lower) then
                        - R(r,c) == lower
                    - else
                        - R(r,c) == m(r,c)
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp clamp (
        const matrix_exp& m,
        const matrix_exp& lower,
        const matrix_exp& upper
    );
    /*!
        requires
            - m.nr() == lower.nr()
            - m.nc() == lower.nc()
            - m.nr() == upper.nr()
            - m.nc() == upper.nc()
            - m, lower, and upper all contain the same type of elements.
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m
                - R has the same dimensions as m
                - for all valid r and c:
                    - if (m(r,c) > upper(r,c)) then
                        - R(r,c) == upper(r,c)
                    - else if (m(r,c) < lower(r,c)) then
                        - R(r,c) == lower(r,c)
                    - else
                        - R(r,c) == m(r,c)
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp lowerbound (
        const matrix_exp& m,
        const matrix_exp::type& thresh
    );
    /*!
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m
                - R has the same dimensions as m
                - for all valid r and c:
                    - if (m(r,c) >= thresh) then
                        - R(r,c) == m(r,c)
                    - else
                        - R(r,c) == thresh
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp upperbound (
        const matrix_exp& m,
        const matrix_exp::type& thresh
    );
    /*!
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m
                - R has the same dimensions as m
                - for all valid r and c:
                    - if (m(r,c) <= thresh) then
                        - R(r,c) == m(r,c)
                    - else
                        - R(r,c) == thresh
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MATRIx_UTILITIES_ABSTRACT_


dlib C++ Library - matrix_la_abstract.h

// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_MATRIx_LA_FUNCTS_ABSTRACT_
#ifdef DLIB_MATRIx_LA_FUNCTS_ABSTRACT_

#include "matrix_abstract.h"
#include <complex>

namespace dlib
{

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                             Global linear algebra functions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    const matrix_exp::matrix_type inv (
        const matrix_exp& m
    );
    /*!
        requires
            - m is a square matrix
        ensures
            - returns the inverse of m
              (Note that if m is singular or so close to being singular that there
              is a lot of numerical error then the returned matrix will be bogus.
              You can check by seeing if m*inv(m) is an identity matrix)
    !*/

// ----------------------------------------------------------------------------------------

    const matrix pinv (
        const matrix_exp& m,
        double tol = 0
    );
    /*!
        requires
            - tol >= 0
        ensures
            - returns the Moore-Penrose pseudoinverse of m.
            - The returned matrix has m.nc() rows and m.nr() columns.
            - if (tol == 0) then
                - singular values less than max(m.nr(),m.nc()) times the machine epsilon
                  times the largest singular value are ignored.
            - else
                - singular values less than tol are ignored.
    !*/

// ----------------------------------------------------------------------------------------

    void svd (
        const matrix_exp& m,
        matrix<matrix_exp::type>& u,
        matrix<matrix_exp::type>& w,
        matrix<matrix_exp::type>& v
    );
    /*!
        ensures
            - computes the singular value decomposition of m
            - m == #u*#w*trans(#v)
            - trans(#u)*#u == identity matrix
            - trans(#v)*#v == identity matrix
            - diag(#w) == the singular values of the matrix m in no
              particular order.  All non-diagonal elements of #w are
              set to 0.
            - #u.nr() == m.nr()
            - #u.nc() == m.nc()
            - #w.nr() == m.nc()
            - #w.nc() == m.nc()
            - #v.nr() == m.nc()
            - #v.nc() == m.nc()
            - if DLIB_USE_LAPACK is #defined then the xGESVD routine
              from LAPACK is used to compute the SVD.
    !*/

// ----------------------------------------------------------------------------------------

    long svd2 (
        bool withu,
        bool withv,
        const matrix_exp& m,
        matrix<matrix_exp::type>& u,
        matrix<matrix_exp::type>& w,
        matrix<matrix_exp::type>& v
    );
    /*!
        requires
            - m.nr() >= m.nc()
        ensures
            - computes the singular value decomposition of matrix m
            - m == subm(#u,get_rect(m))*diagm(#w)*trans(#v)
            - trans(#u)*#u == identity matrix
            - trans(#v)*#v == identity matrix
            - #w == the singular values of the matrix m in no
              particular order.
            - #u.nr() == m.nr()
            - #u.nc() == m.nr()
            - #w.nr() == m.nc()
            - #w.nc() == 1
            - #v.nr() == m.nc()
            - #v.nc() == m.nc()
            - if (widthu == false) then
                - ignore the above regarding #u, it isn't computed and its
                  output state is undefined.
            - if (widthv == false) then
                - ignore the above regarding #v, it isn't computed and its
                  output state is undefined.
            - returns an error code of 0, if no errors and 'k' if we fail to
              converge at the 'kth' singular value.
            - if (DLIB_USE_LAPACK is #defined) then
                - if (withu == withv) then
                    - the xGESDD routine from LAPACK is used to compute the SVD.
                - else
                    - the xGESVD routine from LAPACK is used to compute the SVD.
    !*/

// ----------------------------------------------------------------------------------------

    void svd3 (
        const matrix_exp& m,
        matrix<matrix_exp::type>& u,
        matrix<matrix_exp::type>& w,
        matrix<matrix_exp::type>& v
    );
    /*!
        ensures
            - computes the singular value decomposition of m
            - m == #u*diagm(#w)*trans(#v)
            - trans(#u)*#u == identity matrix
            - trans(#v)*#v == identity matrix
            - #w == the singular values of the matrix m in no
              particular order.
            - #u.nr() == m.nr()
            - #u.nc() == m.nc()
            - #w.nr() == m.nc()
            - #w.nc() == 1
            - #v.nr() == m.nc()
            - #v.nc() == m.nc()
            - if DLIB_USE_LAPACK is #defined then the xGESVD routine
              from LAPACK is used to compute the SVD.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    void svd_fast (
        const matrix<T>& A,
        matrix<T>& u,
        matrix<T>& w,
        matrix<T>& v,
        unsigned long l,
        unsigned long q = 1
    );
    /*!
        requires
            - l > 0
            - A.size() > 0
              (i.e. A can't be an empty matrix)
        ensures
            - computes the singular value decomposition of A.
            - Lets define some constants we use to document the behavior of svd_fast():
                - Let m = A.nr()
                - Let n = A.nc()
                - Let k = min(l, min(m,n))
                - Therefore, A represents an m by n matrix and svd_fast() is designed
                  to find a rank-k representation of it.
            - if (the rank of A is <= k) then
                - A == #u*diagm(#w)*trans(#v)
            - else
                - A is approximated by #u*diagm(#w)*trans(#v)
                  (i.e. In this case A can't be represented with a rank-k matrix, so the
                  matrix you get by trying to reconstruct A from the output of the SVD is
                  not exactly the same.)
            - trans(#u)*#u == identity matrix
            - trans(#v)*#v == identity matrix
            - #w == the top k singular values of the matrix A (in no particular order).
            - #u.nr() == m
            - #u.nc() == k
            - #w.nr() == k
            - #w.nc() == 1
            - #v.nr() == n
            - #v.nc() == k
            - This function implements the randomized subspace iteration defined in the
              algorithm 4.4 and 5.1 boxes of the paper:
                Finding Structure with Randomness: Probabilistic Algorithms for
                Constructing Approximate Matrix Decompositions by Halko et al.
              Therefore, it is very fast and suitable for use with very large matrices.
              Moreover, q is the number of subspace iterations performed.  Larger
              values of q might increase the accuracy of the solution but the default
              value should be good for many problems.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename sparse_vector_type,
        typename T
        >
    void svd_fast (
        const std::vector<sparse_vector_type>& A,
        matrix<T>& u,
        matrix<T>& w,
        matrix<T>& v,
        unsigned long l,
        unsigned long q = 1
    );
    /*!
        requires
            - A contains a set of sparse vectors.  See dlib/svm/sparse_vector_abstract.h
              for a definition of what constitutes a sparse vector.
            - l > 0
            - max_index_plus_one(A) > 0
              (i.e. A can't be an empty matrix)
        ensures
            - computes the singular value decomposition of A.  In this case, we interpret A
              as a matrix of A.size() rows, where each row is defined by a sparse vector.
            - Lets define some constants we use to document the behavior of svd_fast():
                - Let m = A.size()
                - Let n = max_index_plus_one(A)
                - Let k = min(l, min(m,n))
                - Therefore, A represents an m by n matrix and svd_fast() is designed
                  to find a rank-k representation of it.
            - if (the rank of A is <= k) then
                - A == #u*diagm(#w)*trans(#v)
            - else
                - A is approximated by #u*diagm(#w)*trans(#v)
                  (i.e. In this case A can't be represented with a rank-k matrix, so the
                  matrix you get by trying to reconstruct A from the output of the SVD is
                  not exactly the same.)
            - trans(#u)*#u == identity matrix
            - trans(#v)*#v == identity matrix
            - #w == the top k singular values of the matrix A (in no particular order).
            - #u.nr() == m
            - #u.nc() == k
            - #w.nr() == k
            - #w.nc() == 1
            - #v.nr() == n
            - #v.nc() == k
            - This function implements the randomized subspace iteration defined in the
              algorithm 4.4 and 5.1 boxes of the paper:
                Finding Structure with Randomness: Probabilistic Algorithms for
                Constructing Approximate Matrix Decompositions by Halko et al.
              Therefore, it is very fast and suitable for use with very large matrices.
              Moreover, q is the number of subspace iterations performed.  Larger
              values of q might increase the accuracy of the solution but the default
              value should be good for many problems.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        long NR,
        long NC,
        typename MM,
        typename L
        >
    void orthogonalize (
        matrix<T,NR,NC,MM,L>& m
    );
    /*!
        requires
            - m.nr() >= m.nc()
            - m.size() > 0
        ensures
            - #m == an orthogonal matrix with the same dimensions as m.  In particular,
              the columns of #m have the same span as the columns of m.
            - trans(#m)*#m == identity matrix
            - This function is just shorthand for computing the QR decomposition of m
              and then storing the Q factor into #m.
    !*/

// ----------------------------------------------------------------------------------------

    const matrix real_eigenvalues (
        const matrix_exp& m
    );
    /*!
        requires
            - m.nr() == m.nc()
            - matrix_exp::type == float or double
        ensures
            - returns a matrix E such that:
                - E.nr() == m.nr()
                - E.nc() == 1
                - E contains the real part of all eigenvalues of the matrix m.
                  (note that the eigenvalues are not sorted)
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp::type det (
        const matrix_exp& m
    );
    /*!
        requires
            - m is a square matrix
        ensures
            - returns the determinant of m
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp::type trace (
        const matrix_exp& m
    );
    /*!
        requires
            - m is a square matrix
        ensures
            - returns the trace of m
              (i.e. returns sum(diag(m)))
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp::matrix_type chol (
        const matrix_exp& A
    );
    /*!
        requires
            - A is a square matrix
        ensures
            - if (A has a Cholesky Decomposition) then
                - returns the decomposition of A.  That is, returns a matrix L
                  such that L*trans(L) == A.  L will also be lower triangular.
            - else
                - returns a matrix with the same dimensions as A but it
                  will have a bogus value.  I.e. it won't be a decomposition.
                  In this case the algorithm returns a partial decomposition.
                - You can tell when chol fails by looking at the lower right
                  element of the returned matrix.  If it is 0 then it means
                  A does not have a cholesky decomposition.

            - If DLIB_USE_LAPACK is defined then the LAPACK routine xPOTRF
              is used to compute the cholesky decomposition.
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp::matrix_type inv_lower_triangular (
        const matrix_exp& A
    );
    /*!
        requires
            - A is a square matrix
        ensures
            - if (A is lower triangular) then
                - returns the inverse of A.
            - else
                - returns a matrix with the same dimensions as A but it
                  will have a bogus value.  I.e. it won't be an inverse.
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp::matrix_type inv_upper_triangular (
        const matrix_exp& A
    );
    /*!
        requires
            - A is a square matrix
        ensures
            - if (A is upper triangular) then
                - returns the inverse of A.
            - else
                - returns a matrix with the same dimensions as A but it
                  will have a bogus value.  I.e. it won't be an inverse.
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                             Matrix decomposition classes
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename matrix_exp_type
        >
    class lu_decomposition
    {
        /*!
            REQUIREMENTS ON matrix_exp_type
                must be some kind of matrix expression as defined in the
                dlib/matrix/matrix_abstract.h file.   (e.g. a dlib::matrix object)
                The matrix type must also contain float or double values.

            WHAT THIS OBJECT REPRESENTS
                This object represents something that can compute an LU
                decomposition of a real valued matrix.  That is, for any
                matrix A it computes matrices L, U, and a pivot vector P such
                that rowm(A,P) == L*U.

                The LU decomposition with pivoting always exists, even if the matrix is
                singular, so the constructor will never fail.  The primary use of the
                LU decomposition is in the solution of square systems of simultaneous
                linear equations.  This will fail if is_singular() returns true (or
                if A is very nearly singular).

                If DLIB_USE_LAPACK is defined then the LAPACK routine xGETRF
                is used to compute the LU decomposition.
        !*/

    public:

        const static long NR = matrix_exp_type::NR;
        const static long NC = matrix_exp_type::NC;
        typedef typename matrix_exp_type::type type;
        typedef typename matrix_exp_type::mem_manager_type mem_manager_type;
        typedef typename matrix_exp_type::layout_type layout_type;

        typedef matrix<type,0,0,mem_manager_type,layout_type>  matrix_type;
        typedef matrix<type,NR,1,mem_manager_type,layout_type> column_vector_type;
        typedef matrix<long,NR,1,mem_manager_type,layout_type> pivot_column_vector_type;

        template <typename EXP>
        lu_decomposition (
            const matrix_exp<EXP> &A
        );
        /*!
            requires
                - EXP::type == lu_decomposition::type
                - A.size() > 0
            ensures
                - #nr() == A.nr()
                - #nc() == A.nc()
                - #is_square() == (A.nr() == A.nc())
                - computes the LU factorization of the given A matrix.
        !*/

        bool is_square (
        ) const;
        /*!
            ensures
                - if (the input A matrix was a square matrix) then
                    - returns true
                - else
                    - returns false
        !*/

        bool is_singular (
        ) const;
        /*!
            requires
                - is_square() == true
            ensures
                - if (the input A matrix is singular) then
                    - returns true
                - else
                    - returns false
        !*/

        long nr(
        ) const;
        /*!
            ensures
                - returns the number of rows in the input matrix
        !*/

        long nc(
        ) const;
        /*!
            ensures
                - returns the number of columns in the input matrix
        !*/

        const matrix_type get_l (
        ) const;
        /*!
            ensures
                - returns the lower triangular L factor of the LU factorization.
                - L.nr() == nr()
                - L.nc() == min(nr(),nc())
        !*/

        const matrix_type get_u (
        ) const;
        /*!
            ensures
                - returns the upper triangular U factor of the LU factorization.
                - U.nr() == min(nr(),nc())
                - U.nc() == nc()
        !*/

        const pivot_column_vector_type& get_pivot (
        ) const;
        /*!
            ensures
                - returns the pivot permutation vector.  That is,
                  if A is the input matrix then this function
                  returns a vector P such that:
                    - rowm(A,P) == get_l()*get_u()
                    - P.nr() == A.nr()
        !*/

        type det (
        ) const;
        /*!
            requires
                - is_square() == true
            ensures
                - computes and returns the determinant of the input
                  matrix using LU factors.
        !*/

        template <typename EXP>
        const matrix_type solve (
            const matrix_exp<EXP> &B
        ) const;
        /*!
            requires
                - EXP::type == lu_decomposition::type
                - is_square() == true
                - B.nr() == nr()
            ensures
                - Let A denote the input matrix to this class's constructor.
                  Then this function solves A*X == B for X and returns X.
                - Note that if A is singular (or very close to singular) then
                  the X returned by this function won't fit A*X == B very well (if at all).
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_exp_type
        >
    class cholesky_decomposition
    {
        /*!
            REQUIREMENTS ON matrix_exp_type
                must be some kind of matrix expression as defined in the
                dlib/matrix/matrix_abstract.h file.   (e.g. a dlib::matrix object)
                The matrix type must also contain float or double values.

            WHAT THIS OBJECT REPRESENTS
                This object represents something that can compute a cholesky
                decomposition of a real valued matrix.  That is, for any
                symmetric, positive definite matrix A, it computes a lower
                triangular matrix L such that A == L*trans(L).

                If the matrix is not symmetric or positive definite, the function
                computes only a partial decomposition.  This can be tested with
                the is_spd() flag.

                If DLIB_USE_LAPACK is defined then the LAPACK routine xPOTRF
                is used to compute the cholesky decomposition.
        !*/

    public:

        const static long NR = matrix_exp_type::NR;
        const static long NC = matrix_exp_type::NC;
        typedef typename matrix_exp_type::type type;
        typedef typename matrix_exp_type::mem_manager_type mem_manager_type;
        typedef typename matrix_exp_type::layout_type layout_type;

        typedef typename matrix_exp_type::matrix_type matrix_type;
        typedef matrix<type,NR,1,mem_manager_type,layout_type> column_vector_type;

        template <typename EXP>
        cholesky_decomposition(
            const matrix_exp<EXP>& A
        );
        /*!
            requires
                - EXP::type == cholesky_decomposition::type
                - A.size() > 0
                - A.nr() == A.nc()
                  (i.e. A must be a square matrix)
            ensures
                - if (A is symmetric positive-definite) then
                    - #is_spd() == true
                    - Constructs a lower triangular matrix L, such that L*trans(L) == A.
                      and #get_l() == L
                - else
                    - #is_spd() == false
        !*/

        bool is_spd(
        ) const;
        /*!
            ensures
                - if (the input matrix was symmetric positive-definite) then
                    - returns true
                - else
                    - returns false
        !*/

        const matrix_type& get_l(
        ) const;
        /*!
            ensures
                - returns the lower triangular factor, L, such that L*trans(L) == A
                  (where A is the input matrix to this class's constructor)
                - Note that if A is not symmetric positive definite or positive semi-definite
                  then the equation L*trans(L) == A won't hold.
        !*/

        template <typename EXP>
        const matrix solve (
            const matrix_exp<EXP>& B
        ) const;
        /*!
            requires
                - EXP::type == cholesky_decomposition::type
                - B.nr() == get_l().nr()
                  (i.e. the number of rows in B must match the number of rows in the
                  input matrix A)
            ensures
                - Let A denote the input matrix to this class's constructor.  Then
                  this function solves A*X = B for X and returns X.
                - Note that if is_spd() == false or A was really close to being
                  non-SPD then the solver will fail to find an accurate solution.
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_exp_type
        >
    class qr_decomposition
    {
        /*!
            REQUIREMENTS ON matrix_exp_type
                must be some kind of matrix expression as defined in the
                dlib/matrix/matrix_abstract.h file.   (e.g. a dlib::matrix object)
                The matrix type must also contain float or double values.

            WHAT THIS OBJECT REPRESENTS
                This object represents something that can compute a classical
                QR decomposition of an m-by-n real valued matrix A with m >= n.

                The QR decomposition is an m-by-n orthogonal matrix Q and an
                n-by-n upper triangular matrix R so that A == Q*R. The QR decomposition
                always exists, even if the matrix does not have full rank, so the
                constructor will never fail.  The primary use of the QR decomposition
                is in the least squares solution of non-square systems of simultaneous
                linear equations.  This will fail if is_full_rank() returns false or
                A is very nearly not full rank.

                The Q and R factors can be retrieved via the get_q() and get_r()
                methods. Furthermore, a solve() method is provided to find the
                least squares solution of Ax=b using the QR factors.

                If DLIB_USE_LAPACK is #defined then the xGEQRF routine
                from LAPACK is used to compute the QR decomposition.
        !*/

    public:

        const static long NR = matrix_exp_type::NR;
        const static long NC = matrix_exp_type::NC;
        typedef typename matrix_exp_type::type type;
        typedef typename matrix_exp_type::mem_manager_type mem_manager_type;
        typedef typename matrix_exp_type::layout_type layout_type;

        typedef matrix<type,0,0,mem_manager_type,layout_type> matrix_type;

        template <typename EXP>
        qr_decomposition(
            const matrix_exp<EXP>& A
        );
        /*!
            requires
                - EXP::type == qr_decomposition::type
                - A.nr() >= A.nc()
                - A.size() > 0
            ensures
                - #nr() == A.nr()
                - #nc() == A.nc()
                - computes the QR decomposition of the given A matrix.
        !*/

        bool is_full_rank(
        ) const;
        /*!
            ensures
                - if (the input A matrix had full rank) then
                    - returns true
                - else
                    - returns false
        !*/

        long nr(
        ) const;
        /*!
            ensures
                - returns the number of rows in the input matrix
        !*/

        long nc(
        ) const;
        /*!
            ensures
                - returns the number of columns in the input matrix
        !*/

        const matrix_type get_r (
        ) const;
        /*!
            ensures
                - returns a matrix R such that:
                    - R is the upper triangular factor, R, of the QR factorization
                    - get_q()*R == input matrix A
                    - R.nr() == nc()
                    - R.nc() == nc()
        !*/

        const matrix_type get_q (
        ) const;
        /*!
            ensures
                - returns a matrix Q such that:
                    - Q is the economy-sized orthogonal factor Q from the QR
                      factorization.
                    - trans(Q)*Q == identity matrix
                    - Q*get_r() == input matrix A
                    - Q.nr() == nr()
                    - Q.nc() == nc()
        !*/

        void get_q (
            matrix_type& Q
        ) const;
        /*!
            ensures
                - #Q == get_q()
                - This function exists to allow a user to get the Q matrix without the
                  overhead of returning a matrix by value.
        !*/

        template <typename EXP>
        const matrix_type solve (
            const matrix_exp<EXP>& B
        ) const;
        /*!
            requires
                - EXP::type == qr_decomposition::type
                - B.nr() == nr()
            ensures
                - Let A denote the input matrix to this class's constructor.
                  Then this function finds the least squares solution to the equation A*X = B
                  and returns X.  X has the following properties:
                    - X is the matrix that minimizes the two norm of A*X-B.  That is, it
                      minimizes sum(squared(A*X - B)).
                    - X.nr() == nc()
                    - X.nc() == B.nc()
                - Note that this function will fail to output a good solution if is_full_rank() == false
                  or the A matrix is close to not being full rank.
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_exp_type
        >
    class eigenvalue_decomposition
    {
        /*!
            REQUIREMENTS ON matrix_exp_type
                must be some kind of matrix expression as defined in the
                dlib/matrix/matrix_abstract.h file.   (e.g. a dlib::matrix object)
                The matrix type must also contain float or double values.

            WHAT THIS OBJECT REPRESENTS
                This object represents something that can compute an eigenvalue
                decomposition of a real valued matrix.   So it gives
                you the set of eigenvalues and eigenvectors for a matrix.

                Let A denote the input matrix to this object's constructor.  Then
                what this object does is it finds two matrices, D and V, such that
                    - A*V == V*D
                Where V is a square matrix that contains all the eigenvectors
                of the A matrix (each column of V is an eigenvector) and
                D is a diagonal matrix containing the eigenvalues of A.

                It is important to note that if A is symmetric or non-symmetric you
                get somewhat different results.  If A is a symmetric matrix (i.e. A == trans(A))
                then:
                    - All the eigenvalues and eigenvectors of A are real numbers.
                        - Because of this there isn't really any point in using the
                          part of this class's interface that returns complex matrices.
                          All you need are the get_real_eigenvalues() and
                          get_pseudo_v() functions.
                    - V*trans(V) should be equal to the identity matrix.  That is, all the
                      eigenvectors in V should be orthonormal.
                        - So A == V*D*trans(V)
                    - If DLIB_USE_LAPACK is #defined then this object uses the xSYEVR LAPACK
                      routine.

                On the other hand, if A is not symmetric then:
                    - Some of the eigenvalues and eigenvectors might be complex numbers.
                        - An eigenvalue is complex if and only if its corresponding eigenvector
                          is complex.  So you can check for this case by just checking
                          get_imag_eigenvalues() to see if any values are non-zero.  You don't
                          have to check the V matrix as well.
                    - V*trans(V) won't be equal to the identity matrix but it is usually
                      invertible.  So A == V*D*inv(V) is usually a valid statement but
                      A == V*D*trans(V) won't be.
                    - If DLIB_USE_LAPACK is #defined then this object uses the xGEEV LAPACK
                      routine.
        !*/

    public:

        const static long NR = matrix_exp_type::NR;
        const static long NC = matrix_exp_type::NC;
        typedef typename matrix_exp_type::type type;
        typedef typename matrix_exp_type::mem_manager_type mem_manager_type;
        typedef typename matrix_exp_type::layout_type layout_type;

        typedef typename matrix_exp_type::matrix_type matrix_type;
        typedef matrix<type,NR,1,mem_manager_type,layout_type> column_vector_type;

        typedef matrix<std::complex<type>,0,0,mem_manager_type,layout_type> complex_matrix_type;
        typedef matrix<std::complex<type>,NR,1,mem_manager_type,layout_type> complex_column_vector_type;

        template <typename EXP>
        eigenvalue_decomposition(
            const matrix_exp<EXP>& A
        );
        /*!
            requires
                - A.nr() == A.nc()
                - A.size() > 0
                - EXP::type == eigenvalue_decomposition::type
            ensures
                - #dim() == A.nr()
                - computes the eigenvalue decomposition of A.
                - #get_eigenvalues() == the eigenvalues of A
                - #get_v() == all the eigenvectors of A
        !*/

        template <typename EXP>
        eigenvalue_decomposition(
            const matrix_op<op_make_symmetric<EXP> >& A
        );
        /*!
            requires
                - A.nr() == A.nc()
                - A.size() > 0
                - EXP::type == eigenvalue_decomposition::type
            ensures
                - #dim() == A.nr()
                - computes the eigenvalue decomposition of the symmetric matrix A.  Does so
                  using a method optimized for symmetric matrices.
                - #get_eigenvalues() == the eigenvalues of A
                - #get_v() == all the eigenvectors of A
                - moreover, since A is symmetric there won't be any imaginary eigenvalues. So
                  we will have:
                    - #get_imag_eigenvalues() == 0
                    - #get_real_eigenvalues() == the eigenvalues of A
                    - #get_pseudo_v() == all the eigenvectors of A
                    - diagm(#get_real_eigenvalues()) == #get_pseudo_d()

                Note that the symmetric matrix operator is created by the
                dlib::make_symmetric() function.  This function simply reflects
                the lower triangular part of a square matrix into the upper triangular
                part to create a symmetric matrix.  It can also be used to denote that a
                matrix is already symmetric using the C++ type system.
        !*/

        long dim (
        ) const;
        /*!
            ensures
                - dim() == the number of rows/columns in the input matrix A
        !*/

        const complex_column_vector_type get_eigenvalues (
        ) const;
        /*!
            ensures
                - returns diag(get_d()).  That is, returns a
                  vector that contains the eigenvalues of the input
                  matrix.
                - the returned vector has dim() rows
                - the eigenvalues are not sorted in any particular way
        !*/

        const column_vector_type& get_real_eigenvalues (
        ) const;
        /*!
            ensures
                - returns the real parts of the eigenvalues.  That is,
                  returns real(get_eigenvalues())
                - the returned vector has dim() rows
                - the eigenvalues are not sorted in any particular way
        !*/

        const column_vector_type& get_imag_eigenvalues (
        ) const;
        /*!
            ensures
                - returns the imaginary parts of the eigenvalues.  That is,
                  returns imag(get_eigenvalues())
                - the returned vector has dim() rows
                - the eigenvalues are not sorted in any particular way
        !*/

        const complex_matrix_type get_v (
        ) const;
        /*!
            ensures
                - returns the eigenvector matrix V that is
                  dim() rows by dim() columns
                - Each column in V is one of the eigenvectors of the input
                  matrix
        !*/

        const complex_matrix_type get_d (
        ) const;
        /*!
            ensures
                - returns a matrix D such that:
                    - D.nr() == dim()
                    - D.nc() == dim()
                    - diag(D) == get_eigenvalues()
                      (i.e. the diagonal of D contains all the eigenvalues in the input matrix)
                    - all off diagonal elements of D are set to 0
        !*/

        const matrix_type& get_pseudo_v (
        ) const;
        /*!
            ensures
                - returns a matrix that is dim() rows by dim() columns
                - Let A denote the input matrix given to this object's constructor.
                - if (A has any imaginary eigenvalues) then
                    - returns the pseudo-eigenvector matrix V
                    - The matrix V returned by this function is structured such that:
                        - A*V == V*get_pseudo_d()
                - else
                    - returns the eigenvector matrix V with A's eigenvectors as
                      the columns of V
                    - A*V == V*diagm(get_real_eigenvalues())
        !*/

        const matrix_type get_pseudo_d (
        ) const;
        /*!
            ensures
                - The returned matrix is dim() rows by dim() columns
                - Computes and returns the block diagonal eigenvalue matrix.
                  If the original matrix A is not symmetric, then the eigenvalue
                  matrix D is block diagonal with the real eigenvalues in 1-by-1
                  blocks and any complex eigenvalues,
                  a + i*b, in 2-by-2 blocks, (a, b; -b, a).  That is, if the complex
                  eigenvalues look like

                      u + iv     .        .          .      .    .
                        .      u - iv     .          .      .    .
                        .        .      a + ib       .      .    .
                        .        .        .        a - ib   .    .
                        .        .        .          .      x    .
                        .        .        .          .      .    y

                  Then D looks like

                        u        v        .          .      .    .
                       -v        u        .          .      .    .
                        .        .        a          b      .    .
                        .        .       -b          a      .    .
                        .        .        .          .      x    .
                        .        .        .          .      .    y

                  This keeps V (The V you get from get_pseudo_v()) a real matrix in both
                  symmetric and non-symmetric cases, and A*V = V*D.
                - the eigenvalues are not sorted in any particular way
        !*/

    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MATRIx_LA_FUNCTS_ABSTRACT_


dlib C++ Library - matrix_abstract.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_MATRIx_ABSTRACT_
#ifdef DLIB_MATRIx_ABSTRACT_

#include "matrix_exp_abstract.h"
#include "../serialize.h"
#include "../algs.h"
#include "matrix_data_layout_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    /*
        Note that these operator prototypes are not correct C++ (the real versions, which
        you can see in the implementation are really complex and so probably would
        distract/confuse people if shown here).  Think of this as just a list of the
        operators available to you and what they do.
    */

    const matrix_exp operator* (
        const matrix_exp& m1,
        const matrix_exp& m2
    );
    /*!
        requires
            - m1.nc() == m2.nr()
            - m1.size() > 0 && m2.size() > 0
              (you can't multiply any sort of empty matrices together)
            - m1 and m2 both contain elements of the same type
        ensures
            - returns the result of doing the matrix multiplication m1*m2.  The resulting
              matrix will have m1.nr() rows and m2.nc() columns.
    !*/

    const matrix_exp operator+ (
        const matrix_exp& m1,
        const matrix_exp& m2
    );
    /*!
        requires
            - m1.nr() == m2.nr()
            - m1.nc() == m2.nc()
            - m1 and m2 both contain elements of the same type
        ensures
            - returns a matrix R such that for all valid r and c:
              R(r,c) == m1(r,c) + m2(r,c)
              (i.e. returns the result of doing a pairwise addition of the matrices m1 and m2.)
              The resulting matrix will have the same dimensions as the originals.
    !*/

    const matrix_exp operator- (
        const matrix_exp& m1,
        const matrix_exp& m2
    );
    /*!
        requires
            - m1.nr() == m2.nr()
            - m1.nc() == m2.nc()
            - m1 and m2 both contain elements of the same type
        ensures
            - returns a matrix R such that for all valid r and c:
              R(r,c) == m1(r,c) - m2(r,c)
              (i.e. returns the result of doing a pairwise subtraction of the matrices m1 and m2.)
              The resulting matrix will have the same dimensions as the originals.
    !*/

    template <typename T>
    const matrix_exp operator* (
        const matrix_exp& m,
        const T& value
    );
    /*!
        ensures
            - returns the result of multiplying all the elements of matrix m by the given
              scalar value.  The resulting matrix will have the same dimensions as m.
    !*/

    template <typename T>
    const matrix_exp operator* (
        const T& value,
        const matrix_exp& m
    );
    /*!
        ensures
            - returns the result of multiplying all the elements of matrix m by the given
              scalar value.  The resulting matrix will have the same dimensions as m.
    !*/

    const matrix_exp operator- (
        const matrix_exp& m
    );
    /*!
        ensures
            - returns -1*m
    !*/

    template <typename T>
    const matrix_exp operator/ (
        const matrix_exp& m,
        const T& value
    );
    /*!
        ensures
            - returns the result of dividing all the elements of matrix m by the given
              scalar value.  The resulting matrix will have the same dimensions as m.
    !*/

    template <typename T>
    const matrix_exp operator/ (
        const T& value,
        const matrix_exp& m
    );
    /*!
        ensures
            - returns the result of dividing the given scalar value by all the elements
              of matrix m.  The resulting matrix will have the same dimensions as m.
    !*/

    template <typename T>
    const matrix_exp operator+ (
        const matrix_exp& m,
        const T& value
    );
    /*!
        ensures
            - returns the result of adding value to all the elements of matrix m.
              The resulting matrix will have the same dimensions as m.
    !*/

    template <typename T>
    const matrix_exp operator+ (
        const T& value,
        const matrix_exp& m
    );
    /*!
        ensures
            - returns the result of adding value to all the elements of matrix m.
              The resulting matrix will have the same dimensions as m.
    !*/

    template <typename T>
    const matrix_exp operator- (
        const matrix_exp& m,
        const T& value
    );
    /*!
        ensures
            - returns the result of subtracting value from all the elements of matrix m.
              The resulting matrix will have the same dimensions as m.
    !*/

    template <typename T>
    const matrix_exp operator- (
        const T& value,
        const matrix_exp& m
    );
    /*!
        ensures
            - Returns a matrix M such that:
                - M has the same dimensions as m
                - M contains the same type of element as m
                - for all valid r and c:
                    - M(r,c) == value - m(r,c)
    !*/

    bool operator== (
        const matrix_exp& m1,
        const matrix_exp& m2
    );
    /*!
        ensures
            - if (m1.nr() == m2.nr() && m1.nc() == m2.nc() &&
              for all valid r and c:  m1(r,c) == m2(r,c) ) then
                - returns true
            - else
                - returns false
    !*/

    bool operator!= (
        const matrix_exp& m1,
        const matrix_exp& m2
    );
    /*!
        ensures
            - returns !(m1 == m2)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        long num_rows = 0,
        long num_cols = 0,
        typename mem_manager = default_memory_manager,
        typename layout = row_major_layout
        >
    class matrix : public matrix_exp<matrix<T,num_rows,num_cols,mem_manager,layout> >
    {
        /*!
            REQUIREMENTS ON num_rows and num_cols
                both must be bigger than or equal to 0

            REQUIREMENTS ON mem_manager
                must be an implementation of memory_manager/memory_manager_kernel_abstract.h or
                must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or
                must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h
                mem_manager::type can be set to anything.

            REQUIREMENTS ON layout
                Must be either row_major_layout or column_major_layout

            INITIAL VALUE
                - if (num_rows > 0) then
                    - nr() == num_rows
                - else
                    - nr() == 0

                - if (num_cols > 0) then
                    - nc() == num_cols
                - else
                    - nc() == 0

            WHAT THIS OBJECT REPRESENTS
                This object represents a matrix of nr() rows and nc() columns.  This object
                is also a matrix_exp.  Thus it can be used in all of the above
                global operators.

                The number of rows and columns of this object are determined by the template
                arguments num_rows and num_cols.  If num_rows or num_cols are 0 then
                the matrix starts out empty (i.e. nr() == 0 and nc() == 0) and you may change
                its size via the set_size() member function.

                Setting num_rows or num_cols to something other than 0 causes that dimension
                to have a fixed size.  Setting a fixed size at compile time is useful because
                any errors related to operating on matrices with incompatible dimensions will
                be detected at compile time.  It also allows the compiler to perform loop
                unrolling which can result in substantially faster code.

                Also note that the elements of this matrix are laid out in memory by the layout
                object supplied as a template argument to this class.  The row_major_layout
                sets elements down contiguously in memory and in row major order.  Additionally,
                all memory allocations are performed using the memory manager object supplied as
                a template argument to this class.
        !*/

    public:
        typedef T type;
        typedef mem_manager mem_manager_type;
        typedef layout layout_type;
        const static long NR = num_rows;
        const static long NC = num_cols;
        const static long cost = 1;
        typedef T*          iterator;
        typedef const T*    const_iterator;

        matrix (
        );
        /*!
            ensures
                - #*this is properly initialized
                - #aliases(*this) == true
                - #ref().aliases(*this) == true
        !*/

        explicit matrix (
            long length
        );
        /*!
            requires
                - NR == 1 || NC == 1 (i.e. this must be a column or row vector)
                - length >= 0
                - if (NR == 1 && NC > 0) then
                    - length == NC
                - if (NC == 1 && NR > 0) then
                    - length == NR
            ensures
                - #*this is properly initialized
                - #aliases(*this) == true
                - #ref().aliases(*this) == true
                - if (NR == 1) then
                    - #nr() == 1
                    - #nc() == length
                - else
                    - #nr() == length
                    - #nc() == 1
        !*/

        matrix (
            long rows,
            long cols
        );
        /*!
            requires
                - rows == NR || NR == 0
                - cols == NC || NC == 0
                - rows >= 0 && cols >= 0
            ensures
                - #*this is properly initialized
                - #aliases(*this) == true
                - #ref().aliases(*this) == true
                - #nr() == rows
                - #nc() == cols
        !*/

        template <typename EXP>
        matrix (
            const matrix_exp<EXP>& m
        );
        /*!
            requires
                - matrix_exp<EXP>::type == T
                  (i.e. m contains the same type as *this does)
                - if (NR != 0) then NR == m.nr()
                - if (NC != 0) then NC == m.nc()
            ensures
                - #*this == m
                - #aliases(*this) == true
                - #ref().aliases(*this) == true
        !*/

        template <typename U, size_t len>
        explicit matrix (
            U (&array)[len]
        );
        /*!
            requires
                - NR != 0 && NC != 0 (i.e. you can only use this constructor on statically sized matrices)
                - len == nr()*nc()  (i.e. the array you give here must be the right size)
            ensures
                - for all valid r and c:
                  #(*this)(r,c) == array[r*nc() + c]
                  (i.e. initializes this matrix with the contents of the given array)
                - #aliases(*this) == true
                - #ref().aliases(*this) == true
        !*/

        T& operator() (
            long r,
            long c
        );
        /*!
            requires
                - 0 <= r < nr()
                - 0 <= c < nc()
            ensures
                - returns a reference to the value at the given row and column in
                  this matrix.
        !*/

        const T& operator() (
            long r,
            long c
        ) const;
        /*!
            requires
                - 0 <= r < nr()
                - 0 <= c < nc()
            ensures
                - returns a const reference to the value at the given row and column in
                  this matrix.
        !*/

        T& operator() (
            long i
        );
        /*!
            requires
                - nc() == 1 || nr() == 1 (i.e. this must be a column or row vector)
                - 0 <= i < size()
            ensures
                - if (nc() == 1) then
                    - returns a reference to (*this)(i,0)
                - else
                    - returns a reference to (*this)(0,i)
        !*/

        const T& operator() (
            long i
        ) const;
        /*!
            requires
                - nc() == 1 || nr() == 1 (i.e. this must be a column or row vector)
                - 0 <= i < size()
            ensures
                - if (nc() == 1) then
                    - returns a reference to (*this)(i,0)
                - else
                    - returns a reference to (*this)(0,i)
        !*/

        operator const type (
        ) const;
        /*!
            requires
                - nr() == 1
                - nc() == 1
            ensures
                - returns (*this)(0,0)
        !*/

        long nr(
        ) const;
        /*!
            ensures
                - returns the number of rows in this matrix
        !*/

        long nc(
        ) const;
        /*!
            ensures
                - returns the number of columns in this matrix
        !*/

        long size (
        ) const;
        /*!
            ensures
                - returns nr()*nc()
        !*/

        void set_size (
            long rows,
            long cols
        );
        /*!
            requires
                - rows == NR || NR == 0
                - cols == NC || NC == 0
                - rows >= 0 && cols >= 0
            ensures
                - #nr() == rows
                - #nc() == cols
        !*/

        void set_size (
            long length
        );
        /*!
            requires
                - NR == 1 || NC == 1 (i.e. this must be a column or row vector)
                - length >= 0
                - if (NR == 1 && NC > 0) then
                    - length == NC
                - if (NC == 1 && NR > 0) then
                    - length == NR
            ensures
                - if (NR == 1) then
                    - #nr() == 1
                    - #nc() == length
                - else
                    - #nr() == length
                    - #nc() == 1
        !*/

        template <typename U, size_t len>
        matrix& operator= (
            U (&array)[len]
        );
        /*!
            requires
                - len == nr()*nc()  (i.e. the array you give here must be the right size)
            ensures
                - for all valid r and c:
                  #(*this)(r,c) == array[r*nc() + c]
                  (i.e. loads this matrix with the contents of the given array)
                - returns *this
        !*/

        template <typename EXP>
        matrix& operator= (
            const matrix_exp<EXP>& m
        );
        /*!
            requires
                - matrix_exp<EXP>::type == T
                  (i.e. m contains the same type as *this does)
                - if (NR != 0) then NR == m.nr()
                - if (NC != 0) then NC == m.nc()
            ensures
                - copies the given matrix expression m to *this
                - returns *this
        !*/

        template <typename EXP>
        matrix& operator += (
            const matrix_exp<EXP>& m
        );
        /*!
            requires
                - matrix_exp<EXP>::type == T
            ensures
                - if (nr() == m.nr() && nc() == m.nc()) then
                    - #(*this) == *this + m
                - else
                    - #(*this) == m
                      (i.e. if the dimensions don't match then this function performs a
                      normal assignment)
                - returns *this
        !*/

        template <typename EXP>
        matrix& operator -= (
            const matrix_exp<EXP>& m
        );
        /*!
            requires
                - matrix_exp<EXP>::type == T
            ensures
                - if (nr() == m.nr() && nc() == m.nc()) then
                    - #(*this) == *this - m
                - else
                    - #(*this) == -m
                - returns *this
        !*/

        template <typename EXP>
        matrix& operator *= (
            const matrix_exp<EXP>& m
        );
        /*!
            requires
                - matrix_exp<EXP>::type == T
                  (i.e. m must contain the same type of element as *this)
                - nc() == m.nr()
                - size() > 0 && m.size() > 0
                  (you can't multiply any sort of empty matrices together)
            ensures
                - #(*this) == *this * m
                - returns *this
        !*/

        matrix& operator *= (
            const T& a
        );
        /*!
            ensures
                - #(*this) == *this * a
                - returns *this
        !*/

        matrix& operator /= (
            const T& a
        );
        /*!
            ensures
                - #(*this) == *this / a
                - returns *this
        !*/

        matrix& operator += (
            const T& a
        );
        /*!
            ensures
                - #(*this) == *this + a
                - returns *this
        !*/

        matrix& operator -= (
            const T& a
        );
        /*!
            ensures
                - #(*this) == *this - a
                - returns *this
        !*/

        const literal_assign_helper operator = (
            const T& val
        );
        /*!
            This function is somewhat different than all the others defined in this file.
            The purpose of this function is to enable you to easily initialize a matrix object.
            For example:
                matrix<double> m(2,3);
                m = 1,2,3,
                    4,5,6;

            The above code creates a matrix m with 2 rows and 3 columns and sets it so that
            it contains the matrix | 1 2 3 |
                                   | 4 5 6 |

            You can also use this function to assign to all elements of a matrix.  So
            saying m = 3; would assign all elements of m equal to 3.

            Note that to use this method of assignment it is required that you supply
            exactly m.size() or 1 values so that the matrix is fully initialized.  Supplying
            fewer or more than that is an error that will cause a dlib::fatal_error to be
            thrown.

            Note also that using an expression of the form m = scalar; when m.size() == 0
            is legal but has no effect on m.
        !*/

        void swap (
            matrix& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/

        iterator begin(
        );
        /*!
            ensures
                - returns a random access iterator pointing to the first element in this
                  matrix.
                - The iterator will iterate over the elements of the matrix in row major
                  order if layout is row_major_layout or in column major order if layout is
                  column_major_layout.
        !*/

        iterator end(
        );
        /*!
            ensures
                - returns a random access iterator pointing to one past the end of the last
                  element in this matrix.
        !*/

        const_iterator begin(
        ) const;
        /*!
            ensures
                - returns a random access iterator pointing to the first element in this
                  matrix.
                - The iterator will iterate over the elements of the matrix in row major
                  order if layout is row_major_layout or in column major order if layout is
                  column_major_layout.
        !*/

        const_iterator end(
        ) const;
        /*!
            ensures
                - returns a random access iterator pointing to one past the end of the last
                  element in this matrix.
        !*/
    };

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        long NR,
        long NC,
        typename mm,
        typename l
        >
    void swap(
        matrix<T,NR,NC,mm,l>& a,
        matrix<T,NR,NC,mm,l>& b
    ) { a.swap(b); }
    /*!
        Provides a global swap function
    !*/

    template <
        typename T,
        long NR,
        long NC,
        typename mm,
        typename l
        >
    void serialize (
        const matrix<T,NR,NC,mm,l>& item,
        std::ostream& out
    );
    /*!
        Provides serialization support.  Note that the serialization formats used by the
        dlib::matrix and dlib::array2d objects are compatible.  That means you can load the
        serialized data from one into another and it will work properly.
    !*/

    template <
        typename T,
        long NR,
        long NC,
        typename mm,
        typename l
        >
    void deserialize (
        matrix<T,NR,NC,mm,l>& item,
        std::istream& in
    );
    /*!
        Provides deserialization support
    !*/

    template <
        typename EXP
        >
    std::ostream& operator<< (
        std::ostream& out,
        const matrix_exp<EXP>& m
    );
    /*!
        ensures
            - writes m to the given out stream in a form suitable for human consumption.
            - returns out
    !*/

    template <
        typename T,
        long NR,
        long NC,
        typename MM,
        typename L
        >
    std::istream& operator>> (
        std::istream& in,
        matrix<T,NR,NC,MM,L>& m
    );
    /*!
        ensures
            - Tries to read a matrix from the given input stream and store it into #m.
            - The format expected is the text format output by the above operator<<().
              That is, the format should be a grid of text such as:
                2 3 4
                5 2 6
            - The separation between numbers can be any number of whitespace characters or
              commas.
            - The matrix data is assumed to end upon the first blank line or end-of-file,
              whichever comes first.  This means you can create an input stream with
              multiple matrices in it by separating them with empty lines.
            - returns in.
            - If there was a formatting error or something which prevents the input data
              from being parsed into a matrix then #in.fail() == true.
    !*/

    /*!A csv
        This object is used to define an io manipulator for matrix expressions.  In
        particular, you can write statements like:
            cout << csv << yourmatrix;
        and have it print the matrix with commas separating each element.
    !*/
    some_undefined_iomnaip_type csv;

// ----------------------------------------------------------------------------------------

    template <typename EXP>
    class const_temp_matrix : public matrix_exp<const_temp_matrix<EXP> >, noncopyable
    {
        /*!
            REQUIREMENTS ON EXP
                - must be an object that inherits publicly from matrix_exp.

            WHAT THIS OBJECT REPRESENTS
                This object represents a copy of a matrix expression.  The twist
                is that it only actually makes a copy of its input matrix expression
                if that matrix expression is costly to evaluate.  If it has
                low cost then this object just stores a reference.

                This class is useful in cases where you write a function that
                takes a matrix_exp object as input and you want to do some
                intensive computation that looks at each element of that matrix_exp
                many times.  If the input matrix_exp has a high cost then you want
                to store it into a temporary matrix.  But if it has low cost then
                it is faster if you just use a reference to it.  The const_temp_matrix
                makes doing this easy.
        !*/
    public:

        const_temp_matrix (
            const matrix_exp<EXP>& item
        );
        /*!
            ensures
                - #*this == item
                - if (EXP::cost <= 1) then
                    - this const_temp_matrix stores a reference to the item matrix
                - else
                    - this const_temp_matrix creates a temporary matrix and copies
                      item into it
        !*/

        const_temp_matrix (
            const EXP& item
        );
        /*!
            ensures
                - #*this == item
                - if (EXP::cost <= 1) then
                    - this const_temp_matrix stores a reference to the item matrix
                - else
                    - this const_temp_matrix creates a temporary matrix and copies
                      item into it
        !*/
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MATRIx_ABSTRACT_


dlib C++ Library - matrix_subexp_abstract.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_MATRIx_SUBEXP_ABSTRACT_
#ifdef DLIB_MATRIx_SUBEXP_ABSTRACT_

#include "matrix_abstract.h"
#include "../geometry/rectangle.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <long start, long inc, long end>
    const matrix_exp range (
    );
    /*!
        requires
            - inc > 0
        ensures
            - returns a matrix R such that:
                - R::type == long
                - R.nr() == 1
                - R.nc() == abs(end - start)/inc + 1
                - if (start <= end) then
                    - R(i) == start + i*inc
                - else
                    - R(i) == start - i*inc
    !*/

    template <long start, long end>
    const matrix_exp range (
    ) { return range<start,1,end>(); }

    const matrix_exp range (
        long start,
        long inc,
        long end
    );
    /*!
        requires
            - inc > 0
        ensures
            - returns a matrix R such that:
                - R::type == long
                - R.nr() == 1
                - R.nc() == abs(end - start)/inc + 1
                - if (start <= end) then
                    - R(i) == start + i*inc
                - else
                    - R(i) == start - i*inc
    !*/

    const matrix_exp range (
        long start,
        long end
    ) { return range(start,1,end); }

// ----------------------------------------------------------------------------------------

    const matrix_exp subm (
        const matrix_exp& m,
        const matrix_exp& rows,
        const matrix_exp& cols,
    );
    /*!
        requires
            - rows and cols contain integral elements (e.g. int, long)
            - 0 <= min(rows) && max(rows) < m.nr()
            - 0 <= min(cols) && max(cols) < m.nc()
            - rows.nr() == 1 || rows.nc() == 1
            - cols.nr() == 1 || cols.nc() == 1
              (i.e. rows and cols must be vectors)
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m
                - R.nr() == rows.size()
                - R.nc() == cols.size()
                - for all valid r and c:
                  R(r,c) == m(rows(r),cols(c))
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp subm (
        const matrix_exp& m,
        long row,
        long col,
        long nr,
        long nc
    );
    /*!
        requires
            - row >= 0
            - col >= 0
            - nr >= 0
            - nc >= 0
            - row + nr <= m.nr()
            - col + nc <= m.nc()
        ensures
            - returns a matrix R such that:
                - R.nr() == nr
                - R.nc() == nc
                - for all valid r and c:
                  R(r, c) == m(r+row,c+col)
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp subm (
        const matrix_exp& m,
        const rectangle& rect
    );
    /*!
        requires
            - get_rect(m).contains(rect) == true
              (i.e. rect is a region inside the matrix m)
        ensures
            - returns a matrix R such that:
                - R.nr() == rect.height()
                - R.nc() == rect.width()
                - for all valid r and c:
                  R(r, c) == m(r+rect.top(), c+rect.left())
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp rowm (
        const matrix_exp& m,
        long row
    );
    /*!
        requires
            - 0 <= row < m.nr()
        ensures
            - returns a matrix R such that:
                - R.nr() == 1
                - R.nc() == m.nc()
                - for all valid i:
                  R(i) == m(row,i)
    !*/

    template <typename EXP>
    struct rowm_exp
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This struct allows you to determine the type of matrix expression
                object returned from the rowm(m,row) function.  An example makes its
                use clear:

                template <typename EXP>
                void do_something( const matrix_exp<EXP>& mat)
                {
                    // r is a matrix expression that aliases mat.
                    typename rowm_exp<EXP>::type r = rowm(mat,0);

                    // Print the first row of mat.  So we see that by using
                    // rowm_exp we can save the object returned by rowm() in
                    // a local variable.
                    cout << r << endl;

                    // Note that you can only save the return value of rowm() to
                    // a local variable if the argument to rowm() has a lifetime
                    // beyond the rowm() expression.  The example shown above is
                    // OK but the following would result in undefined behavior:
                    typename rowm_exp<EXP>::type bad = rowm(mat + mat,0);
                }
        !*/
        typedef type_of_expression_returned_by_rowm type;
    };

// ----------------------------------------------------------------------------------------

    const matrix_exp rowm (
        const matrix_exp& m,
        long row,
        long length
    );
    /*!
        requires
            - 0 <= row < m.nr()
            - 0 <= length <= m.nc()
        ensures
            - returns a matrix R such that:
                - R.nr() == 1
                - R.nc() == length
                - for all valid i:
                  R(i) == m(row,i)
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp rowm (
        const matrix_exp& m,
        const matrix_exp& rows
    );
    /*!
        requires
            - rows contains integral elements (e.g. int, long)
            - 0 <= min(rows) && max(rows) < m.nr()
            - rows.nr() == 1 || rows.nc() == 1
              (i.e. rows must be a vector)
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m
                - R.nr() == rows.size()
                - R.nc() == m.nc()
                - for all valid r and c:
                  R(r,c) == m(rows(r),c)
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp colm (
        const matrix_exp& m,
        long col
    );
    /*!
        requires
            - 0 <= col < m.nc()
        ensures
            - returns a matrix R such that:
                - R.nr() == m.nr()
                - R.nc() == 1
                - for all valid i:
                  R(i) == m(i,col)
    !*/

    template <typename EXP>
    struct colm_exp
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This struct allows you to determine the type of matrix expression
                object returned from the colm(m,col) function.  An example makes its
                use clear:

                template <typename EXP>
                void do_something( const matrix_exp<EXP>& mat)
                {
                    // c is a matrix expression that aliases mat.
                    typename colm_exp<EXP>::type c = colm(mat,0);

                    // Print the first column of mat.  So we see that by using
                    // colm_exp we can save the object returned by colm() in
                    // a local variable.
                    cout << c << endl;

                    // Note that you can only save the return value of colm() to
                    // a local variable if the argument to colm() has a lifetime
                    // beyond the colm() expression.  The example shown above is
                    // OK but the following would result in undefined behavior:
                    typename colm_exp<EXP>::type bad = colm(mat + mat,0);
                }
        !*/
        typedef type_of_expression_returned_by_colm type;
    };

// ----------------------------------------------------------------------------------------

    const matrix_exp colm (
        const matrix_exp& m,
        long col,
        long length
    );
    /*!
        requires
            - 0 <= col < m.nc()
            - 0 <= length <= m.nr()
        ensures
            - returns a matrix R such that:
                - R.nr() == length
                - R.nc() == 1
                - for all valid i:
                  R(i) == m(i,col)
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp colm (
        const matrix_exp& m,
        const matrix_exp& cols
    );
    /*!
        requires
            - cols contains integral elements (e.g. int, long)
            - 0 <= min(cols) && max(cols) < m.nc()
            - cols.nr() == 1 || cols.nc() == 1
              (i.e. cols must be a vector)
        ensures
            - returns a matrix R such that:
                - R::type == the same type that was in m
                - R.nr() == m.nr()
                - R.nc() == cols.size()
                - for all valid r and c:
                  R(r,c) == m(r,cols(c))
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    assignable_matrix_expression set_ptrm (
        T* ptr,
        long nr,
        long nc = 1
    );
    /*!
        requires
            - ptr == a pointer to nr*nc elements of type T
            - nr >= 0
            - nc >= 0
        ensures
            - statements of the following form:
                - set_ptrm(ptr,nr,nc) = some_matrix;
              result in it being the case that:
                - mat(ptr,nr,nc) == some_matrix.

            - statements of the following form:
                - set_ptrm(ptr,nr,nc) = scalar_value;
              result in it being the case that:
                - mat(ptr,nr,nc) == uniform_matrix<matrix::type>(nr,nc,scalar_value).

            - In addition to the normal assignment statements using the = symbol, you may
              also use the usual += and -= versions of the assignment operator.  In these
              cases, they have their usual effect.
    !*/

// ----------------------------------------------------------------------------------------

    assignable_matrix_expression set_subm (
        matrix& m,
        long row,
        long col,
        long nr,
        long nc
    );
    /*!
        requires
            - row >= 0
            - col >= 0
            - nr >= 0
            - nc >= 0
            - row + nr <= m.nr()
            - col + nc <= m.nc()
        ensures
            - statements of the following form:
                - set_subm(m,row,col,nr,nc) = some_matrix;
              result in it being the case that:
                - subm(m,row,col,nr,nc) == some_matrix.

            - statements of the following form:
                - set_subm(m,row,col,nr,nc) = scalar_value;
              result in it being the case that:
                - subm(m,row,col,nr,nc) == uniform_matrix<matrix::type>(nr,nc,scalar_value).

            - In addition to the normal assignment statements using the = symbol, you may
              also use the usual += and -= versions of the assignment operator.  In these
              cases, they have their usual effect.
    !*/

// ----------------------------------------------------------------------------------------

    assignable_matrix_expression set_subm (
        matrix& m,
        const rectangle& rect
    );
    /*!
        requires
            - get_rect(m).contains(rect) == true
              (i.e. rect is a region inside the matrix m)
        ensures
            - statements of the following form:
                - set_subm(m,rect) = some_matrix;
              result in it being the case that:
                - subm(m,rect) == some_matrix.

            - statements of the following form:
                - set_subm(m,rect) = scalar_value;
              result in it being the case that:
                - subm(m,rect) == uniform_matrix<matrix::type>(nr,nc,scalar_value).

            - In addition to the normal assignment statements using the = symbol, you may
              also use the usual += and -= versions of the assignment operator.  In these
              cases, they have their usual effect.
    !*/

// ----------------------------------------------------------------------------------------

    assignable_matrix_expression set_subm (
        matrix& m,
        const matrix_exp& rows,
        const matrix_exp& cols
    );
    /*!
        requires
            - rows and cols contain integral elements (e.g. int, long)
            - 0 <= min(rows) && max(rows) < m.nr()
            - 0 <= min(cols) && max(cols) < m.nc()
            - rows.nr() == 1 || rows.nc() == 1
            - cols.nr() == 1 || cols.nc() == 1
              (i.e. rows and cols must be vectors)
        ensures
            - statements of the following form:
                - set_subm(m,rows,cols) = some_matrix;
              result in it being the case that:
                - subm(m,rows,cols) == some_matrix.

            - statements of the following form:
                - set_subm(m,rows,cols) = scalar_value;
              result in it being the case that:
                - subm(m,rows,cols) == uniform_matrix<matrix::type>(nr,nc,scalar_value).

            - In addition to the normal assignment statements using the = symbol, you may
              also use the usual += and -= versions of the assignment operator.  In these
              cases, they have their usual effect.
    !*/

// ----------------------------------------------------------------------------------------

    assignable_matrix_expression set_rowm (
        matrix& m,
        long row
    );
    /*!
        requires
            - 0 <= row < m.nr()
        ensures
            - statements of the following form:
                - set_rowm(m,row) = some_matrix;
              result in it being the case that:
                - rowm(m,row) == some_matrix.

            - statements of the following form:
                - set_rowm(m,row) = scalar_value;
              result in it being the case that:
                - rowm(m,row) == uniform_matrix<matrix::type>(1,nc,scalar_value).

            - In addition to the normal assignment statements using the = symbol, you may
              also use the usual += and -= versions of the assignment operator.  In these
              cases, they have their usual effect.
    !*/

// ----------------------------------------------------------------------------------------

    assignable_matrix_expression set_rowm (
        matrix& m,
        const matrix_exp& rows
    );
    /*!
        requires
            - rows contains integral elements (e.g. int, long)
            - 0 <= min(rows) && max(rows) < m.nr()
            - rows.nr() == 1 || rows.nc() == 1
              (i.e. rows must be a vector)
        ensures
            - statements of the following form:
                - set_rowm(m,rows) = some_matrix;
              result in it being the case that:
                - rowm(m,rows) == some_matrix.

            - statements of the following form:
                - set_rowm(m,rows) = scalar_value;
              result in it being the case that:
                - rowm(m,rows) == uniform_matrix<matrix::type>(nr,nc,scalar_value).

            - In addition to the normal assignment statements using the = symbol, you may
              also use the usual += and -= versions of the assignment operator.  In these
              cases, they have their usual effect.
    !*/

// ----------------------------------------------------------------------------------------

    assignable_matrix_expression set_colm (
        matrix& m,
        long col
    );
    /*!
        requires
            - 0 <= col < m.nr()
        ensures
            - statements of the following form:
                - set_colm(m,col) = some_matrix;
              result in it being the case that:
                - colm(m,col) == some_matrix.

            - statements of the following form:
                - set_colm(m,col) = scalar_value;
              result in it being the case that:
                - colm(m,col) == uniform_matrix<matrix::type>(nr,1,scalar_value).

            - In addition to the normal assignment statements using the = symbol, you may
              also use the usual += and -= versions of the assignment operator.  In these
              cases, they have their usual effect.
    !*/

// ----------------------------------------------------------------------------------------

    assignable_matrix_expression set_colm (
        matrix& m,
        const matrix_exp& cols
    );
    /*!
        requires
            - cols contains integral elements (e.g. int, long)
            - 0 <= min(cols) && max(cols) < m.nc()
            - cols.nr() == 1 || cols.nc() == 1
              (i.e. cols must be a vector)
        ensures
            - statements of the following form:
                - set_colm(m,cols) = some_matrix;
              result in it being the case that:
                - colm(m,cols) == some_matrix.

            - statements of the following form:
                - set_colm(m,cols) = scalar_value;
              result in it being the case that:
                - colm(m,cols) == uniform_matrix<matrix::type>(nr,nc,scalar_value).

            - In addition to the normal assignment statements using the = symbol, you may
              also use the usual += and -= versions of the assignment operator.  In these
              cases, they have their usual effect.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MATRIx_SUBEXP_ABSTRACT_


dlib C++ Library - matrix_conv_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_MATRIx_CONV_ABSTRACT_Hh_
#ifdef DLIB_MATRIx_CONV_ABSTRACT_Hh_

#include "matrix_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    const matrix_exp conv (
        const matrix_exp& m1,
        const matrix_exp& m2
    );
    /*!
        requires
            - m1 and m2 both contain elements of the same type
        ensures
            - returns a matrix R such that:
                - R is the convolution of m1 with m2.  In particular, this function is
                  equivalent to performing the following in matlab: R = conv2(m1,m2).
                - R::type == the same type that was in m1 and m2.
                - R.nr() == m1.nr()+m2.nr()-1
                - R.nc() == m1.nc()+m2.nc()-1
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp xcorr (
        const matrix_exp& m1,
        const matrix_exp& m2
    );
    /*!
        requires
            - m1 and m2 both contain elements of the same type
        ensures
            - returns a matrix R such that:
                - R is the cross-correlation of m1 with m2.  In particular, this
                  function returns conv(m1,flip(m2)) if the matrices contain real
                  elements and conv(m1,flip(conj(m2))) if they are complex.
                - R::type == the same type that was in m1 and m2.
                - R.nr() == m1.nr()+m2.nr()-1
                - R.nc() == m1.nc()+m2.nc()-1
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp conv_same (
        const matrix_exp& m1,
        const matrix_exp& m2
    );
    /*!
        requires
            - m1 and m2 both contain elements of the same type
        ensures
            - returns a matrix R such that:
                - R is the convolution of m1 with m2.  In particular, this function is
                  equivalent to performing the following in matlab: R = conv2(m1,m2,'same').
                  In particular, this means the result will have the same dimensions as m1 and will
                  contain the central part of the full convolution.  Therefore, conv_same(m1,m2) is
                  equivalent to subm(conv(m1,m2), m2.nr()/2, m2.nc()/2, m1.nr(), m1.nc()).
                - R::type == the same type that was in m1 and m2.
                - R.nr() == m1.nr()
                - R.nc() == m1.nc()
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp xcorr_same (
        const matrix_exp& m1,
        const matrix_exp& m2
    );
    /*!
        requires
            - m1 and m2 both contain elements of the same type
        ensures
            - returns a matrix R such that:
                - R is the cross-correlation of m1 with m2.  In particular, this
                  function returns conv_same(m1,flip(m2)) if the matrices contain real
                  elements and conv_same(m1,flip(conj(m2))) if they are complex.
                - R::type == the same type that was in m1 and m2.
                - R.nr() == m1.nr()
                - R.nc() == m1.nc()
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp conv_valid (
        const matrix_exp& m1,
        const matrix_exp& m2
    );
    /*!
        requires
            - m1 and m2 both contain elements of the same type
        ensures
            - returns a matrix R such that:
                - R is the convolution of m1 with m2.  In particular, this function is
                  equivalent to performing the following in matlab: R = conv2(m1,m2,'valid').
                  In particular, this means only elements of the convolution which don't require
                  zero padding are included in the result.
                - R::type == the same type that was in m1 and m2.
                - if (m1 has larger dimensions than m2) then
                    - R.nr() == m1.nr()-m2.nr()+1
                    - R.nc() == m1.nc()-m2.nc()+1
                - else
                    - R.nr() == 0
                    - R.nc() == 0
    !*/

// ----------------------------------------------------------------------------------------

    const matrix_exp xcorr_valid (
        const matrix_exp& m1,
        const matrix_exp& m2
    );
    /*!
        requires
            - m1 and m2 both contain elements of the same type
        ensures
            - returns a matrix R such that:
                - R is the cross-correlation of m1 with m2.  In particular, this
                  function returns conv_valid(m1,flip(m2)) if the matrices contain real
                  elements and conv_valid(m1,flip(conj(m2))) if they are complex.
                - R::type == the same type that was in m1 and m2.
                - if (m1 has larger dimensions than m2) then
                    - R.nr() == m1.nr()-m2.nr()+1
                    - R.nc() == m1.nc()-m2.nc()+1
                - else
                    - R.nr() == 0
                    - R.nc() == 0
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MATRIx_CONV_ABSTRACT_Hh_


dlib C++ Library - matrix_fft_abstract.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_FFt_ABSTRACT_Hh_
#ifdef DLIB_FFt_ABSTRACT_Hh_

#include "matrix_abstract.h"
#include "../algs.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    bool is_power_of_two (
        const unsigned long& value
    );
    /*!
        ensures
            - returns true if value contains a power of two and false otherwise.  As a
              special case, we also consider 0 to be a power of two.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename EXP>
    typename EXP::matrix_type fft (
        const matrix_exp<EXP>& data
    );
    /*!
        requires
            - data contains elements of type std::complex<>
            - is_power_of_two(data.nr()) == true
            - is_power_of_two(data.nc()) == true
        ensures
            - Computes the 1 or 2 dimensional discrete Fourier transform of the given data
              matrix and returns it.  In particular, we return a matrix D such that:
                - D.nr() == data.nr()
                - D.nc() == data.nc()
                - D(0,0) == the DC term of the Fourier transform.
                - starting with D(0,0), D contains progressively higher frequency components
                  of the input data.
                - ifft(D) == D
    !*/

// ----------------------------------------------------------------------------------------

    template <typename EXP>
    typename EXP::matrix_type ifft (
        const matrix_exp<EXP>& data
    );
    /*!
        requires
            - data contains elements of type std::complex<>
            - is_power_of_two(data.nr()) == true
            - is_power_of_two(data.nc()) == true
        ensures
            - Computes the 1 or 2 dimensional inverse discrete Fourier transform of the
              given data vector and returns it.  In particular, we return a matrix D such
              that:
                - D.nr() == data.nr()
                - D.nc() == data.nc()
                - fft(D) == data
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        long NR,
        long NC,
        typename MM,
        typename L
        >
    void fft_inplace (
        matrix<std::complex<T>,NR,NC,MM,L>& data
    );
    /*!
        requires
            - data contains elements of type std::complex<>
            - is_power_of_two(data.nr()) == true
            - is_power_of_two(data.nc()) == true
        ensures
            - This function is identical to fft() except that it does the FFT in-place.
              That is, after this function executes we will have:
                - #data == fft(data)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        long NR,
        long NC,
        typename MM,
        typename L
        >
    void ifft_inplace (
        matrix<std::complex<T>,NR,NC,MM,L>& data
    );
    /*!
        requires
            - data contains elements of type std::complex<>
            - is_power_of_two(data.nr()) == true
            - is_power_of_two(data.nc()) == true
        ensures
            - This function is identical to ifft() except that it does the inverse FFT
              in-place.  That is, after this function executes we will have:
                - #data == ifft(data)*data.size()
                - Note that the output needs to be divided by data.size() to complete the
                  inverse transformation.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_FFt_ABSTRACT_Hh_


dlib C++ Library - symmetric_matrix_cache_abstract.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#define DLIB_SYMMETRIC_MATRIX_CAcHE_ABSTRACT_Hh_
#ifndef DLIB_SYMMETRIC_MATRIX_CAcHE_ABSTRACT_Hh_

#include "matrix_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename cache_element_type
        >
    const matrix_exp symmetric_matrix_cache (
        const matrix_exp& m,
        long max_size_megabytes
    );
    /*!
        requires
            - m.size() > 0
            - m.nr() == m.nc()
            - max_size_megabytes >= 0
        ensures
            - This function assumes that m is symmetric.  If m is not symmetric then it won't
              crash but you will get incorrect results.
            - This method creates a matrix expression which internally caches the elements
              of m so that they can be accessed quickly.  It is useful if m is some kind of
              complex matrix expression which is both very large and expensive to evaluate.
              An example would be a kernel_matrix() expression with an expensive kernel and
              a large number of samples.  Such an expression would result in a huge matrix,
              potentially too big to store in memory.  The symmetric_matrix_cache() then makes
              it easy to store just the parts of a matrix expression which are accessed most
              often in memory.  The specific details are defined below.
            - returns a matrix M such that
                - M == m
                  (i.e. M represents the same matrix as m)
                - M will cache elements of m and hold them internally so they can be quickly
                  accessed.  In particular, M will attempt to allocate no more than
                  max_size_megabytes megabytes of memory for the purposes of caching
                  elements of m.  When an element of the matrix is accessed it is either
                  retrieved from the cache, or if this is not possible, then an entire
                  column of m is loaded into a part of the cache which hasn't been used
                  recently and the needed element returned.
                - diag(m) is always loaded into the cache and is stored separately from
                  the cached columns.  That means accesses to the diagonal elements of m
                  are always fast.
                - M will store the cached elements of m as cache_element_type objects.
                  Typically, cache_element_type will be float or double.
                - To avoid repeated cache lookups, the following operations are optimized for
                  use with the symmetric_matrix_cache():
                    - diag(M), rowm(M,row_idx), colm(M,col_idx)
                      These methods will perform only one cache lookup operation for an
                      entire row/column/diagonal worth of data.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SYMMETRIC_MATRIX_CAcHE_ABSTRACT_Hh_


dlib C++ Library - border_enumerator_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_BORDER_EnUMERATOR_ABSTRACT_H_
#ifdef DLIB_BORDER_EnUMERATOR_ABSTRACT_H_

#include "rectangle_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class border_enumerator
    {
        /*!
            POINTERS AND REFERENCES TO INTERNAL DATA
                All operations on this object other than calling element() invalidate
                pointers and references to internal data.

            WHAT THIS OBJECT REPRESENTS
                This object is an enumerator over the border points of a rectangle.
        !*/
    public:

        border_enumerator(
        );
        /*!
            ensures
                - #move_next() == false
                  (i.e. this object is "empty" and won't enumerate anything)
                - current_element_valid() == false
                - at_start() == true
                - size() == 0
        !*/

        border_enumerator(
            const rectangle& rect,
            unsigned long border_size
        );
        /*!
            ensures
                - This object will enumerate over the border points which are inside rect
                  but within border_size of the edge.  For example, if border_size == 1
                  then it enumerates over the single point wide strip of points all around
                  the interior edge of rect.
                - current_element_valid() == false
                - at_start() == true
                - size() == rect.area() - shrink_rect(rect,border_size).area()
                  (i.e. the number of points in the border area of rect)
        !*/

        border_enumerator(
            const rectangle& rect,
            const rectangle& non_border_region
        );
        /*!
            ensures
                - This object will enumerate over all points which are in rect but
                  not in non_border_region.
                - current_element_valid() == false
                - at_start() == true
                - size() == rect.area() - rect.intersect(non_border_region).area()
        !*/

        bool at_start (
        ) const;
        /*!
            ensures
                - returns true if *this represents one position before the first point
                  (this would also make the current element invalid) else returns false
        !*/

        void reset (
        );
        /*!
            ensures
                - #current_element_valid() == false
                - #at_start() == true
        !*/

        bool current_element_valid(
        ) const;
        /*!
            ensures
                - returns true if we are currently at a valid element else
                  returns false
        !*/

        bool move_next(
        );
        /*!
            ensures
                - moves to the next element.  i.e. #element() will now
                  return the next border point.
                - the return value will be equal to #current_element_valid()
                - #at_start() == false

                - returns true if there is another element
                - returns false if there are no more elements in the container
        !*/

        unsigned long size (
        ) const;
        /*!
            ensures
                - returns the number of border points
        !*/

        const point& element (
        ) const;
        /*!
            requires
                - current_element_valid() == true
            ensures
                - returns the current border point
        !*/

    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_BORDER_EnUMERATOR_ABSTRACT_H_


dlib C++ Library - point_transforms_abstract.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_POINT_TrANSFORMS_ABSTRACT_Hh_
#ifdef DLIB_POINT_TrANSFORMS_ABSTRACT_Hh_

#include "../matrix/matrix_abstract.h"
#include "vector_abstract.h"
#include <vector>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class point_transform_affine
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is an object that takes 2D points or vectors and
                applies an affine transformation to them.

            THREAD SAFETY
                It is safe for multiple threads to make concurrent accesses to this object
                without synchronization.
        !*/
    public:

        point_transform_affine (
        );
        /*!
            ensures
                - This object will perform the identity transform.  That is, given a point
                  as input it will return the same point as output.
        !*/

        point_transform_affine (
            const matrix<double,2,2>& m,
            const dlib::vector<double,2>& b
        );
        /*!
            ensures
                - #get_m() == m
                - #get_b() == b
                - When (*this)(p) is invoked it will return a point P such that:
                    - P == m*p + b
        !*/

        const dlib::vector<double,2> operator() (
            const dlib::vector<double,2>& p
        ) const;
        /*!
            ensures
                - applies the affine transformation defined by this object's constructor
                  to p and returns the result.
        !*/

        const matrix<double,2,2>& get_m(
        ) const;
        /*!
            ensures
                - returns the transformation matrix used by this object.
        !*/

        const dlib::vector<double,2>& get_b(
        ) const;
        /*!
            ensures
                - returns the offset vector used by this object.
        !*/

    };

    void serialize   (const point_transform_affine& item, std::ostream& out);
    void deserialize (point_transform_affine& item, std::istream& in);
    /*!
        provides serialization support
    !*/

// ----------------------------------------------------------------------------------------

    point_transform_affine operator* (
        const point_transform_affine& lhs,
        const point_transform_affine& rhs
    );
    /*!
        ensures
            - returns a transformation TFORM(x) that is equivalent to lhs(rhs(x)).  That
              is, for all valid x: TFORM(x) == lhs(rhs(x)).
    !*/

    // ----------------------------------------------------------------------------------------

    point_transform_affine inv (
        const point_transform_affine& trans
    );
    /*!
        ensures
            - If trans is an invertible transformation then this function returns a new
              transformation that is the inverse of trans.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    point_transform_affine find_affine_transform (
        const std::vector<dlib::vector<T,2> >& from_points,
        const std::vector<dlib::vector<T,2> >& to_points
    );
    /*!
        requires
            - from_points.size() == to_points.size()
            - from_points.size() >= 3
        ensures
            - returns a point_transform_affine object, T, such that for all valid i:
                length(T(from_points[i]) - to_points[i])
              is minimized as often as possible.  That is, this function finds the affine
              transform that maps points in from_points to points in to_points.  If no
              affine transform exists which performs this mapping exactly then the one
              which minimizes the mean squared error is selected.  Additionally, if many
              equally good transformations exist, then the transformation with the smallest
              squared parameters is selected (i.e. if you wrote the transformation as a
              matrix then we say we select the transform with minimum Frobenius norm among
              all possible solutions).
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    point_transform_affine find_similarity_transform (
        const std::vector<dlib::vector<T,2> >& from_points,
        const std::vector<dlib::vector<T,2> >& to_points
    );
    /*!
        requires
            - from_points.size() == to_points.size()
            - from_points.size() >= 2
        ensures
            - This function is just like find_affine_transform() except it finds the best
              similarity transform instead of a full affine transform.  This means that it
              optimizes over only the space of rotations, scale changes, and translations.
              So for example, if you mapped the 3 vertices of a triangle through a
              similarity transform then the output would still be the same triangle.
              However, the triangle itself may be larger or smaller, rotated, or at a
              different location in the coordinate system.  This is not the case for a
              general affine transform which can stretch points in ways that cause, for
              example, an equilateral triangle to turn into an isosceles triangle.
    !*/

// ----------------------------------------------------------------------------------------

    class point_transform_projective
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is an object that takes 2D points or vectors and
                applies a projective transformation to them.

            THREAD SAFETY
                It is safe for multiple threads to make concurrent accesses to this object
                without synchronization.
        !*/

    public:

        point_transform_projective (
        );
        /*!
            ensures
                - This object will perform the identity transform.  That is, given a point
                  as input it will return the same point as output.
        !*/

        point_transform_projective (
            const matrix<double,3,3>& m
        );
        /*!
            ensures
                - #get_m() == m
        !*/

        point_transform_projective (
            const point_transform_affine& tran
        );
        /*!
            ensures
                - This object will perform exactly the same transformation as the given
                  affine transform.
        !*/

        const dlib::vector<double,2> operator() (
            const dlib::vector<double,2>& p
        ) const;
        /*!
            ensures
                - Applies the projective transformation defined by this object's constructor
                  to p and returns the result.  To define this precisely:
                    - let p_h == the point p in homogeneous coordinates.  That is:
                        - p_h.x() == p.x()
                        - p_h.y() == p.y()
                        - p_h.z() == 1
                    - let x == get_m()*p_h
                    - Then this function returns the value x/x.z()
        !*/

        const matrix<double,3,3>& get_m(
        ) const;
        /*!
            ensures
                - returns the transformation matrix used by this object.
        !*/

    };

    void serialize   (const point_transform_projective& item, std::ostream& out);
    void deserialize (point_transform_projective& item, std::istream& in);
    /*!
        provides serialization support
    !*/

// ----------------------------------------------------------------------------------------

    point_transform_projective operator* (
        const point_transform_projective& lhs,
        const point_transform_projective& rhs
    );
    /*!
        ensures
            - returns a transformation TFORM(x) that is equivalent to lhs(rhs(x)).  That
              is, for all valid x: TFORM(x) == lhs(rhs(x)).
    !*/

// ----------------------------------------------------------------------------------------

    point_transform_projective inv (
        const point_transform_projective& trans
    );
    /*!
        ensures
            - If trans is an invertible transformation then this function returns a new
              transformation that is the inverse of trans.
    !*/

// ----------------------------------------------------------------------------------------

    point_transform_projective find_projective_transform (
        const std::vector<dlib::vector<double,2> >& from_points,
        const std::vector<dlib::vector<double,2> >& to_points
    );
    /*!
        requires
            - from_points.size() == to_points.size()
            - from_points.size() >= 4
        ensures
            - returns a point_transform_projective object, T, such that for all valid i:
                length(T(from_points[i]) - to_points[i])
              is minimized as often as possible.  That is, this function finds the projective
              transform that maps points in from_points to points in to_points.  If no
              projective transform exists which performs this mapping exactly then the one
              which minimizes the mean squared error is selected.
    !*/

// ----------------------------------------------------------------------------------------

    class point_transform
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is an object that takes 2D points or vectors and
                rotates them around the origin by a given angle and then
                translates them.

            THREAD SAFETY
                It is safe for multiple threads to make concurrent accesses to this object
                without synchronization.
        !*/
    public:

        point_transform (
        );
        /*!
            ensures
                - This object will perform the identity transform.  That is, given a point
                  as input it will return the same point as output.
        !*/

        point_transform (
            const double& angle,
            const dlib::vector<double,2>& translate
        )
        /*!
            ensures
                - When (*this)(p) is invoked it will return a point P such that:
                    - P is the point p rotated counter-clockwise around the origin
                      angle radians and then shifted by having translate added to it.
                      (Note that this is counter clockwise with respect to the normal
                      coordinate system with positive y going up and positive x going
                      to the right)
        !*/

        template <typename T>
        const dlib::vector<T,2> operator() (
            const dlib::vector<T,2>& p
        ) const;
        /*!
            ensures
                - rotates p, then translates it and returns the result.  The output
                  of this function is therefore equal to get_m()*p + get_b().
        !*/

        const matrix<double,2,2> get_m(
        ) const;
        /*!
            ensures
                - returns the transformation matrix used by this object.
        !*/

        const dlib::vector<double,2> get_b(
        ) const;
        /*!
            ensures
                - returns the offset vector used by this object.
        !*/

    };

    void serialize   (const point_transform& item, std::ostream& out);
    void deserialize (point_transform& item, std::istream& in);
    /*!
        provides serialization support
    !*/

// ----------------------------------------------------------------------------------------

    class point_rotator
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is an object that takes 2D points or vectors and
                rotates them around the origin by a given angle.

            THREAD SAFETY
                It is safe for multiple threads to make concurrent accesses to this object
                without synchronization.
        !*/
    public:

        point_rotator (
        );
        /*!
            ensures
                - This object will perform the identity transform.  That is, given a point
                  as input it will return the same point as output.
        !*/

        point_rotator (
            const double& angle
        );
        /*!
            ensures
                - When (*this)(p) is invoked it will return a point P such that:
                    - P is the point p rotated counter-clockwise around the origin
                      angle radians.
                      (Note that this is counter clockwise with respect to the normal
                      coordinate system with positive y going up and positive x going
                      to the right)
        !*/

        template <typename T>
        const dlib::vector<T,2> operator() (
            const dlib::vector<T,2>& p
        ) const;
        /*!
            ensures
                - rotates p and returns the result. The output of this function is
                  therefore equal to get_m()*p.
        !*/

        const matrix<double,2,2> get_m(
        ) const;
        /*!
            ensures
                - returns the transformation matrix used by this object.
        !*/
    };

    void serialize   (const point_rotator& item, std::ostream& out);
    void deserialize (point_rotator& item, std::istream& in);
    /*!
        provides serialization support
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    const dlib::vector<T,2> rotate_point (
        const dlib::vector<T,2> center,
        const dlib::vector<T,2> p,
        double angle
    );
    /*!
        ensures
            - returns a point P such that:
                - P is the point p rotated counter-clockwise around the given
                  center point by angle radians.
                  (Note that this is counter clockwise with respect to the normal
                  coordinate system with positive y going up and positive x going
                  to the right)
    !*/

// ----------------------------------------------------------------------------------------

    matrix<double,2,2> rotation_matrix (
         double angle
    );
    /*!
        ensures
            - returns a rotation matrix which rotates points around the origin in a
              counter-clockwise direction by angle radians.
              (Note that this is counter clockwise with respect to the normal
              coordinate system with positive y going up and positive x going
              to the right)
              Or in other words, this function returns a matrix M such that, given a
              point P, M*P gives a point which is P rotated by angle radians around
              the origin in a counter-clockwise direction.
    !*/

// ----------------------------------------------------------------------------------------

    class point_transform_affine3d
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is an object that takes 3D points or vectors and
                applies an affine transformation to them.

            THREAD SAFETY
                It is safe for multiple threads to make concurrent accesses to this object
                without synchronization.
        !*/
    public:

        point_transform_affine3d (
        );
        /*!
            ensures
                - This object will perform the identity transform.  That is, given a point
                  as input it will return the same point as output.
        !*/

        point_transform_affine3d (
            const matrix<double,3,3>& m,
            const dlib::vector<double,3>& b
        );
        /*!
            ensures
                - #get_m() == m
                - #get_b() == b
                - When (*this)(p) is invoked it will return a point P such that:
                    - P == m*p + b
        !*/

        const dlib::vector<double,3> operator() (
            const dlib::vector<double,3>& p
        ) const;
        /*!
            ensures
                - applies the affine transformation defined by this object's constructor
                  to p and returns the result.
        !*/

        const matrix<double,3,3>& get_m(
        ) const;
        /*!
            ensures
                - returns the transformation matrix used by this object.
        !*/

        const dlib::vector<double,3>& get_b(
        ) const;
        /*!
            ensures
                - returns the offset vector used by this object.
        !*/

    };

    void serialize   (const point_transform_affine3d& item, std::ostream& out);
    void deserialize (point_transform_affine3d& item, std::istream& in);
    /*!
        provides serialization support
    !*/

// ----------------------------------------------------------------------------------------

    point_transform_affine3d operator* (
        const point_transform_affine3d& lhs,
        const point_transform_affine3d& rhs
    );
    /*!
        ensures
            - returns a transformation TFORM(x) that is equivalent to lhs(rhs(x)).  That
              is, for all valid x: TFORM(x) == lhs(rhs(x)).
    !*/

// ----------------------------------------------------------------------------------------

    point_transform_affine3d operator* (
        const point_transform_affine3d& lhs,
        const point_transform_affine& rhs
    );
    /*!
        ensures
            - returns a transformation TFORM(x) that is equivalent to lhs(rhs(x)).  That
              is, for all valid x: TFORM(x) == lhs(rhs(x)).
    !*/

// ----------------------------------------------------------------------------------------

    point_transform_affine3d inv (
        const point_transform_affine3d& trans
    );
    /*!
        ensures
            - If trans is an invertible transformation then this function returns a new
              transformation that is the inverse of trans.
    !*/

// ----------------------------------------------------------------------------------------

    point_transform_affine3d rotate_around_x (
        double angle
    );
    /*!
        ensures
            - Returns a transformation that rotates a point around the x axis in a
              counter-clockwise direction by angle radians.  That is, the rotation appears
              counter-clockwise when the x axis points toward the observer, the coordinate
              system is right-handed, and the angle is positive.
    !*/

// ----------------------------------------------------------------------------------------

    point_transform_affine3d rotate_around_y (
        double angle
    );
    /*!
        ensures
            - Returns a transformation that rotates a point around the y axis in a
              counter-clockwise direction by angle radians.  That is, the rotation appears
              counter-clockwise when the y axis points toward the observer, the coordinate
              system is right-handed, and the angle is positive.
    !*/

// ----------------------------------------------------------------------------------------

    point_transform_affine3d rotate_around_z (
        double angle
    );
    /*!
        ensures
            - Returns a transformation that rotates a point around the z axis in a
              counter-clockwise direction by angle radians.  That is, the rotation appears
              counter-clockwise when the z axis points toward the observer, the coordinate
              system is right-handed, and the angle is positive.
    !*/

// ----------------------------------------------------------------------------------------

    point_transform_affine3d translate_point (
        const vector<double,3>& delta
    );
    /*!
        ensures
            - returns a transformation that simply translates points by adding delta to
              them.  That is, this function returns:
                point_transform_affine3d(identity_matrix<double>(3),delta);
    !*/

    point_transform_affine3d translate_point (
        double x,
        double y,
        double z
    );
    /*!
        ensures
            - returns translate_point(vector<double>(x,y,z))
    !*/

// ----------------------------------------------------------------------------------------

    class camera_transform
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object maps 3D points into the image plane of a camera.  Therefore,
                you can use it to compute 2D representations of 3D data from the point of
                view of some camera in 3D space.

            THREAD SAFETY
                It is safe for multiple threads to make concurrent accesses to this object
                without synchronization.
        !*/

    public:

        camera_transform  (
        );
        /*!
            ensures
                - #get_camera_pos()           == vector<double>(1,1,1)
                - #get_camera_looking_at()    == vector<double>(0,0,0)
                - #get_camera_up_direction()  == vector<double>(0,0,1)
                - #get_camera_field_of_view() == 90
                - #get_num_pixels()           == 1
        !*/

        camera_transform (
            const vector<double>& camera_pos,
            const vector<double>& camera_looking_at,
            const vector<double>& camera_up_direction,
            const double camera_field_of_view,
            const unsigned long num_pixels
        );
        /*!
            requires
                - 0 < camera_field_of_view < 180
            ensures
                - #get_camera_pos() == camera_pos
                - #get_camera_looking_at() == camera_looking_at
                - #get_camera_up_direction() == camera_up_direction
                - #get_camera_field_of_view() == camera_field_of_view
                - #get_num_pixels() == num_pixels
        !*/

        dpoint operator() (
            const vector<double>& p
        ) const;
        /*!
            ensures
                - Maps the given 3D point p into the 2D image plane defined by the camera
                  parameters given to this object's constructor.  The 2D point in the image
                  plane is returned.
        !*/

        dpoint operator() (
            const vector<double>& p,
            double& scale,
            double& distance
        ) const;
        /*!
            ensures
                - Maps the given 3D point p into the 2D image plane defined by the camera
                  parameters given to this object's constructor.  The 2D point in the image
                  plane is returned.
                - #scale == a number that tells you how large things are at the point p.
                  Objects further from the camera appear smaller, in particular, they
                  appear #scale times their normal size.
                - #distance == how far away the point is from the image plane.  Objects in
                  front of the camera will have a positive distance and those behind a
                  negative distance.
        !*/

        vector<double> get_camera_pos(
        ) const;
        /*!
            ensures
                - returns the position, in 3D space, of the camera.  When operator() is
                  invoked it maps 3D points into the image plane of this camera.
        !*/

        vector<double> get_camera_looking_at(
        ) const;
        /*!
            ensures
                - returns the point in 3D space the camera is pointed at.
        !*/

        vector<double> get_camera_up_direction(
        ) const;
        /*!
            ensures
                - returns a vector that defines what direction is "up" for the camera.
                  This means that as you travel from the bottom of the image plane to the
                  top you will be traveling in the direction of this vector.  Note that
                  get_camera_up_direction() doesn't need to be orthogonal to the camera's
                  line of sight (i.e. get_camera_looking_at()-get_camera_pos()), it just
                  needs to not be an exact multiple of the line of sight.  Any necessary
                  orthogonalization will be taken care of internally.
        !*/

        double get_camera_field_of_view(
        ) const;
        /*!
            ensures
                - returns the field of view of the camera in degrees.
        !*/

        unsigned long get_num_pixels(
        ) const;
        /*!
            ensures
                - 3D points that fall within the field of view of the camera are mapped by
                  operator() into the pixel coordinates of a get_num_pixels() by
                  get_num_pixels() image.  Therefore, you can use the output of operator()
                  to index into an image.  However, you still need to perform bounds
                  checking as there might be 3D points outside the field of view of the
                  camera and those will be mapped to 2D points outside the image.
        !*/

    };

    void serialize   (const camera_transform& item, std::ostream& out);
    void deserialize (camera_transform& item, std::istream& in);
    /*!
        provides serialization support
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_POINT_TrANSFORMS_ABSTRACT_Hh_


dlib C++ Library - rectangle_abstract.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_RECTANGLe_ABSTRACT_
#ifdef DLIB_RECTANGLe_ABSTRACT_

#include "vector_abstract.h"
#include <iostream>
#include "../serialize.h"

namespace dlib
{

    class rectangle
    {
        /*!
            INITIAL VALUE
                The initial value of this object is defined by its constructor.

            WHAT THIS OBJECT REPRESENTS
                This object represents a rectangular region inside a Cartesian
                coordinate system.  The region is the rectangle with its top
                left corner at position (left(),top()) and its bottom right corner
                at (right(),bottom()).

                Note that the origin of the coordinate system, i.e. (0,0), is located
                at the upper left corner.  That is, points such as (1,1) or (3,5)
                represent locations that are below and to the right of the origin.

                Also note that rectangles where top() > bottom() or left() > right()
                represent empty rectangles.
        !*/

    public:

        rectangle (
            const rectangle& rect
        );
        /*!
            ensures
                - #*this represents the same rectangle as rect
        !*/

        rectangle (
        );
        /*!
            ensures
                - #left() == 0
                - #top() == 0
                - #right() == -1
                - #bottom() == -1
                - #is_empty() == true
        !*/

        rectangle (
            long left_,
            long top_,
            long right_,
            long bottom_
        );
        /*!
            ensures
                - #left() == left_
                - #top() == top_
                - #right() == right_
                - #bottom() == bottom_
        !*/

        rectangle (
            unsigned long width_,
            unsigned long height_
        );
        /*!
            requires
                - (width_ > 0 && height_ > 0) || (width_ == 0 && height_ == 0)
            ensures
                - #left() == 0
                - #top() == 0
                - #width() == width_
                - #height() == height_
        !*/

        rectangle (
            const point& p
        );
        /*!
            ensures
                - #left()   == p.x()
                - #top()    == p.y()
                - #right()  == p.x()
                - #bottom() == p.y()
        !*/

        template <typename T>
        rectangle (
            const vector<T,2>& p1,
            const vector<T,2>& p2
        );
        /*!
            ensures
                - #*this == rectangle(p1) + rectangle(p2)
        !*/

        long left (
        ) const;
        /*!
            ensures
                - returns the x coordinate for the left side of this rectangle
        !*/

        long& left (
        );
        /*!
            ensures
                - returns a non-const reference to the x coordinate for the left side
                  of this rectangle
        !*/

        void set_left (
            long left_
        );
        /*!
            ensures
                - #left() == left_
        !*/

        long top (
        ) const;
        /*!
            ensures
                - returns the y coordinate for the top of this rectangle
        !*/

        long& top (
        );
        /*!
            ensures
                - returns a non-const reference to the y coordinate for the
                  top of this rectangle
        !*/

        void set_top (
            long top_
        );
        /*!
            ensures
                - #top() == top_
        !*/

        long right (
        ) const;
        /*!
            ensures
                - returns the x coordinate for the right side of this rectangle
        !*/

        long& right (
        );
        /*!
            ensures
                - returns a non-const reference to the x coordinate for the right
                  side of this rectangle
        !*/

        void set_right (
            long right_
        );
        /*!
            ensures
                - #right() == right_
        !*/

        long bottom (
        ) const;
        /*!
            ensures
                - returns the y coordinate for the bottom of this rectangle
        !*/

        long& bottom (
        );
        /*!
            ensures
                - returns a non-const reference to the y coordinate for the bottom
                  of this rectangle
        !*/

        void set_bottom (
            long bottom_
        );
        /*!
            ensures
                - #bottom() == bottom_
        !*/

        const point tl_corner (
        ) const;
        /*!
            ensures
                - returns point(left(), top())
                  (i.e. returns the top left corner point for this rectangle)
        !*/

        const point bl_corner (
        ) const;
        /*!
            ensures
                - returns point(left(), bottom())
                  (i.e. returns the bottom left corner point for this rectangle)
        !*/

        const point tr_corner (
        ) const;
        /*!
            ensures
                - returns point(right(), top())
                  (i.e. returns the top right corner point for this rectangle)
        !*/

        const point br_corner (
        ) const;
        /*!
            ensures
                - returns point(right(), bottom())
                  (i.e. returns the bottom right corner point for this rectangle)
        !*/

        bool is_empty (
        ) const;
        /*!
            ensures
                - if (top() > bottom() || left() > right()) then
                    - returns true
                - else
                    - returns false
        !*/

        unsigned long width (
        ) const;
        /*!
            ensures
                - if (is_empty()) then
                    - returns 0
                - else
                    - returns the width of this rectangle.
                      (i.e. right() - left() + 1)
        !*/

        unsigned long height (
        ) const;
        /*!
            ensures
                - if (is_empty()) then
                    - returns 0
                - else
                    - returns the height of this rectangle.
                      (i.e. bottom() - top() + 1)
        !*/

        unsigned long area (
        ) const;
        /*!
            ensures
                - returns width()*height()
        !*/

        rectangle operator + (
            const rectangle& rhs
        ) const;
        /*!
            ensures
                - if (rhs.is_empty() == false && this->is_empty() == false) then
                    - returns the smallest rectangle that contains both *this and
                      rhs.
                - if (rhs.is_empty() == true && this->is_empty() == false) then
                    - returns *this
                - if (rhs.is_empty() == false && this->is_empty() == true) then
                    - returns rhs
                - if (rhs.is_empty() == true && this->is_empty() == true) then
                    - returns a rectangle that has is_empty() == true
        !*/

        rectangle intersect (
            const rectangle& rhs
        ) const;
        /*!
            ensures
                - if (there is a region of intersection between *this and rhs) then
                    - returns a rectangle that represents the intersection of *this
                      and rhs.
                - else
                    - returns a rectangle where is_empty() == true
        !*/

        bool contains (
            long x,
            long y
        ) const;
        /*!
            ensures
                - if (the point (x,y) is contained in this rectangle) then
                    - returns true
                - else
                    - returns false
        !*/

        bool contains (
            const point& p
        ) const;
        /*!
            ensures
                - if (the point (p.x(),p.y()) is contained in this rectangle) then
                    - returns true
                - else
                    - returns false
        !*/

        bool contains (
            const rectangle& rect
        ) const;
        /*!
            ensures
                - if (rect + *this == *this) then
                    - returns true
                      (i.e. returns true if *this contains the given rectangle)
                - else
                    - returns false
        !*/

        rectangle& operator= (
            const rectangle& rect
        );
        /*!
            ensures
                - #*this represents the same rectangle as rect
                - returns #*this
        !*/

        rectangle& operator+= (
            const rectangle& rect
        );
        /*!
            ensures
                - #*this == *this + rect
                - returns #*this
        !*/

        bool operator== (
            const rectangle& rect
        ) const;
        /*!
            ensures
                - if (top() == rect.top() && left() == rect.left() &&
                      right() == rect.right() && bottom() == rect.bottom()) then
                    - returns true
                - else
                    - returns false
        !*/

        bool operator!= (
            const rectangle& rect
        ) const;
        /*!
            ensures
                - returns !(*this == rect)
        !*/
    };

// ----------------------------------------------------------------------------------------

    void serialize (
        const rectangle& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

    void deserialize (
        rectangle& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

    std::ostream& operator<< (
        std::ostream& out,
        const rectangle& item
    );
    /*!
        ensures
            - writes item to out in the form "[(left, top) (right, bottom)]"
    !*/

    std::istream& operator>>(
        std::istream& in,
        rectangle& item
    );
    /*!
        ensures
            - reads a rectangle from the input stream in and stores it in #item.
              The data in the input stream should be of the form [(left, top) (right, bottom)]
    !*/

// ----------------------------------------------------------------------------------------

    point center (
        const dlib::rectangle& rect
    );
    /*!
        ensures
            - returns the center of the given rectangle
    !*/

// ----------------------------------------------------------------------------------------

    dlib::vector<double,2> dcenter (
        const dlib::rectangle& rect
    );
    /*!
        ensures
            - returns the center of the given rectangle using a real valued vector.
    !*/

// ----------------------------------------------------------------------------------------

    inline const rectangle centered_rect (
        const point& p,
        unsigned long width,
        unsigned long height
    );
    /*!
        ensures
            - returns a rectangle R such that:
                - center(R) == p
                - if (width == 0 || height == 0)
                    - R.width() == 0
                    - R.height() == 0
                - else
                    - R.width() == width
                    - R.height() == height
                - R.tl_corner() == point(p.x()-width/2, p.y()-height/2)
    !*/

// ----------------------------------------------------------------------------------------

    const rectangle centered_rect (
        long x,
        long y,
        unsigned long width,
        unsigned long height
    );
    /*!
        ensures
            - returns a rectangle R such that:
                - center(R) == p
                - if (width == 0 || height == 0)
                    - R.width() == 0
                    - R.height() == 0
                - else
                    - R.width() == width
                    - R.height() == height
                - R.tl_corner() == point(x-width/2, y-height/2)
    !*/

// ----------------------------------------------------------------------------------------

    inline const rectangle centered_rect (
        const rectangle& rect,
        unsigned long width,
        unsigned long height
    );
    /*!
        ensures
            - returns centered_rect( (rect.tl_corner() + rect.br_corner())/2, width, height)
              (i.e. returns a rectangle centered on rect but with the given width
              and height)
    !*/

// ----------------------------------------------------------------------------------------

    inline rectangle set_aspect_ratio (
        const rectangle& rect,
        double ratio
    );
    /*!
        requires
            - ratio > 0
        ensures
            - This function reshapes the given rectangle so that it has the given aspect
              ratio.  In particular, this means we return a rectangle R such that the
              following equations are as true as possible:
                - R.width()/R.height() == ratio
                - R.area() == rect.area()
                - center(rect) == center(R)
    !*/

// ----------------------------------------------------------------------------------------

    inline rectangle intersect (
        const rectangle& a,
        const rectangle& b
    );
    /*!
        ensures
            - returns a.intersect(b)
              (i.e. returns a rectangle representing the intersection of a and b)
    !*/

// ----------------------------------------------------------------------------------------

    inline unsigned long area (
        const rectangle& a
    );
    /*!
        ensures
            - returns a.area()
    !*/

// ----------------------------------------------------------------------------------------

    inline const rectangle shrink_rect (
        const rectangle& rect,
        long num
    );
    /*!
        ensures
            - returns rectangle(rect.left()+num, rect.top()+num, rect.right()-num, rect.bottom()-num)
              (i.e. shrinks the given rectangle by shrinking its border by num)
    !*/

// ----------------------------------------------------------------------------------------

    inline const rectangle grow_rect (
        const rectangle& rect,
        long num
    );
    /*!
        ensures
            - return shrink_rect(rect, -num)
              (i.e. grows the given rectangle by expanding its border by num)
    !*/

// ----------------------------------------------------------------------------------------

    inline const rectangle shrink_rect (
        const rectangle& rect,
        long width,
        long height
    );
    /*!
        ensures
            - returns rectangle(rect.left()+width, rect.top()+height, rect.right()-width, rect.bottom()-height)
              (i.e. shrinks the given rectangle by shrinking its left and right borders by width
              and its top and bottom borders by height. )
    !*/

// ----------------------------------------------------------------------------------------

    inline const rectangle grow_rect (
        const rectangle& rect,
        long width,
        long height
    );
    /*!
        ensures
            - return shrink_rect(rect, -width, -height)
              (i.e. grows the given rectangle by expanding its border)
    !*/

// ----------------------------------------------------------------------------------------

    const rectangle translate_rect (
        const rectangle& rect,
        const point& p
    );
    /*!
        ensures
            - returns a rectangle R such that:
                - R.left()   == rect.left()   + p.x()
                - R.right()  == rect.right()  + p.x()
                - R.top()    == rect.top()    + p.y()
                - R.bottom() == rect.bottom() + p.y()
    !*/

// ----------------------------------------------------------------------------------------

    const rectangle translate_rect (
        const rectangle& rect,
        long x,
        long y
    );
    /*!
        ensures
            - returns a rectangle R such that:
                - R.left()   == rect.left()   + x
                - R.right()  == rect.right()  + x
                - R.top()    == rect.top()    + y
                - R.bottom() == rect.bottom() + y
    !*/

// ----------------------------------------------------------------------------------------

    const rectangle resize_rect (
        const rectangle& rect,
        unsigned long width,
        unsigned long height
    );
    /*!
        ensures
            - returns a rectangle R such that:
                - if (width == 0 || height == 0)
                    - R.width() == 0
                    - R.height() == 0
                - else
                    - R.width() == width
                    - R.height() == height
                - R.left() == rect.left()
                - R.top() == rect.top()
    !*/

// ----------------------------------------------------------------------------------------

    const rectangle resize_rect_width (
        const rectangle& rect,
        unsigned long width
    );
    /*!
        ensures
            - returns a rectangle R such that:
                - R.width() == width
                - R.left() == rect.left()
                - R.top() == rect.top()
                - R.bottom() == rect.bottom()
    !*/

// ----------------------------------------------------------------------------------------

    const rectangle resize_rect_height (
        const rectangle& rect,
        unsigned long height
    );
    /*!
        ensures
            - returns a rectangle R such that:
                - R.height() == height
                - R.left() == rect.left()
                - R.top() == rect.top()
                - R.right() == rect.right()
    !*/

// ----------------------------------------------------------------------------------------

    const rectangle move_rect (
        const rectangle& rect,
        const point& p
    );
    /*!
        ensures
            - returns a rectangle R such that:
                - R.width() == rect.width()
                - R.height() == rect.height()
                - R.left() == p.x()
                - R.top() == p.y()
    !*/

// ----------------------------------------------------------------------------------------

    const rectangle move_rect (
        const rectangle& rect,
        long x,
        long y
    );
    /*!
        ensures
            - returns a rectangle R such that:
                - R.width() == rect.width()
                - R.height() == rect.height()
                - R.left() == x
                - R.top() == y
    !*/

// ----------------------------------------------------------------------------------------

    inline const point nearest_point (
        const rectangle& rect,
        const point& p
    );
    /*!
        ensures
            - if (rect.contains(p)) then
                - returns p
            - else
                - returns the point in rect that is closest to p
    !*/

// ----------------------------------------------------------------------------------------

    inline long distance_to_rect_edge (
        const rectangle& rect,
        const point& p
    );
    /*!
        ensures
            - returns the Manhattan distance between the edge of rect and p.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T, typename U>
    double distance_to_line (
        const std::pair<vector<T,2>,vector<T,2> >& line,
        const vector<U,2>& p
    );
    /*!
        ensures
            - returns the euclidean distance between the given line and the point p.  That
              is, given a line that passes though the points line.first and line.second,
              what is the distance between p and the nearest point on the line?  This
              function returns that distance.
    !*/

// ----------------------------------------------------------------------------------------

    void clip_line_to_rectangle (
        const rectangle& box,
        point& p1,
        point& p2
    );
    /*!
        ensures
            - clips the line segment that goes from points p1 to p2 so that it is entirely
              within the given box.  In particular, we will have:
                - box.contains(#p1) == true
                - box.contains(#p2) == true
                - The line segment #p1 to #p2 is entirely contained within the line segment
                  p1 to p2.  Moreover, #p1 to #p2 is the largest such line segment that
                  fits within the given box.
            - If the line segment does not intersect the box then the result is some
              arbitrary line segment inside the box.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    const rectangle get_rect (
        const T& m
    );
    /*!
        requires
            - It must be possible to determine the number of "rows" and "columns" in m.
              Either by calling num_rows(m) and num_columns(m) or by calling m.nr() and
              m.nc() to obtain the number of rows and columns respectively.  Moreover,
              these routines should return longs.
        ensures
            - returns rectangle(0, 0, num_columns(m)-1, num_rows(m)-1)
              (i.e. assuming T represents some kind of rectangular grid, such as
              the dlib::matrix or dlib::array2d objects, this function returns the
              bounding rectangle for that gridded object.)
    !*/

// ----------------------------------------------------------------------------------------

    inline rectangle operator+ (
        const rectangle& r,
        const point& p
    );
    /*!
        ensures
            - returns r + rectangle(p)
              (i.e. returns the rectangle that contains both r and p)
    !*/

// ----------------------------------------------------------------------------------------

    inline rectangle operator+ (
        const point& p,
        const rectangle& r
    );
    /*!
        ensures
            - returns r + rectangle(p)
              (i.e. returns the rectangle that contains both r and p)
    !*/

// ----------------------------------------------------------------------------------------

}

namespace std
{
    /*!
        Define std::less<rectangle> so that you can use rectangles in the associative containers.
    !*/
    template<>
    struct less<dlib::rectangle> : public binary_function<dlib::rectangle,dlib::rectangle,bool>
    {
        inline bool operator() (const dlib::rectangle& a, const dlib::rectangle& b) const
        {
            if      (a.left() < b.left()) return true;
            else if (a.left() > b.left()) return false;
            else if (a.top() < b.top()) return true;
            else if (a.top() > b.top()) return false;
            else if (a.right() < b.right()) return true;
            else if (a.right() > b.right()) return false;
            else if (a.bottom() < b.bottom()) return true;
            else if (a.bottom() > b.bottom()) return false;
            else                    return false;
        }
    };
}

#endif // DLIB_RECTANGLe_ABSTRACT_


dlib C++ Library - drectangle_abstract.h

// Copyright (C) 2015  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_DRECTANGLe_ABSTRACT_H_
#ifdef DLIB_DRECTANGLe_ABSTRACT_H_

#include "rectangle_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class drectangle
    {
        /*!
            INITIAL VALUE
                The initial value of this object is defined by its constructor.

            WHAT THIS OBJECT REPRESENTS
                This object is just like dlib::rectangle except that it stores the
                coordinates of the rectangle using double rather than long variables.  As
                such, this object represents a rectangular region inside an image.  The
                region is the rectangle with its top left corner at position (left(),top())
                and its bottom right corner at (right(),bottom()).

                Note that the origin of the coordinate system, i.e. (0,0), is located at
                the upper left corner.  That is, points such as (1,1) or (3,5) represent
                locations that are below and to the right of the origin.

                Also note that rectangles where top() > bottom() or left() > right()
                represent empty rectangles.
        !*/
    public:

        drectangle (
        );
        /*!
            ensures
                - #left() == 0
                - #top() == 0
                - #right() == -1
                - #bottom() == -1
                - #is_empty() == true
        !*/

        drectangle (
            double left_,
            double top_,
            double right_,
            double bottom_
        );
        /*!
            ensures
                - #left() == left_
                - #top() == top_
                - #right() == right_
                - #bottom() == bottom_
        !*/

        drectangle (
            const vector<double,2>& p
        );
        /*!
            ensures
                - #left()   == p.x()
                - #top()    == p.y()
                - #right()  == p.x()
                - #bottom() == p.y()
        !*/

        template <typename T, typename U>
        drectangle (
            const vector<T,2>& p1,
            const vector<U,2>& p2
        );
        /*!
            ensures
                - #*this == drectangle(p1) + drectangle(p2)
        !*/

        drectangle (
            const drectangle& rect
        );
        /*!
            ensures
                - #*this represents the same rectangle as rect
        !*/

        drectangle (
            const rectangle& rect
        );
        /*!
            ensures
                - left()   == rect.left()
                - top()    == rect.top()
                - right()  == rect.right()
                - bottom() == rect.bottom()
                - dcenter(*this) == dcenter(rect)
                - width() == rect.width()
                - height() == rect.height()
        !*/

        operator rectangle (
        ) const;
        /*!
            ensures
                - returns a rectangle where left(), top(), right(), and bottom() have been
                  rounded to the nearest integer values.
        !*/

        double left (
        ) const;
        /*!
            ensures
                - returns the x coordinate for the left side of this rectangle
        !*/

        double& left (
        );
        /*!
            ensures
                - returns a non-const reference to the x coordinate for the left side
                  of this rectangle
        !*/

        double top (
        ) const;
        /*!
            ensures
                - returns the y coordinate for the top of this rectangle
        !*/

        double& top (
        );
        /*!
            ensures
                - returns a non-const reference to the y coordinate for the
                  top of this rectangle
        !*/

        double right (
        ) const;
        /*!
            ensures
                - returns the x coordinate for the right side of this rectangle
        !*/

        double& right (
        );
        /*!
            ensures
                - returns a non-const reference to the x coordinate for the right
                  side of this rectangle
        !*/

        double bottom (
        ) const;
        /*!
            ensures
                - returns the y coordinate for the bottom of this rectangle
        !*/

        double& bottom (
        );
        /*!
            ensures
                - returns a non-const reference to the y coordinate for the bottom
                  of this rectangle
        !*/

        const vector<double,2> tl_corner (
        ) const;
        /*!
            ensures
                - returns vector<double,2>(left(), top())
                  (i.e. returns the top left corner point for this rectangle)
        !*/

        const vector<double,2> bl_corner (
        ) const;
        /*!
            ensures
                - returns vector<double,2>(left(), bottom())
                  (i.e. returns the bottom left corner point for this rectangle)
        !*/

        const vector<double,2> tr_corner (
        ) const;
        /*!
            ensures
                - returns vector<double,2>(right(), top())
                  (i.e. returns the top right corner point for this rectangle)
        !*/

        const vector<double,2> br_corner (
        ) const;
        /*!
            ensures
                - returns vector<double,2>(right(), bottom())
                  (i.e. returns the bottom right corner point for this rectangle)
        !*/

        double width (
        ) const;
        /*!
            ensures
                - if (is_empty()) then
                    - returns 0
                - else
                    - returns the width of this rectangle.
                      (i.e. right() - left() + 1)
        !*/

        double height (
        ) const;
        /*!
            ensures
                - if (is_empty()) then
                    - returns 0
                - else
                    - returns the height of this rectangle.
                      (i.e. bottom() - top() + 1)
        !*/

        double area (
        ) const;
        /*!
            ensures
                - returns width()*height()
        !*/

        bool is_empty (
        ) const;
        /*!
            ensures
                - if (top() > bottom() || left() > right()) then
                    - returns true
                - else
                    - returns false
        !*/

        drectangle operator + (
            const drectangle& rhs
        ) const;
        /*!
            ensures
                - if (rhs.is_empty() == false && this->is_empty() == false) then
                    - returns the smallest rectangle that contains both *this and
                      rhs.
                - if (rhs.is_empty() == true && this->is_empty() == false) then
                    - returns *this
                - if (rhs.is_empty() == false && this->is_empty() == true) then
                    - returns rhs
                - if (rhs.is_empty() == true && this->is_empty() == true) then
                    - returns a rectangle that has is_empty() == true
        !*/

        drectangle intersect (
            const drectangle& rhs
        ) const;
        /*!
            ensures
                - if (there is a region of intersection between *this and rhs) then
                    - returns a rectangle that represents the intersection of *this
                      and rhs.
                - else
                    - returns a rectangle where is_empty() == true
        !*/

        bool contains (
            const vector<double,2>& p
        ) const;
        /*!
            ensures
                - if (the point (p.x(),p.y()) is contained in this rectangle) then
                    - returns true
                - else
                    - returns false
        !*/

        bool contains (
            const drectangle& rect
        ) const
        /*!
            ensures
                - if (rect + *this == *this) then
                    - returns true
                      (i.e. returns true if *this contains the given rectangle)
                - else
                    - returns false
        !*/

        drectangle& operator *= (
            const double& scale
        );
        /*!
            ensures
                - performs: *this = *this*scale;
                - returns #*this
        !*/

        drectangle& operator /= (
            const double& scale
        );
        /*!
            requires
                - scale != 0
            ensures
                - performs: *this = *this*(1.0/scale);
                - returns #*this
        !*/

        drectangle& operator += (
            const dlib::vector<double,2>& p
        );
        /*!
            ensures
                - performs: *this = *this + drectangle(p)
                - returns #*this
        !*/

    };

// ----------------------------------------------------------------------------------------

    void serialize (
        const drectangle& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

    void deserialize (
        drectangle& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// ----------------------------------------------------------------------------------------

    std::ostream& operator<< (
        std::ostream& out,
        const drectangle& item
    );
    /*!
        ensures
            - writes item to out in the form "[(left, top) (right, bottom)]"
    !*/

// ----------------------------------------------------------------------------------------

    std::istream& operator>>(
        std::istream& in,
        drectangle& item
    );
    /*!
        ensures
            - reads a drectangle from the input stream in and stores it in #item.  The data
              in the input stream should be of the form [(left, top) (right, bottom)]
    !*/

// ----------------------------------------------------------------------------------------

    vector<double,2> center (
        const drectangle& rect
    );
    /*!
        ensures
            - returns the center of the given rectangle
    !*/

// ----------------------------------------------------------------------------------------

    vector<double,2> dcenter (
        const drectangle& rect
    );
    /*!
        ensures
            - returns the center of the given rectangle.  (Both center() and dcenter() are
              identical when applied to drectangle objects)
    !*/

// ----------------------------------------------------------------------------------------

    drectangle operator* (
        const drectangle& rect,
        const double& scale
    );
    /*!
        ensures
            - This function returns a rectangle that has the same center as rect but with
              dimensions that are scale times larger.  That is, we return a new rectangle R
              such that:
                - center(R) == center(rect)
                - R.right()-R.left() == (rect.right()-rect.left())*scale
                - R.bottom()-R.top() == (rect.bottom()-rect.top())*scale
    !*/

// ----------------------------------------------------------------------------------------

    drectangle operator* (
        const double& scale,
        const drectangle& rect
    );
    /*!
        ensures
            - returns rect*scale
    !*/

// ----------------------------------------------------------------------------------------

    drectangle operator/ (
        const drectangle& rect,
        const double& scale
    );
    /*!
        ensures
            - returns rect*(1.0/scale)
    !*/

// ----------------------------------------------------------------------------------------

    drectangle operator+ (
        const drectangle& r,
        const vector<double,2>& p
    );
    /*!
        ensures
            - returns r + drectangle(p)
              (i.e. returns the rectangle that contains both r and p)
    !*/

// ----------------------------------------------------------------------------------------

    drectangle operator+ (
        const vector<double,2>& p,
        const drectangle& r
    );
    /*!
        ensures
            - returns r + drectangle(p)
              (i.e. returns the rectangle that contains both r and p)
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    drectangle translate_rect (
        const drectangle& rect,
        const vector<T,2>& p
    );
    /*!
        ensures
            - returns a rectangle R such that:
                - R.left()   == rect.left()   + p.x()
                - R.right()  == rect.right()  + p.x()
                - R.top()    == rect.top()    + p.y()
                - R.bottom() == rect.bottom() + p.y()
    !*/

// ----------------------------------------------------------------------------------------

    drectangle intersect (
        const drectangle& a,
        const drectangle& b
    );
    /*!
        ensures
            - returns a.intersect(b)
              (i.e. returns a rectangle representing the intersection of a and b)
    !*/

// ----------------------------------------------------------------------------------------

    double area (
        const drectangle& a
    );
    /*!
        ensures
            - returns a.area()
    !*/

// ----------------------------------------------------------------------------------------

    drectangle centered_drect (
        const vector<double,2>& p,
        double width,
        double height
    );
    /*!
        ensures
            - returns a rectangle R such that:
                - center(R) == p
                - if (width < 1 || height < 1)
                    - R.width() == 0
                    - R.height() == 0
                    - R.is_empty() == true
                - else
                    - R.width() == width
                    - R.height() == height
    !*/

// ----------------------------------------------------------------------------------------

    drectangle centered_drect (
        const drectangle& rect,
        double width,
        double height
    );
    /*!
        ensures
            - returns centered_drect(center(rect), width, height)
    !*/

// ----------------------------------------------------------------------------------------

    const drectangle shrink_rect (
        const drectangle& rect,
        double num
    );
    /*!
        ensures
            - returns drectangle(rect.left()+num, rect.top()+num, rect.right()-num, rect.bottom()-num)
              (i.e. shrinks the given drectangle by shrinking its border by num)
    !*/

// ----------------------------------------------------------------------------------------

    const drectangle grow_rect (
        const drectangle& rect,
        double num
    );
    /*!
        ensures
            - return shrink_rect(rect, -num)
              (i.e. grows the given drectangle by expanding its border by num)
    !*/

// ----------------------------------------------------------------------------------------

    const drectangle shrink_rect (
        const drectangle& rect,
        double width,
        double height
    );
    /*!
        ensures
            - returns drectangle(rect.left()+width, rect.top()+height, rect.right()-width, rect.bottom()-height)
              (i.e. shrinks the given drectangle by shrinking its left and right borders by width
              and its top and bottom borders by height. )
    !*/

// ----------------------------------------------------------------------------------------

    const drectangle grow_rect (
        const drectangle& rect,
        double width,
        double height
    );
    /*!
        ensures
            - return shrink_rect(rect, -width, -height)
              (i.e. grows the given drectangle by expanding its border)
    !*/

// ----------------------------------------------------------------------------------------

    drectangle set_aspect_ratio (
        const drectangle& rect,
        double ratio
    );
    /*!
        requires
            - ratio > 0
        ensures
            - This function reshapes the given rectangle so that it has the given aspect
              ratio.  In particular, this means we return a rectangle R such that the
              following equations are true:
                - R.width()/R.height() == ratio
                - R.area() == rect.area()
                - dcenter(rect) == dcenter(R)
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_DRECTANGLe_ABSTRACT_H_


dlib C++ Library - vector_abstract.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_VECTOR_ABSTRACT_
#ifdef DLIB_VECTOR_ABSTRACT_

#include "../serialize.h"
#include <functional>
#include <iostream>
#include "../matrix/matrix_abstract.h"

namespace dlib
{
    template <
        typename T,
        long NR = 3
        >
    class vector : public matrix<T,NR,1>
    {
        /*!
            REQUIREMENTS ON T
                T should be some object that provides an interface that is
                compatible with double, float, int, long and the like.

            REQUIREMENTS ON NR
                NR == 3 || NR == 2

            INITIAL VALUE
                x() == 0
                y() == 0
                z() == 0

            WHAT THIS OBJECT REPRESENTS
                This object represents a three dimensional vector.  If NR == 2 then
                this object is limited to representing points on the XY plane where
                Z is set to 0.

                Also note that this object performs the appropriate integer and
                floating point conversions and promotions when vectors of mixed
                type are used together.  For example:
                    vector<int,3> vi;
                    vector<double,2> vd;
                    vd + vi == a vector<double,3> object type since that is what
                               is needed to contain the result of vi+vd without
                               any loss of information.
        !*/

    public:

        typedef T type;

        vector (
        );
        /*!
            ensures
               - #*this has been properly initialized
        !*/

        vector (
            const T _x,
            const T _y,
            const T _z
        );
        /*!
            requires
                - NR == 3
            ensures
                - #x() == _x
                - #y() == _y
                - #z() == _z
        !*/

        vector (
            const T _x,
            const T _y
        );
        /*!
            requires
                - NR == 2
            ensures
                - #x() == _x
                - #y() == _y
                - #z() == 0
        !*/

        template <typename U, long NRv>
        vector (
            const vector<U,NRv>& v
        );
        /*!
            ensures
                - Initializes *this with the contents of v and does any rounding if necessary and also
                  takes care of converting between 2 and 3 dimensional vectors.
                - if (U is a real valued type like float or double and T is an integral type like long) then
                    - if (NR == 3) then
                        - #x() == floor(v.x() + 0.5)
                        - #y() == floor(v.y() + 0.5)
                        - #z() == floor(v.z() + 0.5)
                    - else // NR == 2
                        - #x() == floor(v.x() + 0.5)
                        - #y() == floor(v.y() + 0.5)
                        - #z() == 0
                - else
                    - if (NR == 3) then
                        - #x() == v.x()
                        - #y() == v.y()
                        - #z() == v.z()
                    - else // NR == 2
                        - #x() == v.x()
                        - #y() == v.y()
                        - #z() == 0
        !*/

        template <typename EXP>
        vector (
            const matrix_exp<EXP>& m
        );
        /*!
            requires
                - m.size() == NR
                - m.nr() == 1 || m.nc() == 1 (i.e. m must be a row or column matrix)
            ensures
                - Initializes *this with the contents of m and does any rounding if necessary and also
                  takes care of converting between 2 and 3 dimensional vectors.
                - if (m contains real valued values like float or double and T is an integral type like long) then
                    - #x() == floor(m(0) + 0.5)
                    - #y() == floor(m(1) + 0.5)
                    - if (NR == 3) then
                        - #z() == floor(m(2) + 0.5)
                    - else
                        - #z() == 0
                - else
                    - #x() == m(0)
                    - #y() == m(1)
                    - if (NR == 3) then
                        - #z() == m(2)
                    - else
                        - #z() == 0
        !*/

        ~vector (
        );
        /*!
            ensures
                - all resources associated with *this have been released
        !*/

        double length(
        ) const;
        /*!
            ensures
                - returns the length of the vector
        !*/

        double length_squared(
        ) const;
        /*!
            ensures
                - returns length()*length()
        !*/

        T& x (
        );
        /*!
            ensures
                - returns a reference to the x component of the vector
        !*/

        T& y (
        );
        /*!
            ensures
                - returns a reference to the y component of the vector
        !*/

        T& z (
        );
        /*!
            requires
                - NR == 3 (this function actually doesn't exist when NR != 3)
            ensures
                - returns a reference to the z component of the vector
        !*/

        const T& x (
        ) const;
        /*!
            ensures
                - returns a const reference to the x component of the vector
        !*/

        const T& y (
        ) const;
        /*!
            ensures
                - returns a const reference to the y component of the vector
        !*/

        const T& z (
        ) const;
        /*!
            ensures
                - if (NR == 3) then
                    - returns a const reference to the z component of the vector
                - else
                    - return 0
                      (there isn't really a z in this case so we just return 0)
        !*/

        T dot (
            const vector& rhs
        ) const;
        /*!
            ensures
                - returns the result of the dot product between *this and rhs
        !*/

        vector<T,3> cross (
            const vector& rhs
        ) const;
        /*!
            ensures
                - returns the result of the cross product between *this and rhs
        !*/

        vector<double,NR> normalize (
        ) const;
        /*!
            ensures
                - returns a vector with length() == 1 and in the same direction as *this
        !*/

        vector operator+ (
            const vector& rhs
        ) const;
        /*!
            ensures
                - returns the result of adding *this to rhs
        !*/

        vector operator- (
            const vector& rhs
        ) const;
        /*!
            ensures
                - returns the result of subtracting rhs from *this
        !*/

        vector operator- (
        ) const;
        /*!
            ensures
                - returns -1*(*this)
        !*/

        vector operator/ (
            const T rhs
        ) const;
        /*!
            ensures
                - returns the result of dividing *this by rhs
        !*/

        vector& operator= (
            const vector& rhs
        );
        /*!
            ensures
                - #x() == rhs.x()
                - #y() == rhs.y()
                - #z() == rhs.z()
                - returns #*this
        !*/

        vector& operator += (
            const vector& rhs
        );
        /*!
            ensures
                - #*this == *this + rhs
                - returns #*this
        !*/

        vector& operator -= (
            const vector& rhs
        );
        /*!
            ensures
                - #*this == *this - rhs
                - returns #*this
        !*/

        vector& operator *= (
            const T rhs
        );
        /*!
            ensures
                - #*this == *this * rhs
                - returns #*this
        !*/

        vector& operator /= (
            const T rhs
        );
        /*!
            ensures
                - #*this == *this / rhs
                - returns #*this
        !*/

        template <typename U, long NR2>
        bool operator== (
            const vector<U,NR2>& rhs
        ) const;
        /*!
            ensures
                - if (x() == rhs.x() && y() == rhs.y() && z() == rhs.z()) then
                    - returns true
                - else
                    - returns false
        !*/

        template <typename U, long NR2>
        bool operator!= (
            const vector<U,NR2>& rhs
        ) const;
        /*!
            ensures
                - returns !((*this) == rhs)
        !*/

        void swap (
            vector& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/

    };

// ----------------------------------------------------------------------------------------

    template<typename T, typename U, long NR>
    vector operator* (
        const vector<T,NR> & lhs,
        const U rhs
    );
    /*!
        ensures
            - returns the result of multiplying the scalar rhs by lhs
    !*/

    template<typename T, typename U, long NR>
    vector operator* (
        const U lhs,
        const vector<T,NR> & rhs
    );
    /*!
        ensures
            - returns the result of multiplying the scalar lhs by rhs
    !*/

    template<typename T, long NR>
    inline void swap (
        vector<T,NR> & a,
        vector<T,NR> & b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

    template<typename T, long NR>
    void serialize (
        const vector<T,NR>& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

    template<typename T, long NR>
    void deserialize (
        vector<T,NR>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

    template<typename T>
    std::ostream& operator<< (
        std::ostream& out,
        const vector<T,3>& item
    );
    /*!
        ensures
            - writes item to out in the form "(x, y, z)"
    !*/

    template<typename T>
    std::istream& operator>>(
        std::istream& in,
        vector<T,3>& item
    );
    /*!
        ensures
            - reads a vector from the input stream in and stores it in #item.
              The data in the input stream should be of the form (x, y, z)
    !*/

    template<typename T>
    std::ostream& operator<< (
        std::ostream& out,
        const vector<T,2>& item
    );
    /*!
        ensures
            - writes item to out in the form "(x, y)"
    !*/

    template<typename T>
    std::istream& operator>>(
        std::istream& in,
        vector<T,2>& item
    );
    /*!
        ensures
            - reads a vector from the input stream in and stores it in #item.
              The data in the input stream should be of the form (x, y)
    !*/

// ----------------------------------------------------------------------------------------

    /*!A point
        This is just a typedef of the vector object.
    !*/

    typedef vector<long,2> point;

    /*!A dpoint
        This is just a typedef of the vector object.
    !*/

    typedef vector<double,2> dpoint;

// ----------------------------------------------------------------------------------------

}

namespace std
{
    /*!
        Define std::less<vector<T,3> > so that you can use vectors in the associative containers.
    !*/
    template<typename T>
    struct less<dlib::vector<T,3> > : public binary_function<dlib::vector<T,3> ,dlib::vector<T,3> ,bool>
    {
        inline bool operator() (const dlib::vector<T,3> & a, const dlib::vector<T,3> & b) const
        {
            if      (a.x() < b.x()) return true;
            else if (a.x() > b.x()) return false;
            else if (a.y() < b.y()) return true;
            else if (a.y() > b.y()) return false;
            else if (a.z() < b.z()) return true;
            else if (a.z() > b.z()) return false;
            else                    return false;
        }
    };

    /*!
        Define std::less<vector<T,2> > so that you can use vector<T,2>s in the associative containers.
    !*/
    template<typename T>
    struct less<dlib::vector<T,2> > : public binary_function<dlib::vector<T,2> ,dlib::vector<T,2> ,bool>
    {
        inline bool operator() (const dlib::vector<T,2> & a, const dlib::vector<T,2> & b) const
        {
            if      (a.x() < b.x()) return true;
            else if (a.x() > b.x()) return false;
            else if (a.y() < b.y()) return true;
            else if (a.y() > b.y()) return false;
            else                    return false;
        }
    };
}

#endif // DLIB_VECTOR_ABSTRACT_


dlib C++ Library - sparse_vector_abstract.h

// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SVm_SPARSE_VECTOR_ABSTRACT_
#ifdef DLIB_SVm_SPARSE_VECTOR_ABSTRACT_

#include <cmath>
#include "../algs.h"
#include "../serialize.h"
#include "../matrix.h"
#include <map>
#include <vector>
#include "../graph_utils/sample_pair_abstract.h"
#include "../graph_utils/ordered_sample_pair_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    /*!A sparse_vectors

        In dlib, sparse vectors are represented using the container objects
        in the C++ STL.  In particular, a sparse vector is any container that
        contains a range of std::pair<key, scalar_value> objects where:
            - key is an unsigned integral type
            - scalar_value is float, double, or long double
            - the std::pair objects have unique key values
            - the std::pair objects are sorted such that small keys come first

        Therefore, if an object satisfies the above requirements we call it a
        "sparse vector".  Additionally, we define the concept of an "unsorted sparse vector"
        to be a sparse vector that doesn't necessarily have sorted or unique key values.
        Therefore, all sparse vectors are valid unsorted sparse vectors but not the other
        way around.

        An unsorted sparse vector with duplicate keys is always interpreted as
        a vector where each dimension contains the sum of all corresponding elements
        of the unsorted sparse vector.  For example, an unsorted sparse vector
        with the elements { (3,1), (0, 4), (3,5) } represents the 4D vector:
            [4, 0, 0, 1+5]

        Examples of valid sparse vectors are:
            - std::map<unsigned long, double>
            - std::vector<std::pair<unsigned long, float> > where the vector is sorted.
              (you could make sure it was sorted by applying std::sort to it)

        Finally, by "dense vector" we mean a dlib::matrix object which represents
        either a row or column vector.

        The rest of this file defines a number of helper functions for doing normal
        vector arithmetic things with sparse vectors.
    !*/

// ----------------------------------------------------------------------------------------

    /*!A has_unsigned_keys

        This is a template where has_unsigned_keys<T>::value == true when T is a
        sparse vector that contains unsigned integral keys and false otherwise.
    !*/

    template <typename T>
    struct has_unsigned_keys
    {
        static const bool value = is_unsigned_type<typename T::value_type::first_type>::value;
    };

// ----------------------------------------------------------------------------------------

    template <typename T, typename U>
    typename T::value_type::second_type distance_squared (
        const T& a,
        const U& b
    );
    /*!
        requires
            - a and b are sparse vectors
        ensures
            - returns the squared distance between the vectors
              a and b
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T, typename U, typename V, typename W>
    typename T::value_type::second_type distance_squared (
        const V& a_scale,
        const T& a,
        const W& b_scale,
        const U& b
    );
    /*!
        requires
            - a and b are sparse vectors
        ensures
            - returns the squared distance between the vectors
              a_scale*a and b_scale*b
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T, typename U>
    typename T::value_type::second_type distance (
        const T& a,
        const U& b
    );
    /*!
        requires
            - a and b are sparse vectors
        ensures
            - returns the distance between the vectors
              a and b.  (i.e. std::sqrt(distance_squared(a,b)))
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T, typename U, typename V, typename W>
    typename T::value_type::second_type distance (
        const V& a_scale,
        const T& a,
        const W& b_scale,
        const U& b
    );
    /*!
        requires
            - a and b are sparse vectors
        ensures
            - returns the distance between the vectors
              a_scale*a and b_scale*b.  (i.e. std::sqrt(distance_squared(a_scale,a,b_scale,b)))
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T, typename U>
    void assign (
        T& dest,
        const U& src
    );
    /*!
        requires
            - dest == a sparse vector or a dense vector
            - src == a sparse vector or a dense vector
            - dest is not dense when src is sparse
              (i.e. you can't assign a sparse vector to a dense vector.  This is
              because we don't know what the proper dimensionality should be for the
              dense vector)
        ensures
            - #src represents the same vector as dest.
              (conversion between sparse/dense formats is done automatically)
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    typename T::value_type::second_type dot (
        const T& a,
        const T& b
    );
    /*!
        requires
            - a and b are sparse vectors
        ensures
            - returns the dot product between the vectors a and b
    !*/

    template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
    T4 dot (
        const std::vector<T1,T2>& a,
        const std::map<T3,T4,T5,T6>& b
    );
    /*!
        requires
            - a and b are sparse vectors
        ensures
            - returns the dot product between the vectors a and b
    !*/

    template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
    T4 dot (
        const std::map<T3,T4,T5,T6>& a,
        const std::vector<T1,T2>& b
    );
    /*!
        requires
            - a and b are sparse vectors
        ensures
            - returns the dot product between the vectors a and b
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T, typename EXP>
    typename T::value_type::second_type dot (
        const T& a,
        const matrix_exp<EXP>& b
    );
    /*!
        requires
            - a is an unsorted sparse vector
            - is_vector(b) == true
        ensures
            - returns the dot product between the vectors a and b.
            - if (max_index_plus_one(a) >= b.size()) then
                - a's dimensionality is greater than b's dimensionality.  In this case we
                  pretend b is padded by as many zeros as is needed to make the dot product
                  work.  So this means that any elements in a that go beyond the length of
                  b are simply ignored.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T, typename EXP>
    typename T::value_type::second_type dot (
        const matrix_exp<EXP>& a,
        const T& b
    );
    /*!
        requires
            - b is an unsorted sparse vector
            - is_vector(a) == true
        ensures
            - returns the dot product between the vectors a and b
            - if (max_index_plus_one(b) >= a.size()) then
                - b's dimensionality is greater than a's dimensionality.  In this case we
                  pretend a is padded by as many zeros as is needed to make the dot product
                  work.  So this means that any elements in b that go beyond the length of
                  a are simply ignored.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    typename T::value_type::second_type length_squared (
        const T& a
    );
    /*!
        requires
            - a is a sparse vector
        ensures
            - returns dot(a,a)
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    typename T::value_type::second_type length (
        const T& a
    );
    /*!
        requires
            - a is a sparse vector
        ensures
            - returns std::sqrt(length_squared(a,a))
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T, typename U>
    void scale_by (
        T& a,
        const U& value
    );
    /*!
        requires
            - a is an unsorted sparse vector or a dlib::matrix
        ensures
            - #a == a*value
              (i.e. multiplies every element of the vector a by value)
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    T add (
        const T& a,
        const T& b
    );
    /*!
        requires
            - a is a sparse vector or dlib::matrix
            - b is a sparse vector or dlib::matrix
        ensures
            - returns a vector or matrix which represents a+b.  If the inputs are
              sparse vectors then the result is a sparse vector.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    T subtract (
        const T& a,
        const T& b
    );
    /*!
        requires
            - a is a sparse vector or dlib::matrix
            - b is a sparse vector or dlib::matrix
        ensures
            - returns a vector or matrix which represents a-b.  If the inputs are
              sparse vectors then the result is a sparse vector.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    unsigned long max_index_plus_one (
        const T& samples
    );
    /*!
        requires
            - samples == a single vector (either sparse or dense), or a container
              of vectors which is either a dlib::matrix of vectors or something
              convertible to a dlib::matrix via mat() (e.g. a std::vector)
              Valid types of samples include (but are not limited to):
                - dlib::matrix<double,0,1>                      // A single dense vector
                - std::map<unsigned int, double>                // A single sparse vector
                - std::vector<dlib::matrix<double,0,1> >        // An array of dense vectors
                - std::vector<std::map<unsigned int, double> >  // An array of sparse vectors
        ensures
            - This function tells you the dimensionality of a set of vectors.  The vectors
              can be either sparse or dense.
            - if (samples.size() == 0) then
                - returns 0
            - else if (samples contains dense vectors or is a dense vector) then
                - returns the number of elements in the first sample vector.  This means
                  we implicitly assume all dense vectors have the same length)
            - else
                - In this case samples contains sparse vectors or is a sparse vector.
                - returns the largest element index in any sample + 1.  Note that the element index values
                  are the values stored in std::pair::first.  So this number tells you the dimensionality
                  of a set of sparse vectors.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T, long NR, long NC, typename MM, typename L, typename SRC, typename U>
    inline void add_to (
        matrix<T,NR,NC,MM,L>& dest,
        const SRC& src,
        const U& C = 1
    );
    /*!
        requires
            - SRC == a matrix expression or an unsorted sparse vector
            - is_vector(dest) == true
            - Let MAX denote the largest element index in src.
              Then we require that:
                - MAX < dest.size()
                - (i.e. dest needs to be big enough to contain all the elements of src)
        ensures
            - #dest == dest + C*src
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T, long NR, long NC, typename MM, typename L, typename SRC, typename U>
    inline void subtract_from (
        matrix<T,NR,NC,MM,L>& dest,
        const SRC& src,
        const U& C = 1
    );
    /*!
        requires
            - SRC == a matrix expression or an unsorted sparse vector
            - is_vector(dest) == true
            - Let MAX denote the largest element index in src.
              Then we require that:
                - MAX < dest.size()
                - (i.e. dest needs to be big enough to contain all the elements of src)
        ensures
            - #dest == dest - C*src
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    typename T::value_type::second_type min (
        const T& vect
    );
    /*!
        requires
            - T == an unsorted sparse vector
        ensures
            - returns the minimum value in the sparse vector vect.  Note that
              this value is always <= 0 since a sparse vector has an unlimited number
              of 0 elements.
    !*/

// ------------------------------------------------------------------------------------

    template <typename T>
    typename T::value_type::second_type max (
        const T& vect
    );
    /*!
        requires
            - T == an unsorted sparse vector
        ensures
            - returns the maximum value in the sparse vector vect.  Note that
              this value is always >= 0 since a sparse vector has an unlimited number
              of 0 elements.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename sample_type
        >
    matrix<typename sample_type::value_type::second_type,0,1> sparse_to_dense (
        const sample_type& vect
    );
    /*!
        requires
            - vect must be a sparse vector or a dense column vector.
        ensures
            - converts the single sparse or dense vector vect to a dense (column matrix form)
              representation.  That is, this function returns a vector V such that:
                - V.size() == max_index_plus_one(vect)
                - for all valid j:
                    - V(j) == The value of the j'th dimension of the vector vect.  Note
                      that V(j) is zero if it is a sparse vector that doesn't contain an
                      entry for the j'th dimension.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename sample_type
        >
    matrix<typename sample_type::value_type::second_type,0,1> sparse_to_dense (
        const sample_type& vect,
        unsigned long num_dimensions
    );
    /*!
        requires
            - vect must be a sparse vector or a dense column vector.
        ensures
            - converts the single sparse or dense vector vect to a dense (column matrix form)
              representation.  That is, this function returns a vector V such that:
                - V.size() == num_dimensions
                - for all valid j:
                    - V(j) == The value of the j'th dimension of the vector vect.  Note
                      that V(j) is zero if it is a sparse vector that doesn't contain an
                      entry for the j'th dimension.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename sample_type,
        typename alloc
        >
    std::vector<matrix<typename sample_type::value_type::second_type,0,1> > sparse_to_dense (
        const std::vector<sample_type, alloc>& samples
    );
    /*!
        requires
            - all elements of samples must be sparse vectors or dense column vectors.
        ensures
            - converts from sparse sample vectors to dense (column matrix form)
            - That is, this function returns a std::vector R such that:
                - R contains column matrices
                - R.size() == samples.size()
                - for all valid i:
                    - R[i] == sparse_to_dense(samples[i], max_index_plus_one(samples))
                      (i.e. the dense (i.e. dlib::matrix) version of the sparse sample
                      given by samples[i].)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename sample_type,
        typename alloc
        >
    std::vector<matrix<typename sample_type::value_type::second_type,0,1> > sparse_to_dense (
        const std::vector<sample_type, alloc>& samples,
        unsigned long num_dimensions
    );
    /*!
        requires
            - all elements of samples must be sparse vectors or dense column vectors.
        ensures
            - converts from sparse sample vectors to dense (column matrix form)
            - That is, this function returns a std::vector R such that:
                - R contains column matrices
                - R.size() == samples.size()
                - for all valid i:
                    - R[i] == sparse_to_dense(samples[i], num_dimensions)
                      (i.e. the dense (i.e. dlib::matrix) version of the sparse sample
                      given by samples[i].)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    T make_sparse_vector (
        const T& v
    );
    /*!
        requires
            - v is an unsorted sparse vector
        ensures
            - returns a copy of v which is a sparse vector.
              (i.e. it will be properly sorted and not have any duplicate key values but
              will still logically represent the same vector).
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    void make_sparse_vector_inplace(
        T& vect
    );
    /*!
        requires
            - v is an unsorted sparse vector
        ensures
            - vect == make_sparse_vector(vect)
            - This function is just an optimized version of make_sparse_vector(), in
              particular, when T is a std::vector<std::pair<>> type it is much more
              efficient.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename EXP,
        typename T,
        long NR,
        long NC,
        typename MM,
        typename L
        >
    void sparse_matrix_vector_multiply (
        const std::vector<sample_pair>& edges,
        const matrix_exp<EXP>& v,
        matrix<T,NR,NC,MM,L>& result
    );
    /*!
        requires
            - is_col_vector(v) == true
            - max_index_plus_one(edges) <= v.size()
        ensures
            - Interprets edges as representing a symmetric sparse matrix M.  The elements
              of M are defined such that, for all valid i,j:
                - M(i,j) == sum of edges[k].distance() for all k where edges[k]==sample_pair(i,j)
                - This means that any element of M that doesn't have any edges associated
                  with it will have a value of 0.
            - #result == M*v
              (i.e. this function multiplies the vector v with the sparse matrix
              represented by edges and stores the output into result)
            - get_rect(#result) == get_rect(v)
              (i.e. result will have the same dimensions as v)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename EXP,
        typename T,
        long NR,
        long NC,
        typename MM,
        typename L
        >
    void sparse_matrix_vector_multiply (
        const std::vector<ordered_sample_pair>& edges,
        const matrix_exp<EXP>& v,
        matrix<T,NR,NC,MM,L>& result
    );
    /*!
        requires
            - is_col_vector(v) == true
            - max_index_plus_one(edges) <= v.size()
        ensures
            - Interprets edges as representing a square sparse matrix M.  The elements of M
              are defined such that, for all valid i,j:
                - M(i,j) == sum of edges[k].distance() for all k where edges[k]==ordered_sample_pair(i,j)
                - This means that any element of M that doesn't have any edges associated
                  with it will have a value of 0.
            - #result == M*v
              (i.e. this function multiplies the vector v with the sparse matrix
              represented by edges and stores the output into result)
            - get_rect(#result) == get_rect(v)
              (i.e. result will have the same dimensions as v)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename EXP
        >
    matrix<typename EXP::type,0,1> sparse_matrix_vector_multiply (
        const std::vector<sample_pair>& edges,
        const matrix_exp<EXP>& v
    );
    /*!
        requires
            - is_col_vector(v) == true
            - max_index_plus_one(edges) <= v.size()
        ensures
            - This is just a convenience routine for invoking the above
              sparse_matrix_vector_multiply() routine.  In particular, it just calls
              sparse_matrix_vector_multiply() with a temporary result matrix and then
              returns the result.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename EXP
        >
    matrix<typename EXP::type,0,1> sparse_matrix_vector_multiply (
        const std::vector<ordered_sample_pair>& edges,
        const matrix_exp<EXP>& v
    );
    /*!
        requires
            - is_col_vector(v) == true
            - max_index_plus_one(edges) <= v.size()
        ensures
            - This is just a convenience routine for invoking the above
              sparse_matrix_vector_multiply() routine.  In particular, it just calls
              sparse_matrix_vector_multiply() with a temporary result matrix and then
              returns the result.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename EXP,
        typename sparse_vector_type,
        typename T,
        long NR,
        long NC,
        typename MM,
        typename L
        >
    void sparse_matrix_vector_multiply (
        const matrix_exp<EXP>& m,
        const sparse_vector_type& v,
        matrix<T,NR,NC,MM,L>& result
    );
    /*!
        requires
            - max_index_plus_one(v) <= m.nc()
            - v == an unsorted sparse vector
        ensures
            - #result == m*v
              (i.e. multiply m by the vector v and store the output in result)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename EXP,
        typename sparse_vector_type
        >
    matrix<typename EXP::type,0,1> sparse_matrix_vector_multiply (
        const matrix_exp<EXP>& m,
        const sparse_vector_type& v
    );
    /*!
        requires
            - max_index_plus_one(v) <= m.nc()
            - v == an unsorted sparse vector
        ensures
            - returns m*v
              (i.e. multiply m by the vector v and return the resulting vector)
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SVm_SPARSE_VECTOR_ABSTRACT_


dlib C++ Library - Machine Learning

The Library
  • Algorithms
  • API Wrappers
  • Bayesian Nets
  • Compression
  • Containers
  • Graph Tools
  • Image Processing
  • Linear Algebra
  • Machine Learning
  • Metaprogramming
  • Miscellaneous
  • Networking
  • Optimization
  • Parsing

Help/Info
  • Dlib Blog
  • Examples: C++
    • 3D Point Cloud
    • Assignment Learning
    • Base64 Encoder
    • Bayesian Network From Disk
    • Bayesian Network GUI
    • Bayesian Network
    • Bridge
    • BSP
    • C-Support Vector Machine
    • Cmd Line Parser
    • Compress Stream
    • Config File Reader
    • Custom Trainers
    • Directory Navigation
    • Empirical Kernel Map
    • Face Detection
    • Face Landmark Detection
    • FHOG Feature Extraction
    • FHOG Object Detection
    • Graph Labeling
    • GUI
    • Hough Transform
    • HTTP Server
    • Image
    • IO Socket Streams
    • IO Streams Server
    • Kernel Centroid
    • Kernel K-Means Clustering
    • Kernel Ridge Regression
    • Kernel RLS Filtering
    • Kernel RLS Regression
    • KRR Classification
    • Learning to Track
    • Linear Assignment Problems
    • Linear Manifold Regularizer
    • Linear Model Predictive Control
    • Logger Advanced
    • Logger Custom Output
    • Logger
    • Matrix Expressions
    • Matrix
    • Member Function Pointer
    • Model Selection
    • Multiclass Classification
    • Multithreaded Object
    • Neural Network
    • Non-Linear Least Squares
    • Nu-Support Vector Machine
    • Numerical Integration
    • Object Detector Advanced
    • Object Detector
    • One Class Classifiers
    • Online SVM
    • Optimization
    • Parallel For Loops
    • Pipe 2
    • Pipe
    • Quantum Computing
    • Queue
    • Rank Features
    • Relevance Vector Classification
    • Relevance Vector Regression
    • Running Stats
    • Sequence Labeling
    • Sequence Segmentation
    • Sockets
    • Sockstreambuf
    • Sparse Vectors
    • SQLite
    • Std C++ Allocator
    • Structural Support Vector Machines
    • Support Vector Regression
    • SURF
    • SVM-Rank
    • Thread Function
    • Thread Pool
    • Threaded Object
    • Threads
    • Timer
    • Train Object Detector
    • Train Shape Predictor
    • Using Custom Kernels
    • Video Object Tracking
    • Webcam Face Pose Estimation
    • XML Parser
  • Examples: Python
    • Face Detector
    • Face Landmark Detection
    • find candidate object locations
    • Linear Assignment Problems
    • Sequence Segmenter
    • Structural Support Vector Machines
    • SVM-Rank
    • Train Object Detector
    • Train Shape Predictor
    • Video Object Tracking
  • FAQ
  • Forums
  • Home
  • How to compile
  • How to contribute
  • Index
  • Introduction
  • License
  • Python API
  • Suggested Books
  • Who uses dlib?

Current Release
  • Change Log
  • Release Notes
  • Version: 18.18

Last Modified:
Sep 13, 2015
Machine Learning

A major design goal of this portion of the library is to provide a highly modular and simple architecture for dealing with kernel algorithms. Towards this end, dlib takes a generic programming approach using C++ templates. In particular, each algorithm is parameterized to allow a user to supply either one of the predefined dlib kernels (e.g. RBF operating on column vectors), or a new user defined kernel. Moreover, the implementations of the algorithms are totally separated from the data on which they operate. This makes the dlib implementation generic enough to operate on any kind of data, be it column vectors, images, or some other form of structured data. All that is necessary is an appropriate kernel.

Paper Describing dlib Machine Learning

Davis E. King. Dlib-ml: A Machine Learning Toolkit.
   Journal of Machine Learning Research 10, pp. 1755-1758, 2009

@Article{dlib09,
  author = {Davis E. King},
  title = {Dlib-ml: A Machine Learning Toolkit},
  journal = {Journal of Machine Learning Research},
  year = {2009},
  volume = {10},
  pages = {1755-1758},
}

Primary Algorithms

Binary Classification
  • rvm_trainer
  • svm_c_ekm_trainer
  • svm_c_linear_dcd_trainer
  • svm_c_linear_trainer
  • svm_c_trainer
  • svm_nu_trainer
  • svm_pegasos
  • train_probabilistic_decision_function

Multiclass Classification
  • one_vs_all_trainer
  • one_vs_one_trainer
  • svm_multiclass_linear_trainer

Regression
  • krls
  • krr_trainer
  • mlp
  • rbf_network_trainer
  • rls
  • rr_trainer
  • rvm_regression_trainer
  • svr_linear_trainer
  • svr_trainer

Structured Prediction
  • Core Tools
    • structural_svm_problem
    • structural_svm_problem_threaded
    • svm_struct_controller_node
    • svm_struct_processing_node
  • Problem Instances
    • structural_svm_assignment_problem
    • structural_svm_graph_labeling_problem
    • structural_svm_object_detection_problem
    • structural_svm_sequence_labeling_problem
  • shape_predictor_trainer
  • structural_assignment_trainer
  • structural_graph_labeling_trainer
  • structural_object_detection_trainer
  • structural_sequence_labeling_trainer
  • structural_sequence_segmentation_trainer
  • structural_track_association_trainer
  • svm_rank_trainer

Clustering
  • bottom_up_cluster
  • chinese_whispers
  • find_clusters_using_angular_kmeans
  • find_clusters_using_kmeans
  • kkmeans
  • modularity
  • nearest_center
  • newman_cluster
  • pick_initial_centers
  • spectral_cluster

Unsupervised
  • cca
  • empirical_kernel_map
  • kcentroid
  • linearly_independent_subset_finder
  • sammon_projection
  • svm_one_class_trainer
  • vector_normalizer
  • vector_normalizer_pca

Semi-Supervised/Metric Learning
  • compute_lda_transform
  • discriminant_pca
  • linear_manifold_regularizer
  • vector_normalizer_frobmetric

Reinforcement Learning
  • lspi

Feature Selection
  • rank_features
  • rank_unlabeled_training_samples
  • sort_basis_vectors

Other Tools

Validation
  • average_precision
  • cross_validate_assignment_trainer
  • cross_validate_graph_labeling_trainer
  • cross_validate_multiclass_trainer
  • cross_validate_object_detection_trainer
  • cross_validate_ranking_trainer
  • cross_validate_regression_trainer
  • cross_validate_sequence_labeler
  • cross_validate_sequence_segmenter
  • cross_validate_track_association_trainer
  • cross_validate_trainer
  • cross_validate_trainer_threaded
  • equal_error_rate
  • test_assignment_function
  • test_binary_decision_function
  • test_graph_labeling_function
  • test_multiclass_decision_function
  • test_object_detection_function
  • test_ranking_function
  • test_regression_function
  • test_sequence_labeler
  • test_sequence_segmenter
  • test_shape_predictor
  • test_track_association_function

Trainer Adapters
  • batch
  • batch_cached
  • null_trainer
  • probabilistic
  • reduced
  • reduced2
  • roc_c1_trainer
  • roc_c2_trainer
  • verbose_batch
  • verbose_batch_cached

Kernels
  • histogram_intersection_kernel
  • linear_kernel
  • offset_kernel
  • polynomial_kernel
  • radial_basis_kernel
  • sigmoid_kernel
  • sparse_histogram_intersection_kernel
  • sparse_linear_kernel
  • sparse_polynomial_kernel
  • sparse_radial_basis_kernel
  • sparse_sigmoid_kernel

Function Objects
  • assignment_function
  • decision_function
  • distance_function
  • graph_labeler
  • multiclass_linear_decision_function
  • normalized_function
  • one_vs_all_decision_function
  • one_vs_one_decision_function
  • policy
  • probabilistic_decision_function
  • probabilistic_function
  • projection_function
  • sequence_labeler
  • sequence_segmenter
  • track_association_function

Data IO
  • fix_nonzero_indexing
  • load_image_dataset
  • load_image_dataset_metadata
  • load_libsvm_formatted_data
  • save_image_dataset_metadata
  • save_libsvm_formatted_data

Miscellaneous
  • approximate_distance_function
  • compute_mean_squared_distance
  • count_ranking_inversions
  • fill_lisf
  • find_gamma_with_big_centroid_gap
  • is_assignment_problem
  • is_binary_classification_problem
  • is_forced_assignment_problem
  • is_graph_labeling_problem
  • is_learning_problem
  • is_ranking_problem
  • is_sequence_labeling_problem
  • is_sequence_segmentation_problem
  • is_track_association_problem
  • kernel_matrix
  • learn_platt_scaling
  • process_sample
  • randomize_samples
  • ranking_pair
  • select_all_distinct_labels
  • simplify_linear_decision_function

[top]

approximate_distance_function

This function attempts to find a distance_function object which is close to a target distance_function. That is, it searches for an X such that target(X) is minimized. Critically, X may be set to use fewer basis vectors than the target.

The optimization begins with an initial guess supplied by the user and searches for an X which locally minimizes target(X). Since this problem can have many local minima the quality of the starting point can significantly influence the results.

More Details...
#include <dlib/svm.h>
[top]

assignment_function

This object is a tool for solving the optimal assignment problem given a user defined method for computing the quality of any particular assignment.

C++ Example Programs: assignment_learning_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

average_precision

This function computes the average precision of a ranking.
More Details...
#include <dlib/statistics.h>
[top]

batch

This is a convenience function for creating batch_trainer objects.

C++ Example Programs: svm_pegasos_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

batch_cached

This is a convenience function for creating batch_trainer objects that are setup to use a kernel matrix cache.
More Details...
#include <dlib/svm.h>
[top]

batch_trainer

This is a batch trainer object that is meant to wrap online trainer objects that create decision_functions. It turns an online learning algorithm such as svm_pegasos into a batch learning object. This allows you to use objects like svm_pegasos with functions (e.g. cross_validate_trainer) that expect batch mode training objects.
More Details...
#include <dlib/svm.h>
[top]

bottom_up_cluster

This function runs a bottom up agglomerative clustering algorithm.
More Details...
#include <dlib/clustering.h>
[top]

cca

This function performs a canonical correlation analysis between two sets of vectors. Additionally, it is designed to be very fast, even for large datasets of over a million high dimensional vectors.
More Details...
#include <dlib/statistics.h>
[top]

chinese_whispers

This function performs the clustering algorithm described in the paper
Chinese Whispers - an Efficient Graph Clustering Algorithm and its Application to Natural Language Processing Problems by Chris Biemann.
In particular, this is a method for automatically clustering the nodes in a graph into groups. The method is able to automatically determine the number of clusters.
More Details...
#include <dlib/clustering.h>
[top]

compute_lda_transform

This function performs the dimensionality reducing version of linear discriminant analysis. That is, you give it a set of labeled vectors and it returns a linear transform that maps the input vectors into a new space that is good for distinguishing between the different classes.
More Details...
#include <dlib/statistics.h>
[top]

compute_mean_squared_distance

This is a function that simply finds the average squared distance between all pairs of a set of data samples. It is often convenient to use the reciprocal of this value as the estimate of the gamma parameter of the radial_basis_kernel.
More Details...
#include <dlib/svm.h>
[top]

count_ranking_inversions

Given two sets of objects, X and Y, and an ordering relationship defined between their elements, this function counts how many times we see an element in the set Y ordered before an element in the set X. Additionally, this routine executes efficiently in O(n*log(n)) time via the use of quick sort.
More Details...
#include <dlib/svm.h>
[top]

cross_validate_assignment_trainer

Performs k-fold cross validation on a user supplied assignment trainer object such as the structural_assignment_trainer and returns the fraction of assignments predicted correctly.

C++ Example Programs: assignment_learning_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

cross_validate_graph_labeling_trainer

Performs k-fold cross validation on a user supplied graph labeling trainer object such as the structural_graph_labeling_trainer and returns the fraction of assignments predicted correctly.

C++ Example Programs: graph_labeling_ex.cpp
More Details...
#include <dlib/svm_threaded.h>
[top]

cross_validate_multiclass_trainer

Performs k-fold cross validation on a user supplied multiclass classification trainer object such as the one_vs_one_trainer. The result is described by a confusion matrix.

C++ Example Programs: multiclass_classification_ex.cpp, custom_trainer_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

cross_validate_object_detection_trainer

Performs k-fold cross validation on a user supplied object detection trainer such as the structural_object_detection_trainer and returns the precision and recall.

C++ Example Programs: object_detector_ex.cpp, object_detector_advanced_ex.cpp, train_object_detector.cpp
More Details...
#include <dlib/svm.h>
[top]

cross_validate_ranking_trainer

Performs k-fold cross validation on a user supplied ranking trainer object such as the svm_rank_trainer and returns the fraction of ranking pairs ordered correctly as well as the mean average precision.

C++ Example Programs: svm_rank_ex.cpp
Python Example Programs: svm_rank.py
More Details...
#include <dlib/svm.h>
[top]

cross_validate_regression_trainer

Performs k-fold cross validation on a user supplied regression trainer object such as the svr_trainer and returns the mean squared error and R-squared value.

C++ Example Programs: svr_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

cross_validate_sequence_labeler

Performs k-fold cross validation on a user supplied sequence labeling trainer object such as the structural_sequence_labeling_trainer and returns a confusion matrix describing the results.

C++ Example Programs: sequence_labeler_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

cross_validate_sequence_segmenter

Performs k-fold cross validation on a user supplied sequence segmentation trainer object such as the structural_sequence_segmentation_trainer and returns the resulting precision, recall, and F1-score.

C++ Example Programs: sequence_segmenter_ex.cpp
Python Example Programs: sequence_segmenter.py,
More Details...
#include <dlib/svm.h>
[top]

cross_validate_track_association_trainer

Performs k-fold cross validation on a user supplied track association trainer object such as the structural_track_association_trainer and returns the fraction of detections which were correctly associated to their tracks.

C++ Example Programs: learning_to_track_ex.cpp
More Details...
#include <dlib/svm_threaded.h>
[top]

cross_validate_trainer

Performs k-fold cross validation on a user supplied binary classification trainer object such as the svm_nu_trainer or rbf_network_trainer.

C++ Example Programs: svm_ex.cpp, model_selection_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

cross_validate_trainer_threaded

Performs k-fold cross validation on a user supplied binary classification trainer object such as the svm_nu_trainer or rbf_network_trainer. This function does the same thing as cross_validate_trainer except this function also allows you to specify how many threads of execution to use. So you can use this function to take advantage of a multi-core system to perform cross validation faster.
More Details...
#include <dlib/svm_threaded.h>
[top]

decision_function

This object represents a classification or regression function that was learned by a kernel based learning algorithm. Therefore, it is a function object that takes a sample object and returns a scalar value.

C++ Example Programs: svm_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

discriminant_pca

This object implements the Discriminant PCA technique described in the paper:
A New Discriminant Principal Component Analysis Method with Partial Supervision (2009) by Dan Sun and Daoqiang Zhang
This algorithm is basically a straightforward generalization of the classical PCA technique to handle partially labeled data. It is useful if you want to learn a linear dimensionality reduction rule using a bunch of data that is partially labeled.
More Details...
#include <dlib/statistics.h>
[top]

distance_function

This object represents a point in kernel induced feature space. You may use this object to find the distance from the point it represents to points in input space as well as other points represented by distance_functions.
More Details...
#include <dlib/svm.h>
[top]

empirical_kernel_map

This object represents a map from objects of sample_type (the kind of object a kernel function operates on) to finite dimensional column vectors which represent points in the kernel feature space defined by whatever kernel is used with this object.

To use the empirical_kernel_map you supply it with a particular kernel and a set of basis samples. After that you can present it with new samples and it will project them into the part of kernel feature space spanned by your basis samples.

This means the empirical_kernel_map is a tool you can use to very easily kernelize any algorithm that operates on column vectors. All you have to do is select a set of basis samples and then use the empirical_kernel_map to project all your data points into the part of kernel feature space spanned by those basis samples. Then just run your normal algorithm on the output vectors and it will be effectively kernelized.

Regarding methods to select a set of basis samples, if you are working with only a few thousand samples then you can just use all of them as basis samples. Alternatively, the linearly_independent_subset_finder often works well for selecting a basis set. I also find that picking a random subset typically works well.

C++ Example Programs: empirical_kernel_map_ex.cpp, linear_manifold_regularizer_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

equal_error_rate

This function finds a threshold that best separates the elements of two vectors by selecting the threshold with equal error rate. It also reports the value of the equal error rate.
More Details...
#include <dlib/statistics.h>
[top]

fill_lisf

This is a simple function for filling a linearly_independent_subset_finder with data points by using random sampling.

C++ Example Programs: empirical_kernel_map_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

find_clusters_using_angular_kmeans

This is a simple linear kmeans clustering implementation. To compare a sample to a cluster, it measures the angle between them with respect to the origin. Therefore, it tries to find clusters of points that all have small angles between each cluster member.
More Details...
#include <dlib/clustering.h>
[top]

find_clusters_using_kmeans

This is a simple linear kmeans clustering implementation. It uses Euclidean distance to compare samples.
More Details...
#include <dlib/clustering.h>
[top]

find_gamma_with_big_centroid_gap

This is a function that tries to pick a reasonable default value for the gamma parameter of the radial_basis_kernel. It picks the parameter that gives the largest separation between the centroids, in kernel feature space, of two classes of data.

C++ Example Programs: rank_features_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

fix_nonzero_indexing

This is a simple function that takes a std::vector of sparse vectors and makes sure they are zero-indexed (e.g. makes sure the first index value is zero).
More Details...
#include <dlib/data_io.h>
[top]

graph_labeler

This object is a tool for labeling each node in a graph with a value of true or false, subject to a labeling consistency constraint between nodes that share an edge. In particular, this object is useful for representing a graph labeling model learned via some machine learning method, such as the structural_graph_labeling_trainer.

C++ Example Programs: graph_labeling_ex.cpp
More Details...
#include <dlib/graph_cuts.h>
[top]

histogram_intersection_kernel

This object represents a histogram intersection kernel for use with kernel learning machines.
More Details...
#include <dlib/svm.h>
[top]

is_assignment_problem

This function takes a set of training data for an assignment problem and reports back if it could possibly be a well formed assignment problem.
More Details...
#include <dlib/svm.h>
[top]

is_binary_classification_problem

This function simply takes two vectors, the first containing feature vectors and the second containing labels, and reports back if the two could possibly contain data for a well formed classification problem.
More Details...
#include <dlib/svm.h>
[top]

is_forced_assignment_problem

This function takes a set of training data for a forced assignment problem and reports back if it could possibly be a well formed forced assignment problem.
More Details...
#include <dlib/svm.h>
[top]

is_graph_labeling_problem

This function takes a set of training data for a graph labeling problem and reports back if it could possibly be a well formed problem.
More Details...
#include <dlib/svm_threaded.h>
[top]

is_learning_problem

This function simply takes two vectors, the first containing feature vectors and the second containing labels, and reports back if the two could possibly contain data for a well formed learning problem. In this case it just means that the two vectors have the same length and aren't empty.
More Details...
#include <dlib/svm.h>
[top]

is_ranking_problem

This function takes a set of training data for a learning-to-rank problem and reports back if it could possibly be a well formed problem.
More Details...
#include <dlib/svm.h>
[top]

is_sequence_labeling_problem

This function takes a set of training data for a sequence labeling problem and reports back if it could possibly be a well formed sequence labeling problem.
More Details...
#include <dlib/svm.h>
[top]

is_sequence_segmentation_problem

This function takes a set of training data for a sequence segmentation problem and reports back if it could possibly be a well formed sequence segmentation problem.
More Details...
#include <dlib/svm.h>
[top]

is_track_association_problem

This function takes a set of training data for a track association learning problem and reports back if it could possibly be a well formed track association problem.
More Details...
#include <dlib/svm.h>
[top]

kcentroid

This object represents a weighted sum of sample points in a kernel induced feature space. It can be used to kernelize any algorithm that requires only the ability to perform vector addition, subtraction, scalar multiplication, and inner products.

An example use of this object is as an online algorithm for recursively estimating the centroid of a sequence of training points. This object then allows you to compute the distance between the centroid and any test points. So you can use this object to predict how similar a test point is to the data this object has been trained on (larger distances from the centroid indicate dissimilarity/anomalous points).

The object internally keeps a set of "dictionary vectors" that are used to represent the centroid. It manages these vectors using the sparsification technique described in the paper The Kernel Recursive Least Squares Algorithm by Yaakov Engel. This technique allows us to keep the number of dictionary vectors down to a minimum. In fact, the object has a user selectable tolerance parameter that controls the trade off between accuracy and number of stored dictionary vectors.

C++ Example Programs: kcentroid_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

kernel_matrix

This is a simple set of functions that makes it easy to turn a kernel object and a set of samples into a kernel matrix. It takes these two things and returns a matrix expression that represents the kernel matrix.
More Details...
#include <dlib/svm.h>
[top]

kkmeans

This is an implementation of a kernelized k-means clustering algorithm. It performs k-means clustering by using the kcentroid object.

If you want to use the linear kernel (i.e. do a normal k-means clustering) then you should use the find_clusters_using_kmeans routine.

C++ Example Programs: kkmeans_ex.cpp
More Details...
#include <dlib/clustering.h>
[top]

krls

This is an implementation of the kernel recursive least squares algorithm described in the paper The Kernel Recursive Least Squares Algorithm by Yaakov Engel.

The long and short of this algorithm is that it is an online kernel based regression algorithm. You give it samples (x,y) and it learns the function f(x) == y. For a detailed description of the algorithm read the above paper.

Note that if you want to use the linear kernel then you would be better off using the rls object as it is optimized for this case.

C++ Example Programs: krls_ex.cpp, krls_filter_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

krr_trainer

Performs kernel ridge regression and outputs a decision_function that represents the learned function.

The implementation is done using the empirical_kernel_map and linearly_independent_subset_finder to kernelize the rr_trainer object. Thus it allows you to run the algorithm on large datasets and obtain sparse outputs. It is also capable of automatically estimating its regularization parameter using leave-one-out cross-validation.

C++ Example Programs: krr_regression_ex.cpp, krr_classification_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

learn_platt_scaling

This function is an implementation of the algorithm described in the following papers:

Probabilistic Outputs for Support Vector Machines and Comparisons to Regularized Likelihood Methods by John C. Platt. March 26, 1999

A Note on Platt's Probabilistic Outputs for Support Vector Machines by Hsuan-Tien Lin, Chih-Jen Lin, and Ruby C. Weng

This function is the tool used to implement the train_probabilistic_decision_function routine.

More Details...
#include <dlib/svm.h>
[top]

linearly_independent_subset_finder

This is an implementation of an online algorithm for recursively finding a set (aka dictionary) of linearly independent vectors in a kernel induced feature space. To use it you decide how large you would like the dictionary to be and then you feed it sample points.

The implementation uses the Approximately Linearly Dependent metric described in the paper The Kernel Recursive Least Squares Algorithm by Yaakov Engel to decide which points are more linearly independent than others. The metric is simply the squared distance between a test point and the subspace spanned by the set of dictionary vectors.

Each time you present this object with a new sample point it calculates the projection distance and if it is sufficiently large then this new point is included into the dictionary. Note that this object can be configured to have a maximum size. Once the max dictionary size is reached each new point kicks out a previous point. This is done by removing the dictionary vector that has the smallest projection distance onto the others. That is, the "least linearly independent" vector is removed to make room for the new one.

C++ Example Programs: empirical_kernel_map_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

linear_kernel

This object represents a linear function kernel for use with kernel learning machines.
More Details...
#include <dlib/svm.h>
[top]

linear_manifold_regularizer

Many learning algorithms attempt to minimize a function that, at a high level, looks like this:

   f(w) == complexity + training_set_error

The idea is to find the set of parameters, w, that gives low error on your training data but also is not "complex" according to some particular measure of complexity. This strategy of penalizing complexity is usually called regularization.

In the above setting, all the training data consists of labeled samples. However, it would be nice to be able to benefit from unlabeled data. The idea of manifold regularization is to extract useful information from unlabeled data by first defining which data samples are "close" to each other (perhaps by using their 3 nearest neighbors) and then adding a term to the above function that penalizes any decision rule which produces different outputs on data samples which we have designated as being close.

It turns out that it is possible to transform these manifold regularized learning problems into the normal form shown above by applying a certain kind of preprocessing to all our data samples. Once this is done we can use a normal learning algorithm, such as the svm_c_linear_trainer, on just the labeled data samples and obtain the same output as the manifold regularized learner would have produced.

The linear_manifold_regularizer is a tool for creating this preprocessing transformation. In particular, the transformation is linear. That is, it is just a matrix you multiply with all your samples. For a more detailed discussion of this topic you should consult the following paper. In particular, see section 4.2. This object computes the inverse T matrix described in that section.

Linear Manifold Regularization for Large Scale Semi-supervised Learning by Vikas Sindhwani, Partha Niyogi, and Mikhail Belkin

C++ Example Programs: linear_manifold_regularizer_ex.cpp
More Details...
#include <dlib/manifold_regularization.h>
[top]

load_image_dataset

This is a function which loads the list of images indicated by an image dataset metadata file as well as the box locations for each image. It makes loading the data necessary to train an object_detector a little more convenient.

C++ Example Programs: fhog_object_detector_ex.cpp, train_object_detector.cpp
More Details...
#include <dlib/data_io.h>
[top]

load_image_dataset_metadata

dlib comes with a graphical tool for annotating images with labeled rectangles. The tool produces an XML file containing these annotations. Therefore, load_image_dataset_metadata() is a routine for parsing these XML files. Note also that this is the metadata format used by the image labeling tool included with dlib in the tools/imglab folder.
More Details...
#include <dlib/data_io.h>
[top]

load_libsvm_formatted_data

This is a function that loads the data from a file that uses the LIBSVM format. It loads the data into a std::vector of sparse vectors. If you want to load data into dense vectors (i.e. dlib::matrix objects) then you can use the sparse_to_dense function to perform the conversion. Also, some LIBSVM formatted files number their features beginning with 1 rather than 0. If this bothers you, then you can fix it by using the fix_nonzero_indexing function on the data after it is loaded.
More Details...
#include <dlib/data_io.h>
[top]

lspi

This object is an implementation of the reinforcement learning algorithm described in the following paper:
Lagoudakis, Michail G., and Ronald Parr. "Least-squares policy iteration." The Journal of Machine Learning Research 4 (2003): 1107-1149.

More Details...
#include <dlib/control.h>
[top]

mlp

This object represents a multilayer layer perceptron network that is trained using the back propagation algorithm. The training algorithm also incorporates the momentum method. That is, each round of back propagation training also adds a fraction of the previous update. This fraction is controlled by the momentum term set in the constructor.

It is worth noting that a MLP is, in general, very inferior to modern kernel algorithms such as the support vector machine. So if you haven't tried any other techniques with your data you really should.

C++ Example Programs: mlp_ex.cpp
More Details...
#include <dlib/mlp.h>

Implementations:
mlp_kernel_1:
This is implemented in the obvious way.
kernel_1a
is a typedef for mlp_kernel_1
kernel_1a_c
 is a typedef for kernel_1a that checks its preconditions.
[top]

modularity

This function computes the modularity of a particular graph clustering. This is a number that tells you how good the clustering is. In particular, it is the measure optimized by the newman_cluster routine.
More Details...
#include <dlib/clustering.h>
[top]

multiclass_linear_decision_function

This object represents a multiclass classifier built out of a set of binary classifiers. Each binary classifier is used to vote for the correct multiclass label using a one vs. all strategy. Therefore, if you have N classes then there will be N binary classifiers inside this object. Additionally, this object is linear in the sense that each of these binary classifiers is a simple linear plane.
More Details...
#include <dlib/svm.h>
[top]

nearest_center

This function takes a list of cluster centers and a query vector and identifies which cluster center is nearest to the query vector.
More Details...
#include <dlib/clustering.h>
[top]

newman_cluster

This function performs the clustering algorithm described in the paper
Modularity and community structure in networks by M. E. J. Newman.
In particular, this is a method for automatically clustering the nodes in a graph into groups. The method is able to automatically determine the number of clusters and does not have any parameters. In general, it is a very good clustering technique.
More Details...
#include <dlib/clustering.h>
[top]

normalized_function

This object represents a container for another function object and an instance of the vector_normalizer object. It automatically normalizes all inputs before passing them off to the contained function object.

C++ Example Programs: svm_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

null_trainer

This is a convenience function for creating null_trainer_type objects.
More Details...
#include <dlib/svm.h>
[top]

null_trainer_type

This object is a simple tool for turning a decision_function (or any object with an interface compatible with decision_function) into a trainer object that always returns the original decision function when you try to train with it.

dlib contains a few "training post processing" algorithms (e.g. reduced and reduced2). These tools take in a trainer object, tell it to perform training, and then they take the output decision function and do some kind of post processing to it. The null_trainer_type object is useful because you can use it to run an already learned decision function through the training post processing algorithms by turning a decision function into a null_trainer_type and then giving it to a post processor.

More Details...
#include <dlib/svm.h>
[top]

offset_kernel

This object represents a kernel with a fixed value offset added to it.
More Details...
#include <dlib/svm.h>
[top]

one_vs_all_decision_function

This object represents a multiclass classifier built out of a set of binary classifiers. Each binary classifier is used to vote for the correct multiclass label using a one vs. all strategy. Therefore, if you have N classes then there will be N binary classifiers inside this object.
More Details...
#include <dlib/svm.h>
[top]

one_vs_all_trainer

This object is a tool for turning a bunch of binary classifiers into a multiclass classifier. It does this by training the binary classifiers in a one vs. all fashion. That is, if you have N possible classes then it trains N binary classifiers which are then used to vote on the identity of a test sample.
More Details...
#include <dlib/svm_threaded.h>
[top]

one_vs_one_decision_function

This object represents a multiclass classifier built out of a set of binary classifiers. Each binary classifier is used to vote for the correct multiclass label using a one vs. one strategy. Therefore, if you have N classes then there will be N*(N-1)/2 binary classifiers inside this object.

C++ Example Programs: multiclass_classification_ex.cpp, custom_trainer_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

one_vs_one_trainer

This object is a tool for turning a bunch of binary classifiers into a multiclass classifier. It does this by training the binary classifiers in a one vs. one fashion. That is, if you have N possible classes then it trains N*(N-1)/2 binary classifiers which are then used to vote on the identity of a test sample.

C++ Example Programs: multiclass_classification_ex.cpp, custom_trainer_ex.cpp
More Details...
#include <dlib/svm_threaded.h>
[top]

pick_initial_centers

This is a function that you can use to seed data clustering algorithms like the kkmeans clustering method. What it does is pick reasonable starting points for clustering by basically trying to find a set of points that are all far away from each other.

C++ Example Programs: kkmeans_ex.cpp
More Details...
#include <dlib/clustering.h>
[top]

policy

This is a policy (i.e. a control law) based on a linear function approximator. You can use a tool like lspi to learn the parameters of a policy.
More Details...
#include <dlib/control.h>
[top]

polynomial_kernel

This object represents a polynomial kernel for use with kernel learning machines.
More Details...
#include <dlib/svm.h>
[top]

probabilistic

This is a trainer adapter which simply runs the trainer it is given though the train_probabilistic_decision_function function.
More Details...
#include <dlib/svm.h>
[top]

probabilistic_decision_function

This object represents a binary decision function for use with kernel-based learning-machines. It returns an estimate of the probability that a given sample is in the +1 class.

C++ Example Programs: svm_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

probabilistic_function

This object represents a binary decision function for use with any kind of binary classifier. It returns an estimate of the probability that a given sample is in the +1 class.
More Details...
#include <dlib/svm.h>
[top]

process_sample

This object holds a training sample for a reinforcement learning algorithm (e.g. lspi). In particular, it contains a state, action, reward, next state sample from some process.
More Details...
#include <dlib/control.h>
[top]

projection_function

This object represents a function that takes a data sample and projects it into kernel feature space. The result is a real valued column vector that represents a point in a kernel feature space. Instances of this object are created using the empirical_kernel_map.

C++ Example Programs: linear_manifold_regularizer_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

radial_basis_kernel

This object represents a radial basis function kernel for use with kernel learning machines.

C++ Example Programs: svm_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

randomize_samples

Randomizes the order of samples in a column vector containing sample data.

C++ Example Programs: svm_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

ranking_pair

This object is used to contain a ranking example. Therefore, ranking_pair objects are used to represent training examples for learning-to-rank tasks, such as those used by the svm_rank_trainer.

C++ Example Programs: svm_rank_ex.cpp
Python Example Programs: svm_rank.py
More Details...
#include <dlib/svm.h>
[top]

rank_features

Finds a ranking of the top N (a user supplied parameter) features in a set of data from a two class classification problem. It does this by computing the distance between the centroids of both classes in kernel defined feature space. Good features are then ones that result in the biggest separation between the two centroids.

C++ Example Programs: rank_features_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

rank_unlabeled_training_samples

This routine implements an active learning method for selecting the most informative data sample to label out of a set of unlabeled samples. In particular, it implements the MaxMin Margin and Ratio Margin methods described in the paper:
Support Vector Machine Active Learning with Applications to Text Classification by Simon Tong and Daphne Koller.

More Details...
#include <dlib/svm.h>
[top]

rbf_network_trainer

Trains a radial basis function network and outputs a decision_function. This object can be used for either regression or binary classification problems. It's worth pointing out that this object is essentially an unregularized version of kernel ridge regression. This means you should really prefer to use kernel ridge regression instead.
More Details...
#include <dlib/svm.h>
[top]

reduced

This is a convenience function for creating reduced_decision_function_trainer objects.
More Details...
#include <dlib/svm.h>
[top]

reduced2

This is a convenience function for creating reduced_decision_function_trainer2 objects.

C++ Example Programs: svm_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

reduced_decision_function_trainer

This is a batch trainer object that is meant to wrap other batch trainer objects that create decision_function objects. It performs post processing on the output decision_function objects with the intent of representing the decision_function with fewer basis vectors.
More Details...
#include <dlib/svm.h>
[top]

reduced_decision_function_trainer2

This is a batch trainer object that is meant to wrap other batch trainer objects that create decision_function objects. It performs post processing on the output decision_function objects with the intent of representing the decision_function with fewer basis vectors.

It begins by performing the same post processing as the reduced_decision_function_trainer object but it also performs a global gradient based optimization to further improve the results. The gradient based optimization is implemented using the approximate_distance_function routine.

C++ Example Programs: svm_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

rls

This is an implementation of the linear version of the recursive least squares algorithm. It accepts training points incrementally and, at each step, maintains the solution to the following optimization problem:
find w minimizing: 0.5*dot(w,w) + C*sum_i(y_i - trans(x_i)*w)^2
Where (x_i,y_i) are training pairs. x_i is some vector and y_i is a target scalar value.
More Details...
#include <dlib/svm.h>
[top]

roc_c1_trainer

This is a convenience function for creating roc_trainer_type objects that are setup to pick a point on the ROC curve with respect to the +1 class.
More Details...
#include <dlib/svm.h>
[top]

roc_c2_trainer

This is a convenience function for creating roc_trainer_type objects that are setup to pick a point on the ROC curve with respect to the -1 class.
More Details...
#include <dlib/svm.h>
[top]

roc_trainer_type

This object is a simple trainer post processor that allows you to easily adjust the bias term in a trained decision_function object. That is, this object lets you pick a point on the ROC curve and it will adjust the bias term appropriately.

So for example, suppose you wanted to set the bias term so that the accuracy of your decision function on +1 labeled samples was 99%. To do this you would use an instance of this object declared as follows: roc_trainer_type<trainer_type>(your_trainer, 0.99, +1);

More Details...
#include <dlib/svm.h>
[top]

rr_trainer

Performs linear ridge regression and outputs a decision_function that represents the learned function. In particular, this object can only be used with the linear_kernel. It is optimized for the linear case where the number of features in each sample vector is small (i.e. on the order of 1000 or less since the algorithm is cubic in the number of features.). If you want to use a nonlinear kernel then you should use the krr_trainer.

This object is capable of automatically estimating its regularization parameter using leave-one-out cross-validation.
More Details...
#include <dlib/svm.h>
[top]

rvm_regression_trainer

Trains a relevance vector machine for solving regression problems. Outputs a decision_function that represents the learned regression function.

The implementation of the RVM training algorithm used by this library is based on the following paper:
Tipping, M. E. and A. C. Faul (2003). Fast marginal likelihood maximisation for sparse Bayesian models. In C. M. Bishop and B. J. Frey (Eds.), Proceedings of the Ninth International Workshop on Artificial Intelligence and Statistics, Key West, FL, Jan 3-6.

C++ Example Programs: rvm_regression_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

rvm_trainer

Trains a relevance vector machine for solving binary classification problems. Outputs a decision_function that represents the learned classifier.

The implementation of the RVM training algorithm used by this library is based on the following paper:
Tipping, M. E. and A. C. Faul (2003). Fast marginal likelihood maximisation for sparse Bayesian models. In C. M. Bishop and B. J. Frey (Eds.), Proceedings of the Ninth International Workshop on Artificial Intelligence and Statistics, Key West, FL, Jan 3-6.

C++ Example Programs: rvm_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

sammon_projection

This is a function object that computes the Sammon projection of a set of N points in a L-dimensional vector space onto a d-dimensional space (d < L), according to the paper:
A Nonlinear Mapping for Data Structure Analysis (1969) by J.W. Sammon

More Details...
#include <dlib/statistics.h>
[top]

save_image_dataset_metadata

This routine is a tool for saving labeled image metadata to an XML file. In particular, this routine saves the metadata into a form which can be read by the load_image_dataset_metadata routine. Note also that this is the metadata format used by the image labeling tool included with dlib in the tools/imglab folder.
More Details...
#include <dlib/data_io.h>
[top]

save_libsvm_formatted_data

This is actually a pair of overloaded functions. Between the two of them they let you save sparse or dense data vectors to file using the LIBSVM format.
More Details...
#include <dlib/data_io.h>
[top]

select_all_distinct_labels

This is a function which determines all distinct values present in a std::vector and returns the result.
More Details...
#include <dlib/svm.h>
[top]

sequence_labeler

This object is a tool for doing sequence labeling. In particular, it is capable of representing sequence labeling models such as those produced by Hidden Markov SVMs or Conditional Random fields. See the following papers for an introduction to these techniques:
Hidden Markov Support Vector Machines by Y. Altun, I. Tsochantaridis, T. Hofmann
Shallow Parsing with Conditional Random Fields by Fei Sha and Fernando Pereira

C++ Example Programs: sequence_labeler_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

sequence_segmenter

This object is a tool for segmenting a sequence of objects into a set of non-overlapping chunks. An example sequence segmentation task is to take English sentences and identify all the named entities. In this example, you would be using a sequence_segmenter to find all the chunks of contiguous words which refer to proper names.

Internally, the sequence_segmenter uses the BIO (Begin, Inside, Outside) or BILOU (Begin, Inside, Last, Outside, Unit) sequence tagging model. Moreover, it is implemented using a sequence_labeler object and therefore sequence_segmenter objects are examples of chain structured conditional random field style sequence taggers.

C++ Example Programs: sequence_segmenter_ex.cpp
Python Example Programs: sequence_segmenter.py,
More Details...
#include <dlib/svm.h>
[top]

shape_predictor_trainer

This object is a tool for training shape_predictors based on annotated training images. Its implementation uses the algorithm described in:
One Millisecond Face Alignment with an Ensemble of Regression Trees by Vahid Kazemi and Josephine Sullivan, CVPR 2014
It is capable of learning high quality shape models. For example, this is an example output for one of the faces in the HELEN face dataset:

C++ Example Programs: train_shape_predictor_ex.cpp
Python Example Programs: train_shape_predictor.py
More Details...
#include <dlib/image_processing.h>
[top]

sigmoid_kernel

This object represents a sigmoid kernel for use with kernel learning machines.
More Details...
#include <dlib/svm.h>
[top]

simplify_linear_decision_function

This is a set of functions that takes various forms of linear decision functions and collapses them down so that they only compute a single dot product when invoked.
More Details...
#include <dlib/svm.h>
[top]

sort_basis_vectors

A kernel based learning method ultimately needs to select a set of basis functions represented by a particular choice of kernel and a set of basis vectors. sort_basis_vectors() is a function which attempts to perform supervised basis set selection. In particular, you give it a candidate set of basis vectors and it sorts them according to how useful they are for solving a particular decision problem.
More Details...
#include <dlib/svm.h>
[top]

sparse_histogram_intersection_kernel

This object represents a histogram intersection kernel kernel for use with kernel learning machines that operate on sparse vectors.
More Details...
#include <dlib/svm.h>
[top]

sparse_linear_kernel

This object represents a linear kernel for use with kernel learning machines that operate on sparse vectors.
More Details...
#include <dlib/svm.h>
[top]

sparse_polynomial_kernel

This object represents a polynomial kernel for use with kernel learning machines that operate on sparse vectors.
More Details...
#include <dlib/svm.h>
[top]

sparse_radial_basis_kernel

This object represents a radial basis function kernel for use with kernel learning machines that operate on sparse vectors.
More Details...
#include <dlib/svm.h>
[top]

sparse_sigmoid_kernel

This object represents a sigmoid kernel for use with kernel learning machines that operate on sparse vectors.
More Details...
#include <dlib/svm.h>
[top]

spectral_cluster

This function performs the clustering algorithm described in the paper
On spectral clustering: Analysis and an algorithm by Ng, Jordan, and Weiss.

C++ Example Programs: kkmeans_ex.cpp
More Details...
#include <dlib/clustering.h>
[top]

structural_assignment_trainer

This object is a tool for learning to solve an assignment problem based on a training dataset of example assignments. The training procedure produces an assignment_function object which can be used to predict the assignments of new data. Note that this is just a convenience wrapper around the structural_svm_assignment_problem to make it look similar to all the other trainers in dlib.

C++ Example Programs: assignment_learning_ex.cpp
More Details...
#include <dlib/svm_threaded.h>
[top]

structural_graph_labeling_trainer

This object is a tool for learning to solve a graph labeling problem based on a training dataset of example labeled graphs. The training procedure produces a graph_labeler object which can be used to predict the labelings of new graphs.

To elaborate, a graph labeling problem is a task to learn a binary classifier which predicts the label of each node in a graph. Additionally, we have information in the form of edges between nodes where edges are present when we believe the linked nodes are likely to have the same label. Therefore, part of a graph labeling problem is to learn to score each edge in terms of how strongly the edge should enforce labeling consistency between its two nodes.

Note that this is just a convenience wrapper around the structural_svm_graph_labeling_problem to make it look similar to all the other trainers in dlib. You might also consider reading the book Structured Prediction and Learning in Computer Vision by Sebastian Nowozin and Christoph H. Lampert since it contains a good introduction to machine learning methods such as the algorithm implemented by the structural_graph_labeling_trainer.

C++ Example Programs: graph_labeling_ex.cpp
More Details...
#include <dlib/svm_threaded.h>
[top]

structural_object_detection_trainer

This object is a tool for learning to detect objects in images based on a set of labeled images. The training procedure produces an object_detector which can be used to predict the locations of objects in new images. It learns the parameter vector by formulating the problem as a structural SVM problem. The exact details of the method are described in the paper Max-Margin Object Detection by Davis E. King.

Note that this is just a convenience wrapper around the structural_svm_object_detection_problem to make it look similar to all the other trainers in dlib.

C++ Example Programs: fhog_object_detector_ex.cpp, object_detector_ex.cpp, object_detector_advanced_ex.cpp, train_object_detector.cpp
Python Example Programs: train_object_detector.py
More Details...
#include <dlib/svm_threaded.h>
[top]

structural_sequence_labeling_trainer

This object is a tool for learning to do sequence labeling based on a set of training data. The training procedure produces a sequence_labeler object which can be use to predict the labels of new data sequences.

Note that this is just a convenience wrapper around the structural_svm_sequence_labeling_problem to make it look similar to all the other trainers in dlib.

C++ Example Programs: sequence_labeler_ex.cpp
More Details...
#include <dlib/svm_threaded.h>
[top]

structural_sequence_segmentation_trainer

This object is a tool for learning to do sequence segmentation based on a set of training data. The training procedure produces a sequence_segmenter object which can be used to identify the sub-segments of new data sequences.

This object internally uses the structural_sequence_labeling_trainer to solve the learning problem.

C++ Example Programs: sequence_segmenter_ex.cpp
Python Example Programs: sequence_segmenter.py,
More Details...
#include <dlib/svm_threaded.h>
[top]

structural_svm_assignment_problem

This object is a tool for learning the parameters needed to use an assignment_function object. It learns the parameters by formulating the problem as a structural SVM problem.
More Details...
#include <dlib/svm_threaded.h>
[top]

structural_svm_graph_labeling_problem

This object is a tool for learning the weight vectors needed to use a graph_labeler object. It learns the parameter vectors by formulating the problem as a structural SVM problem.
More Details...
#include <dlib/svm_threaded.h>
[top]

structural_svm_object_detection_problem

This object is a tool for learning the parameter vector needed to use a scan_fhog_pyramid, scan_image_pyramid, scan_image_boxes, or scan_image_custom object.

It learns the parameter vector by formulating the problem as a structural SVM problem. The exact details of the method are described in the paper Max-Margin Object Detection by Davis E. King.

More Details...
#include <dlib/svm_threaded.h>
[top]

structural_svm_problem

This object, when used with the oca optimizer, is a tool for solving the optimization problem associated with a structural support vector machine. A structural SVM is a supervised machine learning method for learning to predict complex outputs. This is contrasted with a binary classifier which makes only simple yes/no predictions. A structural SVM, on the other hand, can learn to predict complex outputs such as entire parse trees or DNA sequence alignments. To do this, it learns a function F(x,y) which measures how well a particular data sample x matches a label y. When used for prediction, the best label for a new x is given by the y which maximizes F(x,y).

For an introduction to structured support vector machines you should consult the following paper:
Predicting Structured Objects with Support Vector Machines by Thorsten Joachims, Thomas Hofmann, Yisong Yue, and Chun-nam Yu
For a more detailed discussion of the particular algorithm implemented by this object see the following paper:
T. Joachims, T. Finley, Chun-Nam Yu, Cutting-Plane Training of Structural SVMs, Machine Learning, 77(1):27-59, 2009.
Note that this object is essentially a tool for solving the 1-Slack structural SVM with margin-rescaling. Specifically, see Algorithm 3 in the above referenced paper.

Finally, for a very detailed introduction to this subject, you should consider the book:
Structured Prediction and Learning in Computer Vision by Sebastian Nowozin and Christoph H. Lampert

C++ Example Programs: svm_struct_ex.cpp
Python Example Programs: svm_struct.py,
More Details...
#include <dlib/svm.h>
[top]

structural_svm_problem_threaded

This is just a version of the structural_svm_problem which is capable of using multiple cores/threads at a time. You should use it if you have a multi-core CPU and the separation oracle takes a long time to compute. Or even better, if you have multiple computers then you can use the svm_struct_controller_node to distribute the work across many computers.

C++ Example Programs: svm_struct_ex.cpp
More Details...
#include <dlib/svm_threaded.h>
[top]

structural_svm_sequence_labeling_problem

This object is a tool for learning the weight vector needed to use a sequence_labeler object. It learns the parameter vector by formulating the problem as a structural SVM problem. The general approach is discussed in the paper:
Hidden Markov Support Vector Machines by Y. Altun, I. Tsochantaridis, T. Hofmann
While the particular optimization strategy used is the method from:
T. Joachims, T. Finley, Chun-Nam Yu, Cutting-Plane Training of Structural SVMs, Machine Learning, 77(1):27-59, 2009.

More Details...
#include <dlib/svm_threaded.h>
[top]

structural_track_association_trainer

This object is a tool for learning to solve a track association problem. That is, it takes in a set of training data and outputs a track_association_function you can use to do detection to track association.

C++ Example Programs: learning_to_track_ex.cpp
More Details...
#include <dlib/svm_threaded.h>
[top]

svm_c_ekm_trainer

This object represents a tool for training the C formulation of a support vector machine for solving binary classification problems. It is implemented using the empirical_kernel_map to kernelize the svm_c_linear_trainer. This makes it a very fast algorithm capable of learning from very large datasets.
More Details...
#include <dlib/svm.h>
[top]

svm_c_linear_dcd_trainer

This object represents a tool for training the C formulation of a support vector machine to solve binary classification problems. It is optimized for the case where linear kernels are used and is implemented using the method described in the following paper:
A Dual Coordinate Descent Method for Large-scale Linear SVM by Cho-Jui Hsieh, Kai-Wei Chang, and Chih-Jen Lin
This trainer has the ability to disable the bias term and also to force the last element of the learned weight vector to be 1. Additionally, it can be warm-started from the solution to a previous training run.

C++ Example Programs: one_class_classifiers_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

svm_c_linear_trainer

This object represents a tool for training the C formulation of a support vector machine to solve binary classification problems. It is optimized for the case where linear kernels are used and is implemented using the oca optimizer and uses the exact line search described in the following paper:
Optimized Cutting Plane Algorithm for Large-Scale Risk Minimization by Vojtech Franc, Soren Sonnenburg; Journal of Machine Learning Research, 10(Oct):2157--2192, 2009.
This trainer has the ability to restrict the learned weights to non-negative values.

C++ Example Programs: svm_sparse_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

svm_c_trainer

Trains a C support vector machine for solving binary classification problems and outputs a decision_function. It is implemented using the SMO algorithm.

The implementation of the C-SVM training algorithm used by this library is based on the following paper:
  • Chih-Chung Chang and Chih-Jen Lin, LIBSVM : a library for support vector machines, 2001. Software available at http://www.csie.ntu.edu.tw/~cjlin/libsvm

C++ Example Programs: svm_c_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

svm_multiclass_linear_trainer

This object represents a tool for training a multiclass support vector machine. It is optimized for the case where linear kernels are used and implemented using the structural_svm_problem object.
More Details...
#include <dlib/svm_threaded.h>
[top]

svm_nu_trainer

Trains a nu support vector machine for solving binary classification problems and outputs a decision_function. It is implemented using the SMO algorithm.

The implementation of the nu-svm training algorithm used by this library is based on the following excellent papers:
  • Chang and Lin, Training {nu}-Support Vector Classifiers: Theory and Algorithms
  • Chih-Chung Chang and Chih-Jen Lin, LIBSVM : a library for support vector machines, 2001. Software available at http://www.csie.ntu.edu.tw/~cjlin/libsvm

C++ Example Programs: svm_ex.cpp, model_selection_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

svm_one_class_trainer

Trains a one-class support vector classifier and outputs a decision_function. It is implemented using the SMO algorithm.

The implementation of the one-class training algorithm used by this library is based on the following paper:
  • Chih-Chung Chang and Chih-Jen Lin, LIBSVM : a library for support vector machines, 2001. Software available at http://www.csie.ntu.edu.tw/~cjlin/libsvm

C++ Example Programs: one_class_classifiers_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

svm_pegasos

This object implements an online algorithm for training a support vector machine for solving binary classification problems.

The implementation of the Pegasos algorithm used by this object is based on the following excellent paper:

Pegasos: Primal estimated sub-gradient solver for SVM (2007) by Shai Shalev-Shwartz, Yoram Singer, Nathan Srebro In ICML

This SVM training algorithm has two interesting properties. First, the pegasos algorithm itself converges to the solution in an amount of time unrelated to the size of the training set (in addition to being quite fast to begin with). This makes it an appropriate algorithm for learning from very large datasets. Second, this object uses the kcentroid object to maintain a sparse approximation of the learned decision function. This means that the number of support vectors in the resulting decision function is also unrelated to the size of the dataset (in normal SVM training algorithms, the number of support vectors grows approximately linearly with the size of the training set).

However, if you are considering using svm_pegasos, you should also try the svm_c_linear_trainer for linear kernels or svm_c_ekm_trainer for non-linear kernels since these other trainers are, usually, faster and easier to use than svm_pegasos.

C++ Example Programs: svm_pegasos_ex.cpp, svm_sparse_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

svm_rank_trainer

This object represents a tool for training a ranking support vector machine using linear kernels. In particular, this object is a tool for training the Ranking SVM described in the paper:
Optimizing Search Engines using Clickthrough Data by Thorsten Joachims
Finally, note that the implementation of this object is done using the oca optimizer and count_ranking_inversions method. This means that it runs in O(n*log(n)) time, making it suitable for use with large datasets.

C++ Example Programs: svm_rank_ex.cpp
Python Example Programs: svm_rank.py
More Details...
#include <dlib/svm.h>
[top]

svm_struct_controller_node

This object is a tool for distributing the work involved in solving a structural_svm_problem across many computers.
More Details...
#include <dlib/svm_threaded.h>
[top]

svm_struct_processing_node

This object is a tool for distributing the work involved in solving a structural_svm_problem across many computers.
More Details...
#include <dlib/svm_threaded.h>
[top]

svr_linear_trainer

This object implements a trainer for performing epsilon-insensitive support vector regression. It uses the oca optimizer so it is very efficient at solving this problem when linear kernels are used, making it suitable for use with large datasets.
More Details...
#include <dlib/svm.h>
[top]

svr_trainer

This object implements a trainer for performing epsilon-insensitive support vector regression. It is implemented using the SMO algorithm, allowing the use of non-linear kernels. If you are interested in performing support vector regression with a linear kernel and you have a lot of training data then you should use the svr_linear_trainer which is highly optimized for this case.

The implementation of the eps-SVR training algorithm used by this object is based on the following paper:
  • Chih-Chung Chang and Chih-Jen Lin, LIBSVM : a library for support vector machines, 2001. Software available at http://www.csie.ntu.edu.tw/~cjlin/libsvm

C++ Example Programs: svr_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

test_assignment_function

Tests an assignment_function on a set of data and returns the fraction of assignments predicted correctly.

C++ Example Programs: assignment_learning_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

test_binary_decision_function

Tests a decision_function that represents a binary decision function and returns the test accuracy.
More Details...
#include <dlib/svm.h>
[top]

test_graph_labeling_function

Tests a graph_labeler on a set of data and returns the fraction of labels predicted correctly.
More Details...
#include <dlib/svm_threaded.h>
[top]

test_multiclass_decision_function

Tests a multiclass decision function (e.g. one_vs_one_decision_function) and returns a confusion matrix describing the results.

C++ Example Programs: multiclass_classification_ex.cpp, custom_trainer_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

test_object_detection_function

Tests an object detector such as the object_detector and returns the precision and recall.

C++ Example Programs: fhog_object_detector_ex.cpp, object_detector_ex.cpp, object_detector_advanced_ex.cpp, train_object_detector.cpp
More Details...
#include <dlib/svm.h>
[top]

test_ranking_function

Tests a decision_function's ability to correctly rank a dataset and returns the resulting ranking accuracy and mean average precision metrics.

C++ Example Programs: svm_rank_ex.cpp
Python Example Programs: svm_rank.py
More Details...
#include <dlib/svm.h>
[top]

test_regression_function

Tests a regression function (e.g. decision_function) and returns the mean squared error and R-squared value.
More Details...
#include <dlib/svm.h>
[top]

test_sequence_labeler

Tests a sequence_labeler on a set of data and returns a confusion matrix describing the results.

C++ Example Programs: sequence_labeler_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

test_sequence_segmenter

Tests a sequence_segmenter on a set of data and returns the resulting precision, recall, and F1-score.

C++ Example Programs: sequence_segmenter_ex.cpp
Python Example Programs: sequence_segmenter.py,
More Details...
#include <dlib/svm.h>
[top]

test_shape_predictor

Tests a shape_predictor's ability to correctly predict the part locations of objects. The output is the average distance (measured in pixels) between each part and its true location. You can optionally normalize each distance using a user supplied scale. For example, when performing face landmarking, you might want to normalize the distances by the interocular distance.

C++ Example Programs: train_shape_predictor_ex.cpp
Python Example Programs: train_shape_predictor.py
More Details...
#include <dlib/image_processing.h>
[top]

test_track_association_function

Tests a track_association_function on a set of data and returns the fraction of detections which were correctly associated to their tracks.

C++ Example Programs: learning_to_track_ex.cpp
More Details...
#include <dlib/svm_threaded.h>
[top]

track_association_function

This object is a tool that helps you implement an object tracker. So for example, if you wanted to track people moving around in a video then this object can help. In particular, imagine you have a tool for detecting the positions of each person in an image. Then you can run this person detector on the video and at each time step, i.e. at each frame, you get a set of person detections. However, that by itself doesn't tell you how many people there are in the video and where they are moving to and from. To get that information you need to figure out which detections match each other from frame to frame. This is where the track_association_function comes in. It performs the detection to track association. It will also do some of the track management tasks like creating a new track when a detection doesn't match any of the existing tracks.

Internally, this object is implemented using the assignment_function object. In fact, it's really just a thin wrapper around assignment_function and exists just to provide a more convenient interface to users doing detection to track association.

C++ Example Programs: learning_to_track_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

train_probabilistic_decision_function

Trains a probabilistic_function using some sort of binary classification trainer object such as the svm_nu_trainer or krr_trainer.

The probability model is created by using the technique described in the following papers:
Probabilistic Outputs for Support Vector Machines and Comparisons to Regularized Likelihood Methods by John C. Platt. March 26, 1999
A Note on Platt's Probabilistic Outputs for Support Vector Machines by Hsuan-Tien Lin, Chih-Jen Lin, and Ruby C. Weng

C++ Example Programs: svm_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

vector_normalizer

This object represents something that can learn to normalize a set of column vectors. In particular, normalized column vectors should have zero mean and a variance of one.

C++ Example Programs: svm_ex.cpp
More Details...
#include <dlib/statistics.h>
[top]

vector_normalizer_frobmetric

This object is a tool for performing the FrobMetric distance metric learning algorithm described in the following paper:
A Scalable Dual Approach to Semidefinite Metric Learning By Chunhua Shen, Junae Kim, Lei Wang, in CVPR 2011
Therefore, this object is a tool that takes as input training triplets (anchor, near, far) of vectors and attempts to learn a linear transformation T such that:
length(T*anchor-T*near) + 1 < length(T*anchor - T*far)
That is, you give a bunch of anchor vectors and for each anchor vector you specify some vectors which should be near to it and some that should be far form it. This object then tries to find a transformation matrix that makes the "near" vectors close to their anchors while the "far" vectors are farther away.
More Details...
#include <dlib/statistics.h>
[top]

vector_normalizer_pca

This object represents something that can learn to normalize a set of column vectors. In particular, normalized column vectors should have zero mean and a variance of one. This object also uses principal component analysis for the purposes of reducing the number of elements in a vector.
More Details...
#include <dlib/statistics.h>
[top]

verbose_batch

This is a convenience function for creating batch_trainer objects. This function generates a batch_trainer that will print status messages to standard output so that you can observe the progress of a training algorithm.

C++ Example Programs: svm_pegasos_ex.cpp
More Details...
#include <dlib/svm.h>
[top]

verbose_batch_cached

This is a convenience function for creating batch_trainer objects. This function generates a batch_trainer that will print status messages to standard output so that you can observe the progress of a training algorithm. It will also be configured to use a kernel matrix cache.
More Details...
#include <dlib/svm.h>


dlib C++ Library - rvm_abstract.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_RVm_ABSTRACT_
#ifdef DLIB_RVm_ABSTRACT_

#include <cmath>
#include <limits>
#include "../matrix.h"
#include "../algs.h"
#include "function.h"
#include "kernel.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename kern_type
        >
    class rvm_trainer
    {
        /*!
            REQUIREMENTS ON kern_type
                is a kernel function object as defined in dlib/svm/kernel_abstract.h

            WHAT THIS OBJECT REPRESENTS
                This object implements a trainer for a relevance vector machine for
                solving binary classification problems.

                The implementation of the RVM training algorithm used by this object is based
                on the following excellent paper:
                    Tipping, M. E. and A. C. Faul (2003). Fast marginal likelihood maximisation
                    for sparse Bayesian models. In C. M. Bishop and B. J. Frey (Eds.), Proceedings
                    of the Ninth International Workshop on Artificial Intelligence and Statistics,
                    Key West, FL, Jan 3-6.
        !*/

    public:
        typedef kern_type 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 decision_function<kernel_type> trained_function_type;

        rvm_trainer (
        );
        /*!
            ensures
                - This object is properly initialized and ready to be used
                  to train a relevance vector machine.
                - #get_epsilon() == 0.001
                - #get_max_iterations() == 2000
        !*/

        void set_epsilon (
            scalar_type eps
        );
        /*!
            requires
                - eps > 0
            ensures
                - #get_epsilon() == eps
        !*/

        const scalar_type get_epsilon (
        ) const;
        /*!
            ensures
                - returns the error epsilon that determines when training should stop.
                  Generally a good value for this is 0.001.  Smaller values may result
                  in a more accurate solution but take longer to execute.
        !*/

        void set_kernel (
            const kernel_type& k
        );
        /*!
            ensures
                - #get_kernel() == k
        !*/

        const kernel_type& get_kernel (
        ) const;
        /*!
            ensures
                - returns a copy of the kernel function in use by this object
        !*/

        unsigned long get_max_iterations (
        ) const;
        /*!
            ensures
                - returns the maximum number of iterations the RVM optimizer is allowed to
                  run before it is required to stop and return a result.
        !*/

        void set_max_iterations (
            unsigned long max_iter
        );
        /*!
            ensures
                - #get_max_iterations() == max_iter
        !*/

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y
        ) const;
        /*!
            requires
                - is_binary_classification_problem(x,y) == true
                - x == a matrix or something convertible to a matrix via mat().
                  Also, x should contain sample_type objects.
                - y == a matrix or something convertible to a matrix via mat().
                  Also, y should contain scalar_type objects.
            ensures
                - trains a relevance vector classifier given the training samples in x and
                  labels in y.
                - returns a decision function F with the following properties:
                    - if (new_x is a sample predicted have +1 label) then
                        - F(new_x) >= 0
                    - else
                        - F(new_x) < 0
            throws
                - std::bad_alloc
        !*/

        void swap (
            rvm_trainer& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <typename K>
    void swap (
        rvm_trainer<K>& a,
        rvm_trainer<K>& b
    ) { a.swap(b); }
    /*!
        provides a global swap
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename kern_type
        >
    class rvm_regression_trainer
    {
        /*!
            REQUIREMENTS ON kern_type
                is a kernel function object as defined in dlib/svm/kernel_abstract.h

            WHAT THIS OBJECT REPRESENTS
                This object implements a trainer for a relevance vector machine for
                solving regression problems.

                The implementation of the RVM training algorithm used by this object is based
                on the following excellent paper:
                    Tipping, M. E. and A. C. Faul (2003). Fast marginal likelihood maximisation
                    for sparse Bayesian models. In C. M. Bishop and B. J. Frey (Eds.), Proceedings
                    of the Ninth International Workshop on Artificial Intelligence and Statistics,
                    Key West, FL, Jan 3-6.
        !*/

    public:
        typedef kern_type 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 decision_function<kernel_type> trained_function_type;

        rvm_regression_trainer (
        );
        /*!
            ensures
                - This object is properly initialized and ready to be used
                  to train a relevance vector machine.
                - #get_epsilon() == 0.001
        !*/

        void set_epsilon (
            scalar_type eps
        );
        /*!
            requires
                - eps > 0
            ensures
                - #get_epsilon() == eps
        !*/

        const scalar_type get_epsilon (
        ) const;
        /*!
            ensures
                - returns the error epsilon that determines when training should stop.
                  Generally a good value for this is 0.001.  Smaller values may result
                  in a more accurate solution but take longer to execute.
        !*/

        void set_kernel (
            const kernel_type& k
        );
        /*!
            ensures
                - #get_kernel() == k
        !*/

        const kernel_type& get_kernel (
        ) const;
        /*!
            ensures
                - returns a copy of the kernel function in use by this object
        !*/

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y
        ) const;
        /*!
            requires
                - x == a matrix or something convertible to a matrix via mat().
                  Also, x should contain sample_type objects.
                - y == a matrix or something convertible to a matrix via mat().
                  Also, y should contain scalar_type objects.
                - is_learning_problem(x,y) == true
                - x.size() > 0
            ensures
                - trains a RVM given the training samples in x and
                  labels in y and returns the resulting decision_function.
            throws
                - std::bad_alloc
        !*/

        void swap (
            rvm_regression_trainer& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <typename K>
    void swap (
        rvm_regression_trainer<K>& a,
        rvm_regression_trainer<K>& b
    ) { a.swap(b); }
    /*!
        provides a global swap
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_RVm_ABSTRACT_


dlib C++ Library - svm_c_ekm_trainer_abstract.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SVM_C_EKm_TRAINER_ABSTRACT_Hh_
#ifdef DLIB_SVM_C_EKm_TRAINER_ABSTRACT_Hh_

#include "../algs.h"
#include "function_abstract.h"
#include "kernel_abstract.h"
#include "empirical_kernel_map_abstract.h"
#include "svm_c_linear_trainer_abstract.h"

namespace dlib
{
    template <
        typename K
        >
    class svm_c_ekm_trainer
    {
        /*!
            REQUIREMENTS ON K
                is a kernel function object as defined in dlib/svm/kernel_abstract.h

            WHAT THIS OBJECT REPRESENTS
                This object represents a tool for training the C formulation of
                a support vector machine.   It is implemented using the empirical_kernel_map
                to kernelize the svm_c_linear_trainer.  This makes it a very fast algorithm
                capable of learning from very large datasets.
        !*/

    public:
        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 decision_function<kernel_type> trained_function_type;

        svm_c_ekm_trainer (
        );
        /*!
            ensures
                - This object is properly initialized and ready to be used
                  to train a support vector machine.
                - #get_oca() == oca() (i.e. an instance of oca with default parameters)
                - #get_c_class1() == 1
                - #get_c_class2() == 1
                - #get_epsilon() == 0.001
                - #basis_loaded() == false
                - #get_initial_basis_size() == 10
                - #get_basis_size_increment() == 50
                - #get_max_basis_size() == 300
                - this object will not be verbose unless be_verbose() is called
                - #get_max_iterations() == 10000
        !*/

        explicit svm_c_ekm_trainer (
            const scalar_type& C
        );
        /*!
            requires
                - C > 0
            ensures
                - This object is properly initialized and ready to be used
                  to train a support vector machine.
                - #get_oca() == oca() (i.e. an instance of oca with default parameters)
                - #get_c_class1() == C
                - #get_c_class2() == C
                - #get_epsilon() == 0.001
                - #basis_loaded() == false
                - #get_initial_basis_size() == 10
                - #get_basis_size_increment() == 50
                - #get_max_basis_size() == 300
                - this object will not be verbose unless be_verbose() is called
                - #get_max_iterations() == 10000
        !*/

        void set_epsilon (
            scalar_type eps
        );
        /*!
            requires
                - eps > 0
            ensures
                - #get_epsilon() == eps
        !*/

        const scalar_type get_epsilon (
        ) const;
        /*!
            ensures
                - returns the error epsilon that determines when training should stop.
                  Smaller values may result in a more accurate solution but take longer
                  to execute.
        !*/

        void set_max_iterations (
            unsigned long max_iter
        );
        /*!
            ensures
                - #get_max_iterations() == max_iter
        !*/

        unsigned long get_max_iterations (
        );
        /*!
            ensures
                - returns the maximum number of iterations the SVM optimizer is allowed to
                  run before it is required to stop and return a result.
        !*/

        void be_verbose (
        );
        /*!
            ensures
                - This object will print status messages to standard out so that a
                  user can observe the progress of the algorithm.
        !*/

        void be_very_verbose (
        );
        /*!
            ensures
                - This object will print a lot of status messages to standard out so that a
                  user can observe the progress of the algorithm.  In addition to the
                  few status messages normal verbosity produces this setting also causes
                  the underlying svm_c_linear_trainer to be verbose.
        !*/

        void be_quiet (
        );
        /*!
            ensures
                - this object will not print anything to standard out
        !*/

        void set_oca (
            const oca& item
        );
        /*!
            ensures
                - #get_oca() == item
        !*/

        const oca get_oca (
        ) const;
        /*!
            ensures
                - returns a copy of the optimizer used to solve the SVM problem.
        !*/

        const kernel_type get_kernel (
        ) const;
        /*!
            ensures
                - returns a copy of the kernel function in use by this object
        !*/

        void set_kernel (
            const kernel_type& k
        );
        /*!
            ensures
                - #get_kernel() == k
        !*/

        template <typename T>
        void set_basis (
            const T& basis_samples
        );
        /*!
            requires
                - T must be a dlib::matrix type or something convertible to a matrix via mat()
                  (e.g. a std::vector)
                - is_vector(basis_samples) == true
                - basis_samples.size() > 0
                - get_kernel() must be capable of operating on the elements of basis_samples.  That is,
                  expressions such as get_kernel()(basis_samples(0), basis_samples(0)) should make sense.
            ensures
                - #basis_loaded() == true
                - training will be carried out in the span of the given basis_samples
        !*/

        bool basis_loaded (
        ) const;
        /*!
            ensures
                - returns true if this object has been loaded with user supplied basis vectors and false otherwise.
        !*/

        void clear_basis (
        );
        /*!
            ensures
                - #basis_loaded() == false
        !*/

        unsigned long get_max_basis_size (
        ) const;
        /*!
            ensures
                - returns the maximum number of basis vectors this object is allowed
                  to use.  This parameter only matters when the user has not supplied
                  a basis via set_basis().
        !*/

        void set_max_basis_size (
            unsigned long max_basis_size
        );
        /*!
            requires
                - max_basis_size > 0
            ensures
                - #get_max_basis_size() == max_basis_size
                - if (get_initial_basis_size() > max_basis_size) then
                    - #get_initial_basis_size() == max_basis_size
        !*/

        unsigned long get_initial_basis_size (
        ) const;
        /*!
            ensures
                - If the user does not supply a basis via set_basis() then this object
                  will generate one automatically.  It does this by starting with
                  a small basis of size N and repeatedly adds basis vectors to it
                  until a stopping condition is reached.  This function returns that
                  initial size N.
        !*/

        void set_initial_basis_size (
            unsigned long initial_basis_size
        );
        /*!
            requires
                - initial_basis_size > 0
            ensures
                - #get_initial_basis_size() == initial_basis_size
                - if (initial_basis_size > get_max_basis_size()) then
                    - #get_max_basis_size() == initial_basis_size
        !*/

        unsigned long get_basis_size_increment (
        ) const;
        /*!
            ensures
                - If the user does not supply a basis via set_basis() then this object
                  will generate one automatically.  It does this by starting with a small
                  basis and repeatedly adds sets of N basis vectors to it until a stopping
                  condition is reached.  This function returns that increment size N.
        !*/

        void set_basis_size_increment (
            unsigned long basis_size_increment
        );
        /*!
            requires
                - basis_size_increment > 0
            ensures
                - #get_basis_size_increment() == basis_size_increment
        !*/

        void set_c (
            scalar_type C
        );
        /*!
            requires
                - C > 0
            ensures
                - #get_c_class1() == C
                - #get_c_class2() == C
        !*/

        const scalar_type get_c_class1 (
        ) const;
        /*!
            ensures
                - returns the SVM regularization parameter for the +1 class.
                  It is the parameter that determines the trade off between
                  trying to fit the +1 training data exactly or allowing more errors
                  but hopefully improving the generalization ability of the
                  resulting classifier.  Larger values encourage exact fitting
                  while smaller values of C may encourage better generalization.
        !*/

        const scalar_type get_c_class2 (
        ) const;
        /*!
            ensures
                - returns the SVM regularization parameter for the -1 class.
                  It is the parameter that determines the trade off between
                  trying to fit the -1 training data exactly or allowing more errors
                  but hopefully improving the generalization ability of the
                  resulting classifier.  Larger values encourage exact fitting
                  while smaller values of C may encourage better generalization.
        !*/

        void set_c_class1 (
            scalar_type C
        );
        /*!
            requires
                - C > 0
            ensures
                - #get_c_class1() == C
        !*/

        void set_c_class2 (
            scalar_type C
        );
        /*!
            requires
                - C > 0
            ensures
                - #get_c_class2() == C
        !*/

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y
        ) const;
        /*!
            requires
                - is_binary_classification_problem(x,y) == true
                - x == a matrix or something convertible to a matrix via mat().
                  Also, x should contain sample_type objects.
                - y == a matrix or something convertible to a matrix via mat().
                  Also, y should contain scalar_type objects.
            ensures
                - trains a C support vector classifier given the training samples in x and
                  labels in y.
                - if (basis_loaded()) then
                    - training will be carried out in the span of the user supplied basis vectors
                - else
                    - this object will attempt to automatically select an appropriate basis

                - returns a decision function F with the following properties:
                    - if (new_x is a sample predicted have +1 label) then
                        - F(new_x) >= 0
                    - else
                        - F(new_x) < 0
        !*/

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y,
            scalar_type& svm_objective
        ) const;
        /*!
            requires
                - is_binary_classification_problem(x,y) == true
                - x == a matrix or something convertible to a matrix via mat().
                  Also, x should contain sample_type objects.
                - y == a matrix or something convertible to a matrix via mat().
                  Also, y should contain scalar_type objects.
            ensures
                - trains a C support vector classifier given the training samples in x and
                  labels in y.
                - if (basis_loaded()) then
                    - training will be carried out in the span of the user supplied basis vectors
                - else
                    - this object will attempt to automatically select an appropriate basis

                - #svm_objective == the final value of the SVM objective function
                - returns a decision function F with the following properties:
                    - if (new_x is a sample predicted have +1 label) then
                        - F(new_x) >= 0
                    - else
                        - F(new_x) < 0
        !*/

    };

}

#endif // DLIB_SVM_C_EKm_TRAINER_ABSTRACT_Hh_


dlib C++ Library - svm_c_linear_dcd_trainer_abstract.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SVm_C_LINEAR_DCD_TRAINER_ABSTRACT_Hh_
#ifdef DLIB_SVm_C_LINEAR_DCD_TRAINER_ABSTRACT_Hh_

#include "function_abstract.h"
#include "kernel_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename K
        >
    class svm_c_linear_dcd_trainer
    {
        /*!
            REQUIREMENTS ON K
                Is either linear_kernel or sparse_linear_kernel.

            WHAT THIS OBJECT REPRESENTS
                This object represents a tool for training the C formulation of a support
                vector machine.  It is optimized for the case where linear kernels are
                used.

                In particular, it is implemented using the algorithm described in the
                following paper:
                    A Dual Coordinate Descent Method for Large-scale Linear SVM
                    by Cho-Jui Hsieh, Kai-Wei Chang, and Chih-Jen Lin

                It solves the optimization problem of:
                min_w: 0.5||w||^2 + C*sum_i (hinge loss for sample i)
                where w is the learned SVM parameter vector.

                Note that this object is very similar to the svm_c_linear_trainer, however,
                it interprets the C parameter slightly differently.  In particular, C for
                the DCD trainer is not automatically divided by the number of samples like
                it is with the svm_c_linear_trainer.  For example, a C value of 10 when
                given to the svm_c_linear_trainer is equivalent to a C value of 10/N for
                the svm_c_linear_dcd_trainer, where N is the number of training samples.
        !*/

    public:
        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 decision_function<kernel_type> trained_function_type;
        typedef typename decision_function<K>::sample_vector_type sample_vector_type;
        typedef typename decision_function<K>::scalar_vector_type scalar_vector_type;

        svm_c_linear_dcd_trainer (
        );
        /*!
            ensures
                - This object is properly initialized and ready to be used to train a
                  support vector machine.
                - #get_c_class1() == 1
                - #get_c_class2() == 1
                - #get_epsilon() == 0.1
                - #get_max_iterations() == 10000
                - This object will not be verbose unless be_verbose() is called
                - #forces_last_weight_to_1() == false
                - #includes_bias() == true
                - #shrinking_enabled() == true
        !*/

        explicit svm_c_linear_dcd_trainer (
            const scalar_type& C
        );
        /*!
            requires
                - C > 0
            ensures
                - This object is properly initialized and ready to be used to train a
                  support vector machine.
                - #get_c_class1() == C
                - #get_c_class2() == C
                - #get_epsilon() == 0.1
                - #get_max_iterations() == 10000
                - This object will not be verbose unless be_verbose() is called
                - #forces_last_weight_to_1() == false
                - #includes_bias() == true
                - #shrinking_enabled() == true
        !*/

        bool includes_bias (
        ) const;
        /*!
            ensures
                - returns true if this trainer will produce decision_functions with
                  non-zero bias values.
        !*/

        void include_bias (
            bool should_have_bias
        );
        /*!
            ensures
                - #includes_bias() == should_have_bias
        !*/

        bool forces_last_weight_to_1 (
        ) const;
        /*!
            ensures
                - returns true if this trainer has the constraint that the last weight in
                  the learned parameter vector must be 1.  This is the weight corresponding
                  to the feature in the training vectors with the highest dimension.
                - Forcing the last weight to 1 also disables the bias and therefore the b
                  field of the learned decision_function will be 0 when forces_last_weight_to_1() == true.
                  This is true regardless of the setting of #include_bias().
        !*/

        void force_last_weight_to_1 (
            bool should_last_weight_be_1
        );
        /*!
            ensures
                - #forces_last_weight_to_1() == should_last_weight_be_1
        !*/

        bool shrinking_enabled (
        ) const;
        /*!
            ensures
                - returns true if the shrinking heuristic is enabled.  Typically this makes
                  the algorithm run a lot faster so it should be enabled.
        !*/

        void enable_shrinking (
            bool enabled
        );
        /*!
            ensures
                - #shrinking_enabled() == enabled
        !*/

        void be_verbose (
        );
        /*!
            ensures
                - This object will print status messages to standard out so that a
                  user can observe the progress of the algorithm.
        !*/

        void be_quiet (
        );
        /*!
            ensures
                - this object will not print anything to standard out
        !*/

        void set_epsilon (
            scalar_type eps_
        );
        /*!
            requires
                - eps > 0
            ensures
                - #get_epsilon() == eps
        !*/

        const scalar_type get_epsilon (
        ) const;
        /*!
            ensures
                - returns the error epsilon that determines when training should stop.
                  Smaller values may result in a more accurate solution but take longer to
                  train.
        !*/

        const kernel_type& get_kernel (
        ) const;
        /*!
            ensures
                - returns a copy of the kernel function in use by this object.  Since the
                  linear kernels don't have any parameters this function just returns
                  kernel_type()
        !*/

        unsigned long get_max_iterations (
        ) const;
        /*!
            ensures
                - returns the maximum number of iterations the SVM optimizer is allowed to
                  run before it is required to stop and return a result.
        !*/

        void set_max_iterations (
            unsigned long max_iter
        );
        /*!
            ensures
                - #get_max_iterations() == max_iter
        !*/

        void set_c (
            scalar_type C
        );
        /*!
            requires
                - C > 0
            ensures
                - #get_c_class1() == C
                - #get_c_class2() == C
        !*/

        const scalar_type get_c_class1 (
        ) const;
        /*!
            ensures
                - returns the SVM regularization parameter for the +1 class.  It is the
                  parameter that determines the trade off between trying to fit the +1
                  training data exactly or allowing more errors but hopefully improving the
                  generalization of the resulting classifier.  Larger values encourage
                  exact fitting while smaller values of C may encourage better
                  generalization.
        !*/

        const scalar_type get_c_class2 (
        ) const;
        /*!
            ensures
                - returns the SVM regularization parameter for the -1 class.  It is the
                  parameter that determines the trade off between trying to fit the -1
                  training data exactly or allowing more errors but hopefully improving the
                  generalization of the resulting classifier.  Larger values encourage
                  exact fitting while smaller values of C may encourage better
                  generalization.
        !*/

        void set_c_class1 (
            scalar_type C
        );
        /*!
            requires
                - C > 0
            ensures
                - #get_c_class1() == C
        !*/

        void set_c_class2 (
            scalar_type C
        );
        /*!
            requires
                - C > 0
            ensures
                - #get_c_class2() == C
        !*/

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y
        ) const;
        /*!
            requires
                - is_learning_problem(x,y) == true
                  (Note that it is ok for x.size() == 1)
                - All elements of y must be equal to +1 or -1
                - x == a matrix or something convertible to a matrix via mat().
                  Also, x should contain sample_type objects.
                - y == a matrix or something convertible to a matrix via mat().
                  Also, y should contain scalar_type objects.
            ensures
                - Trains a C support vector classifier given the training samples in x and
                  labels in y.
                - returns a decision function F with the following properties:
                    - F.alpha.size() == 1
                    - F.basis_vectors.size() == 1
                    - F.alpha(0) == 1
                    - if (new_x is a sample predicted have +1 label) then
                        - F(new_x) >= 0
                    - else
                        - F(new_x) < 0
        !*/

        // optimizer_state is used to record the internal state of the SVM optimizer.  It
        // can be used with the following train() routine to warm-start the optimizer.
        // Note, that optimizer_state objects are serializable but are otherwise completely
        // opaque to the user.
        class optimizer_state;

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y,
            optimizer_state& state
        ) const;
        /*!
            requires
                - is_learning_problem(x,y) == true
                  (Note that it is ok for x.size() == 1)
                - All elements of y must be equal to +1 or -1
                - state must be either a default initialized optimizer_state object or all the
                  following conditions must be satisfied:
                    - Let LAST denote the previous trainer used with the state object, then
                      we must have:
                        - LAST.includes_bias() == includes_bias()
                        - LAST.forces_last_weight_to_1() == forces_last_weight_to_1()
                    - Let X denote the previous training samples used with state, then the
                      following must be satisfied:
                        - x.size() >= X.size()
                        - for all valid i:
                            - x(i) == X(i)
                              (i.e. the samples x and X have in common must be identical.
                              That is, the only allowed difference between x and X is that
                              x might have new training samples appended onto its end)
                        - if (x contains dense vectors) then
                            - max_index_plus_one(x) == max_index_plus_one(X)
                        - else
                            - max_index_plus_one(x) >= max_index_plus_one(X)
                - x == a matrix or something convertible to a matrix via mat().
                  Also, x should contain sample_type objects.
                - y == a matrix or something convertible to a matrix via mat().
                  Also, y should contain scalar_type objects.
            ensures
                - Trains a C support vector classifier given the training samples in x and
                  labels in y.
                - The point of the state object is to allow you to warm start the SVM
                  optimizer from the solution to a previous call to train().  Doing this
                  might make the training run faster.  This is useful when you are trying
                  different C values or have grown the training set and want to retrain.
                - #state == the internal state of the optimizer at the solution to the SVM
                  problem.  Therefore, passing #state to a new call to train() will start
                  the optimizer from the current solution.
                - returns a decision function F with the following properties:
                    - F.alpha.size() == 1
                    - F.basis_vectors.size() == 1
                    - F.alpha(0) == 1
                    - if (new_x is a sample predicted have +1 label) then
                        - F(new_x) >= 0
                    - else
                        - F(new_x) < 0
        !*/
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SVm_C_LINEAR_DCD_TRAINER_ABSTRACT_Hh_


dlib C++ Library - svm_c_linear_trainer_abstract.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SVM_C_LiNEAR_TRAINER_ABSTRACT_Hh_
#ifdef DLIB_SVM_C_LiNEAR_TRAINER_ABSTRACT_Hh_

#include "../matrix/matrix_abstract.h"
#include "../algs.h"
#include "function_abstract.h"
#include "kernel_abstract.h"
#include "sparse_kernel_abstract.h"

namespace dlib
{
    template <
        typename K
        >
    class svm_c_linear_trainer
    {
        /*!
            REQUIREMENTS ON K
                Is either linear_kernel or sparse_linear_kernel.

            WHAT THIS OBJECT REPRESENTS
                This object represents a tool for training the C formulation of
                a support vector machine.  It is optimized for the case where
                linear kernels are used.

                In particular, it is implemented using the OCAS algorithm
                described in the following paper:
                    Optimized Cutting Plane Algorithm for Large-Scale Risk Minimization
                        Vojtech Franc, Soren Sonnenburg; Journal of Machine Learning
                        Research, 10(Oct):2157--2192, 2009.
        !*/

    public:
        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 decision_function<kernel_type> trained_function_type;

        svm_c_linear_trainer (
        );
        /*!
            ensures
                - This object is properly initialized and ready to be used
                  to train a support vector machine.
                - #get_oca() == oca() (i.e. an instance of oca with default parameters)
                - #get_c_class1() == 1
                - #get_c_class2() == 1
                - #get_epsilon() == 0.001
                - this object will not be verbose unless be_verbose() is called
                - #get_max_iterations() == 10000
                - #learns_nonnegative_weights() == false
                - #force_last_weight_to_1() == false
                - #has_prior() == false
        !*/

        explicit svm_c_linear_trainer (
            const scalar_type& C
        );
        /*!
            requires
                - C > 0
            ensures
                - This object is properly initialized and ready to be used
                  to train a support vector machine.
                - #get_oca() == oca() (i.e. an instance of oca with default parameters)
                - #get_c_class1() == C
                - #get_c_class2() == C
                - #get_epsilon() == 0.001
                - this object will not be verbose unless be_verbose() is called
                - #get_max_iterations() == 10000
                - #learns_nonnegative_weights() == false
                - #force_last_weight_to_1() == false
                - #has_prior() == false
        !*/

        void set_epsilon (
            scalar_type eps
        );
        /*!
            requires
                - eps > 0
            ensures
                - #get_epsilon() == eps
        !*/

        const scalar_type get_epsilon (
        ) const;
        /*!
            ensures
                - returns the error epsilon that determines when training should stop.
                  Smaller values may result in a more accurate solution but take longer to
                  train.  You can think of this epsilon value as saying "solve the
                  optimization problem until the probability of misclassification is within
                  epsilon of its optimal value".
        !*/

        void set_max_iterations (
            unsigned long max_iter
        );
        /*!
            ensures
                - #get_max_iterations() == max_iter
        !*/

        unsigned long get_max_iterations (
        );
        /*!
            ensures
                - returns the maximum number of iterations the SVM optimizer is allowed to
                  run before it is required to stop and return a result.
        !*/

        void be_verbose (
        );
        /*!
            ensures
                - This object will print status messages to standard out so that a
                  user can observe the progress of the algorithm.
        !*/

        void be_quiet (
        );
        /*!
            ensures
                - this object will not print anything to standard out
        !*/

        void set_oca (
            const oca& item
        );
        /*!
            ensures
                - #get_oca() == item
        !*/

        const oca get_oca (
        ) const;
        /*!
            ensures
                - returns a copy of the optimizer used to solve the SVM problem.
        !*/

        const kernel_type get_kernel (
        ) const;
        /*!
            ensures
                - returns a copy of the kernel function in use by this object.  Since
                  the linear kernels don't have any parameters this function just
                  returns kernel_type()
        !*/

        bool learns_nonnegative_weights (
        ) const;
        /*!
            ensures
                - The output of training is a weight vector and a bias value.  These
                  two things define the resulting decision function.  That is, the
                  decision function simply takes the dot product between the learned
                  weight vector and a test sample, then subtracts the bias value.
                  Therefore, if learns_nonnegative_weights() == true then the resulting
                  learned weight vector will always have non-negative entries.  The
                  bias value may still be negative though.
        !*/

        void set_learns_nonnegative_weights (
            bool value
        );
        /*!
            ensures
                - #learns_nonnegative_weights() == value
                - if (value == true) then
                    - #has_prior() == false
        !*/

        void set_prior (
            const trained_function_type& prior
        );
        /*!
            requires
                - prior == a function produced by a call to this class's train() function.
                  Therefore, it must be the case that:
                    - prior.basis_vectors.size() == 1
                    - prior.alpha(0) == 1
            ensures
                - Subsequent calls to train() will try to learn a function similar to the
                  given prior.
                - #has_prior() == true
                - #learns_nonnegative_weights() == false
                - #forces_last_weight_to_1() == false
        !*/

        bool has_prior (
        ) const
        /*!
            ensures
                - returns true if a prior has been set and false otherwise.  Having a prior
                  set means that you have called set_prior() and supplied a previously
                  trained function as a reference.  In this case, any call to train() will
                  try to learn a function that matches the behavior of the prior as close
                  as possible but also fits the supplied training data.  In more technical
                  detail, having a prior means we replace the ||w||^2 regularizer with one
                  of the form ||w-prior||^2 where w is the set of parameters for a learned
                  function.
        !*/

        bool forces_last_weight_to_1 (
        ) const;
        /*!
            ensures
                - returns true if this trainer has the constraint that the last weight in
                  the learned parameter vector must be 1.  This is the weight corresponding
                  to the feature in the training vectors with the highest dimension.
                - Forcing the last weight to 1 also disables the bias and therefore the b
                  field of the learned decision_function will be 0 when forces_last_weight_to_1() == true.
        !*/

        void force_last_weight_to_1 (
            bool should_last_weight_be_1
        );
        /*!
            ensures
                - #forces_last_weight_to_1() == should_last_weight_be_1
                - if (should_last_weight_be_1 == true) then
                    - #has_prior() == false
        !*/

        void set_c (
            scalar_type C
        );
        /*!
            requires
                - C > 0
            ensures
                - #get_c_class1() == C
                - #get_c_class2() == C
        !*/

        const scalar_type get_c_class1 (
        ) const;
        /*!
            ensures
                - returns the SVM regularization parameter for the +1 class.
                  It is the parameter that determines the trade off between
                  trying to fit the +1 training data exactly or allowing more errors
                  but hopefully improving the generalization of the resulting
                  classifier.  Larger values encourage exact fitting while
                  smaller values of C may encourage better generalization.
        !*/

        const scalar_type get_c_class2 (
        ) const;
        /*!
            ensures
                - returns the SVM regularization parameter for the -1 class.
                  It is the parameter that determines the trade off between
                  trying to fit the -1 training data exactly or allowing more errors
                  but hopefully improving the generalization of the resulting
                  classifier.  Larger values encourage exact fitting while
                  smaller values of C may encourage better generalization.
        !*/

        void set_c_class1 (
            scalar_type C
        );
        /*!
            requires
                - C > 0
            ensures
                - #get_c_class1() == C
        !*/

        void set_c_class2 (
            scalar_type C
        );
        /*!
            requires
                - C > 0
            ensures
                - #get_c_class2() == C
        !*/

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y
        ) const;
        /*!
            requires
                - is_learning_problem(x,y) == true
                  (Note that it is ok for x.size() == 1)
                - All elements of y must be equal to +1 or -1
                - x == a matrix or something convertible to a matrix via mat().
                  Also, x should contain sample_type objects.
                - y == a matrix or something convertible to a matrix via mat().
                  Also, y should contain scalar_type objects.
                - if (has_prior()) then
                    - The vectors in x must have the same dimensionality as the vectors
                      used to train the prior given to set_prior().
            ensures
                - trains a C support vector classifier given the training samples in x and
                  labels in y.
                - returns a decision function F with the following properties:
                    - F.alpha.size() == 1
                    - F.basis_vectors.size() == 1
                    - F.alpha(0) == 1
                    - if (new_x is a sample predicted have +1 label) then
                        - F(new_x) >= 0
                    - else
                        - F(new_x) < 0
        !*/

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y,
            scalar_type& svm_objective
        ) const;
        /*!
            requires
                - is_learning_problem(x,y) == true
                  (Note that it is ok for x.size() == 1)
                - All elements of y must be equal to +1 or -1
                - x == a matrix or something convertible to a matrix via mat().
                  Also, x should contain sample_type objects.
                - y == a matrix or something convertible to a matrix via mat().
                  Also, y should contain scalar_type objects.
                - if (has_prior()) then
                    - The vectors in x must have the same dimensionality as the vectors
                      used to train the prior given to set_prior().
            ensures
                - trains a C support vector classifier given the training samples in x and
                  labels in y.
                - #svm_objective == the final value of the SVM objective function
                - returns a decision function F with the following properties:
                    - F.alpha.size() == 1
                    - F.basis_vectors.size() == 1
                    - F.alpha(0) == 1
                    - if (new_x is a sample predicted have +1 label) then
                        - F(new_x) >= 0
                    - else
                        - F(new_x) < 0
        !*/

    };

}

#endif // DLIB_SVM_C_LiNEAR_TRAINER_ABSTRACT_Hh_


dlib C++ Library - svm_c_trainer_abstract.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SVm_C_TRAINER_ABSTRACT_
#ifdef DLIB_SVm_C_TRAINER_ABSTRACT_

#include <cmath>
#include <limits>
#include <sstream>
#include "../matrix/matrix_abstract.h"
#include "../algs.h"
#include "function_abstract.h"
#include "kernel_abstract.h"
#include "../optimization/optimization_solve_qp3_using_smo_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename K
        >
    class svm_c_trainer
    {
        /*!
            REQUIREMENTS ON K
                is a kernel function object as defined in dlib/svm/kernel_abstract.h

            WHAT THIS OBJECT REPRESENTS
                This object implements a trainer for a C support vector machine for
                solving binary classification problems.  It is implemented using the SMO
                algorithm.

                The implementation of the C-SVM training algorithm used by this object is based
                on the following paper:
                    - Chih-Chung Chang and Chih-Jen Lin, LIBSVM : a library for support vector
                      machines, 2001. Software available at http://www.csie.ntu.edu.tw/~cjlin/libsvm

        !*/

    public:
        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 decision_function<kernel_type> trained_function_type;

        svm_c_trainer (
        );
        /*!
            ensures
                - This object is properly initialized and ready to be used
                  to train a support vector machine.
                - #get_c_class1() == 1
                - #get_c_class2() == 1
                - #get_cache_size() == 200
                - #get_epsilon() == 0.001
        !*/

        svm_c_trainer (
            const kernel_type& kernel,
            const scalar_type& C
        );
        /*!
            requires
                - 0 < C
            ensures
                - This object is properly initialized and ready to be used
                  to train a support vector machine.
                - #get_kernel() == kernel
                - #get_c_class1() == C
                - #get_c_class2() == C
                - #get_cache_size() == 200
                - #get_epsilon() == 0.001
        !*/

        void set_cache_size (
            long cache_size
        );
        /*!
            requires
                - cache_size > 0
            ensures
                - #get_cache_size() == cache_size
        !*/

        const long get_cache_size (
        ) const;
        /*!
            ensures
                - returns the number of megabytes of cache this object will use
                  when it performs training via the this->train() function.
                  (bigger values of this may make training go faster but won't affect
                  the result.  However, too big a value will cause you to run out of
                  memory, obviously.)
        !*/

        void set_epsilon (
            scalar_type eps
        );
        /*!
            requires
                - eps > 0
            ensures
                - #get_epsilon() == eps
        !*/

        const scalar_type get_epsilon (
        ) const;
        /*!
            ensures
                - returns the error epsilon that determines when training should stop.
                  Generally a good value for this is 0.001.  Smaller values may result
                  in a more accurate solution but take longer to execute.
        !*/

        void set_kernel (
            const kernel_type& k
        );
        /*!
            ensures
                - #get_kernel() == k
        !*/

        const kernel_type& get_kernel (
        ) const;
        /*!
            ensures
                - returns a copy of the kernel function in use by this object
        !*/

        void set_c (
            scalar_type C
        );
        /*!
            requires
                - C > 0
            ensures
                - #get_c_class1() == C
                - #get_c_class2() == C
        !*/

        const scalar_type get_c_class1 (
        ) const;
        /*!
            ensures
                - returns the SVM regularization parameter for the +1 class.
                  It is the parameter that determines the trade off between
                  trying to fit the +1 training data exactly or allowing more errors
                  but hopefully improving the generalization ability of the
                  resulting classifier.  Larger values encourage exact fitting
                  while smaller values of C may encourage better generalization.
        !*/

        const scalar_type get_c_class2 (
        ) const;
        /*!
            ensures
                - returns the SVM regularization parameter for the -1 class.
                  It is the parameter that determines the trade off between
                  trying to fit the -1 training data exactly or allowing more errors
                  but hopefully improving the generalization ability of the
                  resulting classifier.  Larger values encourage exact fitting
                  while smaller values of C may encourage better generalization.
        !*/

        void set_c_class1 (
            scalar_type C
        );
        /*!
            requires
                - C > 0
            ensures
                - #get_c_class1() == C
        !*/

        void set_c_class2 (
            scalar_type C
        );
        /*!
            requires
                - C > 0
            ensures
                - #get_c_class2() == C
        !*/

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y
        ) const;
        /*!
            requires
                - is_binary_classification_problem(x,y) == true
                - x == a matrix or something convertible to a matrix via mat().
                  Also, x should contain sample_type objects.
                - y == a matrix or something convertible to a matrix via mat().
                  Also, y should contain scalar_type objects.
            ensures
                - trains a C support vector classifier given the training samples in x and
                  labels in y.  Training is done when the error is less than get_epsilon().
                - returns a decision function F with the following properties:
                    - if (new_x is a sample predicted have +1 label) then
                        - F(new_x) >= 0
                    - else
                        - F(new_x) < 0
        !*/

        void swap (
            svm_c_trainer& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/
    };

    template <typename K>
    void swap (
        svm_c_trainer<K>& a,
        svm_c_trainer<K>& b
    ) { a.swap(b); }
    /*!
        provides a global swap
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SVm_C_TRAINER_ABSTRACT_


dlib C++ Library - svm_nu_trainer_abstract.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SVm_NU_TRAINER_ABSTRACT_
#ifdef DLIB_SVm_NU_TRAINER_ABSTRACT_

#include <cmath>
#include <limits>
#include <sstream>
#include "../matrix/matrix_abstract.h"
#include "../algs.h"
#include "../serialize.h"
#include "function_abstract.h"
#include "kernel_abstract.h"
#include "../optimization/optimization_solve_qp2_using_smo_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename K
        >
    class svm_nu_trainer
    {
        /*!
            REQUIREMENTS ON K
                is a kernel function object as defined in dlib/svm/kernel_abstract.h

            WHAT THIS OBJECT REPRESENTS
                This object implements a trainer for a nu support vector machine for
                solving binary classification problems.  It is implemented using the SMO
                algorithm.

                The implementation of the nu-svm training algorithm used by this object is based
                on the following excellent papers:
                    - Chang and Lin, Training {nu}-Support Vector Classifiers: Theory and Algorithms
                    - Chih-Chung Chang and Chih-Jen Lin, LIBSVM : a library for support vector
                      machines, 2001. Software available at http://www.csie.ntu.edu.tw/~cjlin/libsvm

        !*/

    public:
        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 decision_function<kernel_type> trained_function_type;

        svm_nu_trainer (
        );
        /*!
            ensures
                - This object is properly initialized and ready to be used
                  to train a support vector machine.
                - #get_nu() == 0.1
                - #get_cache_size() == 200
                - #get_epsilon() == 0.001
        !*/

        svm_nu_trainer (
            const kernel_type& kernel,
            const scalar_type& nu
        );
        /*!
            requires
                - 0 < nu <= 1
            ensures
                - This object is properly initialized and ready to be used
                  to train a support vector machine.
                - #get_kernel() == kernel
                - #get_nu() == nu
                - #get_cache_size() == 200
                - #get_epsilon() == 0.001
        !*/

        void set_cache_size (
            long cache_size
        );
        /*!
            requires
                - cache_size > 0
            ensures
                - #get_cache_size() == cache_size
        !*/

        const long get_cache_size (
        ) const;
        /*!
            ensures
                - returns the number of megabytes of cache this object will use
                  when it performs training via the this->train() function.
                  (bigger values of this may make training go faster but won't affect
                  the result.  However, too big a value will cause you to run out of
                  memory, obviously.)
        !*/

        void set_epsilon (
            scalar_type eps
        );
        /*!
            requires
                - eps > 0
            ensures
                - #get_epsilon() == eps
        !*/

        const scalar_type get_epsilon (
        ) const;
        /*!
            ensures
                - returns the error epsilon that determines when training should stop.
                  Generally a good value for this is 0.001.  Smaller values may result
                  in a more accurate solution but take longer to execute.
        !*/

        void set_kernel (
            const kernel_type& k
        );
        /*!
            ensures
                - #get_kernel() == k
        !*/

        const kernel_type& get_kernel (
        ) const;
        /*!
            ensures
                - returns a copy of the kernel function in use by this object
        !*/

        void set_nu (
            scalar_type nu
        );
        /*!
            requires
                - 0 < nu <= 1
            ensures
                - #get_nu() == nu
        !*/

        const scalar_type get_nu (
        ) const;
        /*!
            ensures
                - returns the nu svm parameter.  This is a value between 0 and
                  1.  It is the parameter that determines the trade off between
                  trying to fit the training data exactly or allowing more errors
                  but hopefully improving the generalization ability of the
                  resulting classifier.  Smaller values encourage exact fitting
                  while larger values of nu may encourage better generalization.
                  For more information you should consult the papers referenced
                  above.
        !*/

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y
        ) const;
        /*!
            requires
                - is_binary_classification_problem(x,y) == true
                - x == a matrix or something convertible to a matrix via mat().
                  Also, x should contain sample_type objects.
                - y == a matrix or something convertible to a matrix via mat().
                  Also, y should contain scalar_type objects.
            ensures
                - trains a nu support vector classifier given the training samples in x and
                  labels in y.  Training is done when the error is less than get_epsilon().
                - returns a decision function F with the following properties:
                    - if (new_x is a sample predicted have +1 label) then
                        - F(new_x) >= 0
                    - else
                        - F(new_x) < 0
            throws
                - invalid_nu_error
                  This exception is thrown if get_nu() >= maximum_nu(y)
                - std::bad_alloc
        !*/

        void swap (
            svm_nu_trainer& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/
    };

    template <typename K>
    void swap (
        svm_nu_trainer<K>& a,
        svm_nu_trainer<K>& b
    ) { a.swap(b); }
    /*!
        provides a global swap
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SVm_NU_TRAINER_ABSTRACT_


dlib C++ Library - pegasos_abstract.h

// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_PEGASoS_ABSTRACT_
#ifdef DLIB_PEGASoS_ABSTRACT_

#include <cmath>
#include "../algs.h"
#include "function_abstract.h"
#include "kernel_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename kern_type
        >
    class svm_pegasos
    {
        /*!
            REQUIREMENTS ON kern_type
                is a kernel function object as defined in dlib/svm/kernel_abstract.h

            WHAT THIS OBJECT REPRESENTS
                This object implements an online algorithm for training a support
                vector machine for solving binary classification problems.

                The implementation of the Pegasos algorithm used by this object is based
                on the following excellent paper:
                    Pegasos: Primal estimated sub-gradient solver for SVM (2007)
                    by Shai Shalev-Shwartz, Yoram Singer, Nathan Srebro
                    In ICML

                This SVM training algorithm has two interesting properties.  First, the
                pegasos algorithm itself converges to the solution in an amount of time
                unrelated to the size of the training set (in addition to being quite fast
                to begin with).  This makes it an appropriate algorithm for learning from
                very large datasets.  Second, this object uses the dlib::kcentroid object
                to maintain a sparse approximation of the learned decision function.
                This means that the number of support vectors in the resulting decision
                function is also unrelated to the size of the dataset (in normal SVM
                training algorithms, the number of support vectors grows approximately
                linearly with the size of the training set).
        !*/

    public:
        typedef kern_type 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 decision_function<kernel_type> trained_function_type;

        template <typename K_>
        struct rebind {
            typedef svm_pegasos<K_> other;
        };

        svm_pegasos (
        );
        /*!
            ensures
                - this object is properly initialized
                - #get_lambda_class1() == 0.0001
                - #get_lambda_class2() == 0.0001
                - #get_tolerance() == 0.01
                - #get_train_count() == 0
                - #get_max_num_sv() == 40
        !*/

        svm_pegasos (
            const kernel_type& kernel_,
            const scalar_type& lambda_,
            const scalar_type& tolerance_,
            unsigned long max_num_sv
        );
        /*!
            requires
                - lambda_ > 0
                - tolerance_ > 0
                - max_num_sv > 0
            ensures
                - this object is properly initialized
                - #get_lambda_class1() == lambda_
                - #get_lambda_class2() == lambda_
                - #get_tolerance() == tolerance_
                - #get_kernel() == kernel_
                - #get_train_count() == 0
                - #get_max_num_sv() == max_num_sv
        !*/

        void clear (
        );
        /*!
            ensures
                - #get_train_count() == 0
                - clears out any memory of previous calls to train()
                - doesn't change any of the algorithm parameters.  I.e.
                    - #get_lambda_class1()  == get_lambda_class1()
                    - #get_lambda_class2()  == get_lambda_class2()
                    - #get_tolerance()      == get_tolerance()
                    - #get_kernel()         == get_kernel()
                    - #get_max_num_sv()     == get_max_num_sv()
        !*/

        const scalar_type get_lambda_class1 (
        ) const;
        /*!
            ensures
                - returns the SVM regularization term for the +1 class.  It is the
                  parameter that determines the trade off between trying to fit the
                  +1 training data exactly or allowing more errors but hopefully
                  improving the generalization ability of the resulting classifier.
                  Smaller values encourage exact fitting while larger values may
                  encourage better generalization. It is also worth noting that the
                  number of iterations it takes for this algorithm to converge is
                  proportional to 1/lambda.  So smaller values of this term cause
                  the running time of this algorithm to increase.  For more
                  information you should consult the paper referenced above.
        !*/

        const scalar_type get_lambda_class2 (
        ) const;
        /*!
            ensures
                - returns the SVM regularization term for the -1 class.  It has
                  the same properties as the get_lambda_class1() parameter except that
                  it applies to the -1 class.
        !*/

        const scalar_type get_tolerance (
        ) const;
        /*!
            ensures
                - returns the tolerance used by the internal kcentroid object to
                  represent the learned decision function.  Smaller values of this
                  tolerance will result in a more accurate representation of the
                  decision function but will use more support vectors (up to
                  a max of get_max_num_sv()).
        !*/

        unsigned long get_max_num_sv (
        ) const;
        /*!
            ensures
                - returns the maximum number of support vectors this object is
                  allowed to use.
        !*/

        const kernel_type get_kernel (
        ) const;
        /*!
            ensures
                - returns the kernel used by this object
        !*/

        void set_kernel (
            kernel_type k
        );
        /*!
            ensures
                - #get_kernel() == k
                - #get_train_count() == 0
                  (i.e. clears any memory of previous training)
        !*/

        void set_tolerance (
            double tol
        );
        /*!
            requires
                - tol > 0
            ensures
                - #get_tolerance() == tol
                - #get_train_count() == 0
                  (i.e. clears any memory of previous training)
        !*/

        void set_max_num_sv (
            unsigned long max_num_sv
        );
        /*!
            requires
                - max_num_sv > 0
            ensures
                - #get_max_num_sv() == max_num_sv
                - #get_train_count() == 0
                  (i.e. clears any memory of previous training)
        !*/

        void set_lambda (
            scalar_type lambda_
        );
        /*!
            requires
                - lambda_ > 0
            ensures
                - #get_lambda_class1() == lambda_
                - #get_lambda_class2() == lambda_
                - #get_train_count() == 0
                  (i.e. clears any memory of previous training)
        !*/

        void set_lambda_class1 (
            scalar_type lambda_
        );
        /*!
            requires
                - lambda_ > 0
            ensures
                - #get_lambda_class1() == lambda_
                  #get_train_count() == 0
                  (i.e. clears any memory of previous training)
        !*/

        void set_lambda_class2 (
            scalar_type lambda_
        );
        /*!
            requires
                - lambda_ > 0
            ensures
                - #get_lambda_class2() == lambda_
                  #get_train_count() == 0
                  (i.e. clears any memory of previous training)
        !*/

        unsigned long get_train_count (
        ) const;
        /*!
            ensures
                - returns how many times this->train() has been called
                  since this object was constructed or last cleared.
        !*/

        scalar_type train (
            const sample_type& x,
            const scalar_type& y
        );
        /*!
            requires
                - y == 1 || y == -1
            ensures
                - trains this svm using the given sample x and label y
                - #get_train_count() == get_train_count() + 1
                - returns the current learning rate
                  (i.e. 1/(get_train_count()*min(get_lambda_class1(),get_lambda_class2())) )
        !*/

        scalar_type operator() (
            const sample_type& x
        ) const;
        /*!
            ensures
                - classifies the given x sample using the decision function
                  this object has learned so far.
                - if (x is a sample predicted have +1 label) then
                    - returns a number >= 0
                - else
                    - returns a number < 0
        !*/

        const decision_function<kernel_type> get_decision_function (
        ) const;
        /*!
            ensures
                - returns a decision function F that represents the function learned
                  by this object so far.  I.e. it is the case that:
                    - for all x: F(x) == (*this)(x)
        !*/

        void swap (
            svm_pegasos& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <
        typename kern_type
        >
    void swap(
        svm_pegasos<kern_type>& a,
        svm_pegasos<kern_type>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

    template <
        typename kern_type
        >
    void serialize (
        const svm_pegasos<kern_type>& item,
        std::ostream& out
    );
    /*!
        provides serialization support for svm_pegasos objects
    !*/

    template <
        typename kern_type
        >
    void deserialize (
        svm_pegasos<kern_type>& item,
        std::istream& in
    );
    /*!
        provides serialization support for svm_pegasos objects
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename U
        >
    void replicate_settings (
        const svm_pegasos<T>& source,
        svm_pegasos<U>& dest
    );
    /*!
        ensures
            - copies all the parameters from the source trainer to the dest trainer.
            - #dest.get_tolerance() == source.get_tolerance()
            - #dest.get_lambda_class1() == source.get_lambda_class1()
            - #dest.get_lambda_class2() == source.get_lambda_class2()
            - #dest.get_max_num_sv() == source.get_max_num_sv()
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type
        >
    class batch_trainer
    {
        /*!
            REQUIREMENTS ON trainer_type
                - trainer_type == some kind of online trainer object (e.g. svm_pegasos)
                  replicate_settings() must also be defined for the type.

            WHAT THIS OBJECT REPRESENTS
                This is a trainer object that is meant to wrap online trainer objects
                that create decision_functions. It turns an online learning algorithm
                such as svm_pegasos into a batch learning object.  This allows you to
                use objects like svm_pegasos with functions (e.g. cross_validate_trainer)
                that expect batch mode training objects.
        !*/

    public:
        typedef typename trainer_type::kernel_type kernel_type;
        typedef typename trainer_type::scalar_type scalar_type;
        typedef typename trainer_type::sample_type sample_type;
        typedef typename trainer_type::mem_manager_type mem_manager_type;
        typedef typename trainer_type::trained_function_type trained_function_type;

        batch_trainer (
        );
        /*!
            ensures
                - This object is in an uninitialized state.  You must
                  construct a real one with the other constructor and assign it
                  to this instance before you use this object.
        !*/

        batch_trainer (
            const trainer_type& online_trainer,
            const scalar_type min_learning_rate_,
            bool verbose_,
            bool use_cache_,
            long cache_size_ = 100
        );
        /*!
            requires
                - min_learning_rate_ > 0
                - cache_size_ > 0
            ensures
                - returns a batch trainer object that uses the given online_trainer object
                  to train a decision function.
                - #get_min_learning_rate() == min_learning_rate_
                - if (verbose_ == true) then
                    - this object will output status messages to standard out while
                      training is under way.
                - if (use_cache_ == true) then
                    - this object will cache up to cache_size_ columns of the kernel
                      matrix during the training process.
        !*/

        const scalar_type get_min_learning_rate (
        ) const;
        /*!
            ensures
                - returns the min learning rate that the online trainer must reach
                  before this object considers training to be complete.
        !*/

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y
        ) const;
        /*!
            ensures
                - trains and returns a decision_function using the trainer that was
                  supplied to this object's constructor.
                - training continues until the online training object indicates that
                  its learning rate has dropped below get_min_learning_rate().
            throws
                - std::bad_alloc
                - any exceptions thrown by the trainer_type object
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type
        >
    const batch_trainer<trainer_type> batch (
        const trainer_type& trainer,
        const typename trainer_type::scalar_type min_learning_rate = 0.1
    ) { return batch_trainer<trainer_type>(trainer, min_learning_rate, false, false); }
    /*!
        requires
            - min_learning_rate > 0
            - trainer_type == some kind of online trainer object that creates decision_function
              objects (e.g. svm_pegasos).  replicate_settings() must also be defined for the type.
        ensures
            - returns a batch_trainer object that has been instantiated with the
              given arguments.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type
        >
    const batch_trainer<trainer_type> verbose_batch (
        const trainer_type& trainer,
        const typename trainer_type::scalar_type min_learning_rate = 0.1
    ) { return batch_trainer<trainer_type>(trainer, min_learning_rate, true, false); }
    /*!
        requires
            - min_learning_rate > 0
            - trainer_type == some kind of online trainer object that creates decision_function
              objects (e.g. svm_pegasos).  replicate_settings() must also be defined for the type.
        ensures
            - returns a batch_trainer object that has been instantiated with the
              given arguments (and is verbose).
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type
        >
    const batch_trainer<trainer_type> batch_cached (
        const trainer_type& trainer,
        const typename trainer_type::scalar_type min_learning_rate = 0.1,
        long cache_size = 100
    ) { return batch_trainer<trainer_type>(trainer, min_learning_rate, false, true, cache_size); }
    /*!
        requires
            - min_learning_rate > 0
            - cache_size > 0
            - trainer_type == some kind of online trainer object that creates decision_function
              objects (e.g. svm_pegasos).  replicate_settings() must also be defined for the type.
        ensures
            - returns a batch_trainer object that has been instantiated with the
              given arguments (uses a kernel cache).
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type
        >
    const batch_trainer<trainer_type> verbose_batch_cached (
        const trainer_type& trainer,
        const typename trainer_type::scalar_type min_learning_rate = 0.1,
        long cache_size = 100
    ) { return batch_trainer<trainer_type>(trainer, min_learning_rate, true, true, cache_size); }
    /*!
        requires
            - min_learning_rate > 0
            - cache_size > 0
            - trainer_type == some kind of online trainer object that creates decision_function
              objects (e.g. svm_pegasos).  replicate_settings() must also be defined for the type.
        ensures
            - returns a batch_trainer object that has been instantiated with the
              given arguments (is verbose and uses a kernel cache).
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_PEGASoS_ABSTRACT_


dlib C++ Library - svm_abstract.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SVm_ABSTRACT_
#ifdef DLIB_SVm_ABSTRACT_

#include <cmath>
#include <limits>
#include <sstream>
#include "../matrix/matrix_abstract.h"
#include "../algs.h"
#include "../serialize.h"
#include "function_abstract.h"
#include "kernel_abstract.h"
#include "svm_nu_trainer_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename U
        >
    bool is_learning_problem (
        const T& x,
        const U& x_labels
    );
    /*!
        requires
            - T == a matrix or something convertible to a matrix via mat()
            - U == a matrix or something convertible to a matrix via mat()
        ensures
            - returns true if all of the following are true and false otherwise:
                - is_col_vector(x) == true
                - is_col_vector(x_labels) == true
                - x.size() == x_labels.size()
                - x.size() > 0
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename U
        >
    bool is_binary_classification_problem (
        const T& x,
        const U& x_labels
    );
    /*!
        requires
            - T == a matrix or something convertible to a matrix via mat()
            - U == a matrix or something convertible to a matrix via mat()
        ensures
            - returns true if all of the following are true and false otherwise:
                - is_learning_problem(x, x_labels) == true
                - x.size() > 1
                - there exists at least one sample from both the +1 and -1 classes.
                  (i.e. all samples can't have the same label)
                - for all valid i:
                    - x_labels(i) == -1 or +1
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename sequence_type
        >
    bool is_sequence_labeling_problem (
        const std::vector<sequence_type>& samples,
        const std::vector<std::vector<unsigned long> >& labels
    );
    /*!
        ensures
            - returns true if all of the following are true and false otherwise:
                - is_learning_problem(samples, labels) == true
                - for all valid i:
                    - samples[i].size() == labels[i].size()
                      (i.e. The size of a label sequence need to match the size of
                      its corresponding sample sequence)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename sequence_type
        >
    bool is_sequence_segmentation_problem (
        const std::vector<sequence_type>& samples,
        const std::vector<std::vector<std::pair<unsigned long,unsigned long> > >& segments
    );
    /*!
        ensures
            - Note that a sequence segmentation problem is a task where you are given a
              sequence of objects (e.g. words in a sentence) and your task is to find
              certain types of sub-sequences (e.g. proper names).
            - returns true if all of the following are true and false otherwise:
                - is_learning_problem(samples, segments) == true
                - for all valid i and j:
                    - We interpret segments[i][j] as defining a half open range starting
                      with segments[i][j].first and ending just before segments[i][j].second.
                    - segments[i][j].first < segments[i][j].second
                    - segments[i][j].second <= samples[i].size()
                      (i.e. Each segment must be contained within its associated sequence)
                    - segments[i][j] does not overlap with any of the other ranges in
                      segments[i].
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename lhs_type,
        typename rhs_type
        >
    bool is_assignment_problem (
        const std::vector<std::pair<std::vector<lhs_type>, std::vector<rhs_type> > >& samples,
        const std::vector<std::vector<long> >& labels
    );
    /*!
        ensures
            - Note that an assignment problem is a task to associate each element of samples[i].first
              to an element of samples[i].second, or to indicate that the element doesn't associate
              with anything.  Therefore, labels[i] should contain the association information for
              samples[i].
            - This function returns true if all of the following are true and false otherwise:
                - is_learning_problem(samples, labels) == true
                - for all valid i:
                    - samples[i].first.size() == labels[i].size()
                    - for all valid j:
                        -1 <= labels[i][j] < samples[i].second.size()
                        (A value of -1 indicates that samples[i].first[j] isn't associated with anything.
                        All other values indicate the associating element of samples[i].second)
                    - All elements of labels[i] which are not equal to -1 are unique.  That is,
                      multiple elements of samples[i].first can't associate to the same element
                      in samples[i].second.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename lhs_type,
        typename rhs_type
        >
    bool is_forced_assignment_problem (
        const std::vector<std::pair<std::vector<lhs_type>, std::vector<rhs_type> > >& samples,
        const std::vector<std::vector<long> >& labels
    );
    /*!
        ensures
            - A regular assignment problem is allowed to indicate that all elements of
              samples[i].first don't associate to anything.  However, a forced assignment
              problem is required to always associate an element of samples[i].first to
              something in samples[i].second if there is an element of samples[i].second
              that hasn't already been associated to something.
            - This function returns true if all of the following are true and false otherwise:
                - is_assignment_problem(samples, labels) == true
                - for all valid i:
                    - let N denote the number of elements in labels[i] that are not equal to -1.
                    - min(samples[i].first.size(), samples[i].second.size()) == N
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename detection_type_,
        typename label_type_ = long
        >
    struct labeled_detection
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is a simple object, like std::pair, it just holds two objects.  It
                serves the same purpose as std::pair except that it has informative names
                describing its two members and is intended for use with track association
                problems.
        !*/

        typedef detection_type_ detection_type;
        typedef label_type_ label_type;

        detection_type det;
        label_type label;
    };

    template <
        typename detection_type_,
        typename label_type_
        >
    void serialize (const labeled_detection<detection_type_,label_type_>& item, std::ostream& out);
    /*!
        provides serialization support
    !*/

    template <
        typename detection_type_,
        typename label_type_
        >
    void deserialize (labeled_detection<detection_type_,label_type_>& item, std::istream& in);
    /*!
        provides deserialization support
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename detection_type,
        typename label_type
        >
    bool is_track_association_problem (
        const std::vector<std::vector<labeled_detection<detection_type,label_type> > >& samples
    );
    /*!
        ensures
            - In this tracking model you get a set of detections at each time step and are
              expected to associate each detection with a track or have it spawn a new
              track.  Therefore, a track association problem is a machine learning problem
              where you are given a dataset of example input detections and are expected to
              learn to perform the proper detection to track association.
            - This function checks if samples can form a valid dataset for this machine
              learning problem and returns true if this is the case.  This means we should
              interpret samples in the following way:
                - samples is a track history and for each valid i:
                    - samples[i] is a set of labeled detections from the i-th time step.
                      Each detection has been labeled with its "true object identity".
                      That is, all the detection throughout the history with the same
                      label_type value are detections from the same object and therefore
                      should be associated to the same track.
              Putting this all together, samples is a valid track association learning
              problem if and only if the following are all true:
                - samples.size() > 0
                - There are at least two values, i and j such that:
                    - i != j
                    - samples[i].size() > 0
                    - samples[j].size() > 0
                  Or in other words, there needs to be some detections in samples somewhere
                  or it is impossible to learn anything.
                - for all valid i:
                    - for all valid j and k where j!=k:
                        - samples[i][j].label != samples[i][k].label
                          (i.e. the label_type values must be unique within each time step.
                          Or in other words, you can't have two detections on the same
                          object in a single time step.)
    !*/

    template <
        typename detection_type,
        typename label_type
        >
    bool is_track_association_problem (
        const std::vector<std::vector<std::vector<labeled_detection<detection_type,label_type> > > >& samples
    );
    /*!
        ensures
            - returns true if is_track_association_problem(samples[i]) == true for all
              valid i and false otherwise.
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    double platt_scale (
        const std::pair<double,double>& params,
        const double score
    );
    /*!
        ensures
            - returns 1/(1 + std::exp(params.first*score + params.second))
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T, typename alloc>
    std::pair<double,double> learn_platt_scaling (
        const std::vector<T,alloc>& scores,
        const std::vector<T,alloc>& labels
    );
    /*!
        requires
            - T should be either float, double, or long double
            - is_binary_classification_problem(scores,labels) == true
        ensures
            - This function learns to map scalar values into well calibrated probabilities
              using Platt scaling.  In particular, it returns a params object such that,
              for all valid i:
                - platt_scale(params,scores[i]) == the scaled version of the scalar value
                  scores[i].  That is, the output is a number between 0 and 1.  In
                  particular, platt_scale(params,scores[i]) is meant to represent the
                  probability that labels[i] == +1.
            - This function is an implementation of the algorithm described in the following
              papers:
                Probabilistic Outputs for Support Vector Machines and Comparisons to
                Regularized Likelihood Methods by John C. Platt.  March 26, 1999

                A Note on Platt's Probabilistic Outputs for Support Vector Machines
                by Hsuan-Tien Lin, Chih-Jen Lin, and Ruby C. Weng
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type,
        typename sample_vector_type,
        typename label_vector_type
        >
    const probabilistic_function<typename trainer_type::trained_function_type>
    train_probabilistic_decision_function (
        const trainer_type& trainer,
        const sample_vector_type& x,
        const label_vector_type& y,
        const long folds
    );
    /*!
        requires
            - 1 < folds <= x.size()
            - is_binary_classification_problem(x,y) == true
            - x and y must be std::vector objects or types with a compatible interface.
            - trainer_type == some kind of batch trainer object (e.g. svm_nu_trainer)
        ensures
            - trains a classifier given the training samples in x and labels in y.
            - returns a probabilistic_decision_function that represents the trained classifier.
            - The parameters of the probability model are estimated by performing k-fold
              cross validation.
            - The number of folds used is given by the folds argument.
            - This function is implemented using learn_platt_scaling()
        throws
            - any exceptions thrown by trainer.train()
            - std::bad_alloc
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type
        >
    trainer_adapter_probabilistic<trainer_type> probabilistic (
        const trainer_type& trainer,
        const long folds
    );
    /*!
        requires
            - 1 < folds <= x.size()
            - trainer_type == some kind of batch trainer object (e.g. svm_nu_trainer)
        ensures
            - returns a trainer adapter TA such that calling TA.train(samples, labels)
              returns the same object as calling train_probabilistic_decision_function(trainer,samples,labels,folds).
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                                  Miscellaneous functions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type,
        typename in_sample_vector_type,
        typename in_scalar_vector_type
        >
    const matrix<double,1,2> cross_validate_trainer (
        const trainer_type& trainer,
        const in_sample_vector_type& x,
        const in_scalar_vector_type& y,
        const long folds
    );
    /*!
        requires
            - is_binary_classification_problem(x,y) == true
            - 1 < folds <= std::min(sum(y>0),sum(y<0))
              (e.g. There must be at least as many examples of each class as there are folds)
            - trainer_type == some kind of binary classification trainer object (e.g. svm_nu_trainer)
        ensures
            - performs k-fold cross validation by using the given trainer to solve the
              given binary classification problem for the given number of folds.
              Each fold is tested using the output of the trainer and the average
              classification accuracy from all folds is returned.
            - The average accuracy is computed by running test_binary_decision_function()
              on each fold and its output is averaged and returned.
            - The number of folds used is given by the folds argument.
        throws
            - any exceptions thrown by trainer.train()
            - std::bad_alloc
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename dec_funct_type,
        typename in_sample_vector_type,
        typename in_scalar_vector_type
        >
    const matrix<double,1,2> test_binary_decision_function (
        const dec_funct_type& dec_funct,
        const in_sample_vector_type& x_test,
        const in_scalar_vector_type& y_test
    );
    /*!
        requires
            - is_binary_classification_problem(x_test,y_test) == true
            - dec_funct_type == some kind of decision function object (e.g. decision_function)
        ensures
            - Tests the given decision function by calling it on the x_test and y_test samples.
              The output of dec_funct is interpreted as a prediction for the +1 class
              if its output is >= 0 and as a prediction for the -1 class otherwise.
            - The test accuracy is returned in a row vector, let us call it R.  Both
              quantities in R are numbers between 0 and 1 which represent the fraction
              of examples correctly classified.  R(0) is the fraction of +1 examples
              correctly classified and R(1) is the fraction of -1 examples correctly
              classified.
        throws
            - std::bad_alloc
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename U
        >
    void randomize_samples (
        T& samples,
        U& labels
    );
    /*!
        requires
            - T == a matrix object or an object compatible with std::vector that contains
              a swappable type.
            - U == a matrix object or an object compatible with std::vector that contains
              a swappable type.
            - if samples or labels are matrix objects then is_vector(samples) == true and
              is_vector(labels) == true
            - samples.size() == labels.size()
        ensures
            - randomizes the order of the samples and labels but preserves
              the pairing between each sample and its label
            - A default initialized random number generator is used to perform the randomizing.
              Note that this means that each call this this function does the same thing.
              That is, the random number generator always uses the same seed.
            - for all valid i:
                - let r == the random index samples(i) was moved to.  then:
                    - #labels(r) == labels(i)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename U,
        typename rand_type
        >
    void randomize_samples (
        T& samples,
        U& labels,
        rand_type& rnd
    );
    /*!
        requires
            - T == a matrix object or an object compatible with std::vector that contains
              a swappable type.
            - U == a matrix object or an object compatible with std::vector that contains
              a swappable type.
            - if samples or labels are matrix objects then is_vector(samples) == true and
              is_vector(labels) == true
            - samples.size() == labels.size()
            - rand_type == a type that implements the dlib/rand/rand_kernel_abstract.h interface
        ensures
            - randomizes the order of the samples and labels but preserves
              the pairing between each sample and its label
            - the given rnd random number generator object is used to do the randomizing
            - for all valid i:
                - let r == the random index samples(i) was moved to.  then:
                    - #labels(r) == labels(i)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    void randomize_samples (
        T& samples
    );
    /*!
        requires
            - T == a matrix object or an object compatible with std::vector that contains
              a swappable type.
            - if (samples is a matrix) then
                - is_vector(samples) == true
        ensures
            - randomizes the order of the elements inside samples
            - A default initialized random number generator is used to perform the randomizing.
              Note that this means that each call this this function does the same thing.
              That is, the random number generator always uses the same seed.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename rand_type
        >
    void randomize_samples (
        T& samples,
        rand_type& rnd
    );
    /*!
        requires
            - T == a matrix object or an object compatible with std::vector that contains
              a swappable type.
            - rand_type == a type that implements the dlib/rand/rand_kernel_abstract.h interface
            - if (samples is a matrix) then
                - is_vector(samples) == true
        ensures
            - randomizes the order of the elements inside samples
            - the given rnd random number generator object is used to do the randomizing
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename U,
        typename V
        >
    void randomize_samples (
        T& samples,
        U& labels,
        V& auxiliary
    );
    /*!
        requires
            - T == a matrix object or an object compatible with std::vector that contains
              a swappable type.
            - U == a matrix object or an object compatible with std::vector that contains
              a swappable type.
            - V == a matrix object or an object compatible with std::vector that contains
              a swappable type.
            - if (samples, labels, or auxiliary are matrix objects) then
                - is_vector(samples) == true
                - is_vector(labels) == true
                - is_vector(auxiliary) == true
            - samples.size() == labels.size() == auxiliary.size()
        ensures
            - randomizes the order of the samples, labels, and auxiliary but preserves the
              pairing between each sample, its label, and its auxiliary value.
            - A default initialized random number generator is used to perform the
              randomizing.  Note that this means that each call this this function does the
              same thing.  That is, the random number generator always uses the same seed.
            - for all valid i:
                - let r == the random index samples(i) was moved to.  then:
                    - #labels(r) == labels(i)
                    - #auxiliary(r) == auxiliary(i)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename U,
        typename V,
        typename rand_type
        >
    void randomize_samples (
        T& samples,
        U& labels,
        V& auxiliary,
        rand_type& rnd
    );
    /*!
        requires
            - T == a matrix object or an object compatible with std::vector that contains
              a swappable type.
            - U == a matrix object or an object compatible with std::vector that contains
              a swappable type.
            - V == a matrix object or an object compatible with std::vector that contains
              a swappable type.
            - if (samples, labels, or auxiliary are matrix objects) then
                - is_vector(samples) == true
                - is_vector(labels) == true
                - is_vector(auxiliary) == true
            - samples.size() == labels.size() == auxiliary.size()
            - rand_type == a type that implements the dlib/rand/rand_kernel_abstract.h interface
        ensures
            - randomizes the order of the samples, labels, and auxiliary but preserves the
              pairing between each sample, its label, and its auxiliary value.
            - the given rnd random number generator object is used to do the randomizing
            - for all valid i:
                - let r == the random index samples(i) was moved to.  then:
                    - #labels(r) == labels(i)
                    - #auxiliary(r) == auxiliary(i)
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SVm_ABSTRACT_


dlib C++ Library - one_vs_all_trainer_abstract.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_ONE_VS_ALL_TRAiNER_ABSTRACT_Hh_
#ifdef DLIB_ONE_VS_ALL_TRAiNER_ABSTRACT_Hh_

#include "one_vs_all_decision_function_abstract.h"
#include <vector>

#include "../any/any_trainer_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename any_trainer,
        typename label_type_ = double
        >
    class one_vs_all_trainer
    {
        /*!
            REQUIREMENTS ON any_trainer
                must be an instantiation of the dlib::any_trainer template.

            REQUIREMENTS ON label_type_
                label_type_ must be default constructable, copyable, and comparable using
                operator < and ==.  It must also be possible to write it to an std::ostream
                using operator<<.

            WHAT THIS OBJECT REPRESENTS
                This object is a tool for turning a bunch of binary classifiers into a
                multiclass classifier.  It does this by training the binary classifiers
                in a one vs. all fashion.  That is, if you have N possible classes then
                it trains N binary classifiers which are then used to vote on the identity
                of a test sample.

                This object works with any kind of binary classification trainer object
                capable of being assigned to an any_trainer object.  (e.g. the svm_nu_trainer)
        !*/

    public:

        typedef label_type_ label_type;

        typedef typename any_trainer::sample_type sample_type;
        typedef typename any_trainer::scalar_type scalar_type;
        typedef typename any_trainer::mem_manager_type mem_manager_type;

        typedef one_vs_all_decision_function<one_vs_all_trainer> trained_function_type;

        one_vs_all_trainer (
        );
        /*!
            ensures
                - This object is properly initialized.
                - This object will not be verbose unless be_verbose() is called.
                - No binary trainers are associated with *this.  I.e. you have to
                  call set_trainer() before calling train().
                - #get_num_threads() == 4
        !*/

        void set_trainer (
            const any_trainer& trainer
        );
        /*!
            ensures
                - sets the trainer used for all binary subproblems.  Any previous
                  calls to set_trainer() are overridden by this function.  Even the
                  more specific set_trainer(trainer, l) form.
        !*/

        void set_trainer (
            const any_trainer& trainer,
            const label_type& l
        );
        /*!
            ensures
                - Sets the trainer object used to create a binary classifier to
                  distinguish l labeled samples from all other samples.
        !*/

        void be_verbose (
        );
        /*!
            ensures
                - This object will print status messages to standard out so that a
                  user can observe the progress of the algorithm.
        !*/

        void be_quiet (
        );
        /*!
            ensures
                - this object will not print anything to standard out
        !*/

        void set_num_threads (
            unsigned long num
        );
        /*!
            ensures
                - #get_num_threads() == num
        !*/

        unsigned long get_num_threads (
        ) const;
        /*!
            ensures
                - returns the number of threads used during training.  You should
                  usually set this equal to the number of processing cores on your
                  machine.
        !*/

        struct invalid_label : public dlib::error
        {
            /*!
                This is the exception thrown by the train() function below.
            !*/
            label_type l;
        };

        trained_function_type train (
            const std::vector<sample_type>& all_samples,
            const std::vector<label_type>& all_labels
        ) const;
        /*!
            requires
                - is_learning_problem(all_samples, all_labels)
            ensures
                - trains a bunch of binary classifiers in a one vs all fashion to solve the given
                  multiclass classification problem.
                - returns a one_vs_all_decision_function F with the following properties:
                    - F contains all the learned binary classifiers and can be used to predict
                      the labels of new samples.
                    - if (new_x is a sample predicted to have a label of L) then
                        - F(new_x) == L
                    - F.get_labels() == select_all_distinct_labels(all_labels)
                    - F.number_of_classes() == select_all_distinct_labels(all_labels).size()
            throws
                - invalid_label
                  This exception is thrown if there are labels in all_labels which don't have
                  any corresponding trainer object.  This will never happen if set_trainer(trainer)
                  has been called.  However, if only the set_trainer(trainer,l) form has been
                  used then this exception is thrown if not all labels have been given a trainer.

                  invalid_label::l will contain the label which is missing a trainer object.
                  Additionally, the exception will contain an informative error message available
                  via invalid_label::what().
        !*/

    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_ONE_VS_ALL_TRAiNER_ABSTRACT_Hh_


dlib C++ Library - one_vs_one_trainer_abstract.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_ONE_VS_ONE_TRAiNER_ABSTRACT_Hh_
#ifdef DLIB_ONE_VS_ONE_TRAiNER_ABSTRACT_Hh_

#include "one_vs_one_decision_function_abstract.h"
#include <vector>

#include "../any/any_trainer_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename any_trainer,
        typename label_type_ = double
        >
    class one_vs_one_trainer
    {
        /*!
            REQUIREMENTS ON any_trainer
                must be an instantiation of the dlib::any_trainer template.

            REQUIREMENTS ON label_type_
                label_type_ must be default constructable, copyable, and comparable using
                operator < and ==.  It must also be possible to write it to an std::ostream
                using operator<<.

            WHAT THIS OBJECT REPRESENTS
                This object is a tool for turning a bunch of binary classifiers
                into a multiclass classifier.  It does this by training the binary
                classifiers in a one vs. one fashion.  That is, if you have N possible
                classes then it trains N*(N-1)/2 binary classifiers which are then used
                to vote on the identity of a test sample.

                This object works with any kind of binary classification trainer object
                capable of being assigned to an any_trainer object.  (e.g. the svm_nu_trainer)
        !*/

    public:

        typedef label_type_ label_type;

        typedef typename any_trainer::sample_type sample_type;
        typedef typename any_trainer::scalar_type scalar_type;
        typedef typename any_trainer::mem_manager_type mem_manager_type;

        typedef one_vs_one_decision_function<one_vs_one_trainer> trained_function_type;

        one_vs_one_trainer (
        );
        /*!
            ensures
                - This object is properly initialized
                - This object will not be verbose unless be_verbose() is called.
                - No binary trainers are associated with *this.  I.e. you have to
                  call set_trainer() before calling train().
                - #get_num_threads() == 4
        !*/

        void set_trainer (
            const any_trainer& trainer
        );
        /*!
            ensures
                - sets the trainer used for all pairs of training.  Any previous
                  calls to set_trainer() are overridden by this function.  Even the
                  more specific set_trainer(trainer, l1, l2) form.
        !*/

        void set_trainer (
            const any_trainer& trainer,
            const label_type& l1,
            const label_type& l2
        );
        /*!
            requires
                - l1 != l2
            ensures
                - Sets the trainer object used to create a binary classifier to
                  distinguish l1 labeled samples from l2 labeled samples.
        !*/

        void be_verbose (
        );
        /*!
            ensures
                - This object will print status messages to standard out so that a
                  user can observe the progress of the algorithm.
        !*/

        void be_quiet (
        );
        /*!
            ensures
                - this object will not print anything to standard out
        !*/

        void set_num_threads (
            unsigned long num
        );
        /*!
            ensures
                - #get_num_threads() == num
        !*/

        unsigned long get_num_threads (
        ) const;
        /*!
            ensures
                - returns the number of threads used during training.  You should
                  usually set this equal to the number of processing cores on your
                  machine.
        !*/

        struct invalid_label : public dlib::error
        {
            /*!
                This is the exception thrown by the train() function below.
            !*/
            label_type l1, l2;
        };

        trained_function_type train (
            const std::vector<sample_type>& all_samples,
            const std::vector<label_type>& all_labels
        ) const;
        /*!
            requires
                - is_learning_problem(all_samples, all_labels)
            ensures
                - trains a bunch of binary classifiers in a one vs one fashion to solve the given
                  multiclass classification problem.
                - returns a one_vs_one_decision_function F with the following properties:
                    - F contains all the learned binary classifiers and can be used to predict
                      the labels of new samples.
                    - if (new_x is a sample predicted to have a label of L) then
                        - F(new_x) == L
                    - F.get_labels() == select_all_distinct_labels(all_labels)
                    - F.number_of_classes() == select_all_distinct_labels(all_labels).size()
            throws
                - invalid_label
                  This exception is thrown if there are labels in all_labels which don't have
                  any corresponding trainer object.  This will never happen if set_trainer(trainer)
                  has been called.  However, if only the set_trainer(trainer,l1,l2) form has been
                  used then this exception is thrown if not all necessary label pairs have been
                  given a trainer.

                  invalid_label::l1 and invalid_label::l2 will contain the label pair which is
                  missing a trainer object.  Additionally, the exception will contain an
                  informative error message available via invalid_label::what().
        !*/

    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_ONE_VS_ONE_TRAiNER_ABSTRACT_Hh_


dlib C++ Library - svm_multiclass_linear_trainer_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SVm_MULTICLASS_LINEAR_TRAINER_ABSTRACT_Hh_
#ifdef DLIB_SVm_MULTICLASS_LINEAR_TRAINER_ABSTRACT_Hh_

#include "../matrix/matrix_abstract.h"
#include "../algs.h"
#include "function_abstract.h"
#include "kernel_abstract.h"
#include "sparse_kernel_abstract.h"
#include "../optimization/optimization_oca_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename K,
        typename label_type_ = typename K::scalar_type
        >
    class svm_multiclass_linear_trainer
    {
        /*!
            REQUIREMENTS ON K
                Is either linear_kernel or sparse_linear_kernel.

            REQUIREMENTS ON label_type_
                label_type_ must be default constructable, copyable, and comparable using
                operator < and ==.  It must also be possible to write it to an std::ostream
                using operator<<.

            INITIAL VALUE
                - get_num_threads() == 4
                - learns_nonnegative_weights() == false
                - get_epsilon() == 0.001
                - get_max_iterations() == 10000
                - get_c() == 1
                - this object will not be verbose unless be_verbose() is called
                - #get_oca() == oca() (i.e. an instance of oca with default parameters)
                - has_prior() == false

            WHAT THIS OBJECT REPRESENTS
                This object represents a tool for training a multiclass support
                vector machine.  It is optimized for the case where linear kernels
                are used.
        !*/

    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;

        svm_multiclass_linear_trainer (
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        void set_epsilon (
            scalar_type eps
        );
        /*!
            requires
                - eps > 0
            ensures
                - #get_epsilon() == eps
        !*/

        const scalar_type get_epsilon (
        ) const;
        /*!
            ensures
                - returns the error epsilon that determines when training should stop.
                  Smaller values may result in a more accurate solution but take longer
                  to execute.
        !*/

        void set_max_iterations (
            unsigned long max_iter
        );
        /*!
            ensures
                - #get_max_iterations() == max_iter
        !*/

        unsigned long get_max_iterations (
        );
        /*!
            ensures
                - returns the maximum number of iterations the SVM optimizer is allowed to
                  run before it is required to stop and return a result.
        !*/

        void be_verbose (
        );
        /*!
            ensures
                - This object will print status messages to standard out so that a
                  user can observe the progress of the algorithm.
        !*/

        void be_quiet (
        );
        /*!
            ensures
                - this object will not print anything to standard out
        !*/

        void set_oca (
            const oca& item
        );
        /*!
            ensures
                - #get_oca() == item
        !*/

        const oca get_oca (
        ) const;
        /*!
            ensures
                - returns a copy of the optimizer used to solve the SVM problem.
        !*/

        void set_num_threads (
            unsigned long num
        );
        /*!
            ensures
                - #get_num_threads() == num
        !*/

        unsigned long get_num_threads (
        ) const;
        /*!
            ensures
                - returns the number of threads used during training.  You should
                  usually set this equal to the number of processing cores on your
                  machine.
        !*/

        const kernel_type get_kernel (
        ) const;
        /*!
            ensures
                - returns a copy of the kernel function in use by this object.  Since
                  the linear kernels don't have any parameters this function just
                  returns kernel_type()
        !*/

        void set_c (
            scalar_type C
        );
        /*!
            requires
                - C > 0
            ensures
                - #get_c() == C
        !*/

        const scalar_type get_c (
        ) const;
        /*!
            ensures
                - returns the SVM regularization parameter.  It is the parameter that
                  determines the trade off between trying to fit the training data
                  exactly or allowing more errors but hopefully improving the
                  generalization of the resulting classifier.  Larger values encourage
                  exact fitting while smaller values of C may encourage better
                  generalization.
        !*/

        bool learns_nonnegative_weights (
        ) const;
        /*!
            ensures
                - The output of training is a set of weights and bias values that together
                  define the behavior of a multiclass_linear_decision_function object.  If
                  learns_nonnegative_weights() == true then the resulting weights and bias
                  values will always have non-negative values.  That is, if this function
                  returns true then all the numbers in the multiclass_linear_decision_function
                  objects output by train() will be non-negative.
        !*/

        void set_learns_nonnegative_weights (
            bool value
        );
        /*!
            ensures
                - #learns_nonnegative_weights() == value
                - if (value == true) then
                    - #has_prior() == false
        !*/

        void set_prior (
            const trained_function_type& prior
        );
        /*!
            ensures
                - Subsequent calls to train() will try to learn a function similar to the
                  given prior.
                - #has_prior() == true
                - #learns_nonnegative_weights() == false
        !*/

        bool has_prior (
        ) const
        /*!
            ensures
                - returns true if a prior has been set and false otherwise.  Having a prior
                  set means that you have called set_prior() and supplied a previously
                  trained function as a reference.  In this case, any call to train() will
                  try to learn a function that matches the behavior of the prior as close
                  as possible but also fits the supplied training data.  In more technical
                  detail, having a prior means we replace the ||w||^2 regularizer with one
                  of the form ||w-prior||^2 where w is the set of parameters for a learned
                  function.
        !*/

        trained_function_type train (
            const std::vector<sample_type>& all_samples,
            const std::vector<label_type>& all_labels
        ) const;
        /*!
            requires
                - is_learning_problem(all_samples, all_labels)
                - All the vectors in all_samples must have the same dimensionality.
                - if (has_prior()) then
                    - The vectors in all_samples must have the same dimensionality as the
                      vectors used to train the prior given to set_prior().
            ensures
                - trains a multiclass SVM to solve the given multiclass classification problem.
                - returns a multiclass_linear_decision_function F with the following properties:
                    - if (new_x is a sample predicted to have a label of L) then
                        - F(new_x) == L
                    - F.get_labels() == select_all_distinct_labels(all_labels)
                    - F.number_of_classes() == select_all_distinct_labels(all_labels).size()
        !*/

        trained_function_type train (
            const std::vector<sample_type>& all_samples,
            const std::vector<label_type>& all_labels,
            scalar_type& svm_objective
        ) const;
        /*!
            requires
                - is_learning_problem(all_samples, all_labels)
                - All the vectors in all_samples must have the same dimensionality.
                - if (has_prior()) then
                    - The vectors in all_samples must have the same dimensionality as the
                      vectors used to train the prior given to set_prior().
            ensures
                - trains a multiclass SVM to solve the given multiclass classification problem.
                - returns a multiclass_linear_decision_function F with the following properties:
                    - if (new_x is a sample predicted to have a label of L) then
                        - F(new_x) == L
                    - F.get_labels() == select_all_distinct_labels(all_labels)
                    - F.number_of_classes() == select_all_distinct_labels(all_labels).size()
                - #svm_objective == the final value of the SVM objective function
        !*/

    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SVm_MULTICLASS_LINEAR_TRAINER_ABSTRACT_Hh_


dlib C++ Library - krls_abstract.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_KRLs_ABSTRACT_
#ifdef DLIB_KRLs_ABSTRACT_

#include <cmath>
#include "../matrix/matrix_abstract.h"
#include "../algs.h"
#include "../serialize.h"
#include "kernel_abstract.h"

namespace dlib
{

    template <
        typename kernel_type
        >
    class krls
    {
        /*!
            REQUIREMENTS ON kernel_type
                is a kernel function object as defined in dlib/svm/kernel_abstract.h

            INITIAL VALUE
                - dictionary_size() == 0

            WHAT THIS OBJECT REPRESENTS
                This is an implementation of the kernel recursive least squares algorithm
                described in the paper:
                    The Kernel Recursive Least Squares Algorithm by Yaakov Engel.

                The long and short of this algorithm is that it is an online kernel based
                regression algorithm.  You give it samples (x,y) and it learns the function
                f(x) == y.  For a detailed description of the algorithm read the above paper.

                Also note that the algorithm internally keeps a set of "dictionary vectors"
                that are used to represent the regression function.  You can force the
                algorithm to use no more than a set number of vectors by setting
                the 3rd constructor argument to whatever you want.  However, note that
                doing this causes the algorithm to bias it's results towards more
                recent training examples.
        !*/

    public:
        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;

        explicit krls (
            const kernel_type& kernel_,
            scalar_type tolerance_ = 0.001,
            unsigned long max_dictionary_size_ = 1000000
        );
        /*!
            requires
                - tolerance >= 0
            ensures
                - this object is properly initialized
                - #tolerance() == tolerance_
                - #get_decision_function().kernel_function == kernel_
                  (i.e. this object will use the given kernel function)
                - #get_kernel() == kernel_
                - #max_dictionary_size() == max_dictionary_size_
        !*/

        scalar_type tolerance(
        ) const;
        /*!
            ensures
                - returns the tolerance to use for the approximately linearly dependent
                  test in the KRLS algorithm.  This is a number which governs how
                  accurately this object will approximate the decision function it is
                  learning.  Smaller values generally result in a more accurate
                  estimate while also resulting in a bigger set of dictionary vectors in
                  the learned decision function.  Bigger tolerances values result in a
                  less accurate decision function but also in less dictionary vectors.
                - The exact meaning of the tolerance parameter is the following:
                  Imagine that we have an empirical_kernel_map that contains all
                  the current dictionary vectors.  Then the tolerance is the minimum
                  projection error (as given by empirical_kernel_map::project()) required
                  to cause us to include a new vector in the dictionary.  So each time
                  you call train() the krls object basically just computes the projection
                  error for that new sample and if it is larger than the tolerance
                  then that new sample becomes part of the dictionary.
        !*/

        const kernel_type& get_kernel (
        ) const;
        /*!
            ensures
                - returns a const reference to the kernel used by this object
        !*/

        unsigned long max_dictionary_size(
        ) const;
        /*!
            ensures
                - returns the maximum number of dictionary vectors this object
                  will use at a time.  That is, dictionary_size() will never be
                  greater than max_dictionary_size().
        !*/

        void clear_dictionary (
        );
        /*!
            ensures
                - clears out all learned data
                  (e.g. #get_decision_function().basis_vectors.size() == 0)
        !*/

        scalar_type operator() (
            const sample_type& x
        ) const;
        /*!
            ensures
                - returns the current y estimate for the given x
        !*/

        void train (
            const sample_type& x,
            scalar_type y
        );
        /*!
            ensures
                - trains this object that the given x should be mapped to the given y
                - if (dictionary_size() == max_dictionary_size() and training
                  would add another dictionary vector to this object) then
                    - discards the oldest dictionary vector so that we can still
                      add a new one and remain below the max number of dictionary
                      vectors.
        !*/

        void swap (
            krls& item
        );
        /*!
            ensures
                - swaps *this with item
        !*/

        unsigned long dictionary_size (
        ) const;
        /*!
            ensures
                - returns the number of vectors in the dictionary.  That is,
                  returns a number equal to get_decision_function().basis_vectors.size()
        !*/

        decision_function<kernel_type> get_decision_function (
        ) const;
        /*!
            ensures
                - returns a decision function F that represents the function learned
                  by this object so far.  I.e. it is the case that:
                    - for all x: F(x) == (*this)(x)
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <
        typename kernel_type
        >
    void swap(
        krls<kernel_type>& a,
        krls<kernel_type>& b
    )
    { a.swap(b); }
    /*!
        provides a global swap function
    !*/

    template <
        typename kernel_type
        >
    void serialize (
        const krls<kernel_type>& item,
        std::ostream& out
    );
    /*!
        provides serialization support for krls objects
    !*/

    template <
        typename kernel_type
        >
    void deserialize (
        krls<kernel_type>& item,
        std::istream& in
    );
    /*!
        provides serialization support for krls objects
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_KRLs_ABSTRACT_


dlib C++ Library - krr_trainer_abstract.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_KRR_TRAInER_ABSTRACT_Hh_
#ifdef DLIB_KRR_TRAInER_ABSTRACT_Hh_

#include "../algs.h"
#include "function_abstract.h"
#include "kernel_abstract.h"
#include "empirical_kernel_map_abstract.h"

namespace dlib
{
    template <
        typename K
        >
    class krr_trainer
    {
        /*!
            REQUIREMENTS ON K
                is a kernel function object as defined in dlib/svm/kernel_abstract.h

            INITIAL VALUE
                - get_lambda() == 0
                - basis_loaded() == false
                - get_max_basis_size() == 400
                - will_use_regression_loss_for_loo_cv() == true
                - get_search_lambdas() == logspace(-9, 2, 50)
                - this object will not be verbose unless be_verbose() is called

            WHAT THIS OBJECT REPRESENTS
                This object represents a tool for performing kernel ridge regression
                (This basic algorithm is also known my many other names, e.g. regularized
                least squares or least squares SVM).

                The exact definition of what this algorithm does is this:
                    Find w and b that minimizes the following (x_i are input samples and y_i are target values):
                        lambda*dot(w,w) + sum_over_i( (f(x_i) - y_i)^2 )
                        where f(x) == dot(x,w) - b

                    Except the dot products are replaced by kernel functions.  So this
                    algorithm is just regular old least squares regression but with the
                    addition of a regularization term which encourages small w and the
                    application of the kernel trick.

                It is implemented using the empirical_kernel_map and thus allows you
                to run the algorithm on large datasets and obtain sparse outputs.  It is also
                capable of estimating the lambda parameter using leave-one-out cross-validation.

                The leave-one-out cross-validation implementation is based on the techniques
                discussed in this paper:
                    Notes on Regularized Least Squares by Ryan M. Rifkin and Ross A. Lippert.
        !*/

    public:
        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 decision_function<kernel_type> trained_function_type;

        krr_trainer (
        );
        /*!
            ensures
                - This object is properly initialized and ready to be used.
        !*/

        void be_verbose (
        );
        /*!
            ensures
                - This object will print status messages to standard out.
        !*/

        void be_quiet (
        );
        /*!
            ensures
                - this object will not print anything to standard out
        !*/

        const kernel_type get_kernel (
        ) const;
        /*!
            ensures
                - returns a copy of the kernel function in use by this object
        !*/

        void set_kernel (
            const kernel_type& k
        );
        /*!
            ensures
                - #get_kernel() == k
        !*/

        template <typename T>
        void set_basis (
            const T& basis_samples
        );
        /*!
            requires
                - T must be a dlib::matrix type or something convertible to a matrix via mat()
                  (e.g. a std::vector)
                - is_vector(basis_samples) == true
                - basis_samples.size() > 0
                - get_kernel() must be capable of operating on the elements of basis_samples.  That is,
                  expressions such as get_kernel()(basis_samples(0), basis_samples(0)) should make sense.
            ensures
                - #basis_loaded() == true
                - training will be carried out in the span of the given basis_samples
        !*/

        bool basis_loaded (
        ) const;
        /*!
            ensures
                - returns true if this object has been loaded with user supplied basis vectors and false otherwise.
        !*/

        void clear_basis (
        );
        /*!
            ensures
                - #basis_loaded() == false
        !*/

        unsigned long get_max_basis_size (
        ) const;
        /*!
            ensures
                - returns the maximum number of basis vectors this object is allowed
                  to use.  This parameter only matters when the user has not supplied
                  a basis via set_basis().
        !*/

        void set_max_basis_size (
            unsigned long max_basis_size
        );
        /*!
            requires
                - max_basis_size > 0
            ensures
                - #get_max_basis_size() == max_basis_size
        !*/

        void set_lambda (
            scalar_type lambda
        );
        /*!
            requires
                - lambda >= 0
            ensures
                - #get_lambda() == lambda
        !*/

        const scalar_type get_lambda (
        ) const;
        /*!
            ensures
                - returns the regularization parameter.  It is the parameter that
                  determines the trade off between trying to fit the training data
                  exactly or allowing more errors but hopefully improving the
                  generalization ability of the resulting function.  Smaller values
                  encourage exact fitting while larger values of lambda may encourage
                  better generalization.

                  Note that a lambda of 0 has a special meaning.  It indicates to this
                  object that it should automatically determine an appropriate lambda
                  value.  This is done using leave-one-out cross-validation.
        !*/

        void use_regression_loss_for_loo_cv (
        );
        /*!
            ensures
                - #will_use_regression_loss_for_loo_cv() == true
        !*/

        void use_classification_loss_for_loo_cv (
        );
        /*!
            ensures
                - #will_use_regression_loss_for_loo_cv() == false
        !*/

        bool will_use_regression_loss_for_loo_cv (
        ) const;
        /*!
            ensures
                - returns true if the automatic lambda estimation will attempt to estimate a lambda
                  appropriate for a regression task.  Otherwise it will try and find one which
                  minimizes the number of classification errors.
        !*/

        template <typename EXP>
        void set_search_lambdas (
            const matrix_exp<EXP>& lambdas
        );
        /*!
            requires
                - is_vector(lambdas) == true
                - lambdas.size() > 0
                - min(lambdas) > 0
                - lambdas must contain floating point numbers
            ensures
                - #get_search_lambdas() == lambdas
        !*/

        const matrix<scalar_type,0,0,mem_manager_type>& get_search_lambdas (
        ) const;
        /*!
            ensures
                - returns a matrix M such that:
                    - is_vector(M) == true
                    - M == a list of all the lambda values which will be tried when performing
                      LOO cross-validation for determining the best lambda.
        !*/

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y
        ) const;
        /*!
            requires
                - x == a matrix or something convertible to a matrix via mat().
                  Also, x should contain sample_type objects.
                - y == a matrix or something convertible to a matrix via mat().
                  Also, y should contain scalar_type objects.
                - is_learning_problem(x,y) == true
                - if (get_lambda() == 0 && will_use_regression_loss_for_loo_cv() == false) then
                    - is_binary_classification_problem(x,y) == true
                      (i.e. if you want this algorithm to estimate a lambda appropriate for
                      classification functions then you had better give a valid classification
                      problem)
            ensures
                - performs kernel ridge regression given the training samples in x and target values in y.
                - returns a decision_function F with the following properties:
                    - F(new_x) == predicted y value

                - if (basis_loaded()) then
                    - training will be carried out in the span of the user supplied basis vectors
                - else
                    - this object will attempt to automatically select an appropriate basis

                - if (get_lambda() == 0) then
                    - This object will perform internal leave-one-out cross-validation to determine an
                      appropriate lambda automatically.  It will compute the LOO error for each lambda
                      in get_search_lambdas() and select the best one.
                    - if (will_use_regression_loss_for_loo_cv()) then
                        - the lambda selected will be the one that minimizes the mean squared error.
                    - else
                        - the lambda selected will be the one that minimizes the number classification
                          mistakes.  We say a point is classified correctly if the output of the
                          decision_function has the same sign as its label.
                    - #get_lambda() == 0
                      (i.e. we don't change the get_lambda() value.  If you want to know what the
                      automatically selected lambda value was then call the version of train()
                      defined below)
                - else
                    - The user supplied value of get_lambda() will be used to perform the kernel
                      ridge regression.
        !*/

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y,
            std::vector<scalar_type>& loo_values
        ) const;
        /*!
            requires
                - all the requirements for train(x,y) must be satisfied
            ensures
                - returns train(x,y)
                  (i.e. executes train(x,y) and returns its result)
                - #loo_values.size() == y.size()
                - for all valid i:
                    - #loo_values[i] == leave-one-out prediction for the value of y(i) based
                      on all the training samples other than (x(i),y(i)).
        !*/

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y,
            std::vector<scalar_type>& loo_values,
            scalar_type& lambda_used
        ) const;
        /*!
            requires
                - all the requirements for train(x,y) must be satisfied
            ensures
                - returns train(x,y)
                  (i.e. executes train(x,y) and returns its result)
                - #loo_values.size() == y.size()
                - for all valid i:
                    - #loo_values[i] == leave-one-out prediction for the value of y(i) based
                      on all the training samples other than (x(i),y(i)).
                - #lambda_used == the value of lambda used to generate the
                  decision_function.  Note that this lambda value is always
                  equal to get_lambda() if get_lambda() isn't 0.
        !*/

    };

}

#endif // DLIB_KRR_TRAInER_ABSTRACT_Hh_


dlib C++ Library - mlp_kernel_abstract.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_MLp_ABSTRACT_
#ifdef DLIB_MLp_ABSTRACT_

#include "../algs.h"
#include "../serialize.h"
#include "../matrix/matrix_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class mlp : noncopyable
    {
        /*!
            INITIAL VALUE
                The network is initially initialized with random weights

            WHAT THIS OBJECT REPRESENTS
                This object represents a multilayer layer perceptron network that is
                trained using the back propagation algorithm.  The training algorithm also
                incorporates the momentum method.  That is, each round of back propagation
                training also adds a fraction of the previous update.  This fraction
                is controlled by the momentum term set in the constructor.

                The activation function used at each node is the sigmoid function.  I.e.
                sigmoid(x) = 1/(1 + pow(e,-x)).  Thus the output of the network is
                always in the range [0,1]
        !*/

    public:

        mlp (
            long nodes_in_input_layer,
            long nodes_in_first_hidden_layer,
            long nodes_in_second_hidden_layer = 0,
            long nodes_in_output_layer = 1,
            double alpha = 0.1,
            double momentum = 0.8
        );
        /*!
            requires
                - nodes_in_input_layer > 0
                - nodes_in_first_hidden_layer > 0
                - nodes_in_second_hidden_layer >= 0
                - nodes_in_output_layer > 0
            ensures
                - #*this is properly initialized
                - #input_layer_nodes() == nodes_in_input_layer
                - #first_hidden_layer_nodes() == nodes_in_first_hidden_layer
                - #second_hidden_layer_nodes() == nodes_in_second_hidden_layer
                - #output_layer_nodes() == nodes_in_output_layer
                - #get_alpha() == alpha
                - #get_momentum() == momentum
            throws
                - std::bad_alloc
                    if this is thrown the mlp will be unusable but
                    will not leak memory
        !*/

        virtual ~mlp (
        );
        /*!
            ensures
                - all resources associated with #*this have been released
        !*/

        void reset (
        ) const;
        /*!
            ensures
                - reinitialize the network with random weights
        !*/

        long input_layer_nodes (
        ) const;
        /*!
            ensures
                - returns the number of nodes in the input layer
        !*/

        long first_hidden_layer_nodes (
        ) const;
        /*!
            ensures
                - returns the number of nodes in the first hidden layer.  This is
                  the hidden layer that is directly connected to the input layer.
        !*/

        long second_hidden_layer_nodes (
        ) const;
        /*!
            ensures
                - if (this network has a second hidden layer) then
                    - returns the number of nodes in the second hidden layer.  This is
                      the hidden layer that is directly connected to the output layer.
                - else
                    - returns 0
        !*/

        long output_layer_nodes (
        ) const;
        /*!
            ensures
                - returns the number of nodes in the output layer
        !*/

        double get_alpha (
        ) const;
        /*!
            ensures
                - returns the back propagation learning rate used by this object.
        !*/

        double get_momentum (
        ) const;
        /*!
            ensures
                - returns the momentum term used by this object during back propagation
                  training.  The momentum is is the fraction of a previous update to
                  carry forward to the next call to train()
        !*/

        template <typename EXP>
        const matrix<double> operator() (
            const matrix_exp<EXP>& in
        ) const;
        /*!
            requires
                - in.nr() == input_layer_nodes()
                - in.nc() == 1
                - EXP::type == double
            ensures
                - returns the output of the network when it is given the
                  input in.  The output's elements are always in the range
                  of 0.0 to 1.0
        !*/

        template <typename EXP1, typename EXP2>
        void train (
            const matrix_exp<EXP1>& example_in,
            const matrix_exp<EXP2>& example_out
        );
        /*!
            requires
                - example_in.nr() == input_layer_nodes()
                - example_in.nc() == 1
                - example_out.nr() == output_layer_nodes()
                - example_out.nc() == 1
                - max(example_out) <= 1.0 && min(example_out) >= 0.0
                - EXP1::type == double
                - EXP2::type == double
            ensures
                - trains the network that the correct output when given example_in
                  should be example_out.
        !*/

        template <typename EXP>
        void train (
            const matrix_exp<EXP>& example_in,
            double example_out
        );
        /*!
            requires
                - example_in.nr() == input_layer_nodes()
                - example_in.nc() == 1
                - output_layer_nodes() == 1
                - example_out <= 1.0 && example_out >= 0.0
                - EXP::type == double
            ensures
                - trains the network that the correct output when given example_in
                  should be example_out.
        !*/

        double get_average_change (
        ) const;
        /*!
            ensures
                - returns the average change in the node weights in the
                  neural network during the last call to train()
        !*/

        void swap (
            mlp& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/

    };

    inline void swap (
        mlp& a,
        mlp& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

    void serialize (
        const mlp& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

    void deserialize (
        mlp& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MLp_ABSTRACT_


dlib C++ Library - rbf_network_abstract.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_RBf_NETWORK_ABSTRACT_
#ifdef DLIB_RBf_NETWORK_ABSTRACT_

#include "../algs.h"
#include "function_abstract.h"
#include "kernel_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename K
        >
    class rbf_network_trainer
    {
        /*!
            REQUIREMENTS ON K
                is a kernel function object as defined in dlib/svm/kernel_abstract.h
                (since this is supposed to be a RBF network it is probably reasonable
                to use some sort of radial basis kernel)

            INITIAL VALUE
                - get_num_centers() == 10

            WHAT THIS OBJECT REPRESENTS
                This object implements a trainer for a radial basis function network.

                The implementation of this algorithm follows the normal RBF training
                process.  For more details see the code or the Wikipedia article
                about RBF networks.
        !*/

    public:
        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 decision_function<kernel_type> trained_function_type;

        rbf_network_trainer (
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        void set_kernel (
            const kernel_type& k
        );
        /*!
            ensures
                - #get_kernel() == k
        !*/

        const kernel_type& get_kernel (
        ) const;
        /*!
            ensures
                - returns a copy of the kernel function in use by this object
        !*/

        void set_num_centers (
            const unsigned long num_centers
        );
        /*!
            ensures
                - #get_num_centers() == num_centers
        !*/

        const unsigned long get_num_centers (
        ) const;
        /*!
            ensures
                - returns the maximum number of centers (a.k.a. basis_vectors in the
                  trained decision_function) you will get when you train this object on data.
        !*/

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y
        ) const
        /*!
            requires
                - x == a matrix or something convertible to a matrix via mat().
                  Also, x should contain sample_type objects.
                - y == a matrix or something convertible to a matrix via mat().
                  Also, y should contain scalar_type objects.
                - is_learning_problem(x,y) == true
            ensures
                - trains a RBF network given the training samples in x and
                  labels in y and returns the resulting decision_function
            throws
                - std::bad_alloc
        !*/

        void swap (
            rbf_network_trainer& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <typename K>
    void swap (
        rbf_network_trainer<K>& a,
        rbf_network_trainer<K>& b
    ) { a.swap(b); }
    /*!
        provides a global swap
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_RBf_NETWORK_ABSTRACT_


dlib C++ Library - rls_abstract.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_RLs_ABSTRACT_Hh_
#ifdef DLIB_RLs_ABSTRACT_Hh_

#include "../matrix/matrix_abstract.h"
#include "function_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class rls
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is an implementation of the linear version of the recursive least
                squares algorithm.  It accepts training points incrementally and, at
                each step, maintains the solution to the following optimization problem:
                    find w minimizing: 0.5*dot(w,w) + C*sum_i(y_i - trans(x_i)*w)^2
                Where (x_i,y_i) are training pairs.  x_i is some vector and y_i is a target
                scalar value.

                This object can also be configured to use exponential forgetting.  This is
                where each training example is weighted by pow(forget_factor, i), where i
                indicates the sample's age.  So older samples are weighted less in the
                least squares solution and therefore become forgotten after some time.
                Therefore, with forgetting, this object solves the following optimization
                problem at each step:
                    find w minimizing: 0.5*dot(w,w) + C*sum_i pow(forget_factor, i)*(y_i - trans(x_i)*w)^2
                Where i starts at 0 and i==0 corresponds to the most recent training point.
        !*/

    public:

        explicit rls(
            double forget_factor,
            double C = 1000
        );
        /*!
            requires
                - 0 < forget_factor <= 1
                - 0 < C
            ensures
                - #get_w().size() == 0
                - #get_c() == C
                - #get_forget_factor() == forget_factor
        !*/

        rls(
        );
        /*!
            ensures
                - #get_w().size() == 0
                - #get_c() == 1000
                - #get_forget_factor() == 1
        !*/

        double get_c(
        ) const;
        /*!
            ensures
                - returns the regularization parameter.  It is the parameter
                  that determines the trade-off between trying to fit the training
                  data or allowing more errors but hopefully improving the generalization
                  of the resulting regression.  Larger values encourage exact fitting while
                  smaller values of C may encourage better generalization.
        !*/

        double get_forget_factor(
        ) const;
        /*!
            ensures
                - returns the exponential forgetting factor.  A value of 1 disables forgetting
                  and results in normal least squares regression.  On the other hand, a smaller
                  value causes the regression to forget about old training examples and prefer
                  instead to fit more recent examples.  The closer the forget factor is to
                  zero the faster old examples are forgotten.
        !*/

        template <typename EXP>
        void train (
            const matrix_exp<EXP>& x,
            double y
        )
        /*!
            requires
                - is_col_vector(x) == true
                - if (get_w().size() != 0) then
                    - x.size() == get_w().size()
                      (i.e. all training examples must have the same
                      dimensionality)
            ensures
                - #get_w().size() == x.size()
                - updates #get_w() such that it contains the solution to the least
                  squares problem of regressing the given x onto the given y as well
                  as all the previous training examples supplied to train().
        !*/

        const matrix<double,0,1>& get_w(
        ) const;
        /*!
            ensures
                - returns the regression weights.  These are the values learned by the
                  least squares procedure.  If train() has not been called then this
                  function returns an empty vector.
        !*/

        template <typename EXP>
        double operator() (
            const matrix_exp<EXP>& x
        ) const;
        /*!
            requires
                - is_col_vector(x) == true
                - get_w().size() == x.size()
            ensures
                - returns dot(x, get_w())
        !*/

        decision_function<linear_kernel<matrix<double,0,1> > > get_decision_function (
        ) const;
        /*!
            requires
                - get_w().size() != 0
            ensures
                - returns a decision function DF such that:
                    - DF(x) == dot(x, get_w())
        !*/

    };

// ----------------------------------------------------------------------------------------

    void serialize (
        const rls& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

    void deserialize (
        rls& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_RLs_ABSTRACT_Hh_


dlib C++ Library - rr_trainer_abstract.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_RR_TRAInER_ABSTRACT_Hh_
#ifdef DLIB_RR_TRAInER_ABSTRACT_Hh_

#include "../algs.h"
#include "function_abstract.h"

namespace dlib
{
    template <
        typename K
        >
    class rr_trainer
    {
        /*!
            REQUIREMENTS ON K
                is the dlib::linear_kernel instantiated with some kind of column vector.

            INITIAL VALUE
                - get_lambda() == 0
                - will_use_regression_loss_for_loo_cv() == true
                - get_search_lambdas() == logspace(-9, 2, 50)
                - this object will not be verbose unless be_verbose() is called

            WHAT THIS OBJECT REPRESENTS
                This object represents a tool for performing linear ridge regression
                (This basic algorithm is also known my many other names, e.g. regularized
                least squares or least squares SVM).

                The exact definition of what this algorithm does is this:
                    Find w and b that minimizes the following (x_i are input samples and y_i are target values):
                        lambda*dot(w,w) + sum_over_i( (f(x_i) - y_i)^2 )
                        where f(x) == dot(x,w) - b

                    So this algorithm is just regular old least squares regression but
                    with the addition of a regularization term which encourages small w.

                It is capable of estimating the lambda parameter using leave-one-out cross-validation.

                The leave-one-out cross-validation implementation is based on the techniques
                discussed in this paper:
                    Notes on Regularized Least Squares by Ryan M. Rifkin and Ross A. Lippert.
        !*/

    public:
        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 decision_function<kernel_type> trained_function_type;

        rr_trainer (
        );
        /*!
            ensures
                - This object is properly initialized and ready to be used.
        !*/

        void be_verbose (
        );
        /*!
            ensures
                - This object will print status messages to standard out.
        !*/

        void be_quiet (
        );
        /*!
            ensures
                - this object will not print anything to standard out
        !*/

        const kernel_type get_kernel (
        ) const;
        /*!
            ensures
                - returns a copy of the kernel function in use by this object.  Since
                  the linear kernels don't have any parameters this function just
                  returns kernel_type()
        !*/

        void set_lambda (
            scalar_type lambda
        );
        /*!
            requires
                - lambda >= 0
            ensures
                - #get_lambda() == lambda
        !*/

        const scalar_type get_lambda (
        ) const;
        /*!
            ensures
                - returns the regularization parameter.  It is the parameter that
                  determines the trade off between trying to fit the training data
                  exactly or allowing more errors but hopefully improving the
                  generalization ability of the resulting function.  Smaller values
                  encourage exact fitting while larger values of lambda may encourage
                  better generalization.

                  Note that a lambda of 0 has a special meaning.  It indicates to this
                  object that it should automatically determine an appropriate lambda
                  value.  This is done using leave-one-out cross-validation.
        !*/

        void use_regression_loss_for_loo_cv (
        );
        /*!
            ensures
                - #will_use_regression_loss_for_loo_cv() == true
        !*/

        void use_classification_loss_for_loo_cv (
        );
        /*!
            ensures
                - #will_use_regression_loss_for_loo_cv() == false
        !*/

        bool will_use_regression_loss_for_loo_cv (
        ) const;
        /*!
            ensures
                - returns true if the automatic lambda estimation will attempt to estimate a lambda
                  appropriate for a regression task.  Otherwise it will try and find one which
                  minimizes the number of classification errors.
        !*/

        template <typename EXP>
        void set_search_lambdas (
            const matrix_exp<EXP>& lambdas
        );
        /*!
            requires
                - is_vector(lambdas) == true
                - lambdas.size() > 0
                - min(lambdas) > 0
                - lambdas must contain floating point numbers
            ensures
                - #get_search_lambdas() == lambdas
        !*/

        const matrix<scalar_type,0,0,mem_manager_type>& get_search_lambdas (
        ) const;
        /*!
            ensures
                - returns a matrix M such that:
                    - is_vector(M) == true
                    - M == a list of all the lambda values which will be tried when performing
                      LOO cross-validation for determining the best lambda.
        !*/

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y
        ) const;
        /*!
            requires
                - x == a matrix or something convertible to a matrix via mat().
                  Also, x should contain sample_type objects.
                - y == a matrix or something convertible to a matrix via mat().
                  Also, y should contain scalar_type objects.
                - is_learning_problem(x,y) == true
                - if (get_lambda() == 0 && will_use_regression_loss_for_loo_cv() == false) then
                    - is_binary_classification_problem(x,y) == true
                      (i.e. if you want this algorithm to estimate a lambda appropriate for
                      classification functions then you had better give a valid classification
                      problem)
            ensures
                - performs linear ridge regression given the training samples in x and target values in y.
                - returns a decision_function F with the following properties:
                    - F(new_x) == predicted y value
                    - F.alpha.size() == 1
                    - F.basis_vectors.size() == 1
                    - F.alpha(0) == 1

                - if (get_lambda() == 0) then
                    - This object will perform internal leave-one-out cross-validation to determine an
                      appropriate lambda automatically.  It will compute the LOO error for each lambda
                      in get_search_lambdas() and select the best one.
                    - if (will_use_regression_loss_for_loo_cv()) then
                        - the lambda selected will be the one that minimizes the mean squared error.
                    - else
                        - the lambda selected will be the one that minimizes the number classification
                          mistakes.  We say a point is classified correctly if the output of the
                          decision_function has the same sign as its label.
                    - #get_lambda() == 0
                      (i.e. we don't change the get_lambda() value.  If you want to know what the
                      automatically selected lambda value was then call the version of train()
                      defined below)
                - else
                    - The user supplied value of get_lambda() will be used to perform the ridge regression.
        !*/

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y,
            std::vector<scalar_type>& loo_values
        ) const;
        /*!
            requires
                - all the requirements for train(x,y) must be satisfied
            ensures
                - returns train(x,y)
                  (i.e. executes train(x,y) and returns its result)
                - #loo_values.size() == y.size()
                - for all valid i:
                    - #loo_values[i] == leave-one-out prediction for the value of y(i) based
                      on all the training samples other than (x(i),y(i)).
        !*/

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y,
            std::vector<scalar_type>& loo_values,
            scalar_type& lambda_used
        ) const;
        /*!
            requires
                - all the requirements for train(x,y) must be satisfied
            ensures
                - returns train(x,y)
                  (i.e. executes train(x,y) and returns its result)
                - #loo_values.size() == y.size()
                - for all valid i:
                    - #loo_values[i] == leave-one-out prediction for the value of y(i) based
                      on all the training samples other than (x(i),y(i)).
                - #lambda_used == the value of lambda used to generate the
                  decision_function.  Note that this lambda value is always
                  equal to get_lambda() if get_lambda() isn't 0.
        !*/

    };

}

#endif // DLIB_RR_TRAInER_ABSTRACT_Hh_


dlib C++ Library - svr_linear_trainer_abstract.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SVR_LINEAR_TrAINER_ABSTRACT_Hh_
#ifdef DLIB_SVR_LINEAR_TrAINER_ABSTRACT_Hh_

#include "sparse_vector_abstract.h"
#include "function_abstract.h"
#include "kernel_abstract.h"
#include "../algs.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename K
        >
    class svr_linear_trainer
    {
        /*!
            REQUIREMENTS ON K
                Is either linear_kernel or sparse_linear_kernel.

            WHAT THIS OBJECT REPRESENTS
                This object implements a trainer for performing epsilon-insensitive support
                vector regression.  It uses the oca optimizer so it is very efficient at
                solving this problem when linear kernels are used, making it suitable for
                use with large datasets.

                For an introduction to support vector regression see the following paper:
                    A Tutorial on Support Vector Regression by Alex J. Smola and Bernhard Scholkopf.
                Note that this object solves the version of support vector regression
                defined by equation (3) in the paper, except that we incorporate the bias
                term into the w vector by appending a 1 to the end of each sample.
        !*/

    public:
        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 decision_function<kernel_type> trained_function_type;

        svr_linear_trainer (
        );
        /*!
            ensures
                - This object is properly initialized and ready to be used to train a
                  ranking support vector machine.
                - #get_oca() == oca() (i.e. an instance of oca with default parameters)
                - #get_c() == 1
                - #get_epsilon() == 0.01
                - #get_epsilon_insensitivity() = 0.1
                - This object will not be verbose unless be_verbose() is called
                - #get_max_iterations() == 10000
                - #learns_nonnegative_weights() == false
                - #forces_last_weight_to_1() == false
        !*/

        explicit svr_linear_trainer (
            const scalar_type& C
        );
        /*!
            requires
                - C > 0
            ensures
                - This object is properly initialized and ready to be used to train a
                  ranking support vector machine.
                - #get_oca() == oca() (i.e. an instance of oca with default parameters)
                - #get_c() == C
                - #get_epsilon() == 0.01
                - #get_epsilon_insensitivity() = 0.1
                - This object will not be verbose unless be_verbose() is called
                - #get_max_iterations() == 10000
                - #learns_nonnegative_weights() == false
                - #forces_last_weight_to_1() == false
        !*/

        void set_epsilon (
            scalar_type eps
        );
        /*!
            requires
                - eps > 0
            ensures
                - #get_epsilon() == eps
        !*/

        const scalar_type get_epsilon (
        ) const;
        /*!
            ensures
                - returns the error epsilon that determines when training should stop.
                  Smaller values may result in a more accurate solution but take longer to
                  train.  You can think of this epsilon value as saying "solve the
                  optimization problem until the average regression error is within epsilon
                  of its optimal value".  See get_epsilon_insensitivity() below for a
                  definition of "regression error".
        !*/

        void set_epsilon_insensitivity (
            scalar_type eps
        );
        /*!
            requires
                - eps > 0
            ensures
                - #get_epsilon_insensitivity() == eps
        !*/

        const scalar_type get_epsilon_insensitivity (
        ) const;
        /*!
            ensures
                - This object tries to find a function which minimizes the regression error
                  on a training set.  This error is measured in the following way:
                    - if (abs(predicted_value - true_labeled_value) < eps) then
                        - The error is 0.  That is, any function which gets within eps of
                          the correct output is good enough.
                    - else
                        - The error grows linearly once it gets bigger than eps.

                  So epsilon-insensitive regression means we do regression but stop trying
                  to fit a data point once it is "close enough".  This function returns
                  that eps value which controls what we mean by "close enough".
        !*/

        unsigned long get_max_iterations (
        ) const;
        /*!
            ensures
                - returns the maximum number of iterations the SVM optimizer is allowed to
                  run before it is required to stop and return a result.
        !*/

        void set_max_iterations (
            unsigned long max_iter
        );
        /*!
            ensures
                - #get_max_iterations() == max_iter
        !*/

        void be_verbose (
        );
        /*!
            ensures
                - This object will print status messages to standard out so that a user can
                  observe the progress of the algorithm.
        !*/

        void be_quiet (
        );
        /*!
            ensures
                - this object will not print anything to standard out
        !*/

        bool forces_last_weight_to_1 (
        ) const;
        /*!
            ensures
                - returns true if this trainer has the constraint that the last weight in
                  the learned parameter vector must be 1.  This is the weight corresponding
                  to the feature in the training vectors with the highest dimension.
                - Forcing the last weight to 1 also disables the bias and therefore the b
                  field of the learned decision_function will be 0 when forces_last_weight_to_1() == true.
        !*/

        void force_last_weight_to_1 (
            bool should_last_weight_be_1
        );
        /*!
            ensures
                - #forces_last_weight_to_1() == should_last_weight_be_1
        !*/

        void set_oca (
            const oca& item
        );
        /*!
            ensures
                - #get_oca() == item
        !*/

        const oca get_oca (
        ) const;
        /*!
            ensures
                - returns a copy of the optimizer used to solve the SVM problem.
        !*/

        const kernel_type get_kernel (
        ) const;
        /*!
            ensures
                - returns a copy of the kernel function in use by this object.  Since the
                  linear kernels don't have any parameters this function just returns
                  kernel_type()
        !*/

        bool learns_nonnegative_weights (
        ) const;
        /*!
            ensures
                - The output of training is a weight vector and a bias value.  These two
                  things define the resulting decision function.  That is, the decision
                  function simply takes the dot product between the learned weight vector
                  and a test sample, then subtracts the bias value.  Therefore, if
                  learns_nonnegative_weights() == true then the resulting learned weight
                  vector will always have non-negative entries.  The bias value may still
                  be negative though.
        !*/

        void set_learns_nonnegative_weights (
            bool value
        );
        /*!
            ensures
                - #learns_nonnegative_weights() == value
        !*/

        void set_c (
            scalar_type C
        );
        /*!
            requires
                - C > 0
            ensures
                - #get_c() == C
        !*/

        const scalar_type get_c (
        ) const;
        /*!
            ensures
                - returns the SVM regularization parameter.  It is the parameter that
                  determines the trade off between trying to fit the training data exactly
                  or allowing more errors but hopefully improving the generalization of the
                  resulting classifier.  Larger values encourage exact fitting while
                  smaller values of C may encourage better generalization.
        !*/

        const decision_function<kernel_type> train (
            const std::vector<sample_type>& samples,
            const std::vector<scalar_type>& targets
        ) const;
        /*!
            requires
                - is_learning_problem(samples,targets) == true
            ensures
                - performs support vector regression given the training samples and targets.
                - returns a decision_function F with the following properties:
                    - F(new_sample) == predicted target value for new_sample
                    - F.alpha.size() == 1
                    - F.basis_vectors.size() == 1
                    - F.alpha(0) == 1
        !*/

    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SVR_LINEAR_TrAINER_ABSTRACT_Hh_


dlib C++ Library - svr_trainer_abstract.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SVm_EPSILON_REGRESSION_TRAINER_ABSTRACT_
#ifdef DLIB_SVm_EPSILON_REGRESSION_TRAINER_ABSTRACT_

#include <cmath>
#include <limits>
#include "../matrix/matrix_abstract.h"
#include "../algs.h"
#include "function_abstract.h"
#include "kernel_abstract.h"
#include "../optimization/optimization_solve_qp3_using_smo_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename K
        >
    class svr_trainer
    {
        /*!
            REQUIREMENTS ON K
                is a kernel function object as defined in dlib/svm/kernel_abstract.h

            WHAT THIS OBJECT REPRESENTS
                This object implements a trainer for performing epsilon-insensitive support
                vector regression.  It is implemented using the SMO algorithm.

                The implementation of the eps-SVR training algorithm used by this object is based
                on the following paper:
                    - Chih-Chung Chang and Chih-Jen Lin, LIBSVM : a library for support vector
                      machines, 2001. Software available at http://www.csie.ntu.edu.tw/~cjlin/libsvm
        !*/

    public:
        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 decision_function<kernel_type> trained_function_type;

        svr_trainer (
        );
        /*!
            ensures
                - This object is properly initialized and ready to be used
                  to train a support vector machine.
                - #get_c() == 1
                - #get_epsilon_insensitivity() == 0.1
                - #get_cache_size() == 200
                - #get_epsilon() == 0.001
        !*/

        void set_cache_size (
            long cache_size
        );
        /*!
            requires
                - cache_size > 0
            ensures
                - #get_cache_size() == cache_size
        !*/

        const long get_cache_size (
        ) const;
        /*!
            ensures
                - returns the number of megabytes of cache this object will use
                  when it performs training via the this->train() function.
                  (bigger values of this may make training go faster but won't affect
                  the result.  However, too big a value will cause you to run out of
                  memory, obviously.)
        !*/

        void set_epsilon (
            scalar_type eps
        );
        /*!
            requires
                - eps > 0
            ensures
                - #get_epsilon() == eps
        !*/

        const scalar_type get_epsilon (
        ) const;
        /*!
            ensures
                - returns the error epsilon that determines when training should stop.
                  Generally a good value for this is 0.001.  Smaller values may result
                  in a more accurate solution but take longer to execute.
        !*/

        void set_epsilon_insensitivity (
            scalar_type eps
        );
        /*!
            requires
                - eps > 0
            ensures
                - #get_epsilon_insensitivity() == eps
        !*/

        const scalar_type get_epsilon_insensitivity (
        ) const;
        /*!
            ensures
                - This object tries to find a function which minimizes the
                  regression error on a training set.  This error is measured
                  in the following way:
                    - if (abs(predicted_value - true_labeled_value) < eps) then
                        - The error is 0.  That is, any function which gets within
                          eps of the correct output is good enough.
                    - else
                        - The error grows linearly once it gets bigger than eps

                  So epsilon-insensitive regression means we do regression but
                  stop trying to fit a data point once it is "close enough".
                  This function returns that eps value which controls what we
                  mean by "close enough".
        !*/

        void set_kernel (
            const kernel_type& k
        );
        /*!
            ensures
                - #get_kernel() == k
        !*/

        const kernel_type& get_kernel (
        ) const;
        /*!
            ensures
                - returns a copy of the kernel function in use by this object
        !*/

        void set_c (
            scalar_type C
        );
        /*!
            requires
                - C > 0
            ensures
                - #get_c() == C
        !*/

        const scalar_type get_c (
        ) const;
        /*!
            ensures
                - returns the SVR regularization parameter.  It is the parameter that
                  determines the trade-off between trying to reduce the training error
                  or allowing more errors but hopefully improving the generalization
                  of the resulting decision_function.  Larger values encourage exact
                  fitting while smaller values of C may encourage better generalization.
        !*/

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y
        ) const;
        /*!
            requires
                - is_learning_problem(x,y) == true
                - x == a matrix or something convertible to a matrix via mat().
                  Also, x should contain sample_type objects.
                - y == a matrix or something convertible to a matrix via mat().
                  Also, y should contain scalar_type objects.
            ensures
                - performs support vector regression given the training samples in x and
                  target values in y.
                - returns a decision_function F with the following properties:
                    - F(new_x) == predicted y value
        !*/

        void swap (
            svr_trainer& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/
    };

    template <typename K>
    void swap (
        svr_trainer<K>& a,
        svr_trainer<K>& b
    ) { a.swap(b); }
    /*!
        provides a global swap
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SVm_EPSILON_REGRESSION_TRAINER_ABSTRACT_


dlib C++ Library - structural_svm_problem_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_STRUCTURAL_SVM_PRObLEM_ABSTRACT_Hh_
#ifdef DLIB_STRUCTURAL_SVM_PRObLEM_ABSTRACT_Hh_

#include "../optimization/optimization_oca_abstract.h"
#include "sparse_vector_abstract.h"
#include "../matrix.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_type_,
        typename feature_vector_type_ = matrix_type_
        >
    class structural_svm_problem : public oca_problem<matrix_type_>
    {
    public:
        /*!
            REQUIREMENTS ON matrix_type_
                - matrix_type_ == a dlib::matrix capable of storing column vectors

            REQUIREMENTS ON feature_vector_type_
                - feature_vector_type_ == a dlib::matrix capable of storing column vectors
                  or an unsorted sparse vector type as defined in dlib/svm/sparse_vector_abstract.h.

            INITIAL VALUE
                - get_epsilon() == 0.001
                - get_max_iterations() == 10000
                - get_max_cache_size() == 5
                - get_c() == 1
                - get_cache_based_epsilon() == std::numeric_limits<scalar_type>::infinity()
                  (I.e. the cache based epsilon feature is disabled)
                - num_nuclear_norm_regularizers() == 0
                - This object will not be verbose

            WHAT THIS OBJECT REPRESENTS
                This object is a tool for solving the optimization problem associated with
                a structural support vector machine.  A structural SVM is a supervised
                machine learning method for learning to predict complex outputs.  This is
                contrasted with a binary classifier which makes only simple yes/no
                predictions.  A structural SVM, on the other hand, can learn to predict
                complex outputs such as entire parse trees or DNA sequence alignments.  To
                do this, it learns a function F(x,y) which measures how well a particular
                data sample x matches a label y.  When used for prediction, the best label
                for a new x is given by the y which maximizes F(x,y).

                To use this object you inherit from it, provide implementations of its four
                pure virtual functions, and then pass your object to the oca optimizer.
                Also, you should only pass an instance of this object to the oca optimizer
                once.  That is, the act of using a structural_svm_problem instance with the
                oca solver "uses" the structural_svm_problem instance.  If you want to
                solve the same problem multiple times then you must use a fresh instance of
                your structural_svm_problem.

                To define the optimization problem precisely, we first introduce some notation:
                    - let PSI(x,y)    == the joint feature vector for input x and a label y.
                    - let F(x,y|w)    == dot(w,PSI(x,y)).
                    - let LOSS(idx,y) == the loss incurred for predicting that the idx-th training
                      sample has a label of y.  Note that LOSS() should always be >= 0 and should
                      become exactly 0 when y is the correct label for the idx-th sample.
                    - let x_i == the i-th training sample.
                    - let y_i == the correct label for the i-th training sample.
                    - The number of data samples is N.

                Then the optimization problem solved using this object is the following:
                    Minimize: h(w) == 0.5*dot(w,w) + C*R(w)

                    Where R(w) == sum from i=1 to N: 1/N * sample_risk(i,w)
                    and sample_risk(i,w) == max over all Y: LOSS(i,Y) + F(x_i,Y|w) - F(x_i,y_i|w)
                    and C > 0

                For an introduction to structured support vector machines you should consult
                the following paper:
                    Predicting Structured Objects with Support Vector Machines by
                    Thorsten Joachims, Thomas Hofmann, Yisong Yue, and Chun-nam Yu

                For a more detailed discussion of the particular algorithm implemented by this
                object see the following paper:
                    T. Joachims, T. Finley, Chun-Nam Yu, Cutting-Plane Training of Structural SVMs,
                    Machine Learning, 77(1):27-59, 2009.

                    Note that this object is essentially a tool for solving the 1-Slack structural
                    SVM with margin-rescaling.  Specifically, see Algorithm 3 in the above referenced
                    paper.
        !*/

        typedef matrix_type_ matrix_type;
        typedef typename matrix_type::type scalar_type;
        typedef feature_vector_type_ feature_vector_type;

        structural_svm_problem (
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        void set_epsilon (
            scalar_type eps
        );
        /*!
            requires
                - eps > 0
            ensures
                - #get_epsilon() == eps
        !*/

        const scalar_type get_epsilon (
        ) const;
        /*!
            ensures
                - returns the error epsilon that determines when training should stop.
                  Smaller values may result in a more accurate solution but take longer
                  to execute.  Specifically, the algorithm stops when the average sample
                  risk (i.e. R(w) as defined above) is within epsilon of its optimal value.

                  Also note that sample risk is an upper bound on a sample's loss.  So
                  you can think of this epsilon value as saying "solve the optimization
                  problem until the average loss per sample is within epsilon of it's
                  optimal value".
        !*/

        scalar_type get_cache_based_epsilon (
        ) const;
        /*!
            ensures
                - if (get_max_cache_size() != 0) then
                    - The solver will not stop when the average sample risk is within
                      get_epsilon() of its optimal value.  Instead, it will keep running
                      but will run the optimizer completely on the cache until the average
                      sample risk is within #get_cache_based_epsilon() of its optimal
                      value.  This means that it will perform this additional refinement in
                      the solution accuracy without making any additional calls to the
                      separation_oracle().  This is useful when using a nuclear norm
                      regularization term because it allows you to quickly solve the
                      optimization problem to a high precision, which in the case of a
                      nuclear norm regularized problem means that many of the learned
                      matrices will be low rank or very close to low rank due to the
                      nuclear norm regularizer.  This may not happen without solving the
                      problem to a high accuracy or their ranks may be difficult to
                      determine, so the extra accuracy given by the cache based refinement
                      is very useful.  Finally, note that we include the nuclear norm term
                      as part of the "risk" for the purposes of determining when to stop.
                - else
                    - The value of #get_cache_based_epsilon() has no effect.
        !*/

        void set_cache_based_epsilon (
            scalar_type eps
        );
        /*!
            requires
                - eps > 0
            ensures
                - #get_cache_based_epsilon() == eps
        !*/

        void set_max_iterations (
            unsigned long max_iter
        );
        /*!
            ensures
                - #get_max_iterations() == max_iter
        !*/

        unsigned long get_max_iterations (
        );
        /*!
            ensures
                - returns the maximum number of iterations the SVM optimizer is allowed to
                  run before it is required to stop and return a result.
        !*/

        void set_max_cache_size (
            unsigned long max_size
        );
        /*!
            ensures
                - #get_max_cache_size() == max_size
        !*/

        unsigned long get_max_cache_size (
        ) const;
        /*!
            ensures
                - Returns the number of joint feature vectors per training sample kept in
                  the separation oracle cache.  This cache is used to avoid unnecessary
                  calls to the user supplied separation_oracle() function.  Note that a
                  value of 0 means that caching is not used at all.  This is appropriate
                  if the separation oracle is cheap to evaluate.
        !*/

        void add_nuclear_norm_regularizer (
            long first_dimension,
            long rows,
            long cols,
            double regularization_strength
        );
        /*!
            requires
                - 0 <= first_dimension < get_num_dimensions()
                - 0 <= rows
                - 0 <= cols
                - first_dimension+rows*cols <= get_num_dimensions()
                - 0 < regularization_strength
            ensures
                - Adds a nuclear norm regularization term to the optimization problem
                  solved by this object.  That is, instead of solving:
                    Minimize: h(w) == 0.5*dot(w,w) + C*R(w)
                  this object will solve:
                    Minimize: h(w) == 0.5*dot(w,w) + C*R(w) + regularization_strength*nuclear_norm_of(part of w)
                  where "part of w" is the part of w indicated by the arguments to this
                  function. In particular, the part of w included in the nuclear norm is
                  exactly the matrix reshape(rowm(w, range(first_dimension, first_dimension+rows*cols-1)), rows, cols).
                  Therefore, if you think of the w vector as being the concatenation of a
                  bunch of matrices then you can use multiple calls to add_nuclear_norm_regularizer()
                  to add nuclear norm regularization terms to any of the matrices packed into w.
                - #num_nuclear_norm_regularizers() == num_nuclear_norm_regularizers() + 1
        !*/

        unsigned long num_nuclear_norm_regularizers (
        ) const;
        /*!
            ensures
                - returns the number of nuclear norm regularizers that are currently a part
                  of this optimization problem.  That is, returns the number of times
                  add_nuclear_norm_regularizer() has been called since the last call to
                  clear_nuclear_norm_regularizers() or object construction, whichever is
                  most recent.
        !*/

        void clear_nuclear_norm_regularizers (
        );
        /*!
            ensures
                - #num_nuclear_norm_regularizers() == 0
        !*/

        void be_verbose (
        );
        /*!
            ensures
                - This object will print status messages to standard out so that a
                  user can observe the progress of the algorithm.
        !*/

        void be_quiet(
        );
        /*!
            ensures
                - this object will not print anything to standard out
        !*/

        scalar_type get_c (
        ) const;
        /*!
            ensures
                - returns the SVM regularization parameter.  It is the parameter that
                  determines the trade off between trying to fit the training data
                  exactly or allowing more errors but hopefully improving the
                  generalization of the resulting classifier.  Larger values encourage
                  exact fitting while smaller values of C may encourage better
                  generalization.
        !*/

        void set_c (
            scalar_type C
        );
        /*!
            requires
                - C > 0
            ensures
                - #get_c() == C
        !*/

    // --------------------------------
    //     User supplied routines
    // --------------------------------

        virtual long get_num_dimensions (
        ) const = 0;
        /*!
            ensures
                - returns the dimensionality of a joint feature vector
        !*/

        virtual long get_num_samples (
        ) const = 0;
        /*!
            ensures
                - returns the number of training samples in this problem.
        !*/

        virtual void get_truth_joint_feature_vector (
            long idx,
            feature_vector_type& psi
        ) const = 0;
        /*!
            requires
                - 0 <= idx < get_num_samples()
            ensures
                - #psi == PSI(x_idx, y_idx)
                  (i.e. the joint feature vector for the idx-th training sample its true label.)
        !*/

        virtual void separation_oracle (
            const long idx,
            const matrix_type& current_solution,
            scalar_type& loss,
            feature_vector_type& psi
        ) const = 0;
        /*!
            requires
                - 0 <= idx < get_num_samples()
                - current_solution.size() == get_num_dimensions()
            ensures
                - runs the separation oracle on the idx-th sample.  We define this as follows:
                    - let X           == the idx-th training sample.
                    - let PSI(X,y)    == the joint feature vector for input X and an arbitrary label y.
                    - let F(X,y)      == dot(current_solution,PSI(X,y)).
                    - let LOSS(idx,y) == the loss incurred for predicting that the idx-th sample
                      has a label of y.  Note that LOSS() should always be >= 0 and should
                      become exactly 0 when y is the correct label for the idx-th sample.

                        Then the separation oracle finds a Y such that:
                            Y = argmax over all y: LOSS(idx,y) + F(X,y)
                            (i.e. It finds the label which maximizes the above expression.)

                        Finally, we can define the outputs of this function as:
                        - #loss == LOSS(idx,Y)
                        - #psi == PSI(X,Y)
        !*/
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_STRUCTURAL_SVM_PRObLEM_ABSTRACT_Hh_


dlib C++ Library - structural_svm_problem_threaded_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_STRUCTURAL_SVM_PRObLEM_THREADED_ABSTRACT_Hh_
#ifdef DLIB_STRUCTURAL_SVM_PRObLEM_THREADED_ABSTRACT_Hh_

#include "structural_svm_problem_abstract.h"
#include "../matrix.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_type_,
        typename feature_vector_type_ = matrix_type_
        >
    class structural_svm_problem_threaded : public structural_svm_problem<matrix_type_,feature_vector_type_>
    {
    public:
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is identical to the structural_svm_problem object defined in
                dlib/svm/structural_svm_problem_abstract.h except that its constructor
                takes a number which defines how many threads will be used to make concurrent
                calls to the separation_oracle() routine.

                So this object lets you take advantage of a multi-core system.  You should
                set the num_threads parameter equal to the number of available cores.  Note
                that the separation_oracle() function which you provide must be thread safe
                if you are to use this version of the structural_svm_problem.  In
                particular, it must be safe to call separation_oracle() concurrently from
                different threads.  However, it is guaranteed that different threads will
                never make concurrent calls to separation_oracle() using the same idx value
                (i.e. the first argument).
        !*/

        typedef matrix_type_ matrix_type;
        typedef typename matrix_type::type scalar_type;
        typedef feature_vector_type_ feature_vector_type;

        structural_svm_problem (
            unsigned long num_threads
        );
        /*!
            ensures
                - this object is properly initialized
                - #get_num_threads() == num_threads
        !*/

        unsigned long get_num_threads (
        ) const;
        /*!
            ensures
                - Returns the number of threads which will be used to make concurrent
                  calls to the separation_oracle() function.
        !*/

    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_STRUCTURAL_SVM_PRObLEM_THREADED_ABSTRACT_Hh_


dlib C++ Library - structural_svm_distributed_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_STRUCTURAL_SVM_DISTRIBUTeD_ABSTRACT_Hh_
#ifdef DLIB_STRUCTURAL_SVM_DISTRIBUTeD_ABSTRACT_Hh_

#include "structural_svm_problem_abstract.h"
#include "../optimization/optimization_oca_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class svm_struct_processing_node : noncopyable
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is a tool for distributing the work involved in solving
                a dlib::structural_svm_problem across many computers.  It is used in
                conjunction with the svm_struct_controller_node defined below.
        !*/

    public:

        template <
            typename T,
            typename U
            >
        svm_struct_processing_node (
            const structural_svm_problem<T,U>& problem,
            unsigned short port,
            unsigned short num_threads
        );
        /*!
            requires
                - port != 0
                - problem.get_num_samples() != 0
                - problem.get_num_dimensions() != 0
            ensures
                - This object will listen on the given port for a TCP connection from a
                  svm_struct_controller_node.  Once connected, the controller node will
                  be able to access the given problem.
                - Will use num_threads threads at a time to make concurrent calls to the
                  problem.separation_oracle() routine.  You should set this parameter equal
                  to the number of available processing cores.
                - Note that the following parameters within the given problem are ignored:
                    - problem.get_c()
                    - problem.get_epsilon()
                    - problem.get_cache_based_epsilon()
                    - problem.num_nuclear_norm_regularizers()
                    - weather the problem is verbose or not
                  Instead, they are defined by the svm_struct_controller_node. Note, however,
                  that the problem.get_max_cache_size() parameter is meaningful and controls
                  the size of the separation oracle cache within a svm_struct_processing_node.
        !*/
    };

// ----------------------------------------------------------------------------------------

    class svm_struct_controller_node : noncopyable
    {
        /*!
            INITIAL VALUE
                - get_num_processing_nodes() == 0
                - get_epsilon() == 0.001
                - get_max_iterations() == 10000
                - get_c() == 1
                - This object will not be verbose

            WHAT THIS OBJECT REPRESENTS
                This object is a tool for distributing the work involved in solving a
                dlib::structural_svm_problem across many computers.  The best way to understand
                its use is via example:

                First, suppose you have defined a structural_svm_problem object by inheriting from
                it and defining the appropriate virtual functions.  You could solve it by passing
                an instance to the oca optimizer.  However, if your separation oracle takes a long
                time to evaluate then the optimization will take a long time to solve.  To speed
                this up we can distribute the calls to the separation oracle across many computers.

                To make this concrete, lets imagine you want to distribute the work across three
                computers. You can accomplish this by creating four programs.  One containing a
                svm_struct_controller_node and three containing svm_struct_processing_nodes.

                The programs might look like this:

                Controller program:
                    int main()
                    {
                        svm_struct_controller_node cont;
                        cont.set_c(100);
                        // Tell cont where the processing nodes are on your network.
                        cont.add_processing_node("192.168.1.10:12345");
                        cont.add_processing_node("192.168.1.11:12345");
                        cont.add_processing_node("192.168.1.12:12345");
                        matrix<double> w;
                        oca solver;
                        cont(solver, w); // Run the optimization.
                        // After this finishes w will contain the solution vector.
                    }

                Processing programs (they are all the same, except that each loads a different subset
                of the training data):
                    int main()
                    {
                        // Put one third of your data into this problem object.  How you do this depends on your problem.
                        your_structural_svm_problem problem;
                        svm_struct_processing_node node(problem, 12345, number_of_cores_on_this_computer);
                        cout << "hit enter to terminate this program" << endl;
                        cin.get();
                    }

        !*/

    public:

        svm_struct_controller_node (
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        void set_epsilon (
            double eps
        );
        /*!
            requires
                - eps > 0
            ensures
                - #get_epsilon() == eps
        !*/

        double get_epsilon (
        ) const;
        /*!
            ensures
                - returns the error epsilon that determines when training should stop.
                  Smaller values may result in a more accurate solution but take longer
                  to execute.  Specifically, the algorithm stops when the average sample
                  risk (i.e. R(w) as defined by the dlib::structural_svm_problem object) is
                  within epsilon of its optimal value.

                  Also note that sample risk is an upper bound on a sample's loss.  So
                  you can think of this epsilon value as saying "solve the optimization
                  problem until the average loss per sample is within epsilon of it's
                  optimal value".
        !*/

        double get_cache_based_epsilon (
        ) const;
        /*!
            ensures
                - if (get_max_cache_size() != 0) then
                    - The solver will not stop when the average sample risk is within
                      get_epsilon() of its optimal value.  Instead, it will keep running
                      but will run the optimizer completely on the cache until the average
                      sample risk is within #get_cache_based_epsilon() of its optimal
                      value.  This means that it will perform this additional refinement in
                      the solution accuracy without making any additional calls to the
                      separation_oracle().  This is useful when using a nuclear norm
                      regularization term because it allows you to quickly solve the
                      optimization problem to a high precision, which in the case of a
                      nuclear norm regularized problem means that many of the learned
                      matrices will be low rank or very close to low rank due to the
                      nuclear norm regularizer.  This may not happen without solving the
                      problem to a high accuracy or their ranks may be difficult to
                      determine, so the extra accuracy given by the cache based refinement
                      is very useful.  Finally, note that we include the nuclear norm term
                      as part of the "risk" for the purposes of determining when to stop.
                - else
                    - The value of #get_cache_based_epsilon() has no effect.
        !*/

        void set_cache_based_epsilon (
            double eps
        );
        /*!
            requires
                - eps > 0
            ensures
                - #get_cache_based_epsilon() == eps
        !*/

        void set_max_iterations (
            unsigned long max_iter
        );
        /*!
            ensures
                - #get_max_iterations() == max_iter
        !*/

        unsigned long get_max_iterations (
        );
        /*!
            ensures
                - returns the maximum number of iterations the SVM optimizer is allowed to
                  run before it is required to stop and return a result.
        !*/

        void add_nuclear_norm_regularizer (
            long first_dimension,
            long rows,
            long cols,
            double regularization_strength
        );
        /*!
            requires
                - 0 <= first_dimension < number of dimensions in problem
                - 0 <= rows
                - 0 <= cols
                - first_dimension+rows*cols <= number of dimensions in problem
                - 0 < regularization_strength
            ensures
                - Adds a nuclear norm regularization term to the optimization problem
                  solved by this object.  That is, instead of solving:
                    Minimize: h(w) == 0.5*dot(w,w) + C*R(w)
                  this object will solve:
                    Minimize: h(w) == 0.5*dot(w,w) + C*R(w) + regularization_strength*nuclear_norm_of(part of w)
                  where "part of w" is the part of w indicated by the arguments to this
                  function. In particular, the part of w included in the nuclear norm is
                  exactly the matrix reshape(rowm(w, range(first_dimension, first_dimension+rows*cols-1)), rows, cols).
                  Therefore, if you think of the w vector as being the concatenation of a
                  bunch of matrices then you can use multiple calls to add_nuclear_norm_regularizer()
                  to add nuclear norm regularization terms to any of the matrices packed into w.
                - #num_nuclear_norm_regularizers() == num_nuclear_norm_regularizers() + 1
        !*/

        unsigned long num_nuclear_norm_regularizers (
        ) const;
        /*!
            ensures
                - returns the number of nuclear norm regularizers that are currently a part
                  of this optimization problem.  That is, returns the number of times
                  add_nuclear_norm_regularizer() has been called since the last call to
                  clear_nuclear_norm_regularizers() or object construction, whichever is
                  most recent.
        !*/

        void clear_nuclear_norm_regularizers (
        );
        /*!
            ensures
                - #num_nuclear_norm_regularizers() == 0
        !*/

        void be_verbose (
        );
        /*!
            ensures
                - This object will print status messages to standard out so that a
                  user can observe the progress of the algorithm.
        !*/

        void be_quiet(
        );
        /*!
            ensures
                - this object will not print anything to standard out
        !*/

        double get_c (
        ) const;
        /*!
            ensures
                - returns the SVM regularization parameter.  It is the parameter that
                  determines the trade off between trying to fit the training data
                  exactly or allowing more errors but hopefully improving the
                  generalization of the resulting classifier.  Larger values encourage
                  exact fitting while smaller values of C may encourage better
                  generalization.
        !*/

        void set_c (
            double C
        );
        /*!
            requires
                - C > 0
            ensures
                - #get_c() == C
        !*/

        void add_processing_node (
            const network_address& addr
        );
        /*!
            requires
                - addr.port != 0
            ensures
                - if (this address hasn't already been added) then
                    - #get_num_processing_nodes() == get_num_processing_nodes() + 1
                    - When operator() is invoked to solve the structural svm problem this
                      object will connect to the svm_struct_processing_node located at the
                      given network address and will include it in the distributed
                      optimization.
        !*/

        void add_processing_node (
            const std::string& ip_or_hostname,
            unsigned short port
        );
        /*!
            requires
                - port != 0
            ensures
                - invokes: add_processing_node(network_address(ip_or_hostname, port))
        !*/

        unsigned long get_num_processing_nodes (
        ) const;
        /*!
            ensures
                - returns the number of remote processing nodes that have been
                  registered with this object.
        !*/

        void remove_processing_nodes (
        );
        /*!
            ensures
                - #get_num_processing_nodes() == 0
        !*/

        class invalid_problem : public error {};

        template <typename matrix_type>
        double operator() (
            const oca& solver,
            matrix_type& w
        ) const;
        /*!
            requires
                - get_num_processing_nodes() != 0
                - matrix_type == a dlib::matrix capable of storing column vectors
            ensures
                - connects to the processing nodes and begins optimizing the structural
                  svm problem using the given oca solver.
                - stores the solution in #w
                - returns the objective value at the solution #w
            throws
                - invalid_problem
                  This exception is thrown if the svm_struct_processing_nodes disagree
                  on the dimensionality of the problem.  That is, if they disagree on
                  the value of structural_svm_problem::get_num_dimensions().
        !*/

    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_STRUCTURAL_SVM_DISTRIBUTeD_ABSTRACT_Hh_


dlib C++ Library - structural_svm_assignment_problem_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_STRUCTURAL_SVM_ASSiGNMENT_PROBLEM_ABSTRACT_Hh_
#ifdef DLIB_STRUCTURAL_SVM_ASSiGNMENT_PROBLEM_ABSTRACT_Hh_

#include "../matrix.h"
#include <vector>
#include "structural_svm_problem_threaded_abstract.h"
#include "assignment_function_abstract.h"

// ----------------------------------------------------------------------------------------

namespace dlib
{

    template <
        typename feature_extractor
        >
    class structural_svm_assignment_problem : noncopyable,
                                              public structural_svm_problem_threaded<matrix<double,0,1>,
                                                     typename feature_extractor::feature_vector_type >
    {
        /*!
            REQUIREMENTS ON feature_extractor
                It must be an object that implements an interface compatible with
                the example_feature_extractor defined in dlib/svm/assignment_function_abstract.h.

            WHAT THIS OBJECT REPRESENTS
                This object is a tool for learning the parameters needed to use an
                assignment_function object.  It learns the parameters by formulating the
                problem as a structural SVM problem.
        !*/

    public:
        typedef matrix<double,0,1> matrix_type;
        typedef typename feature_extractor::feature_vector_type feature_vector_type;
        typedef typename feature_extractor::lhs_element lhs_element;
        typedef typename feature_extractor::rhs_element rhs_element;
        typedef std::pair<std::vector<lhs_element>, std::vector<rhs_element> > sample_type;
        typedef std::vector<long> label_type;

        structural_svm_assignment_problem(
            const std::vector<sample_type>& samples,
            const std::vector<label_type>& labels,
            const feature_extractor& fe,
            bool force_assignment,
            unsigned long num_threads,
            const double loss_per_false_association,
            const double loss_per_missed_association
        );
        /*!
            requires
                - loss_per_false_association > 0
                - loss_per_missed_association > 0
                - is_assignment_problem(samples,labels) == true
                - if (force_assignment) then
                    - is_forced_assignment_problem(samples,labels) == true
            ensures
                - This object attempts to learn a mapping from the given samples to the
                  given labels.  In particular, it attempts to learn to predict labels[i]
                  based on samples[i].  Or in other words, this object can be used to learn
                  a parameter vector and bias, w and b, such that an assignment_function declared as:
                    assignment_function<feature_extractor> assigner(w,b,fe,force_assignment)
                  results in an assigner object which attempts to compute the following mapping:
                    labels[i] == labeler(samples[i])
                - This object will use num_threads threads during the optimization
                  procedure.  You should set this parameter equal to the number of
                  available processing cores on your machine.
                - When solving the structural SVM problem, we will use
                  loss_per_false_association as the loss for incorrectly associating
                  objects that shouldn't be associated.
                - When solving the structural SVM problem, we will use
                  loss_per_missed_association as the loss for failing to associate to
                  objects that are supposed to be associated with each other.
        !*/

    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_STRUCTURAL_SVM_ASSiGNMENT_PROBLEM_ABSTRACT_Hh_


dlib C++ Library - structural_svm_graph_labeling_problem_abstract.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_STRUCTURAL_SVM_GRAPH_LAbELING_PROBLEM_ABSTRACT_Hh_
#ifdef DLIB_STRUCTURAL_SVM_GRAPH_LAbELING_PROBLEM_ABSTRACT_Hh_

#include "../array/array_kernel_abstract.h"
#include "../graph/graph_kernel_abstract.h"
#include "../matrix/matrix_abstract.h"
#include "sparse_vector_abstract.h"
#include "structural_svm_problem_threaded_abstract.h"
#include <vector>

// ----------------------------------------------------------------------------------------

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename graph_type
        >
    bool is_graph_labeling_problem (
        const dlib::array<graph_type>& samples,
        const std::vector<std::vector<bool> >& labels
    );
    /*!
        requires
            - graph_type is an implementation of dlib/graph/graph_kernel_abstract.h
            - graph_type::type and graph_type::edge_type are either both dlib::matrix types
              capable of containing column vectors or both some kind of sparse vector type
              as defined in dlib/svm/sparse_vector_abstract.h.
        ensures
            - Note that a graph labeling problem is a task to learn a binary classifier which
              predicts the correct label for each node in the provided graphs.  Additionally,
              we have information in the form of edges between nodes where edges are present
              when we believe the linked nodes are likely to have the same label.  Therefore,
              part of a graph labeling problem is to learn to score each edge in terms of how
              strongly the edge should enforce labeling consistency between its two nodes.
              Thus, to be a valid graph labeling problem, samples should contain example graphs
              of connected nodes while labels should indicate the desired label of each node.
              The precise requirements for a valid graph labeling problem are listed below.
            - This function returns true if all of the following are true and false otherwise:
                - is_learning_problem(samples, labels) == true
                - All the vectors stored on the edges of each graph in samples
                  contain only values which are >= 0.
                - for all valid i:
                    - graph_contains_length_one_cycle(samples[i]) == false
                    - samples[i].number_of_nodes() == labels[i].size()
                      (i.e. Every graph node gets its own label)
                - if (graph_type::edge_type is a dlib::matrix) then
                    - All the nodes must contain vectors with the same number of dimensions.
                    - All the edges must contain vectors with the same number of dimensions.
                      (However, edge vectors may differ in dimension from node vectors.)
                    - All vectors have non-zero size.  That is, they have more than 0 dimensions.
    !*/

    template <
        typename graph_type
        >
    bool is_graph_labeling_problem (
        const dlib::array<graph_type>& samples,
        const std::vector<std::vector<bool> >& labels,
        std::string& reason_for_failure
    );
    /*!
        This function is identical to the above version of is_graph_labeling_problem()
        except that if it returns false it will populate reason_for_failure with a message
        describing why the graph is not a valid learning problem.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename U
        >
    bool sizes_match (
        const std::vector<std::vector<T> >& lhs,
        const std::vector<std::vector<U> >& rhs
    );
    /*!
        ensures
            - returns true if the sizes of lhs and rhs, as well as their constituent vectors
              all match.  In particular, we return true if all of the following conditions are
              met and false otherwise:
                - lhs.size() == rhs.size()
                - for all valid i:
                    - lhs[i].size() == rhs[i].size()
    !*/

// ----------------------------------------------------------------------------------------

    bool all_values_are_nonnegative (
        const std::vector<std::vector<double> >& x
    );
    /*!
        ensures
            - returns true if all the double values contained in x are >= 0.
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename graph_type
        >
    class structural_svm_graph_labeling_problem : noncopyable,
                                                  public structural_svm_problem_threaded<matrix<double,0,1>,
                                                         typename graph_type::type >
    {
        /*!
            REQUIREMENTS ON graph_type
                - graph_type is an implementation of dlib/graph/graph_kernel_abstract.h
                - graph_type::type and graph_type::edge_type must be either matrix objects
                  capable of representing column vectors or some kind of sparse vector
                  type as defined in dlib/svm/sparse_vector_abstract.h.

            WHAT THIS OBJECT REPRESENTS
                This object is a tool for learning the weight vectors needed to use
                a graph_labeler object.  It learns the parameter vectors by formulating
                the problem as a structural SVM problem.
        !*/

    public:
        typedef matrix<double,0,1> matrix_type;
        typedef typename graph_type::type feature_vector_type;
        typedef graph_type sample_type;
        typedef std::vector<bool> label_type;

        structural_svm_graph_labeling_problem(
            const dlib::array<sample_type>& samples,
            const std::vector<label_type>& labels,
            const std::vector<std::vector<double> >& losses,
            unsigned long num_threads
        );
        /*!
            requires
                - is_graph_labeling_problem(samples,labels) == true
                - if (losses.size() != 0) then
                    - sizes_match(labels, losses) == true
                    - all_values_are_nonnegative(losses) == true
            ensures
                - This object attempts to learn a mapping from the given samples to the
                  given labels.  In particular, it attempts to learn to predict labels[i]
                  based on samples[i].  Or in other words, this object can be used to learn
                  parameter vectors, E and W, such that a graph_labeler declared as:
                    graph_labeler<feature_vector_type> labeler(E,W)
                  results in a labeler object which attempts to compute the following mapping:
                    labels[i] == labeler(samples[i])
                - When you use this object with the oca optimizer you get back just one
                  big parameter vector as the solution.  Therefore, note that this single
                  big vector is the concatenation of E and W.  The first get_num_edge_weights()
                  elements of this vector correspond to E and the rest is W.
                - This object will use num_threads threads during the optimization
                  procedure.  You should set this parameter equal to the number of
                  available processing cores on your machine.
                - if (losses.size() == 0) then
                    - #get_loss_on_positive_class() == 1.0
                    - #get_loss_on_negative_class() == 1.0
                    - #get_losses().size() == 0
                    - The losses argument is effectively ignored if its size is zero.
                - else
                    - #get_losses() == losses
                    - Each node in the training data has its own loss value defined by
                      the corresponding entry of losses.  In particular, this means that
                      the node with label labels[i][j] incurs a loss of losses[i][j] if
                      it is incorrectly labeled.
                    - The get_loss_on_positive_class() and get_loss_on_negative_class()
                      parameters are ignored.  Only get_losses() is used in this case.
        !*/

        const std::vector<std::vector<double> >& get_losses (
        ) const;
        /*!
            ensures
                - returns the losses vector given to this object's constructor.
                  This vector defines the per sample loss values used.  If the vector
                  is empty then the loss values defined by get_loss_on_positive_class() and
                  get_loss_on_positive_class() are used instead.
        !*/

        long get_num_edge_weights (
        ) const;
        /*!
            ensures
                - returns the dimensionality of the edge weight vector.  It is also
                  important to know that when using the oca solver with this object,
                  you must set it to generate non-negative weights for the edge weight
                  part of the total weight vector.  You can do this by passing get_num_edge_weights()
                  to the third argument to oca::operator().
        !*/

        void set_loss_on_positive_class (
            double loss
        );
        /*!
            requires
                - loss >= 0
                - get_losses().size() == 0
            ensures
                - #get_loss_on_positive_class() == loss
        !*/

        void set_loss_on_negative_class (
            double loss
        );
        /*!
            requires
                - loss >= 0
                - get_losses().size() == 0
            ensures
                - #get_loss_on_negative_class() == loss
        !*/

        double get_loss_on_positive_class (
        ) const;
        /*!
            requires
                - get_losses().size() == 0
            ensures
                - returns the loss incurred when a graph node which is supposed to have
                  a label of true gets misclassified.  This value controls how much we care
                  about correctly classifying nodes which should be labeled as true.  Larger
                  loss values indicate that we care more strongly than smaller values.
        !*/

        double get_loss_on_negative_class (
        ) const;
        /*!
            requires
                - get_losses().size() == 0
            ensures
                - returns the loss incurred when a graph node which is supposed to have
                  a label of false gets misclassified.  This value controls how much we care
                  about correctly classifying nodes which should be labeled as false.  Larger
                  loss values indicate that we care more strongly than smaller values.
        !*/
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_STRUCTURAL_SVM_GRAPH_LAbELING_PROBLEM_ABSTRACT_Hh_


dlib C++ Library - structural_svm_object_detection_problem_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_STRUCTURAL_SVM_ObJECT_DETECTION_PROBLEM_ABSTRACT_Hh_
#ifdef DLIB_STRUCTURAL_SVM_ObJECT_DETECTION_PROBLEM_ABSTRACT_Hh_

#include "../matrix.h"
#include "structural_svm_problem_threaded_abstract.h"
#include <sstream>
#include "../image_processing/full_object_detection_abstract.h"
#include "../image_processing/box_overlap_testing.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class impossible_labeling_error : public dlib::error
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is the exception thrown by the structural_svm_object_detection_problem
                when it detects that the image_scanner_type it is working with is incapable
                of representing the truth rectangles it has been asked to predict.

                This kind of problem can happen when the test_box_overlap object indicates
                that two ground truth rectangles overlap and are therefore not allowed to
                both be output at the same time.  Or alternatively, if there are not enough
                detection templates to cover the variety of truth rectangle shapes.
        !*/
    };

// ----------------------------------------------------------------------------------------

    template <
        typename image_scanner_type,
        typename image_array_type
        >
    class structural_svm_object_detection_problem : public structural_svm_problem_threaded<matrix<double,0,1> >,
                                                    noncopyable
    {
        /*!
            REQUIREMENTS ON image_scanner_type
                image_scanner_type must be an implementation of
                dlib/image_processing/scan_fhog_pyramid_abstract.h or
                dlib/image_processing/scan_image_custom_abstract.h or
                dlib/image_processing/scan_image_pyramid_abstract.h or
                dlib/image_processing/scan_image_boxes_abstract.h

            REQUIREMENTS ON image_array_type
                image_array_type must be an implementation of dlib/array/array_kernel_abstract.h
                and it must contain objects which can be accepted by image_scanner_type::load().

            WHAT THIS OBJECT REPRESENTS
                This object is a tool for learning the parameter vector needed to use a
                scan_image_pyramid, scan_fhog_pyramid, scan_image_custom, or
                scan_image_boxes object.

                It learns the parameter vector by formulating the problem as a structural
                SVM problem.  The exact details of the method are described in the paper
                Max-Margin Object Detection by Davis E. King (http://arxiv.org/abs/1502.00046).

        !*/

    public:

        structural_svm_object_detection_problem(
            const image_scanner_type& scanner,
            const test_box_overlap& overlap_tester,
            const bool auto_overlap_tester,
            const image_array_type& images,
            const std::vector<std::vector<full_object_detection> >& truth_object_detections,
            const std::vector<std::vector<rectangle> >& ignore,
            const test_box_overlap& ignore_overlap_tester,
            unsigned long num_threads = 2
        );
        /*!
            requires
                - is_learning_problem(images, truth_object_detections)
                - ignore.size() == images.size()
                - scanner.get_num_detection_templates() > 0
                - scanner.load(images[0]) must be a valid expression.
                - for all valid i, j:
                    - truth_object_detections[i][j].num_parts() == scanner.get_num_movable_components_per_detection_template()
                    - all_parts_in_rect(truth_object_detections[i][j]) == true
            ensures
                - This object attempts to learn a mapping from the given images to the
                  object locations given in truth_object_detections.  In particular, it
                  attempts to learn to predict truth_object_detections[i] based on
                  images[i].  Or in other words, this object can be used to learn a
                  parameter vector, w, such that an object_detector declared as:
                    object_detector<image_scanner_type> detector(scanner,get_overlap_tester(),w)
                  results in a detector object which attempts to compute the locations of
                  all the objects in truth_object_detections.  So if you called
                  detector(images[i]) you would hopefully get a list of rectangles back
                  that had truth_object_detections[i].size() elements and contained exactly
                  the rectangles indicated by truth_object_detections[i].
                - if (auto_overlap_tester == true) then
                    - #get_overlap_tester() == a test_box_overlap object that is configured
                      using the find_tight_overlap_tester() routine and the contents of
                      truth_object_detections.
                - else
                    - #get_overlap_tester() == overlap_tester
                - #get_match_eps() == 0.5
                - This object will use num_threads threads during the optimization
                  procedure.  You should set this parameter equal to the number of
                  available processing cores on your machine.
                - #get_loss_per_missed_target() == 1
                - #get_loss_per_false_alarm() == 1
                - for all valid i:
                    - Within images[i] any detections that match against a rectangle in
                      ignore[i], according to ignore_overlap_tester, are ignored.  That is,
                      the optimizer doesn't care if the detector outputs a detection that
                      matches any of the ignore rectangles or if it fails to output a
                      detection for an ignore rectangle.  Therefore, if there are objects
                      in your dataset that you are unsure you want to detect or otherwise
                      don't care if the detector gets or doesn't then you can mark them
                      with ignore rectangles and the optimizer will simply ignore them.
        !*/

        test_box_overlap get_overlap_tester (
        ) const;
        /*!
            ensures
                - returns the overlap tester used by this object.
        !*/

        void set_match_eps (
            double eps
        );
        /*!
            requires
                - 0 < eps < 1
            ensures
                - #get_match_eps() == eps
        !*/

        double get_match_eps (
        ) const;
        /*!
            ensures
                - returns the amount of alignment necessary for a detection to be considered
                  as matching with a ground truth rectangle.  The precise formula for determining
                  if two rectangles match each other is the following, rectangles A and B match
                  if and only if:
                    A.intersect(B).area()/(A+B).area() > get_match_eps()
        !*/

        double get_loss_per_missed_target (
        ) const;
        /*!
            ensures
                - returns the amount of loss experienced for failing to detect one of the
                  targets.
        !*/

        void set_loss_per_missed_target (
            double loss
        );
        /*!
            requires
                - loss > 0
            ensures
                - #get_loss_per_missed_target() == loss
        !*/

        double get_loss_per_false_alarm (
        ) const;
        /*!
            ensures
                - returns the amount of loss experienced for emitting a false alarm detection.
                  Or in other words, the loss for generating a detection that doesn't correspond
                  to one of the truth rectangles.
        !*/

        void set_loss_per_false_alarm (
            double loss
        );
        /*!
            requires
                - loss > 0
            ensures
                - #get_loss_per_false_alarm() == loss
        !*/

    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_STRUCTURAL_SVM_ObJECT_DETECTION_PROBLEM_ABSTRACT_Hh_


dlib C++ Library - structural_svm_sequence_labeling_problem_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_STRUCTURAL_SVM_SEQUENCE_LaBELING_PROBLEM_ABSTRACT_Hh_
#ifdef DLIB_STRUCTURAL_SVM_SEQUENCE_LaBELING_PROBLEM_ABSTRACT_Hh_

#include "../matrix.h"
#include <vector>
#include "structural_svm_problem_threaded_abstract.h"
#include "sequence_labeler_abstract.h"

// ----------------------------------------------------------------------------------------

namespace dlib
{

    template <
        typename feature_extractor
        >
    class structural_svm_sequence_labeling_problem : noncopyable,
                                                     public structural_svm_problem_threaded<matrix<double,0,1>,
                                                            std::vector<std::pair<unsigned long,double> > >
    {
        /*!
            REQUIREMENTS ON feature_extractor
                It must be an object that implements an interface compatible with
                the example_feature_extractor defined in dlib/svm/sequence_labeler_abstract.h.

            WHAT THIS OBJECT REPRESENTS
                This object is a tool for learning the weight vector needed to use
                a sequence_labeler object.

                It learns the parameter vector by formulating the problem as a structural
                SVM problem.  The general approach is discussed in the paper:
                    Hidden Markov Support Vector Machines by
                    Y. Altun, I. Tsochantaridis, T. Hofmann
                While the particular optimization strategy used is the method from:
                    T. Joachims, T. Finley, Chun-Nam Yu, Cutting-Plane Training of
                    Structural SVMs, Machine Learning, 77(1):27-59, 2009.
        !*/

    public:
        typedef typename feature_extractor::sequence_type sequence_type;

        structural_svm_sequence_labeling_problem(
            const std::vector<sequence_type>& samples,
            const std::vector<std::vector<unsigned long> >& labels,
            const feature_extractor& fe,
            unsigned long num_threads = 2
        );
        /*!
            requires
                - is_sequence_labeling_problem(samples, labels) == true
                - contains_invalid_labeling(fe, samples, labels) == false
                - for all valid i and j: labels[i][j] < fe.num_labels()
            ensures
                - This object attempts to learn a mapping from the given samples to the
                  given labels.  In particular, it attempts to learn to predict labels[i]
                  based on samples[i].  Or in other words, this object can be used to learn
                  a parameter vector, w, such that a sequence_labeler declared as:
                    sequence_labeler<feature_extractor> labeler(w,fe)
                  results in a labeler object which attempts to compute the following mapping:
                    labels[i] == labeler(samples[i])
                - This object will use num_threads threads during the optimization
                  procedure.  You should set this parameter equal to the number of
                  available processing cores on your machine.
                - #num_labels() == fe.num_labels()
                - for all valid i: #get_loss(i) == 1
        !*/

        unsigned long num_labels (
        ) const;
        /*!
            ensures
                - returns the number of possible labels in this learning problem
        !*/

        double get_loss (
            unsigned long label
        ) const;
        /*!
            requires
                - label < num_labels()
            ensures
                - returns the loss incurred when a sequence element with the given
                  label is misclassified.  This value controls how much we care about
                  correctly classifying this type of label.  Larger loss values indicate
                  that we care more strongly than smaller values.
        !*/

        void set_loss (
            unsigned long label,
            double value
        );
        /*!
            requires
                - label < num_labels()
                - value >= 0
            ensures
                - #get_loss(label) == value
        !*/
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_STRUCTURAL_SVM_SEQUENCE_LaBELING_PROBLEM_ABSTRACT_Hh_


dlib C++ Library - structural_assignment_trainer_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_STRUCTURAL_ASSiGNMENT_TRAINER_ABSTRACT_Hh_
#ifdef DLIB_STRUCTURAL_ASSiGNMENT_TRAINER_ABSTRACT_Hh_

#include "../algs.h"
#include "structural_svm_assignment_problem.h"
#include "assignment_function_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    class structural_assignment_trainer
    {
        /*!
            REQUIREMENTS ON feature_extractor
                It must be an object that implements an interface compatible with
                the example_feature_extractor defined in dlib/svm/assignment_function_abstract.h.

            WHAT THIS OBJECT REPRESENTS
                This object is a tool for learning to solve an assignment problem based
                on a training dataset of example assignments.  The training procedure produces an
                assignment_function object which can be used to predict the assignments of
                new data.

                Note that this is just a convenience wrapper around the
                structural_svm_assignment_problem to make it look
                similar to all the other trainers in dlib.
        !*/

    public:
        typedef typename feature_extractor::lhs_element lhs_element;
        typedef typename feature_extractor::rhs_element rhs_element;
        typedef std::pair<std::vector<lhs_element>, std::vector<rhs_element> > sample_type;
        typedef std::vector<long> label_type;
        typedef assignment_function<feature_extractor> trained_function_type;

        structural_assignment_trainer (
        );
        /*!
            ensures
                - #get_c() == 100
                - this object isn't verbose
                - #get_epsilon() == 0.01
                - #get_num_threads() == 2
                - #get_max_cache_size() == 5
                - #get_feature_extractor() == a default initialized feature_extractor
                - #forces_assignment() == false
                - #get_loss_per_false_association() == 1
                - #get_loss_per_missed_association() == 1
                - #forces_last_weight_to_1() == false
        !*/

        explicit structural_assignment_trainer (
            const feature_extractor& fe
        );
        /*!
            ensures
                - #get_c() == 100
                - this object isn't verbose
                - #get_epsilon() == 0.01
                - #get_num_threads() == 2
                - #get_max_cache_size() == 40
                - #get_feature_extractor() == fe
                - #forces_assignment() == false
                - #get_loss_per_false_association() == 1
                - #get_loss_per_missed_association() == 1
                - #forces_last_weight_to_1() == false
        !*/

        const feature_extractor& get_feature_extractor (
        ) const;
        /*!
            ensures
                - returns the feature extractor used by this object
        !*/

        void set_num_threads (
            unsigned long num
        );
        /*!
            ensures
                - #get_num_threads() == num
        !*/

        unsigned long get_num_threads (
        ) const;
        /*!
            ensures
                - returns the number of threads used during training.  You should
                  usually set this equal to the number of processing cores on your
                  machine.
        !*/

        void set_epsilon (
            double eps
        );
        /*!
            requires
                - eps > 0
            ensures
                - #get_epsilon() == eps
        !*/

        double get_epsilon (
        ) const;
        /*!
            ensures
                - returns the error epsilon that determines when training should stop.
                  Smaller values may result in a more accurate solution but take longer
                  to train.  You can think of this epsilon value as saying "solve the
                  optimization problem until the average number of assignment mistakes per
                  training sample is within epsilon of its optimal value".
        !*/

        void set_max_cache_size (
            unsigned long max_size
        );
        /*!
            ensures
                - #get_max_cache_size() == max_size
        !*/

        unsigned long get_max_cache_size (
        ) const;
        /*!
            ensures
                - During training, this object basically runs the assignment_function on
                  each training sample, over and over.  To speed this up, it is possible to
                  cache the results of these invocations.  This function returns the number
                  of cache elements per training sample kept in the cache.  Note that a value
                  of 0 means caching is not used at all.
        !*/

        void set_loss_per_false_association (
            double loss
        );
        /*!
            requires
                - loss > 0
            ensures
                - #get_loss_per_false_association() == loss
        !*/

        double get_loss_per_false_association (
        ) const;
        /*!
            ensures
                - returns the amount of loss experienced for associating two objects
                  together that shouldn't be associated.  If you care more about avoiding
                  accidental associations than ensuring all possible associations are
                  identified then then you can increase this value.
        !*/

        void set_loss_per_missed_association (
            double loss
        );
        /*!
            requires
                - loss > 0
            ensures
                - #get_loss_per_missed_association() == loss
        !*/

        double get_loss_per_missed_association (
        ) const;
        /*!
            ensures
                - returns the amount of loss experienced for failing to associate two
                  objects that are supposed to be associated.  If you care more about
                  getting all the associations than avoiding accidentally associating
                  objects that shouldn't be associated then you can increase this value.
        !*/

        void be_verbose (
        );
        /*!
            ensures
                - This object will print status messages to standard out so that a
                  user can observe the progress of the algorithm.
        !*/

        void be_quiet (
        );
        /*!
            ensures
                - this object will not print anything to standard out
        !*/

        void set_oca (
            const oca& item
        );
        /*!
            ensures
                - #get_oca() == item
        !*/

        const oca get_oca (
        ) const;
        /*!
            ensures
                - returns a copy of the optimizer used to solve the structural SVM problem.
        !*/

        void set_c (
            double C
        );
        /*!
            requires
                - C > 0
            ensures
                - #get_c() = C
        !*/

        double get_c (
        ) const;
        /*!
            ensures
                - returns the SVM regularization parameter.  It is the parameter
                  that determines the trade-off between trying to fit the training
                  data (i.e. minimize the loss) or allowing more errors but hopefully
                  improving the generalization of the resulting assignment_function.
                  Larger values encourage exact fitting while smaller values of C may
                  encourage better generalization.
        !*/

        void set_forces_assignment (
            bool new_value
        );
        /*!
            ensures
                - #forces_assignment() == new_value
        !*/

        bool forces_assignment(
        ) const;
        /*!
            ensures
                - returns the value of the forces_assignment() parameter for the
                  assignment_functions generated by this object.
        !*/

        bool forces_last_weight_to_1 (
        ) const;
        /*!
            ensures
                - returns true if this trainer has the constraint that the last weight in
                  the learned parameter vector must be 1.  This is the weight corresponding
                  to the feature in the training vectors with the highest dimension.
                - Forcing the last weight to 1 also disables the bias and therefore the
                  get_bias() field of the learned assignment_function will be 0 when
                  forces_last_weight_to_1() == true.
        !*/

        void force_last_weight_to_1 (
            bool should_last_weight_be_1
        );
        /*!
            ensures
                - #forces_last_weight_to_1() == should_last_weight_be_1
        !*/

        const assignment_function<feature_extractor> train (
            const std::vector<sample_type>& samples,
            const std::vector<label_type>& labels
        ) const;
        /*!
            requires
                - is_assignment_problem(samples,labels) == true
                - if (forces_assignment()) then
                    - is_forced_assignment_problem(samples,labels) == true
            ensures
                - Uses the structural_svm_assignment_problem to train an
                  assignment_function on the given samples/labels training pairs.
                  The idea is to learn to predict a label given an input sample.
                - returns a function F with the following properties:
                    - F(new_sample) == A set of assignments indicating how the elements of
                      new_sample.first match up with the elements of new_sample.second.
                    - F.forces_assignment() == forces_assignment()
                    - F.get_feature_extractor() == get_feature_extractor()
                    - if (forces_last_weight_to_1()) then
                        - F.get_bias() == 0
                        - F.get_weights()(F.get_weights().size()-1) == 1
        !*/
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_STRUCTURAL_ASSiGNMENT_TRAINER_ABSTRACT_Hh_


dlib C++ Library - structural_graph_labeling_trainer_abstract.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_STRUCTURAL_GRAPH_LABELING_tRAINER_ABSTRACT_Hh_
#ifdef DLIB_STRUCTURAL_GRAPH_LABELING_tRAINER_ABSTRACT_Hh_

#include "../algs.h"
#include "../optimization.h"
#include "structural_svm_graph_labeling_problem_abstract.h"
#include "../graph_cuts/graph_labeler_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type
        >
    class structural_graph_labeling_trainer
    {
        /*!
            REQUIREMENTS ON vector_type
                - vector_type is a dlib::matrix capable of representing column
                  vectors or it is a sparse vector type as defined in dlib/svm/sparse_vector_abstract.h.

            WHAT THIS OBJECT REPRESENTS
                This object is a tool for learning to solve a graph labeling problem based
                on a training dataset of example labeled graphs.  The training procedure
                produces a graph_labeler object which can be used to predict the labelings
                of new graphs.

                Note that this is just a convenience wrapper around the
                structural_svm_graph_labeling_problem to make it look
                similar to all the other trainers in dlib.
        !*/

    public:
        typedef std::vector<bool> label_type;
        typedef graph_labeler<vector_type> trained_function_type;

        structural_graph_labeling_trainer (
        );
        /*!
            ensures
                - #get_c() == 10
                - this object isn't verbose
                - #get_epsilon() == 0.1
                - #get_num_threads() == 2
                - #get_max_cache_size() == 5
                - #get_loss_on_positive_class() == 1.0
                - #get_loss_on_negative_class() == 1.0
        !*/

        void set_num_threads (
            unsigned long num
        );
        /*!
            ensures
                - #get_num_threads() == num
        !*/

        unsigned long get_num_threads (
        ) const;
        /*!
            ensures
                - returns the number of threads used during training.  You should
                  usually set this equal to the number of processing cores on your
                  machine.
        !*/

        void set_epsilon (
            double eps
        );
        /*!
            requires
                - eps > 0
            ensures
                - #get_epsilon() == eps
        !*/

        double get_epsilon (
        ) const;
        /*!
            ensures
                - returns the error epsilon that determines when training should stop.
                  Smaller values may result in a more accurate solution but take longer
                  to train.  You can think of this epsilon value as saying "solve the
                  optimization problem until the average number of labeling mistakes per
                  example graph is within epsilon of its optimal value".
        !*/

        void set_max_cache_size (
            unsigned long max_size
        );
        /*!
            ensures
                - #get_max_cache_size() == max_size
        !*/

        unsigned long get_max_cache_size (
        ) const;
        /*!
            ensures
                - During training, this object basically runs the graph_labeler on each
                  training sample, over and over.  To speed this up, it is possible to
                  cache the results of these invocations.  This function returns the number
                  of cache elements per training sample kept in the cache.  Note that a value
                  of 0 means caching is not used at all.
        !*/

        void be_verbose (
        );
        /*!
            ensures
                - This object will print status messages to standard out so that a
                  user can observe the progress of the algorithm.
        !*/

        void be_quiet (
        );
        /*!
            ensures
                - this object will not print anything to standard out
        !*/

        void set_oca (
            const oca& item
        );
        /*!
            ensures
                - #get_oca() == item
        !*/

        const oca get_oca (
        ) const;
        /*!
            ensures
                - returns a copy of the optimizer used to solve the structural SVM problem.
        !*/

        void set_c (
            double C
        );
        /*!
            requires
                - C > 0
            ensures
                - #get_c() = C
        !*/

        double get_c (
        ) const;
        /*!
            ensures
                - returns the SVM regularization parameter.  It is the parameter
                  that determines the trade-off between trying to fit the training
                  data (i.e. minimize the loss) or allowing more errors but hopefully
                  improving the generalization of the resulting graph_labeler.  Larger
                  values encourage exact fitting while smaller values of C may encourage
                  better generalization.
        !*/

        void set_loss_on_positive_class (
            double loss
        );
        /*!
            requires
                - loss >= 0
            ensures
                - #get_loss_on_positive_class() == loss
        !*/

        void set_loss_on_negative_class (
            double loss
        );
        /*!
            requires
                - loss >= 0
            ensures
                - #get_loss_on_negative_class() == loss
        !*/

        double get_loss_on_positive_class (
        ) const;
        /*!
            ensures
                - returns the loss incurred when a graph node which is supposed to have
                  a label of true gets misclassified.  This value controls how much we care
                  about correctly classifying nodes which should be labeled as true.  Larger
                  loss values indicate that we care more strongly than smaller values.
        !*/

        double get_loss_on_negative_class (
        ) const;
        /*!
            ensures
                - returns the loss incurred when a graph node which is supposed to have
                  a label of false gets misclassified.  This value controls how much we care
                  about correctly classifying nodes which should be labeled as false.  Larger
                  loss values indicate that we care more strongly than smaller values.
        !*/

        template <
            typename graph_type
            >
        const graph_labeler<vector_type> train (
            const dlib::array<graph_type>& samples,
            const std::vector<label_type>& labels
        ) const;
        /*!
            requires
                - is_graph_labeling_problem(samples,labels) == true
            ensures
                - Uses the structural_svm_graph_labeling_problem to train a graph_labeler
                  on the given samples/labels training pairs.  The idea is to learn to
                  predict a label given an input sample.
                - The values of get_loss_on_positive_class() and get_loss_on_negative_class()
                  are used to determine how to value mistakes on each node during training.
                - returns a function F with the following properties:
                    - F(new_sample) == The predicted labels for the nodes in the graph
                      new_sample.
        !*/

        template <
            typename graph_type
            >
        const graph_labeler<vector_type> train (
            const dlib::array<graph_type>& samples,
            const std::vector<label_type>& labels,
            const std::vector<std::vector<double> >& losses
        ) const;
        /*!
            requires
                - is_graph_labeling_problem(samples,labels) == true
                - if (losses.size() != 0) then
                    - sizes_match(labels, losses) == true
                    - all_values_are_nonnegative(losses) == true
            ensures
                - Uses the structural_svm_graph_labeling_problem to train a graph_labeler
                  on the given samples/labels training pairs.  The idea is to learn to
                  predict a label given an input sample.
                - returns a function F with the following properties:
                    - F(new_sample) == The predicted labels for the nodes in the graph
                      new_sample.
                - if (losses.size() == 0) then
                    - The values of get_loss_on_positive_class() and get_loss_on_negative_class()
                      are used to determine how to value mistakes on each node during training.
                    - The losses argument is effectively ignored if its size is zero.
                - else
                    - Each node in the training data has its own loss value defined by the
                      corresponding entry of losses.  In particular, this means that the
                      node with label labels[i][j] incurs a loss of losses[i][j] if it is
                      incorrectly labeled.
                    - The get_loss_on_positive_class() and get_loss_on_negative_class()
                      parameters are ignored.  Only losses is used in this case.
        !*/
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_STRUCTURAL_GRAPH_LABELING_tRAINER_ABSTRACT_Hh_


dlib C++ Library - structural_object_detection_trainer_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_STRUCTURAL_OBJECT_DETECTION_TRAiNER_H_ABSTRACTh_
#ifdef DLIB_STRUCTURAL_OBJECT_DETECTION_TRAiNER_H_ABSTRACTh_

#include "structural_svm_object_detection_problem_abstract.h"
#include "../image_processing/object_detector_abstract.h"
#include "../image_processing/box_overlap_testing_abstract.h"
#include "../image_processing/full_object_detection_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename image_scanner_type
        >
    class structural_object_detection_trainer : noncopyable
    {
        /*!
            REQUIREMENTS ON image_scanner_type
                image_scanner_type must be an implementation of
                dlib/image_processing/scan_fhog_pyramid_abstract.h or
                dlib/image_processing/scan_image_custom_abstract.h or
                dlib/image_processing/scan_image_pyramid_abstract.h or
                dlib/image_processing/scan_image_boxes_abstract.h

            WHAT THIS OBJECT REPRESENTS
                This object is a tool for learning to detect objects in images based on a
                set of labeled images. The training procedure produces an object_detector
                which can be used to predict the locations of objects in new images.

                Note that this is just a convenience wrapper around the structural_svm_object_detection_problem
                to make it look similar to all the other trainers in dlib.
        !*/

    public:
        typedef double scalar_type;
        typedef default_memory_manager mem_manager_type;
        typedef object_detector<image_scanner_type> trained_function_type;

        explicit structural_object_detection_trainer (
            const image_scanner_type& scanner
        );
        /*!
            requires
                - scanner.get_num_detection_templates() > 0
            ensures
                - #get_c() == 1
                - this object isn't verbose
                - #get_epsilon() == 0.1
                - #get_num_threads() == 2
                - #get_max_cache_size() == 5
                - #get_match_eps() == 0.5
                - #get_loss_per_missed_target() == 1
                - #get_loss_per_false_alarm() == 1
                - This object will attempt to learn a model for the given
                  scanner object when train() is called.
                - #get_scanner() == scanner
                  (note that only the "configuration" of scanner is copied.
                  I.e. the copy is done using copy_configuration())
                - #auto_set_overlap_tester() == true
        !*/

        const image_scanner_type& get_scanner (
        ) const;
        /*!
            ensures
                - returns the image scanner used by this object.
        !*/

        bool auto_set_overlap_tester (
        ) const;
        /*!
            ensures
                - if (this object will automatically determine an appropriate
                  state for the overlap tester used for non-max suppression.) then
                    - returns true
                    - In this case, it is determined using the find_tight_overlap_tester()
                      routine based on the truth_object_detections given to the
                      structural_object_detection_trainer::train() method.
                - else
                    - returns false
        !*/

        void set_overlap_tester (
            const test_box_overlap& tester
        );
        /*!
            ensures
                - #get_overlap_tester() == tester
                - #auto_set_overlap_tester() == false
        !*/

        test_box_overlap get_overlap_tester (
        ) const;
        /*!
            requires
                - auto_set_overlap_tester() == false
            ensures
                - returns the overlap tester object which will be used to perform non-max suppression.
                  In particular, this function returns the overlap tester which will populate the
                  object_detector returned by train().
        !*/

        void set_num_threads (
            unsigned long num
        );
        /*!
            ensures
                - #get_num_threads() == num
        !*/

        unsigned long get_num_threads (
        ) const;
        /*!
            ensures
                - returns the number of threads used during training.  You should
                  usually set this equal to the number of processing cores on your
                  machine.
        !*/

        void set_epsilon (
            scalar_type eps
        );
        /*!
            requires
                - eps > 0
            ensures
                - #get_epsilon() == eps
        !*/

        const scalar_type get_epsilon (
        ) const;
        /*!
            ensures
                - returns the error epsilon that determines when training should stop.
                  Smaller values may result in a more accurate solution but take longer
                  to train.  You can think of this epsilon value as saying "solve the
                  optimization problem until the average loss per sample is within epsilon
                  of its optimal value".
        !*/

        void set_max_cache_size (
            unsigned long max_size
        );
        /*!
            ensures
                - #get_max_cache_size() == max_size
        !*/

        unsigned long get_max_cache_size (
        ) const;
        /*!
            ensures
                - During training, this object basically runs the object detector on
                  each image, over and over.  To speed this up, it is possible to cache
                  the results of these detector invocations.  This function returns the
                  number of cache elements per training sample kept in the cache.  Note
                  that a value of 0 means caching is not used at all.  Note also that
                  each cache element takes up about sizeof(double)*scanner.get_num_dimensions()
                  memory (where scanner is the scanner given to this object's constructor).
        !*/

        void be_verbose (
        );
        /*!
            ensures
                - This object will print status messages to standard out so that a
                  user can observe the progress of the algorithm.
        !*/

        void be_quiet (
        );
        /*!
            ensures
                - this object will not print anything to standard out
        !*/

        void set_oca (
            const oca& item
        );
        /*!
            ensures
                - #get_oca() == item
        !*/

        const oca get_oca (
        ) const;
        /*!
            ensures
                - returns a copy of the optimizer used to solve the structural SVM problem.
        !*/

        void set_c (
            scalar_type C
        );
        /*!
            requires
                - C > 0
            ensures
                - #get_c() = C
        !*/

        const scalar_type get_c (
        ) const;
        /*!
            ensures
                - returns the SVM regularization parameter.  It is the parameter
                  that determines the trade-off between trying to fit the training
                  data (i.e. minimize the loss) or allowing more errors but hopefully
                  improving the generalization of the resulting detector.  Larger
                  values encourage exact fitting while smaller values of C may encourage
                  better generalization.
        !*/

        void set_match_eps (
            double eps
        );
        /*!
            requires
                - 0 < eps < 1
            ensures
                - #get_match_eps() == eps
        !*/

        double get_match_eps (
        ) const;
        /*!
            ensures
                - returns the amount of alignment necessary for a detection to be considered
                  as matching with a ground truth rectangle.  If it doesn't match then
                  it is considered to be a false alarm.  To define this precisely, let
                  A and B be two rectangles, then A and B match if and only if:
                    A.intersect(B).area()/(A+B).area() > get_match_eps()
        !*/

        double get_loss_per_missed_target (
        ) const;
        /*!
            ensures
                - returns the amount of loss experienced for failing to detect one of the
                  targets.  If you care more about finding targets than having a low false
                  alarm rate then you can increase this value.
        !*/

        void set_loss_per_missed_target (
            double loss
        );
        /*!
            requires
                - loss > 0
            ensures
                - #get_loss_per_missed_target() == loss
        !*/

        double get_loss_per_false_alarm (
        ) const;
        /*!
            ensures
                - returns the amount of loss experienced for emitting a false alarm detection.
                  Or in other words, the loss for generating a detection that doesn't correspond
                  to one of the truth rectangles.  If you care more about having a low false
                  alarm rate than finding all the targets then you can increase this value.
        !*/

        void set_loss_per_false_alarm (
            double loss
        );
        /*!
            requires
                - loss > 0
            ensures
                - #get_loss_per_false_alarm() == loss
        !*/

        template <
            typename image_array_type
            >
        const trained_function_type train (
            const image_array_type& images,
            const std::vector<std::vector<full_object_detection> >& truth_object_detections
        ) const;
        /*!
            requires
                - is_learning_problem(images, truth_object_detections) == true
                - it must be valid to pass images[0] into the image_scanner_type::load() method.
                  (also, image_array_type must be an implementation of dlib/array/array_kernel_abstract.h)
                - for all valid i, j:
                    - truth_object_detections[i][j].num_parts() == get_scanner().get_num_movable_components_per_detection_template()
                    - all_parts_in_rect(truth_object_detections[i][j]) == true
            ensures
                - Uses the structural_svm_object_detection_problem to train an object_detector
                  on the given images and truth_object_detections.
                - returns a function F with the following properties:
                    - F(new_image) == A prediction of what objects are present in new_image.  This
                      is a set of rectangles indicating their positions.
        !*/

        template <
            typename image_array_type
            >
        const trained_function_type train (
            const image_array_type& images,
            const std::vector<std::vector<rectangle> >& truth_object_detections
        ) const;
        /*!
            requires
                - is_learning_problem(images, truth_object_detections) == true
                - it must be valid to pass images[0] into the image_scanner_type::load() method.
                  (also, image_array_type must be an implementation of dlib/array/array_kernel_abstract.h)
                - get_scanner().get_num_movable_components_per_detection_template() == 0
            ensures
                - This function is identical to the above train(), except that it converts
                  each element of truth_object_detections into a full_object_detection by
                  passing it to full_object_detection's constructor taking only a rectangle.
                  Therefore, this version of train() is a convenience function for for the
                  case where you don't have any movable components of the detection templates.
        !*/

        template <
            typename image_array_type
            >
        const trained_function_type train (
            const image_array_type& images,
            const std::vector<std::vector<full_object_detection> >& truth_object_detections,
            const std::vector<std::vector<rectangle> >& ignore,
            const test_box_overlap& ignore_overlap_tester = test_box_overlap()
        ) const;
        /*!
            requires
                - is_learning_problem(images, truth_object_detections) == true
                - it must be valid to pass images[0] into the image_scanner_type::load() method.
                  (also, image_array_type must be an implementation of dlib/array/array_kernel_abstract.h)
                - ignore.size() == images.size()
                - for all valid i, j:
                    - truth_object_detections[i][j].num_parts() == get_scanner().get_num_movable_components_per_detection_template()
                    - all_parts_in_rect(truth_object_detections[i][j]) == true
            ensures
                - Uses the structural_svm_object_detection_problem to train an object_detector
                  on the given images and truth_object_detections.
                - for all valid i:
                    - Within images[i] any detections that match against a rectangle in
                      ignore[i], according to ignore_overlap_tester, are ignored.  That is,
                      the optimizer doesn't care if the detector outputs a detection that
                      matches any of the ignore rectangles or if it fails to output a
                      detection for an ignore rectangle.  Therefore, if there are objects
                      in your dataset that you are unsure if you want to detect or otherwise
                      don't care if the detector gets or doesn't then you can mark them
                      with ignore rectangles and the optimizer will simply ignore them.
                - returns a function F with the following properties:
                    - F(new_image) == A prediction of what objects are present in new_image.  This
                      is a set of rectangles indicating their positions.
        !*/

        template <
            typename image_array_type
            >
        const trained_function_type train (
            const image_array_type& images,
            const std::vector<std::vector<rectangle> >& truth_object_detections,
            const std::vector<std::vector<rectangle> >& ignore,
            const test_box_overlap& ignore_overlap_tester = test_box_overlap()
        ) const;
        /*!
            requires
                - is_learning_problem(images, truth_object_detections) == true
                - ignore.size() == images.size()
                - it must be valid to pass images[0] into the image_scanner_type::load() method.
                  (also, image_array_type must be an implementation of dlib/array/array_kernel_abstract.h)
                - get_scanner().get_num_movable_components_per_detection_template() == 0
            ensures
                - This function is identical to the above train(), except that it converts
                  each element of truth_object_detections into a full_object_detection by
                  passing it to full_object_detection's constructor taking only a rectangle.
                  Therefore, this version of train() is a convenience function for for the
                  case where you don't have any movable components of the detection templates.
        !*/
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_STRUCTURAL_OBJECT_DETECTION_TRAiNER_H_ABSTRACTh_


dlib C++ Library - structural_sequence_labeling_trainer_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_STRUCTURAL_SEQUENCE_LABELING_TRAiNER_ABSTRACT_Hh_
#ifdef DLIB_STRUCTURAL_SEQUENCE_LABELING_TRAiNER_ABSTRACT_Hh_

#include "../algs.h"
#include "../optimization.h"
#include "structural_svm_sequence_labeling_problem_abstract.h"
#include "sequence_labeler_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    class structural_sequence_labeling_trainer
    {
        /*!
            REQUIREMENTS ON feature_extractor
                It must be an object that implements an interface compatible with
                the example_feature_extractor defined in dlib/svm/sequence_labeler_abstract.h.

            WHAT THIS OBJECT REPRESENTS
                This object is a tool for learning to do sequence labeling based
                on a set of training data.  The training procedure produces a
                sequence_labeler object which can be used to predict the labels of
                new data sequences.

                Note that this is just a convenience wrapper around the
                structural_svm_sequence_labeling_problem to make it look
                similar to all the other trainers in dlib.
        !*/

    public:
        typedef typename feature_extractor::sequence_type sample_sequence_type;
        typedef std::vector<unsigned long> labeled_sequence_type;
        typedef sequence_labeler<feature_extractor> trained_function_type;

        structural_sequence_labeling_trainer (
        );
        /*!
            ensures
                - #get_c() == 100
                - this object isn't verbose
                - #get_epsilon() == 0.1
                - #get_max_iterations() == 10000
                - #get_num_threads() == 2
                - #get_max_cache_size() == 5
                - #get_feature_extractor() == a default initialized feature_extractor
        !*/

        explicit structural_sequence_labeling_trainer (
            const feature_extractor& fe
        );
        /*!
            ensures
                - #get_c() == 100
                - this object isn't verbose
                - #get_epsilon() == 0.1
                - #get_max_iterations() == 10000
                - #get_num_threads() == 2
                - #get_max_cache_size() == 5
                - #get_feature_extractor() == fe
        !*/

        const feature_extractor& get_feature_extractor (
        ) const;
        /*!
            ensures
                - returns the feature extractor used by this object
        !*/

        unsigned long num_labels (
        ) const;
        /*!
            ensures
                - returns get_feature_extractor().num_labels()
                  (i.e. returns the number of possible output labels for each
                  element of a sequence)
        !*/

        void set_num_threads (
            unsigned long num
        );
        /*!
            ensures
                - #get_num_threads() == num
        !*/

        unsigned long get_num_threads (
        ) const;
        /*!
            ensures
                - returns the number of threads used during training.  You should
                  usually set this equal to the number of processing cores on your
                  machine.
        !*/

        void set_epsilon (
            double eps
        );
        /*!
            requires
                - eps > 0
            ensures
                - #get_epsilon() == eps
        !*/

        const double get_epsilon (
        ) const;
        /*!
            ensures
                - returns the error epsilon that determines when training should stop.
                  Smaller values may result in a more accurate solution but take longer
                  to train.  You can think of this epsilon value as saying "solve the
                  optimization problem until the average number of labeling mistakes per
                  training sample is within epsilon of its optimal value".
        !*/

        void set_max_iterations (
            unsigned long max_iter
        );
        /*!
            ensures
                - #get_max_iterations() == max_iter
        !*/

        unsigned long get_max_iterations (
        );
        /*!
            ensures
                - returns the maximum number of iterations the SVM optimizer is allowed to
                  run before it is required to stop and return a result.
        !*/

        void set_max_cache_size (
            unsigned long max_size
        );
        /*!
            ensures
                - #get_max_cache_size() == max_size
        !*/

        unsigned long get_max_cache_size (
        ) const;
        /*!
            ensures
                - During training, this object basically runs the sequence_labeler on
                  each training sample, over and over.  To speed this up, it is possible to
                  cache the results of these labeler invocations.  This function returns the
                  number of cache elements per training sample kept in the cache.  Note
                  that a value of 0 means caching is not used at all.
        !*/

        void be_verbose (
        );
        /*!
            ensures
                - This object will print status messages to standard out so that a
                  user can observe the progress of the algorithm.
        !*/

        void be_quiet (
        );
        /*!
            ensures
                - this object will not print anything to standard out
        !*/

        void set_oca (
            const oca& item
        );
        /*!
            ensures
                - #get_oca() == item
        !*/

        const oca get_oca (
        ) const;
        /*!
            ensures
                - returns a copy of the optimizer used to solve the structural SVM problem.
        !*/

        void set_c (
            double C
        );
        /*!
            requires
                - C > 0
            ensures
                - #get_c() = C
        !*/

        double get_c (
        ) const;
        /*!
            ensures
                - returns the SVM regularization parameter.  It is the parameter
                  that determines the trade-off between trying to fit the training
                  data (i.e. minimize the loss) or allowing more errors but hopefully
                  improving the generalization of the resulting sequence labeler.  Larger
                  values encourage exact fitting while smaller values of C may encourage
                  better generalization.
        !*/

        double get_loss (
            unsigned long label
        ) const;
        /*!
            requires
                - label < num_labels()
            ensures
                - returns the loss incurred when a sequence element with the given
                  label is misclassified.  This value controls how much we care about
                  correctly classifying this type of label.  Larger loss values indicate
                  that we care more strongly than smaller values.
        !*/

        void set_loss (
            unsigned long label,
            double value
        );
        /*!
            requires
                - label < num_labels()
                - value >= 0
            ensures
                - #get_loss(label) == value
        !*/

        const sequence_labeler<feature_extractor> train(
            const std::vector<sample_sequence_type>& x,
            const std::vector<labeled_sequence_type>& y
        ) const;
        /*!
            requires
                - is_sequence_labeling_problem(x, y) == true
                - contains_invalid_labeling(get_feature_extractor(), x, y) == false
                - for all valid i and j: y[i][j] < num_labels()
            ensures
                - Uses the structural_svm_sequence_labeling_problem to train a
                  sequence_labeler on the given x/y training pairs.  The idea is
                  to learn to predict a y given an input x.
                - returns a function F with the following properties:
                    - F(new_x) == A sequence of predicted labels for the elements of new_x.
                    - F(new_x).size() == new_x.size()
                    - for all valid i:
                        - F(new_x)[i] == the predicted label of new_x[i]
        !*/

    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_STRUCTURAL_SEQUENCE_LABELING_TRAiNER_ABSTRACT_Hh_


dlib C++ Library - structural_sequence_segmentation_trainer_abstract.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_STRUCTURAL_SEQUENCE_sEGMENTATION_TRAINER_ABSTRACT_Hh_
#ifdef DLIB_STRUCTURAL_SEQUENCE_sEGMENTATION_TRAINER_ABSTRACT_Hh_

#include "sequence_segmenter_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    class structural_sequence_segmentation_trainer
    {
        /*!
            REQUIREMENTS ON feature_extractor
                It must be an object that implements an interface compatible with
                the example_feature_extractor defined in dlib/svm/sequence_segmenter_abstract.h.

            WHAT THIS OBJECT REPRESENTS
                This object is a tool for learning to do sequence segmentation based on a
                set of training data.  The training procedure produces a sequence_segmenter
                object which can be used to identify the sub-segments of new data
                sequences.

                This object internally uses the structural_sequence_labeling_trainer to
                solve the learning problem.
        !*/

    public:

        typedef typename feature_extractor::sequence_type sample_sequence_type;
        typedef std::vector<std::pair<unsigned long, unsigned long> > segmented_sequence_type;

        typedef sequence_segmenter<feature_extractor> trained_function_type;

        structural_sequence_segmentation_trainer (
        );
        /*!
            ensures
                - #get_c() == 100
                - this object isn't verbose
                - #get_epsilon() == 0.1
                - #get_max_iterations() == 10000
                - #get_num_threads() == 2
                - #get_max_cache_size() == 40
                - #get_feature_extractor() == a default initialized feature_extractor
                - #get_loss_per_missed_segment() == 1
                - #get_loss_per_false_alarm() == 1
        !*/

        explicit structural_sequence_segmentation_trainer (
            const feature_extractor& fe
        );
        /*!
            ensures
                - #get_c() == 100
                - this object isn't verbose
                - #get_epsilon() == 0.1
                - #get_max_iterations() == 10000
                - #get_num_threads() == 2
                - #get_max_cache_size() == 40
                - #get_feature_extractor() == fe
                - #get_loss_per_missed_segment() == 1
                - #get_loss_per_false_alarm() == 1
        !*/

        const feature_extractor& get_feature_extractor (
        ) const;
        /*!
            ensures
                - returns the feature extractor used by this object
        !*/

        void set_num_threads (
            unsigned long num
        );
        /*!
            ensures
                - #get_num_threads() == num
        !*/

        unsigned long get_num_threads (
        ) const;
        /*!
            ensures
                - returns the number of threads used during training.  You should
                  usually set this equal to the number of processing cores on your
                  machine.
        !*/

        void set_epsilon (
            double eps_
        );
        /*!
            requires
                - eps > 0
            ensures
                - #get_epsilon() == eps
        !*/

        double get_epsilon (
        ) const;
        /*!
            ensures
                - returns the error epsilon that determines when training should stop.
                  Smaller values may result in a more accurate solution but take longer
                  to train.  You can think of this epsilon value as saying "solve the
                  optimization problem until the average number of segmentation mistakes
                  per training sample is within epsilon of its optimal value".
        !*/

        void set_max_iterations (
            unsigned long max_iter
        );
        /*!
            ensures
                - #get_max_iterations() == max_iter
        !*/

        unsigned long get_max_iterations (
        );
        /*!
            ensures
                - returns the maximum number of iterations the SVM optimizer is allowed to
                  run before it is required to stop and return a result.
        !*/

        void set_max_cache_size (
            unsigned long max_size
        );
        /*!
            ensures
                - #get_max_cache_size() == max_size
        !*/

        unsigned long get_max_cache_size (
        ) const;
        /*!
            ensures
                - During training, this object basically runs the sequence_segmenter on
                  each training sample, over and over.  To speed this up, it is possible to
                  cache the results of these segmenter invocations.  This function returns
                  the number of cache elements per training sample kept in the cache.  Note
                  that a value of 0 means caching is not used at all.
        !*/

        void be_verbose (
        );
        /*!
            ensures
                - This object will print status messages to standard out so that a user can
                  observe the progress of the algorithm.
        !*/

        void be_quiet (
        );
        /*!
            ensures
                - this object will not print anything to standard out
        !*/

        void set_oca (
            const oca& item
        );
        /*!
            ensures
                - #get_oca() == item
        !*/

        const oca get_oca (
        ) const;
        /*!
            ensures
                - returns a copy of the optimizer used to solve the structural SVM problem.
        !*/

        void set_c (
            double C
        );
        /*!
            requires
                - C > 0
            ensures
                - #get_c() = C
        !*/

        double get_c (
        ) const;
        /*!
            ensures
                - returns the SVM regularization parameter.  It is the parameter that
                  determines the trade-off between trying to fit the training data (i.e.
                  minimize the loss) or allowing more errors but hopefully improving the
                  generalization of the resulting sequence labeler.  Larger values
                  encourage exact fitting while smaller values of C may encourage better
                  generalization.
        !*/

        void set_loss_per_missed_segment (
            double loss
        );
        /*!
            requires
                - loss >= 0
            ensures
                - #get_loss_per_missed_segment() == loss
        !*/

        double get_loss_per_missed_segment (
        ) const;
        /*!
            ensures
                - returns the amount of loss incurred for failing to detect a segment.  The
                  larger the loss the more important it is to detect all the segments.
        !*/

        void set_loss_per_false_alarm (
            double loss
        );
        /*!
            requires
                - loss >= 0
            ensures
                - #get_loss_per_false_alarm() == loss
        !*/

        double get_loss_per_false_alarm (
        ) const;
        /*!
            ensures
                - returns the amount of loss incurred for outputting a false detection. The
                  larger the loss the more important it is to avoid outputting false
                  detections.
        !*/

        const sequence_segmenter<feature_extractor> train(
            const std::vector<sample_sequence_type>& x,
            const std::vector<segmented_sequence_type>& y
        ) const;
        /*!
            requires
                - is_sequence_segmentation_problem(x, y) == true
            ensures
                - Uses the given training data to learn to do sequence segmentation.  That
                  is, this function will try to find a sequence_segmenter capable of
                  predicting y[i] when given x[i] as input.  Moreover, it should also be
                  capable of predicting the segmentation of new input sequences.  Or in
                  other words, the learned sequence_segmenter should also generalize to new
                  data outside the training dataset.
        !*/

    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_STRUCTURAL_SEQUENCE_sEGMENTATION_TRAINER_ABSTRACT_Hh_


dlib C++ Library - structural_track_association_trainer_abstract.h

// Copyright (C) 2014  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_STRUCTURAL_TRACK_ASSOCIATION_TRAnER_ABSTRACT_Hh_
#ifdef DLIB_STRUCTURAL_TRACK_ASSOCIATION_TRAnER_ABSTRACT_Hh_

#include "track_association_function_abstract.h"
#include "structural_assignment_trainer_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class structural_track_association_trainer
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is a tool for learning to solve a track association problem.  That
                is, it takes in a set of training data and outputs a track_association_function
                you can use to do detection to track association.  The training data takes the
                form of a set or sets of "track histories".  Each track history is a
                std::vector where each element contains all the detections from a single time
                step.  Moreover, each detection has a label that uniquely identifies which
                object (e.g. person or whatever) the detection really corresponds to.  That is,
                the labels indicate the correct detection to track associations.  The goal of
                this object is then to produce a track_association_function that can perform a
                correct detection to track association at each time step.
        !*/

    public:

        structural_track_association_trainer (
        );
        /*!
            ensures
                - #get_c() == 100
                - this object isn't verbose
                - #get_epsilon() == 0.001
                - #get_num_threads() == 2
                - #get_max_cache_size() == 5
                - #learns_nonnegative_weights() == false
                - #get_loss_per_track_break() == 1
                - #get_loss_per_false_association() == 1
        !*/

        void set_num_threads (
            unsigned long num
        );
        /*!
            ensures
                - #get_num_threads() == num
        !*/

        unsigned long get_num_threads (
        ) const;
        /*!
            ensures
                - returns the number of threads used during training.  You should
                  usually set this equal to the number of processing cores on your
                  machine.
        !*/

        void set_epsilon (
            double eps
        );
        /*!
            requires
                - eps > 0
            ensures
                - #get_epsilon() == eps
        !*/

        double get_epsilon (
        ) const;
        /*!
            ensures
                - returns the error epsilon that determines when training should stop.
                  Smaller values may result in a more accurate solution but take longer to
                  train.  You can think of this epsilon value as saying "solve the
                  optimization problem until the average number of association mistakes per
                  time step is within epsilon of its optimal value".
        !*/

        void set_max_cache_size (
            unsigned long max_size
        );
        /*!
            ensures
                - #get_max_cache_size() == max_size
        !*/

        unsigned long get_max_cache_size (
        ) const;
        /*!
            ensures
                - During training, this object basically runs the track_association_function on
                  each training sample, over and over.  To speed this up, it is possible to
                  cache the results of these invocations.  This function returns the number
                  of cache elements per training sample kept in the cache.  Note that a value
                  of 0 means caching is not used at all.
        !*/

        void be_verbose (
        );
        /*!
            ensures
                - This object will print status messages to standard out so that a user can
                  observe the progress of the algorithm.
        !*/

        void be_quiet (
        );
        /*!
            ensures
                - this object will not print anything to standard out
        !*/

        void set_loss_per_false_association (
            double loss
        );
        /*!
            requires
                - loss > 0
            ensures
                - #get_loss_per_false_association() == loss
        !*/

        double get_loss_per_false_association (
        ) const;
        /*!
            ensures
                - returns the amount of loss experienced for assigning a detection to the
                  wrong track.  If you care more about avoiding false associations than
                  avoiding track breaks then you can increase this value.
        !*/

        void set_loss_per_track_break (
            double loss
        );
        /*!
            requires
                - loss > 0
            ensures
                - #get_loss_per_track_break() == loss
        !*/

        double get_loss_per_track_break (
        ) const;
        /*!
            ensures
                - returns the amount of loss experienced for incorrectly assigning a
                  detection to a new track instead of assigning it to its existing track.
                  If you care more about avoiding track breaks than avoiding things like
                  track swaps then you can increase this value.
        !*/

        void set_oca (
            const oca& item
        );
        /*!
            ensures
                - #get_oca() == item
        !*/

        const oca get_oca (
        ) const;
        /*!
            ensures
                - Internally this object treats track association learning as a structural
                  SVM problem.  This routine returns a copy of the optimizer used to solve
                  the structural SVM problem.
        !*/

        void set_c (
            double C
        );
        /*!
            ensures
                - returns the SVM regularization parameter.  It is the parameter that
                  determines the trade-off between trying to fit the training data (i.e.
                  minimize the loss) or allowing more errors but hopefully improving the
                  generalization of the resulting track_association_function.  Larger
                  values encourage exact fitting while smaller values of C may encourage
                  better generalization.
        !*/

        double get_c (
        ) const;
        /*!
            requires
                - C > 0
            ensures
                - #get_c() = C
        !*/

        bool learns_nonnegative_weights (
        ) const;
        /*!
            ensures
                - Ultimately, the output of training is a parameter vector that defines the
                  behavior of the track_association_function.  If
                  learns_nonnegative_weights() == true then the resulting learned parameter
                  vector will always have non-negative entries.
        !*/

        void set_learns_nonnegative_weights (
            bool value
        );
        /*!
            ensures
                - #learns_nonnegative_weights() == value
        !*/

        template <
            typename detection_type,
            typename label_type
            >
        const track_association_function<detection_type> train (
            const std::vector<std::vector<labeled_detection<detection_type,label_type> > >& sample
        ) const;
        /*!
            requires
                - is_track_association_problem(sample) == true
            ensures
                - This function attempts to learn to do track association from the given
                  training data.  Note that we interpret sample as a single track history such
                  that sample[0] are all detections from the first time step, then sample[1]
                  are detections from the second time step, and so on.
                - returns a function F such that:
                    - Executing F(tracks, detections) will try to correctly associate the
                      contents of detections to the contents of tracks and perform track
                      updating and creation.
                    - if (learns_nonnegative_weights() == true) then
                        - min(F.get_assignment_function().get_weights()) >= 0
        !*/

        template <
            typename detection_type,
            typename label_type
            >
        const track_association_function<detection_type> train (
            const std::vector<std::vector<std::vector<labeled_detection<detection_type,label_type> > > >& sample
        ) const;
        /*!
            requires
                - is_track_association_problem(samples) == true
            ensures
                - This function attempts to learn to do track association from the given
                  training data.  In this case, we take a set of track histories as
                  training data instead of just one track history as with the above train()
                  method.
                - returns a function F such that:
                    - Executing F(tracks, detections) will try to correctly associate the
                      contents of detections to the contents of tracks and perform track
                      updating and creation.
                    - if (learns_nonnegative_weights() == true) then
                        - min(F.get_assignment_function().get_weights()) >= 0
        !*/

    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_STRUCTURAL_TRACK_ASSOCIATION_TRAnER_ABSTRACT_Hh_


dlib C++ Library - svm_rank_trainer_abstract.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SVM_RANK_TrAINER_ABSTRACT_Hh_
#ifdef DLIB_SVM_RANK_TrAINER_ABSTRACT_Hh_

#include "ranking_tools_abstract.h"
#include "sparse_vector_abstract.h"
#include "function_abstract.h"
#include "kernel_abstract.h"
#include "../algs.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename K
        >
    class svm_rank_trainer
    {
        /*!
            REQUIREMENTS ON K
                Is either linear_kernel or sparse_linear_kernel.

            WHAT THIS OBJECT REPRESENTS
                This object represents a tool for training a ranking support vector machine
                using linear kernels.  In particular, this object is a tool for training
                the Ranking SVM described in the paper:
                    Optimizing Search Engines using Clickthrough Data by Thorsten Joachims

                Note that we normalize the C parameter by multiplying it by 1/(number of ranking pairs).
                Therefore, to make an exact comparison between this object and Equation 12
                in the paper you must multiply C by the appropriate normalizing quantity.

                Finally, note that the implementation of this object is done using the oca
                optimizer and count_ranking_inversions() method.  This means that it runs
                in O(n*log(n)) time, making it suitable for use with large datasets.
        !*/

    public:
        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 decision_function<kernel_type> trained_function_type;

        svm_rank_trainer (
        );
        /*!
            ensures
                - This object is properly initialized and ready to be used to train a
                  ranking support vector machine.
                - #get_oca() == oca() (i.e. an instance of oca with default parameters)
                - #get_c() == 1
                - #get_epsilon() == 0.001
                - this object will not be verbose unless be_verbose() is called
                - #get_max_iterations() == 10000
                - #learns_nonnegative_weights() == false
                - #forces_last_weight_to_1() == false
                - #has_prior() == false
        !*/

        explicit svm_rank_trainer (
            const scalar_type& C
        );
        /*!
            requires
                - C > 0
            ensures
                - This object is properly initialized and ready to be used to train a
                  ranking support vector machine.
                - #get_oca() == oca() (i.e. an instance of oca with default parameters)
                - #get_c() == C
                - #get_epsilon() == 0.001
                - this object will not be verbose unless be_verbose() is called
                - #get_max_iterations() == 10000
                - #learns_nonnegative_weights() == false
                - #forces_last_weight_to_1() == false
                - #has_prior() == false
        !*/

        void set_epsilon (
            scalar_type eps
        );
        /*!
            requires
                - eps > 0
            ensures
                - #get_epsilon() == eps
        !*/

        const scalar_type get_epsilon (
        );
        /*!
            ensures
                - returns the error epsilon that determines when training should stop.
                  Smaller values may result in a more accurate solution but take longer to
                  train.  You can think of this epsilon value as saying "solve the
                  optimization problem until the average ranking accuracy is within epsilon
                  of its optimal value".  Here we mean "ranking accuracy" in the same sense
                  used by test_ranking_function() and cross_validate_ranking_trainer().
        !*/

        unsigned long get_max_iterations (
        ) const;
        /*!
            ensures
                - returns the maximum number of iterations the SVM optimizer is allowed to
                  run before it is required to stop and return a result.
        !*/

        void set_max_iterations (
            unsigned long max_iter
        );
        /*!
            ensures
                - #get_max_iterations() == max_iter
        !*/

        void be_verbose (
        );
        /*!
            ensures
                - This object will print status messages to standard out so that a user can
                  observe the progress of the algorithm.
        !*/

        void be_quiet (
        );
        /*!
            ensures
                - this object will not print anything to standard out
        !*/

        bool forces_last_weight_to_1 (
        ) const;
        /*!
            ensures
                - returns true if this trainer has the constraint that the last weight in
                  the learned parameter vector must be 1.  This is the weight corresponding
                  to the feature in the training vectors with the highest dimension.
        !*/

        void force_last_weight_to_1 (
            bool should_last_weight_be_1
        );
        /*!
            ensures
                - #forces_last_weight_to_1() == should_last_weight_be_1
                - if (should_last_weight_be_1 == true) then
                    - #has_prior() == false
        !*/

        void set_oca (
            const oca& item
        );
        /*!
            ensures
                - #get_oca() == item
        !*/

        const oca get_oca (
        ) const;
        /*!
            ensures
                - returns a copy of the optimizer used to solve the SVM problem.
        !*/

        const kernel_type get_kernel (
        ) const;
        /*!
            ensures
                - returns a copy of the kernel function in use by this object.  Since the
                  linear kernels don't have any parameters this function just returns
                  kernel_type()
        !*/

        bool learns_nonnegative_weights (
        ) const;
        /*!
            ensures
                - The output of training is a weight vector that defines the behavior of
                  the resulting decision function.  That is, the decision function simply
                  takes the dot product between the learned weight vector and a test sample
                  and returns the result.  Therefore, if learns_nonnegative_weights() == true
                  then the resulting learned weight vector will always have non-negative
                  entries.
        !*/

        void set_learns_nonnegative_weights (
            bool value
        );
        /*!
            ensures
                - #learns_nonnegative_weights() == value
                - if (value == true) then
                    - #has_prior() == false
        !*/

        void set_prior (
            const trained_function_type& prior
        );
        /*!
            requires
                - prior == a function produced by a call to this class's train() function.
                  Therefore, it must be the case that:
                    - prior.basis_vectors.size() == 1
                    - prior.alpha(0) == 1
            ensures
                - Subsequent calls to train() will try to learn a function similar to the
                  given prior.
                - #has_prior() == true
                - #learns_nonnegative_weights() == false
                - #forces_last_weight_to_1() == false
        !*/

        bool has_prior (
        ) const
        /*!
            ensures
                - returns true if a prior has been set and false otherwise.  Having a prior
                  set means that you have called set_prior() and supplied a previously
                  trained function as a reference.  In this case, any call to train() will
                  try to learn a function that matches the behavior of the prior as close
                  as possible but also fits the supplied training data.  In more technical
                  detail, having a prior means we replace the ||w||^2 regularizer with one
                  of the form ||w-prior||^2 where w is the set of parameters for a learned
                  function.
        !*/

        void set_c (
            scalar_type C
        );
        /*!
            requires
                - C > 0
            ensures
                - #get_c() == C
        !*/

        const scalar_type get_c (
        ) const;
        /*!
            ensures
                - returns the SVM regularization parameter.  It is the parameter that
                  determines the trade off between trying to fit the training data exactly
                  or allowing more errors but hopefully improving the generalization of the
                  resulting classifier.  Larger values encourage exact fitting while
                  smaller values of C may encourage better generalization.
        !*/

        const decision_function<kernel_type> train (
            const std::vector<ranking_pair<sample_type> >& samples
        ) const;
        /*!
            requires
                - is_ranking_problem(samples) == true
                - if (has_prior()) then
                    - The vectors in samples must have the same dimensionality as the
                      vectors used to train the prior given to set_prior().
            ensures
                - trains a ranking support vector classifier given the training samples.
                - returns a decision function F with the following properties:
                    - F.alpha.size() == 1
                    - F.basis_vectors.size() == 1
                    - F.alpha(0) == 1
                    - Given two vectors, A and B, then A is predicted to come before B
                      in the learned ranking if and only if F(A) > F(B).
                    - Based on the contents of samples, F will attempt to give relevant
                      vectors higher scores than non-relevant vectors.
        !*/

        const decision_function<kernel_type> train (
            const ranking_pair<sample_type>& sample
        ) const;
        /*!
            requires
                - is_ranking_problem(std::vector<ranking_pair<sample_type> >(1, sample)) == true
                - if (has_prior()) then
                    - The vectors in samples must have the same dimensionality as the
                      vectors used to train the prior given to set_prior().
            ensures
                - This is just a convenience routine for calling the above train()
                  function.  That is, it just copies sample into a std::vector object and
                  invokes the above train() method.  This means that calling this function
                  is equivalent to invoking:
                    return train(std::vector<ranking_pair<sample_type> >(1, sample));
        !*/

    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SVM_RANK_TrAINER_ABSTRACT_Hh_


dlib C++ Library - bottom_up_cluster_abstract.h

// Copyright (C) 2015  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_BOTTOM_uP_CLUSTER_ABSTRACT_Hh_
#ifdef DLIB_BOTTOM_uP_CLUSTER_ABSTRACT_Hh_

#include "../matrix.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename EXP
        >
    unsigned long bottom_up_cluster (
        const matrix_exp<EXP>& dists,
        std::vector<unsigned long>& labels,
        unsigned long min_num_clusters,
        double max_dist = std::numeric_limits<double>::infinity()
    );
    /*!
        requires
            - dists.nr() == dists.nc()
            - min_num_clusters > 0
            - dists == trans(dists)
              (l.e. dists should be symmetric)
        ensures
            - Runs a bottom up agglomerative clustering algorithm.
            - Interprets dists as a matrix that gives the distances between dists.nr()
              items.  In particular, we take dists(i,j) to be the distance between the ith
              and jth element of some set.  This function clusters the elements of this set
              into at least min_num_clusters (or dists.nr() if there aren't enough
              elements).  Additionally, within each cluster, the maximum pairwise distance
              between any two cluster elements is <= max_dist.
            - returns the number of clusters found.
            - #labels.size() == dists.nr()
            - for all valid i:
                - #labels[i] == the cluster ID of the node with index i (i.e. the node
                  corresponding to the distances dists(i,*)).
                - 0 <= #labels[i] < the number of clusters found
                  (i.e. cluster IDs are assigned contiguously and start at 0)
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_BOTTOM_uP_CLUSTER_ABSTRACT_Hh_


dlib C++ Library - chinese_whispers_abstract.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_CHINESE_WHISPErS_ABSTRACT_Hh_
#ifdef DLIB_CHINESE_WHISPErS_ABSTRACT_Hh_

#include <vector>
#include "../rand.h"
#include "../graph_utils/ordered_sample_pair_abstract.h"
#include "../graph_utils/sample_pair_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    unsigned long chinese_whispers (
        const std::vector<ordered_sample_pair>& edges,
        std::vector<unsigned long>& labels,
        const unsigned long num_iterations,
        dlib::rand& rnd
    );
    /*!
        requires
            - is_ordered_by_index(edges) == true
        ensures
            - This function implements the graph clustering algorithm described in the
              paper: Chinese Whispers - an Efficient Graph Clustering Algorithm and its
              Application to Natural Language Processing Problems by Chris Biemann.
            - Interprets edges as a directed graph.  That is, it contains the edges on the
              said graph and the ordered_sample_pair::distance() values define the edge
              weights (larger values indicating a stronger edge connection between the
              nodes).  If an edge has a distance() value of infinity then it is considered
              a "must link" edge.
            - returns the number of clusters found.
            - #labels.size() == max_index_plus_one(edges)
            - for all valid i:
                - #labels[i] == the cluster ID of the node with index i in the graph.
                - 0 <= #labels[i] < the number of clusters found
                  (i.e. cluster IDs are assigned contiguously and start at 0)
            - Duplicate edges are interpreted as if there had been just one edge with a
              distance value equal to the sum of all the duplicate edge's distance values.
            - The algorithm performs exactly num_iterations passes over the graph before
              terminating.
    !*/

// ----------------------------------------------------------------------------------------

    unsigned long chinese_whispers (
        const std::vector<sample_pair>& edges,
        std::vector<unsigned long>& labels,
        const unsigned long num_iterations,
        dlib::rand& rnd
    );
    /*!
        ensures
            - This function is identical to the above chinese_whispers() routine except
              that it operates on a vector of sample_pair objects instead of
              ordered_sample_pairs.  Therefore, this is simply a convenience routine.  In
              particular, it is implemented by transforming the given edges into
              ordered_sample_pairs and then calling the chinese_whispers() routine defined
              above.
    !*/

// ----------------------------------------------------------------------------------------

    unsigned long chinese_whispers (
        const std::vector<ordered_sample_pair>& edges,
        std::vector<unsigned long>& labels,
        const unsigned long num_iterations = 100
    );
    /*!
        requires
            - is_ordered_by_index(edges) == true
        ensures
            - performs: return chinese_whispers(edges, labels, num_iterations, rnd)
              where rnd is a default initialized dlib::rand object.
    !*/

// ----------------------------------------------------------------------------------------

    unsigned long chinese_whispers (
        const std::vector<sample_pair>& edges,
        std::vector<unsigned long>& labels,
        const unsigned long num_iterations = 100
    );
    /*!
        ensures
            - performs: return chinese_whispers(edges, labels, num_iterations, rnd)
              where rnd is a default initialized dlib::rand object.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_CHINESE_WHISPErS_ABSTRACT_Hh_


dlib C++ Library - kkmeans_abstract.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_KKMEANs_ABSTRACT_
#ifdef DLIB_KKMEANs_ABSTRACT_

#include <cmath>
#include "../matrix/matrix_abstract.h"
#include "../algs.h"
#include "../serialize.h"
#include "kernel_abstract.h"
#include "kcentroid_abstract.h"
#include "../noncopyable.h"

namespace dlib
{

    template <
        typename kernel_type
        >
    class kkmeans : public noncopyable
    {
        /*!
            REQUIREMENTS ON kernel_type
                is a kernel function object as defined in dlib/svm/kernel_abstract.h

            INITIAL VALUE
                - number_of_centers() == 1
                - get_min_change() == 0.01

            WHAT THIS OBJECT REPRESENTS
                This is an implementation of a kernelized k-means clustering algorithm.
                It performs k-means clustering by using the kcentroid object.
        !*/

    public:
        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;

        kkmeans (
            const kcentroid<kernel_type>& kc_
        );
        /*!
            ensures
                - #number_of_centers() == 1
                - #get_min_change() == 0.01
                - #get_kcentroid(0) == a copy of kc_
        !*/

        ~kkmeans(
        );
        /*!
            ensures
                - all resources associated with *this have been released
        !*/

        void set_kcentroid (
            const kcentroid<kernel_type>& kc_
        );
        /*!
            ensures
                - for all idx:
                    - #get_kcentroid(idx) == a copy of kc_
        !*/

        const kcentroid<kernel_type>& get_kcentroid (
            unsigned long i
        ) const;
        /*!
            requires
                - i < number_of_centers()
            ensures
                - returns a const reference to the ith kcentroid object contained in
                  this object.  Each kcentroid represents one of the centers found
                  by the k-means clustering algorithm.
        !*/

        const kernel_type& get_kernel (
        ) const;
        /*!
            ensures
                - returns a const reference to the kernel used by this object
        !*/

        void set_number_of_centers (
            unsigned long num
        );
        /*!
            requires
                - num > 0
            ensures
                - #number_of_centers() == num
        !*/

        unsigned long number_of_centers (
        ) const;
        /*!
            ensures
                - returns the number of centers used in this instance of the k-means clustering
                  algorithm.
        !*/

        template <
            typename matrix_type,
            typename matrix_type2
            >
        void train (
            const matrix_type& samples,
            const matrix_type2& initial_centers,
            long max_iter = 1000
        );
        /*!
            requires
                - matrix_type and matrix_type2 must either be dlib::matrix objects or convertible to dlib::matrix
                  via mat()
                - matrix_type::type == sample_type  (i.e. matrix_type should contain sample_type objects)
                - matrix_type2::type == sample_type (i.e. matrix_type2 should contain sample_type objects)
                - initial_centers.nc() == 1         (i.e. must be a column vector)
                - samples.nc() == 1                 (i.e. must be a column vector)
                - initial_centers.nr() == number_of_centers()
            ensures
                - performs k-means clustering of the given set of samples.  The initial center points
                  are taken from the initial_centers argument.
                - loops over the data and continues to refine the clustering until either less than
                  get_min_change() fraction of the data points change clusters or we have done max_iter
                  iterations over the data.
                - After this function finishes you can call the operator() function below
                  to determine which centroid a given sample is closest to.
        !*/

        unsigned long operator() (
            const sample_type& sample
        ) const;
        /*!
            ensures
                - returns a number idx such that:
                    - idx < number_of_centers()
                    - get_kcentroid(idx) == the centroid that is closest to the given
                      sample.
        !*/

        void set_min_change (
            scalar_type min_change
        );
        /*!
            requires
                - 0 <= min_change < 1
            ensures
                - #get_min_change() == min_change
        !*/

        const scalar_type get_min_change (
        ) const;
        /*!
            ensures
                - returns the minimum fraction of data points that need to change
                  centers in an iteration of kmeans for the algorithm to keep going.
        !*/

        void swap (
            kkmeans& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/
    };

// ----------------------------------------------------------------------------------------

    template <
        typename kernel_type
        >
    void swap(
        kkmeans<kernel_type>& a,
        kkmeans<kernel_type>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

    template <
        typename kernel_type
        >
    void serialize (
        const kkmeans<kernel_type>& item,
        std::ostream& out
    );
    /*!
        provides serialization support for kkmeans objects
    !*/

    template <
        typename kernel_type
        >
    void deserialize (
        kkmeans<kernel_type>& item,
        std::istream& in
    );
    /*!
        provides serialization support for kkmeans objects
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type1,
        typename vector_type2,
        typename kernel_type
        >
    void pick_initial_centers(
        long num_centers,
        vector_type1& centers,
        const vector_type2& samples,
        const kernel_type& k,
        double percentile = 0.01
    );
    /*!
        requires
            - num_centers > 1
            - 0 <= percentile < 1
            - samples.size() > 1
            - vector_type1 == something with an interface compatible with std::vector
            - vector_type2 == something with an interface compatible with std::vector
            - k(samples[0],samples[0]) must be a valid expression that returns a double
            - both centers and samples must be able to contain kernel_type::sample_type
              objects
        ensures
            - finds num_centers candidate cluster centers in the data in the samples
              vector.  Assumes that k is the kernel that will be used during clustering
              to define the space in which clustering occurs.
            - The centers are found by looking for points that are far away from other
              candidate centers.  However, if the data is noisy you probably want to
              ignore the farthest way points since they will be outliers.  To do this
              set percentile to the fraction of outliers you expect the data to contain.
            - #centers.size() == num_centers
            - #centers == a vector containing the candidate centers found
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type1,
        typename vector_type2
        >
    void pick_initial_centers(
        long num_centers,
        vector_type1& centers,
        const vector_type2& samples,
        double percentile = 0.01
    );
    /*!
        requires
            - num_centers > 1
            - 0 <= percentile < 1
            - samples.size() > 1
            - vector_type1 == something with an interface compatible with std::vector
            - vector_type2 == something with an interface compatible with std::vector
            - Both centers and samples must be able to contain dlib::matrix based row or
              column vectors.
        ensures
            - performs: pick_initial_centers(num_centers, centers, samples, linear_kernel<sample_type>(), percentile)
              (i.e. this function is simply an overload that uses the linear kernel.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename array_type,
        typename sample_type,
        typename alloc
        >
    void find_clusters_using_kmeans (
        const array_type& samples,
        std::vector<sample_type, alloc>& centers,
        unsigned long max_iter = 1000
    );
    /*!
        requires
            - samples.size() > 0
            - samples == a bunch of row or column vectors and they all must be of the
              same length.
            - centers.size() > 0
            - array_type == something with an interface compatible with std::vector
              and it must contain row or column vectors capable of being stored in
              sample_type objects.
            - sample_type == a dlib::matrix capable of representing vectors
        ensures
            - performs regular old linear kmeans clustering on the samples.  The clustering
              begins with the initial set of centers given as an argument to this function.
              When it finishes #centers will contain the resulting centers.
            - no more than max_iter iterations will be performed before this function
              terminates.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename array_type,
        typename sample_type,
        typename alloc
        >
    void find_clusters_using_angular_kmeans (
        const array_type& samples,
        std::vector<sample_type, alloc>& centers,
        unsigned long max_iter = 1000
    );
    /*!
        requires
            - samples.size() > 0
            - samples == a bunch of row or column vectors and they all must be of the
              same length.
            - centers.size() > 0
            - array_type == something with an interface compatible with std::vector
              and it must contain row or column vectors capable of being stored in
              sample_type objects.
            - sample_type == a dlib::matrix capable of representing vectors
        ensures
            - performs linear kmeans clustering on the samples, except instead of using
              Euclidean distance to compare samples to the centers it uses the angle
              between a sample and a center (with respect to the origin).  So we try to
              cluster samples together if they have small angles with respect to each
              other. The clustering begins with the initial set of centers given as an
              argument to this function.  When it finishes #centers will contain the
              resulting centers.
            - for all valid i:
                - length(#centers[i]) == 1
                  (i.e. the output centers are scaled to be unit vectors since their
                  magnitude is irrelevant.  Moreover, this makes it so you can use
                  functions like nearest_center() with #centers to find the cluster
                  assignments.)
            - No more than max_iter iterations will be performed before this function
              terminates.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename array_type,
        typename EXP
        >
    unsigned long nearest_center (
        const array_type& centers,
        const matrix_exp<EXP>& sample
    );
    /*!
        requires
            - centers.size() > 0
            - sample.size() > 0
            - is_vector(sample) == true
            - centers must be an array of vectors such that the following expression is
              valid: length_squared(sample - centers[0]).  (e.g. centers could be a
              std::vector of matrix objects holding column vectors).
        ensures
            - returns the index that identifies the element of centers that is nearest to
              sample.  That is, returns a number IDX such that centers[IDX] is the element
              of centers that minimizes length(centers[IDX]-sample).
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_KKMEANs_ABSTRACT_


dlib C++ Library - modularity_clustering_abstract.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_MODULARITY_ClUSTERING_ABSTRACT_Hh_
#ifdef DLIB_MODULARITY_ClUSTERING_ABSTRACT_Hh_

#include <vector>
#include "../graph_utils/ordered_sample_pair_abstract.h"
#include "../graph_utils/sample_pair_abstract.h"

namespace dlib
{

// -----------------------------------------------------------------------------------------

    double modularity (
        const std::vector<sample_pair>& edges,
        const std::vector<unsigned long>& labels
    );
    /*!
        requires
            - labels.size() == max_index_plus_one(edges)
            - for all valid i:
                - 0 <= edges[i].distance() < std::numeric_limits<double>::infinity()
        ensures
            - Interprets edges as an undirected graph.  That is, it contains the edges on
              the said graph and the sample_pair::distance() values define the edge weights
              (larger values indicating a stronger edge connection between the nodes).
            - This function returns the modularity value obtained when the given input
              graph is broken into subgraphs according to the contents of labels.  In
              particular, we say that two nodes with indices i and j are in the same
              subgraph or community if and only if labels[i] == labels[j].
            - Duplicate edges are interpreted as if there had been just one edge with a
              distance value equal to the sum of all the duplicate edge's distance values.
            - See the paper Modularity and community structure in networks by M. E. J. Newman
              for a detailed definition.
    !*/

// ----------------------------------------------------------------------------------------

    double modularity (
        const std::vector<ordered_sample_pair>& edges,
        const std::vector<unsigned long>& labels
    );
    /*!
        requires
            - labels.size() == max_index_plus_one(edges)
            - for all valid i:
                - 0 <= edges[i].distance() < std::numeric_limits<double>::infinity()
        ensures
            - Interprets edges as a directed graph.  That is, it contains the edges on the
              said graph and the ordered_sample_pair::distance() values define the edge
              weights (larger values indicating a stronger edge connection between the
              nodes).  Note that, generally, modularity is only really defined for
              undirected graphs.  Therefore, the "directed graph" given to this function
              should have symmetric edges between all nodes.  The reason this function is
              provided at all is because sometimes a vector of ordered_sample_pair objects
              is a useful representation of an undirected graph.
            - This function returns the modularity value obtained when the given input
              graph is broken into subgraphs according to the contents of labels.  In
              particular, we say that two nodes with indices i and j are in the same
              subgraph or community if and only if labels[i] == labels[j].
            - Duplicate edges are interpreted as if there had been just one edge with a
              distance value equal to the sum of all the duplicate edge's distance values.
            - See the paper Modularity and community structure in networks by M. E. J. Newman
              for a detailed definition.
    !*/

// ----------------------------------------------------------------------------------------

    unsigned long newman_cluster (
        const std::vector<ordered_sample_pair>& edges,
        std::vector<unsigned long>& labels,
        const double eps = 1e-4,
        const unsigned long max_iterations = 2000
    );
    /*!
        requires
            - is_ordered_by_index(edges) == true
            - for all valid i:
                - 0 <= edges[i].distance() < std::numeric_limits<double>::infinity()
        ensures
            - This function performs the clustering algorithm described in the paper
              Modularity and community structure in networks by M. E. J. Newman.
            - This function interprets edges as a graph and attempts to find the labeling
              that maximizes modularity(edges, #labels).
            - returns the number of clusters found.
            - #labels.size() == max_index_plus_one(edges)
            - for all valid i:
                - #labels[i] == the cluster ID of the node with index i in the graph.
                - 0 <= #labels[i] < the number of clusters found
                  (i.e. cluster IDs are assigned contiguously and start at 0)
            - The main computation of the algorithm is involved in finding an eigenvector
              of a certain matrix.  To do this, we use the power iteration.  In particular,
              each time we try to find an eigenvector we will let the power iteration loop
              at most max_iterations times or until it reaches an accuracy of eps.
              Whichever comes first.
    !*/

// ----------------------------------------------------------------------------------------

    unsigned long newman_cluster (
        const std::vector<sample_pair>& edges,
        std::vector<unsigned long>& labels,
        const double eps = 1e-4,
        const unsigned long max_iterations = 2000
    );
    /*!
        requires
            - for all valid i:
                - 0 <= edges[i].distance() < std::numeric_limits<double>::infinity()
        ensures
            - This function is identical to the above newman_cluster() routine except that
              it operates on a vector of sample_pair objects instead of
              ordered_sample_pairs.  Therefore, this is simply a convenience routine.  In
              particular, it is implemented by transforming the given edges into
              ordered_sample_pairs and then calling the newman_cluster() routine defined
              above.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MODULARITY_ClUSTERING_ABSTRACT_Hh_


dlib C++ Library - spectral_cluster_abstract.h

// Copyright (C) 2015  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SPECTRAL_CLUSTEr_ABSTRACT_H_
#ifdef DLIB_SPECTRAL_CLUSTEr_ABSTRACT_H_

#include <vector>

namespace dlib
{
    template <
        typename kernel_type,
        typename vector_type
        >
    std::vector<unsigned long> spectral_cluster (
        const kernel_type& k,
        const vector_type& samples,
        const unsigned long num_clusters
    );
    /*!
        requires
            - samples must be something with an interface compatible with std::vector.
            - The following expression must evaluate to a double or float:
                k(samples[i], samples[j])
            - num_clusters > 0
        ensures
            - Performs the spectral clustering algorithm described in the paper:
              On spectral clustering: Analysis and an algorithm by Ng, Jordan, and Weiss.
              and returns the results.
            - This function clusters the input data samples into num_clusters clusters and
              returns a vector that indicates which cluster each sample falls into.  In
              particular, we return an array A such that:
                - A.size() == samples.size()
                - A[i] == the cluster assignment of samples[i].
                - for all valid i: 0 <= A[i] < num_clusters
            - The "similarity" of samples[i] with samples[j] is given by
              k(samples[i],samples[j]).  This means that k() should output a number >= 0
              and the number should be larger for samples that are more similar.
    !*/
}

#endif // DLIB_SPECTRAL_CLUSTEr_ABSTRACT_H_


dlib C++ Library - cca_abstract.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_CCA_AbSTRACT_Hh_
#ifdef DLIB_CCA_AbSTRACT_Hh_

#include "../matrix/matrix_la_abstract.h"
#include "random_subset_selector_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    matrix<typename T::type,0,1> compute_correlations (
        const matrix_exp<T>& L,
        const matrix_exp<T>& R
    );
    /*!
        requires
            - L.size() > 0
            - R.size() > 0
            - L.nr() == R.nr()
        ensures
            - This function treats L and R as sequences of paired row vectors.  It
              then computes the correlation values between the elements of these
              row vectors.  In particular, we return a vector COR such that:
                - COR.size() == L.nc()
                - for all valid i:
                    - COR(i) == the correlation coefficient between the following sequence
                      of paired numbers: (L(k,i), R(k,i)) for k: 0 <= k < L.nr().
                      Therefore, COR(i) is a value between -1 and 1 inclusive where 1
                      indicates perfect correlation and -1 perfect anti-correlation.  Note
                      that this function assumes the input data vectors have been centered
                      (i.e. made to have zero mean).  If this is not the case then it will
                      report inaccurate results.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    matrix<T,0,1> cca (
        const matrix<T>& L,
        const matrix<T>& R,
        matrix<T>& Ltrans,
        matrix<T>& Rtrans,
        unsigned long num_correlations,
        unsigned long extra_rank = 5,
        unsigned long q = 2,
        double regularization = 0
    );
    /*!
        requires
            - num_correlations > 0
            - L.size() > 0
            - R.size() > 0
            - L.nr() == R.nr()
            - regularization >= 0
        ensures
            - This function performs a canonical correlation analysis between the row
              vectors in L and R.  That is, it finds two transformation matrices, Ltrans
              and Rtrans, such that row vectors in the transformed matrices L*Ltrans and
              R*Rtrans are as correlated as possible.  That is, we try to find two transforms
              such that the correlation values returned by compute_correlations(L*Ltrans, R*Rtrans)
              would be maximized.
            - Let N == min(num_correlations, min(R.nr(),min(L.nc(),R.nc())))
              (This is the actual number of elements in the transformed vectors.
              Therefore, note that you can't get more outputs than there are rows or
              columns in the input matrices.)
            - #Ltrans.nr() == L.nc()
            - #Ltrans.nc() == N
            - #Rtrans.nr() == R.nc()
            - #Rtrans.nc() == N
            - This function assumes the data vectors in L and R have already been centered
              (i.e. we assume the vectors have zero means).  However, in many cases it is
              fine to use uncentered data with cca().  But if it is important for your
              problem then you should center your data before passing it to cca().
            - This function works with reduced rank approximations of the L and R matrices.
              This makes it fast when working with large matrices.  In particular, we use
              the svd_fast() routine to find reduced rank representations of the input
              matrices by calling it as follows: svd_fast(L, U,D,V, num_correlations+extra_rank, q)
              and similarly for R.  This means that you can use the extra_rank and q
              arguments to cca() to influence the accuracy of the reduced rank
              approximation.  However, the default values should work fine for most
              problems.
            - returns an estimate of compute_correlations(L*#Ltrans, R*#Rtrans).  The
              returned vector should exactly match the output of compute_correlations()
              when the reduced rank approximation to L and R is accurate and regularization
              is set to 0.  However, if this is not the case then the return value of this
              function will deviate from compute_correlations(L*#Ltrans, R*#Rtrans).  This
              deviation can be used to check if the reduced rank approximation is working
              or you need to increase extra_rank.
            - The dimensions of the output vectors produced by L*#Ltrans or R*#Rtrans are
              ordered such that the dimensions with the highest correlations come first.
              That is, after applying the transforms produced by cca() to a set of vectors
              you will find that dimension 0 has the highest correlation, then dimension 1
              has the next highest, and so on.  This also means that the list of numbers
              returned from cca() will always be listed in decreasing order.
            - This function performs the ridge regression version of Canonical Correlation
              Analysis when regularization is set to a value > 0.  In particular, larger
              values indicate the solution should be more heavily regularized.  This can be
              useful when the dimensionality of the data is larger than the number of
              samples.
            - A good discussion of CCA can be found in the paper "Canonical Correlation
              Analysis" by David Weenink.  In particular, this function is implemented
              using equations 29 and 30 from his paper.  We also use the idea of doing CCA
              on a reduced rank approximation of L and R as suggested by Paramveer S.
              Dhillon in his paper "Two Step CCA: A new spectral method for estimating
              vector models of words".
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename sparse_vector_type,
        typename T
        >
    matrix<T,0,1> cca (
        const std::vector<sparse_vector_type>& L,
        const std::vector<sparse_vector_type>& R,
        matrix<T>& Ltrans,
        matrix<T>& Rtrans,
        unsigned long num_correlations,
        unsigned long extra_rank = 5,
        unsigned long q = 2,
        double regularization = 0
    );
    /*!
        requires
            - num_correlations > 0
            - L.size() == R.size()
            - max_index_plus_one(L) > 0 && max_index_plus_one(R) > 0
              (i.e. L and R can't represent empty matrices)
            - L and R must contain sparse vectors (see the top of dlib/svm/sparse_vector_abstract.h
              for a definition of sparse vector)
            - regularization >= 0
        ensures
            - This is just an overload of the cca() function defined above.  Except in this
              case we take a sparse representation of the input L and R matrices rather than
              dense matrices.  Therefore, in this case, we interpret L and R as matrices
              with L.size() rows, where each row is defined by a sparse vector.  So this
              function does exactly the same thing as the above cca().
            - Note that you can apply the output transforms to a sparse vector with the
              following code:
                sparse_matrix_vector_multiply(trans(Ltrans), your_sparse_vector)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename sparse_vector_type,
        typename Rand_type,
        typename T
        >
    matrix<T,0,1> cca (
        const random_subset_selector<sparse_vector_type,Rand_type>& L,
        const random_subset_selector<sparse_vector_type,Rand_type>& R,
        matrix<T>& Ltrans,
        matrix<T>& Rtrans,
        unsigned long num_correlations,
        unsigned long extra_rank = 5,
        unsigned long q = 2,
        double regularization = 0
    );
    /*!
        requires
            - num_correlations > 0
            - L.size() == R.size()
            - max_index_plus_one(L) > 0 && max_index_plus_one(R) > 0
              (i.e. L and R can't represent empty matrices)
            - L and R must contain sparse vectors (see the top of dlib/svm/sparse_vector_abstract.h
              for a definition of sparse vector)
            - regularization >= 0
        ensures
            - returns cca(L.to_std_vector(), R.to_std_vector(), Ltrans, Rtrans, num_correlations, extra_rank, q)
              (i.e. this is just a convenience function for calling the cca() routine when
              your sparse vectors are contained inside a random_subset_selector rather than
              a std::vector)
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_CCA_AbSTRACT_Hh_


dlib C++ Library - empirical_kernel_map_abstract.h

// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_EMPIRICAL_KERNEl_MAP_ABSTRACT_H_
#ifdef DLIB_EMPIRICAL_KERNEl_MAP_ABSTRACT_H_

#include <vector>
#include "../matrix.h"
#include "kernel_abstract.h"
#include "function_abstract.h"
#include "linearly_independent_subset_finder_abstract.h"
#include <vector>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename kernel_type,
        typename EXP
        >
    const decision_function<kernel_type> convert_to_decision_function (
        const projection_function<kernel_type>& project_funct,
        const matrix_exp<EXP>& vect
    );
    /*!
        requires
            - is_vector(vect) == true
            - vect.size() == project_funct.out_vector_size()
            - project_funct.out_vector_size() > 0
            - project_funct.weights.nc() == project_funct.basis_vectors.size()
        ensures
            - This function interprets the given vector as a point in the kernel feature space defined
              by the given projection function.  The return value of this function is a decision
              function, DF, that represents the given vector in the following sense:
                - for all possible sample_type objects, S, it is the case that DF(S) == dot(project_funct(S), vect)
                  (i.e. the returned decision function computes dot products, in kernel feature space,
                  between vect and any argument you give it.  Note also that this equality is exact, even
                  for sample_type objects not in the span of the basis_vectors.)
                - DF.kernel_function == project_funct.kernel_function
                - DF.b == 0
                - DF.basis_vectors == project_funct.basis_vectors.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename kern_type
        >
    class empirical_kernel_map
    {
        /*!
            REQUIREMENTS ON kern_type
                - must be a kernel function object as defined in dlib/svm/kernel_abstract.h

            INITIAL VALUE
                - out_vector_size() == 0
                - basis_size() == 0

            WHAT THIS OBJECT REPRESENTS
                This object represents a map from objects of sample_type (the kind of object
                a kernel function operates on) to finite dimensional column vectors which
                represent points in the kernel feature space defined by whatever kernel
                is used with this object.

                To use the empirical_kernel_map you supply it with a particular kernel and a set of
                basis samples.  After that you can present it with new samples and it will project
                them into the part of kernel feature space spanned by your basis samples.

                This means the empirical_kernel_map is a tool you can use to very easily kernelize
                any algorithm that operates on column vectors.  All you have to do is select a
                set of basis samples and then use the empirical_kernel_map to project all your
                data points into the part of kernel feature space spanned by those basis samples.
                Then just run your normal algorithm on the output vectors and it will be effectively
                kernelized.

                Regarding methods to select a set of basis samples, if you are working with only a
                few thousand samples then you can just use all of them as basis samples.
                Alternatively, the linearly_independent_subset_finder often works well for
                selecting a basis set.  I also find that picking a random subset typically works
                well.

                The empirical kernel map is something that has been around in the kernel methods
                literature for a long time but is seemingly not well known.  Anyway, one of the
                best books on the subject is the following:
                    Learning with Kernels: Support Vector Machines, Regularization, Optimization,
                    and Beyond by Bernhard Schlkopf, Alexander J. Smola
                The authors discuss the empirical kernel map as well as many other interesting
                topics.
        !*/

    public:

        typedef kern_type kernel_type;
        typedef typename kernel_type::sample_type sample_type;
        typedef typename kernel_type::scalar_type scalar_type;
        typedef typename kernel_type::mem_manager_type mem_manager_type;

        struct empirical_kernel_map_error : public error;
        /*!
            This is an exception class used to indicate a failure to create a
            kernel map from data given by the user.
        !*/

        empirical_kernel_map (
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        void clear (
        );
        /*!
            ensures
                - this object has its initial value
        !*/

        template <typename T>
        void load(
            const kernel_type& kernel,
            const T& basis_samples
        );
        /*!
            requires
                - T must be a dlib::matrix type or something convertible to a matrix via mat()
                  (e.g. a std::vector)
                - is_vector(basis_samples) == true
                - basis_samples.size() > 0
                - kernel must be capable of operating on the elements of basis_samples.  That is,
                  expressions such as kernel(basis_samples(0), basis_samples(0)) should make sense.
            ensures
                - 0 < #out_vector_size() <= basis_samples.size()
                - #basis_size() == basis_samples.size()
                - #get_kernel() == kernel
                - This function constructs a map between normal sample_type objects and the
                  subspace of the kernel feature space defined by the given kernel and the
                  given set of basis samples.  So after this function has been called you
                  will be able to project sample_type objects into kernel feature space
                  and obtain the resulting vector as a regular column matrix.
                - The basis samples are loaded into this object in the order in which they
                  are stored in basis_samples.  That is:
                    - for all valid i: (*this)[i] == basis_samples(i)
            throws
                - empirical_kernel_map_error
                    This exception is thrown if we are unable to create a kernel map.
                    If this happens then this object will revert back to its initial value.
        !*/

        void load(
            const linearly_independent_subset_finder<kernel_type>& lisf
        );
        /*!
            ensures
                - #out_vector_size() == lisf.dictionary_size()
                - #basis_size() == lisf.dictionary_size()
                - #get_kernel() == lisf.get_kernel()
                - Uses the dictionary vectors from lisf as a basis set.  Thus, this function
                  constructs a map between normal sample_type objects and the subspace of
                  the kernel feature space defined by the given kernel and the given set
                  of basis samples.  So after this function has been called you will be
                  able to project sample_type objects into kernel feature space and obtain
                  the resulting vector as a regular column matrix.
                - The basis samples are loaded into this object in the order in which they
                  are stored in lisf.  That is:
                    - for all valid i: (*this)[i] == lisf[i]
            throws
                - empirical_kernel_map_error
                    This exception is thrown if we are unable to create a kernel map.
                    E.g.  if the lisf.size() == 0.
                    If this happens then this object will revert back to its initial value.
        !*/

        const kernel_type get_kernel (
        ) const;
        /*!
            requires
                - out_vector_size() != 0
            ensures
                - returns a copy of the kernel used by this object
        !*/

        long out_vector_size (
        ) const;
        /*!
            ensures
                - if (this object has been loaded with basis samples) then
                    - returns the dimensionality of the vectors output by the project() function.
                - else
                    - returns 0
        !*/

        unsigned long basis_size (
        ) const;
        /*!
            ensures
                - returns the number of basis vectors in projection_functions created
                  by this object.  This is also equal to the number of basis vectors
                  given to the load() function.
        !*/

        const sample_type& operator[] (
            unsigned long idx
        ) const;
        /*!
            requires
                - idx < basis_size()
            ensures
                - returns a const reference to the idx'th basis vector contained inside
                  this object.
        !*/

        const matrix<scalar_type,0,1,mem_manager_type>& project (
            const sample_type& sample
        ) const;
        /*!
            requires
                - out_vector_size() != 0
            ensures
                - takes the given sample and projects it into the kernel feature space
                  of out_vector_size() dimensions defined by this kernel map and
                  returns the resulting vector.
                - in more precise terms, this function returns a vector such that:
                    - The returned vector will contain out_vector_size() elements.
                    - for any sample_type object S, the following equality is approximately true:
                        - get_kernel()(sample,S) == dot(project(sample), project(S)).
                    - The approximation error in the above equality will be zero (within rounding error)
                      if both sample_type objects involved are within the span of the set of basis
                      samples given to the load() function.  If they are not then there will be some
                      approximation error.  Note that all the basis samples are always within their
                      own span.  So the equality is always exact for the samples given to the load()
                      function.
        !*/

        const matrix<scalar_type,0,1,mem_manager_type>& project (
            const sample_type& samp,
            scalar_type& projection_error
        ) const;
        /*!
            requires
                - out_vector_size() != 0
            ensures
                - This function returns project(samp)
                  (i.e. it returns the same thing as the above project() function)
                - #projection_error == the square of the distance between the point samp
                  gets projected onto and samp's true image in kernel feature space.
                  That is, this value is equal to:
                    pow(convert_to_distance_function(project(samp))(samp),2)
        !*/

        template <typename EXP>
        const decision_function<kernel_type> convert_to_decision_function (
            const matrix_exp<EXP>& vect
        ) const;
        /*!
            requires
                - is_vector(vect) == true
                - vect.size() == out_vector_size()
                - out_vector_size() != 0
            ensures
                - This function interprets the given vector as a point in the kernel feature space defined
                  by this empirical_kernel_map.  The return value of this function is a decision
                  function, DF, that represents the given vector in the following sense:
                    - for all possible sample_type objects, S, it is the case that DF(S) == dot(project(S), vect)
                      (i.e. the returned decision function computes dot products, in kernel feature space,
                      between vect and any argument you give it.  Note also that this equality is exact, even
                      for sample_type objects not in the span of the basis samples.)
                    - DF.kernel_function == get_kernel()
                    - DF.b == 0
                    - DF.basis_vectors == these will be the basis samples given to the previous call to load().  Note
                      that it is possible for there to be fewer basis_vectors than basis samples given to load().
                    - DF.basis_vectors.size() == basis_size()
        !*/

        template <typename EXP>
        const distance_function<kernel_type> convert_to_distance_function (
            const matrix_exp<EXP>& vect
        ) const
        /*!
            requires
                - is_vector(vect) == true
                - vect.size() == out_vector_size()
                - out_vector_size() != 0
            ensures
                - This function interprets the given vector as a point in the kernel feature space defined
                  by this empirical_kernel_map.  The return value of this function is a distance
                  function, DF, that represents the given vector in the following sense:
                    - for any sample_type object S, the following equality is approximately true:
                        - DF(S) == length(project(S) - vect)
                          (i.e. the returned distance function computes distances, in kernel feature space,
                          between vect and any argument you give it. )
                    - The approximation error in the above equality will be zero (within rounding error)
                      if S is within the span of the set of basis samples given to the load() function.
                      If it is not then there will be some approximation error.  Note that all the basis
                      samples are always within their own span.  So the equality is always exact for the
                      samples given to the load() function.  Note further that the distance computed
                      by DF(S) is always the correct distance in kernel feature space between vect and
                      the true projection of S.  That is, the above equality is approximate only because
                      of potential error in the project() function, not in DF(S).
                    - DF.kernel_function == get_kernel()
                    - DF.b == dot(vect,vect)
                    - DF.basis_vectors == these will be the basis samples given to the previous call to load().  Note
                      that it is possible for there to be fewer basis_vectors than basis samples given to load().
                    - DF.basis_vectors.size() == basis_size()
        !*/

        const projection_function<kernel_type> get_projection_function (
        ) const;
        /*!
            requires
                - out_vector_size() != 0
            ensures
                - returns a projection_function, PF, that computes the same projection as project().
                  That is, calling PF() on any sample will produce the same output vector as calling
                  this->project() on that sample.
                - PF.basis_vectors.size() == basis_size()
        !*/

        const matrix<scalar_type,0,0,mem_manager_type> get_transformation_to (
            const empirical_kernel_map& target
        ) const;
        /*!
            requires
                - get_kernel() == target.get_kernel()
                - out_vector_size() != 0
                - target.out_vector_size() != 0
            ensures
                - A point in the kernel feature space defined by the kernel get_kernel() typically
                  has different representations with respect to different empirical_kernel_maps.
                  This function lets you obtain a transformation matrix that will allow you
                  to project between these different representations. That is, this function returns
                  a matrix M with the following properties:
                    - M maps vectors represented according to *this into the representation used by target.
                    - M.nr() == target.out_vector_size()
                    - M.nc() == this->out_vector_size()
                    - Let V be a vector of this->out_vector_size() length.  Then define two distance_functions
                      DF1 = this->convert_to_distance_function(V)
                      DF2 = target.convert_to_distance_function(M*V)

                      Then DF1(DF2) == 0 // i.e. the distance between these two points should be 0

                      That is, DF1 and DF2 both represent the same point in kernel feature space.  Note
                      that the above equality is only approximate.  If the vector V represents a point in
                      kernel space that isn't in the span of the basis samples used by target then the
                      equality is approximate.  However, if it is in their span then the equality will
                      be exact.  For example, if target's basis samples are a superset of the basis samples
                      used by *this then the equality will always be exact (within rounding error).
        !*/

        void get_transformation_to (
            const empirical_kernel_map& target,
            matrix<scalar_type, 0, 0, mem_manager_type>& tmat,
            projection_function<kernel_type>& partial_projection
        ) const;
        /*!
            requires
                - get_kernel() == target.get_kernel()
                - out_vector_size() != 0
                - target.out_vector_size() != 0
                - basis_size() < target.basis_size()
                - for all i < basis_size(): (*this)[i] == target[i]
                  i.e. target must contain a superset of the basis vectors contained in *this.  Moreover,
                  it must contain them in the same order.
            ensures
                - The single argument version of get_transformation_to() allows you to project
                  vectors from one empirical_kernel_map representation to another.  This version
                  provides a somewhat different capability.  Assuming target's basis vectors form a
                  superset of *this's basis vectors then this form of get_transformation_to() allows
                  you to reuse a vector from *this ekm to speed up the projection performed by target.
                  The defining relation is given below.
                - for any sample S:
                    - target.project(S) == #tmat * this->project(S) + #partial_projection(S)
                      (this is always true to within rounding error for any S)
                - #partial_projection.basis_vectors.size() == target.basis_vectors.size() - this->basis_vectors.size()
                - #tmat.nr() == target.out_vector_size()
                - #tmat.nc() == this->out_vector_size()
        !*/

        void swap (
            empirical_kernel_map& item
        );
        /*!
            ensures
                - swaps the state of *this and item
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <
        typename kernel_type
        >
    void swap (
        empirical_kernel_map<kernel_type>& a,
        empirical_kernel_map<kernel_type>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

    template <
        typename kernel_type
        >
    void serialize (
        const empirical_kernel_map<kernel_type>& item,
        std::ostream& out
    );
    /*!
        provides serialization support for empirical_kernel_map objects
    !*/

    template <
        typename kernel_type
        >
    void deserialize (
        empirical_kernel_map<kernel_type>& item,
        std::istream& in
    );
    /*!
        provides serialization support for empirical_kernel_map objects
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_EMPIRICAL_KERNEl_MAP_ABSTRACT_H_


dlib C++ Library - kcentroid_abstract.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_KCENTROId_ABSTRACT_
#ifdef DLIB_KCENTROId_ABSTRACT_

#include "../algs.h"
#include "../serialize.h"
#include "kernel_abstract.h"

namespace dlib
{

    template <
        typename kernel_type
        >
    class kcentroid
    {
        /*!
            REQUIREMENTS ON kernel_type
                is a kernel function object as defined in dlib/svm/kernel_abstract.h

            INITIAL VALUE
                - dictionary_size() == 0
                - samples_trained() == 0

            WHAT THIS OBJECT REPRESENTS
                This object represents a weighted sum of sample points in a kernel induced
                feature space.  It can be used to kernelize any algorithm that requires only
                the ability to perform vector addition, subtraction, scalar multiplication,
                and inner products.

                An example use of this object is as an online algorithm for recursively estimating
                the centroid of a sequence of training points.  This object then allows you to
                compute the distance between the centroid and any test points.  So you can use
                this object to predict how similar a test point is to the data this object has
                been trained on (larger distances from the centroid indicate dissimilarity/anomalous
                points).

                Also note that the algorithm internally keeps a set of "dictionary vectors"
                that are used to represent the centroid.  You can force the algorithm to use
                no more than a set number of vectors by setting the 3rd constructor argument
                to whatever you want.

                This object uses the sparsification technique described in the paper The
                Kernel Recursive Least Squares Algorithm by Yaakov Engel.  This technique
                allows us to keep the number of dictionary vectors down to a minimum.  In fact,
                the object has a user selectable tolerance parameter that controls the trade off
                between accuracy and number of stored dictionary vectors.
        !*/

    public:
        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;

        kcentroid (
        );
        /*!
            ensures
                - this object is properly initialized
                - #tolerance() == 0.001
                - #get_kernel() == kernel_type() (i.e. whatever the kernel's default value is)
                - #max_dictionary_size() == 1000000
                - #remove_oldest_first() == false
        !*/

        explicit kcentroid (
            const kernel_type& kernel_,
            scalar_type tolerance_ = 0.001,
            unsigned long max_dictionary_size_ = 1000000,
            bool remove_oldest_first_ = false
        );
        /*!
            requires
                - tolerance > 0
                - max_dictionary_size_ > 1
            ensures
                - this object is properly initialized
                - #tolerance() == tolerance_
                - #get_kernel() == kernel_
                - #max_dictionary_size() == max_dictionary_size_
                - #remove_oldest_first() == remove_oldest_first_
        !*/

        const kernel_type& get_kernel (
        ) const;
        /*!
            ensures
                - returns a const reference to the kernel used by this object
        !*/

        unsigned long max_dictionary_size(
        ) const;
        /*!
            ensures
                - returns the maximum number of dictionary vectors this object will
                  use at a time.  That is, dictionary_size() will never be greater
                  than max_dictionary_size().
        !*/

        bool remove_oldest_first (
        ) const;
        /*!
            ensures
                - When the maximum dictionary size is reached this object sometimes
                  needs to discard dictionary vectors when new samples are added via
                  one of the train functions.  When this happens this object chooses
                  the dictionary vector to discard based on the setting of the
                  remove_oldest_first() parameter.
                - if (remove_oldest_first() == true) then
                    - This object discards the oldest dictionary vectors when necessary.
                      This is an appropriate mode when using this object in an online
                      setting and the input training samples come from a slowly
                      varying distribution.
                - else (remove_oldest_first() == false) then
                    - This object discards the most linearly dependent dictionary vectors
                      when necessary.  This it the default behavior and should be used
                      in most cases.
        !*/

        unsigned long dictionary_size (
        ) const;
        /*!
            ensures
                - returns the number of basis vectors in the dictionary.  These are
                  the basis vectors used by this object to represent a point in kernel
                  feature space.
        !*/

        scalar_type samples_trained (
        ) const;
        /*!
            ensures
                - returns the number of samples this object has been trained on so far
        !*/

        scalar_type tolerance(
        ) const;
        /*!
            ensures
                - returns the tolerance to use for the approximately linearly dependent
                  test used for sparsification (see the KRLS paper for details).  This is
                  a number which governs how accurately this object will approximate the
                  centroid it is learning.  Smaller values generally result in a more
                  accurate estimate while also resulting in a bigger set of vectors in
                  the dictionary.  Bigger tolerances values result in a less accurate
                  estimate but also in less dictionary vectors.  (Note that in any case,
                  the max_dictionary_size() limits the number of dictionary vectors no
                  matter the setting of the tolerance)
                - The exact meaning of the tolerance parameter is the following:
                  Imagine that we have an empirical_kernel_map that contains all
                  the current dictionary vectors.  Then the tolerance is the minimum
                  projection error (as given by empirical_kernel_map::project()) required
                  to cause us to include a new vector in the dictionary.  So each time
                  you call train() the kcentroid basically just computes the projection
                  error for that new sample and if it is larger than the tolerance
                  then that new sample becomes part of the dictionary.
        !*/

        void clear_dictionary (
        );
        /*!
            ensures
                - clears out all learned data (e.g. #dictionary_size() == 0)
                - #samples_seen() == 0
        !*/

        scalar_type operator() (
            const kcentroid& x
        ) const;
        /*!
            requires
                - x.get_kernel() == get_kernel()
            ensures
                - returns the distance in kernel feature space between this centroid and the
                  centroid represented by x.
        !*/

        scalar_type operator() (
            const sample_type& x
        ) const;
        /*!
            ensures
                - returns the distance in kernel feature space between the sample x and the
                  current estimate of the centroid of the training samples given
                  to this object so far.
        !*/

        scalar_type inner_product (
            const sample_type& x
        ) const;
        /*!
            ensures
                - returns the inner product of the given x point and the current
                  estimate of the centroid of the training samples given to this object
                  so far.
        !*/

        scalar_type inner_product (
            const kcentroid& x
        ) const;
        /*!
            requires
                - x.get_kernel() == get_kernel()
            ensures
                - returns the inner product between x and this centroid object.
        !*/

        scalar_type squared_norm (
        ) const;
        /*!
            ensures
                - returns the squared norm of the centroid vector represented by this
                  object.  I.e. returns this->inner_product(*this)
        !*/

        void train (
            const sample_type& x
        );
        /*!
            ensures
                - adds the sample x into the current estimate of the centroid
                - also note that calling this function is equivalent to calling
                  train(x, samples_trained()/(samples_trained()+1.0, 1.0/(samples_trained()+1.0).
                  That is, this function finds the normal unweighted centroid of all training points.
        !*/

        void train (
            const sample_type& x,
            scalar_type cscale,
            scalar_type xscale
        );
        /*!
            ensures
                - adds the sample x into the current estimate of the centroid but
                  uses a user given scale.  That is, this function performs:
                    - new_centroid = cscale*old_centroid + xscale*x
                - This function allows you to weight different samples however
                  you want.
        !*/

        void scale_by (
            scalar_type cscale
        );
        /*!
            ensures
                - multiplies the current centroid vector by the given scale value.
                  This function is equivalent to calling train(some_x_value, cscale, 0).
                  So it performs:
                    - new_centroid == cscale*old_centroid
        !*/

        scalar_type test_and_train (
            const sample_type& x
        );
        /*!
            ensures
                - calls train(x)
                - returns (*this)(x)
                - The reason this function exists is because train() and operator()
                  both compute some of the same things.  So this function is more efficient
                  than calling both individually.
        !*/

        scalar_type test_and_train (
            const sample_type& x,
            scalar_type cscale,
            scalar_type xscale
        );
        /*!
            ensures
                - calls train(x,cscale,xscale)
                - returns (*this)(x)
                - The reason this function exists is because train() and operator()
                  both compute some of the same things.  So this function is more efficient
                  than calling both individually.
        !*/

        void swap (
            kcentroid& item
        );
        /*!
            ensures
                - swaps *this with item
        !*/

        distance_function<kernel_type> get_distance_function (
        ) const;
        /*!
            ensures
                - returns a distance function F that represents the point learned
                  by this object so far.  I.e. it is the case that:
                    - for all x: F(x) == (*this)(x)
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <
        typename kernel_type
        >
    void swap(
        kcentroid<kernel_type>& a,
        kcentroid<kernel_type>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

    template <
        typename kernel_type
        >
    void serialize (
        const kcentroid<kernel_type>& item,
        std::ostream& out
    );
    /*!
        provides serialization support for kcentroid objects
    !*/

    template <
        typename kernel_type
        >
    void deserialize (
        kcentroid<kernel_type>& item,
        std::istream& in
    );
    /*!
        provides serialization support for kcentroid objects
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_KCENTROId_ABSTRACT_


dlib C++ Library - linearly_independent_subset_finder_abstract.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_LISf_ABSTRACT_
#ifdef DLIB_LISf_ABSTRACT_

#include "../algs.h"
#include "../serialize.h"
#include "kernel_abstract.h"

namespace dlib
{

    template <
        typename kernel_type
        >
    class linearly_independent_subset_finder
    {
        /*!
            REQUIREMENTS ON kernel_type
                is a kernel function object as defined in dlib/svm/kernel_abstract.h

            INITIAL VALUE
                - size() == 0

            WHAT THIS OBJECT REPRESENTS
                This is an implementation of an online algorithm for recursively finding a
                set (aka dictionary) of linearly independent vectors in a kernel induced
                feature space.  To use it you decide how large you would like the dictionary
                to be and then you feed it sample points.

                The implementation uses the Approximately Linearly Dependent metric described
                in the paper The Kernel Recursive Least Squares Algorithm by Yaakov Engel to
                decide which points are more linearly independent than others.  The metric is
                simply the squared distance between a test point and the subspace spanned by
                the set of dictionary vectors.

                Each time you present this object with a new sample point (via this->add())
                it calculates the projection distance and if it is sufficiently large then this
                new point is included into the dictionary.  Note that this object can be configured
                to have a maximum size.  Once the max dictionary size is reached each new point
                kicks out a previous point.  This is done by removing the dictionary vector that
                has the smallest projection distance onto the others.  That is, the "least linearly
                independent" vector is removed to make room for the new one.
        !*/

    public:
        typedef typename kernel_type::scalar_type scalar_type;
        typedef typename kernel_type::sample_type sample_type;
        typedef typename kernel_type::sample_type type;
        typedef typename kernel_type::mem_manager_type mem_manager_type;

        linearly_independent_subset_finder (
        );
        /*!
            ensures
                - #minimum_tolerance() == 0.001
                - this object is properly initialized
                - #get_kernel() == kernel_type()  (i.e. whatever the default is for the supplied kernel)
                - #max_dictionary_size() == 100
        !*/

        linearly_independent_subset_finder (
            const kernel_type& kernel_,
            unsigned long max_dictionary_size_,
            scalar_type min_tolerance = 0.001
        );
        /*!
            requires
                - min_tolerance > 0
                - max_dictionary_size > 1
            ensures
                - #minimum_tolerance() == min_tolerance
                - this object is properly initialized
                - #get_kernel() == kernel_
                - #max_dictionary_size() == max_dictionary_size_
        !*/

        const kernel_type& get_kernel (
        ) const;
        /*!
            ensures
                - returns a const reference to the kernel used by this object
        !*/

        unsigned long max_dictionary_size(
        ) const;
        /*!
            ensures
                - returns the maximum number of dictionary vectors this object
                  will accumulate.  That is, size() will never be
                  greater than max_dictionary_size().
        !*/

        scalar_type minimum_tolerance(
        ) const;
        /*!
            ensures
                - returns the minimum projection error necessary to include a sample point
                  into the dictionary.
        !*/

        void set_minimum_tolerance (
            scalar_type min_tolerance
        );
        /*!
            requires
                - min_tolerance > 0
            ensures
                - #minimum_tolerance() == min_tolerance
        !*/

        void clear_dictionary (
        );
        /*!
            ensures
                - clears out all the data (e.g. #size() == 0)
        !*/

        bool add (
            const sample_type& x
        );
        /*!
            ensures
                - if (size() < max_dictionary_size() then
                    - if (projection_error(x) > minimum_tolerance()) then
                        - adds x into the dictionary
                        - (*this)[#size()-1] == x
                        - #size() == size() + 1
                        - returns true
                    - else
                        - the dictionary is not changed
                        - returns false
                - else
                    - #size() == size()
                      (i.e. the number of vectors in this object doesn't change)
                    - since the dictionary is full adding a new element means we have to
                      remove one of the current ones.  So let proj_error[i] be equal to the
                      projection error obtained when projecting dictionary vector (*this)[i]
                      onto the other elements of the dictionary.  Then let min_proj_error
                      be equal to the minimum value in proj_error.  The dictionary element
                      with the minimum projection error is the "least linearly independent"
                      vector in the dictionary and is the one which will be removed to make
                      room for a new element.
                    - if (projection_error(x) > minimum_tolerance() && projection_error(x) > min_proj_error)
                        - the least linearly independent vector in this object is removed
                        - adds x into the dictionary
                        - (*this)[#size()-1] == x
                        - returns true
                    - else
                        - the dictionary is not changed
                        - returns false
        !*/

        scalar_type projection_error (
            const sample_type& x
        ) const;
        /*!
            ensures
                - returns the squared distance between x and the subspace spanned by
                  the set of dictionary vectors.  (e.g. this is the same number that
                  gets returned by the empirical_kernel_map::project() function's
                  projection_error argument when the ekm is loaded with the dictionary
                  vectors.)
                - Note that if the dictionary is empty then the return value is
                  equal to get_kernel()(x,x).
        !*/

        void swap (
            linearly_independent_subset_finder& item
        );
        /*!
            ensures
                - swaps *this with item
        !*/

        unsigned long size (
        ) const;
        /*!
            ensures
                - returns the number of vectors in the dictionary.
        !*/

        const sample_type& operator[] (
            unsigned long index
        ) const;
        /*!
            requires
                - index < size()
            ensures
                - returns the index'th element in the set of linearly independent
                  vectors contained in this object.
        !*/

        const matrix<sample_type,0,1,mem_manager_type> get_dictionary (
        ) const;
        /*!
            ensures
                - returns a column vector that contains all the dictionary
                  vectors in this object.
        !*/

        const matrix<scalar_type,0,0,mem_manager_type>& get_kernel_matrix (
        ) const;
        /*!
            ensures
                - returns a matrix K such that:
                    - K.nr() == K.nc() == size()
                    - K == kernel_matrix(get_kernel(), get_dictionary())
                      i.e. K == the kernel matrix for the dictionary vectors
        !*/

        const matrix<scalar_type,0,0,mem_manager_type>& get_inv_kernel_marix (
        ) const;
        /*!
            ensures
                - if (size() != 0)
                    - returns inv(get_kernel_matrix())
                - else
                    - returns an empty matrix
        !*/
    };

// ----------------------------------------------------------------------------------------

    template <
        typename kernel_type
        >
    void swap(
        linearly_independent_subset_finder<kernel_type>& a,
        linearly_independent_subset_finder<kernel_type>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

    template <
        typename kernel_type
        >
    void serialize (
        const linearly_independent_subset_finder<kernel_type>& item,
        std::ostream& out
    );
    /*!
        provides serialization support for linearly_independent_subset_finder objects
    !*/

    template <
        typename kernel_type
        >
    void deserialize (
        linearly_independent_subset_finder<kernel_type>& item,
        std::istream& in
    );
    /*!
        provides serialization support for linearly_independent_subset_finder objects
    !*/

    template <
        typename T
        >
    const matrix_exp mat (
        const linearly_independent_subset_finder<T>& m
    );
    /*!
        ensures
            - converts m into a matrix
            - returns a matrix R such that:
                - is_col_vector(R) == true
                - R.size() == m.size()
                - for all valid r:
                  R(r) == m[r]
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename kernel_type,
        typename vector_type,
        typename rand_type
        >
    void fill_lisf (
        linearly_independent_subset_finder<kernel_type>& lisf,
        const vector_type& samples,
        rand_type& rnd,
        int sampling_size = 2000
    );
    /*!
        requires
            - vector_type == a dlib::matrix or something convertible to one via
              mat()
            - is_vector(mat(samples)) == true
            - rand_type == an implementation of rand/rand_kernel_abstract.h or a type
              convertible to a string via cast_to_string()
            - sampling_size > 0
        ensures
            - The purpose of this function is to fill lisf with points from samples.  It does
              this by randomly sampling elements of samples until no more can be added.  The
              precise stopping condition is when sampling_size additions to lisf have failed
              or the max dictionary size has been reached.
            - This function employs a random number generator.  If rand_type is a random
              number generator then it uses the instance given.  Otherwise it uses cast_to_string(rnd)
              to seed a new random number generator.
    !*/

    template <
        typename kernel_type,
        typename vector_type
        >
    void fill_lisf (
        linearly_independent_subset_finder<kernel_type>& lisf,
        const vector_type& samples
    );
    /*!
        requires
            - vector_type == a dlib::matrix or something convertible to one via
              mat()
            - is_vector(mat(samples)) == true
        ensures
            - performs fill_lisf(lisf, samples, default_rand_generator, 2000)
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_LISf_ABSTRACT_


dlib C++ Library - sammon_abstract.h

// Copyright (C) 2012  Emanuele Cesena (emanuele.cesena@gmail.com), Davis E. King
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SAMMoN_ABSTRACT_Hh_
#ifdef DLIB_SAMMoN_ABSTRACT_Hh_

#include "../matrix/matrix_abstract.h"
#include <vector>

namespace dlib
{

    class sammon_projection
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is a function object that computes the Sammon projection of a set
                of N points in a L-dimensional vector space onto a d-dimensional space
                (d < L), according to the paper:
                    A Nonlinear Mapping for Data Structure Analysis (1969) by J.W. Sammon

                The current implementation is a vectorized version of the original algorithm.
        !*/

    public:

        sammon_projection(
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        template <typename matrix_type>
        std::vector<matrix<double,0,1> > operator() (
            const std::vector<matrix_type>& data,
            const long num_dims
        );
        /*!
            requires
                - num_dims > 0
                - matrix_type should be a kind of dlib::matrix of doubles capable
                  of representing column vectors.
                - for all valid i:
                    - is_col_vector(data[i]) == true
                    - data[0].size() == data[i].size()
                      (i.e. all the vectors in data must have the same dimensionality)
                - if (data.size() != 0) then
                    - 0 < num_dims <= data[0].size()
                      (i.e. you can't project into a higher dimension than the input data,
                      only to a lower dimension.)
            ensures
                - This routine computes Sammon's dimensionality reduction method based on the
                  given input data.  It will attempt to project the contents of data into a
                  num_dims dimensional space that preserves relative distances between the
                  input data points.
                - This function returns a std::vector, OUT, such that:
                    - OUT == a set of column vectors that represent the Sammon projection of
                      the input data vectors.
                    - OUT.size() == data.size()
                    - for all valid i:
                        - OUT[i].size() == num_dims
                        - OUT[i] == the Sammon projection of the input vector data[i]
        !*/

        template <typename matrix_type>
        void operator() (
            const std::vector<matrix_type>& data,
            const long num_dims,
            std::vector<matrix<double,0,1> >& result,
            double &err,
            const unsigned long num_iters = 1000,
            const double err_delta = 1.0e-9
        );
        /*!
            requires
                - num_iters > 0
                - err_delta > 0
                - num_dims > 0
                - matrix_type should be a kind of dlib::matrix of doubles capable
                  of representing column vectors.
                - for all valid i:
                    - is_col_vector(data[i]) == true
                    - data[0].size() == data[i].size()
                      (i.e. all the vectors in data must have the same dimensionality)
                - if (data.size() != 0) then
                    - 0 < num_dims <= data[0].size()
                      (i.e. you can't project into a higher dimension than the input data,
                      only to a lower dimension.)
            ensures
                - This routine computes Sammon's dimensionality reduction method based on the
                  given input data.  It will attempt to project the contents of data into a
                  num_dims dimensional space that preserves relative distances between the
                  input data points.
                - #err == the final error value at the end of the algorithm.  The goal of Sammon's
                  algorithm is to find a lower dimensional projection of the input data that
                  preserves the relative distances between points.  The value in #err is a measure
                  of the total error at the end of the algorithm.  So smaller values indicate
                  a better projection was found than if a large value is returned via #err.
                - Sammon's algorithm will run until either num_iters iterations has executed
                  or the change in error from one iteration to the next is less than err_delta.
                - Upon completion, the output of Sammon's projection is stored into #result, in
                  particular, we will have:
                    - #result == a set of column vectors that represent the Sammon projection of
                      the input data vectors.
                    - #result.size() == data.size()
                    - for all valid i:
                        - #result[i].size() == num_dims
                        - #result[i] == the Sammon projection of the input vector data[i]
        !*/

    };

}

#endif // DLIB_SAMMoN_ABSTRACT_Hh_


dlib C++ Library - svm_one_class_trainer_abstract.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SVm_ONE_CLASS_TRAINER_ABSTRACT_
#ifdef DLIB_SVm_ONE_CLASS_TRAINER_ABSTRACT_

#include <cmath>
#include <limits>
#include "../matrix/matrix_abstract.h"
#include "../algs.h"
#include "function_abstract.h"
#include "kernel_abstract.h"
#include "../optimization/optimization_solve_qp3_using_smo_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename K
        >
    class svm_one_class_trainer
    {
        /*!
            REQUIREMENTS ON K
                is a kernel function object as defined in dlib/svm/kernel_abstract.h

            WHAT THIS OBJECT REPRESENTS
                This object implements a trainer for a support vector machine for
                solving one-class classification problems.  It is implemented using the SMO
                algorithm.

                The implementation of the training algorithm used by this object is based
                on the following excellent paper:
                    - Chih-Chung Chang and Chih-Jen Lin, LIBSVM : a library for support vector
                      machines, 2001. Software available at http://www.csie.ntu.edu.tw/~cjlin/libsvm

        !*/

    public:
        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 decision_function<kernel_type> trained_function_type;

        svm_one_class_trainer (
        );
        /*!
            ensures
                - This object is properly initialized and ready to be used
                  to train a support vector machine.
                - #get_nu() == 0.1
                - #get_cache_size() == 200
                - #get_epsilon() == 0.001
        !*/

        svm_one_class_trainer (
            const kernel_type& kernel,
            const scalar_type& nu
        );
        /*!
            requires
                - 0 < nu <= 1
            ensures
                - This object is properly initialized and ready to be used
                  to train a support vector machine.
                - #get_kernel() == kernel
                - #get_nu() == nu
                - #get_cache_size() == 200
                - #get_epsilon() == 0.001
        !*/

        void set_cache_size (
            long cache_size
        );
        /*!
            requires
                - cache_size > 0
            ensures
                - #get_cache_size() == cache_size
        !*/

        const long get_cache_size (
        ) const;
        /*!
            ensures
                - returns the number of megabytes of cache this object will use
                  when it performs training via the this->train() function.
                  (bigger values of this may make training go faster but won't affect
                  the result.  However, too big a value will cause you to run out of
                  memory, obviously.)
        !*/

        void set_epsilon (
            scalar_type eps
        );
        /*!
            requires
                - eps > 0
            ensures
                - #get_epsilon() == eps
        !*/

        const scalar_type get_epsilon (
        ) const;
        /*!
            ensures
                - returns the error epsilon that determines when training should stop.
                  Generally a good value for this is 0.001.  Smaller values may result
                  in a more accurate solution but take longer to execute.
        !*/

        void set_kernel (
            const kernel_type& k
        );
        /*!
            ensures
                - #get_kernel() == k
        !*/

        const kernel_type& get_kernel (
        ) const;
        /*!
            ensures
                - returns a copy of the kernel function in use by this object
        !*/

        void set_nu (
            scalar_type nu
        );
        /*!
            requires
                - 0 < nu <= 1
            ensures
                - #get_nu() == nu
        !*/

        const scalar_type get_nu (
        ) const;
        /*!
            ensures
                - returns the nu svm parameter.  This is a value between 0 and
                  1.  It is the parameter that determines the trade off between
                  trying to fit the training data exactly or allowing more errors
                  but hopefully improving the generalization ability of the
                  resulting classifier.  Smaller values encourage exact fitting
                  while larger values of nu may encourage better generalization.
                  For more information you should consult the papers referenced
                  above.
        !*/

        template <
            typename in_sample_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x
        ) const;
        /*!
            requires
                - x.size() > 0
                - is_col_vector(x) == true
                - x == a matrix or something convertible to a matrix via mat().
                  Also, x should contain sample_type objects.
            ensures
                - trains a one-class support vector classifier given the training samples in x.
                  Training is done when the error is less than get_epsilon().
                - returns a decision function F with the following properties:
                    - if (new_x is a sample predicted to arise from the distribution
                      which generated the training samples) then
                        - F(new_x) >= 0
                    - else
                        - F(new_x) < 0
        !*/

        void swap (
            svm_one_class_trainer& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/
    };

    template <typename K>
    void swap (
        svm_one_class_trainer<K>& a,
        svm_one_class_trainer<K>& b
    ) { a.swap(b); }
    /*!
        provides a global swap
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SVm_ONE_CLASS_TRAINER_ABSTRACT_


dlib C++ Library - lda_abstract.h

// Copyright (C) 2014  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_LDA_ABSTRACT_Hh_
#ifdef DLIB_LDA_ABSTRACT_Hh_

#include <map>
#include "../matrix.h"
#include <vector>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    void compute_lda_transform (
        matrix<T>& X,
        matrix<T,0,1>& M,
        const std::vector<unsigned long>& row_labels,
        unsigned long lda_dims = 500,
        unsigned long extra_pca_dims = 200
    );
    /*!
        requires
            - X.size() != 0
            - row_labels.size() == X.nr()
            - The number of distinct values in row_labels > 1
            - lda_dims != 0
        ensures
            - We interpret X as a collection X.nr() of input vectors, where each row of X
              is one of the vectors.
            - We interpret row_labels[i] as the label of the vector rowm(X,i).
            - This function performs the dimensionality reducing version of linear
              discriminant analysis.  That is, you give it a set of labeled vectors and it
              returns a linear transform that maps the input vectors into a new space that
              is good for distinguishing between the different classes.  In particular,
              this function finds matrices Z and M such that:
                - Given an input vector x, Z*x-M, is the transformed version of x.  That is,
                  Z*x-M maps x into a space where x vectors that share the same class label
                  are near each other.
                - Z*x-M results in the transformed vectors having zero expected mean.
                - Z.nr() <= lda_dims
                  (it might be less than lda_dims if there are not enough distinct class
                  labels to support lda_dims dimensions).
                - Z.nc() == X.nc()
                - We overwrite the input matrix X and store Z in it.  Therefore, the
                  outputs of this function are in X and M.
            - In order to deal with very high dimensional inputs, we perform PCA internally
              to map the input vectors into a space of at most lda_dims+extra_pca_dims
              prior to performing LDA.
    !*/

// ----------------------------------------------------------------------------------------

    std::pair<double,double> equal_error_rate (
        const std::vector<double>& low_vals,
        const std::vector<double>& high_vals
    );
    /*!
        ensures
            - This function finds a threshold T that best separates the elements of
              low_vals from high_vals by selecting the threshold with equal error rate.  In
              particular, we try to pick a threshold T such that:
                - for all valid i:
                    - high_vals[i] >= T
                - for all valid i:
                    - low_vals[i] < T
              Where the best T is determined such that the fraction of low_vals >= T is the
              same as the fraction of high_vals < T.
            - Let ERR == the equal error rate.  I.e. the fraction of times low_vals >= T
              and high_vals < T.  Note that 0 <= ERR <= 1.
            - returns make_pair(ERR,T)
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_LDA_ABSTRACT_Hh_


dlib C++ Library - dpca_abstract.h

// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_DPCA_ABSTRaCT_
#ifdef DLIB_DPCA_ABSTRaCT_

#include <limits>
#include <cmath>
#include "../matrix/matrix_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_type
        >
    class discriminant_pca
    {
        /*!
            REQUIREMENTS ON matrix_type
                Must be some type of dlib::matrix.

            INITIAL VALUE
                - in_vector_size() == 0
                - between_class_weight() == 1
                - within_class_weight() == 1

            WHAT THIS OBJECT REPRESENTS
                This object implements the Discriminant PCA technique described in the paper:
                    A New Discriminant Principal Component Analysis Method with Partial Supervision (2009)
                    by Dan Sun and Daoqiang Zhang

                This algorithm is basically a straightforward generalization of the classical PCA
                technique to handle partially labeled data.  It is useful if you want to learn a linear
                dimensionality reduction rule using a bunch of data that is partially labeled.

                It functions by estimating three different scatter matrices.  The first is the total scatter
                matrix St (i.e. the total data covariance matrix), the second is the between class scatter
                matrix Sb (basically a measure of the variance between data of different classes) and the
                third is the within class scatter matrix Sw (a measure of the variance of data within the
                same classes).

                Once these three matrices are estimated they are combined according to the following equation:
                   S = St + a*Sb - b*Sw
                Where a and b are user supplied weights.  Then the largest eigenvalues of the S matrix are
                computed and their associated eigenvectors are returned as the output of this algorithm.
                That is, the desired linear dimensionality reduction is given by the matrix with these
                eigenvectors stored in its rows.

                Note that if a and b are set to 0 (or no labeled data is provided) then the output transformation
                matrix is the same as the one produced by the classical PCA algorithm.
        !*/

    public:

        struct discriminant_pca_error : public error;
        /*!
            This exception is thrown if there is some error that prevents us from creating
            a DPCA matrix.
        !*/

        typedef typename matrix_type::mem_manager_type mem_manager_type;
        typedef typename matrix_type::type scalar_type;
        typedef typename matrix_type::layout_type layout_type;
        typedef matrix<scalar_type,0,0,mem_manager_type,layout_type> general_matrix;
        typedef matrix<scalar_type,0,1,mem_manager_type,layout_type> column_matrix;

        discriminant_pca (
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        void clear(
        );
        /*!
            ensures
                - #*this has its initial value
        !*/

        long in_vector_size (
        ) const;
        /*!
            ensures
                - if (this object has been presented with any input vectors) then
                    - returns the dimension of the column vectors used with this object
                - else
                    - returns 0
        !*/

        void set_within_class_weight (
            scalar_type weight
        );
        /*!
            requires
                - weight >= 0
            ensures
                - #within_class_weight() == weight
        !*/

        scalar_type within_class_weight (
        ) const;
        /*!
            ensures
                - returns the weight used when combining the within class scatter matrix with
                  the other scatter matrices.
        !*/

        void set_between_class_weight (
            scalar_type weight
        );
        /*!
            requires
                - weight >= 0
            ensures
                - #between_class_weight() == weight
        !*/

        scalar_type between_class_weight (
        ) const;
        /*!
            ensures
                - returns the weight used when combining the between class scatter matrix with
                  the other scatter matrices.
        !*/

        void add_to_within_class_variance(
            const matrix_exp& x,
            const matrix_exp& y
        );
        /*!
            requires
                - is_col_vector(x) == true
                - is_col_vector(y) == true
                - x.size() == y.size()
                - if (in_vector_size() != 0) then
                    - x.size() == y.size() == in_vector_size()
            ensures
                - #in_vector_size() == x.size()
                - Adds (x-y)*trans(x-y) to the within class scatter matrix.
                  (i.e. the direction given by (x-y) is recorded as being a direction associated
                  with within class variance and is therefore unimportant and will be weighted
                  less in the final dimensionality reduction)
        !*/

        void add_to_between_class_variance(
            const matrix_exp& x,
            const matrix_exp& y
        );
        /*!
            requires
                - is_col_vector(x) == true
                - is_col_vector(y) == true
                - x.size() == y.size()
                - if (in_vector_size() != 0) then
                    - x.size() == y.size() == in_vector_size()
            ensures
                - #in_vector_size() == x.size()
                - Adds (x-y)*trans(x-y) to the between class scatter matrix.
                  (i.e. the direction given by (x-y) is recorded as being a direction associated
                  with between class variance and is therefore important and will be weighted
                  higher in the final dimensionality reduction)
        !*/

        void add_to_total_variance(
            const matrix_exp& x
        );
        /*!
            requires
                - is_col_vector(x) == true
                - if (in_vector_size() != 0) then
                    - x.size() == in_vector_size()
            ensures
                - #in_vector_size() == x.size()
                - let M denote the centroid (or mean) of all the data.  Then this function
                  Adds (x-M)*trans(x-M) to the total scatter matrix.
                  (i.e. the direction given by (x-M) is recorded as being a direction associated
                  with unlabeled variance and is therefore of default importance and will be weighted
                  as described in the discriminant_pca class description.)
        !*/

        const general_matrix dpca_matrix (
            const double eps = 0.99
        ) const;
        /*!
            requires
                - 0 < eps <= 1
                - in_vector_size() != 0
                  (i.e. you have to have given this object some data)
            ensures
                - computes and returns the matrix MAT given by dpca_matrix(MAT,eigen,eps).
                  That is, this function returns the dpca_matrix computed by the function
                  defined below.
                - Note that MAT is the desired linear transformation matrix.  That is,
                  multiplying a vector by MAT performs the desired linear dimensionality reduction.
            throws
                - discriminant_pca_error
                    This exception is thrown if we are unable to create the dpca_matrix for some
                    reason.  For example, if only within class examples have been given or
                    within_class_weight() is very large then all eigenvalues will be negative and
                    that prevents this algorithm from working properly.
        !*/

        void dpca_matrix (
            general_matrix& dpca_mat,
            general_matrix& eigenvalues,
            const double eps = 0.99
        ) const;
        /*!
            requires
                - 0 < eps <= 1
                - in_vector_size() != 0
                  (i.e. you have to have given this object some data)
            ensures
                - is_col_vector(#eigenvalues) == true
                - #dpca_mat.nr() == eigenvalues.size()
                - #dpca_mat.nc() == in_vector_size()
                - rowm(#dpca_mat,i) represents the ith eigenvector of the S matrix described
                  in the class description and its eigenvalue is given by eigenvalues(i).
                - all values in #eigenvalues are > 0.  Moreover, the eigenvalues are in
                  sorted order with the largest eigenvalue stored at eigenvalues(0).
                - (#dpca_mat)*trans(#dpca_mat) == identity_matrix.
                  (i.e. the rows of the dpca_matrix are all unit length vectors and are mutually
                  orthogonal)
                - Note that #dpca_mat is the desired linear transformation matrix.  That is,
                  multiplying a vector by #dpca_mat performs the desired linear dimensionality
                  reduction.
                - sum(#eigenvalues) will be equal to about eps times the total sum of all
                  positive eigenvalues in the S matrix described in this class's description.
                  This means that eps is a number that controls how "lossy" the dimensionality
                  reduction will be.  Large values of eps result in more output dimensions
                  while smaller values result in fewer.
            throws
                - discriminant_pca_error
                    This exception is thrown if we are unable to create the dpca_matrix for some
                    reason.  For example, if only within class examples have been given or
                    within_class_weight() is very large then all eigenvalues will be negative and
                    that prevents this algorithm from working properly.
        !*/

        const general_matrix dpca_matrix_of_size (
            const long num_rows
        );
        /*!
            requires
                - 0 < num_rows <= in_vector_size()
            ensures
                - computes and returns the matrix MAT given by dpca_matrix_of_size(MAT,eigen,num_rows).
                  That is, this function returns the dpca_matrix computed by the function
                  defined below.
                - Note that MAT is the desired linear transformation matrix.  That is,
                  multiplying a vector by MAT performs the desired linear dimensionality
                  reduction to num_rows dimensions.
        !*/

        void dpca_matrix_of_size (
            general_matrix& dpca_mat,
            general_matrix& eigenvalues,
            const long num_rows
        );
        /*!
            requires
                - 0 < num_rows <= in_vector_size()
            ensures
                - is_col_vector(#eigenvalues) == true
                - #dpca_mat.nr() == eigenvalues.size()
                - #dpca_mat.nr() == num_rows
                - #dpca_mat.nc() == in_vector_size()
                - rowm(#dpca_mat,i) represents the ith eigenvector of the S matrix described
                  in the class description and its eigenvalue is given by eigenvalues(i).
                - The values in #eigenvalues might be positive or negative.  Additionally, the
                  eigenvalues are in sorted order with the largest eigenvalue stored at
                  eigenvalues(0).
                - (#dpca_mat)*trans(#dpca_mat) == identity_matrix.
                  (i.e. the rows of the dpca_matrix are all unit length vectors and are mutually
                  orthogonal)
                - Note that #dpca_mat is the desired linear transformation matrix.  That is,
                  multiplying a vector by #dpca_mat performs the desired linear dimensionality
                  reduction to num_rows dimensions.
        !*/

        discriminant_pca operator+ (
            const discriminant_pca& item
        ) const;
        /*!
            requires
                - in_vector_size() == 0 || item.in_vector_size() == 0 || in_vector_size() == item.in_vector_size()
                  (i.e. the in_vector_size() of *this and item must match or one must be zero)
                - between_class_weight() == item.between_class_weight()
                - within_class_weight() == item.within_class_weight()
            ensures
                - returns a new discriminant_pca object that represents the combination of all
                  the measurements given to *this and item.  That is, this function returns a
                  discriminant_pca object, R, that is equivalent to what you would obtain if all
                  modifying calls (e.g. the add_to_*() functions) to *this and item had instead
                  been done to R.
        !*/

        discriminant_pca& operator+= (
            const discriminant_pca& rhs
        );
        /*!
            requires
                - in_vector_size() == 0 || rhs.in_vector_size() == 0 || in_vector_size() == rhs.in_vector_size()
                  (i.e. the in_vector_size() of *this and rhs must match or one must be zero)
                - between_class_weight() == rhs.between_class_weight()
                - within_class_weight() == rhs.within_class_weight()
            ensures
                - #*this == *item + rhs
                - returns #*this
        !*/

        void swap (
            discriminant_pca& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_type
        >
    inline void swap (
        discriminant_pca<matrix_type>& a,
        discriminant_pca<matrix_type>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

    template <
        typename matrix_type,
        >
    void deserialize (
        discriminant_pca<matrix_type>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

    template <
        typename matrix_type,
        >
    void serialize (
        const discriminant_pca<matrix_type>& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_DPCA_ABSTRaCT_


dlib C++ Library - linear_manifold_regularizer_abstract.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_LINEAR_MANIFOLD_ReGULARIZER_ABSTRACT_Hh_
#ifdef DLIB_LINEAR_MANIFOLD_ReGULARIZER_ABSTRACT_Hh_

#include <limits>
#include <vector>
#include "../serialize.h"
#include "../matrix.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_type
        >
    class linear_manifold_regularizer
    {
        /*!
            REQUIREMENTS ON matrix_type
                Must be some type of dlib::matrix.

            INITIAL VALUE
                - dimensionality() == 0

            WHAT THIS OBJECT REPRESENTS
                Many learning algorithms attempt to minimize a function that, at a high
                level, looks like this:
                    f(w) == complexity + training_set_error

                The idea is to find the set of parameters, w, that gives low error on
                your training data but also is not "complex" according to some particular
                measure of complexity.  This strategy of penalizing complexity is
                usually called regularization.

                In the above setting, all the training data consists of labeled samples.
                However, it would be nice to be able to benefit from unlabeled data.
                The idea of manifold regularization is to extract useful information from
                unlabeled data by first defining which data samples are "close" to each other
                (perhaps by using their 3 nearest neighbors) and then adding a term to
                the above function that penalizes any decision rule which produces
                different outputs on data samples which we have designated as being close.

                It turns out that it is possible to transform these manifold regularized
                learning problems into the normal form shown above by applying a certain kind
                of preprocessing to all our data samples.  Once this is done we can use a
                normal learning algorithm, such as the svm_c_linear_trainer, on just the
                labeled data samples and obtain the same output as the manifold regularized
                learner would have produced.

                The linear_manifold_regularizer is a tool for creating this preprocessing
                transformation.  In particular, the transformation is linear.  That is, it
                is just a matrix you multiply with all your samples.  For a more detailed
                discussion of this topic you should consult the following paper.  In
                particular, see section 4.2.  This object computes the inverse T matrix
                described in that section.

                    Linear Manifold Regularization for Large Scale Semi-supervised Learning
                    by Vikas Sindhwani, Partha Niyogi, and Mikhail Belkin
        !*/

    public:
        typedef typename matrix_type::mem_manager_type mem_manager_type;
        typedef typename matrix_type::type scalar_type;
        typedef typename matrix_type::layout_type layout_type;
        typedef matrix<scalar_type,0,0,mem_manager_type,layout_type> general_matrix;

        template <
            typename vector_type1,
            typename vector_type2,
            typename weight_function_type
            >
        void build (
            const vector_type1& samples,
            const vector_type2& edges,
            const weight_function_type& weight_funct
        );
        /*!
            requires
                - vector_type1 == a type with an interface compatible with std::vector and it must
                  in turn contain dlib::matrix objects.
                - vector_type2 == a type with an interface compatible with std::vector and
                  it must in turn contain objects with an interface compatible with dlib::sample_pair
                - edges.size() > 0
                - contains_duplicate_pairs(edges) == false
                - max_index_plus_one(edges) <= samples.size()
                - weight_funct(edges[i]) must be a valid expression that evaluates to a
                  floating point number >= 0
            ensures
                - #dimensionality() == samples[0].size()
                - This function sets up the transformation matrix describe above.  The manifold
                  regularization is done assuming that the samples are meant to be "close"
                  according to the graph defined by the given edges.  I.e:
                    - for all valid i:  samples[edges[i].index1()] is close to samples[edges[i].index2()].
                      How much we care about these two samples having similar outputs according
                      to the learned rule is given by weight_funct(edges[i]).  Bigger weights mean
                      we care more.
        !*/

        long dimensionality (
        ) const;
        /*!
            ensures
                - returns the number of rows and columns in the transformation matrix
                  produced by this object.
        !*/

        general_matrix get_transformation_matrix (
            scalar_type intrinsic_regularization_strength
        ) const;
        /*!
            requires
                - intrinsic_regularization_strength >= 0
            ensures
                - returns a matrix that represents the preprocessing transformation described above.
                - You must choose how important the manifold regularizer is relative to the basic
                  "don't be complex" regularizer described above.  The intrinsic_regularization_strength
                  is the parameter that controls this trade-off.  A large value of
                  intrinsic_regularization_strength means that more emphasis should be placed on
                  finding decision rules which produce the same output on similar samples.  On
                  the other hand, a small value would mean that we don't care much about the
                  manifold regularizer.  For example, using 0 will cause this function to return the
                  identity matrix.
                - The returned matrix will have dimensionality() rows and columns.
        !*/

    };

}

// ----------------------------------------------------------------------------------------

#endif // DLIB_LINEAR_MANIFOLD_ReGULARIZER_ABSTRACT_Hh_


dlib C++ Library - vector_normalizer_frobmetric_abstract.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_VECTOR_NORMALIZER_FRoBMETRIC_ABSTRACT_Hh_
#ifdef DLIB_VECTOR_NORMALIZER_FRoBMETRIC_ABSTRACT_Hh_

#include "../matrix.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_type
        >
    struct frobmetric_training_sample
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object represents a training data sample for the
                vector_normalizer_frobmetric object.  It defines a set of training triplets
                relative to a single anchor_vect vector.  That is, it specifies that the
                learned distance metric should satisfy num_triples() constraints which are,
                for all valid i and j:
                    length(T*anchor_vect-T*near_vects[i]) + 1 < length(T*anchor_vect - T*far_vects[j])
                for some appropriate linear transformation T which will be learned by
                vector_normalizer_frobmetric.
        !*/

        matrix_type anchor_vect;
        std::vector<matrix_type> near_vects;
        std::vector<matrix_type> far_vects;

        unsigned long num_triples (
        ) const { return near_vects.size() * far_vects.size(); }
        /*!
            ensures
                - returns the number of training triplets defined by this object.
        !*/

        void clear()
        /*!
            ensures
                - #near_vects.size() == 0
                - #far_vects.size() == 0
        !*/
    };

    template < typename matrix_type >
    void serialize(const frobmetric_training_sample<matrix_type>& item, std::ostream& out)
    template < typename matrix_type >
    void deserialize(frobmetric_training_sample<matrix_type>& item, std::istream& in)
    /*!
        provides serialisation support.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_type
        >
    class vector_normalizer_frobmetric
    {
        /*!
            REQUIREMENTS ON matrix_type
                - must be a dlib::matrix object capable of representing column
                  vectors

            INITIAL VALUE
                - in_vector_size() == 0
                - out_vector_size() == 0
                - get_epsilon() == 0.1
                - get_c() == 1
                - get_max_iterations() == 5000
                - This object is not verbose
                - uses_identity_matrix_prior() == false

            WHAT THIS OBJECT REPRESENTS
                This object is a tool for performing the FrobMetric distance metric
                learning algorithm described in the following paper:
                    A Scalable Dual Approach to Semidefinite Metric Learning
                    By Chunhua Shen, Junae Kim, Lei Wang, in CVPR 2011

                Therefore, this object is a tool that takes as input training triplets
                (anchor_vect, near, far) of vectors and attempts to learn a linear
                transformation T such that:
                    length(T*anchor_vect-T*near) + 1 < length(T*anchor_vect - T*far)
                That is, you give a bunch of anchor_vect vectors and for each anchor_vect
                you specify some vectors which should be near to it and some that should be
                far form it.  This object then tries to find a transformation matrix that
                makes the "near" vectors close to their anchors while the "far" vectors are
                farther away.

            THREAD SAFETY
                Note that this object contains a cached matrix object it uses
                to store intermediate results for normalization.  This avoids
                needing to reallocate it every time this object performs normalization
                but also makes it non-thread safe.  So make sure you don't share
                instances of this object between threads.
        !*/

    public:
        typedef typename matrix_type::mem_manager_type mem_manager_type;
        typedef typename matrix_type::type scalar_type;
        typedef matrix_type result_type;

        vector_normalizer_frobmetric (
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        bool uses_identity_matrix_prior (
        ) const;
        /*!
            ensures
                - Normally this object will try and find a matrix transform() that
                  minimizes sum(squared(transform())) but also fits the training data.
                  However, if #uses_identity_matrix_prior() == true then it will instead
                  try to find the transformation matrix that minimizes
                  sum(squared(identity_matrix()-transform())).  That is, it will try to
                  find the matrix most similar to the identity matrix that best fits the
                  training data.
        !*/

        void set_uses_identity_matrix_prior (
            bool use_prior
        );
        /*!
            ensures
                - #uses_identity_matrix_prior() == use_prior
        !*/

        void be_verbose(
        );
        /*!
            ensures
                - This object will print status messages to standard out so the user can
                  observe the progress of the train() routine.
        !*/

        void be_quiet (
        );
        /*!
            ensures
                - this object will not print anything to standard out.
        !*/

        void set_epsilon (
            double eps
        );
        /*!
            requires
                - eps > 0
            ensures
                - #get_epsilon() == eps
        !*/

        double get_epsilon (
        ) const;
        /*!
            ensures
                - returns the error epsilon that determines when training should stop.
                  Smaller values may result in a more accurate solution but take longer to
                  execute.
        !*/

        void set_c (
            double C
        );
        /*!
            requires
                - C > 0
            ensures
                - #set_c() == C
        !*/

        double get_c (
        ) const;
        /*!
            ensures
                - returns the regularization parameter.  It is the parameter that
                  determines the trade-off between trying to fit the training data exactly
                  or allowing more errors but hopefully improving the generalization of the
                  resulting distance metric.  Larger values encourage exact fitting while
                  smaller values of C may encourage better generalization.
        !*/

        void set_max_iterations (
            unsigned long max_iterations
        );
        /*!
            ensures
                - #get_max_iterations() == max_iterations
        !*/

        unsigned long get_max_iterations (
        ) const;
        /*!
            ensures
                - The train() routine uses an iterative numerical solver to find the best
                  distance metric.  This function returns the maximum allowable number of
                  iterations it will use before terminating.  Note that typically the
                  solver terminates prior to the max iteration count limit due to the error
                  dropping below get_epsilon().
        !*/

        void train (
            const std::vector<frobmetric_training_sample<matrix_type> >& samples
        );
        /*!
            requires
                - samples.size() != 0
                - All matrices inside samples (i.e. anchors and elements of near_vects and far_vects)
                  are column vectors with the same non-zero dimension.
                - All the vectors in samples contain finite values.
                - All elements of samples contain data, specifically, for all valid i:
                    - samples[i].num_triples() != 0
            ensures
                - learns a distance metric from the given training samples.  After train
                  finishes you can use this object's operator() to transform vectors
                  according to the learned distance metric.  In particular, we will have:
                    - #transform() == The linear transformation learned by the FrobMetric
                      learning procedure.
                    - #in_vector_size() == samples[0].anchor_vect.size()
                    - You can call (*this)(x) to transform a vector according to the learned
                      distance metric.  That is, it should generally be the case that:
                        - length((*this)(anchor_vect) - (*this)(near)) + 1 < length((*this)(anchor_vect) - (*this)(far))
                      for the anchor_vect, near, and far vectors in the training data.
                    - #transformed_means() == the mean of the input anchor_vect vectors
                      after being transformed by #transform()
        !*/

        long in_vector_size (
        ) const;
        /*!
            ensures
                - returns the number of rows that input vectors are required to contain if
                  they are to be normalized by this object.
        !*/

        long out_vector_size (
        ) const;
        /*!
            ensures
                - returns the number of rows in the normalized vectors that come out of
                  this object.
                - The value returned is always in_vector_size().  So out_vector_size() is
                  just provided to maintain interface consistency with other vector
                  normalizer objects.  That is, the transformations applied by this object
                  do not change the dimensionality of the vectors.
        !*/

        const matrix<scalar_type,0,1,mem_manager_type>& transformed_means (
        ) const;
        /*!
            ensures
                - returns a column vector V such that:
                    - V.size() == in_vector_size()
                    - V is a vector such that subtracting it from transformed vectors
                      results in them having an expected value of 0.  Therefore, it is
                      equal to transform() times the mean of the input anchor_vect vectors
                      given to train().
        !*/

        const matrix<scalar_type,0,0,mem_manager_type>& transform (
        ) const;
        /*!
            ensures
                - returns a copy of the transformation matrix we learned during the last
                  call to train().
                - The returned matrix is square and has in_vector_size() by in_vector_size()
                  dimensions.
        !*/

        const result_type& operator() (
            const matrix_type& x
        ) const;
        /*!
            requires
                - in_vector_size() != 0
                - in_vector_size() == x.size()
                - is_col_vector(x) == true
            ensures
                - returns a normalized version of x, call it Z, that has the following
                  properties:
                    - Z == The result of applying the linear transform we learned during
                      train() to the input vector x.
                    - Z == transform()*x-transformed_means()
                    - is_col_vector(Z) == true
                    - Z.size() == x.size()
                    - The expected value of each element of Z is 0.
        !*/
    };

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_type
        >
    void serialize (
        const vector_normalizer_frobmetric<matrix_type>& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_type
        >
    void deserialize (
        vector_normalizer_frobmetric<matrix_type>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_VECTOR_NORMALIZER_FRoBMETRIC_ABSTRACT_Hh_


dlib C++ Library - lspi_abstract.h

// Copyright (C) 2015  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_LSPI_ABSTRACT_Hh_
#ifdef DLIB_LSPI_ABSTRACT_Hh_

#include "approximate_linear_models_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    class lspi
    {
        /*!
            REQUIREMENTS ON feature_extractor
                feature_extractor should implement the example_feature_extractor interface
                defined at the top of dlib/control/approximate_linear_models_abstract.h

            WHAT THIS OBJECT REPRESENTS
                This object is an implementation of the reinforcement learning algorithm
                described in the following paper:
                    Lagoudakis, Michail G., and Ronald Parr. "Least-squares policy
                    iteration." The Journal of Machine Learning Research 4 (2003):
                    1107-1149.

                This means that it takes a bunch of training data in the form of
                process_samples and outputs a policy that hopefully performs well when run
                on the process that generated those samples.
        !*/

    public:
        typedef feature_extractor feature_extractor_type;
        typedef typename feature_extractor::state_type state_type;
        typedef typename feature_extractor::action_type action_type;

        explicit lspi(
            const feature_extractor& fe_
        );
        /*!
            ensures
                - #get_feature_extractor() == fe_
                - #get_lambda() == 0.01
                - #get_discount == 0.8
                - #get_epsilon() == 0.01
                - is not verbose
                - #get_max_iterations() == 100
        !*/

        lspi(
        );
        /*!
            ensures
                - #get_feature_extractor() == feature_extractor()
                  (i.e. it will have its default value)
                - #get_lambda() == 0.01
                - #get_discount == 0.8
                - #get_epsilon() == 0.01
                - is not verbose
                - #get_max_iterations() == 100
        !*/

        double get_discount (
        ) const;
        /*!
            ensures
                - returns the discount applied to the sum of rewards in the Bellman
                  equation.
        !*/

        void set_discount (
            double value
        );
        /*!
            requires
                - 0 < value <= 1
            ensures
                - #get_discount() == value
        !*/

        const feature_extractor& get_feature_extractor (
        ) const;
        /*!
            ensures
                - returns the feature extractor used by this object
        !*/

        void be_verbose (
        );
        /*!
            ensures
                - This object will print status messages to standard out so that a
                  user can observe the progress of the algorithm.
        !*/

        void be_quiet (
        );
        /*!
            ensures
                - this object will not print anything to standard out
        !*/

        void set_epsilon (
            double eps
        );
        /*!
            requires
                - eps > 0
            ensures
                - #get_epsilon() == eps
        !*/

        double get_epsilon (
        ) const;
        /*!
            ensures
                - returns the error epsilon that determines when training should stop.
                  Smaller values may result in a more accurate solution but take longer to
                  train.
        !*/

        void set_lambda (
            double lambda_
        );
        /*!
            requires
                - lambda >= 0
            ensures
                - #get_lambda() == lambda
        !*/

        double get_lambda (
        ) const;
        /*!
            ensures
                - returns the regularization parameter.  It is the parameter that
                  determines the trade off between trying to fit the training data
                  exactly or allowing more errors but hopefully improving the
                  generalization ability of the resulting function.  Smaller values
                  encourage exact fitting while larger values of lambda may encourage
                  better generalization.
        !*/

        void set_max_iterations (
            unsigned long max_iter
        );
        /*!
            ensures
                - #get_max_iterations() == max_iter
        !*/

        unsigned long get_max_iterations (
        );
        /*!
            ensures
                - returns the maximum number of iterations the SVM optimizer is allowed to
                  run before it is required to stop and return a result.
        !*/

        template <
            typename vector_type
            >
        policy<feature_extractor> train (
            const vector_type& samples
        ) const;
        /*!
            requires
                - samples.size() > 0
                - samples is something with an interface that looks like
                  std::vector<process_sample<feature_extractor>>.  That is, it should
                  be some kind of array of process_sample objects.
            ensures
                - Trains a policy based on the given data and returns the results.  The
                  idea is to find a policy that will obtain the largest possible reward
                  when run on the process that generated the samples.  In particular,
                  if the returned policy is P then:
                    - P(S) == the best action to take when in state S.
                    - if (feature_extractor::force_last_weight_to_1) then
                        - The last element of P.get_weights() is 1.
        !*/

    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_LSPI_ABSTRACT_Hh_


dlib C++ Library - feature_ranking_abstract.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_KERNEL_FEATURE_RANKINg_ABSTRACT_H_
#ifdef DLIB_KERNEL_FEATURE_RANKINg_ABSTRACT_H_

#include <vector>
#include <limits>

#include "svm_abstract.h"
#include "kcentroid_abstract.h"
#include "../is_kind.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename kernel_type,
        typename sample_matrix_type,
        typename label_matrix_type
        >
    matrix<typename kernel_type::scalar_type> rank_features (
        const kcentroid<kernel_type>& kc,
        const sample_matrix_type& samples,
        const label_matrix_type& labels,
        const long num_features = samples(0).nr()
    );
    /*!
        requires
            - sample_matrix_type == a matrix or something convertible to a matrix via mat()
            - label_matrix_type  == a matrix or something convertible to a matrix via mat()
            - is_binary_classification_problem(samples, labels) == true
            - kc.train(samples(0)) must be a valid expression.  This means that
              kc must use a kernel type that is capable of operating on the
              contents of the samples matrix
            - 0 < num_features <= samples(0).nr()
        ensures
            - Let Class1 denote the centroid of all the samples with labels that are < 0
            - Let Class2 denote the centroid of all the samples with labels that are > 0
            - finds a ranking of the features where the best features come first.  This
              function does this by computing the distance between the centroid of the Class1
              samples and the Class2 samples in kernel defined feature space.
              Good features are then ones that result in the biggest separation between
              the two centroids of Class1 and Class2.
            - Uses the kc object to compute the centroids of the two classes
            - returns a ranking matrix R where:
                - R.nr() == num_features
                - r.nc() == 2
                - R(i,0) == the index of the ith best feature according to our ranking.
                  (e.g. samples(n)(R(0,0)) is the best feature from sample(n) and
                   samples(n)(R(1,0)) is the second best, samples(n)(R(2,0)) the
                   third best and so on)
                - R(i,1) == a number that indicates how much separation exists between
                  the two centroids when features 0 through i are used.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename sample_matrix_type,
        typename label_matrix_type
        >
    double find_gamma_with_big_centroid_gap (
        const sample_matrix_type& samples,
        const label_matrix_type& labels,
        double initial_gamma = 0.1,
        unsigned long num_sv = 40
    );
    /*!
        requires
            - initial_gamma > 0
            - num_sv > 0
            - is_binary_classification_problem(samples, labels) == true
        ensures
            - This is a function that tries to pick a reasonable default value for the gamma
              parameter of the radial_basis_kernel.  It picks the parameter that gives the
              largest separation between the centroids, in kernel feature space, of two classes
              of data. It does this using the kcentroid object and it sets the kcentroid up
              to use num_sv dictionary vectors.
            - This function does a search for the best gamma and the search starts with
              the value given by initial_gamma.  Better initial guesses will give
              better results since the routine may get stuck in a local minima.
            - returns the value of gamma that results in the largest separation.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename sample_matrix_type,
        typename label_matrix_type
        >
    double verbose_find_gamma_with_big_centroid_gap (
        const sample_matrix_type& samples,
        const label_matrix_type& labels,
        double initial_gamma = 0.1,
        unsigned long num_sv = 40
    );
    /*!
        requires
            - initial_gamma > 0
            - num_sv > 0
            - is_binary_classification_problem(samples, labels) == true
        ensures
            - This function does the same exact thing as the above find_gamma_with_big_centroid_gap()
              except that it is also verbose in the sense that it will print status messages to
              standard out during its processing.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type
        >
    double compute_mean_squared_distance (
        const vector_type& samples
    );
    /*!
        requires
            - vector_type is something with an interface compatible with std::vector.
              Additionally, it must in turn contain dlib::matrix types which contain
              scalars such as float or double values.
            - for all valid i: is_vector(samples[i]) == true
        ensures
            - computes the average value of the squares of all the pairwise
              distances between every element of samples.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_KERNEL_FEATURE_RANKINg_ABSTRACT_H_


dlib C++ Library - active_learning_abstract.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_ACTIVE_LEARnING_ABSTRACT_Hh_
#ifdef DLIB_ACTIVE_LEARnING_ABSTRACT_Hh_

#include "svm_c_linear_dcd_trainer_abstract.h"
#include <vector>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    enum active_learning_mode
    {
        max_min_margin,
        ratio_margin
    };

// ----------------------------------------------------------------------------------------

    template <
        typename kernel_type,
        typename in_sample_vector_type,
        typename in_scalar_vector_type,
        typename in_sample_vector_type2
        >
    std::vector<unsigned long> rank_unlabeled_training_samples (
        const svm_c_linear_dcd_trainer<kernel_type>& trainer,
        const in_sample_vector_type& samples,
        const in_scalar_vector_type& labels,
        const in_sample_vector_type2& unlabeled_samples,
        const active_learning_mode mode = max_min_margin
    );
    /*!
        requires
            - if (samples.size() != 0) then
                - it must be legal to call trainer.train(samples, labels)
                - is_learning_problem(samples, labels) == true
            - unlabeled_samples must contain the same kind of vectors as samples.
            - unlabeled_samples, samples, and labels must be matrices or types of
              objects convertible to a matrix via mat().
            - is_vector(unlabeled_samples) == true
        ensures
            - Suppose that we wish to learn a binary classifier by calling
              trainer.train(samples, labels) but we are also interested in selecting one of
              the elements of unlabeled_samples to add to our training data.  Since doing
              this requires us to find out the label of the sample, a potentially tedious
              or expensive process, we would like to select the "best" element from
              unlabeled_samples for labeling.  The rank_unlabeled_training_samples()
              attempts to find this "best" element.  In particular, this function returns a
              ranked list of all the elements in unlabeled_samples such that that the
              "best" elements come first.
            - The method used by this function is described in the paper:
                Support Vector Machine Active Learning with Applications to Text Classification
                by Simon Tong and Daphne Koller
              In particular, this function implements the MaxMin Margin and Ratio Margin
              selection strategies described in the paper.  Moreover, the mode argument
              to this function selects which of these strategies is used.
            - returns a std::vector V such that:
                - V contains a list of all the indices from unlabeled_samples.  Moreover,
                  they are ordered so that the most useful samples come first.
                - V.size() == unlabeled_samples.size()
                - unlabeled_samples[V[0]] == The best sample to add into the training set.
                - unlabeled_samples[V[1]] == The second best sample to add into the training set.
                - unlabeled_samples[V[i]] == The i-th best sample to add into the training set.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_ACTIVE_LEARnING_ABSTRACT_Hh_


dlib C++ Library - sort_basis_vectors_abstract.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SORT_BASIS_VECTORs_ABSTRACT_Hh_
#ifdef DLIB_SORT_BASIS_VECTORs_ABSTRACT_Hh_

#include <vector>

#include "../matrix.h"
#include "../statistics.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename kernel_type,
        typename vect1_type,
        typename vect2_type,
        typename vect3_type
        >
    const std::vector<typename kernel_type::sample_type> sort_basis_vectors (
        const kernel_type& kern,
        const vect1_type& samples,
        const vect2_type& labels,
        const vect3_type& basis,
        double eps = 0.99
    );
    /*!
        requires
            - is_binary_classification_problem(samples, labels)
            - 0 < eps <= 1
            - basis.size() > 0
            - kernel_type is a kernel function object as defined in dlib/svm/kernel_abstract.h
              It must be capable of operating on the elements of samples and basis.
            - vect1_type == a matrix or something convertible to a matrix via mat()
            - vect2_type == a matrix or something convertible to a matrix via mat()
            - vect3_type == a matrix or something convertible to a matrix via mat()
        ensures
            - A kernel based learning method ultimately needs to select a set of basis functions
              represented by a particular choice of kernel and a set of basis vectors.
              sort_basis_vectors() attempts to order the elements of basis so that elements which are
              most useful in solving the binary classification problem defined by samples and
              labels come first.
            - In particular, this function returns a std::vector, SB, of sorted basis vectors such that:
                - 0 < SB.size() <= basis.size()
                - SB will contain elements from basis but they will have been sorted so that
                  the most useful elements come first (i.e. SB[0] is the most important).
                - eps notionally controls how big SB will be.  Bigger eps corresponds to a
                  bigger basis.  You can think of it like asking for eps percent of the
                  discriminating power from the input basis.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SORT_BASIS_VECTORs_ABSTRACT_Hh_


dlib C++ Library - average_precision_abstract.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_AVERAGE_PREcISION_ABSTRACT_Hh_
#ifdef DLIB_AVERAGE_PREcISION_ABSTRACT_Hh_

#include <vector>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename alloc
        >
    double average_precision (
        const std::vector<bool,alloc>& items,
        unsigned long missing_relevant_items = 0
    );
    /*!
        ensures
            - Interprets items as a list of relevant and non-relevant items in a response
              from an information retrieval system.  In particular, items with a true value
              are relevant and false items are non-relevant.  This function then returns
              the average precision of the ranking of the given items.  For, example, the
              ranking [true, true, true, true, false] would have an average precision of 1.
              On the other hand, the ranking of [true false false true] would have an
              average precision of 0.75 (because the first true has a precision of 1 and
              the second true has a precision of 0.5, giving an average of 0.75).
            - As a special case, if item contains no true elements then the average
              precision is considered to be 1.
            - Note that we use the interpolated precision.  That is, the interpolated
              precision at a recall value r is set to the maximum precision obtained at any
              higher recall value.  Or in other words, we interpolate the precision/recall
              curve so that precision is monotonically decreasing.  Therefore, the average
              precision value returned by this function is the area under this interpolated
              precision/recall curve.
            - This function will add in missing_relevant_items number of items with a
              precision of zero into the average value returned.  For example, the average
              precision of the ranking [true, true] if there are 2 missing relevant items
              is 0.5.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename alloc
        >
    double average_precision (
        const std::vector<std::pair<T,bool>,alloc>& items,
        unsigned long missing_relevant_items = 0
    );
    /*!
        ensures
            - this function is equivalent to copying the bool values from items into a
              std::vector<bool> and then calling the above average_precision() routine on
              it and returning the result.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_AVERAGE_PREcISION_ABSTRACT_Hh_


dlib C++ Library - cross_validate_assignment_trainer_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_CROSS_VALIDATE_ASSiGNEMNT_TRAINER_ABSTRACT_Hh_
#ifdef DLIB_CROSS_VALIDATE_ASSiGNEMNT_TRAINER_ABSTRACT_Hh_

#include <vector>
#include "../matrix.h"
#include "svm.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename assignment_function
        >
    double test_assignment_function (
        const assignment_function& assigner,
        const std::vector<typename assignment_function::sample_type>& samples,
        const std::vector<typename assignment_function::label_type>& labels
    );
    /*!
        requires
            - is_assignment_problem(samples, labels)
            - if (assigner.forces_assignment()) then
                - is_forced_assignment_problem(samples, labels)
            - assignment_function == an instantiation of the dlib::assignment_function
              template or an object with a compatible interface.
        ensures
            - Tests assigner against the given samples and labels and returns the fraction
              of assignments predicted correctly.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type
        >
    double cross_validate_assignment_trainer (
        const trainer_type& trainer,
        const std::vector<typename trainer_type::sample_type>& samples,
        const std::vector<typename trainer_type::label_type>& labels,
        const long folds
    );
    /*!
        requires
            - is_assignment_problem(samples, labels)
            - if (trainer.forces_assignment()) then
                - is_forced_assignment_problem(samples, labels)
            - 1 < folds <= samples.size()
            - trainer_type == dlib::structural_assignment_trainer or an object
              with a compatible interface.
        ensures
            - performs k-fold cross validation by using the given trainer to solve the
              given assignment learning problem for the given number of folds.  Each fold
              is tested using the output of the trainer and the fraction of assignments
              predicted correctly is returned.
            - The number of folds used is given by the folds argument.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_CROSS_VALIDATE_ASSiGNEMNT_TRAINER_ABSTRACT_Hh_


dlib C++ Library - cross_validate_graph_labeling_trainer_abstract.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_CROSS_VALIDATE_GRAPh_LABELING_TRAINER_ABSTRACT_Hh_
#ifdef DLIB_CROSS_VALIDATE_GRAPh_LABELING_TRAINER_ABSTRACT_Hh_

#include "../array/array_kernel_abstract.h"
#include <vector>
#include "../matrix/matrix_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename graph_labeler,
        typename graph_type
        >
    matrix<double,1,2> test_graph_labeling_function (
        const graph_labeler& labeler,
        const dlib::array<graph_type>& samples,
        const std::vector<std::vector<bool> >& labels
    );
    /*!
        requires
            - is_graph_labeling_problem(samples,labels) == true
            - graph_labeler == an object with an interface compatible with the
              dlib::graph_labeler object.
            - the following must be a valid expression: labeler(samples[0]);
        ensures
            - This function tests the accuracy of the given graph labeler against
              the sample graphs and their associated labels.  In particular, this
              function returns a matrix R such that:
                - R(0) == The fraction of nodes which are supposed to have a label of
                  true that are labeled as such by the labeler.
                - R(1) == The fraction of nodes which are supposed to have a label of
                  false that are labeled as such by the labeler.
              Therefore, if R is [1,1] then the labeler makes perfect predictions while
              an R of [0,0] indicates that it gets everything wrong.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename graph_labeler,
        typename graph_type
        >
    matrix<double,1,2> test_graph_labeling_function (
        const graph_labeler& labeler,
        const dlib::array<graph_type>& samples,
        const std::vector<std::vector<bool> >& labels,
        const std::vector<std::vector<double> >& losses
    );
    /*!
        requires
            - is_graph_labeling_problem(samples,labels) == true
            - graph_labeler == an object with an interface compatible with the
              dlib::graph_labeler object.
            - the following must be a valid expression: labeler(samples[0]);
            - if (losses.size() != 0) then
                - sizes_match(labels, losses) == true
                - all_values_are_nonnegative(losses) == true
        ensures
            - This overload of test_graph_labeling_function() does the same thing as the
              one defined above, except that instead of counting 1 for each labeling
              mistake, it weights each mistake according to the corresponding value in
              losses.  That is, instead of counting a value of 1 for making a mistake on
              samples[i].node(j), this routine counts a value of losses[i][j].  Under this
              interpretation, the loss values represent how useful it is to correctly label
              each node.  Therefore, the values returned represent fractions of overall
              labeling utility rather than raw labeling accuracy.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type,
        typename graph_type
        >
    matrix<double,1,2> cross_validate_graph_labeling_trainer (
        const trainer_type& trainer,
        const dlib::array<graph_type>& samples,
        const std::vector<std::vector<bool> >& labels,
        const long folds
    );
    /*!
        requires
            - is_graph_labeling_problem(samples,labels) == true
            - 1 < folds <= samples.size()
            - trainer_type == an object which trains some kind of graph labeler object
              (e.g. structural_graph_labeling_trainer)
        ensures
            - performs k-fold cross validation by using the given trainer to solve the
              given graph labeling problem for the given number of folds.  Each fold
              is tested using the output of the trainer and the average classification
              accuracy from all folds is returned.  In particular, this function returns
              a matrix R such that:
                - R(0) == The fraction of nodes which are supposed to have a label of
                  true that are labeled as such by the learned labeler.
                - R(1) == The fraction of nodes which are supposed to have a label of
                  false that are labeled as such by the learned labeler.
              Therefore, if R is [1,1] then the labeler makes perfect predictions while
              an R of [0,0] indicates that it gets everything wrong.
            - The number of folds used is given by the folds argument.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type,
        typename graph_type
        >
    matrix<double,1,2> cross_validate_graph_labeling_trainer (
        const trainer_type& trainer,
        const dlib::array<graph_type>& samples,
        const std::vector<std::vector<bool> >& labels,
        const std::vector<std::vector<double> >& losses,
        const long folds
    );
    /*!
        requires
            - is_graph_labeling_problem(samples,labels) == true
            - 1 < folds <= samples.size()
            - trainer_type == an object which trains some kind of graph labeler object
              (e.g. structural_graph_labeling_trainer)
            - if (losses.size() != 0) then
                - sizes_match(labels, losses) == true
                - all_values_are_nonnegative(losses) == true
        ensures
            - This overload of cross_validate_graph_labeling_trainer() does the same thing
              as the one defined above, except that instead of counting 1 for each labeling
              mistake, it weights each mistake according to the corresponding value in
              losses.  That is, instead of counting a value of 1 for making a mistake on
              samples[i].node(j), this routine counts a value of losses[i][j].  Under this
              interpretation, the loss values represent how useful it is to correctly label
              each node.  Therefore, the values returned represent fractions of overall
              labeling utility rather than raw labeling accuracy.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_CROSS_VALIDATE_GRAPh_LABELING_TRAINER_ABSTRACT_Hh_


dlib C++ Library - cross_validate_multiclass_trainer_abstract.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_CROSS_VALIDATE_MULTICLASS_TRaINER_ABSTRACT_Hh_
#ifdef DLIB_CROSS_VALIDATE_MULTICLASS_TRaINER_ABSTRACT_Hh_

#include <vector>
#include "../matrix.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename dec_funct_type,
        typename sample_type,
        typename label_type
        >
    const matrix<double> test_multiclass_decision_function (
        const dec_funct_type& dec_funct,
        const std::vector<sample_type>& x_test,
        const std::vector<label_type>& y_test
    );
    /*!
        requires
            - is_learning_problem(x_test, y_test)
            - dec_funct_type == some kind of multiclass decision function object
              (e.g. one_vs_one_decision_function)
        ensures
            - Tests dec_funct against the given samples in x_test and labels in y_test
              and returns a confusion matrix summarizing the results.
            - let L = dec_funct.get_labels().  Then the confusion matrix C returned
              by this function has the following properties.
                - C.nr() == C.nc() == L.size()
                - C(r,c) == the number of times a sample with label L(r) was predicted
                  to have a label of L(c)
            - Any samples with a y_test value not in L are ignored.  That is, samples
              with labels the decision function hasn't ever seen before are ignored.
    !*/

// ----------------------------------------------------------------------------------------

    class cross_validation_error : public dlib::error
    {
        /*!
            This is the exception class used by the cross_validate_multiclass_trainer()
            routine.
        !*/
    };

// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type,
        typename sample_type,
        typename label_type
        >
    const matrix<double> cross_validate_multiclass_trainer (
        const trainer_type& trainer,
        const std::vector<sample_type>& x,
        const std::vector<label_type>& y,
        const long folds
    );
    /*!
        requires
            - is_learning_problem(x,y)
            - 1 < folds <= x.size()
            - trainer_type == some kind of multiclass classification trainer object (e.g. one_vs_one_trainer)
        ensures
            - performs k-fold cross validation by using the given trainer to solve the
              given multiclass classification problem for the given number of folds.
              Each fold is tested using the output of the trainer and the confusion
              matrix from all folds is summed and returned.
            - The total confusion matrix is computed by running test_binary_decision_function()
              on each fold and summing its output.
            - The number of folds used is given by the folds argument.
            - let L = select_all_distinct_labels(y).  Then the confusion matrix C returned
              by this function has the following properties.
                - C.nr() == C.nc() == L.size()
                - C(r,c) == the number of times a sample with label L(r) was predicted
                  to have a label of L(c)

              Note that sum(C) might be slightly less than x.size().  This happens if the number of
              samples in a class is not an even multiple of folds.  This is because each fold has the
              same number of test samples in it and so if the number of samples in a class isn't a
              multiple of folds then a few are not tested.
        throws
            - cross_validation_error
              This exception is thrown if one of the classes has fewer samples than
              the number of requested folds.
    !*/

}

// ----------------------------------------------------------------------------------------

#endif // DLIB_CROSS_VALIDATE_MULTICLASS_TRaINER_ABSTRACT_Hh_


dlib C++ Library - cross_validate_object_detection_trainer_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_CROSS_VALIDATE_OBJECT_DETECTION_TRaINER_ABSTRACT_Hh_
#ifdef DLIB_CROSS_VALIDATE_OBJECT_DETECTION_TRaINER_ABSTRACT_Hh_

#include <vector>
#include "../matrix.h"
#include "../geometry.h"
#include "../image_processing/full_object_detection_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename object_detector_type,
        typename image_array_type
        >
    const matrix<double,1,3> test_object_detection_function (
        object_detector_type& detector,
        const image_array_type& images,
        const std::vector<std::vector<full_object_detection> >& truth_dets,
        const std::vector<std::vector<rectangle> >& ignore,
        const test_box_overlap& overlap_tester = test_box_overlap(),
        const double adjust_threshold = 0
    );
    /*!
        requires
            - is_learning_problem(images,truth_dets)
            - images.size() == ignore.size()
            - object_detector_type == some kind of object detector function object
              (e.g. object_detector)
            - image_array_type must be an implementation of dlib/array/array_kernel_abstract.h
              and it must contain objects which can be accepted by detector().
        ensures
            - Tests the given detector against the supplied object detection problem and
              returns the precision, recall, and average precision.  Note that the task is
              to predict, for each images[i], the set of object locations given by
              truth_dets[i].  Additionally, any detections on image[i] that match a box in
              ignore[i] are ignored.  That is, detections matching a box in ignore[i] do
              not count as a false alarm and similarly if any element of ignore[i] goes
              undetected it does not count as a missed detection.  So we say that ignore[i]
              contains a set of boxes that we "don't care" if they are detected or not.
            - In particular, returns a matrix M such that:
                - M(0) == the precision of the detector object.  This is a number
                  in the range [0,1] which measures the fraction of detector outputs
                  which correspond to a real target.  A value of 1 means the detector
                  never produces any false alarms while a value of 0 means it only
                  produces false alarms.
                - M(1) == the recall of the detector object.  This is a number in the
                  range [0,1] which measures the fraction of targets found by the
                  detector.  A value of 1 means the detector found all the targets
                  in truth_dets while a value of 0 means the detector didn't locate
                  any of the targets.
                - M(2) == the average precision of the detector object.  This is a number
                  in the range [0,1] which measures the overall quality of the detector.
                  We compute this by taking all the detections output by the detector and
                  ordering them in descending order of their detection scores.  Then we use
                  the average_precision() routine to score the ranked listing and store the
                  output into M(2).
                - This function considers a detector output D to match a rectangle T if and
                  only if overlap_tester(T,D) returns true.
                - Note that you can use the adjust_threshold argument to raise or lower the
                  detection threshold.  This value is passed into the identically named
                  argument to the detector object and therefore influences the number of
                  output detections.  It can be useful, for example, to lower the detection
                  threshold because it results in more detections being output by the
                  detector, and therefore provides more information in the ranking,
                  possibly raising the average precision.
    !*/

    template <
        typename object_detector_type,
        typename image_array_type
        >
    const matrix<double,1,3> test_object_detection_function (
        object_detector_type& detector,
        const image_array_type& images,
        const std::vector<std::vector<rectangle> >& truth_dets,
        const std::vector<std::vector<rectangle> >& ignore,
        const test_box_overlap& overlap_tester = test_box_overlap(),
        const double adjust_threshold = 0
    );
    /*!
        requires
            - All the requirements of the above test_object_detection_function() routine.
        ensures
            - converts all the rectangles in truth_dets into full_object_detection objects
              via full_object_detection's rectangle constructor.  Then invokes
              test_object_detection_function() on the full_object_detections and returns
              the results.
    !*/

    template <
        typename object_detector_type,
        typename image_array_type
        >
    const matrix<double,1,3> test_object_detection_function (
        object_detector_type& detector,
        const image_array_type& images,
        const std::vector<std::vector<rectangle> >& truth_dets,
        const test_box_overlap& overlap_tester = test_box_overlap(),
        const double adjust_threshold = 0
    );
    /*!
        requires
            - All the requirements of the above test_object_detection_function() routine.
        ensures
            - This function simply invokes test_object_detection_function() with all the
              given arguments and an empty set of ignore rectangles and returns the results.
    !*/

    template <
        typename object_detector_type,
        typename image_array_type
        >
    const matrix<double,1,3> test_object_detection_function (
        object_detector_type& detector,
        const image_array_type& images,
        const std::vector<std::vector<full_object_detection> >& truth_dets,
        const test_box_overlap& overlap_tester = test_box_overlap(),
        const double adjust_threshold = 0
    );
    /*!
        requires
            - All the requirements of the above test_object_detection_function() routine.
        ensures
            - This function simply invokes test_object_detection_function() with all the
              given arguments and an empty set of ignore rectangles and returns the results.
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type,
        typename image_array_type
        >
    const matrix<double,1,3> cross_validate_object_detection_trainer (
        const trainer_type& trainer,
        const image_array_type& images,
        const std::vector<std::vector<full_object_detection> >& truth_dets,
        const std::vector<std::vector<rectangle> >& ignore,
        const long folds,
        const test_box_overlap& overlap_tester = test_box_overlap(),
        const double adjust_threshold = 0
    );
    /*!
        requires
            - is_learning_problem(images,truth_dets)
            - images.size() == ignore.size()
            - 1 < folds <= images.size()
            - trainer_type == some kind of object detection trainer (e.g structural_object_detection_trainer)
            - image_array_type must be an implementation of dlib/array/array_kernel_abstract.h
              and it must contain objects which can be accepted by detector().
            - it is legal to call trainer.train(images, truth_dets)
        ensures
            - Performs k-fold cross-validation by using the given trainer to solve an
              object detection problem for the given number of folds.  Each fold is tested
              using the output of the trainer and a matrix summarizing the results is
              returned.  The matrix contains the precision, recall, and average
              precision of the trained detectors and is defined identically to the
              test_object_detection_function() routine defined at the top of this file.
    !*/

    template <
        typename trainer_type,
        typename image_array_type
        >
    const matrix<double,1,3> cross_validate_object_detection_trainer (
        const trainer_type& trainer,
        const image_array_type& images,
        const std::vector<std::vector<rectangle> >& truth_dets,
        const std::vector<std::vector<rectangle> >& ignore,
        const long folds,
        const test_box_overlap& overlap_tester = test_box_overlap(),
        const double adjust_threshold = 0
    );
    /*!
        requires
            - all the requirements of the above cross_validate_object_detection_trainer() routine.
        ensures
            - converts all the rectangles in truth_dets into full_object_detection objects
              via full_object_detection's rectangle constructor.  Then invokes
              cross_validate_object_detection_trainer() on the full_object_detections and
              returns the results.
    !*/

    template <
        typename trainer_type,
        typename image_array_type
        >
    const matrix<double,1,3> cross_validate_object_detection_trainer (
        const trainer_type& trainer,
        const image_array_type& images,
        const std::vector<std::vector<rectangle> >& truth_dets,
        const long folds,
        const test_box_overlap& overlap_tester = test_box_overlap(),
        const double adjust_threshold = 0
    );
    /*!
        requires
            - All the requirements of the above cross_validate_object_detection_trainer() routine.
        ensures
            - This function simply invokes cross_validate_object_detection_trainer() with all
              the given arguments and an empty set of ignore rectangles and returns the results.
    !*/

    template <
        typename trainer_type,
        typename image_array_type
        >
    const matrix<double,1,3> cross_validate_object_detection_trainer (
        const trainer_type& trainer,
        const image_array_type& images,
        const std::vector<std::vector<full_object_detection> >& truth_dets,
        const long folds,
        const test_box_overlap& overlap_tester = test_box_overlap(),
        const double adjust_threshold = 0
    );
    /*!
        requires
            - All the requirements of the above cross_validate_object_detection_trainer() routine.
        ensures
            - This function simply invokes cross_validate_object_detection_trainer() with all
              the given arguments and an empty set of ignore rectangles and returns the results.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_CROSS_VALIDATE_OBJECT_DETECTION_TRaINER_ABSTRACT_Hh_


dlib C++ Library - ranking_tools_abstract.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_RANKING_ToOLS_ABSTRACT_Hh_
#ifdef DLIB_RANKING_ToOLS_ABSTRACT_Hh_

#include "../algs.h"
#include "../matrix.h"
#include <vector>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    struct ranking_pair
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is used to contain a ranking example.  In particular, we say
                that a good ranking of T objects is one in which all the elements in
                this->relevant are ranked higher than the elements of this->nonrelevant.
                Therefore, ranking_pair objects are used to represent training examples for
                learning-to-rank tasks.
        !*/

        ranking_pair() {}
        /*!
            ensures
                - #relevant.size() == 0
                - #nonrelevant.size() == 0
        !*/

        ranking_pair(
            const std::vector<T>& r,
            const std::vector<T>& nr
        ) : relevant(r), nonrelevant(nr) {}
        /*!
            ensures
                - #relevant == r
                - #nonrelevant == nr
        !*/

        std::vector<T> relevant;
        std::vector<T> nonrelevant;
    };

    template <
        typename T
        >
    void serialize (
        const ranking_pair<T>& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

    template <
        typename T
        >
    void deserialize (
        ranking_pair<T>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    bool is_ranking_problem (
        const std::vector<ranking_pair<T> >& samples
    );
    /*!
        ensures
            - returns true if the data in samples represents a valid learning-to-rank
              learning problem.  That is, this function returns true if all of the
              following are true and false otherwise:
                - samples.size() > 0
                - for all valid i:
                    - samples[i].relevant.size() > 0
                    - samples[i].nonrelevant.size() > 0
                - if (is_matrix<T>::value == true) then
                    - All the elements of samples::nonrelevant and samples::relevant must
                      represent row or column vectors and they must be the same dimension.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    unsigned long max_index_plus_one (
        const ranking_pair<T>& item
    );
    /*!
        requires
            - T must be a dlib::matrix capable of storing column vectors or T must be a
              sparse vector type as defined in dlib/svm/sparse_vector_abstract.h.
        ensures
            - returns std::max(max_index_plus_one(item.relevant), max_index_plus_one(item.nonrelevant)).
              Therefore, this function can be used to find the dimensionality of the
              vectors stored in item.
    !*/

    template <
        typename T
        >
    unsigned long max_index_plus_one (
        const std::vector<ranking_pair<T> >& samples
    );
    /*!
        requires
            - T must be a dlib::matrix capable of storing column vectors or T must be a
              sparse vector type as defined in dlib/svm/sparse_vector_abstract.h.
        ensures
            - returns the maximum of max_index_plus_one(samples[i]) over all valid values
              of i.  Therefore, this function can be used to find the dimensionality of the
              vectors stored in samples
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    void 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
    );
    /*!
        requires
            - T objects must be copyable
            - T objects must be comparable via operator<
        ensures
            - This function counts how many times we see a y value greater than or equal to
              an x value.  This is done efficiently in O(n*log(n)) time via the use of
              quick sort.
            - #x_count.size() == x.size()
            - #y_count.size() == y.size()
            - for all valid i:
                - #x_count[i] == how many times a value in y was >= x[i].
            - for all valid j:
                - #y_count[j] == how many times a value in x was <= y[j].
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename ranking_function,
        typename T
        >
    matrix<double,1,2> test_ranking_function (
        const ranking_function& funct,
        const std::vector<ranking_pair<T> >& samples
    );
    /*!
        requires
            - is_ranking_problem(samples) == true
            - ranking_function == some kind of decision function object (e.g. decision_function)
        ensures
            - Tests the given ranking function on the supplied example ranking data and
              returns the fraction of ranking pair orderings predicted correctly.  This is
              a number in the range [0,1] where 0 means everything was incorrectly
              predicted while 1 means everything was correctly predicted.  This function
              also returns the mean average precision.
            - In particular, this function returns a matrix M summarizing the results.
              Specifically, it returns an M such that:
                - M(0) == the fraction of times that the following is true:
                    - funct(samples[k].relevant[i]) > funct(samples[k].nonrelevant[j])
                      (for all valid i,j,k)
                - M(1) == the mean average precision of the rankings induced by funct.
                  (Mean average precision is a number in the range 0 to 1.  Moreover, a
                  mean average precision of 1 means everything was correctly predicted
                  while smaller values indicate worse rankings.  See the documentation
                  for average_precision() for details of its computation.)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename ranking_function,
        typename T
        >
    matrix<double,1,2> test_ranking_function (
        const ranking_function& funct,
        const ranking_pair<T>& sample
    );
    /*!
        requires
            - is_ranking_problem(std::vector<ranking_pair<T> >(1, sample)) == true
            - ranking_function == some kind of decision function object (e.g. decision_function)
        ensures
            - This is just a convenience routine for calling the above
              test_ranking_function() routine.  That is, it just copies sample into a
              std::vector object and invokes the above test_ranking_function() routine.
              This means that calling this function is equivalent to invoking:
                return test_ranking_function(funct, std::vector<ranking_pair<T> >(1, sample));
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type,
        typename T
        >
    matrix<double,1,2> cross_validate_ranking_trainer (
        const trainer_type& trainer,
        const std::vector<ranking_pair<T> >& samples,
        const long folds
    );
    /*!
        requires
            - is_ranking_problem(samples) == true
            - 1 < folds <= samples.size()
            - trainer_type == some kind of ranking trainer object (e.g. svm_rank_trainer)
        ensures
            - Performs k-fold cross validation by using the given trainer to solve the
              given ranking problem for the given number of folds.  Each fold is tested
              using the output of the trainer and the average ranking accuracy as well as
              the mean average precision over the number of folds is returned.
            - The accuracy is computed the same way test_ranking_function() computes its
              accuracy.  Therefore, it is a number in the range [0,1] that represents the
              fraction of times a ranking pair's ordering was predicted correctly.  Similarly,
              the mean average precision is computed identically to test_ranking_function().
              In particular, this means that this function returns a matrix M such that:
                - M(0) == the ranking accuracy
                - M(1) == the mean average precision
            - The number of folds used is given by the folds argument.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_RANKING_ToOLS_ABSTRACT_Hh_


dlib C++ Library - cross_validate_regression_trainer_abstract.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_CROSS_VALIDATE_REGRESSION_TRaINER_ABSTRACT_Hh_
#ifdef DLIB_CROSS_VALIDATE_REGRESSION_TRaINER_ABSTRACT_Hh_

#include <vector>
#include "../matrix.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename reg_funct_type,
        typename sample_type,
        typename label_type
        >
    matrix<double,1,2>
    test_regression_function (
        const reg_funct_type& reg_funct,
        const std::vector<sample_type>& x_test,
        const std::vector<label_type>& y_test
    );
    /*!
        requires
            - is_learning_problem(x_test, y_test)
            - reg_funct_type == some kind of regression function object
              (e.g. a decision_function created by the svr_trainer )
        ensures
            - Tests reg_funct against the given samples in x_test and target values in
              y_test and returns a matrix M summarizing the results.  Specifically:
                - M(0) == the mean squared error.
                  The MSE is given by: sum over i: pow(reg_funct(x_test[i]) - y_test[i], 2.0)
                - M(1) == the R-squared value (i.e. the squared correlation between
                  reg_funct(x_test[i]) and y_test[i]).  This is a number between 0
                  and 1.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type,
        typename sample_type,
        typename label_type
        >
    matrix<double,1,2>
    cross_validate_regression_trainer (
        const trainer_type& trainer,
        const std::vector<sample_type>& x,
        const std::vector<label_type>& y,
        const long folds
    );
    /*!
        requires
            - is_learning_problem(x,y)
            - 1 < folds <= x.size()
            - trainer_type == some kind of regression trainer object (e.g. svr_trainer)
        ensures
            - Performs k-fold cross validation by using the given trainer to solve a
              regression problem for the given number of folds.  Each fold is tested using
              the output of the trainer.  A matrix M summarizing the results is returned.
              Specifically:
                - M(0) == the mean squared error.
                  The MSE is given by: sum over i: pow(reg_funct(x[i]) - y[i], 2.0)
                - M(1) == the R-squared value (i.e. the squared correlation between
                  a predicted y value and its true value).  This is a number between
                  0 and 1.
    !*/

}

// ----------------------------------------------------------------------------------------

#endif // DLIB_CROSS_VALIDATE_REGRESSION_TRaINER_ABSTRACT_Hh_


dlib C++ Library - cross_validate_sequence_labeler_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_CROSS_VALIDATE_SEQUENCE_LABeLER_ABSTRACT_Hh_
#ifdef DLIB_CROSS_VALIDATE_SEQUENCE_LABeLER_ABSTRACT_Hh_

#include <vector>
#include "../matrix.h"
#include "svm.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename sequence_labeler_type,
        typename sequence_type
        >
    const matrix<double> test_sequence_labeler (
        const sequence_labeler_type& labeler,
        const std::vector<sequence_type>& samples,
        const std::vector<std::vector<unsigned long> >& labels
    );
    /*!
        requires
            - is_sequence_labeling_problem(samples, labels)
            - sequence_labeler_type == dlib::sequence_labeler or an object with a
              compatible interface.
        ensures
            - Tests labeler against the given samples and labels and returns a confusion
              matrix summarizing the results.
            - The confusion matrix C returned by this function has the following properties.
                - C.nc() == labeler.num_labels()
                - C.nr() == labeler.num_labels()
                - C(T,P) == the number of times a sequence element with label T was predicted
                  to have a label of P.
            - Any samples with a label value >= labeler.num_labels() are ignored.  That
              is, samples with labels the labeler hasn't ever seen before are ignored.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type,
        typename sequence_type
        >
    const matrix<double> cross_validate_sequence_labeler (
        const trainer_type& trainer,
        const std::vector<sequence_type>& samples,
        const std::vector<std::vector<unsigned long> >& labels,
        const long folds
    );
    /*!
        requires
            - is_sequence_labeling_problem(samples, labels)
            - 1 < folds <= samples.size()
            - for all valid i and j: labels[i][j] < trainer.num_labels()
            - trainer_type == dlib::structural_sequence_labeling_trainer or an object
              with a compatible interface.
        ensures
            - performs k-fold cross validation by using the given trainer to solve the
              given sequence labeling problem for the given number of folds.  Each fold
              is tested using the output of the trainer and the confusion matrix from all
              folds is summed and returned.
            - The total confusion matrix is computed by running test_sequence_labeler()
              on each fold and summing its output.
            - The number of folds used is given by the folds argument.
            - The confusion matrix C returned by this function has the following properties.
                - C.nc() == trainer.num_labels()
                - C.nr() == trainer.num_labels()
                - C(T,P) == the number of times a sequence element with label T was predicted
                  to have a label of P.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_CROSS_VALIDATE_SEQUENCE_LABeLER_ABSTRACT_Hh_


dlib C++ Library - cross_validate_sequence_segmenter_abstract.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_CROSS_VALIDATE_SEQUENCE_sEGMENTER_ABSTRACT_Hh_
#ifdef DLIB_CROSS_VALIDATE_SEQUENCE_sEGMENTER_ABSTRACT_Hh_

#include "sequence_segmenter_abstract.h"
#include "../matrix.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename sequence_segmenter_type,
        typename sequence_type
        >
    const matrix<double,1,3> test_sequence_segmenter (
        const sequence_segmenter_type& segmenter,
        const std::vector<sequence_type>& samples,
        const std::vector<std::vector<std::pair<unsigned long,unsigned long> > >& segments
    );
    /*!
        requires
            - is_sequence_segmentation_problem(samples, segments) == true
            - sequence_segmenter_type == dlib::sequence_segmenter or an object with a
              compatible interface.
        ensures
            - Tests segmenter against the given samples and truth segments and returns the
              precision, recall, and F1-score obtained by the segmenter.  That is, the goal
              of the segmenter should be to predict segments[i] given samples[i] as input.
              The test_sequence_segmenter() routine therefore measures how well the
              segmenter is able to perform this task.
            - Returns a row matrix M with the following properties:
                - M(0) == The precision of the segmenter measured against the task of
                  detecting the segments of each sample.  This is a number in the range 0
                  to 1 and represents the fraction of segments output by the segmenter
                  which correspond to true segments for each sample.
                - M(1) == The recall of the segmenter measured against the task of
                  detecting the segments of each sample.  This is a number in the range 0
                  to 1 and represents the fraction of the true segments found by the
                  segmenter.
                - M(2) == The F1-score for the segmenter.  This is the harmonic mean of
                  M(0) and M(1).
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type,
        typename sequence_type
        >
    const matrix<double,1,3> cross_validate_sequence_segmenter (
        const trainer_type& trainer,
        const std::vector<sequence_type>& samples,
        const std::vector<std::vector<std::pair<unsigned long,unsigned long> > >& segments,
        const long folds
    );
    /*!
        requires
            - is_sequence_segmentation_problem(samples, segments) == true
            - 1 < folds <= samples.size()
            - trainer_type == dlib::structural_sequence_segmentation_trainer or an object
              with a compatible interface.
        ensures
            - Performs k-fold cross validation by using the given trainer to solve the
              given sequence segmentation problem for the given number of folds.  Each fold
              is tested using the output of the trainer and the results from all folds are
              summarized and returned.
            - This function returns the precision, recall, and F1-score for the trainer.
              In particular, the output is the same as the output from the
              test_sequence_segmenter() routine defined above.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_CROSS_VALIDATE_SEQUENCE_sEGMENTER_ABSTRACT_Hh_


dlib C++ Library - cross_validate_track_association_trainer_abstract.h

// Copyright (C) 2014  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_CROSS_VALIDATE_TRACK_ASSOCIATION_TrAINER_ABSTRACT_Hh_
#ifdef DLIB_CROSS_VALIDATE_TRACK_ASSOCIATION_TrAINER_ABSTRACT_Hh_

#include "structural_track_association_trainer_abstract.h"
#include "svm_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename track_association_function,
        typename detection_type,
        typename label_type
        >
    double test_track_association_function (
        const track_association_function& assoc,
        const std::vector<std::vector<std::vector<labeled_detection<detection_type,label_type> > > >& samples
    );
    /*!
        requires
            - is_track_association_problem(samples)
            - track_association_function == an instantiation of the dlib::track_association_function
              template or an object with a compatible interface.
        ensures
            - Tests assoc against the given samples and returns the fraction of detections
              which were correctly associated to their tracks.  That is, if assoc produces
              perfect tracks when used then this function returns a value of 1.  Similarly,
              if 5% of the detections were associated to the incorrect track then the
              return value is 0.05.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type,
        typename detection_type,
        typename label_type
        >
    double cross_validate_track_association_trainer (
        const trainer_type& trainer,
        const std::vector<std::vector<std::vector<labeled_detection<detection_type,label_type> > > >& samples,
        const long folds
    );
    /*!
        requires
            - is_track_association_problem(samples)
            - 1 < folds <= samples.size()
            - trainer_type == dlib::structural_track_association_trainer or an object with
              a compatible interface.
        ensures
            - Performs k-fold cross validation by using the given trainer to solve the
              given track association learning problem for the given number of folds.  Each
              fold is tested using the output of the trainer and the fraction of
              mis-associated detections is returned (i.e. this function returns the same
              measure of track association quality as test_track_association_function()).
            - The number of folds used is given by the folds argument.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_CROSS_VALIDATE_TRACK_ASSOCIATION_TrAINER_ABSTRACT_Hh_


dlib C++ Library - svm_threaded_abstract.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SVm_THREADED_ABSTRACT_
#ifdef DLIB_SVm_THREADED_ABSTRACT_

#include "../matrix/matrix_abstract.h"
#include "../algs.h"
#include "../svm.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type,
        typename in_sample_vector_type,
        typename in_scalar_vector_type
        >
    const matrix<typename trainer_type::scalar_type, 1, 2, typename trainer_type::mem_manager_type>
    cross_validate_trainer_threaded (
        const trainer_type& trainer,
        const in_sample_vector_type& x,
        const in_scalar_vector_type& y,
        const long folds,
        const long num_threads
    );
    /*!
        requires
            - is_binary_classification_problem(x,y) == true
            - 1 < folds <= std::min(sum(y>0),sum(y<0))
              (e.g. There must be at least as many examples of each class as there are folds)
            - trainer_type == some kind of trainer object (e.g. svm_nu_trainer)
            - num_threads > 0
            - It must be safe for multiple trainer objects to access the elements of x from
              multiple threads at the same time.  Note that all trainers and kernels in
              dlib are thread safe in this regard since they do not mutate the elements of x.
        ensures
            - performs k-fold cross validation by using the given trainer to solve the
              given binary classification problem for the given number of folds.
              Each fold is tested using the output of the trainer and the average
              classification accuracy from all folds is returned.
            - uses num_threads threads of execution in doing the cross validation.
            - The accuracy is returned in a row vector, let us call it R.  Both
              quantities in R are numbers between 0 and 1 which represent the fraction
              of examples correctly classified.  R(0) is the fraction of +1 examples
              correctly classified and R(1) is the fraction of -1 examples correctly
              classified.
            - The number of folds used is given by the folds argument.
        throws
            - any exceptions thrown by trainer.train()
            - std::bad_alloc
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SVm_THREADED_ABSTRACT_


dlib C++ Library - null_trainer_abstract.h

// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_NULL_TRAINERs_ABSTRACT_
#ifdef DLIB_NULL_TRAINERs_ABSTRACT_

#include "../algs.h"
#include "function_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename dec_funct_type
        >
    class null_trainer_type
    {
        /*!
            REQUIREMENTS ON dec_funct_type
                dec_funct_type can be any copyable type that provides the needed
                typedefs used below (e.g. kernel_type, scalar_type, etc.).

            WHAT THIS OBJECT REPRESENTS
                This object is a simple tool for turning a decision function
                into a trainer object that always returns the original decision
                function when you try to train with it.

                dlib contains a few "training post processing" algorithms (e.g.
                reduced() and reduced2()).  These tools take in a trainer object,
                tell it to perform training, and then they take the output decision
                function and do some kind of post processing to it.  The null_trainer_type
                object is useful because you can use it to run an already
                learned decision function through the training post processing
                algorithms by turning a decision function into a null_trainer_type
                and then giving it to a post processor.
        !*/

    public:
        typedef typename dec_funct_type::kernel_type kernel_type;
        typedef typename dec_funct_type::scalar_type scalar_type;
        typedef typename dec_funct_type::sample_type sample_type;
        typedef typename dec_funct_type::mem_manager_type mem_manager_type;
        typedef dec_funct_type trained_function_type;

        null_trainer_type (
        );
        /*!
            ensures
                - any call to this->train(x,y) will return a default initialized
                  dec_funct_type object.
        !*/

        null_trainer_type (
            const dec_funct_type& dec_funct
        );
        /*!
            ensures
                - any call to this->train(x,y) will always return a copy of
                  the given dec_funct object.
        !*/

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const dec_funct_type& train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y
        ) const;
        /*!
            ensures
                - returns a copy of the decision function object given to
                  this object's constructor.
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <
        typename dec_funct_type
        >
    const null_trainer_type<dec_funct_type> null_trainer (
        const dec_funct_type& dec_funct
    ) { return null_trainer_type<dec_funct_type>(dec_funct); }
    /*!
        ensures
            - returns a null_trainer_type object that has been instantiated with
              the given arguments.  That is, this function returns a null_trainer_type
              trainer that will return a copy of the given dec_funct object every time
              someone calls its train() function.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_NULL_TRAINERs_ABSTRACT_


dlib C++ Library - reduced_abstract.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_REDUCED_TRAINERs_ABSTRACT_
#ifdef DLIB_REDUCED_TRAINERs_ABSTRACT_

#include "../matrix.h"
#include "../algs.h"
#include "function_abstract.h"
#include "kernel_abstract.h"
#include "../optimization.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type
        >
    class reduced_decision_function_trainer
    {
        /*!
            REQUIREMENTS ON trainer_type
                - trainer_type == some kind of batch trainer object (e.g. svm_nu_trainer)

            WHAT THIS OBJECT REPRESENTS
                This object represents an implementation of a reduced set algorithm.
                This object acts as a post processor for anything that creates
                decision_function objects.  It wraps another trainer object and
                performs this reduced set post processing with the goal of
                representing the original decision function in a form that
                involves fewer basis vectors.
        !*/

    public:
        typedef typename trainer_type::kernel_type kernel_type;
        typedef typename trainer_type::scalar_type scalar_type;
        typedef typename trainer_type::sample_type sample_type;
        typedef typename trainer_type::mem_manager_type mem_manager_type;
        typedef typename trainer_type::trained_function_type trained_function_type;

        reduced_decision_function_trainer (
        );
        /*!
            ensures
                - This object is in an uninitialized state.  You must
                  construct a real one with the other constructor and assign it
                  to this instance before you use this object.
        !*/

        reduced_decision_function_trainer (
            const trainer_type& trainer,
            const unsigned long num_bv
        );
        /*!
            requires
                - num_bv > 0
            ensures
                - returns a trainer object that applies post processing to the decision_function
                  objects created by the given trainer object with the goal of creating
                  decision_function objects with fewer basis vectors.
                - The reduced decision functions that are output will have at most
                  num_bv basis vectors.
        !*/

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y
        ) const;
        /*!
            ensures
                - trains a decision_function using the trainer that was supplied to
                  this object's constructor and then finds a reduced representation
                  for it and returns the reduced version.
            throws
                - std::bad_alloc
                - any exceptions thrown by the trainer_type object
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type
        >
    const reduced_decision_function_trainer<trainer_type> reduced (
        const trainer_type& trainer,
        const unsigned long num_bv
    ) { return reduced_decision_function_trainer<trainer_type>(trainer, num_bv); }
    /*!
        requires
            - num_bv > 0
            - trainer_type == some kind of batch trainer object that creates decision_function
              objects (e.g. svm_nu_trainer)
        ensures
            - returns a reduced_decision_function_trainer object that has been
              instantiated with the given arguments.
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename K,
        typename stop_strategy_type,
        typename T
        >
    distance_function<K> approximate_distance_function (
        stop_strategy_type stop_strategy,
        const distance_function<K>& target,
        const T& starting_basis
    );
    /*!
        requires
            - stop_strategy == an object that defines a stop strategy such as one of
              the objects from dlib/optimization/optimization_stop_strategies_abstract.h
            - requirements on starting_basis
                - T must be a dlib::matrix type or something convertible to a matrix via mat()
                  (e.g. a std::vector).  Additionally, starting_basis must contain K::sample_type
                  objects which can be supplied to the kernel function used by target.
                - is_vector(starting_basis) == true
                - starting_basis.size() > 0
            - target.get_basis_vectors().size() > 0
            - kernel_derivative<K> is defined
              (i.e. The analytic derivative for the given kernel must be defined)
            - K::sample_type must be a dlib::matrix object and the basis_vectors inside target
              and starting_basis must be column vectors.
        ensures
            - This routine attempts to find a distance_function object which is close
              to the given target.  That is, it searches for an X such that target(X) is
              minimized.  The optimization begins with an X in the span of the elements
              of starting_basis and searches for an X which locally minimizes target(X).
              Since this problem can have many local minima, the quality of the starting
              basis can significantly influence the results.
            - The optimization is over all variables in a distance_function, however,
              the size of the basis set is constrained to no more than starting_basis.size().
              That is, in the returned distance_function DF, we will have:
                - DF.get_basis_vectors().size() <= starting_basis.size()
            - The optimization is carried out until the stop_strategy indicates it
              should stop.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type
        >
    class reduced_decision_function_trainer2
    {
        /*!
            REQUIREMENTS ON trainer_type
                - trainer_type == some kind of batch trainer object (e.g. svm_nu_trainer)
                - trainer_type::sample_type must be a dlib::matrix object
                - kernel_derivative<trainer_type::kernel_type> must be defined

            WHAT THIS OBJECT REPRESENTS
                This object represents an implementation of a reduced set algorithm.
                This object acts as a post processor for anything that creates
                decision_function objects.  It wraps another trainer object and
                performs this reduced set post processing with the goal of
                representing the original decision function in a form that
                involves fewer basis vectors.

                This object's implementation is the same as that in the above
                reduced_decision_function_trainer object except it also performs
                a global gradient based optimization at the end to further
                improve the approximation to the original decision function
                object.
        !*/

    public:
        typedef typename trainer_type::kernel_type kernel_type;
        typedef typename trainer_type::scalar_type scalar_type;
        typedef typename trainer_type::sample_type sample_type;
        typedef typename trainer_type::mem_manager_type mem_manager_type;
        typedef typename trainer_type::trained_function_type trained_function_type;

        reduced_decision_function_trainer2 (
        );
        /*!
            ensures
                - This object is in an uninitialized state.  You must
                  construct a real one with the other constructor and assign it
                  to this instance before you use this object.
        !*/

        reduced_decision_function_trainer2 (
            const trainer_type& trainer,
            const unsigned long num_bv,
            double eps = 1e-3
        );
        /*!
            requires
                - num_bv > 0
                - eps > 0
            ensures
                - returns a trainer object that applies post processing to the decision_function
                  objects created by the given trainer object with the goal of creating
                  decision_function objects with fewer basis vectors.
                - The reduced decision functions that are output will have at most
                  num_bv basis vectors.
                - the gradient based optimization will continue until the change in the
                  objective function is less than eps.  So smaller values of eps will
                  give better results but take longer to compute.
        !*/

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y
        ) const;
        /*!
            requires
                - x must be a list of objects which are each some kind of dlib::matrix
                  which represents column or row vectors.
            ensures
                - trains a decision_function using the trainer that was supplied to
                  this object's constructor and then finds a reduced representation
                  for it and returns the reduced version.
            throws
                - std::bad_alloc
                - any exceptions thrown by the trainer_type object
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type
        >
    const reduced_decision_function_trainer2<trainer_type> reduced2 (
        const trainer_type& trainer,
        const unsigned long num_bv,
        double eps = 1e-3
    ) { return reduced_decision_function_trainer2<trainer_type>(trainer, num_bv, eps); }
    /*!
        requires
            - num_bv > 0
            - trainer_type == some kind of batch trainer object that creates decision_function
              objects (e.g. svm_nu_trainer)
            - kernel_derivative<trainer_type::kernel_type> is defined
            - eps > 0
        ensures
            - returns a reduced_decision_function_trainer2 object that has been
              instantiated with the given arguments.
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

}

#endif // DLIB_REDUCED_TRAINERs_ABSTRACT_


dlib C++ Library - roc_trainer_abstract.h

// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_ROC_TRAINEr_ABSTRACT_
#ifdef DLIB_ROC_TRAINEr_ABSTRACT_

#include "../algs.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type
        >
    class roc_trainer_type
    {
        /*!
            REQUIREMENTS ON trainer_type
                - trainer_type == some kind of batch trainer object (e.g. svm_nu_trainer)

            WHAT THIS OBJECT REPRESENTS
                This object is a simple trainer post processor that allows you to
                easily adjust the bias term in a trained decision_function object.
                That is, this object lets you pick a point on the ROC curve and
                it will adjust the bias term appropriately.

                So for example, suppose you wanted to set the bias term so that
                the accuracy of your decision function on +1 labeled samples was 99%.
                To do this you would use an instance of this object declared as follows:
                    roc_trainer_type<trainer_type>(your_trainer, 0.99, +1);
        !*/

    public:
        typedef typename trainer_type::kernel_type kernel_type;
        typedef typename trainer_type::scalar_type scalar_type;
        typedef typename trainer_type::sample_type sample_type;
        typedef typename trainer_type::mem_manager_type mem_manager_type;
        typedef typename trainer_type::trained_function_type trained_function_type;

        roc_trainer_type (
        );
        /*!
            ensures
                - This object is in an uninitialized state.  You must
                  construct a real one with the other constructor and assign it
                  to this instance before you use this object.
        !*/

        roc_trainer_type (
            const trainer_type& trainer_,
            const scalar_type& desired_accuracy_,
            const scalar_type& class_selection_
        );
        /*!
            requires
                - 0 <= desired_accuracy_ <= 1
                - class_selection_ == +1 or -1
            ensures
                - when training is performed using this object it will automatically
                  adjust the bias term in the returned decision function so that it
                  achieves the desired accuracy on the selected class type.
        !*/

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const trained_function_type train (
            const in_sample_vector_type& samples,
            const in_scalar_vector_type& labels
        ) const
        /*!
            requires
                - is_binary_classification_problem(samples, labels) == true
                - x == a matrix or something convertible to a matrix via mat().
                  Also, x should contain sample_type objects.
                - y == a matrix or something convertible to a matrix via mat().
                  Also, y should contain scalar_type objects.
            ensures
                - performs training using the trainer object given to this object's
                  constructor, then modifies the bias term in the returned decision function
                  as discussed above, and finally returns the decision function.
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type
        >
    const roc_trainer_type<trainer_type> roc_c1_trainer (
        const trainer_type& trainer,
        const typename trainer_type::scalar_type& desired_accuracy
    ) { return roc_trainer_type<trainer_type>(trainer, desired_accuracy, +1); }
    /*!
        requires
            - 0 <= desired_accuracy <= 1
            - trainer_type == some kind of batch trainer object that creates decision_function
              objects (e.g. svm_nu_trainer)
        ensures
            - returns a roc_trainer_type object that has been instantiated with the given
              arguments.  The returned roc trainer will select the decision function
              bias that gives the desired accuracy with respect to the +1 class.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type
        >
    const roc_trainer_type<trainer_type> roc_c2_trainer (
        const trainer_type& trainer,
        const typename trainer_type::scalar_type& desired_accuracy
    ) { return roc_trainer_type<trainer_type>(trainer, desired_accuracy, -1); }
    /*!
        requires
            - 0 <= desired_accuracy <= 1
            - trainer_type == some kind of batch trainer object that creates decision_function
              objects (e.g. svm_nu_trainer)
        ensures
            - returns a roc_trainer_type object that has been instantiated with the given
              arguments.  The returned roc trainer will select the decision function
              bias that gives the desired accuracy with respect to the -1 class.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_ROC_TRAINEr_ABSTRACT_


dlib C++ Library - kernel_abstract.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SVm_KERNEL_ABSTRACT_
#ifdef DLIB_SVm_KERNEL_ABSTRACT_

#include <cmath>
#include <limits>
#include <sstream>
#include "../matrix/matrix_abstract.h"
#include "../algs.h"
#include "../serialize.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
/*!A                               Kernel_Function_Objects                               */
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    /*!
        WHAT IS A KERNEL FUNCTION OBJECT?
            In the context of the dlib library documentation a kernel function object
            is an object with an interface with the following properties:
                - a public typedef named sample_type
                - a public typedef named scalar_type which should be a float, double, or
                  long double type.
                - an overloaded operator() that operates on two items of sample_type
                  and returns a scalar_type.
                  (e.g. scalar_type val = kernel_function(sample1,sample2);
                   would be a valid expression)
                - a public typedef named mem_manager_type that is an implementation of
                  dlib/memory_manager/memory_manager_kernel_abstract.h or
                  dlib/memory_manager_global/memory_manager_global_kernel_abstract.h or
                  dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h
                - an overloaded == operator that tells you if two kernels are
                  identical or not.

        THREAD SAFETY
            For a kernel function to be threadsafe it means that it must be safe to
            evaluate an expression like val = kernel_function(sample1,sample2)
            simultaneously from multiple threads, even when the threads operate on the same
            object instances (i.e. kernel_function, sample1, and sample2).  The most common
            way to make this safe is to ensure that the kernel function does not mutate any
            data, either in itself or in its arguments.

        For examples of kernel functions see the following objects
        (e.g. the radial_basis_kernel).
    !*/

    template <
        typename T
        >
    struct radial_basis_kernel
    {
        /*!
            REQUIREMENTS ON T
                T must be a dlib::matrix object

            WHAT THIS OBJECT REPRESENTS
                This object represents a radial basis function kernel

            THREAD SAFETY
                This kernel is threadsafe.
        !*/

        typedef typename T::type scalar_type;
        typedef T sample_type;
        typedef typename T::mem_manager_type mem_manager_type;

        const scalar_type gamma;

        radial_basis_kernel(
        );
        /*!
            ensures
                - #gamma == 0.1
        !*/

        radial_basis_kernel(
            const radial_basis_kernel& k
        );
        /*!
            ensures
                - #gamma == k.gamma
        !*/

        radial_basis_kernel(
            const scalar_type g
        );
        /*!
            ensures
                - #gamma == g
        !*/

        scalar_type operator() (
            const sample_type& a,
            const sample_type& b
        ) const;
        /*!
            requires
                - a.nc() == 1
                - b.nc() == 1
                - a.nr() == b.nr()
            ensures
                - returns exp(-gamma * ||a-b||^2)
        !*/

        radial_basis_kernel& operator= (
            const radial_basis_kernel& k
        );
        /*!
            ensures
                - #gamma = k.gamma
                - returns *this
        !*/

        bool operator== (
            const radial_basis_kernel& k
        ) const;
        /*!
            ensures
                - if (k and *this are identical) then
                    - returns true
                - else
                    - returns false
        !*/

    };

    template <
        typename T
        >
    void serialize (
        const radial_basis_kernel<T>& item,
        std::ostream& out
    );
    /*!
        provides serialization support for radial_basis_kernel
    !*/

    template <
        typename T
        >
    void deserialize (
        radial_basis_kernel<T>& item,
        std::istream& in
    );
    /*!
        provides deserialization support for radial_basis_kernel
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    struct sigmoid_kernel
    {
        /*!
            REQUIREMENTS ON T
                T must be a dlib::matrix object

            WHAT THIS OBJECT REPRESENTS
                This object represents a sigmoid kernel

            THREAD SAFETY
                This kernel is threadsafe.
        !*/

        typedef typename T::type scalar_type;
        typedef T sample_type;
        typedef typename T::mem_manager_type mem_manager_type;

        const scalar_type gamma;
        const scalar_type coef;

        sigmoid_kernel(
        );
        /*!
            ensures
                - #gamma == 0.1
                - #coef == -1.0
        !*/

        sigmoid_kernel(
            const sigmoid_kernel& k
        );
        /*!
            ensures
                - #gamma == k.gamma
                - #coef == k.coef
        !*/

        sigmoid_kernel(
            const scalar_type g,
            const scalar_type c
        );
        /*!
            ensures
                - #gamma == g
                - #coef == c
        !*/

        scalar_type operator() (
            const sample_type& a,
            const sample_type& b
        ) const;
        /*!
            requires
                - a.nc() == 1
                - b.nc() == 1
                - a.nr() == b.nr()
            ensures
                - returns tanh(gamma*trans(a)*b + coef)
        !*/

        sigmoid_kernel& operator= (
            const sigmoid_kernel& k
        );
        /*!
            ensures
                - #gamma = k.gamma
                - #coef = k.coef
                - returns *this
        !*/

        bool operator== (
            const sigmoid_kernel& k
        ) const;
        /*!
            ensures
                - if (k and *this are identical) then
                    - returns true
                - else
                    - returns false
        !*/
    };

    template <
        typename T
        >
    void serialize (
        const sigmoid_kernel<T>& item,
        std::ostream& out
    );
    /*!
        provides serialization support for sigmoid_kernel
    !*/

    template <
        typename T
        >
    void deserialize (
        sigmoid_kernel<T>& item,
        std::istream& in
    );
    /*!
        provides deserialization support for sigmoid_kernel
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    struct polynomial_kernel
    {
        /*!
            REQUIREMENTS ON T
                T must be a dlib::matrix object

            WHAT THIS OBJECT REPRESENTS
                This object represents a polynomial kernel

            THREAD SAFETY
                This kernel is threadsafe.
        !*/

        typedef typename T::type scalar_type;
        typedef T sample_type;
        typedef typename T::mem_manager_type mem_manager_type;

        const scalar_type gamma;
        const scalar_type coef;
        const scalar_type degree;

        polynomial_kernel(
        );
        /*!
            ensures
                - #gamma == 1
                - #coef == 0
                - #degree == 1
        !*/

        polynomial_kernel(
            const polynomial_kernel& k
        );
        /*!
            ensures
                - #gamma == k.gamma
                - #coef == k.coef
                - #degree == k.degree
        !*/

        polynomial_kernel(
            const scalar_type g,
            const scalar_type c,
            const scalar_type d
        );
        /*!
            ensures
                - #gamma == g
                - #coef == c
                - #degree == d
        !*/

        scalar_type operator() (
            const sample_type& a,
            const sample_type& b
        ) const;
        /*!
            requires
                - a.nc() == 1
                - b.nc() == 1
                - a.nr() == b.nr()
            ensures
                - returns pow(gamma*trans(a)*b + coef, degree)
        !*/

        polynomial_kernel& operator= (
            const polynomial_kernel& k
        );
        /*!
            ensures
                - #gamma = k.gamma
                - #coef = k.coef
                - #degree = k.degree
                - returns *this
        !*/

        bool operator== (
            const polynomial_kernel& k
        ) const;
        /*!
            ensures
                - if (k and *this are identical) then
                    - returns true
                - else
                    - returns false
        !*/
    };

    template <
        typename T
        >
    void serialize (
        const polynomial_kernel<T>& item,
        std::ostream& out
    );
    /*!
        provides serialization support for polynomial_kernel
    !*/

    template <
        typename T
        >
    void deserialize (
        polynomial_kernel<T>& item,
        std::istream& in
    );
    /*!
        provides deserialization support for polynomial_kernel
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    struct linear_kernel
    {
        /*!
            REQUIREMENTS ON T
                T must be a dlib::matrix object

            WHAT THIS OBJECT REPRESENTS
                This object represents a linear function kernel

            THREAD SAFETY
                This kernel is threadsafe.
        !*/

        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;
        /*!
            requires
                - a.nc() == 1
                - b.nc() == 1
                - a.nr() == b.nr()
            ensures
                - returns trans(a)*b
        !*/

        bool operator== (
            const linear_kernel& k
        ) const;
        /*!
            ensures
                - returns true
        !*/
    };

    template <
        typename T
        >
    void serialize (
        const linear_kernel<T>& item,
        std::ostream& out
    );
    /*!
        provides serialization support for linear_kernel
    !*/

    template <
        typename T
        >
    void deserialize (
        linear_kernel<T>& item,
        std::istream& in
    );
    /*!
        provides deserialization support for linear_kernel
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    struct histogram_intersection_kernel
    {
        /*!
            REQUIREMENTS ON T
                T must be a dlib::matrix object

            WHAT THIS OBJECT REPRESENTS
                This object represents a histogram intersection kernel kernel

            THREAD SAFETY
                This kernel is threadsafe.
        !*/

        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;
        /*!
            requires
                - is_vector(a)
                - is_vector(b)
                - a.size() == b.size()
                - min(a) >= 0
                - min(b) >= 0
            ensures
                - returns sum over all i: std::min(a(i), b(i))
        !*/

        bool operator== (
            const histogram_intersection_kernel& k
        ) const;
        /*!
            ensures
                - returns true
        !*/
    };

    template <
        typename T
        >
    void serialize (
        const histogram_intersection_kernel<T>& item,
        std::ostream& out
    );
    /*!
        provides serialization support for histogram_intersection_kernel
    !*/

    template <
        typename T
        >
    void deserialize (
        histogram_intersection_kernel<T>& item,
        std::istream& in
    );
    /*!
        provides deserialization support for histogram_intersection_kernel
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    struct offset_kernel
    {
        /*!
            REQUIREMENTS ON T
                T must be a kernel object (e.g. radial_basis_kernel, polynomial_kernel, etc.)

            WHAT THIS OBJECT REPRESENTS
                This object represents a kernel with a fixed value offset
                added to it.

            THREAD SAFETY
                This kernel is threadsafe.
        !*/

        typedef typename T::scalar_type scalar_type;
        typedef typename T::sample_type sample_type;
        typedef typename T::mem_manager_type mem_manager_type;

        const T kernel;
        const scalar_type offset;

        offset_kernel(
        );
        /*!
            ensures
                - #offset == 0.01
        !*/

        offset_kernel(
            const offset_kernel& k
        );
        /*!
            ensures
                - #offset == k.offset
                - #kernel == k.kernel
        !*/

        offset_kernel(
            const T& k,
            const scalar_type& off
        );
        /*!
            ensures
                - #kernel == k
                - #offset == off
        !*/

        scalar_type operator() (
            const sample_type& a,
            const sample_type& b
        ) const;
        /*!
            ensures
                - returns kernel(a,b) + offset
        !*/

        offset_kernel& operator= (
            const offset_kernel& k
        );
        /*!
            ensures
                - #offset == k.offset
                - #kernel == k.kernel
        !*/

        bool operator== (
            const offset_kernel& k
        ) const;
        /*!
            ensures
                - if (k and *this are identical) then
                    - returns true
                - else
                    - returns false
        !*/
    };

    template <
        typename T
        >
    void serialize (
        const offset_kernel<T>& item,
        std::ostream& out
    );
    /*!
        provides serialization support for offset_kernel
    !*/

    template <
        typename T
        >
    void deserialize (
        offset_kernel<T>& item,
        std::istream& in
    );
    /*!
        provides deserialization support for offset_kernel
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename kernel_type
        >
    struct kernel_derivative
    {
        /*!
            REQUIREMENTS ON kernel_type
                kernel_type must be one of the following kernel types:
                    - radial_basis_kernel
                    - polynomial_kernel
                    - sigmoid_kernel
                    - linear_kernel
                    - offset_kernel

            WHAT THIS OBJECT REPRESENTS
                This is a function object that computes the derivative of a kernel
                function object.

            THREAD SAFETY
                It is always safe to use distinct instances of this object in different
                threads.  However, when a single instance is shared between threads then
                the following rules apply:
                    Instances of this object are allowed to have a mutable cache which is
                    used by const member functions.  Therefore, it is not safe to use one
                    instance of this object from multiple threads (unless protected by a
                    mutex).
        !*/

        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;

        kernel_derivative(
            const kernel_type& k_
        );
        /*!
            ensures
                - this object will return derivatives of the kernel object k_
                - #k == k_
        !*/

        const sample_type operator() (
            const sample_type& x,
            const sample_type& y
        ) const;
        /*!
            ensures
                - returns the derivative of k with respect to y.
        !*/

        const kernel_type& k;
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SVm_KERNEL_ABSTRACT_


dlib C++ Library - sparse_kernel_abstract.h

// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SVm_SPARSE_KERNEL_ABSTRACT_
#ifdef DLIB_SVm_SPARSE_KERNEL_ABSTRACT_

#include <cmath>
#include <limits>
#include "../algs.h"
#include "../serialize.h"
#include "kernel_abstract.h"
#include "sparse_vector_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    struct sparse_radial_basis_kernel
    {
        /*!
            REQUIREMENTS ON T
                Must be a sparse vector as defined in dlib/svm/sparse_vector_abstract.h

            WHAT THIS OBJECT REPRESENTS
                This object represents a radial basis function kernel
                that works with sparse vectors.

            THREAD SAFETY
                This kernel is threadsafe.
        !*/

        typedef typename T::value_type::second_type scalar_type;
        typedef T sample_type;
        typedef default_memory_manager mem_manager_type;

        const scalar_type gamma;

        sparse_radial_basis_kernel(
        );
        /*!
            ensures
                - #gamma == 0.1
        !*/

        sparse_radial_basis_kernel(
            const sparse_radial_basis_kernel& k
        );
        /*!
            ensures
                - #gamma == k.gamma
        !*/

        sparse_radial_basis_kernel(
            const scalar_type g
        );
        /*!
            ensures
                - #gamma == g
        !*/

        scalar_type operator() (
            const sample_type& a,
            const sample_type& b
        ) const;
        /*!
            requires
                - a is a sparse vector
                - b is a sparse vector
            ensures
                - returns exp(-gamma * distance_squared(a,b))
        !*/

        sparse_radial_basis_kernel& operator= (
            const sparse_radial_basis_kernel& k
        );
        /*!
            ensures
                - #gamma = k.gamma
                - returns *this
        !*/

        bool operator== (
            const sparse_radial_basis_kernel& k
        ) const;
        /*!
            ensures
                - if (k and *this are identical) then
                    - returns true
                - else
                    - returns false
        !*/

    };

    template <
        typename T
        >
    void serialize (
        const sparse_radial_basis_kernel<T>& item,
        std::ostream& out
    );
    /*!
        provides serialization support for sparse_radial_basis_kernel
    !*/

    template <
        typename T
        >
    void deserialize (
        sparse_radial_basis_kernel<T>& item,
        std::istream& in
    );
    /*!
        provides deserialization support for sparse_radial_basis_kernel
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    struct sparse_sigmoid_kernel
    {
        /*!
            REQUIREMENTS ON T
                Must be a sparse vector as defined in dlib/svm/sparse_vector_abstract.h

            WHAT THIS OBJECT REPRESENTS
                This object represents a sigmoid kernel
                that works with sparse vectors.

            THREAD SAFETY
                This kernel is threadsafe.
        !*/

        typedef typename T::value_type::second_type scalar_type;
        typedef T sample_type;
        typedef default_memory_manager mem_manager_type;

        const scalar_type gamma;
        const scalar_type coef;

        sparse_sigmoid_kernel(
        );
        /*!
            ensures
                - #gamma == 0.1
                - #coef == -1.0
        !*/

        sparse_sigmoid_kernel(
            const sparse_sigmoid_kernel& k
        );
        /*!
            ensures
                - #gamma == k.gamma
                - #coef == k.coef
        !*/

        sparse_sigmoid_kernel(
            const scalar_type g,
            const scalar_type c
        );
        /*!
            ensures
                - #gamma == g
                - #coef == c
        !*/

        scalar_type operator() (
            const sample_type& a,
            const sample_type& b
        ) const;
        /*!
            requires
                - a is a sparse vector
                - b is a sparse vector
            ensures
                - returns tanh(gamma * dot(a,b) + coef)
        !*/

        sparse_sigmoid_kernel& operator= (
            const sparse_sigmoid_kernel& k
        );
        /*!
            ensures
                - #gamma = k.gamma
                - #coef = k.coef
                - returns *this
        !*/

        bool operator== (
            const sparse_sigmoid_kernel& k
        ) const;
        /*!
            ensures
                - if (k and *this are identical) then
                    - returns true
                - else
                    - returns false
        !*/
    };

    template <
        typename T
        >
    void serialize (
        const sparse_sigmoid_kernel<T>& item,
        std::ostream& out
    );
    /*!
        provides serialization support for sparse_sigmoid_kernel
    !*/

    template <
        typename T
        >
    void deserialize (
        sparse_sigmoid_kernel<T>& item,
        std::istream& in
    );
    /*!
        provides deserialization support for sparse_sigmoid_kernel
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    struct sparse_polynomial_kernel
    {
        /*!
            REQUIREMENTS ON T
                Must be a sparse vector as defined in dlib/svm/sparse_vector_abstract.h

            WHAT THIS OBJECT REPRESENTS
                This object represents a polynomial kernel
                that works with sparse vectors.

            THREAD SAFETY
                This kernel is threadsafe.
        !*/

        typedef typename T::value_type::second_type scalar_type;
        typedef T sample_type;
        typedef default_memory_manager mem_manager_type;

        const scalar_type gamma;
        const scalar_type coef;
        const scalar_type degree;

        sparse_polynomial_kernel(
        );
        /*!
            ensures
                - #gamma == 1
                - #coef == 0
                - #degree == 1
        !*/

        sparse_polynomial_kernel(
            const sparse_polynomial_kernel& k
        );
        /*!
            ensures
                - #gamma == k.gamma
                - #coef == k.coef
                - #degree == k.degree
        !*/

        sparse_polynomial_kernel(
            const scalar_type g,
            const scalar_type c,
            const scalar_type d
        );
        /*!
            ensures
                - #gamma == g
                - #coef == c
                - #degree == d
        !*/

        scalar_type operator() (
            const sample_type& a,
            const sample_type& b
        ) const;
        /*!
            requires
                - a is a sparse vector
                - b is a sparse vector
            ensures
                - returns pow(gamma * dot(a,b) + coef, degree)
        !*/

        sparse_polynomial_kernel& operator= (
            const sparse_polynomial_kernel& k
        );
        /*!
            ensures
                - #gamma = k.gamma
                - #coef = k.coef
                - #degree = k.degree
                - returns *this
        !*/

        bool operator== (
            const sparse_polynomial_kernel& k
        ) const;
        /*!
            ensures
                - if (k and *this are identical) then
                    - returns true
                - else
                    - returns false
        !*/
    };

    template <
        typename T
        >
    void serialize (
        const sparse_polynomial_kernel<T>& item,
        std::ostream& out
    );
    /*!
        provides serialization support for sparse_polynomial_kernel
    !*/

    template <
        typename T
        >
    void deserialize (
        sparse_polynomial_kernel<T>& item,
        std::istream& in
    );
    /*!
        provides deserialization support for sparse_polynomial_kernel
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    struct sparse_linear_kernel
    {
        /*!
            REQUIREMENTS ON T
                Must be a sparse vector as defined in dlib/svm/sparse_vector_abstract.h

            WHAT THIS OBJECT REPRESENTS
                This object represents a linear function kernel
                that works with sparse vectors.

            THREAD SAFETY
                This kernel is threadsafe.
        !*/

        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;
        /*!
            requires
                - a is a sparse vector
                - b is a sparse vector
            ensures
                - returns dot(a,b)
        !*/

        bool operator== (
            const sparse_linear_kernel& k
        ) const;
        /*!
            ensures
                - returns true
        !*/
    };

    template <
        typename T
        >
    void serialize (
        const sparse_linear_kernel<T>& item,
        std::ostream& out
    );
    /*!
        provides serialization support for sparse_linear_kernel
    !*/

    template <
        typename T
        >
    void deserialize (
        sparse_linear_kernel<T>& item,
        std::istream& in
    );
    /*!
        provides deserialization support for sparse_linear_kernel
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    struct sparse_histogram_intersection_kernel
    {
        /*!
            REQUIREMENTS ON T
                Must be a sparse vector as defined in dlib/svm/sparse_vector_abstract.h

            WHAT THIS OBJECT REPRESENTS
                This object represents a histogram intersection kernel
                that works with sparse vectors.

            THREAD SAFETY
                This kernel is threadsafe.
        !*/

        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;
        /*!
            requires
                - a is a sparse vector
                - b is a sparse vector
                - all the values in a and b are >= 0
            ensures
                - Let A(i) denote the value of the ith dimension of the a vector.
                - Let B(i) denote the value of the ith dimension of the b vector.
                - returns sum over all i: std::min(A(i), B(i))
        !*/

        bool operator== (
            const sparse_histogram_intersection_kernel& k
        ) const;
        /*!
            ensures
                - returns true
        !*/
    };

    template <
        typename T
        >
    void serialize (
        const sparse_histogram_intersection_kernel<T>& item,
        std::ostream& out
    );
    /*!
        provides serialization support for sparse_histogram_intersection_kernel
    !*/

    template <
        typename T
        >
    void deserialize (
        sparse_histogram_intersection_kernel<T>& item,
        std::istream& in
    );
    /*!
        provides deserialization support for sparse_histogram_intersection_kernel
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SVm_SPARSE_KERNEL_ABSTRACT_


dlib C++ Library - assignment_function_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_ASSIGNMENT_FuNCTION_ABSTRACT_Hh_
#ifdef DLIB_ASSIGNMENT_FuNCTION_ABSTRACT_Hh_

#include <vector>
#include "../optimization/max_cost_assignment_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class example_feature_extractor
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object defines the interface a feature extractor must implement
                if it is to be used with the assignment_function defined at the bottom
                of this file.

                The model used by assignment_function objects is the following.
                Given two sets of objects, the Left Hand Set (LHS) and Right Hand Set (RHS),
                find a one-to-one mapping M from LHS into RHS such that:
                    M == argmax_m  sum_{l in LHS} match_score(l,m(l))
                Where match_score() returns a scalar value indicating how good it is
                to say l maps to the RHS element m(l).  Additionally, in this model,
                m() is allowed to indicate that l doesn't map to anything, and in this
                case it is excluded from the sum.

                Finally, match_score() is defined as:
                    match_score(l,r) == dot(w, PSI(l,r)) + bias
                where l is an element of LHS, r is an element of RHS, w is a parameter
                vector and bias is a scalar valued parameter.

                Therefore, a feature extractor defines how the PSI() feature vector
                is calculated.  In particular, PSI() is defined by the get_features()
                method of this class.

            THREAD SAFETY
                Instances of this object are required to be threadsafe, that is, it should
                be safe for multiple threads to make concurrent calls to the member
                functions of this object.

        !*/

    public:

        // This type should be a dlib::matrix capable of storing column vectors
        // or an unsorted sparse vector type as defined in dlib/svm/sparse_vector_abstract.h.
        typedef matrix_or_sparse_vector_type feature_vector_type;

        // These two typedefs define the types used to represent an element in
        // the left hand and right hand sets.  You can use any copyable types here.
        typedef user_defined_type_1 lhs_element;
        typedef user_defined_type_2 rhs_element;

        unsigned long num_features(
        ) const;
        /*!
            ensures
                - returns the dimensionality of the PSI() feature vector.
        !*/

        void get_features (
            const lhs_element& left,
            const rhs_element& right,
            feature_vector_type& feats
        ) const;
        /*!
            ensures
                - #feats == PSI(left,right)
                  (i.e. This function computes a feature vector which, in some sense,
                  captures information useful for deciding if matching left to right
                  is "good").
        !*/

        unsigned long num_nonnegative_weights (
        ) const;
        /*!
            ensures
                - returns the number of elements of the w parameter vector which should be
                  non-negative.  That is, this feature extractor is intended to be used
                  with w vectors where the first num_nonnegative_weights() elements of w
                  are >= 0.  That is, it should be the case that w(i) >= 0 for all i <
                  num_nonnegative_weights().
                - Note that num_nonnegative_weights() is just an optional method to allow
                  you to tell a tool like the structural_assignment_trainer that the
                  learned w should have a certain number of non-negative elements.
                  Therefore, if you do not provide a num_nonnegative_weights() method in
                  your feature extractor then it will default to a value of 0, indicating
                  that all elements of the w parameter vector may be any value.
        !*/

    };

// ----------------------------------------------------------------------------------------

    void serialize(
        const example_feature_extractor& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

    void deserialize(
        example_feature_extractor& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    class assignment_function
    {
        /*!
            REQUIREMENTS ON feature_extractor
                It must be an object that implements an interface compatible with
                the example_feature_extractor discussed above.

            WHAT THIS OBJECT REPRESENTS
                This object is a tool for solving the optimal assignment problem given a
                user defined method for computing the quality of any particular assignment.

                To define this precisely, suppose you have two sets of objects, a
                Left Hand Set (LHS) and a Right Hand Set (RHS) and you want to
                find a one-to-one mapping M from LHS into RHS such that:
                    M == argmax_m  sum_{l in LHS} match_score(l,m(l))
                Where match_score() returns a scalar value indicating how good it is
                to say l maps to the RHS element m(l).  Additionally, in this model,
                m() is allowed to indicate that l doesn't map to anything, and in this
                case it is excluded from the sum.

                Finally, this object supports match_score() functions of the form:
                    match_score(l,r) == dot(w, PSI(l,r)) + bias
                where l is an element of LHS, r is an element of RHS, w is a parameter
                vector, bias is a scalar valued parameter, and PSI() is defined by the
                feature_extractor template argument.

            THREAD SAFETY
                It is always safe to use distinct instances of this object in different
                threads.  However, when a single instance is shared between threads then
                the following rules apply:
                    It is safe to call the const members of this object from multiple
                    threads so long as the feature_extractor is also threadsafe.  This is
                    because the const members are purely read-only operations.  However,
                    any operation that modifies an assignment_function is not threadsafe.
        !*/

    public:

        typedef typename feature_extractor::lhs_element  lhs_element;
        typedef typename feature_extractor::rhs_element  rhs_element;
        typedef          std::vector<long>               label_type;
        typedef          label_type                      result_type;
        typedef std::pair<std::vector<lhs_element>, std::vector<rhs_element> > sample_type;

        assignment_function(
        );
        /*!
            ensures
                - #get_feature_extractor() == feature_extractor()
                  (i.e. it will have its default value)
                - #get_weights().size() == #get_feature_extractor().num_features()
                - #get_weights() == 0
                - #get_bias() == 0
                - #forces_assignment() == false
        !*/

        explicit assignment_function(
            const matrix<double,0,1>& weights,
            double bias
        );
        /*!
            requires
                - feature_extractor().num_features() == weights.size()
            ensures
                - #get_feature_extractor() == feature_extractor()
                  (i.e. it will have its default value)
                - #get_weights() == weights
                - #get_bias() == bias
                - #forces_assignment() == false
        !*/

        assignment_function(
            const matrix<double,0,1>& weights,
            double bias,
            const feature_extractor& fe
        );
        /*!
            requires
                - fe.num_features() == weights.size()
            ensures
                - #get_feature_extractor() == fe
                - #get_weights() == weights
                - #get_bias() == bias
                - #forces_assignment() == false
        !*/

        assignment_function(
            const matrix<double,0,1>& weights,
            double bias,
            const feature_extractor& fe,
            bool force_assignment
        );
        /*!
            requires
                - fe.num_features() == weights.size()
            ensures
                - #get_feature_extractor() == fe
                - #get_weights() == weights
                - #get_bias() == bias
                - #forces_assignment() == force_assignment
        !*/

        const feature_extractor& get_feature_extractor (
        ) const;
        /*!
            ensures
                - returns the feature extractor used by this object
        !*/

        const matrix<double,0,1>& get_weights (
        ) const;
        /*!
            ensures
                - returns the parameter vector (w) associated with this assignment function.
                  The length of the vector is get_feature_extractor().num_features().
        !*/

        double get_bias (
        ) const;
        /*!
            ensures
                - returns the bias parameter associated with this assignment function.
        !*/

        bool forces_assignment (
        ) const;
        /*!
            ensures
                - returns true if this object is in the "forced assignment mode" and false
                  otherwise.
                - When deciding how to match LHS to RHS, this object can operate in one of
                  two modes.  In the default mode, this object will indicate that there is
                  no match for an element of LHS if the best matching element of RHS would
                  result in a negative match_score().  However, in the "forced assignment mode",
                  this object will always make the assignment if there is an available
                  element in RHS, regardless of the match_score().

                  Another way to understand this distinction is to consider an example.
                  Suppose LHS and RHS both contain 10 elements.  Then in the default mode,
                  it is possible for this object to indicate that there are anywhere between
                  0 to 10 matches between LHS and RHS.  However, in forced assignment mode
                  it will always indicate exactly 10 matches.
        !*/

        result_type operator()(
            const std::vector<lhs_element>& lhs,
            const std::vector<rhs_element>& rhs
        ) const
        /*!
            ensures
                - returns a vector ASSIGN such that:
                    - ASSIGN.size() == lhs.size()
                    - if (ASSIGN[i] != -1) then
                        - lhs[i] is predicted to associate to rhs[ASSIGN[i]].
                    - else
                        - lhs[i] doesn't associate with anything in rhs.
                    - All values in ASSIGN which are not equal to -1 are unique.
                      That is, ASSIGN will never indicate that more than one element
                      of lhs is assigned to a particular element of rhs.
        !*/

        result_type operator() (
            const sample_type& item
        ) const;
        /*!
            ensures
                - returns (*this)(item.first, item.second);
        !*/

        void predict_assignments (
            const sample_type& item,
            result_type& assignment
        ) const;
        /*!
            ensures
                - #assignment == (*this)(item)
        !*/

        void predict_assignments (
            const std::vector<lhs_element>& lhs,
            const std::vector<rhs_element>& rhs
            result_type& assignment
        ) const;
        /*!
            ensures
                - #assignment == (*this)(lhs,rhs)
        !*/
    };

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    void serialize (
        const assignment_function<feature_extractor>& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    void deserialize (
        assignment_function<feature_extractor>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_ASSIGNMENT_FuNCTION_ABSTRACT_Hh_


dlib C++ Library - function_abstract.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SVm_FUNCTION_ABSTRACT_
#ifdef DLIB_SVm_FUNCTION_ABSTRACT_

#include <cmath>
#include <limits>
#include <sstream>
#include "../matrix/matrix_abstract.h"
#include "../algs.h"
#include "../serialize.h"
#include "../statistics/statistics_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename K
        >
    struct decision_function
    {
        /*!
            REQUIREMENTS ON K
                K must be a kernel function object type as defined at the
                top of dlib/svm/kernel_abstract.h

            WHAT THIS OBJECT REPRESENTS
                This object represents a classification or regression function that was
                learned by a kernel based learning algorithm.   Therefore, it is a function
                object that takes a sample object and returns a scalar value.

            THREAD SAFETY
                It is always safe to use distinct instances of this object in different
                threads.  However, when a single instance is shared between threads then
                the following rules apply:
                    It is safe to call operator() on this object from multiple threads so
                    long as the kernel, K, is also threadsafe.  This is because operator()
                    is a read-only operation.  However, any operation that modifies a
                    decision_function is not threadsafe.
        !*/

        typedef K kernel_type;
        typedef typename K::scalar_type scalar_type;
        typedef typename K::scalar_type result_type;
        typedef typename K::sample_type sample_type;
        typedef typename K::mem_manager_type mem_manager_type;

        typedef matrix<scalar_type,0,1,mem_manager_type> scalar_vector_type;
        typedef matrix<sample_type,0,1,mem_manager_type> sample_vector_type;

        scalar_vector_type alpha;
        scalar_type        b;
        K                  kernel_function;
        sample_vector_type basis_vectors;

        decision_function (
        );
        /*!
            ensures
                - #b == 0
                - #alpha.nr() == 0
                - #basis_vectors.nr() == 0
        !*/

        decision_function (
            const decision_function& f
        );
        /*!
            ensures
                - #*this is a copy of f
        !*/

        decision_function (
            const scalar_vector_type& alpha_,
            const scalar_type& b_,
            const K& kernel_function_,
            const sample_vector_type& basis_vectors_
        ) : alpha(alpha_), b(b_), kernel_function(kernel_function_), basis_vectors(basis_vectors_) {}
        /*!
            ensures
                - populates the decision function with the given basis vectors, weights(i.e. alphas),
                  b term, and kernel function.
        !*/

        result_type operator() (
            const sample_type& x
        ) const
        /*!
            ensures
                - evaluates this sample according to the decision
                  function contained in this object.
        !*/
        {
            result_type temp = 0;
            for (long i = 0; i < alpha.nr(); ++i)
                temp += alpha(i) * kernel_function(x,basis_vectors(i));

            return temp - b;
        }
    };

    template <
        typename K
        >
    void serialize (
        const decision_function<K>& item,
        std::ostream& out
    );
    /*!
        provides serialization support for decision_function
    !*/

    template <
        typename K
        >
    void deserialize (
        decision_function<K>& item,
        std::istream& in
    );
    /*!
        provides serialization support for decision_function
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename function_type
        >
    struct probabilistic_function
    {
        /*!
            REQUIREMENTS ON function_type
                - function_type must be a function object with an overloaded
                  operator() similar to the other function objects defined in
                  this file.  The operator() should return a scalar type such as
                  double or float.

            WHAT THIS OBJECT REPRESENTS
                This object represents a binary decision function that returns an
                estimate of the probability that a given sample is in the +1 class.

            THREAD SAFETY
                It is always safe to use distinct instances of this object in different
                threads.  However, when a single instance is shared between threads then
                the following rules apply:
                    It is safe to call operator() on this object from multiple threads so
                    long as decision_funct is also threadsafe.  This is because operator()
                    is a read-only operation.  However, any operation that modifies a
                    probabilistic_function is not threadsafe.
        !*/

        typedef typename function_type::scalar_type scalar_type;
        typedef typename function_type::result_type result_type;
        typedef typename function_type::sample_type sample_type;
        typedef typename function_type::mem_manager_type mem_manager_type;

        scalar_type alpha;
        scalar_type beta;
        function_type decision_funct;

        probabilistic_function (
        );
        /*!
            ensures
                - #alpha == 0
                - #beta == 0
                - #decision_funct has its initial value
        !*/

        probabilistic_function (
            const probabilistic_function& f
        );
        /*!
            ensures
                - #*this is a copy of f
        !*/

        probabilistic_function (
            const scalar_type a,
            const scalar_type b,
            const function_type& decision_funct_
        ) : alpha(a), beta(b), decision_funct(decision_funct_) {}
        /*!
            ensures
                - populates the probabilistic decision function with the given alpha, beta,
                  and decision function.
        !*/

        result_type operator() (
            const sample_type& x
        ) const
        /*!
            ensures
                - returns a number P such that:
                    - 0 <= P <= 1
                    - P represents the probability that sample x is from
                      the class +1
        !*/
        {
            // Evaluate the normal decision function
            result_type f = decision_funct(x);
            // Now basically normalize the output so that it is a properly
            // conditioned probability of x being in the +1 class given
            // the output of the decision function.
            return 1/(1 + std::exp(alpha*f + beta));
        }
    };

    template <
        typename function_type
        >
    void serialize (
        const probabilistic_function<function_type>& item,
        std::ostream& out
    );
    /*!
        provides serialization support for probabilistic_function
    !*/

    template <
        typename function_type
        >
    void deserialize (
        probabilistic_function<function_type>& item,
        std::istream& in
    );
    /*!
        provides serialization support for probabilistic_function
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename K
        >
    struct probabilistic_decision_function
    {
        /*!
            REQUIREMENTS ON K
                K must be a kernel function object type as defined at the
                top of dlib/svm/kernel_abstract.h

            WHAT THIS OBJECT REPRESENTS
                This object represents a binary decision function that returns an
                estimate of the probability that a given sample is in the +1 class.

                Note that this object is essentially just a copy of
                probabilistic_function but with the template argument
                changed from being a function type to a kernel type.  Therefore, this
                type is just a convenient version of probabilistic_function
                for the case where the decision function is a dlib::decision_function<K>.

            THREAD SAFETY
                It is always safe to use distinct instances of this object in different
                threads.  However, when a single instance is shared between threads then
                the following rules apply:
                    It is safe to call operator() on this object from multiple threads so
                    long as the kernel, K, is also threadsafe.  This is because operator()
                    is a read-only operation.  However, any operation that modifies a
                    probabilistic_decision_function is not threadsafe.
        !*/

        typedef K kernel_type;
        typedef typename K::scalar_type scalar_type;
        typedef typename K::scalar_type result_type;
        typedef typename K::sample_type sample_type;
        typedef typename K::mem_manager_type mem_manager_type;

        scalar_type alpha;
        scalar_type beta;
        decision_function<K> decision_funct;

        probabilistic_decision_function (
        );
        /*!
            ensures
                - #alpha == 0
                - #beta == 0
                - #decision_funct has its initial value
        !*/

        probabilistic_decision_function (
            const probabilistic_decision_function& f
        );
        /*!
            ensures
                - #*this is a copy of f
        !*/

        probabilistic_decision_function (
            const probabilistic_function<decision_function<K> >& d
        );
        /*!
            ensures
                - #*this is a copy of f
        !*/

        probabilistic_decision_function (
            const scalar_type a,
            const scalar_type b,
            const decision_function<K>& decision_funct_
        ) : alpha(a), beta(b), decision_funct(decision_funct_) {}
        /*!
            ensures
                - populates the probabilistic decision function with the given alpha, beta,
                  and decision_function.
        !*/

        result_type operator() (
            const sample_type& x
        ) const
        /*!
            ensures
                - returns a number P such that:
                    - 0 <= P <= 1
                    - P represents the probability that sample x is from
                      the class +1
        !*/
        {
            // Evaluate the normal decision function
            result_type f = decision_funct(x);
            // Now basically normalize the output so that it is a properly
            // conditioned probability of x being in the +1 class given
            // the output of the decision function.
            return 1/(1 + std::exp(alpha*f + beta));
        }
    };

    template <
        typename K
        >
    void serialize (
        const probabilistic_decision_function<K>& item,
        std::ostream& out
    );
    /*!
        provides serialization support for probabilistic_decision_function
    !*/

    template <
        typename K
        >
    void deserialize (
        probabilistic_decision_function<K>& item,
        std::istream& in
    );
    /*!
        provides serialization support for probabilistic_decision_function
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename K
        >
    class distance_function
    {
        /*!
            REQUIREMENTS ON K
                K must be a kernel function object type as defined at the
                top of dlib/svm/kernel_abstract.h

            WHAT THIS OBJECT REPRESENTS
                This object represents a point in kernel induced feature space.
                You may use this object to find the distance from the point it
                represents to points in input space as well as other points
                represented by distance_functions.

                Specifically, if O() is the feature mapping associated with
                the kernel used by this object.  Then this object represents
                the point:
                    sum alpha(i)*O(basis_vectors(i))

                I.e.  It represents a linear combination of the basis vectors where
                the weights of the linear combination are stored in the alpha vector.

            THREAD SAFETY
                It is always safe to use distinct instances of this object in different
                threads.  However, when a single instance is shared between threads then
                the following rules apply:
                    It is safe to call the const members of this object from multiple
                    threads so long as the kernel, K, is also threadsafe.  This is because
                    the const members are purely read-only operations.  However, any
                    operation that modifies a distance_function is not threadsafe.
        !*/

    public:
        typedef K kernel_type;
        typedef typename K::scalar_type scalar_type;
        typedef typename K::scalar_type result_type;
        typedef typename K::sample_type sample_type;
        typedef typename K::mem_manager_type mem_manager_type;

        typedef matrix<scalar_type,0,1,mem_manager_type> scalar_vector_type;
        typedef matrix<sample_type,0,1,mem_manager_type> sample_vector_type;

        distance_function (
        );
        /*!
            ensures
                - #get_squared_norm() == 0
                - #get_alpha().size() == 0
                - #get_basis_vectors().size() == 0
                - #get_kernel() == K() (i.e. the default value of the kernel)
        !*/

        explicit distance_function (
            const kernel_type& kern
        );
        /*!
            ensures
                - #get_squared_norm() == 0
                - #get_alpha().size() == 0
                - #get_basis_vectors().size() == 0
                - #get_kernel() == kern
        !*/

        distance_function (
            const kernel_type& kern,
            const sample_type& samp
        );
        /*!
            ensures
                - This object represents the point in kernel feature space which
                  corresponds directly to the given sample.  In particular this means
                  that:
                    - #get_kernel() == kern
                    - #get_alpha() == a vector of length 1 which contains the value 1
                    - #get_basis_vectors() == a vector of length 1 which contains samp
        !*/

        distance_function (
            const decision_function<K>& f
        );
        /*!
            ensures
                - Every decision_function represents a point in kernel feature space along
                  with a bias value.  This constructor discards the bias value and creates
                  a distance_function which represents the point associated with the given
                  decision_function f.  In particular, this means:
                    - #get_alpha() == f.alpha
                    - #get_kernel() == f.kernel_function
                    - #get_basis_vectors() == f.basis_vectors
        !*/

        distance_function (
            const distance_function& f
        );
        /*!
            requires
                - f is a valid distance_function.  In particular, this means that
                  f.alpha.size() == f.basis_vectors.size()
            ensures
                - #*this is a copy of f
        !*/

        distance_function (
            const scalar_vector_type& alpha,
            const scalar_type& squared_norm,
            const K& kernel_function,
            const sample_vector_type& basis_vectors
        );
        /*!
            requires
                - alpha.size() == basis_vectors.size()
                - squared_norm == trans(alpha)*kernel_matrix(kernel_function,basis_vectors)*alpha
                  (Basically, squared_norm needs to be set properly for this object to make sense.
                  You should prefer to use the following constructor which computes squared_norm for
                  you.  This version is provided just in case you already know squared_norm and
                  don't want to spend CPU cycles to recompute it.)
            ensures
                - populates the distance function with the given basis vectors, weights(i.e. alphas),
                  squared_norm value, and kernel function. I.e.
                    - #get_alpha() == alpha
                    - #get_squared_norm() == squared_norm
                    - #get_kernel() == kernel_function
                    - #get_basis_vectors() == basis_vectors
        !*/

        distance_function (
            const scalar_vector_type& alpha,
            const K& kernel_function,
            const sample_vector_type& basis_vectors
        );
        /*!
            requires
                - alpha.size() == basis_vectors.size()
            ensures
                - populates the distance function with the given basis vectors, weights(i.e. alphas),
                  and kernel function.  The correct b value is computed automatically.  I.e.
                    - #get_alpha() == alpha
                    - #get_squared_norm() == trans(alpha)*kernel_matrix(kernel_function,basis_vectors)*alpha
                      (i.e. get_squared_norm() will be automatically set to the correct value)
                    - #get_kernel() == kernel_function
                    - #get_basis_vectors() == basis_vectors
        !*/

        const scalar_vector_type& get_alpha (
        ) const;
        /*!
            ensures
                - returns the set of weights on each basis vector in this object
        !*/

        const scalar_type& get_squared_norm (
        ) const;
        /*!
            ensures
                - returns the squared norm of the point represented by this object.  This value is
                  equal to the following expression:
                    trans(get_alpha()) * kernel_matrix(get_kernel(),get_basis_vectors()) * get_alpha()
        !*/

        const K& get_kernel(
        ) const;
        /*!
            ensures
                - returns the kernel used by this object.
        !*/

        const sample_vector_type& get_basis_vectors (
        ) const;
        /*!
            ensures
                - returns the set of basis vectors contained in this object
        !*/

        result_type operator() (
            const sample_type& x
        ) const;
        /*!
            ensures
                - Let O(x) represent the point x projected into kernel induced feature space.
                - let c == sum_over_i get_alpha()(i)*O(get_basis_vectors()(i)) == the point in kernel space that
                  this object represents.  That is, c is the weighted sum of basis vectors.
                - Then this object returns the distance between the point O(x) and c in kernel
                  space.
        !*/

        result_type operator() (
            const distance_function& x
        ) const;
        /*!
            requires
                - kernel_function == x.kernel_function
            ensures
                - returns the distance between the points in kernel space represented by *this and x.
        !*/

        distance_function operator* (
            const scalar_type& val
        ) const;
        /*!
            ensures
                - multiplies the point represented by *this by val and returns the result.  In
                  particular, this function returns a decision_function DF such that:
                    - DF.get_basis_vectors() == get_basis_vectors()
                    - DF.get_kernel() == get_kernel()
                    - DF.get_alpha() == get_alpha() * val
        !*/

        distance_function operator/ (
            const scalar_type& val
        ) const;
        /*!
            ensures
                - divides the point represented by *this by val and returns the result.  In
                  particular, this function returns a decision_function DF such that:
                    - DF.get_basis_vectors() == get_basis_vectors()
                    - DF.get_kernel() == get_kernel()
                    - DF.get_alpha() == get_alpha() / val
        !*/

        distance_function operator+ (
            const distance_function& rhs
        ) const;
        /*!
            requires
                - get_kernel() == rhs.get_kernel()
            ensures
                - returns a distance function DF such that:
                    - DF represents the sum of the point represented by *this and rhs
                    - DF.get_basis_vectors().size() == get_basis_vectors().size() + rhs.get_basis_vectors().size()
                    - DF.get_basis_vectors() contains all the basis vectors in both *this and rhs.
                    - DF.get_kernel() == get_kernel()
                    - DF.alpha == join_cols(get_alpha(), rhs.get_alpha())
        !*/

        distance_function operator- (
            const distance_function& rhs
        ) const;
        /*!
            requires
                - get_kernel() == rhs.get_kernel()
            ensures
                - returns a distance function DF such that:
                    - DF represents the difference of the point represented by *this and rhs (i.e. *this - rhs)
                    - DF.get_basis_vectors().size() == get_basis_vectors().size() + rhs.get_basis_vectors().size()
                    - DF.get_basis_vectors() contains all the basis vectors in both *this and rhs.
                    - DF.get_kernel() == get_kernel()
                    - DF.alpha == join_cols(get_alpha(), -1 * rhs.get_alpha())
        !*/
    };

    template <
        typename K
        >
    distance_function<K> operator* (
        const typename K::scalar_type& val,
        const distance_function<K>& df
    ) { return df*val; }
    /*!
        ensures
            - multiplies the point represented by *this by val and returns the result.   This
              function just allows multiplication syntax of the form val*df.
    !*/

    template <
        typename K
        >
    void serialize (
        const distance_function<K>& item,
        std::ostream& out
    );
    /*!
        provides serialization support for distance_function
    !*/

    template <
        typename K
        >
    void deserialize (
        distance_function<K>& item,
        std::istream& in
    );
    /*!
        provides serialization support for distance_function
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename function_type,
        typename normalizer_type = vector_normalizer<typename function_type::sample_type>
        >
    struct normalized_function
    {
        /*!
            REQUIREMENTS ON function_type
                - function_type must be a function object with an overloaded
                  operator() similar to the other function objects defined in
                  this file.

            REQUIREMENTS ON normalizer_type
                - normalizer_type must be a function object with an overloaded
                  operator() that takes a sample_type and returns a sample_type.

            WHAT THIS OBJECT REPRESENTS
                This object represents a container for another function
                object and an instance of a normalizer function.

                It automatically normalizes all inputs before passing them
                off to the contained function object.
        !*/

        typedef typename function_type::result_type result_type;
        typedef typename function_type::sample_type sample_type;
        typedef typename function_type::mem_manager_type mem_manager_type;

        normalizer_type normalizer;
        function_type function;

        normalized_function (
        );
        /*!
            ensures
                - the members of this object have their default values
        !*/

        normalized_function (
            const normalized_function& f
        );
        /*!
            ensures
                - #*this is a copy of f
        !*/

        normalized_function (
            const vector_normalizer<sample_type>& normalizer_,
            const function_type& funct
        ) : normalizer(normalizer_), function(funct) {}
        /*!
            ensures
                - populates this object with the vector_normalizer and function object
        !*/

        const std::vector<result_type> get_labels(
        ) const;
        /*!
            ensures
                - returns function.get_labels()
        !*/

        unsigned long number_of_classes (
        ) const;
        /*!
            ensures
                - returns function.number_of_classes()
        !*/

        result_type operator() (
            const sample_type& x
        ) const
        /*!
            ensures
                - returns function(normalizer(x))
        !*/
    };

    template <
        typename function_type,
        typename normalizer_type
        >
    void serialize (
        const normalized_function<function_type, normalizer_type>& item,
        std::ostream& out
    );
    /*!
        provides serialization support for normalized_function
    !*/

    template <
        typename function_type,
        typename normalizer_type
        >
    void deserialize (
        normalized_function<function_type, normalizer_type>& item,
        std::istream& in
    );
    /*!
        provides serialization support for normalized_function
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename K
        >
    struct projection_function
    {
        /*!
            REQUIREMENTS ON K
                K must be a kernel function object type as defined at the
                top of dlib/svm/kernel_abstract.h

            WHAT THIS OBJECT REPRESENTS
                This object represents a function that takes a data sample and projects
                it into kernel feature space.  The result is a real valued column vector that
                represents a point in a kernel feature space.

            THREAD SAFETY
                It is always safe to use distinct instances of this object in different
                threads.  However, when a single instance is shared between threads then
                the following rules apply:
                    Instances of this object have a mutable cache which is used by const
                    member functions.  Therefore, it is not safe to use one instance of
                    this object from multiple threads (unless protected by a mutex).
        !*/

        typedef K kernel_type;
        typedef typename K::scalar_type scalar_type;
        typedef typename K::sample_type sample_type;
        typedef typename K::mem_manager_type mem_manager_type;

        typedef matrix<scalar_type,0,1,mem_manager_type> scalar_vector_type;
        typedef matrix<scalar_type,0,0,mem_manager_type> scalar_matrix_type;
        typedef matrix<sample_type,0,1,mem_manager_type> sample_vector_type;
        typedef scalar_vector_type result_type;

        scalar_matrix_type weights;
        K                  kernel_function;
        sample_vector_type basis_vectors;

        projection_function (
        );
        /*!
            ensures
                - #weights.size() == 0
                - #basis_vectors.size() == 0
        !*/

        projection_function (
            const projection_function& f
        );
        /*!
            ensures
                - #*this is a copy of f
        !*/

        projection_function (
            const scalar_matrix_type& weights_,
            const K& kernel_function_,
            const sample_vector_type& basis_vectors_
        ) : weights(weights_), kernel_function(kernel_function_), basis_vectors(basis_vectors_) {}
        /*!
            ensures
                - populates the projection function with the given basis vectors, weights,
                  and kernel function.
        !*/

        long out_vector_size (
        ) const;
        /*!
            ensures
                - returns weights.nr()
                  (i.e. returns the dimensionality of the vectors output by this projection_function.)
        !*/

        const result_type& operator() (
            const sample_type& x
        ) const
        /*!
            requires
                - weights.nc() == basis_vectors.size()
                - out_vector_size() > 0
            ensures
                - Takes the given x sample and projects it onto part of the kernel feature
                  space spanned by the basis_vectors.  The exact projection arithmetic is
                  defined below.
        !*/
        {
            // Run the x sample through all the basis functions we have and then
            // multiply it by the weights matrix and return the result.  Note that
            // the temp vectors are here to avoid reallocating their memory every
            // time this function is called.
            temp1 = kernel_matrix(kernel_function, basis_vectors, x);
            temp2 = weights*temp1;
            return temp2;
        }

    private:
        mutable result_type temp1, temp2;
    };

    template <
        typename K
        >
    void serialize (
        const projection_function<K>& item,
        std::ostream& out
    );
    /*!
        provides serialization support for projection_function
    !*/

    template <
        typename K
        >
    void deserialize (
        projection_function<K>& item,
        std::istream& in
    );
    /*!
        provides serialization support for projection_function
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename K,
        typename result_type_ = typename K::scalar_type
        >
    struct multiclass_linear_decision_function
    {
        /*!
            REQUIREMENTS ON K
                K must be either linear_kernel or sparse_linear_kernel.

            WHAT THIS OBJECT REPRESENTS
                This object represents a multiclass classifier built out of a set of
                binary classifiers.  Each binary classifier is used to vote for the
                correct multiclass label using a one vs. all strategy.  Therefore,
                if you have N classes then there will be N binary classifiers inside
                this object.  Additionally, this object is linear in the sense that
                each of these binary classifiers is a simple linear plane.

            THREAD SAFETY
                It is always safe to use distinct instances of this object in different
                threads.  However, when a single instance is shared between threads then
                the following rules apply:
                    It is safe to call the const member functions of this object from
                    multiple threads.  This is because the const members are purely
                    read-only operations.  However, any operation that modifies a
                    multiclass_linear_decision_function is not threadsafe.
        !*/

        typedef result_type_ result_type;

        typedef K kernel_type;
        typedef typename K::scalar_type scalar_type;
        typedef typename K::sample_type sample_type;
        typedef typename K::mem_manager_type mem_manager_type;

        typedef matrix<scalar_type,0,1,mem_manager_type> scalar_vector_type;
        typedef matrix<scalar_type,0,0,mem_manager_type> scalar_matrix_type;

        scalar_matrix_type       weights;
        scalar_vector_type       b;
        std::vector<result_type> labels;

        const std::vector<result_type>& get_labels(
        ) const { return labels; }
        /*!
            ensures
                - returns a vector containing all the labels which can be
                  predicted by this object.
        !*/

        unsigned long number_of_classes (
        ) const;
        /*!
            ensures
                - returns get_labels().size()
                  (i.e. returns the number of different labels/classes predicted by
                  this object)
        !*/

        std::pair<result_type, scalar_type> predict (
            const sample_type& x
        ) const;
        /*!
            requires
                - weights.size() > 0
                - weights.nr() == number_of_classes() == b.size()
                - if (x is a dense vector, i.e. a dlib::matrix) then
                    - is_vector(x) == true
                    - x.size() == weights.nc()
                      (i.e. it must be legal to multiply weights with x)
            ensures
                - Returns the predicted label for the x sample and also it's score.
                  In particular, it returns the following:
                    std::make_pair(labels[index_of_max(weights*x-b)],  max(weights*x-b))
        !*/

        result_type operator() (
            const sample_type& x
        ) const;
        /*!
            requires
                - weights.size() > 0
                - weights.nr() == number_of_classes() == b.size()
                - if (x is a dense vector, i.e. a dlib::matrix) then
                    - is_vector(x) == true
                    - x.size() == weights.nc()
                      (i.e. it must be legal to multiply weights with x)
            ensures
                - Returns the predicted label for the x sample.  In particular, it returns
                  the following:
                    labels[index_of_max(weights*x-b)]
                  Or in other words, this function returns predict(x).first
        !*/
    };

    template <
        typename K,
        typename result_type_
        >
    void serialize (
        const multiclass_linear_decision_function<K,result_type_>& item,
        std::ostream& out
    );
    /*!
        provides serialization support for multiclass_linear_decision_function
    !*/

    template <
        typename K,
        typename result_type_
        >
    void deserialize (
        multiclass_linear_decision_function<K,result_type_>& item,
        std::istream& in
    );
    /*!
        provides serialization support for multiclass_linear_decision_function
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SVm_FUNCTION_ABSTRACT_


dlib C++ Library - graph_labeler_abstract.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_GRAPH_LaBELER_ABSTRACT_Hh_
#ifdef DLIB_GRAPH_LaBELER_ABSTRACT_Hh_

#include "find_max_factor_graph_potts_abstract.h"
#include "../graph/graph_kernel_abstract.h"
#include "../matrix/matrix_abstract.h"
#include <vector>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type
        >
    class graph_labeler
    {
        /*!
            REQUIREMENTS ON vector_type
                - vector_type is a dlib::matrix capable of representing column
                  vectors or it is a sparse vector type as defined in dlib/svm/sparse_vector_abstract.h.

            WHAT THIS OBJECT REPRESENTS
                This object is a tool for labeling each node in a graph with a value
                of true or false, subject to a labeling consistency constraint between
                nodes that share an edge.  In particular, this object is useful for
                representing a graph labeling model learned via some machine learning
                method.

                To elaborate, suppose we have a graph we want to label.  Moreover,
                suppose we can assign a score to each node which represents how much
                we want to label the node as true, and we also have scores for each
                edge which represent how much we wanted the nodes sharing the edge to
                have the same label.  If we could do this then we could find the optimal
                labeling using the find_max_factor_graph_potts() routine.  Therefore,
                the graph_labeler is just an object which contains the necessary data
                to compute these score functions and then call find_max_factor_graph_potts().
                Additionally, this object uses linear functions to represent these score
                functions.

            THREAD SAFETY
                It is always safe to use distinct instances of this object in different
                threads.  However, when a single instance is shared between threads then
                the following rules apply:
                    It is safe to call the const members of this object from multiple
                    threads.  This is because the const members are purely read-only
                    operations.  However, any operation that modifies a graph_labeler is
                    not threadsafe.
        !*/

    public:

        typedef std::vector<bool> label_type;
        typedef label_type result_type;

        graph_labeler(
        );
        /*!
            ensures
                - this object is properly initialized
                - #get_node_weights() == an initial value of type vector_type.
                - #get_edge_weights() == an initial value of type vector_type.
        !*/

        graph_labeler(
            const vector_type& edge_weights,
            const vector_type& node_weights
        );
        /*!
            requires
                - min(edge_weights) >= 0
            ensures
                - #get_edge_weights() == edge_weights
                - #get_node_weights() == node_weights
        !*/

        const vector_type& get_edge_weights (
        ) const;
        /*!
            ensures
                - Recall that the score function for an edge is a linear function of
                  the vector stored at that edge.  This means there is some vector, E,
                  which we dot product with the vector in the graph to compute the
                  score.  Therefore, this function returns that E vector which defines
                  the edge score function.
        !*/

        const vector_type& get_node_weights (
        ) const;
        /*!
            ensures
                - Recall that the score function for a node is a linear function of
                  the vector stored in that node.  This means there is some vector, W,
                  which we dot product with the vector in the graph to compute the score.
                  Therefore, this function returns that W vector which defines the node
                  score function.
        !*/

        template <typename graph_type>
        void operator() (
            const graph_type& sample,
            std::vector<bool>& labels
        ) const;
        /*!
            requires
                - graph_type is an implementation of dlib/graph/graph_kernel_abstract.h
                - graph_type::type and graph_type::edge_type must be either matrix objects
                  capable of representing column vectors or some kind of sparse vector
                  type as defined in dlib/svm/sparse_vector_abstract.h.
                - graph_contains_length_one_cycle(sample) == false
                - for all valid i and j:
                    - min(edge(sample,i,j)) >= 0
                    - it must be legal to call dot(edge(sample,i,j), get_edge_weights())
                    - it must be legal to call dot(sample.node(i).data, get_node_weights())
            ensures
                - Computes a labeling for each node in the given graph and stores the result
                  in #labels.
                - #labels.size() == sample.number_of_nodes()
                - for all valid i:
                    - #labels[i] == the label of the node sample.node(i).
                - The labels are computed by creating a graph, G, with scalar values on each node
                  and edge.  The scalar values are calculated according to the following:
                    - for all valid i:
                        - G.node(i).data == dot(get_node_weights(), sample.node(i).data)
                    - for all valid i and j:
                        - edge(G,i,j) == dot(get_edge_weights(), edge(sample,i,j))
                  Then the labels are computed by calling find_max_factor_graph_potts(G,#labels).
        !*/

        template <typename graph_type>
        std::vector<bool> operator() (
            const graph_type& sample
        ) const;
        /*!
            requires
                - graph_type is an implementation of dlib/graph/graph_kernel_abstract.h
                - graph_contains_length_one_cycle(sample) == false
                - for all valid i and j:
                    - min(edge(sample,i,j)) >= 0
                    - it must be legal to call dot(edge(sample,i,j), get_edge_weights())
                    - it must be legal to call dot(sample.node(i).data, get_node_weights())
            ensures
                - Performs (*this)(sample, labels); return labels;
                  (i.e. This is just another version of the above operator() routine
                  but instead of returning the labels via the second argument, it
                  returns them as the normal return value).
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type
        >
    void serialize (
        const graph_labeler<vector_type>& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type
        >
    void deserialize (
        graph_labeler<vector_type>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_GRAPH_LaBELER_ABSTRACT_Hh_


dlib C++ Library - one_vs_all_decision_function_abstract.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_ONE_VS_ALL_DECISION_FUnCTION_ABSTRACT_Hh_
#ifdef DLIB_ONE_VS_ALL_DECISION_FUnCTION_ABSTRACT_Hh_

#include "../serialize.h"
#include <map>
#include "../any/any_decision_function_abstract.h"
#include "one_vs_all_trainer_abstract.h"
#include "null_df.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename one_vs_all_trainer,
        typename DF1 = null_df, typename DF2 = null_df, typename DF3 = null_df,
        typename DF4 = null_df, typename DF5 = null_df, typename DF6 = null_df,
        typename DF7 = null_df, typename DF8 = null_df, typename DF9 = null_df,
        typename DF10 = null_df
        >
    class one_vs_all_decision_function
    {
        /*!
            REQUIREMENTS ON one_vs_all_trainer
                This should be an instantiation of the one_vs_all_trainer template.
                It is used to infer which types are used for various things, such as
                representing labels.

            REQUIREMENTS ON DF*
                These types can either be left at their default values or set
                to any kind of decision function object capable of being
                stored in an any_decision_function<sample_type,scalar_type>
                object.  These types should also be serializable.

            WHAT THIS OBJECT REPRESENTS
                This object represents a multiclass classifier built out of a set of
                binary classifiers.  Each binary classifier is used to vote for the
                correct multiclass label using a one vs. all strategy.  Therefore,
                if you have N classes then there will be N binary classifiers inside
                this object.

                Note that the DF* template arguments are only used if you want
                to serialize and deserialize one_vs_all_decision_function objects.
                Specifically, all the types of binary decision function contained
                within a one_vs_all_decision_function must be listed in the
                template arguments if serialization and deserialization is to
                be used.

            THREAD SAFETY
                It is always safe to use distinct instances of this object in different
                threads.  However, when a single instance is shared between threads then
                the following rules apply:
                    It is safe to call the const members of this object from multiple
                    threads so long as all the decision functions contained in this object
                    are also threadsafe.  This is because the const members are purely
                    read-only operations.  However, any operation that modifies a
                    one_vs_all_decision_function is not threadsafe.
        !*/
    public:

        typedef typename one_vs_all_trainer::label_type result_type;
        typedef typename one_vs_all_trainer::sample_type sample_type;
        typedef typename one_vs_all_trainer::scalar_type scalar_type;
        typedef typename one_vs_all_trainer::mem_manager_type mem_manager_type;

        typedef std::map<result_type, any_decision_function<sample_type, scalar_type> > binary_function_table;

        one_vs_all_decision_function(
        );
        /*!
            ensures
                - #number_of_classes() == 0
                - #get_binary_decision_functions().size() == 0
                - #get_labels().size() == 0
        !*/

        explicit one_vs_all_decision_function(
            const binary_function_table& decision_functions
        );
        /*!
            ensures
                - #get_binary_decision_functions() == decision_functions
                - #get_labels() == a list of all the labels which appear in the
                  given set of decision functions
                - #number_of_classes() == #get_labels().size()
        !*/

        template <
            typename df1, typename df2, typename df3, typename df4, typename df5,
            typename df6, typename df7, typename df8, typename df9, typename df10
            >
        one_vs_all_decision_function (
            const one_vs_all_decision_function<one_vs_all_trainer,
                                               df1, df2, df3, df4, df5,
                                               df6, df7, df8, df9, df10>& item
        );
        /*!
            ensures
                - #*this will be a copy of item
                - #number_of_classes() == item.number_of_classes()
                - #get_labels() == item.get_labels()
                - #get_binary_decision_functions() == item.get_binary_decision_functions()
        !*/

        const binary_function_table& get_binary_decision_functions (
        ) const;
        /*!
            ensures
                - returns the table of binary decision functions used by this
                  object.  The label given to a test sample is computed by
                  determining which binary decision function has the largest
                  (i.e. most positive) output and returning the label associated
                  with that decision function.
        !*/

        const std::vector<result_type> get_labels (
        ) const;
        /*!
            ensures
                - returns a vector containing all the labels which can be
                  predicted by this object.
        !*/

        unsigned long number_of_classes (
        ) const;
        /*!
            ensures
                - returns get_labels().size()
                  (i.e. returns the number of different labels/classes predicted by
                  this object)
        !*/

        std::pair<result_type, scalar_type> predict (
            const sample_type& sample
        ) const;
        /*!
            requires
                - number_of_classes() != 0
            ensures
                - Evaluates all the decision functions in get_binary_decision_functions()
                  and returns the predicted label and score for the input sample.  That is,
                  returns std::make_pair(label,score)
                - The label is determined by whichever classifier outputs the largest
                  score.
        !*/

        result_type operator() (
            const sample_type& sample
        ) const
        /*!
            requires
                - number_of_classes() != 0
            ensures
                - Evaluates all the decision functions in get_binary_decision_functions()
                  and returns the predicted label.  That is, returns predict(sample).first.
        !*/
    };

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename DF1, typename DF2, typename DF3,
        typename DF4, typename DF5, typename DF6,
        typename DF7, typename DF8, typename DF9,
        typename DF10
        >
    void serialize(
        const one_vs_all_decision_function<T,DF1,DF2,DF3,DF4,DF5,DF6,DF7,DF8,DF9,DF10>& item,
        std::ostream& out
    );
    /*!
        ensures
            - writes the given item to the output stream out.
        throws
            - serialization_error.
              This is thrown if there is a problem writing to the ostream or if item
              contains a type of decision function not listed among the DF* template
              arguments.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename DF1, typename DF2, typename DF3,
        typename DF4, typename DF5, typename DF6,
        typename DF7, typename DF8, typename DF9,
        typename DF10
        >
    void deserialize(
        one_vs_all_decision_function<T,DF1,DF2,DF3,DF4,DF5,DF6,DF7,DF8,DF9,DF10>& item,
        std::istream& in
    );
    /*!
        ensures
            - deserializes a one_vs_all_decision_function from in and stores it in item.
        throws
            - serialization_error.
              This is thrown if there is a problem reading from the istream or if the
              serialized data contains decision functions not listed among the DF*
              template arguments.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_ONE_VS_ALL_DECISION_FUnCTION_ABSTRACT_Hh_


dlib C++ Library - one_vs_one_decision_function_abstract.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_ONE_VS_ONE_DECISION_FUnCTION_ABSTRACT_Hh_
#ifdef DLIB_ONE_VS_ONE_DECISION_FUnCTION_ABSTRACT_Hh_

#include "../serialize.h"
#include <map>
#include "../any/any_decision_function_abstract.h"
#include "../unordered_pair.h"
#include "one_vs_one_trainer_abstract.h"
#include "null_df.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename one_vs_one_trainer,
        typename DF1 = null_df, typename DF2 = null_df, typename DF3 = null_df,
        typename DF4 = null_df, typename DF5 = null_df, typename DF6 = null_df,
        typename DF7 = null_df, typename DF8 = null_df, typename DF9 = null_df,
        typename DF10 = null_df
        >
    class one_vs_one_decision_function
    {
        /*!
            REQUIREMENTS ON one_vs_one_trainer
                This should be an instantiation of the one_vs_one_trainer template.
                It is used to infer which types are used for various things, such as
                representing labels.

            REQUIREMENTS ON DF*
                These types can either be left at their default values or set
                to any kind of decision function object capable of being
                stored in an any_decision_function<sample_type,scalar_type>
                object.  These types should also be serializable.

            WHAT THIS OBJECT REPRESENTS
                This object represents a multiclass classifier built out
                of a set of binary classifiers.  Each binary classifier
                is used to vote for the correct multiclass label using a
                one vs. one strategy.  Therefore, if you have N classes then
                there will be N*(N-1)/2 binary classifiers inside this object.

                Note that the DF* template arguments are only used if you want
                to serialize and deserialize one_vs_one_decision_function objects.
                Specifically, all the types of binary decision function contained
                within a one_vs_one_decision_function must be listed in the
                template arguments if serialization and deserialization is to
                be used.

            THREAD SAFETY
                It is always safe to use distinct instances of this object in different
                threads.  However, when a single instance is shared between threads then
                the following rules apply:
                    It is safe to call the const members of this object from multiple
                    threads so long as all the decision functions contained in this object
                    are also threadsafe.  This is because the const members are purely
                    read-only operations.  However, any operation that modifies a
                    one_vs_one_decision_function is not threadsafe.
        !*/
    public:

        typedef typename one_vs_one_trainer::label_type result_type;
        typedef typename one_vs_one_trainer::sample_type sample_type;
        typedef typename one_vs_one_trainer::scalar_type scalar_type;
        typedef typename one_vs_one_trainer::mem_manager_type mem_manager_type;

        typedef std::map<unordered_pair<result_type>, any_decision_function<sample_type, scalar_type> > binary_function_table;

        one_vs_one_decision_function(
        );
        /*!
            ensures
                - #number_of_classes() == 0
                - #get_binary_decision_functions().size() == 0
                - #get_labels().size() == 0
        !*/

        explicit one_vs_one_decision_function(
            const binary_function_table& decision_functions
        );
        /*!
            requires
                - find_missing_pairs(decision_functions).size() == 0
                  (i.e. all pairs of labels have an associated decision function)
            ensures
                - #get_binary_decision_functions() == decision_functions
                - #get_labels() == a list of all the labels which appear in the
                  given set of decision functions
                - #number_of_classes() == #get_labels().size()
        !*/

        template <
            typename df1, typename df2, typename df3, typename df4, typename df5,
            typename df6, typename df7, typename df8, typename df9, typename df10
            >
        one_vs_one_decision_function (
            const one_vs_one_decision_function<one_vs_one_trainer,
                                               df1, df2, df3, df4, df5,
                                               df6, df7, df8, df9, df10>& item
        );
        /*!
            ensures
                - #*this will be a copy of item
                - #number_of_classes() == item.number_of_classes()
                - #get_labels() == item.get_labels()
                - #get_binary_decision_functions() == item.get_binary_decision_functions()
        !*/

        const binary_function_table& get_binary_decision_functions (
        ) const;
        /*!
            ensures
                - returns the table of binary decision functions used by this
                  object.  The correspondence between binary decision functions
                  and multiclass labels is the following:
                    - for each element i of get_binary_decision_functions()
                        - i->first == the label pair associated with binary decision
                          function i->second.
                        - if (decision function i->second outputs a value > 0) then
                            - i->second is indicating that a test sample should
                              receive a label of i->first.first
                        - else
                            - i->second is indicating that a test sample should
                              receive a label of i->first.second
        !*/

        const std::vector<result_type> get_labels (
        ) const;
        /*!
            ensures
                - returns a vector containing all the labels which can be
                  predicted by this object.
        !*/

        unsigned long number_of_classes (
        ) const;
        /*!
            ensures
                - returns get_labels().size()
                  (i.e. returns the number of different labels/classes predicted by
                  this object)
        !*/

        result_type operator() (
            const sample_type& sample
        ) const
        /*!
            requires
                - number_of_classes() != 0
            ensures
                - evaluates all the decision functions in get_binary_decision_functions()
                  and returns the label which received the most votes.
        !*/
    };

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename DF1, typename DF2, typename DF3,
        typename DF4, typename DF5, typename DF6,
        typename DF7, typename DF8, typename DF9,
        typename DF10
        >
    void serialize(
        const one_vs_one_decision_function<T,DF1,DF2,DF3,DF4,DF5,DF6,DF7,DF8,DF9,DF10>& item,
        std::ostream& out
    );
    /*!
        ensures
            - writes the given item to the output stream out.
        throws
            - serialization_error.
              This is thrown if there is a problem writing to the ostream or if item
              contains a type of decision function not listed among the DF* template
              arguments.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename DF1, typename DF2, typename DF3,
        typename DF4, typename DF5, typename DF6,
        typename DF7, typename DF8, typename DF9,
        typename DF10
        >
    void deserialize(
        one_vs_one_decision_function<T,DF1,DF2,DF3,DF4,DF5,DF6,DF7,DF8,DF9,DF10>& item,
        std::istream& in
    );
    /*!
        ensures
            - deserializes a one_vs_one_decision_function from in and stores it in item.
        throws
            - serialization_error.
              This is thrown if there is a problem reading from the istream or if the
              serialized data contains decision functions not listed among the DF*
              template arguments.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_ONE_VS_ONE_DECISION_FUnCTION_ABSTRACT_Hh_


dlib C++ Library - approximate_linear_models_abstract.h

// Copyright (C) 2015  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_APPROXIMATE_LINEAR_MODELS_ABSTRACT_Hh_
#ifdef DLIB_APPROXIMATE_LINEAR_MODELS_ABSTRACT_Hh_

#include "../matrix.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    struct example_feature_extractor
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object defines the interface a feature extractor must implement if it
                is to be used with the process_sample and policy objects defined at the
                bottom of this file.  Moreover, it is meant to represent the core part
                of a model used in a reinforcement learning algorithm.

                In particular, this object models a Q(state,action) function where
                    Q(state,action) == dot(w, PSI(state,action))
                    where PSI(state,action) is a feature vector and w is a parameter
                    vector.

                Therefore, a feature extractor defines how the PSI(x,y) feature vector is
                calculated.  It also defines the types used to represent the state and
                action objects.

            THREAD SAFETY
                Instances of this object are required to be threadsafe, that is, it should
                be safe for multiple threads to make concurrent calls to the member
                functions of this object.
        !*/

        // The state and actions can be any types so long as you provide typedefs for them.
        typedef T state_type;
        typedef U action_type;
        // We can also say that the last element in the weight vector w must be 1.  This
        // can be useful for including a prior into your model.
        const static bool force_last_weight_to_1 = false;

        example_feature_extractor(
        );
        /*!
            ensures
                - this object is properly initialized.
        !*/

        unsigned long num_features(
        ) const;
        /*!
            ensures
                - returns the dimensionality of the PSI() feature vector.
        !*/

        action_type find_best_action (
            const state_type& state,
            const matrix<double,0,1>& w
        ) const;
        /*!
            ensures
                - returns the action A that maximizes Q(state,A) = dot(w,PSI(state,A)).
                  That is, this function finds the best action to take in the given state
                  when our model is parameterized by the given weight vector w.
        !*/

        void get_features (
            const state_type& state,
            const action_type& action,
            matrix<double,0,1>& feats
        ) const;
        /*!
            ensures
                - #feats.size() == num_features()
                - #feats == PSI(state,action)
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    struct process_sample
    {
        /*!
            REQUIREMENTS ON feature_extractor
                feature_extractor should implement the example_feature_extractor interface
                defined at the top of this file.

            WHAT THIS OBJECT REPRESENTS
                This object holds a training sample for a reinforcement learning algorithm.
                In particular, it should be a sample from some process where the process
                was in state this->state, then took this->action action which resulted in
                receiving this->reward and ending up in the state this->next_state.
        !*/

        typedef feature_extractor feature_extractor_type;
        typedef typename feature_extractor::state_type state_type;
        typedef typename feature_extractor::action_type action_type;

        process_sample(){}

        process_sample(
            const state_type& s,
            const action_type& a,
            const state_type& n,
            const double& r
        ) : state(s), action(a), next_state(n), reward(r) {}

        state_type  state;
        action_type action;
        state_type  next_state;
        double reward;
    };

    template < typename feature_extractor >
    void serialize (const process_sample<feature_extractor>& item, std::ostream& out);
    template < typename feature_extractor >
    void deserialize (process_sample<feature_extractor>& item, std::istream& in);
    /*!
        provides serialization support.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    class policy
    {
        /*!
            REQUIREMENTS ON feature_extractor
                feature_extractor should implement the example_feature_extractor interface
                defined at the top of this file.

            WHAT THIS OBJECT REPRESENTS
                This is a policy based on the supplied feature_extractor model.  In
                particular, it maps from feature_extractor::state_type to the best action
                to take in that state.
        !*/

    public:

        typedef feature_extractor feature_extractor_type;
        typedef typename feature_extractor::state_type state_type;
        typedef typename feature_extractor::action_type action_type;

        policy (
        );
        /*!
            ensures
                - #get_feature_extractor() == feature_extractor()
                  (i.e. it will have its default value)
                - #get_weights().size() == #get_feature_extractor().num_features()
                - #get_weights() == 0
        !*/

        policy (
            const matrix<double,0,1>& weights,
            const feature_extractor& fe
        );
        /*!
            requires
                - fe.num_features() == weights.size()
            ensures
                - #get_feature_extractor() == fe
                - #get_weights() == weights
        !*/

        action_type operator() (
            const state_type& state
        ) const;
        /*!
            ensures
                - returns get_feature_extractor().find_best_action(state,w);
        !*/

        const feature_extractor& get_feature_extractor (
        ) const;
        /*!
            ensures
                - returns the feature extractor used by this object
        !*/

        const matrix<double,0,1>& get_weights (
        ) const;
        /*!
            ensures
                - returns the parameter vector (w) associated with this object.  The length
                  of the vector is get_feature_extractor().num_features().
        !*/

    };

    template < typename feature_extractor >
    void serialize(const policy<feature_extractor>& item, std::ostream& out);
    template < typename feature_extractor >
    void deserialize(policy<feature_extractor>& item, std::istream& in);
    /*!
        provides serialization support.
    !*/

// ----------------------------------------------------------------------------------------

#endif // DLIB_APPROXIMATE_LINEAR_MODELS_ABSTRACT_Hh_


dlib C++ Library - sequence_labeler_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SEQUENCE_LAbELER_ABSTRACT_H_h_
#ifdef DLIB_SEQUENCE_LAbELER_ABSTRACT_H_h_

#include "../matrix.h"
#include <vector>
#include "../optimization/find_max_factor_graph_viterbi_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class example_feature_extractor
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object defines the interface a feature extractor must implement
                if it is to be used with the sequence_labeler defined at the bottom
                of this file.

                The model used by sequence_labeler objects is the following.
                Given an input sequence x, predict an output label sequence y
                such that:
                    y == argmax_Y dot(w, PSI(x,Y))
                    Where w is a parameter vector.

                Therefore, a feature extractor defines how the PSI(x,y) feature vector
                is calculated.  It also defines how many output labels there are as
                well as the order of the model.

                Finally, note that PSI(x,y) is a sum of feature vectors, each derived
                from the entire input sequence x but only part of the label sequence y.
                Each of these constituent feature vectors is defined by the get_features()
                method of this class.

            THREAD SAFETY
                Instances of this object are required to be threadsafe, that is, it should
                be safe for multiple threads to make concurrent calls to the member
                functions of this object.
        !*/

    public:
        // This should be the type used to represent an input sequence.  It can be
        // anything so long as it has a .size() which returns the length of the sequence.
        typedef the_type_used_to_represent_a_sequence sequence_type;

        example_feature_extractor (
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        unsigned long num_features (
        ) const;
        /*!
            ensures
                - returns the dimensionality of the PSI() feature vector.
        !*/

        unsigned long order(
        ) const;
        /*!
            ensures
                - This object represents a Markov model on the output labels.
                  This parameter defines the order of the model.  That is, this
                  value controls how many previous label values get to be taken
                  into consideration when performing feature extraction for a
                  particular element of the input sequence.  Note that the runtime
                  of the algorithm is exponential in the order.  So don't make order
                  very large.
        !*/

        unsigned long num_labels(
        ) const;
        /*!
            ensures
                - returns the number of possible output labels.
        !*/

        template <typename EXP>
        bool reject_labeling (
            const sequence_type& x,
            const matrix_exp<EXP>& y,
            unsigned long position
        ) const;
        /*!
            requires
                - EXP::type == unsigned long
                  (i.e. y contains unsigned longs)
                - position < x.size()
                - y.size() == min(position, order()) + 1
                - is_vector(y) == true
                - max(y) < num_labels()
            ensures
                - for all valid i:
                    - interprets y(i) as the label corresponding to x[position-i]
                - if (the labeling in y for x[position] is always the wrong labeling) then
                    - returns true
                      (note that reject_labeling() is just an optional tool to allow you
                      to overrule the normal labeling algorithm.  You don't have to use
                      it.  So if you don't include a reject_labeling() method in your
                      feature extractor it is the same as including one that always
                      returns false.)
                - else
                    - returns 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;
        /*!
            requires
                - EXP::type == unsigned long
                  (i.e. y contains unsigned longs)
                - reject_labeling(x,y,position) == false
                - position < x.size()
                - y.size() == min(position, order()) + 1
                - is_vector(y) == true
                - max(y) < num_labels()
                - set_feature is a function object which allows expressions of the form:
                    - set_features((unsigned long)feature_index, (double)feature_value);
                    - set_features((unsigned long)feature_index);
            ensures
                - for all valid i:
                    - interprets y(i) as the label corresponding to x[position-i]
                - This function computes the part of PSI() corresponding to the x[position]
                  element of the input sequence.  Moreover, this part of PSI() is returned as
                  a sparse vector by invoking set_feature().  For example, to set the feature
                  with an index of 55 to the value of 1 this method would call:
                    set_feature(55);
                  Or equivalently:
                    set_feature(55,1);
                  Therefore, the first argument to set_feature is the index of the feature
                  to be set while the second argument is the value the feature should take.
                  Additionally, note that calling set_feature() multiple times with the same
                  feature index does NOT overwrite the old value, it adds to the previous
                  value.  For example, if you call set_feature(55) 3 times then it will
                  result in feature 55 having a value of 3.
                - This function only calls set_feature() with feature_index values < num_features()
        !*/

        unsigned long num_nonnegative_weights (
        ) const;
        /*!
            ensures
                - returns the number of elements of the w parameter vector which should be
                  non-negative.  That is, this feature extractor is intended to be used
                  with w vectors where the first num_nonnegative_weights() elements of w
                  are >= 0.  That is, it should be the case that w(i) >= 0 for all i <
                  num_nonnegative_weights().
                - Note that num_nonnegative_weights() is just an optional method to allow
                  you to tell a tool like the structural_sequence_labeling_trainer that the
                  learned w should have a certain number of non-negative elements.
                  Therefore, if you do not provide a num_nonnegative_weights() method in
                  your feature extractor then it will default to a value of 0, indicating
                  that all elements of the w parameter vector may be any value.
        !*/

    };

// ----------------------------------------------------------------------------------------

    void serialize(
        const example_feature_extractor& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

    void deserialize(
        example_feature_extractor& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    bool contains_invalid_labeling (
        const feature_extractor& fe,
        const typename feature_extractor::sequence_type& x,
        const std::vector<unsigned long>& y
    );
    /*!
        requires
            - feature_extractor must be an object that implements an interface compatible
              with the example_feature_extractor discussed above.
        ensures
            - if (x.size() != y.size() ||
                fe.reject_labeling() rejects any of the labels in y) then
                - returns true
            - else
                - returns false
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    bool contains_invalid_labeling (
        const feature_extractor& fe,
        const std::vector<typename feature_extractor::sequence_type>& x,
        const std::vector<std::vector<unsigned long> >& y
    );
    /*!
        requires
            - feature_extractor must be an object that implements an interface compatible
              with the example_feature_extractor discussed above.
        ensures
            - if (x.size() != y.size() ||
                contains_invalid_labeling(fe,x[i],y[i]) == true for some i ) then
                - returns true
            - else
                - returns false
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    class sequence_labeler
    {
        /*!
            REQUIREMENTS ON feature_extractor
                It must be an object that implements an interface compatible with
                the example_feature_extractor discussed above.

            WHAT THIS OBJECT REPRESENTS
                This object is a tool for doing sequence labeling.  In particular, it is
                capable of representing sequence labeling models such as those produced by
                Hidden Markov SVMs or Chain Structured Conditional Random fields.  See the
                following papers for an introduction to these techniques:
                    - Hidden Markov Support Vector Machines by
                      Y. Altun, I. Tsochantaridis, T. Hofmann
                    - Shallow Parsing with Conditional Random Fields by
                      Fei Sha and Fernando Pereira

                The model used by this object is the following.  Given
                an input sequence x, predict an output label sequence y
                such that:
                    y == argmax_Y dot(get_weights(), PSI(x,Y))
                    Where PSI() is defined by the feature_extractor template
                    argument.

            THREAD SAFETY
                It is always safe to use distinct instances of this object in different
                threads.  However, when a single instance is shared between threads then
                the following rules apply:
                    It is safe to call the const members of this object from multiple
                    threads so long as the feature_extractor is also threadsafe.  This is
                    because the const members are purely read-only operations.  However,
                    any operation that modifies a sequence_labeler is not threadsafe.
        !*/

    public:
        typedef typename feature_extractor::sequence_type sample_sequence_type;
        typedef std::vector<unsigned long> labeled_sequence_type;

        sequence_labeler(
        );
        /*!
            ensures
                - #get_feature_extractor() == feature_extractor()
                  (i.e. it will have its default value)
                - #get_weights().size() == #get_feature_extractor().num_features()
                - #get_weights() == 0
        !*/

        explicit sequence_labeler(
            const matrix<double,0,1>& weights
        );
        /*!
            requires
                - feature_extractor().num_features() == weights.size()
            ensures
                - #get_feature_extractor() == feature_extractor()
                  (i.e. it will have its default value)
                - #get_weights() == weights
        !*/

        sequence_labeler(
            const matrix<double,0,1>& weights,
            const feature_extractor& fe
        );
        /*!
            requires
                - fe.num_features() == weights.size()
            ensures
                - #get_feature_extractor() == fe
                - #get_weights() == weights
        !*/

        const feature_extractor& get_feature_extractor (
        ) const;
        /*!
            ensures
                - returns the feature extractor used by this object
        !*/

        const matrix<double,0,1>& get_weights (
        ) const;
        /*!
            ensures
                - returns the parameter vector associated with this sequence labeler.
                  The length of the vector is get_feature_extractor().num_features().
        !*/

        unsigned long num_labels (
        ) const;
        /*!
            ensures
                - returns get_feature_extractor().num_labels()
                  (i.e. returns the number of possible output labels for each
                  element of a sequence)
        !*/

        labeled_sequence_type operator() (
            const sample_sequence_type& x
        ) const;
        /*!
            requires
                - num_labels() > 0
            ensures
                - returns a vector Y of label values such that:
                    - Y.size() == x.size()
                    - for all valid i:
                        - Y[i] == the predicted label for x[i]
                        - 0 <= Y[i] < num_labels()
        !*/

        void label_sequence (
            const sample_sequence_type& x,
            labeled_sequence_type& y
        ) const;
        /*!
            requires
                - num_labels() > 0
            ensures
                - #y == (*this)(x)
                  (i.e. This is just another interface to the operator() routine
                  above.  This one avoids returning the results by value and therefore
                  might be a little faster in some cases)
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    void serialize (
        const sequence_labeler<feature_extractor>& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    void deserialize (
        sequence_labeler<feature_extractor>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SEQUENCE_LAbELER_ABSTRACT_H_h_


dlib C++ Library - sequence_segmenter_abstract.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SEQUENCE_SeGMENTER_ABSTRACT_H_h_
#ifdef DLIB_SEQUENCE_SeGMENTER_ABSTRACT_H_h_

#include "../matrix.h"
#include <vector>
#include "sequence_labeler_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class example_feature_extractor
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object defines the interface a feature extractor must implement if it
                is to be used with the sequence_segmenter defined at the bottom of this
                file.

                The model used by sequence_segmenter objects is the following.  Given an
                input sequence x, predict an output label sequence y such that:
                    y == argmax_Y dot(w, PSI(x,Y))
                Where w is a parameter vector and the label sequence defines a segmentation
                of x.

                Recall that a sequence_segmenter uses the BIO or BILOU tagging model and is
                also an instantiation of the dlib::sequence_labeler.  Selecting to use the
                BIO model means that each element of the label sequence y takes on one of
                three possible values (B, I, or O) and together these labels define a
                segmentation of the sequence.  For example, to represent a segmentation of
                the sequence of words "The dog ran to Bob Jones" where only "Bob Jones" was
                segmented out we would use the label sequence OOOOBI.  The BILOU model is
                similar except that it uses five different labels and each segment is
                labeled as U, BL, BIL, BIIL, BIIIL, and so on depending on its length.
                Therefore, the BILOU model is able to more explicitly model the ends of the
                segments than the BIO model, but has more parameters to estimate.

                Keeping all this in mind, the purpose of a sequence_segmenter is to take
                care of the bookkeeping associated with creating BIO/BILOU tagging models
                for segmentation tasks.  In particular, it presents the user with a
                simplified version of the interface used by the dlib::sequence_labeler.  It
                does this by completely hiding the BIO/BILOU tags from the user and instead
                exposes an explicit sub-segment based labeling representation.  It also
                simplifies the construction of the PSI() feature vector.

                Like in the dlib::sequence_labeler, PSI() is a sum of feature vectors, each
                derived from the entire input sequence x but only part of the label
                sequence y.  In the case of the sequence_segmenter, we use an order one
                Markov model.  This means that
                    PSI(x,y) == sum_i XI(x, y_{i-1}, y_{i}, i)
                where the sum is taken over all the elements in the sequence.  At each
                element we extract a feature vector, XI(), that is expected to encode
                important details describing what the i-th position of the sequence looks
                like in the context of the current and previous labels.  To do this, XI()
                is allowed to look at any part of the input sequence x, the current and
                previous labels, and of course it must also know the position in question, i.

                The sequence_segmenter simplifies this further by decomposing XI() into
                components which model the current window around each position as well as
                the conjunction of the current window around each position and the previous
                label.  In particular, the sequence_segmenter only asks a user to provide a
                single feature vector which characterizes a position of the sequence
                independent of any labeling.  We denote this feature vector by ZI(x,i), where
                x is the sequence and i is the position in question.

                For example, suppose we use a window size of 3 and BIO tags, then we can
                put all this together and define XI() in terms of ZI().  To do this, we can
                think of XI() as containing 12*3 slots which contain either a zero vector
                or a ZI() vector.  Each combination of window position and labeling has a
                different slot.  To explain further, consider the following examples where
                we have annotated which parts of XI() correspond to each slot.

                If the previous and current label are both B and we use a window size of 3
                then XI() would be instantiated as:
                    XI(x, B, B, i) = [ZI(x,i-1)  \
                                      ZI(x,i)     > If current label is B
                                      ZI(x,i+1)  /
                                      0          \
                                      0           > If current label is I
                                      0          /
                                      0          \
                                      0           > If current label is O
                                      0          /

                                      ZI(x,i-1)  \
                                      ZI(x,i)     > If previous label is B and current label is B
                                      ZI(x,i+1)  /
                                      0          \
                                      0           > If previous label is B and current label is I
                                      0          /
                                      0          \
                                      0           > If previous label is B and current label is O
                                      0          /

                                      0          \
                                      0           > If previous label is I and current label is B
                                      0          /
                                      0          \
                                      0           > If previous label is I and current label is I
                                      0          /
                                      0          \
                                      0           > If previous label is I and current label is O
                                      0          /

                                      0          \
                                      0           > If previous label is O and current label is B
                                      0          /
                                      0          \
                                      0           > If previous label is O and current label is I
                                      0          /
                                      0          \
                                      0           > If previous label is O and current label is O
                                      0]         /

                If the previous label is I and the current label is O and we use a window
                size of 3 then XI() would be instantiated as:
                    XI(x, I, O, i) = [0          \
                                      0           > If current label is B
                                      0          /
                                      0          \
                                      0           > If current label is I
                                      0          /
                                      ZI(x,i-1)  \
                                      ZI(x,i)     > If current label is O
                                      ZI(x,i+1)  /

                                      0          \
                                      0           > If previous label is B and current label is B
                                      0          /
                                      0          \
                                      0           > If previous label is B and current label is I
                                      0          /
                                      0          \
                                      0           > If previous label is B and current label is O
                                      0          /

                                      0          \
                                      0           > If previous label is I and current label is B
                                      0          /
                                      0          \
                                      0           > If previous label is I and current label is I
                                      0          /
                                      ZI(x,i-1)  \
                                      ZI(x,i)     > If previous label is I and current label is O
                                      ZI(x,i+1)  /

                                      0          \
                                      0           > If previous label is O and current label is B
                                      0          /
                                      0          \
                                      0           > If previous label is O and current label is I
                                      0          /
                                      0          \
                                      0           > If previous label is O and current label is O
                                      0]         /

                    If we had instead used the BILOU tagging model the XI() vector would
                    have been similarly defined except that there would be 30*3 slots for
                    the various label combination instead of 12*3.

                    Finally, while not shown here, we also include indicator features in
                    XI() to model label transitions and individual label biases.  These are
                    12 extra features in the case of the BIO tagging model and 30 extra in
                    the case of the BILOU tagging model.

            THREAD SAFETY
                Instances of this object are required to be threadsafe, that is, it should
                be safe for multiple threads to make concurrent calls to the member
                functions of this object.
        !*/

    public:
        // This should be the type used to represent an input sequence.  It can be
        // anything so long as it has a .size() which returns the length of the sequence.
        typedef the_type_used_to_represent_a_sequence sequence_type;

        // If you want to use the BIO tagging model then set this bool to true.  Set it to
        // false to use the BILOU tagging model.
        const static bool use_BIO_model = true;

        // In the WHAT THIS OBJECT REPRESENTS section above we discussed how we model the
        // conjunction of the previous label and the window around each position.  Doing
        // this greatly expands the size of the parameter vector w.  You can optionally
        // disable these higher order features by setting the use_high_order_features bool
        // to false.  This will cause XI() to include only slots which are independent of
        // the previous label.
        const static bool use_high_order_features = true;

        // You use a tool like the structural_sequence_segmentation_trainer to learn the weight
        // vector needed by a sequence_segmenter.  You can tell the trainer to force all the
        // elements of the weight vector corresponding to ZI() to be non-negative.  This is all
        // the elements of w except for the elements corresponding to the label transition and
        // bias indicator features.  To do this, just set allow_negative_weights to false.
        const static bool allow_negative_weights = true;

        example_feature_extractor (
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        unsigned long num_features(
        ) const;
        /*!
            ensures
                - returns the dimensionality of the ZI() feature vector.  This number is
                  always >= 1
        !*/

        unsigned long window_size(
        ) const;
        /*!
            ensures
                - returns the size of the window ZI() vectors are extracted from.  This
                  number is always >= 1.
        !*/

        template <typename feature_setter>
        void get_features (
            feature_setter& set_feature,
            const sequence_type& x,
            unsigned long position
        ) const;
        /*!
            requires
                - position < x.size()
                - set_feature is a function object which allows expressions of the form:
                    - set_features((unsigned long)feature_index, (double)feature_value);
                    - set_features((unsigned long)feature_index);
            ensures
                - This function computes the ZI(x,position) feature vector.  This is a
                  feature vector which should capture the properties of x[position] that
                  are informative relative to the sequence segmentation task you are trying
                  to perform.
                - ZI(x,position) is returned as a sparse vector by invoking set_feature().
                  For example, to set the feature with an index of 55 to the value of 1
                  this method would call:
                    set_feature(55);
                  Or equivalently:
                    set_feature(55,1);
                  Therefore, the first argument to set_feature is the index of the feature
                  to be set while the second argument is the value the feature should take.
                  Additionally, note that calling set_feature() multiple times with the
                  same feature index does NOT overwrite the old value, it adds to the
                  previous value.  For example, if you call set_feature(55) 3 times then it
                  will result in feature 55 having a value of 3.
                - This function only calls set_feature() with feature_index values < num_features()
        !*/

    };

// ----------------------------------------------------------------------------------------

    void serialize(
        const example_feature_extractor& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

    void deserialize(
        example_feature_extractor& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    unsigned long total_feature_vector_size (
        const feature_extractor& fe
    );
    /*!
        requires
            - fe must be an object that implements an interface compatible with the
              example_feature_extractor discussed above.
        ensures
            - returns the dimensionality of the PSI() vector defined by the given feature
              extractor.
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    class sequence_segmenter
    {
        /*!
            REQUIREMENTS ON feature_extractor
                It must be an object that implements an interface compatible with
                the example_feature_extractor discussed above.

            WHAT THIS OBJECT REPRESENTS
                This object is a tool for segmenting a sequence of objects into a set of
                non-overlapping chunks.  An example sequence segmentation task is to take
                English sentences and identify all the named entities.  In this example,
                you would be using a sequence_segmenter to find all the chunks of
                contiguous words which refer to proper names.

                Internally, the sequence_segmenter uses the BIO (Begin, Inside, Outside) or
                BILOU (Begin, Inside, Last, Outside, Unit) sequence tagging model.
                Moreover, it is implemented using a dlib::sequence_labeler object and
                therefore sequence_segmenter objects are examples of chain structured
                conditional random field style sequence taggers.

            THREAD SAFETY
                It is always safe to use distinct instances of this object in different
                threads.  However, when a single instance is shared between threads then
                the following rules apply:
                    It is safe to call the const members of this object from multiple
                    threads so long as the feature_extractor is also threadsafe.  This is
                    because the const members are purely read-only operations.  However,
                    any operation that modifies a sequence_segmenter is not threadsafe.
        !*/

    public:
        typedef typename feature_extractor::sequence_type sample_sequence_type;
        typedef std::vector<std::pair<unsigned long, unsigned long> > segmented_sequence_type;

        sequence_segmenter(
        );
        /*!
            ensures
                - #get_feature_extractor() == feature_extractor()
                  (i.e. it will have its default value)
                - #get_weights().size() == total_feature_vector_size(#get_feature_extractor())
                - #get_weights() == 0
        !*/

        explicit sequence_segmenter(
            const matrix<double,0,1>& weights
        );
        /*!
            requires
                - total_feature_vector_size(feature_extractor()) == weights.size()
            ensures
                - #get_feature_extractor() == feature_extractor()
                  (i.e. it will have its default value)
                - #get_weights() == weights
        !*/

        sequence_segmenter(
            const matrix<double,0,1>& weights,
            const feature_extractor& fe
        );
        /*!
            requires
                - total_feature_vector_size(fe) == weights.size()
            ensures
                - #get_feature_extractor() == fe
                - #get_weights() == weights
        !*/

        const feature_extractor& get_feature_extractor (
        ) const;
        /*!
            ensures
                - returns the feature extractor used by this object.
        !*/

        const matrix<double,0,1>& get_weights (
        ) const;
        /*!
            ensures
                - returns the parameter vector associated with this sequence segmenter.
                  The length of the vector is total_feature_vector_size(get_feature_extractor()).
        !*/

        segmented_sequence_type operator() (
            const sample_sequence_type& x
        ) const;
        /*!
            ensures
                - Takes an input sequence and returns a list of detected segments within
                  that sequence.
                - None of the returned segments will overlap.
                - The returned segments are listed in the order they appeared in the input sequence.
                - To be precise, this function returns a std::vector Y of segments such that:
                    - Y.size() == the number of segments detected in the input sequence x.
                    - for all valid i:
                        - Y[i].first  == the start of the i-th segment.
                        - Y[i].second == one past the end of the i-th segment.
                        - Therefore, the i-th detected segment in x is composed of the elements
                          x[Y[i].first], x[Y[i].first+1], ..., x[Y[i].second-1]
                        - Y[i].first < x.size()
                        - Y[i].second <= x.size()
                        - Y[i].first < Y[i].second
                          (i.e. This function never outputs empty segments)
                        - Y[i].second <= Y[i+1].first
                          (i.e. the segments are listed in order of appearance and do not overlap)
        !*/

        void segment_sequence (
            const sample_sequence_type& x,
            segmented_sequence_type& y
        ) const;
        /*!
            ensures
                - #y == (*this)(x)
                  (i.e. This is just another interface to the operator() routine
                  above.  This one avoids returning the results by value and therefore
                  might be a little faster in some cases)
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    void serialize (
        const sequence_segmenter<feature_extractor>& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    void deserialize (
        sequence_segmenter<feature_extractor>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SEQUENCE_SeGMENTER_ABSTRACT_H_h_


dlib C++ Library - track_association_function_abstract.h

// Copyright (C) 2014  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_TRACK_ASSOCiATION_FUNCTION_ABSTRACT_Hh_
#ifdef DLIB_TRACK_ASSOCiATION_FUNCTION_ABSTRACT_Hh_

#include <vector>
#include "assignment_function_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class example_detection
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object defines the interface a detection must implement if it is to be
                used with the track_association_function defined at the bottom of this
                file.  In this case, the interface is very simple.  A detection object is
                only required to define the track_type typedef and it must also be possible
                to store detection objects in a std::vector.
        !*/

    public:
        // Each detection object should be designed to work with a specific track object.
        // This typedef lets us determine which track type is meant for use with this
        // detection object.
        typedef class example_track track_type;

    };

// ----------------------------------------------------------------------------------------

    class example_track
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object defines the interface a track must implement if it is to be
                used with the track_association_function defined at the bottom of this
                file.
        !*/

    public:
        // This type should be a dlib::matrix capable of storing column vectors or an
        // unsorted sparse vector type as defined in dlib/svm/sparse_vector_abstract.h.
        typedef matrix_or_sparse_vector_type feature_vector_type;

        example_track(
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        void get_similarity_features (
            const example_detection& det,
            feature_vector_type& feats
        ) const;
        /*!
            requires
                - update_track() has been called on this track at least once.
            ensures
                - #feats == A feature vector that contains information describing how
                  likely it is that det is a detection from the object corresponding to
                  this track.  That is, the feature vector should contain information that
                  lets someone decide if det should be associated to this track.
                - #feats.size() must be a constant.  That is, every time we call
                  get_similarity_features() it must output a feature vector of the same
                  dimensionality.
        !*/

        void update_track (
            const example_detection& det
        );
        /*!
            ensures
                - Updates this track with the given detection assuming that det is the most
                  current observation of the object under track.
        !*/

        void propagate_track (
        );
        /*!
            ensures
                - propagates this track forward in time one time step.
        !*/
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename detection_type
        >
    class feature_extractor_track_association
    {
        /*!
            REQUIREMENTS ON detection_type
                It must be an object that implements an interface compatible with the
                example_detection discussed above.  This also means that detection_type::track_type
                must be an object that implements an interface compatible with example_track
                defined above.

            WHAT THIS OBJECT REPRESENTS
                This object is an adapter that converts from the detection/track style
                interface defined above to the feature extraction interface required by the
                association rule learning tools in dlib.  Specifically, it converts the
                detection/track interface into a form usable by the assignment_function and
                its trainer object structural_assignment_trainer.
        !*/

    public:
        typedef typename detection_type::track_type track_type;
        typedef typename track_type::feature_vector_type feature_vector_type;
        typedef detection_type lhs_element;
        typedef track_type rhs_element;

        unsigned long num_features(
        ) const;
        /*!
            ensures
                - returns the dimensionality of the feature vectors produced by get_features().
        !*/

        void get_features (
            const detection_type& det,
            const track_type& track,
            feature_vector_type& feats
        ) const;
        /*!
            ensures
                - performs: track.get_similarity_features(det, feats);
        !*/
    };

    template <
        typename detection_type
        >
    void serialize (
        const feature_extractor_track_association<detection_type>& item,
        std::ostream& out
    );
    /*!
        Provides serialization support.
    !*/

    template <
        typename detection_type
        >
    void deserialize (
        feature_extractor_track_association<detection_type>& item,
        std::istream& in
    );
    /*!
        Provides deserialization support.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename detection_type_
        >
    class track_association_function
    {
        /*!
            REQUIREMENTS ON detection_type
                It must be an object that implements an interface compatible with the
                example_detection discussed above.  This also means that detection_type::track_type
                must be an object that implements an interface compatible with example_track
                defined above.

            WHAT THIS OBJECT REPRESENTS
                This object is a tool that helps you implement an object tracker.  So for
                example, if you wanted to track people moving around in a video then this
                object can help.  In particular, imagine you have a tool for detecting the
                positions of each person in an image.  Then you can run this person
                detector on the video and at each time step, i.e. at each frame, you get a
                set of person detections.  However, that by itself doesn't tell you how
                many people there are in the video and where they are moving to and from.
                To get that information you need to figure out which detections match each
                other from frame to frame.  This is where the track_association_function
                comes in.  It performs the detection to track association.  It will also do
                some of the track management tasks like creating a new track when a
                detection doesn't match any of the existing tracks.

                Internally, this object is implemented using the assignment_function object.
                In fact, it's really just a thin wrapper around assignment_function and
                exists just to provide a more convenient interface to users doing detection
                to track association.
        !*/
    public:

        typedef detection_type_ detection_type;
        typedef typename detection_type::track_type track_type;
        typedef assignment_function<feature_extractor_track_association<detection_type> > association_function_type;

        track_association_function(
        );
        /*!
            ensures
                - #get_assignment_function() will be default initialized.
        !*/

        track_association_function (
            const association_function_type& assoc
        );
        /*!
            ensures
                - #get_assignment_function() == assoc
        !*/

        const association_function_type& get_assignment_function (
        ) const;
        /*!
            ensures
                - returns the assignment_function used by this object to assign detections
                  to tracks.
        !*/

        void operator() (
            std::vector<track_type>& tracks,
            const std::vector<detection_type>& dets
        ) const;
        /*!
            ensures
                - This function uses get_assignment_function() to assign each detection
                  in dets to its appropriate track in tracks.  Then each track which
                  associates to a detection is updated by calling update_track() with the
                  associated detection.
                - Detections that don't associate with any of the elements of tracks will
                  spawn new tracks.  For each unassociated detection, this is done by
                  creating a new track_type object, calling update_track() on it with the
                  new detection, and then adding the new track into tracks.
                - Tracks that don't have a detection associate to them are propagated
                  forward in time by calling propagate_track() on them.  That is, we call
                  propagate_track() only on tracks that do not get associated with a
                  detection.
        !*/
    };

    template <
        typename detection_type
        >
    void serialize (
        const track_association_function<detection_type>& item,
        std::ostream& out
    );
    /*!
        Provides serialization support.
    !*/

    template <
        typename detection_type
        >
    void deserialize (
        track_association_function<detection_type>& item,
        std::istream& in
    );
    /*!
        Provides deserialization support.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_TRACK_ASSOCiATION_FUNCTION_ABSTRACT_Hh_


dlib C++ Library - libsvm_io_abstract.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_LIBSVM_iO_ABSTRACT_Hh_
#ifdef DLIB_LIBSVM_iO_ABSTRACT_Hh_

#include <fstream>
#include <string>
#include <utility>
#include "../algs.h"
#include "../matrix.h"
#include <vector>

namespace dlib
{
    struct sample_data_io_error : public error
    {
        /*!
            This is the exception class used by the file IO functions defined below.
        !*/
    };

// ----------------------------------------------------------------------------------------

    template <
        typename sample_type,
        typename label_type,
        typename alloc1,
        typename alloc2
        >
    void load_libsvm_formatted_data (
        const std::string& file_name,
        std::vector<sample_type, alloc1>& samples,
        std::vector<label_type, alloc2>& labels
    );
    /*!
        requires
            - sample_type must be an STL container
            - sample_type::value_type == std::pair<T,U> where T is some kind of
              unsigned integral type
        ensures
            - attempts to read a file of the given name that should contain libsvm
              formatted data.  We turn the data into sparse vectors and store it
              in samples
            - #labels.size() == #samples.size()
            - for all valid i: #labels[i] is the label for #samples[i]
        throws
            - sample_data_io_error
                This exception is thrown if there is any problem loading data from file
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename sample_type,
        typename label_type,
        typename alloc1,
        typename alloc2
        >
    void save_libsvm_formatted_data (
        const std::string& file_name,
        const std::vector<sample_type, alloc1>& samples,
        const std::vector<label_type, alloc2>& labels
    );
    /*!
        requires
            - sample_type must be an STL container
            - sample_type::value_type == std::pair<T,U> where T is some kind of
              unsigned integral type
            - samples.size() == labels.size()
        ensures
            - saves the data to the given file in libsvm format
        throws
            - sample_data_io_error
                This exception is thrown if there is any problem saving data to file
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename sample_type,
        typename label_type,
        typename alloc1,
        typename alloc2
        >
    void save_libsvm_formatted_data (
        const std::string& file_name,
        const std::vector<sample_type, alloc1>& samples,
        const std::vector<label_type, alloc2>& labels
    );
    /*!
        requires
            - sample_type == a dense matrix (i.e. dlib::matrix)
            - for all valid i: is_vector(samples[i]) == true
            - samples.size() == labels.size()
        ensures
            - saves the data to the given file in libsvm format
        throws
            - sample_data_io_error
                This exception is thrown if there is any problem saving data to file
    !*/

// ----------------------------------------------------------------------------------------

    template <typename sample_type, typename alloc>
    void fix_nonzero_indexing (
        std::vector<sample_type,alloc>& samples
    );
    /*!
        requires
            - samples must only contain valid sparse vectors.  The definition of
              a sparse vector can be found at the top of dlib/svm/sparse_vector_abstract.h
        ensures
            - Adjusts the sparse vectors in samples so that they are zero-indexed.
              Or in other words, assume the smallest used index value in any of the sparse
              vectors is N.  Then this function subtracts N from all the index values in
              samples.  This is useful, for example, if you load a libsvm formatted datafile
              with features indexed from 1 rather than 0 and you would like to fix this.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_LIBSVM_iO_ABSTRACT_Hh_


dlib C++ Library - load_image_dataset_abstract.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_LOAD_IMAGE_DaTASET_ABSTRACT_Hh_
#ifdef DLIB_LOAD_IMAGE_DaTASET_ABSTRACT_Hh_

#include "image_dataset_metadata.h"
#include "../array/array_kernel_abstract.h"
#include <string>
#include <vector>
#include "../image_processing/full_object_detection_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class image_dataset_file
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is a tool used to tell the load_image_dataset() functions which
                boxes and images to load from an XML based image dataset file.  By default,
                this object tells load_image_dataset() to load all images and object boxes.
        !*/

    public:
        image_dataset_file(
            const std::string& filename
        );
        /*!
            ensures
                - #get_filename() == filename
                - #should_skip_empty_images() == false
                - #get_selected_box_labels().size() == 0
                  This means that, initially, all boxes will be loaded.  Therefore, for all
                  possible boxes B we have:
                    - #should_load_box(B) == true
        !*/

        const std::string& get_filename(
        ) const;
        /*!
            ensures
                - returns the name of the XML image dataset metadata file given to this
                  object's constructor.
        !*/

        bool should_skip_empty_images(
        ) const;
        /*!
            ensures
                - returns true if we are supposed to skip images that don't have any boxes
                  to load when loading an image dataset using load_image_dataset().
        !*/

        image_dataset_file boxes_match_label(
            const std::string& label
        ) const;
        /*!
            ensures
                - returns a copy of *this that is identical in all respects to *this except
                  that label will be included in the labels set (i.e. the set returned by
                  get_selected_box_labels()).
        !*/

        const std::set<std::string>& get_selected_box_labels(
        ) const;
        /*!
            ensures
                - returns the set of box labels currently selected by the should_load_box()
                  method.  Note that if the set is empty then we select all boxes.
        !*/

        image_dataset_file skip_empty_images(
        ) const;
        /*!
            ensures
                - returns a copy of *this that is identical in all respects to *this except
                  that #should_skip_empty_images() == true.
        !*/

        bool should_boxes_have_parts(
        ) const;
        /*!
            ensures
                - returns true if boxes must have some parts defined for them to be loaded.
        !*/

        image_dataset_file boxes_have_parts(
        ) const;
        /*!
            ensures
                - returns a copy of *this that is identical in all respects to *this except
                  that #should_boxes_have_parts() == true.
        !*/

        bool should_load_box (
            const image_dataset_metadata::box& box
        ) const;
        /*!
            ensures
                - returns true if we are supposed to load the given box from an image
                  dataset XML file.  In particular, if should_load_box() returns false then
                  the load_image_dataset() routines will not return the box at all, neither
                  in the ignore rectangles list or in the primary object_locations vector.
                  The behavior of this function is defined as follows:
                    - if (should_boxes_have_parts() && boxes.parts.size() == 0) then
                        - returns false
                    - else if (get_selected_box_labels().size() == 0) then
                        - returns true
                    - else if (get_selected_box_labels().count(box.label) != 0) then
                        - returns true
                    - else
                        - returns false
        !*/

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename image_type,
        typename MM
        >
    std::vector<std::vector<rectangle> > load_image_dataset (
        array<image_type,MM>& images,
        std::vector<std::vector<rectangle> >& object_locations,
        const image_dataset_file& source
    );
    /*!
        requires
            - image_type == is an implementation of array2d/array2d_kernel_abstract.h
            - pixel_traits<typename image_type::type> is defined
        ensures
            - This routine loads the images and their associated object boxes from the
              image metadata file indicated by source.get_filename().  This metadata file
              should be in the XML format used by the save_image_dataset_metadata() routine.
            - #images.size() == The number of images loaded from the metadata file.  This
              is all the images listed in the file unless source.should_skip_empty_images()
              is set to true.
            - #images.size() == #object_locations.size()
            - This routine is capable of loading any image format which can be read by the
              load_image() routine.
            - let IGNORED_RECTS denote the vector returned from this function.
            - IGNORED_RECTS.size() == #object_locations.size()
            - IGNORED_RECTS == a list of the rectangles which have the "ignore" flag set to
              true in the input XML file.
            - for all valid i:
                - #images[i] == a copy of the i-th image from the dataset.
                - #object_locations[i] == a vector of all the rectangles associated with
                  #images[i].  These are the rectangles for which source.should_load_box()
                  returns true and are also not marked as "ignore" in the XML file.
                - IGNORED_RECTS[i] == A vector of all the rectangles associated with #images[i]
                  that are marked as "ignore" but not discarded by source.should_load_box().
                - if (source.should_skip_empty_images() == true) then
                    - #object_locations[i].size() != 0
                      (i.e. we won't load images that don't end up having any object locations)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type,
        typename MM
        >
    std::vector<std::vector<rectangle> > load_image_dataset (
        array<image_type,MM>& images,
        std::vector<std::vector<rectangle> >& object_locations,
        const std::string& filename
    );
    /*!
        requires
            - image_type == is an implementation of array2d/array2d_kernel_abstract.h
            - pixel_traits<typename image_type::type> is defined
        ensures
            - performs: return load_image_dataset(images, object_locations, image_dataset_file(filename));
              (i.e. it ignores box labels and therefore loads all the boxes in the dataset)
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename image_type,
        typename MM
        >
    std::vector<std::vector<rectangle> > load_image_dataset (
        array<image_type,MM>& images,
        std::vector<std::vector<full_object_detection> >& object_locations,
        const image_dataset_file& source,
        std::vector<std::string>& parts_list
    );
    /*!
        requires
            - image_type == is an implementation of array2d/array2d_kernel_abstract.h
            - pixel_traits<typename image_type::type> is defined
        ensures
            - This routine loads the images and their associated object locations from the
              image metadata file indicated by source.get_filename().  This metadata file
              should be in the XML format used by the save_image_dataset_metadata() routine.
            - The difference between this function and the version of load_image_dataset()
              defined above is that this version will also load object part information and
              thus fully populates the full_object_detection objects.
            - #images.size() == The number of images loaded from the metadata file.  This
              is all the images listed in the file unless source.should_skip_empty_images()
              is set to true.
            - #images.size() == #object_locations.size()
            - This routine is capable of loading any image format which can be read
              by the load_image() routine.
            - #parts_list == a vector that contains the list of object parts found in the
              input file and loaded into object_locations.
            - #parts_list is in lexicographic sorted order.
            - let IGNORED_RECTS denote the vector returned from this function.
            - IGNORED_RECTS.size() == #object_locations.size()
            - IGNORED_RECTS == a list of the rectangles which have the "ignore" flag set to
              true in the input XML file.
            - for all valid i:
                - #images[i] == a copy of the i-th image from the dataset.
                - #object_locations[i] == a vector of all the rectangles associated with
                  #images[i].  These are the rectangles for which source.should_load_box()
                  returns true and are also not marked as "ignore" in the XML file.
                - IGNORED_RECTS[i] == A vector of all the rectangles associated with #images[i]
                  that are marked as "ignore" but not discarded by source.should_load_box().
                - if (source.should_skip_empty_images() == true) then
                    - #object_locations[i].size() != 0
                      (i.e. we won't load images that don't end up having any object locations)
                - for all valid j:
                    - #object_locations[i][j].num_parts() == #parts_list.size()
                    - for all valid k:
                        - #object_locations[i][j].part(k) == the location of the part
                          with name #parts_list[k] or OBJECT_PART_NOT_PRESENT if the
                          part was not indicated for object #object_locations[i][j].
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type,
        typename MM
        >
    std::vector<std::vector<rectangle> > load_image_dataset (
        array<image_type,MM>& images,
        std::vector<std::vector<full_object_detection> >& object_locations,
        const image_dataset_file& source
    );
    /*!
        requires
            - image_type == is an implementation of array2d/array2d_kernel_abstract.h
            - pixel_traits<typename image_type::type> is defined
        ensures
            - performs: return load_image_dataset(images, object_locations, source, parts_list);
              (i.e. this function simply calls the above function and discards the output
              parts_list.  So it is just a convenience function you can call if you don't
              care about getting the parts list.)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename image_type,
        typename MM
        >
    std::vector<std::vector<rectangle> > load_image_dataset (
        array<image_type,MM>& images,
        std::vector<std::vector<full_object_detection> >& object_locations,
        const std::string& filename
    );
    /*!
        requires
            - image_type == is an implementation of array2d/array2d_kernel_abstract.h
            - pixel_traits<typename image_type::type> is defined
        ensures
            - performs: return load_image_dataset(images, object_locations, image_dataset_file(filename));
              (i.e. it ignores box labels and therefore loads all the boxes in the dataset)
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_LOAD_IMAGE_DaTASET_ABSTRACT_Hh_


dlib C++ Library - image_dataset_metadata.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_IMAGE_DAtASET_METADATA_Hh_
#define DLIB_IMAGE_DAtASET_METADATA_Hh_

#include <string>
#include <vector>
#include "../geometry.h"

// ----------------------------------------------------------------------------------------

namespace dlib
{
    namespace image_dataset_metadata
    {

    // ------------------------------------------------------------------------------------

        struct box
        {
            /*!
                WHAT THIS OBJECT REPRESENTS
                    This object represents an annotated rectangular area of an image.
                    It is typically used to mark the location of an object such as a
                    person, car, etc.

                    The main variable of interest is rect.  It gives the location of
                    the box.  All the other variables are optional.
            !*/

            box(
            ) :
                difficult(false),
                truncated(false),
                occluded(false),
                ignore(false),
                angle(0)
            {}

            box (
                const rectangle& rect_
            ) :
                rect(rect_),
                difficult(false),
                truncated(false),
                occluded(false),
                ignore(false),
                angle(0)
            {}

            rectangle rect;

            std::map<std::string,point> parts;

            // optional fields
            std::string label;
            bool difficult;
            bool truncated;
            bool occluded;
            bool ignore;

            // The angle of the object in radians.  Positive values indicate that the
            // object at the center of the box is rotated clockwise by angle radians.  A
            // value of 0 would indicate that the object is in its "standard" upright pose.
            // Therefore, to make the object appear upright we would have to rotate the
            // image counter-clockwise by angle radians.
            double angle;

            bool has_label() const { return label.size() != 0; }
            /*!
                ensures
                    - returns true if label metadata is present and false otherwise.
            !*/
        };

    // ------------------------------------------------------------------------------------

        struct image
        {
            /*!
                WHAT THIS OBJECT REPRESENTS
                    This object represents an annotated image.
            !*/

            image() {}
            image(const std::string& f) : filename(f) {}

            std::string filename;
            std::vector<box> boxes;
        };

    // ------------------------------------------------------------------------------------

        struct dataset
        {
            /*!
                WHAT THIS OBJECT REPRESENTS
                    This object represents a labeled set of images.  In particular, it
                    contains the filename for each image as well as annotated boxes.
            !*/

            std::vector<image> images;
            std::string comment;
            std::string name;
        };

    // ------------------------------------------------------------------------------------

        void save_image_dataset_metadata (
            const dataset& meta,
            const std::string& filename
        );
        /*!
            ensures
                - Writes the contents of the meta object to a file with the given
                  filename.  The file will be in an XML format.
            throws
                - dlib::error
                  This exception is thrown if there is an error which prevents
                  this function from succeeding.
        !*/

    // ------------------------------------------------------------------------------------

        void load_image_dataset_metadata (
            dataset& meta,
            const std::string& filename
        );
        /*!
            ensures
                - Attempts to interpret filename as a file containing XML formatted data
                  as produced by the save_image_dataset_metadata() function.  Then
                  meta is loaded with the contents of the file.
            throws
                - dlib::error
                  This exception is thrown if there is an error which prevents
                  this function from succeeding.
        !*/

    // ------------------------------------------------------------------------------------

    }
}

// ----------------------------------------------------------------------------------------

#ifdef NO_MAKEFILE
#include "image_dataset_metadata.cpp"
#endif

#endif // DLIB_IMAGE_DAtASET_METADATA_Hh_


dlib C++ Library - kernel_matrix_abstract.h

// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SVm_KERNEL_MATRIX_ABSTRACT_
#ifdef DLIB_SVm_KERNEL_MATRIX_ABSTRACT_

#include <vector>
#include "kernel_abstract.h"
#include "../matrix/matrix_abstract.h"
#include "../algs.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename kernel_type,
        typename V
        >
    const matrix_exp kernel_matrix (
        const kernel_type& kernel,
        const V& v
    );
    /*!
        requires
            - kernel == a kernel function object as defined by the file dlib/svm/kernel_abstract.h.
              This kernel must also be capable of operating on the contents of v.
            - V == dlib::matrix, std::vector, dlib::std_vector_c, dlib::random_subset_selector,
              dlib::linearly_independent_subset_finder, or kernel_type::sample_type.
            - if (V is a dlib::matrix) then
                - is_vector(v) == true
        ensures
            - if (V is of type kernel_type::sample_type) then
                - returns a matrix R such that:
                    - R::type == kernel_type::scalar_type
                    - R.size() == 1
                    - R(0,0) == kernel(v,v)
            - else
                - returns a matrix R such that:
                    - R::type == kernel_type::scalar_type
                    - R is a square matrix of v.size() rows by v.size() columns
                    - for all valid r and c:
                        - R(r,c) == kernel(v(r), v(c))
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename kernel_type,
        typename V1,
        typename V2
        >
    const matrix_exp kernel_matrix (
        const kernel_type& kernel,
        const V1& v1,
        const V2& v2
    );
    /*!
        requires
            - kernel == a kernel function object as defined by the file dlib/svm/kernel_abstract.h
              This kernel must also be capable of operating on the contents of v1 and v2.
            - V1 == dlib::matrix, std::vector, dlib::std_vector_c, dlib::random_subset_selector,
              dlib::linearly_independent_subset_finder, or kernel_type::sample_type.
            - V2 == dlib::matrix, std::vector, dlib::std_vector_c, dlib::random_subset_selector,
              dlib::linearly_independent_subset_finder, or kernel_type::sample_type.
            - if (V1 is a dlib::matrix) then
                - is_vector(v1) == true
            - if (V2 is a dlib::matrix) then
                - is_vector(v2) == true
        ensures
            - if (V1 and V2 are of type kernel_type::sample_type) then
                - returns a matrix R such that:
                    - R::type == kernel_type::scalar_type
                    - R.size() == 1
                    - R(0,0) == kernel(v1,v2)
            - else if (V1 is of type kernel_type::sample_type) then
                - returns a matrix R such that:
                    - R::type == kernel_type::scalar_type
                    - R.nr() == 1
                    - R.nc() == v2.size()
                    - for all valid c:
                        - R(0,c) == kernel(v1, v2(c))
            - else if (V2 is of type kernel_type::sample_type) then
                - returns a matrix R such that:
                    - R::type == kernel_type::scalar_type
                    - R.nr() == v1.size()
                    - R.nc() == 1
                    - for all valid r:
                        - R(r,0) == kernel(v1(r), v2)
            - else
                - returns a matrix R such that:
                    - R::type == kernel_type::scalar_type
                    - R.nr() == v1.size()
                    - R.nc() == v2.size()
                    - for all valid r and c:
                        - R(r,c) == kernel(v1(r), v2(c))

            A note about aliasing (see the examples/matrix_expressions_ex.cpp example program
            for a discussion of what aliasing is in the context of the dlib::matrix):
                kernel_matrix() expressions can detect aliasing of an argument if that
                argument is of type kernel_type::sample_type.  However, it can't detect
                aliasing though std::vectors or other "list of sample type" container class
                arguments.  This means that it is safe to assign a kernel_matrix() expression
                to a sample_type if V1 or V2 are of sample_type but not safe otherwise.  However,
                since the latter case results in a general n by m matrix rather than a column
                or row vector you shouldn't ever be doing it anyway.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SVm_KERNEL_MATRIX_ABSTRACT_


dlib C++ Library - multiclass_tools_abstract.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_MULTICLASS_TOoLS_ABSTRACT_Hh_
#ifdef DLIB_MULTICLASS_TOoLS_ABSTRACT_Hh_

#include <vector>
#include <map>
#include "../unordered_pair.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <typename label_type>
    std::vector<label_type> select_all_distinct_labels (
        const std::vector<label_type>& labels
    );
    /*!
        ensures
            - Determines all distinct values present in labels and stores them
              into a sorted vector and returns it.  They are sorted in ascending
              order.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename label_type, typename U>
    std::vector<unordered_pair<label_type> > find_missing_pairs (
        const std::map<unordered_pair<label_type>,U>& binary_decision_functions
    );
    /*!
        ensures
            - Let L denote the set of all label_type values present in binary_decision_functions.
            - This function finds all the label pairs with both elements distinct and in L but
              not also in binary_decision_functions.  All these missing pairs are stored
              in a sorted vector and returned.  They are sorted in ascending order.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MULTICLASS_TOoLS_ABSTRACT_Hh_


dlib C++ Library - simplify_linear_decision_function_abstract.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SIMPLIFY_LINEAR_DECiSION_FUNCTION_ABSTRACT_Hh_
#ifdef DLIB_SIMPLIFY_LINEAR_DECiSION_FUNCTION_ABSTRACT_Hh_

#include "../algs.h"
#include "function_abstract.h"
#include "sparse_kernel_abstract.h"
#include "kernel_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    decision_function<sparse_linear_kernel<T> > simplify_linear_decision_function (
        const decision_function<sparse_linear_kernel<T> >& df
    );
    /*!
        requires
            - T must be a sparse vector as defined in dlib/svm/sparse_vector_abstract.h
        ensures
            - returns a simplified version of df that only has one basis vector.  That
              is, returns a decision function D such that:
                - D.basis_vectors.size() == 1 (or 0 if df is empty)
                - for all possible x: D(x) == df(x)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    decision_function<linear_kernel<T> > simplify_linear_decision_function (
        const decision_function<linear_kernel<T> >& df
    );
    /*!
        requires
            - T must be a dlib::matrix object
        ensures
            - returns a simplified version of df that only has one basis vector.  That
              is, returns a decision function D such that:
                - D.basis_vectors.size() == 1 (or 0 if df is empty)
                - for all possible x: D(x) == df(x)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    decision_function<linear_kernel<T> > simplify_linear_decision_function (
        const normalized_function<decision_function<linear_kernel<T> >, vector_normalizer<T> >& df
    );
    /*!
        requires
            - T must be a dlib::matrix object
        ensures
            - returns a simplified version of df that only has one basis vector and
              doesn't involve an explicit vector_normalizer.  That is, returns a
              decision function D such that:
                - D.basis_vectors.size() == 1 (or 0 if df is empty)
                - for all possible x: D(x) == df(x)
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SIMPLIFY_LINEAR_DECiSION_FUNCTION_ABSTRACT_Hh_


dlib C++ Library - Metaprogramming

The Library
  • Algorithms
  • API Wrappers
  • Bayesian Nets
  • Compression
  • Containers
  • Graph Tools
  • Image Processing
  • Linear Algebra
  • Machine Learning
  • Metaprogramming
  • Miscellaneous
  • Networking
  • Optimization
  • Parsing

Help/Info
  • Dlib Blog
  • Examples: C++
    • 3D Point Cloud
    • Assignment Learning
    • Base64 Encoder
    • Bayesian Network From Disk
    • Bayesian Network GUI
    • Bayesian Network
    • Bridge
    • BSP
    • C-Support Vector Machine
    • Cmd Line Parser
    • Compress Stream
    • Config File Reader
    • Custom Trainers
    • Directory Navigation
    • Empirical Kernel Map
    • Face Detection
    • Face Landmark Detection
    • FHOG Feature Extraction
    • FHOG Object Detection
    • Graph Labeling
    • GUI
    • Hough Transform
    • HTTP Server
    • Image
    • IO Socket Streams
    • IO Streams Server
    • Kernel Centroid
    • Kernel K-Means Clustering
    • Kernel Ridge Regression
    • Kernel RLS Filtering
    • Kernel RLS Regression
    • KRR Classification
    • Learning to Track
    • Linear Assignment Problems
    • Linear Manifold Regularizer
    • Linear Model Predictive Control
    • Logger Advanced
    • Logger Custom Output
    • Logger
    • Matrix Expressions
    • Matrix
    • Member Function Pointer
    • Model Selection
    • Multiclass Classification
    • Multithreaded Object
    • Neural Network
    • Non-Linear Least Squares
    • Nu-Support Vector Machine
    • Numerical Integration
    • Object Detector Advanced
    • Object Detector
    • One Class Classifiers
    • Online SVM
    • Optimization
    • Parallel For Loops
    • Pipe 2
    • Pipe
    • Quantum Computing
    • Queue
    • Rank Features
    • Relevance Vector Classification
    • Relevance Vector Regression
    • Running Stats
    • Sequence Labeling
    • Sequence Segmentation
    • Sockets
    • Sockstreambuf
    • Sparse Vectors
    • SQLite
    • Std C++ Allocator
    • Structural Support Vector Machines
    • Support Vector Regression
    • SURF
    • SVM-Rank
    • Thread Function
    • Thread Pool
    • Threaded Object
    • Threads
    • Timer
    • Train Object Detector
    • Train Shape Predictor
    • Using Custom Kernels
    • Video Object Tracking
    • Webcam Face Pose Estimation
    • XML Parser
  • Examples: Python
    • Face Detector
    • Face Landmark Detection
    • find candidate object locations
    • Linear Assignment Problems
    • Sequence Segmenter
    • Structural Support Vector Machines
    • SVM-Rank
    • Train Object Detector
    • Train Shape Predictor
    • Video Object Tracking
  • FAQ
  • Forums
  • Home
  • How to compile
  • How to contribute
  • Index
  • Introduction
  • License
  • Python API
  • Suggested Books
  • Who uses dlib?

Current Release
  • Change Log
  • Release Notes
  • Version: 18.18

Last Modified:
Sep 13, 2015
Metaprogramming

This page documents library components that provide metaprogramming sorts of functionality. For the most part they are useful for putting design by contract checks into code or doing various kinds of clever things with templates.

For example, you might have a templated function that is templated on a type T and you want to make sure that T is either a char or wchar_t type. You could place the following into your code and it would cause the compile to error out when T was set to something other than char or wchar_t.
COMPILE_TIME_ASSERT((is_same_type<T,char>::value || is_same_type<T,wchar_t>::value));

Objects
  • basic_type
  • enable_if
  • is_array
  • is_array2d
  • is_built_in_scalar_type
  • is_complex
  • is_config_reader
  • is_const_type
  • is_convertible
  • is_directed_graph
  • is_float_type
  • is_function
  • is_graph
  • is_matrix
  • is_pair
  • is_pointer_type
  • is_rand
  • is_reference_type
  • is_same_type
  • is_signed_type
  • is_std_vector
  • is_unsigned_type
  • noncopyable
  • promote
  • static_switch
  • tabs
  • tmax
  • tmin
  • unsigned_type

Global Functions
  • ASSERT_ARE_NOT_SAME_TYPE
  • ASSERT_ARE_SAME_TYPE
  • assign_zero_if_built_in_scalar_type
  • COMPILE_TIME_ASSERT
  • DLIB_ASSERT
  • DLIB_ASSERT_HAS_STANDARD_LAYOUT
  • DLIB_CASSERT
  • DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST
  • DLIB_STACK_TRACE
  • DLIB_STACK_TRACE_NAMED
  • get_stack_trace
  • is_same_object
  • wrap_function
  • _dT

Other
  • portability_macros

[top]

ASSERT_ARE_NOT_SAME_TYPE

This is a macro function for debugging. Its form is ASSERT_ARE_NOT_SAME_TYPE(type1, type2). If type1 and type2 are the same type then the compile will fail. This is sometimes useful in validating template arguments.

More Details...
#include <dlib/assert.h>
[top]

ASSERT_ARE_SAME_TYPE

This is a macro function for debugging. Its form is ASSERT_ARE_SAME_TYPE(type1, type2). If type1 and type2 are not the same type then the compile will fail. This is sometimes useful in validating template arguments.

More Details...
#include <dlib/assert.h>
[top]

assign_zero_if_built_in_scalar_type

This function assigns its argument the value of 0 if it is a built in scalar type according to the is_built_in_scalar_type template. If it isn't a built in scalar type then it does nothing.

This function is useful for suppressing compiler warnings about uninitialized types inside of templates that are designed to accept the built in types as well as user defined classes.

More Details...
#include <dlib/algs.h>
[top]

basic_type

This is a template that takes a type and strips off any const, volatile, or reference qualifiers and gives you back the basic underlying type.

For example, promote<const int&>::type == int

More Details...
#include <dlib/algs.h>
[top]

COMPILE_TIME_ASSERT

This is a macro function for debugging. Its form is COMPILE_TIME_ASSERT(condition that should be true). The condition must be a compile time constant and if it is false then the compile will fail.

More Details...
#include <dlib/assert.h>
[top]

DLIB_ASSERT

This is a macro function for debugging. Its form is DLIB_ASSERT(condition that should be true,error message). If the condition is false DLIB_ASSERT throws an exception of type dlib::fatal_error with fatal_error::type == EBROKEN_ASSERT. An error message detailing the nature of the problem is stored in the member variable info which is of type std::string. Look in the following file for more details. The exception classes are defined here.

This macro is only enabled if _DEBUG, DEBUG or ENABLE_ASSERTS is defined. Also, if this macro is enabled then ENABLE_ASSERTS will be defined even if you didn't define it.

Note that when this macro fails and throws an exception it also calls the global C function dlib_assert_breakpoint(). This behavior makes it easy to set a debugging tool to break when DLIB_ASSERT fails by setting a breakpoint on dlib_assert_breakpoint().

More Details...
#include <dlib/assert.h>
[top]

DLIB_ASSERT_HAS_STANDARD_LAYOUT

This macro is meant to cause a compiler error if a type doesn't have a simple memory layout (like a C struct). In particular, types with simple layouts are ones which can be copied via memcpy().

This was called a POD type in C++03 and in C++0x we are looking to check if it is a "standard layout type". Once we can use C++0x we can change this macro to something that uses the std::is_standard_layout type_traits class. See: http://www2.research.att.com/~bs/C++0xFAQ.html#PODs
More Details...
#include <dlib/assert.h>
[top]

DLIB_CASSERT

This is a macro function that is identical to the DLIB_ASSERT macro except that it is always enabled. Even if _DEBUG, DEBUG and ENABLE_ASSERTS are not defined.

Note that when this macro fails and throws an exception it also calls the global C function dlib_assert_breakpoint(). This behavior makes it easy to set a debugging tool to break when DLIB_CASSERT fails by setting a breakpoint on dlib_assert_breakpoint().

More Details...
#include <dlib/assert.h>
[top]

DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST

The DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST() macro is used to define traits templates that tell you if a class has a certain member function. For example, to make a test to see if a class has a public method with the signature void print(int) you would say:

DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST(has_print, void, print, (int))
Then you can check if a class, T, has this method by looking at the boolean value:
has_print<T>::value
which will be true if the member function is in the T class.
More Details...
#include <dlib/algs.h>
[top]

DLIB_STACK_TRACE

This is a preprocessor macro that allows you to tag a function so that dlib will keep track of it in a function call stack. That is, you will be able to see a stack trace by calling get_stack_trace if you put this macro at the top of your functions.

This macro is only enabled if DLIB_ENABLE_STACK_TRACE is defined. If it isn't defined then this macro doesn't do anything. Also note that when this macro is defined it will cause DLIB_ASSERT and DLIB_CASSERT to include a stack trace in their error messages.

More Details...
#include <dlib/assert.h>
[top]

DLIB_STACK_TRACE_NAMED

This is a preprocessor macro just like DLIB_STACK_TRACE except that it allows you to supply your own string to use as the function name in the stack trace instead of the one deduced by DLIB_STACK_TRACE.

This macro is only enabled if DLIB_ENABLE_STACK_TRACE is defined.

More Details...
#include <dlib/assert.h>
[top]

enable_if

This is a family of templates from the Boost C++ libraries that makes it somewhat easier to control template specialization. For the details see this page. Note that the header dlib/enable_if.h brings these templates into the dlib namespace.

#include <dlib/enable_if.h>
[top]

get_stack_trace

This function allows you to query the current stack trace.

This macro is only enabled if DLIB_ENABLE_STACK_TRACE is defined.

More Details...
#include <dlib/assert.h>
[top]

is_array

This is a template where is_array<T>::value == true when T is an array object.
More Details...
#include <dlib/is_kind.h>
[top]

is_array2d

This is a template where is_array2d<T>::value == true when T is an array2d object.
More Details...
#include <dlib/is_kind.h>
[top]

is_built_in_scalar_type

This is a template where is_built_in_scalar_type<T>::value == true when T is a built in scalar type such as int, char, float, etc.
More Details...
#include <dlib/algs.h>
[top]

is_complex

This is a template that can be used to determine if a type is a specialization of std::complex.
More Details...
#include <dlib/matrix.h>
[top]

is_config_reader

This is a template where is_config_reader<T>::value == true when T is a config_reader or config_reader_thread_safe object.
More Details...
#include <dlib/is_kind.h>
[top]

is_const_type

This is a template where is_const_type<T>::value == true when T is a const type and false otherwise.
More Details...
#include <dlib/algs.h>
[top]

is_convertible

This is a template that can be used to determine if one type is convertible into another type.
More Details...
#include <dlib/algs.h>
[top]

is_directed_graph

This is a template where is_directed_graph<T>::value == true when T is a directed_graph object.
More Details...
#include <dlib/is_kind.h>
[top]

is_float_type

This is a template where is_float_type<T>::value == true when T is a floating point type (i.e. float, double, or long double) and false otherwise.
More Details...
#include <dlib/algs.h>
[top]

is_function

This is a template where is_function<T>::value == true when T is a function type.
More Details...
#include <dlib/algs.h>
[top]

is_graph

This is a template where is_graph<T>::value == true when T is a graph object.
More Details...
#include <dlib/is_kind.h>
[top]

is_matrix

This is a template where is_matrix<T>::value == true when T is a matrix object or some kind of matrix expression.
More Details...
#include <dlib/is_kind.h>
[top]

is_pair

This is a template where is_pair<T>::value == true when T is a std::pair object.
More Details...
#include <dlib/is_kind.h>
[top]

is_pointer_type

This is a template where is_pointer_type<T>::value == true when T is a pointer type and false otherwise.
More Details...
#include <dlib/algs.h>
[top]

is_rand

This is a template where is_rand<T>::value == true when T is a rand object.
More Details...
#include <dlib/is_kind.h>
[top]

is_reference_type

This is a template where is_reference_type<T>::value == true when T is a reference type and false otherwise.
More Details...
#include <dlib/algs.h>
[top]

is_same_object

This is a templated function which checks if both of its arguments are actually references to the same object. It returns true if they are and false otherwise.
More Details...
#include <dlib/algs.h>
[top]

is_same_type

This is a template where is_same_type<T,U>::value == true when T and U are the same type and false otherwise.
More Details...
#include <dlib/algs.h>
[top]

is_signed_type

This is a template where is_signed_type<T>::value == true when T is a signed scalar type and false when it is an unsigned scalar type.
More Details...
#include <dlib/algs.h>
[top]

is_std_vector

This is a template where is_std_vector<T>::value == true when T is a std_vector_c or std::vector object.
More Details...
#include <dlib/is_kind.h>
[top]

is_unsigned_type

This is a template where is_unsigned_type<T>::value == true when T is an unsigned scalar type and false when it is a signed scalar type.
More Details...
#include <dlib/algs.h>
[top]

noncopyable

This is a simple class that makes it easy to declare a non-copyable object. To use it to make your own class non-copyable just inherit from it.
More Details...
#include <dlib/noncopyable.h>
[top]

portability_macros

This file #defines various macros depending on the platform being compiled under. See the file itself for the specifics.
More Details...
#include <dlib/platform.h>
[top]

promote

This is a template that takes one of the built in scalar types and gives you another scalar type that should be big enough to hold sums of values from the original scalar type. The new scalar type will also always be signed.

For example, promote<uint16>::type == int32

More Details...
#include <dlib/algs.h>
[top]

static_switch

To use this template you give it some number of boolean expressions and it tells you which one of them is true. If more than one of them is true then it causes a compile time error. It is useful for cases where you want to specialize a template and you want to specialize it not by the type of object it gets per say but instead according to the values of some type traits associated with the various template arguments. A simple example of this can be seen in the assign_pixel's implementation which can be found at the bottom of the dlib/pixel.h file.
More Details...
#include <dlib/algs.h>
[top]

tabs

This is a template to compute the absolute value a number at compile time.
More Details...
#include <dlib/algs.h>
[top]

tmax

This is a template to compute the max of two values at compile time.
More Details...
#include <dlib/algs.h>
[top]

tmin

This is a template to compute the min of two values at compile time.
More Details...
#include <dlib/algs.h>
[top]

unsigned_type

This is a template that allows you to obtain the unsigned version of any integral type. For example, unsigned_type<signed short>::type == unsigned short.
More Details...
#include <dlib/uintn.h>
[top]

wrap_function

This is a template that allows you to turn a global function into a function object. See the specs for more details.
More Details...
#include <dlib/algs.h>
[top]

_dT

This is a macro function for converting a string/character literal to either a char or wchar_t literal. Its form is _dT(target character type,string or character literal)
More Details...
#include <dlib/algs.h>


dlib C++ Library - is_kind.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_IS_KINd_H_
#define DLIB_IS_KINd_H_

#include <vector>

namespace dlib
{
    /*!
        This file contains a set of templates that enable you to determine if
        a given type implements an abstract interface defined in one of the
        dlib *_abstract.h files.
    !*/

// ----------------------------------------------------------------------------------------

    struct default_is_kind_value { static const bool value = false; };

// ----------------------------------------------------------------------------------------

    template <typename T>
    struct is_graph : public default_is_kind_value
    {
        /*!
            - if (T is an implementation of graph/graph_kernel_abstract.h) then
                - is_graph<T>::value == true
            - else
                - is_graph<T>::value == false
        !*/
    };

// ----------------------------------------------------------------------------------------

    template <typename T>
    struct is_directed_graph : public default_is_kind_value
    {
        /*!
            - if (T is an implementation of directed_graph/directed_graph_kernel_abstract.h) then
                - is_directed_graph<T>::value == true
            - else
                - is_directed_graph<T>::value == false
        !*/
    };

// ----------------------------------------------------------------------------------------

    template <typename T, typename helper = void>
    struct is_matrix : public default_is_kind_value
    {
        /*!
            - if (T is some kind of matrix expression from the matrix/matrix_exp_abstract.h component) then
                - is_matrix<T>::value == true
            - else
                - is_matrix<T>::value == false
        !*/

        // Don't set the helper to anything.  Just let it be void.
        ASSERT_ARE_SAME_TYPE(helper,void);
    };

// ----------------------------------------------------------------------------------------

    template <typename T>
    struct is_array2d : public default_is_kind_value
    {
        /*!
            - if (T is an implementation of array2d/array2d_kernel_abstract.h) then
                - is_array2d<T>::value == true
            - else
                - is_array2d<T>::value == false
        !*/
    };

// ----------------------------------------------------------------------------------------

    template <typename T>
    struct is_array : public default_is_kind_value
    {
        /*!
            - if (T is an implementation of array/array_kernel_abstract.h) then
                - is_array<T>::value == true
            - else
                - is_array<T>::value == false
        !*/
    };

// ----------------------------------------------------------------------------------------

    template <typename T>
    struct is_std_vector : public default_is_kind_value
    {
        /*!
            - if (T is an implementation of the standard C++ std::vector object) then
                - is_std_vector<T>::value == true
            - else
                - is_std_vector<T>::value == false
        !*/
    };

// ----------------------------------------------------------------------------------------

    template <typename T>
    struct is_pair : public default_is_kind_value
    {
        /*!
            - if (T is a std::pair object) then
                - is_std_vector<T>::value == true
            - else
                - is_std_vector<T>::value == false
        !*/
    };

// ----------------------------------------------------------------------------------------

    template <typename T>
    struct is_rand : public default_is_kind_value
    {
        /*!
            - if (T is an implementation of rand/rand_kernel_abstract.h) then
                - is_rand<T>::value == true
            - else
                - is_rand<T>::value == false
        !*/
    };

// ----------------------------------------------------------------------------------------

    template <typename T>
    struct is_config_reader : public default_is_kind_value
    {
        /*!
            - if (T is an implementation of config_reader/config_reader_kernel_abstract.h) then
                - is_config_reader<T>::value == true
            - else
                - is_config_reader<T>::value == false
        !*/
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                              Implementation details
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <typename T, typename alloc>
    struct is_std_vector<std::vector<T,alloc> >         { const static bool value = true; };
    template <typename T> struct is_std_vector<T&>      { const static bool value = is_std_vector<T>::value; };
    template <typename T> struct is_std_vector<const T&>{ const static bool value = is_std_vector<T>::value; };
    template <typename T> struct is_std_vector<const T> { const static bool value = is_std_vector<T>::value; };

// ----------------------------------------------------------------------------------------

    template <typename T, typename U>
    struct is_pair<std::pair<T,U> > { const static bool value = true; };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_IS_KINd_H_


dlib C++ Library - matrix_utilities.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MATRIx_UTILITIES_
#define DLIB_MATRIx_UTILITIES_

#include "matrix_utilities_abstract.h"
#include "matrix.h"
#include <cmath>
#include <complex>
#include <limits>
#include "../pixel.h"
#include "../stl_checked.h"
#include <vector>
#include <algorithm>
#include "../std_allocator.h"
#include "matrix_expressions.h"
#include "matrix_math_functions.h"
#include "matrix_op.h"
#include "../general_hash/random_hashing.h"
#include "matrix_mat.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    /*!A is_complex
        This is a template that can be used to determine if a type is a specialization
        of the std::complex template class.

        For example:
            is_complex<float>::value == false
            is_complex<std::complex<float> >::value == true
    !*/

    template <typename T>
    struct is_complex { static const bool value = false; };

    template <typename T>
    struct is_complex<std::complex<T> >         { static const bool value = true; };
    template <typename T>
    struct is_complex<std::complex<T>& >        { static const bool value = true; };
    template <typename T>
    struct is_complex<const std::complex<T>& >  { static const bool value = true; };
    template <typename T>
    struct is_complex<const std::complex<T> >   { static const bool value = true; };

// ----------------------------------------------------------------------------------------

    template <typename EXP>
    inline bool is_row_vector (
        const matrix_exp<EXP>& m
    ) { return m.nr() == 1; }

    template <typename EXP>
    inline bool is_col_vector (
        const matrix_exp<EXP>& m
    ) { return m.nc() == 1; }

    template <typename EXP>
    inline bool is_vector (
        const matrix_exp<EXP>& m
    ) { return is_row_vector(m) || is_col_vector(m); }

// ----------------------------------------------------------------------------------------

    template <typename EXP>
    inline bool is_finite (
        const matrix_exp<EXP>& m
    )
    {
        for (long r = 0; r < m.nr(); ++r)
        {
            for (long c = 0; c < m.nc(); ++c)
            {
                if (!is_finite(m(r,c)))
                    return false;
            }
        }
        return true;
    }

// ----------------------------------------------------------------------------------------

    namespace impl
    {
        template <typename T>
        const T& magnitude (const T& item) { return item; }
        template <typename T>
        T magnitude (const std::complex<T>& item) { return std::norm(item); }
    }

    template <
        typename EXP
        >
    void find_min_and_max (
        const matrix_exp<EXP>& m,
        typename EXP::type& min_val,
        typename EXP::type& max_val
    )
    {
        DLIB_ASSERT(m.size() > 0,
            "\ttype find_min_and_max(const matrix_exp& m, min_val, max_val)"
            << "\n\tYou can't ask for the min and max of an empty matrix"
            << "\n\tm.size():     " << m.size()
            );
        typedef typename matrix_exp<EXP>::type type;

        min_val = m(0,0);
        max_val = min_val;
        for (long r = 0; r < m.nr(); ++r)
        {
            for (long c = 0; c < m.nc(); ++c)
            {
                type temp = m(r,c);
                if (dlib::impl::magnitude(temp) > dlib::impl::magnitude(max_val))
                    max_val = temp;
                if (dlib::impl::magnitude(temp) < dlib::impl::magnitude(min_val))
                    min_val = temp;
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP
        >
    point max_point (
        const matrix_exp<EXP>& m
    )
    {
        DLIB_ASSERT(m.size() > 0,
            "\tpoint max_point(const matrix_exp& m)"
            << "\n\tm can't be empty"
            << "\n\tm.size():   " << m.size()
            << "\n\tm.nr():     " << m.nr()
            << "\n\tm.nc():     " << m.nc()
            );
        typedef typename matrix_exp<EXP>::type type;

        point best_point(0,0);
        type val = m(0,0);
        for (long r = 0; r < m.nr(); ++r)
        {
            for (long c = 0; c < m.nc(); ++c)
            {
                type temp = m(r,c);
                if (dlib::impl::magnitude(temp) > dlib::impl::magnitude(val))
                {
                    val = temp;
                    best_point = point(c,r);
                }
            }
        }
        return best_point;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP
        >
    point min_point (
        const matrix_exp<EXP>& m
    )
    {
        DLIB_ASSERT(m.size() > 0,
            "\tpoint min_point(const matrix_exp& m)"
            << "\n\tm can't be empty"
            << "\n\tm.size():   " << m.size()
            << "\n\tm.nr():     " << m.nr()
            << "\n\tm.nc():     " << m.nc()
            );
        typedef typename matrix_exp<EXP>::type type;

        point best_point(0,0);
        type val = m(0,0);
        for (long r = 0; r < m.nr(); ++r)
        {
            for (long c = 0; c < m.nc(); ++c)
            {
                type temp = m(r,c);
                if (dlib::impl::magnitude(temp) < dlib::impl::magnitude(val))
                {
                    val = temp;
                    best_point = point(c,r);
                }
            }
        }
        return best_point;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP
        >
    long index_of_max (
        const matrix_exp<EXP>& m
    )
    {
        DLIB_ASSERT(m.size() > 0 && is_vector(m) == true,
            "\tlong index_of_max(const matrix_exp& m)"
            << "\n\tm must be a row or column matrix"
            << "\n\tm.size():   " << m.size()
            << "\n\tm.nr():     " << m.nr()
            << "\n\tm.nc():     " << m.nc()
            );
        typedef typename matrix_exp<EXP>::type type;

        type val = m(0);
        long best_idx = 0;
        for (long i = 1; i < m.size(); ++i)
        {
            type temp = m(i);
            if (dlib::impl::magnitude(temp) > dlib::impl::magnitude(val))
            {
                val = temp;
                best_idx = i;
            }
        }
        return best_idx;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP
        >
    long index_of_min (
        const matrix_exp<EXP>& m
    )
    {
        DLIB_ASSERT(m.size() > 0 && is_vector(m),
            "\tlong index_of_min(const matrix_exp& m)"
            << "\n\tm must be a row or column matrix"
            << "\n\tm.size():   " << m.size()
            << "\n\tm.nr():     " << m.nr()
            << "\n\tm.nc():     " << m.nc()
            );
        typedef typename matrix_exp<EXP>::type type;

        type val = m(0);
        long best_idx = 0;
        for (long i = 1; i < m.size(); ++i)
        {
            type temp = m(i);
            if (dlib::impl::magnitude(temp) < dlib::impl::magnitude(val))
            {
                val = temp;
                best_idx = i;
            }
        }
        return best_idx;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP
        >
    const typename matrix_exp<EXP>::type max (
        const matrix_exp<EXP>& m
    )
    {
        DLIB_ASSERT(m.size() > 0,
            "\ttype max(const matrix_exp& m)"
            << "\n\tYou can't ask for the max() of an empty matrix"
            << "\n\tm.size():     " << m.size()
            );
        typedef typename matrix_exp<EXP>::type type;

        type val = m(0,0);
        for (long r = 0; r < m.nr(); ++r)
        {
            for (long c = 0; c < m.nc(); ++c)
            {
                type temp = m(r,c);
                if (dlib::impl::magnitude(temp) > dlib::impl::magnitude(val))
                    val = temp;
            }
        }
        return val;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP
        >
    const typename matrix_exp<EXP>::type min (
        const matrix_exp<EXP>& m
    )
    {
        DLIB_ASSERT(m.size() > 0,
            "\ttype min(const matrix_exp& m)"
            << "\n\tYou can't ask for the min() of an empty matrix"
            << "\n\tm.size():     " << m.size()
            );
        typedef typename matrix_exp<EXP>::type type;

        type val = m(0,0);
        for (long r = 0; r < m.nr(); ++r)
        {
            for (long c = 0; c < m.nc(); ++c)
            {
                type temp = m(r,c);
                if (dlib::impl::magnitude(temp) < dlib::impl::magnitude(val))
                    val = temp;
            }
        }
        return val;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP
        >
    typename enable_if_c<std::numeric_limits<typename EXP::type>::is_integer, double>::type length (
        const matrix_exp<EXP>& m
    )
    {
        DLIB_ASSERT(is_vector(m) == true,
            "\ttype length(const matrix_exp& m)"
            << "\n\tm must be a row or column vector"
            << "\n\tm.nr():     " << m.nr()
            << "\n\tm.nc():     " << m.nc()
            );

        return std::sqrt(static_cast<double>(sum(squared(m))));
    }

    template <
        typename EXP
        >
    typename disable_if_c<std::numeric_limits<typename EXP::type>::is_integer, const typename EXP::type>::type length (
        const matrix_exp<EXP>& m
    )
    {
        DLIB_ASSERT(is_vector(m) == true,
            "\ttype length(const matrix_exp& m)"
            << "\n\tm must be a row or column vector"
            << "\n\tm.nr():     " << m.nr()
            << "\n\tm.nc():     " << m.nc()
            );
        return std::sqrt(sum(squared(m)));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP
        >
    const typename matrix_exp<EXP>::type length_squared (
        const matrix_exp<EXP>& m
    )
    {
        DLIB_ASSERT(is_vector(m) == true,
            "\ttype length_squared(const matrix_exp& m)"
            << "\n\tm must be a row or column vector"
            << "\n\tm.nr():     " << m.nr()
            << "\n\tm.nc():     " << m.nc()
            );
        return sum(squared(m));
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <typename M>
    struct op_trans
    {
        op_trans( const M& m_) : m(m_){}

        const M& m;

        const static long cost = M::cost;
        const static long NR = M::NC;
        const static long NC = M::NR;
        typedef typename M::type type;
        typedef typename M::const_ret_type const_ret_type;
        typedef typename M::mem_manager_type mem_manager_type;
        typedef typename M::layout_type layout_type;

        const_ret_type apply (long r, long c) const { return m(c,r); }

        long nr () const { return m.nc(); }
        long nc () const { return m.nr(); }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }

    };

    template <
        typename M
        >
    const matrix_op<op_trans<M> > trans (
        const matrix_exp<M>& m
    )
    {
        typedef op_trans<M> op;
        return matrix_op<op>(op(m.ref()));
    }

// ----------------------------------------------------------------------------------------

// don't to anything at all for diagonal matrices
    template <
        typename M
        >
    const matrix_diag_exp<M>& trans (
        const matrix_diag_exp<M>& m
    )
    {
        return m;
    }

// ----------------------------------------------------------------------------------------

// I introduced this struct because it avoids an inane compiler warning from gcc
    template <typename EXP>
    struct is_not_ct_vector{ static const bool value = (EXP::NR != 1 && EXP::NC != 1); };

    template <
        typename EXP1,
        typename EXP2
        >
    typename enable_if_c<(is_not_ct_vector<EXP1>::value) || (is_not_ct_vector<EXP2>::value),
                         typename EXP1::type>::type
    dot (
        const matrix_exp<EXP1>& m1,
        const matrix_exp<EXP2>& m2
    )
    {
        // You are getting an error on this line because you are trying to
        // compute the dot product between two matrices that aren't both vectors (i.e.
        // they aren't column or row matrices).
        COMPILE_TIME_ASSERT(EXP1::NR*EXP1::NC == 0 ||
                            EXP2::NR*EXP2::NC == 0);

        DLIB_ASSERT(is_vector(m1) && is_vector(m2) && m1.size() == m2.size() &&
                    m1.size() > 0,
            "\t type dot(const matrix_exp& m1, const matrix_exp& m2)"
            << "\n\t You can only compute the dot product between non-empty vectors of equal length."
            << "\n\t is_vector(m1): " << is_vector(m1)
            << "\n\t is_vector(m2): " << is_vector(m2)
            << "\n\t m1.size():     " << m1.size()
            << "\n\t m2.size():     " << m2.size()
            );

        if (is_col_vector(m1) && is_col_vector(m2)) return (trans(m1)*m2)(0);
        if (is_col_vector(m1) && is_row_vector(m2)) return (m2*m1)(0);
        if (is_row_vector(m1) && is_col_vector(m2)) return (m1*m2)(0);

        //if (is_row_vector(m1) && is_row_vector(m2))
        return (m1*trans(m2))(0);
    }

    template < typename EXP1, typename EXP2 >
    typename enable_if_c<EXP1::NR == 1 && EXP2::NR == 1 && EXP1::NC != 1 && EXP2::NC != 1, typename EXP1::type>::type
    dot ( const matrix_exp<EXP1>& m1, const matrix_exp<EXP2>& m2)
    {
        DLIB_ASSERT(m1.size() == m2.size(),
            "\t type dot(const matrix_exp& m1, const matrix_exp& m2)"
            << "\n\t You can only compute the dot product between vectors of equal length"
            << "\n\t m1.size():     " << m1.size()
            << "\n\t m2.size():     " << m2.size()
            );

        return m1*trans(m2);
    }

    template < typename EXP1, typename EXP2 >
    typename enable_if_c<EXP1::NR == 1 && EXP2::NC == 1 && EXP1::NC != 1 && EXP2::NR != 1, typename EXP1::type>::type
    dot ( const matrix_exp<EXP1>& m1, const matrix_exp<EXP2>& m2)
    {
        DLIB_ASSERT(m1.size() == m2.size(),
            "\t type dot(const matrix_exp& m1, const matrix_exp& m2)"
            << "\n\t You can only compute the dot product between vectors of equal length"
            << "\n\t m1.size():     " << m1.size()
            << "\n\t m2.size():     " << m2.size()
            );

        return m1*m2;
    }

    template < typename EXP1, typename EXP2 >
    typename enable_if_c<EXP1::NC == 1 && EXP2::NR == 1 && EXP1::NR != 1 && EXP2::NC != 1, typename EXP1::type>::type
    dot ( const matrix_exp<EXP1>& m1, const matrix_exp<EXP2>& m2)
    {
        DLIB_ASSERT(m1.size() == m2.size(),
            "\t type dot(const matrix_exp& m1, const matrix_exp& m2)"
            << "\n\t You can only compute the dot product between vectors of equal length"
            << "\n\t m1.size():     " << m1.size()
            << "\n\t m2.size():     " << m2.size()
            );

        return m2*m1;
    }

    template < typename EXP1, typename EXP2 >
    typename enable_if_c<EXP1::NC == 1 && EXP2::NC == 1 && EXP1::NR != 1 && EXP2::NR != 1, typename EXP1::type>::type
    dot ( const matrix_exp<EXP1>& m1, const matrix_exp<EXP2>& m2)
    {
        DLIB_ASSERT(m1.size() == m2.size(),
            "\t type dot(const matrix_exp& m1, const matrix_exp& m2)"
            << "\n\t You can only compute the dot product between vectors of equal length"
            << "\n\t m1.size():     " << m1.size()
            << "\n\t m2.size():     " << m2.size()
            );

        return trans(m1)*m2;
    }

    template < typename EXP1, typename EXP2 >
    typename enable_if_c<(EXP1::NC*EXP1::NR == 1) || (EXP2::NC*EXP2::NR == 1), typename EXP1::type>::type
    dot ( const matrix_exp<EXP1>& m1, const matrix_exp<EXP2>& m2)
    {
        DLIB_ASSERT(m1.size() == m2.size(),
            "\t type dot(const matrix_exp& m1, const matrix_exp& m2)"
            << "\n\t You can only compute the dot product between vectors of equal length"
            << "\n\t m1.size():     " << m1.size()
            << "\n\t m2.size():     " << m2.size()
            );

        return m1(0)*m2(0);
    }

// ----------------------------------------------------------------------------------------

    template <typename M, long R, long C>
    struct op_removerc
    {
        op_removerc( const M& m_) : m(m_){}

        const M& m;

        const static long cost = M::cost+2;
        const static long NR = (M::NR==0) ? 0 : (M::NR - 1);
        const static long NC = (M::NC==0) ? 0 : (M::NC - 1);
        typedef typename M::type type;
        typedef typename M::const_ret_type const_ret_type;
        typedef typename M::mem_manager_type mem_manager_type;
        typedef typename M::layout_type layout_type;
        const_ret_type apply (long r, long c) const
        {
            if (r < R)
            {
                if (c < C)
                    return m(r,c);
                else
                    return m(r,c+1);
            }
            else
            {
                if (c < C)
                    return m(r+1,c);
                else
                    return m(r+1,c+1);
            }
        }

        long nr () const { return m.nr() - 1; }
        long nc () const { return m.nc() - 1; }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }
    };

    template <typename M>
    struct op_removerc2
    {
        op_removerc2( const M& m_, const long R_, const long C_) : m(m_), R(R_), C(C_){}
        const M& m;
        const long R;
        const long C;

        const static long cost = M::cost+2;
        const static long NR = (M::NR==0) ? 0 : (M::NR - 1);
        const static long NC = (M::NC==0) ? 0 : (M::NC - 1);
        typedef typename M::type type;
        typedef typename M::const_ret_type const_ret_type;
        typedef typename M::mem_manager_type mem_manager_type;
        typedef typename M::layout_type layout_type;
        const_ret_type apply (long r, long c) const
        {
            if (r < R)
            {
                if (c < C)
                    return m(r,c);
                else
                    return m(r,c+1);
            }
            else
            {
                if (c < C)
                    return m(r+1,c);
                else
                    return m(r+1,c+1);
            }
        }

        long nr () const { return m.nr() - 1; }
        long nc () const { return m.nc() - 1; }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }
    };

    template <
        long R,
        long C,
        typename EXP
        >
    const matrix_op<op_removerc<EXP,R,C> > removerc (
        const matrix_exp<EXP>& m
    )
    {
        // you can't remove a row from a matrix with only one row
        COMPILE_TIME_ASSERT((EXP::NR > R && R >= 0) || EXP::NR == 0);
        // you can't remove a column from a matrix with only one column
        COMPILE_TIME_ASSERT((EXP::NC > C && C >= 0) || EXP::NR == 0);
        DLIB_ASSERT(m.nr() > R && R >= 0 && m.nc() > C && C >= 0,
            "\tconst matrix_exp removerc<R,C>(const matrix_exp& m)"
            << "\n\tYou can't remove a row/column from a matrix if it doesn't have that row/column"
            << "\n\tm.nr(): " << m.nr()
            << "\n\tm.nc(): " << m.nc()
            << "\n\tR:      " << R
            << "\n\tC:      " << C
            );
        typedef op_removerc<EXP,R,C> op;
        return matrix_op<op>(op(m.ref()));
    }

    template <
        typename EXP
        >
    const matrix_op<op_removerc2<EXP> >  removerc (
        const matrix_exp<EXP>& m,
        long R,
        long C
    )
    {
        DLIB_ASSERT(m.nr() > R && R >= 0 && m.nc() > C && C >= 0,
            "\tconst matrix_exp removerc(const matrix_exp& m,R,C)"
            << "\n\tYou can't remove a row/column from a matrix if it doesn't have that row/column"
            << "\n\tm.nr(): " << m.nr()
            << "\n\tm.nc(): " << m.nc()
            << "\n\tR:      " << R
            << "\n\tC:      " << C
            );
        typedef op_removerc2<EXP> op;
        return matrix_op<op>(op(m.ref(),R,C));
    }

// ----------------------------------------------------------------------------------------

    template <typename M, long C>
    struct op_remove_col
    {
        op_remove_col( const M& m_) : m(m_){}
        const M& m;

        const static long cost = M::cost+2;
        const static long NR = M::NR;
        const static long NC = (M::NC==0) ? 0 : (M::NC - 1);
        typedef typename M::type type;
        typedef typename M::const_ret_type const_ret_type;
        typedef typename M::mem_manager_type mem_manager_type;
        typedef typename M::layout_type layout_type;
        const_ret_type apply ( long r, long c) const
        {
            if (c < C)
            {
                return m(r,c);
            }
            else
            {
                return m(r,c+1);
            }
        }

        long nr () const { return m.nr(); }
        long nc () const { return m.nc() - 1; }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }
    };

    template <typename M>
    struct op_remove_col2
    {
        op_remove_col2( const M& m_,  const long C_) : m(m_), C(C_){}
        const M& m;
        const long C;

        const static long cost = M::cost+2;
        const static long NR = M::NR;
        const static long NC = (M::NC==0) ? 0 : (M::NC - 1);
        typedef typename M::type type;
        typedef typename M::const_ret_type const_ret_type;
        typedef typename M::mem_manager_type mem_manager_type;
        typedef typename M::layout_type layout_type;
        const_ret_type apply ( long r, long c) const
        {
            if (c < C)
            {
                return m(r,c);
            }
            else
            {
                return m(r,c+1);
            }
        }

        long nr () const { return m.nr(); }
        long nc () const { return m.nc() - 1; }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }
    };

    template <
        long C,
        typename EXP
        >
    const matrix_op<op_remove_col<EXP, C> > remove_col (
        const matrix_exp<EXP>& m
    )
    {
        // You can't remove the given column from the matrix because the matrix doesn't
        // have a column with that index.
        COMPILE_TIME_ASSERT((EXP::NC > C && C >= 0) || EXP::NC == 0);
        DLIB_ASSERT(m.nc() > C && C >= 0 ,
            "\tconst matrix_exp remove_col<C>(const matrix_exp& m)"
            << "\n\tYou can't remove a col from a matrix if it doesn't have it"
            << "\n\tm.nr(): " << m.nr()
            << "\n\tm.nc(): " << m.nc()
            << "\n\tC:      " << C
            );
        typedef op_remove_col<EXP,C> op;
        return matrix_op<op>(op(m.ref()));
    }

    template <
        typename EXP
        >
    const matrix_op<op_remove_col2<EXP> > remove_col (
        const matrix_exp<EXP>& m,
        long C
    )
    {
        DLIB_ASSERT(m.nc() > C && C >= 0 ,
            "\tconst matrix_exp remove_col(const matrix_exp& m,C)"
            << "\n\tYou can't remove a col from a matrix if it doesn't have it"
            << "\n\tm.nr(): " << m.nr()
            << "\n\tm.nc(): " << m.nc()
            << "\n\tC:      " << C
            );
        typedef op_remove_col2<EXP> op;
        return matrix_op<op>(op(m.ref(),C));
    }

// ----------------------------------------------------------------------------------------

    template <typename M, long R>
    struct op_remove_row
    {
        op_remove_row( const M& m_) : m(m_){}
        const M& m;

        const static long cost = M::cost+2;
        const static long NR = (M::NR==0) ? 0 : (M::NR - 1);
        const static long NC = M::NC;
        typedef typename M::type type;
        typedef typename M::const_ret_type const_ret_type;
        typedef typename M::mem_manager_type mem_manager_type;
        typedef typename M::layout_type layout_type;
        const_ret_type apply ( long r, long c) const
        {
            if (r < R)
            {
                return m(r,c);
            }
            else
            {
                return m(r+1,c);
            }
        }

        long nr () const { return m.nr() - 1; }
        long nc () const { return m.nc(); }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }
    };

    template <typename M>
    struct op_remove_row2
    {
        op_remove_row2( const M& m_,  const long R_) : m(m_), R(R_){}
        const M& m;
        const long R;

        const static long cost = M::cost+2;
        const static long NR = (M::NR==0) ? 0 : (M::NR - 1);
        const static long NC = M::NC;
        typedef typename M::type type;
        typedef typename M::const_ret_type const_ret_type;
        typedef typename M::mem_manager_type mem_manager_type;
        typedef typename M::layout_type layout_type;
        const_ret_type apply ( long r, long c) const
        {
            if (r < R)
            {
                return m(r,c);
            }
            else
            {
                return m(r+1,c);
            }
        }

        long nr () const { return m.nr() - 1; }
        long nc () const { return m.nc(); }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }
    };

    template <
        long R,
        typename EXP
        >
    const matrix_op<op_remove_row<EXP,R> > remove_row (
        const matrix_exp<EXP>& m
    )
    {
        // You can't remove the given row from the matrix because the matrix doesn't
        // have a row with that index.
        COMPILE_TIME_ASSERT((EXP::NR > R && R >= 0) || EXP::NR == 0);
        DLIB_ASSERT(m.nr() > R && R >= 0,
            "\tconst matrix_exp remove_row<R>(const matrix_exp& m)"
            << "\n\tYou can't remove a row from a matrix if it doesn't have it"
            << "\n\tm.nr(): " << m.nr()
            << "\n\tm.nc(): " << m.nc()
            << "\n\tR:      " << R
            );
        typedef op_remove_row<EXP,R> op;
        return matrix_op<op>(op(m.ref()));
    }

    template <
        typename EXP
        >
    const matrix_op<op_remove_row2<EXP> > remove_row (
        const matrix_exp<EXP>& m,
        long R
    )
    {
        DLIB_ASSERT(m.nr() > R && R >= 0,
            "\tconst matrix_exp remove_row(const matrix_exp& m, long R)"
            << "\n\tYou can't remove a row from a matrix if it doesn't have it"
            << "\n\tm.nr(): " << m.nr()
            << "\n\tm.nc(): " << m.nc()
            << "\n\tR:      " << R
            );
        typedef op_remove_row2<EXP> op;
        return matrix_op<op>(op(m.ref(),R));
    }

// ----------------------------------------------------------------------------------------

    template <typename M>
    struct op_diagm
    {
        op_diagm( const M& m_) : m(m_){}
        const M& m;

        const static long cost = M::cost+2;
        const static long N = M::NC*M::NR;
        const static long NR = N;
        const static long NC = N;
        typedef typename M::type type;
        typedef const typename M::type const_ret_type;
        typedef typename M::mem_manager_type mem_manager_type;
        typedef typename M::layout_type layout_type;
        const_ret_type apply ( long r, long c) const
        {
            if (r==c)
                return m(r);
            else
                return 0;
        }

        long nr () const { return (m.nr()>m.nc())? m.nr():m.nc(); }
        long nc () const { return (m.nr()>m.nc())? m.nr():m.nc(); }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }
    };

    template <
        typename EXP
        >
    const matrix_diag_op<op_diagm<EXP> > diagm (
        const matrix_exp<EXP>& m
    )
    {
        // You can only make a diagonal matrix out of a row or column vector
        COMPILE_TIME_ASSERT(EXP::NR == 0 || EXP::NR == 1 || EXP::NC == 1 || EXP::NC == 0);
        DLIB_ASSERT(is_vector(m),
            "\tconst matrix_exp diagm(const matrix_exp& m)"
            << "\n\tYou can only apply diagm() to a row or column matrix"
            << "\n\tm.nr(): " << m.nr()
            << "\n\tm.nc(): " << m.nc()
            );
        typedef op_diagm<EXP> op;
        return matrix_diag_op<op>(op(m.ref()));
    }

// ----------------------------------------------------------------------------------------

    template <typename M1, typename M2>
    struct op_diagm_mult : basic_op_mm<M1,M2>
    {
        op_diagm_mult( const M1& m1_, const M2& m2_) : basic_op_mm<M1,M2>(m1_,m2_){}

        typedef typename M1::type type;
        typedef const type const_ret_type;
        const static long cost = M1::cost + M2::cost + 1;

        const_ret_type apply ( long r, long c) const
        {
            if (r == c)
                return this->m1(r,c)*this->m2(r,c);
            else
                return 0;
        }
    };

    template <
        typename EXP1,
        typename EXP2
        >
    inline const matrix_diag_op<op_diagm_mult<EXP1,EXP2> > operator* (
        const matrix_diag_exp<EXP1>& a,
        const matrix_diag_exp<EXP2>& b
    )
    {
        COMPILE_TIME_ASSERT((is_same_type<typename EXP1::type, typename EXP2::type>::value));
        COMPILE_TIME_ASSERT(EXP1::NR == EXP2::NR || EXP1::NR == 0 || EXP2::NR == 0);
        COMPILE_TIME_ASSERT(EXP1::NC == EXP2::NC || EXP1::NC == 0 || EXP2::NC == 0);
        DLIB_ASSERT(a.nr() == b.nr() &&
                    a.nc() == b.nc(),
            "\tconst matrix_exp operator(const matrix_diag_exp& a, const matrix_diag_exp& b)"
            << "\n\tYou can only multiply diagonal matrices together if they are the same size"
            << "\n\ta.nr(): " << a.nr()
            << "\n\ta.nc(): " << a.nc()
            << "\n\tb.nr(): " << b.nr()
            << "\n\tb.nc(): " << b.nc()
            );
        typedef op_diagm_mult<EXP1,EXP2> op;
        return matrix_diag_op<op>(op(a.ref(),b.ref()));
    }

// ----------------------------------------------------------------------------------------

    template <typename M>
    struct op_diag
    {
        op_diag( const M& m_) : m(m_){}
        const M& m;

        const static long cost = M::cost;
        const static long NR = tmin<M::NR,M::NC>::value;
        const static long NC = 1;
        typedef typename M::type type;
        typedef typename M::const_ret_type const_ret_type;
        typedef typename M::mem_manager_type mem_manager_type;
        typedef typename M::layout_type layout_type;
        const_ret_type apply ( long r, long ) const { return m(r,r); }

        long nr () const { return std::min(m.nc(),m.nr()); }
        long nc () const { return 1; }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }
    };

    template <
        typename EXP
        >
    const matrix_op<op_diag<EXP> > diag (
        const matrix_exp<EXP>& m
    )
    {
        typedef op_diag<EXP> op;
        return matrix_op<op>(op(m.ref()));
    }

    template <typename EXP>
    struct diag_exp
    {
        typedef matrix_op<op_diag<EXP> > type;
    };

// ----------------------------------------------------------------------------------------

    template <typename M, typename target_type>
    struct op_cast
    {
        op_cast( const M& m_) : m(m_){}
        const M& m;

        const static long cost = M::cost+2;
        const static long NR = M::NR;
        const static long NC = M::NC;
        typedef target_type type;
        typedef const target_type const_ret_type;
        typedef typename M::mem_manager_type mem_manager_type;
        typedef typename M::layout_type layout_type;
        const_ret_type apply ( long r, long c) const { return static_cast<target_type>(m(r,c)); }

        long nr () const { return m.nr(); }
        long nc () const { return m.nc(); }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.destructively_aliases(item); }
    };

    template <
        typename target_type,
        typename EXP
        >
    const matrix_op<op_cast<EXP, target_type> > matrix_cast (
        const matrix_exp<EXP>& m
    )
    {
        typedef op_cast<EXP, target_type> op;
        return matrix_op<op>(op(m.ref()));
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    namespace impl
    {
        template <typename type, typename S>
        inline type lessthan(const type& val, const S& s)
        {
            if (val < s)
                return 1;
            else
                return 0;
        }

    }
    DLIB_DEFINE_OP_MS(op_lessthan, impl::lessthan, 1);

    template <
        typename EXP,
        typename S
        >
    const typename enable_if<is_built_in_scalar_type<S>, matrix_op<op_lessthan<EXP,S> > >::type operator< (
        const matrix_exp<EXP>& m,
        const S& s
    )
    {
        // you can only use this relational operator with the built in scalar types like
        // long, float, etc.
        COMPILE_TIME_ASSERT(is_built_in_scalar_type<typename EXP::type>::value);

        typedef op_lessthan<EXP,S> op;
        return matrix_op<op>(op(m.ref(),s));
    }

    template <
        typename EXP,
        typename S
        >
    const typename enable_if<is_built_in_scalar_type<S>, matrix_op<op_lessthan<EXP,S> > >::type operator> (
        const S& s,
        const matrix_exp<EXP>& m
    )
    {
        // you can only use this relational operator with the built in scalar types like
        // long, float, etc.
        COMPILE_TIME_ASSERT(is_built_in_scalar_type<typename EXP::type>::value);

        typedef op_lessthan<EXP,S> op;
        return matrix_op<op>(op(m.ref(),s));
    }

// ----------------------------------------------------------------------------------------

    namespace impl
    {
        template <typename type, typename S>
        inline type lessthan_eq(const type& val, const S& s)
        {
            if (val <= s)
                return 1;
            else
                return 0;
        }

    }
    DLIB_DEFINE_OP_MS(op_lessthan_eq, impl::lessthan_eq, 1);

    template <
        typename EXP,
        typename S
        >
    const typename enable_if<is_built_in_scalar_type<S>, matrix_op<op_lessthan_eq<EXP,S> > >::type operator<= (
        const matrix_exp<EXP>& m,
        const S& s
    )
    {
        // you can only use this relational operator with the built in scalar types like
        // long, float, etc.
        COMPILE_TIME_ASSERT(is_built_in_scalar_type<typename EXP::type>::value);

        typedef op_lessthan_eq<EXP,S> op;
        return matrix_op<op>(op(m.ref(),s));
    }

    template <
        typename EXP,
        typename S
        >
    const typename enable_if<is_built_in_scalar_type<S>, matrix_op<op_lessthan_eq<EXP,S> > >::type operator>= (
        const S& s,
        const matrix_exp<EXP>& m
    )
    {
        // you can only use this relational operator with the built in scalar types like
        // long, float, etc.
        COMPILE_TIME_ASSERT(is_built_in_scalar_type<typename EXP::type>::value);

        typedef op_lessthan_eq<EXP,S> op;
        return matrix_op<op>(op(m.ref(),s));
    }

// ----------------------------------------------------------------------------------------

    namespace impl
    {
        template <typename type, typename S>
        inline type greaterthan(const type& val, const S& s)
        {
            if (val > s)
                return 1;
            else
                return 0;
        }

    }
    DLIB_DEFINE_OP_MS(op_greaterthan, impl::greaterthan, 1);

    template <
        typename EXP,
        typename S
        >
    const typename enable_if<is_built_in_scalar_type<S>, matrix_op<op_greaterthan<EXP,S> > >::type operator> (
        const matrix_exp<EXP>& m,
        const S& s
    )
    {
        // you can only use this relational operator with the built in scalar types like
        // long, float, etc.
        COMPILE_TIME_ASSERT(is_built_in_scalar_type<typename EXP::type>::value);

        typedef op_greaterthan<EXP,S> op;
        return matrix_op<op>(op(m.ref(),s));
    }

    template <
        typename EXP,
        typename S
        >
    const typename enable_if<is_built_in_scalar_type<S>, matrix_op<op_greaterthan<EXP,S> > >::type operator< (
        const S& s,
        const matrix_exp<EXP>& m
    )
    {
        // you can only use this relational operator with the built in scalar types like
        // long, float, etc.
        COMPILE_TIME_ASSERT(is_built_in_scalar_type<typename EXP::type>::value);

        typedef op_greaterthan<EXP,S> op;
        return matrix_op<op>(op(m.ref(),s));
    }

// ----------------------------------------------------------------------------------------

    namespace impl
    {
        template <typename type, typename S>
        inline type greaterthan_eq(const type& val, const S& s)
        {
            if (val >= s)
                return 1;
            else
                return 0;
        }

    }
    DLIB_DEFINE_OP_MS(op_greaterthan_eq, impl::greaterthan_eq, 1);

    template <
        typename EXP,
        typename S
        >
    const typename enable_if<is_built_in_scalar_type<S>, matrix_op<op_greaterthan_eq<EXP,S> > >::type operator>= (
        const matrix_exp<EXP>& m,
        const S& s
    )
    {
        // you can only use this relational operator with the built in scalar types like
        // long, float, etc.
        COMPILE_TIME_ASSERT(is_built_in_scalar_type<typename EXP::type>::value);

        typedef op_greaterthan_eq<EXP,S> op;
        return matrix_op<op>(op(m.ref(),s));
    }

    template <
        typename EXP,
        typename S
        >
    const typename enable_if<is_built_in_scalar_type<S>, matrix_op<op_greaterthan_eq<EXP,S> > >::type operator<= (
        const S& s,
        const matrix_exp<EXP>& m
    )
    {
        // you can only use this relational operator with the built in scalar types like
        // long, float, etc.
        COMPILE_TIME_ASSERT(is_built_in_scalar_type<typename EXP::type>::value);

        typedef op_greaterthan_eq<EXP,S> op;
        return matrix_op<op>(op(m.ref(),s));
    }

// ----------------------------------------------------------------------------------------

    namespace impl
    {
        template <typename type, typename S>
        inline type equal_to(const type& val, const S& s)
        {
            if (val == s)
                return 1;
            else
                return 0;
        }

    }
    DLIB_DEFINE_OP_MS(op_equal_to, impl::equal_to, 1);

    template <
        typename EXP,
        typename S
        >
    const typename enable_if<is_built_in_scalar_type<S>, matrix_op<op_equal_to<EXP,S> > >::type operator== (
        const matrix_exp<EXP>& m,
        const S& s
    )
    {
        // you can only use this relational operator with the built in scalar types like
        // long, float, etc.
        COMPILE_TIME_ASSERT( is_built_in_scalar_type<typename EXP::type>::value);

        typedef op_equal_to<EXP,S> op;
        return matrix_op<op>(op(m.ref(),s));
    }

    template <
        typename EXP,
        typename S
        >
    const typename enable_if<is_built_in_scalar_type<S>, matrix_op<op_equal_to<EXP,S> > >::type operator== (
        const S& s,
        const matrix_exp<EXP>& m
    )
    {
        // you can only use this relational operator with the built in scalar types like
        // long, float, etc.
        COMPILE_TIME_ASSERT( is_built_in_scalar_type<typename EXP::type>::value);

        typedef op_equal_to<EXP,S> op;
        return matrix_op<op>(op(m.ref(),s));
    }

// ----------------------------------------------------------------------------------------

    namespace impl
    {
        template <typename type, typename S>
        inline type not_equal_to(const type& val, const S& s)
        {
            if (val != s)
                return 1;
            else
                return 0;
        }

    }
    DLIB_DEFINE_OP_MS(op_not_equal_to, impl::not_equal_to, 1);

    template <
        typename EXP,
        typename S
        >
    const typename enable_if<is_built_in_scalar_type<S>, matrix_op<op_not_equal_to<EXP,S> > >::type operator!= (
        const matrix_exp<EXP>& m,
        const S& s
    )
    {
        // you can only use this relational operator with the built in scalar types like
        // long, float, etc.
        COMPILE_TIME_ASSERT(is_built_in_scalar_type<typename EXP::type>::value);

        typedef op_not_equal_to<EXP,S> op;
        return matrix_op<op>(op(m.ref(),s));
    }

    template <
        typename EXP,
        typename S
        >
    const typename enable_if<is_built_in_scalar_type<S>, matrix_op<op_not_equal_to<EXP,S> > >::type operator!= (
        const S& s,
        const matrix_exp<EXP>& m
    )
    {
        // you can only use this relational operator with the built in scalar types like
        // long, float, etc.
        COMPILE_TIME_ASSERT(is_built_in_scalar_type<typename EXP::type>::value);

        typedef op_not_equal_to<EXP,S> op;
        return matrix_op<op>(op(m.ref(),s));
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        long NR,
        long NC,
        typename MM,
        typename U,
        typename L
        >
    typename disable_if<is_matrix<U>,void>::type set_all_elements (
        matrix<T,NR,NC,MM,L>& m,
        const U& value
    )
    {
        // The value you are trying to assign to each element of the m matrix
        // doesn't have the appropriate type.
        COMPILE_TIME_ASSERT(is_matrix<T>::value == is_matrix<U>::value);

        for (long r = 0; r < m.nr(); ++r)
        {
            for (long c = 0; c < m.nc(); ++c)
            {
                m(r,c) = static_cast<T>(value);
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        long NR,
        long NC,
        typename MM,
        typename U,
        typename L
        >
    typename enable_if<is_matrix<U>,void>::type set_all_elements (
        matrix<T,NR,NC,MM,L>& m,
        const U& value
    )
    {
        for (long r = 0; r < m.nr(); ++r)
        {
            for (long c = 0; c < m.nc(); ++c)
            {
                m(r,c) = value;
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP
        >
    inline const typename matrix_exp<EXP>::matrix_type tmp (
        const matrix_exp<EXP>& m
    )
    {
        return typename matrix_exp<EXP>::matrix_type (m);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP
        >
    const typename lazy_disable_if<is_matrix<typename EXP::type>, EXP>::type sum (
        const matrix_exp<EXP>& m
    )
    {
        typedef typename matrix_exp<EXP>::type type;

        type val = 0;
        for (long r = 0; r < m.nr(); ++r)
        {
            for (long c = 0; c < m.nc(); ++c)
            {
                val += m(r,c);
            }
        }
        return val;
    }

    template <
        typename EXP
        >
    const typename lazy_enable_if<is_matrix<typename EXP::type>, EXP>::type sum (
        const matrix_exp<EXP>& m
    )
    {
        typedef typename matrix_exp<EXP>::type type;

        type val;
        if (m.size() > 0)
            val.set_size(m(0,0).nr(),m(0,0).nc());
        set_all_elements(val,0);

        for (long r = 0; r < m.nr(); ++r)
        {
            for (long c = 0; c < m.nc(); ++c)
            {
                val += m(r,c);
            }
        }
        return val;
    }

// ----------------------------------------------------------------------------------------

    template <typename M>
    struct op_sumr
    {
        op_sumr(const M& m_) : m(m_) {}
        const M& m;

        const static long cost = M::cost+10;
        const static long NR = 1;
        const static long NC = M::NC;
        typedef typename M::type type;
        typedef const typename M::type const_ret_type;
        typedef typename M::mem_manager_type mem_manager_type;
        typedef typename M::layout_type layout_type;
        const_ret_type apply ( long , long c) const
        {
            type temp = m(0,c);
            for (long r = 1; r < m.nr(); ++r)
                temp += m(r,c);
            return temp;
        }

        long nr () const { return 1; }
        long nc () const { return m.nc(); }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }
    };

    template <
        typename EXP
        >
    const matrix_op<op_sumr<EXP> > sum_rows (
        const matrix_exp<EXP>& m
    )
    {
        DLIB_ASSERT(m.size() > 0 ,
                    "\tconst matrix_exp sum_rows(m)"
                    << "\n\t The matrix can't be empty"
                    << "\n\t m.size(): " << m.size()
        );
        typedef op_sumr<EXP> op;
        return matrix_op<op>(op(m.ref()));
    }

// ----------------------------------------------------------------------------------------

    template <typename M>
    struct op_sumc
    {
        op_sumc(const M& m_) : m(m_) {}
        const M& m;

        const static long cost = M::cost + 10;
        const static long NR = M::NR;
        const static long NC = 1;
        typedef typename M::type type;
        typedef const typename M::type const_ret_type;
        typedef typename M::mem_manager_type mem_manager_type;
        typedef typename M::layout_type layout_type;
        const_ret_type apply ( long r, long ) const
        {
            type temp = m(r,0);
            for (long c = 1; c < m.nc(); ++c)
                temp += m(r,c);
            return temp;
        }

        long nr () const { return m.nr(); }
        long nc () const { return 1; }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }
    };

    template <
        typename EXP
        >
    const matrix_op<op_sumc<EXP> > sum_cols (
        const matrix_exp<EXP>& m
    )
    {
        DLIB_ASSERT(m.size() > 0 ,
                    "\tconst matrix_exp sum_cols(m)"
                    << "\n\t The matrix can't be empty"
                    << "\n\t m.size(): " << m.size()
        );
        typedef op_sumc<EXP> op;
        return matrix_op<op>(op(m.ref()));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP
        >
    inline const typename disable_if<is_complex<typename EXP::type>, typename matrix_exp<EXP>::type>::type mean (
        const matrix_exp<EXP>& m
    )
    {
        return sum(m)/(m.nr()*m.nc());
    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP
        >
    inline const typename enable_if<is_complex<typename EXP::type>, typename matrix_exp<EXP>::type>::type mean (
        const matrix_exp<EXP>& m
    )
    {
        typedef typename EXP::type::value_type type;
        return sum(m)/(type)(m.nr()*m.nc());
    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP
        >
    const typename matrix_exp<EXP>::type variance (
        const matrix_exp<EXP>& m
    )
    {
        using std::pow;
        using dlib::pow;
        const typename matrix_exp<EXP>::type avg = mean(m);

        typedef typename matrix_exp<EXP>::type type;

        type val;
        val = 0;
        for (long r = 0; r < m.nr(); ++r)
        {
            for (long c = 0; c < m.nc(); ++c)
            {
                val += pow(m(r,c) - avg,2);
            }
        }

        if (m.nr() * m.nc() <= 1)
        {
            return val;
        }
        else
        {
            // Note, for some reason, in gcc 4.1 performing this division using a
            // double instead of a long value avoids a segmentation fault.  That is,
            // using 1.0 instead of 1 does the trick.
            return val/(m.nr()*m.nc() - 1.0);
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP
        >
    const typename matrix_exp<EXP>::type stddev (
        const matrix_exp<EXP>& m
    )
    {
        using std::sqrt;
        using dlib::sqrt;
        return sqrt(variance(m));
    }

// ----------------------------------------------------------------------------------------

// this is a workaround for a bug in visual studio 7.1
    template <typename EXP>
    struct visual_studio_sucks_cov_helper
    {
        typedef typename EXP::type inner_type;
        typedef matrix<typename inner_type::type, inner_type::NR, inner_type::NR, typename EXP::mem_manager_type> type;
    };

    template <
        typename EXP
        >
    const typename visual_studio_sucks_cov_helper<EXP>::type covariance (
        const matrix_exp<EXP>& m
    )
    {
        // perform static checks to make sure m is a column vector
        COMPILE_TIME_ASSERT(EXP::NR == 0 || EXP::NR > 1);
        COMPILE_TIME_ASSERT(EXP::NC == 1 || EXP::NC == 0);

        // perform static checks to make sure the matrices contained in m are column vectors
        COMPILE_TIME_ASSERT(EXP::type::NC == 1 || EXP::type::NC == 0 );

        DLIB_ASSERT(m.size() > 1 && is_col_vector(m),
            "\tconst matrix covariance(const matrix_exp& m)"
            << "\n\tYou can only apply covariance() to a column matrix"
            << "\n\tm.nr(): " << m.nr()
            << "\n\tm.nc(): " << m.nc()
            );
#ifdef ENABLE_ASSERTS
        for (long i = 0; i < m.nr(); ++i)
        {
            DLIB_ASSERT(m(0).size() == m(i).size() && m(i).size() > 0 && is_col_vector(m(i)),
                   "\tconst matrix covariance(const matrix_exp& m)"
                   << "\n\tYou can only apply covariance() to a column matrix of column matrices"
                   << "\n\tm(0).size(): " << m(0).size()
                   << "\n\tm(i).size(): " << m(i).size()
                   << "\n\tis_col_vector(m(i)): " << (is_col_vector(m(i)) ? "true" : "false")
                   << "\n\ti:         " << i
                );
        }
#endif

        // now perform the actual calculation of the covariance matrix.
        typename visual_studio_sucks_cov_helper<EXP>::type cov(m(0).nr(),m(0).nr());
        set_all_elements(cov,0);

        const typename EXP::type avg = mean(m);

        for (long r = 0; r < m.nr(); ++r)
        {
            cov += (m(r) - avg)*trans(m(r) - avg);
        }

        cov *= 1.0 / (m.nr() - 1.0);
        return cov;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP
        >
    const typename matrix_exp<EXP>::type prod (
        const matrix_exp<EXP>& m
    )
    {
        typedef typename matrix_exp<EXP>::type type;

        type val = 1;
        for (long r = 0; r < m.nr(); ++r)
        {
            for (long c = 0; c < m.nc(); ++c)
            {
                val *= m(r,c);
            }
        }
        return val;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    struct op_uniform_matrix_3 : does_not_alias
    {
        op_uniform_matrix_3(const long& rows_, const long& cols_, const T& val_ ) :
            rows(rows_), cols(cols_), val(val_)  {}

        const long rows;
        const long cols;
        const T val;

        const static long cost = 1;
        const static long NR = 0;
        const static long NC = 0;
        typedef default_memory_manager mem_manager_type;
        typedef row_major_layout layout_type;
        typedef T type;
        typedef const T& const_ret_type;
        const_ret_type apply (long, long ) const { return val; }

        long nr() const { return rows; }
        long nc() const { return cols; }
    };

    template <
        typename T
        >
    const matrix_op<op_uniform_matrix_3<T> > uniform_matrix (
        long nr,
        long nc,
        const T& val
    )
    {
        DLIB_ASSERT(nr >= 0 && nc >= 0,
            "\tconst matrix_exp uniform_matrix<T>(nr, nc, val)"
            << "\n\tnr and nc have to be bigger than 0"
            << "\n\tnr: " << nr
            << "\n\tnc: " << nc
            );
        typedef op_uniform_matrix_3<T> op;
        return matrix_op<op>(op(nr, nc, val));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    const matrix_op<op_uniform_matrix_3<T> > zeros_matrix (
        long nr,
        long nc
    )
    {
        DLIB_ASSERT(nr >= 0 && nc >= 0,
            "\tconst matrix_exp zeros_matrix<T>(nr, nc)"
            << "\n\tnr and nc have to be >= 0"
            << "\n\tnr: " << nr
            << "\n\tnc: " << nc
            );
        typedef op_uniform_matrix_3<T> op;
        return matrix_op<op>(op(nr, nc, 0));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP
        >
    const matrix_op<op_uniform_matrix_3<typename EXP::type> > zeros_matrix (
        const matrix_exp<EXP>& mat
    )
    {
        DLIB_ASSERT(mat.nr() >= 0 && mat.nc() >= 0,
            "\tconst matrix_exp zeros_matrix(mat)"
            << "\n\t nr and nc have to be >= 0"
            << "\n\t mat.nr(): " << mat.nr()
            << "\n\t mat.nc(): " << mat.nc()
            );
        typedef typename EXP::type T;
        typedef op_uniform_matrix_3<T> op;
        return matrix_op<op>(op(mat.nr(), mat.nc(), 0));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    const matrix_op<op_uniform_matrix_3<T> > ones_matrix (
        long nr,
        long nc
    )
    {
        DLIB_ASSERT(nr >= 0 && nc >= 0,
            "\tconst matrix_exp ones_matrix<T>(nr, nc)"
            << "\n\tnr and nc have to be >= 0"
            << "\n\tnr: " << nr
            << "\n\tnc: " << nc
            );
        typedef op_uniform_matrix_3<T> op;
        return matrix_op<op>(op(nr, nc, 1));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP
        >
    const matrix_op<op_uniform_matrix_3<typename EXP::type> > ones_matrix (
        const matrix_exp<EXP>& mat
    )
    {
        DLIB_ASSERT(mat.nr() >= 0 && mat.nc() >= 0,
            "\tconst matrix_exp ones_matrix(mat)"
            << "\n\t nr and nc have to be >= 0"
            << "\n\t mat.nr(): " << mat.nr()
            << "\n\t mat.nc(): " << mat.nc()
            );
        typedef typename EXP::type T;
        typedef op_uniform_matrix_3<T> op;
        return matrix_op<op>(op(mat.nr(), mat.nc(), 1));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        long NR_,
        long NC_
        >
    struct op_uniform_matrix_2 : does_not_alias
    {
        op_uniform_matrix_2( const T& val_ ) : val(val_) {}
        const T val;

        const static long cost = 1;
        const static long NR = NR_;
        const static long NC = NC_;
        typedef default_memory_manager mem_manager_type;
        typedef row_major_layout layout_type;
        typedef T type;
        typedef const T& const_ret_type;

        const_ret_type apply (long , long ) const { return val; }

        long nr() const { return NR; }
        long nc() const { return NC; }
    };

    template <
        typename T,
        long NR,
        long NC
        >
    const matrix_op<op_uniform_matrix_2<T,NR,NC> > uniform_matrix (
        const T& val
    )
    {
        COMPILE_TIME_ASSERT(NR > 0 && NC > 0);

        typedef op_uniform_matrix_2<T,NR,NC> op;
        return matrix_op<op>(op(val));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        long NR_,
        long NC_,
        T val
        >
    struct op_uniform_matrix : does_not_alias
    {
        const static long cost = 1;
        const static long NR = NR_;
        const static long NC = NC_;
        typedef default_memory_manager mem_manager_type;
        typedef row_major_layout layout_type;
        typedef T type;
        typedef const T const_ret_type;
        const_ret_type apply ( long , long ) const { return val; }

        long nr() const { return NR; }
        long nc() const { return NC; }
    };

    template <
        typename T,
        long NR,
        long NC,
        T val
        >
    const matrix_op<op_uniform_matrix<T,NR,NC,val> > uniform_matrix (
    )
    {
        COMPILE_TIME_ASSERT(NR > 0 && NC > 0);
        typedef op_uniform_matrix<T,NR,NC,val> op;
        return matrix_op<op>(op());
    }

// ----------------------------------------------------------------------------------------

    struct op_gaussian_randm : does_not_alias
    {
        op_gaussian_randm (
            long nr_,
            long nc_,
            unsigned long seed_
        ) :_nr(nr_), _nc(nc_), seed(seed_){}

        const long _nr;
        const long _nc;
        const unsigned long seed;

        const static long cost = 100;
        const static long NR = 0;
        const static long NC = 0;
        typedef default_memory_manager mem_manager_type;
        typedef row_major_layout layout_type;
        typedef double type;
        typedef double const_ret_type;
        const_ret_type apply ( long r, long c) const { return gaussian_random_hash(r,c,seed); }

        long nr() const { return _nr; }
        long nc() const { return _nc; }
    };

    inline const matrix_op<op_gaussian_randm> gaussian_randm (
        long nr,
        long nc,
        unsigned long seed = 0
    )
    {
        DLIB_ASSERT(nr >= 0 && nc >= 0,
            "\tmatrix_exp gaussian_randm(nr, nc, seed)"
            << "\n\tInvalid inputs to this function"
            << "\n\tnr: " << nr
            << "\n\tnc: " << nc
            );

        typedef op_gaussian_randm op;
        return matrix_op<op>(op(nr,nc,seed));
    }

// ----------------------------------------------------------------------------------------

    template <typename M>
    struct op_add_diag
    {
        op_add_diag( const M& m_, const typename M::type& value_) : m(m_), value(value_){}
        const M& m;
        const typename M::type value;

        const static long cost = M::cost+1;
        const static long NR = M::NR;
        const static long NC = M::NC;
        typedef typename M::type type;
        typedef const typename M::type const_ret_type;
        typedef typename M::mem_manager_type mem_manager_type;
        typedef typename M::layout_type layout_type;
        const_ret_type apply ( long r, long c) const
        {
            if (r==c)
                return m(r,c)+value;
            else
                return m(r,c);
        }

        long nr () const { return m.nr(); }
        long nc () const { return m.nc(); }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.destructively_aliases(item); }
    };

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    struct op_identity_matrix_2 : does_not_alias
    {
        op_identity_matrix_2(const long& size_) : size(size_) {}

        const long size;

        const static long cost = 1;
        const static long NR = 0;
        const static long NC = 0;
        typedef default_memory_manager mem_manager_type;
        typedef row_major_layout layout_type;
        typedef T type;
        typedef const T const_ret_type;
        const_ret_type apply (long r, long c) const { return static_cast<type>(r == c); }

        long nr() const { return size; }
        long nc() const { return size; }
    };

    template <
        typename T,
        typename U
        >
    const matrix_diag_op<op_identity_matrix_2<T> > identity_matrix (
        const U& size
    )
    {
        // the size argument must be some scalar value, not a matrix!
        COMPILE_TIME_ASSERT(is_matrix<U>::value == false);

        DLIB_ASSERT(size > 0,
            "\tconst matrix_exp identity_matrix<T>(size)"
            << "\n\tsize must be bigger than 0"
            << "\n\tsize: " << size
            );
        typedef op_identity_matrix_2<T> op;
        return matrix_diag_op<op>(op(size));
    }

    template <
        typename EXP
        >
    const matrix_diag_op<op_identity_matrix_2<typename EXP::type> > identity_matrix (
        const matrix_exp<EXP>& mat
    )
    {
        DLIB_ASSERT(mat.nr() == mat.nc(),
            "\tconst matrix_exp identity_matrix(mat)"
            << "\n\t mat must be a square matrix."
            << "\n\t mat.nr(): " << mat.nr()
            << "\n\t mat.nc(): " << mat.nc()
            );
        typedef typename EXP::type T;
        typedef op_identity_matrix_2<T> op;
        return matrix_diag_op<op>(op(mat.nr()));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP,
        typename T
        >
    const matrix_op<op_add_diag<EXP> > operator+ (
        const matrix_exp<EXP>& lhs,
        const matrix_exp<matrix_diag_op<op_identity_matrix_2<T> > >& DLIB_IF_ASSERT(rhs)
    )
    {
        // both matrices must contain the same type of element
        COMPILE_TIME_ASSERT((is_same_type<T,typename EXP::type>::value == true));

        // You can only add matrices together if they both have the same number of rows and columns.
        DLIB_ASSERT(lhs.nc() == rhs.nc() &&
                    lhs.nr() == rhs.nr(),
            "\tconst matrix_exp operator+(const matrix_exp& lhs, const matrix_exp& rhs)"
            << "\n\tYou are trying to add two incompatible matrices together"
            << "\n\tlhs.nr(): " << lhs.nr()
            << "\n\tlhs.nc(): " << lhs.nc()
            << "\n\trhs.nr(): " << rhs.nr()
            << "\n\trhs.nc(): " << rhs.nc()
            << "\n\t&lhs: " << &lhs
            << "\n\t&rhs: " << &rhs
            );

        typedef op_add_diag<EXP> op;
        return matrix_op<op>(op(lhs.ref(),1));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP,
        typename T
        >
    const matrix_op<op_add_diag<EXP> > operator+ (
        const matrix_exp<matrix_diag_op<op_identity_matrix_2<T> > >& DLIB_IF_ASSERT(lhs),
        const matrix_exp<EXP>& rhs
    )
    {
        // both matrices must contain the same type of element
        COMPILE_TIME_ASSERT((is_same_type<T,typename EXP::type>::value == true));

        // You can only add matrices together if they both have the same number of rows and columns.
        DLIB_ASSERT(lhs.nc() == rhs.nc() &&
                    lhs.nr() == rhs.nr(),
            "\tconst matrix_exp operator+(const matrix_exp& lhs, const matrix_exp& rhs)"
            << "\n\tYou are trying to add two incompatible matrices together"
            << "\n\tlhs.nr(): " << lhs.nr()
            << "\n\tlhs.nc(): " << lhs.nc()
            << "\n\trhs.nr(): " << rhs.nr()
            << "\n\trhs.nc(): " << rhs.nc()
            << "\n\t&lhs: " << &lhs
            << "\n\t&rhs: " << &rhs
            );

        typedef op_add_diag<EXP> op;
        return matrix_op<op>(op(rhs.ref(),1));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        long N
        >
    struct op_const_diag_matrix : does_not_alias
    {
        op_const_diag_matrix(const long& size_, const T& value_) : size(size_),value(value_) {}

        const long size;
        const T value;

        const static long cost = 1;
        const static long NR = N;
        const static long NC = N;
        typedef default_memory_manager mem_manager_type;
        typedef row_major_layout layout_type;
        typedef T type;
        typedef const T const_ret_type;
        const_ret_type apply (long r, long c) const
        {
            if (r == c)
                return value;
            else
                return 0;
        }

        long nr() const { return size; }
        long nc() const { return size; }
    };

    template <
        typename T,
        typename U
        >
    const typename disable_if<is_matrix<U>, matrix_diag_op<op_const_diag_matrix<T,0> > >::type operator* (
        const matrix_exp<matrix_diag_op<op_identity_matrix_2<T> > >& m,
        const U& value
    )
    {
        typedef op_const_diag_matrix<T,0> op;
        return matrix_diag_op<op>(op(m.nr(), value));
    }

    template <
        typename T,
        typename U
        >
    const typename disable_if<is_matrix<U>, matrix_diag_op<op_const_diag_matrix<T,0> > >::type operator* (
        const U& value,
        const matrix_exp<matrix_diag_op<op_identity_matrix_2<T> > >& m
    )
    {
        typedef op_const_diag_matrix<T,0> op;
        return matrix_diag_op<op>(op(m.nr(), value));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP,
        typename T,
        long N
        >
    const matrix_op<op_add_diag<EXP> > operator+ (
        const matrix_exp<EXP>& lhs,
        const matrix_exp<matrix_diag_op<op_const_diag_matrix<T,N> > >& rhs
    )
    {
        // both matrices must contain the same type of element
        COMPILE_TIME_ASSERT((is_same_type<T,typename EXP::type>::value == true));

        // You can only add matrices together if they both have the same number of rows and columns.
        DLIB_ASSERT(lhs.nc() == rhs.nc() &&
                    lhs.nr() == rhs.nr(),
            "\tconst matrix_exp operator+(const matrix_exp& lhs, const matrix_exp& rhs)"
            << "\n\tYou are trying to add two incompatible matrices together"
            << "\n\tlhs.nr(): " << lhs.nr()
            << "\n\tlhs.nc(): " << lhs.nc()
            << "\n\trhs.nr(): " << rhs.nr()
            << "\n\trhs.nc(): " << rhs.nc()
            << "\n\t&lhs: " << &lhs
            << "\n\t&rhs: " << &rhs
            );

        typedef op_add_diag<EXP> op;
        return matrix_op<op>(op(lhs.ref(),rhs.ref().op.value));
    }

    template <
        typename EXP,
        typename T,
        long N
        >
    const matrix_op<op_add_diag<EXP> > operator+ (
        const matrix_exp<matrix_diag_op<op_const_diag_matrix<T,N> > >& lhs,
        const matrix_exp<EXP>& rhs
    )
    {
        // both matrices must contain the same type of element
        COMPILE_TIME_ASSERT((is_same_type<T,typename EXP::type>::value == true));

        // You can only add matrices together if they both have the same number of rows and columns.
        DLIB_ASSERT(lhs.nc() == rhs.nc() &&
                    lhs.nr() == rhs.nr(),
            "\tconst matrix_exp operator+(const matrix_exp& lhs, const matrix_exp& rhs)"
            << "\n\tYou are trying to add two incompatible matrices together"
            << "\n\tlhs.nr(): " << lhs.nr()
            << "\n\tlhs.nc(): " << lhs.nc()
            << "\n\trhs.nr(): " << rhs.nr()
            << "\n\trhs.nc(): " << rhs.nc()
            << "\n\t&lhs: " << &lhs
            << "\n\t&rhs: " << &rhs
            );

        typedef op_add_diag<EXP> op;
        return matrix_op<op>(op(rhs.ref(),lhs.ref().op.value));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        long N
        >
    struct op_identity_matrix : does_not_alias
    {
        const static long cost = 1;
        const static long NR = N;
        const static long NC = N;
        typedef default_memory_manager mem_manager_type;
        typedef row_major_layout layout_type;
        typedef T type;
        typedef const T const_ret_type;
        const_ret_type apply ( long r, long c) const { return static_cast<type>(r == c); }

        long nr () const { return NR; }
        long nc () const { return NC; }
    };

    template <
        typename T,
        long N
        >
    const matrix_diag_op<op_identity_matrix<T,N> > identity_matrix (
    )
    {
        COMPILE_TIME_ASSERT(N > 0);

        typedef op_identity_matrix<T,N> op;
        return matrix_diag_op<op>(op());
    }

    template <
        typename T,
        typename U,
        long N
        >
    const typename disable_if<is_matrix<U>, matrix_diag_op<op_const_diag_matrix<T,N> > >::type operator* (
        const matrix_exp<matrix_diag_op<op_identity_matrix<T,N> > >& m,
        const U& value
    )
    {
        typedef op_const_diag_matrix<T,N> op;
        return matrix_diag_op<op>(op(m.nr(), value));
    }

    template <
        typename T,
        typename U,
        long N
        >
    const typename disable_if<is_matrix<U>, matrix_diag_op<op_const_diag_matrix<T,N> > >::type operator* (
        const U& value,
        const matrix_exp<matrix_diag_op<op_identity_matrix<T,N> > >& m
    )
    {
        typedef op_const_diag_matrix<T,N> op;
        return matrix_diag_op<op>(op(m.nr(), value));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP,
        typename T,
        long N
        >
    const matrix_op<op_add_diag<EXP> > operator+ (
        const matrix_exp<matrix_diag_op<op_identity_matrix<T,N> > >& DLIB_IF_ASSERT(lhs),
        const matrix_exp<EXP>& rhs
    )
    {
        // both matrices must contain the same type of element
        COMPILE_TIME_ASSERT((is_same_type<T,typename EXP::type>::value == true));

        // You can only add matrices together if they both have the same number of rows and columns.
        DLIB_ASSERT(lhs.nc() == rhs.nc() &&
                    lhs.nr() == rhs.nr(),
            "\tconst matrix_exp operator+(const matrix_exp& lhs, const matrix_exp& rhs)"
            << "\n\tYou are trying to add two incompatible matrices together"
            << "\n\tlhs.nr(): " << lhs.nr()
            << "\n\tlhs.nc(): " << lhs.nc()
            << "\n\trhs.nr(): " << rhs.nr()
            << "\n\trhs.nc(): " << rhs.nc()
            << "\n\t&lhs: " << &lhs
            << "\n\t&rhs: " << &rhs
            );

        typedef op_add_diag<EXP> op;
        return matrix_op<op>(op(rhs.ref(),1));
    }

    template <
        typename EXP,
        typename T,
        long N
        >
    const matrix_op<op_add_diag<EXP> > operator+ (
        const matrix_exp<EXP>& lhs,
        const matrix_exp<matrix_diag_op<op_identity_matrix<T,N> > >& DLIB_IF_ASSERT(rhs)
    )
    {
        // both matrices must contain the same type of element
        COMPILE_TIME_ASSERT((is_same_type<T,typename EXP::type>::value == true));

        // You can only add matrices together if they both have the same number of rows and columns.
        DLIB_ASSERT(lhs.nc() == rhs.nc() &&
                    lhs.nr() == rhs.nr(),
            "\tconst matrix_exp operator+(const matrix_exp& lhs, const matrix_exp& rhs)"
            << "\n\tYou are trying to add two incompatible matrices together"
            << "\n\tlhs.nr(): " << lhs.nr()
            << "\n\tlhs.nc(): " << lhs.nc()
            << "\n\trhs.nr(): " << rhs.nr()
            << "\n\trhs.nc(): " << rhs.nc()
            << "\n\t&lhs: " << &lhs
            << "\n\t&rhs: " << &rhs
            );

        typedef op_add_diag<EXP> op;
        return matrix_op<op>(op(lhs.ref(),1));
    }

// ----------------------------------------------------------------------------------------

    template <typename M, long R, long C>
    struct op_rotate
    {
        op_rotate(const M& m_) : m(m_) {}
        const M& m;

        const static long cost = M::cost + 2;
        const static long NR = M::NR;
        const static long NC = M::NC;
        typedef typename M::type type;
        typedef typename M::const_ret_type const_ret_type;
        typedef typename M::mem_manager_type mem_manager_type;
        typedef typename M::layout_type layout_type;
        const_ret_type apply ( long r, long c) const { return m((r+R)%m.nr(),(c+C)%m.nc()); }

        long nr () const { return m.nr(); }
        long nc () const { return m.nc(); }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }
    };

    template <
        long R,
        long C,
        typename EXP
        >
    const matrix_op<op_rotate<EXP,R,C> > rotate (
        const matrix_exp<EXP>& m
    )
    {
        typedef op_rotate<EXP,R,C> op;
        return matrix_op<op>(op(m.ref()));
    }

// ----------------------------------------------------------------------------------------

    namespace impl
    {
        // A template to tell me if two types can be multiplied together in a sensible way.  Here
        // I'm saying it is ok if they are both the same type or one is the complex version of the other.
        template <typename T, typename U> struct compatible { static const bool value = false;  typedef T type; };
        template <typename T>             struct compatible<T,T> { static const bool value = true; typedef T type; };
        template <typename T>             struct compatible<std::complex<T>,T> { static const bool value = true; typedef std::complex<T> type;  };
        template <typename T>             struct compatible<T,std::complex<T> > { static const bool value = true; typedef std::complex<T> type; };
    }

    template <typename M1, typename M2>
    struct op_pointwise_multiply : basic_op_mm<M1,M2>
    {
        op_pointwise_multiply( const M1& m1_, const M2& m2_) : basic_op_mm<M1,M2>(m1_,m2_){}

        typedef typename impl::compatible<typename M1::type, typename M2::type>::type type;
        typedef const type const_ret_type;
        const static long cost = M1::cost + M2::cost + 1;

        const_ret_type apply ( long r, long c) const
        { return this->m1(r,c)*this->m2(r,c); }
    };

    template <
        typename EXP1,
        typename EXP2
        >
    inline const matrix_op<op_pointwise_multiply<EXP1,EXP2> > pointwise_multiply (
        const matrix_exp<EXP1>& a,
        const matrix_exp<EXP2>& b
    )
    {
        COMPILE_TIME_ASSERT((impl::compatible<typename EXP1::type,typename EXP2::type>::value == true));
        COMPILE_TIME_ASSERT(EXP1::NR == EXP2::NR || EXP1::NR == 0 || EXP2::NR == 0);
        COMPILE_TIME_ASSERT(EXP1::NC == EXP2::NC || EXP1::NC == 0 || EXP2::NC == 0);
        DLIB_ASSERT(a.nr() == b.nr() &&
               a.nc() == b.nc(),
            "\tconst matrix_exp pointwise_multiply(const matrix_exp& a, const matrix_exp& b)"
            << "\n\tYou can only make a do a pointwise multiply with two equally sized matrices"
            << "\n\ta.nr(): " << a.nr()
            << "\n\ta.nc(): " << a.nc()
            << "\n\tb.nr(): " << b.nr()
            << "\n\tb.nc(): " << b.nc()
            );
        typedef op_pointwise_multiply<EXP1,EXP2> op;
        return matrix_op<op>(op(a.ref(),b.ref()));
    }

// ----------------------------------------------------------------------------------------

    template <typename M1, typename M2, typename M3>
    struct op_pointwise_multiply3 : basic_op_mmm<M1,M2,M3>
    {
        op_pointwise_multiply3( const M1& m1_, const M2& m2_, const M3& m3_) :
            basic_op_mmm<M1,M2,M3>(m1_,m2_,m3_){}

        typedef typename M1::type type;
        typedef const typename M1::type const_ret_type;
        const static long cost = M1::cost + M2::cost + M3::cost + 2;

        const_ret_type apply (long r, long c) const
        { return this->m1(r,c)*this->m2(r,c)*this->m3(r,c); }
    };

    template <
        typename EXP1,
        typename EXP2,
        typename EXP3
        >
    inline const matrix_op<op_pointwise_multiply3<EXP1,EXP2,EXP3> >
        pointwise_multiply (
        const matrix_exp<EXP1>& a,
        const matrix_exp<EXP2>& b,
        const matrix_exp<EXP3>& c
    )
    {
        COMPILE_TIME_ASSERT((is_same_type<typename EXP1::type,typename EXP2::type>::value == true));
        COMPILE_TIME_ASSERT((is_same_type<typename EXP2::type,typename EXP3::type>::value == true));
        COMPILE_TIME_ASSERT(EXP1::NR == EXP2::NR || EXP1::NR == 0 || EXP2::NR == 0);
        COMPILE_TIME_ASSERT(EXP1::NC == EXP2::NC || EXP1::NR == 0 || EXP2::NC == 0);
        COMPILE_TIME_ASSERT(EXP2::NR == EXP3::NR || EXP2::NR == 0 || EXP3::NR == 0);
        COMPILE_TIME_ASSERT(EXP2::NC == EXP3::NC || EXP2::NC == 0 || EXP3::NC == 0);
        DLIB_ASSERT(a.nr() == b.nr() &&
               a.nc() == b.nc() &&
               b.nr() == c.nr() &&
               b.nc() == c.nc(),
            "\tconst matrix_exp pointwise_multiply(a,b,c)"
            << "\n\tYou can only make a do a pointwise multiply between equally sized matrices"
            << "\n\ta.nr(): " << a.nr()
            << "\n\ta.nc(): " << a.nc()
            << "\n\tb.nr(): " << b.nr()
            << "\n\tb.nc(): " << b.nc()
            << "\n\tc.nr(): " << c.nr()
            << "\n\tc.nc(): " << c.nc()
            );

        typedef op_pointwise_multiply3<EXP1,EXP2,EXP3> op;
        return matrix_op<op>(op(a.ref(),b.ref(),c.ref()));
    }

// ----------------------------------------------------------------------------------------

    template <typename M1, typename M2, typename M3, typename M4>
    struct op_pointwise_multiply4 : basic_op_mmmm<M1,M2,M3,M4>
    {
        op_pointwise_multiply4( const M1& m1_, const M2& m2_, const M3& m3_, const M4& m4_) :
            basic_op_mmmm<M1,M2,M3,M4>(m1_,m2_,m3_,m4_){}

        typedef typename M1::type type;
        typedef const typename M1::type const_ret_type;
        const static long cost = M1::cost + M2::cost + M3::cost + M4::cost + 3;

        const_ret_type apply (long r, long c) const
        { return this->m1(r,c)*this->m2(r,c)*this->m3(r,c)*this->m4(r,c); }
    };

    template <
        typename EXP1,
        typename EXP2,
        typename EXP3,
        typename EXP4
        >
    inline const matrix_op<op_pointwise_multiply4<EXP1,EXP2,EXP3,EXP4> > pointwise_multiply (
        const matrix_exp<EXP1>& a,
        const matrix_exp<EXP2>& b,
        const matrix_exp<EXP3>& c,
        const matrix_exp<EXP4>& d
    )
    {
        COMPILE_TIME_ASSERT((is_same_type<typename EXP1::type,typename EXP2::type>::value == true));
        COMPILE_TIME_ASSERT((is_same_type<typename EXP2::type,typename EXP3::type>::value == true));
        COMPILE_TIME_ASSERT((is_same_type<typename EXP3::type,typename EXP4::type>::value == true));
        COMPILE_TIME_ASSERT(EXP1::NR == EXP2::NR || EXP1::NR == 0 || EXP2::NR == 0);
        COMPILE_TIME_ASSERT(EXP1::NC == EXP2::NC || EXP1::NC == 0 || EXP2::NC == 0 );
        COMPILE_TIME_ASSERT(EXP2::NR == EXP3::NR || EXP2::NR == 0 || EXP3::NR == 0);
        COMPILE_TIME_ASSERT(EXP2::NC == EXP3::NC || EXP2::NC == 0 || EXP3::NC == 0);
        COMPILE_TIME_ASSERT(EXP3::NR == EXP4::NR || EXP3::NR == 0 || EXP4::NR == 0);
        COMPILE_TIME_ASSERT(EXP3::NC == EXP4::NC || EXP3::NC == 0 || EXP4::NC == 0);
        DLIB_ASSERT(a.nr() == b.nr() &&
               a.nc() == b.nc() &&
               b.nr() == c.nr() &&
               b.nc() == c.nc() &&
               c.nr() == d.nr() &&
               c.nc() == d.nc(),
            "\tconst matrix_exp pointwise_multiply(a,b,c,d)"
            << "\n\tYou can only make a do a pointwise multiply between equally sized matrices"
            << "\n\ta.nr(): " << a.nr()
            << "\n\ta.nc(): " << a.nc()
            << "\n\tb.nr(): " << b.nr()
            << "\n\tb.nc(): " << b.nc()
            << "\n\tc.nr(): " << c.nr()
            << "\n\tc.nc(): " << c.nc()
            << "\n\td.nr(): " << d.nr()
            << "\n\td.nc(): " << d.nc()
            );

        typedef op_pointwise_multiply4<EXP1,EXP2,EXP3,EXP4> op;
        return matrix_op<op>(op(a.ref(),b.ref(),c.ref(),d.ref()));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename P,
        int type = static_switch<
            pixel_traits<P>::grayscale,
            pixel_traits<P>::rgb,
            pixel_traits<P>::hsi,
            pixel_traits<P>::rgb_alpha
            >::value
        >
    struct pixel_to_vector_helper;

    template <typename P>
    struct pixel_to_vector_helper<P,1>
    {
        template <typename M>
        static void assign (
            M& m,
            const P& pixel
        )
        {
            m(0) = static_cast<typename M::type>(pixel);
        }
    };

    template <typename P>
    struct pixel_to_vector_helper<P,2>
    {
        template <typename M>
        static void assign (
            M& m,
            const P& pixel
        )
        {
            m(0) = static_cast<typename M::type>(pixel.red);
            m(1) = static_cast<typename M::type>(pixel.green);
            m(2) = static_cast<typename M::type>(pixel.blue);
        }
    };

    template <typename P>
    struct pixel_to_vector_helper<P,3>
    {
        template <typename M>
        static void assign (
            M& m,
            const P& pixel
        )
        {
            m(0) = static_cast<typename M::type>(pixel.h);
            m(1) = static_cast<typename M::type>(pixel.s);
            m(2) = static_cast<typename M::type>(pixel.i);
        }
    };

    template <typename P>
    struct pixel_to_vector_helper<P,4>
    {
        template <typename M>
        static void assign (
            M& m,
            const P& pixel
        )
        {
            m(0) = static_cast<typename M::type>(pixel.red);
            m(1) = static_cast<typename M::type>(pixel.green);
            m(2) = static_cast<typename M::type>(pixel.blue);
            m(3) = static_cast<typename M::type>(pixel.alpha);
        }
    };

    template <
        typename T,
        typename P
        >
    inline const matrix<T,pixel_traits<P>::num,1> pixel_to_vector (
        const P& pixel
    )
    {
        COMPILE_TIME_ASSERT(pixel_traits<P>::num > 0);
        matrix<T,pixel_traits<P>::num,1> m;
        pixel_to_vector_helper<P>::assign(m,pixel);
        return m;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename P,
        int type = static_switch<
            pixel_traits<P>::grayscale,
            pixel_traits<P>::rgb,
            pixel_traits<P>::hsi,
            pixel_traits<P>::rgb_alpha
            >::value
        >
    struct vector_to_pixel_helper;

    template <typename P>
    struct vector_to_pixel_helper<P,1>
    {
        template <typename M>
        static void assign (
            P& pixel,
            const M& m
        )
        {
            pixel = static_cast<unsigned char>(m(0));
        }
    };

    template <typename P>
    struct vector_to_pixel_helper<P,2>
    {
        template <typename M>
        static void assign (
            P& pixel,
            const M& m
        )
        {
            pixel.red = static_cast<unsigned char>(m(0));
            pixel.green = static_cast<unsigned char>(m(1));
            pixel.blue = static_cast<unsigned char>(m(2));
        }
    };

    template <typename P>
    struct vector_to_pixel_helper<P,3>
    {
        template <typename M>
        static void assign (
            P& pixel,
            const M& m
        )
        {
            pixel.h = static_cast<unsigned char>(m(0));
            pixel.s = static_cast<unsigned char>(m(1));
            pixel.i = static_cast<unsigned char>(m(2));
        }
    };

    template <typename P>
    struct vector_to_pixel_helper<P,4>
    {
        template <typename M>
        static void assign (
            P& pixel,
            const M& m
        )
        {
            pixel.red = static_cast<unsigned char>(m(0));
            pixel.green = static_cast<unsigned char>(m(1));
            pixel.blue = static_cast<unsigned char>(m(2));
            pixel.alpha = static_cast<unsigned char>(m(3));
        }
    };

    template <
        typename P,
        typename EXP
        >
    inline void vector_to_pixel (
        P& pixel,
        const matrix_exp<EXP>& vector
    )
    {
        COMPILE_TIME_ASSERT(pixel_traits<P>::num == matrix_exp<EXP>::NR);
        COMPILE_TIME_ASSERT(matrix_exp<EXP>::NC == 1);
        vector_to_pixel_helper<P>::assign(pixel,vector);
    }

// ----------------------------------------------------------------------------------------

    template <typename M, long lower, long upper>
    struct op_clamp : basic_op_m<M>
    {
        op_clamp( const M& m_) : basic_op_m<M>(m_){}

        typedef typename M::type type;
        typedef const typename M::type const_ret_type;
        const static long cost = M::cost + 2;

        const_ret_type apply ( long r, long c) const
        {
            const type temp = this->m(r,c);
            if (temp > static_cast<type>(upper))
                return static_cast<type>(upper);
            else if (temp < static_cast<type>(lower))
                return static_cast<type>(lower);
            else
                return temp;
        }
    };

    template <
        long l,
        long u,
        typename EXP
        >
    const matrix_op<op_clamp<EXP,l,u> > clamp (
        const matrix_exp<EXP>& m
    )
    {
        typedef op_clamp<EXP,l,u> op;
        return matrix_op<op>(op(m.ref()));
    }

// ----------------------------------------------------------------------------------------

    template <typename M>
    struct op_clamp2 : basic_op_m<M>
    {
        typedef typename M::type type;

        op_clamp2( const M& m_, const type& l, const type& u) :
            basic_op_m<M>(m_), lower(l), upper(u){}

        const type& lower;
        const type& upper;

        typedef const typename M::type const_ret_type;
        const static long cost = M::cost + 2;

        const_ret_type apply ( long r, long c) const
        {
            const type temp = this->m(r,c);
            if (temp > upper)
                return upper;
            else if (temp < lower)
                return lower;
            else
                return temp;
        }
    };

    template <
        typename EXP
        >
    const matrix_op<op_clamp2<EXP> > clamp (
        const matrix_exp<EXP>& m,
        const typename EXP::type& lower,
        const typename EXP::type& upper
    )
    {
        typedef op_clamp2<EXP> op;
        return matrix_op<op>(op(m.ref(),lower, upper));
    }

// ----------------------------------------------------------------------------------------

    template <typename M1, typename M2, typename M3>
    struct op_clamp_m : basic_op_mmm<M1,M2,M3>
    {
        op_clamp_m( const M1& m1_, const M2& m2_, const M3& m3_) :
            basic_op_mmm<M1,M2,M3>(m1_,m2_,m3_){}

        typedef typename M1::type type;
        typedef const typename M1::type const_ret_type;
        const static long cost = M1::cost + M2::cost + M3::cost + 2;

        const_ret_type apply (long r, long c) const
        {
            const type val = this->m1(r,c);
            const type lower = this->m2(r,c);
            const type upper = this->m3(r,c);
            if (val <= upper)
            {
                if (lower <= val)
                    return val;
                else
                    return lower;
            }
            else
            {
                return upper;
            }
        }
    };

    template <
        typename EXP1,
        typename EXP2,
        typename EXP3
        >
    const matrix_op<op_clamp_m<EXP1,EXP2,EXP3> >
    clamp (
        const matrix_exp<EXP1>& m,
        const matrix_exp<EXP2>& lower,
        const matrix_exp<EXP3>& upper
    )
    {
        COMPILE_TIME_ASSERT((is_same_type<typename EXP1::type,typename EXP2::type>::value == true));
        COMPILE_TIME_ASSERT((is_same_type<typename EXP2::type,typename EXP3::type>::value == true));
        COMPILE_TIME_ASSERT(EXP1::NR == EXP2::NR || EXP1::NR == 0 || EXP2::NR == 0);
        COMPILE_TIME_ASSERT(EXP1::NC == EXP2::NC || EXP1::NR == 0 || EXP2::NC == 0);
        COMPILE_TIME_ASSERT(EXP2::NR == EXP3::NR || EXP2::NR == 0 || EXP3::NR == 0);
        COMPILE_TIME_ASSERT(EXP2::NC == EXP3::NC || EXP2::NC == 0 || EXP3::NC == 0);
        DLIB_ASSERT(m.nr() == lower.nr() &&
                    m.nc() == lower.nc() &&
                    m.nr() == upper.nr() &&
                    m.nc() == upper.nc(),
            "\tconst matrix_exp clamp(m,lower,upper)"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t m.nr():     " << m.nr()
            << "\n\t m.nc():     " << m.nc()
            << "\n\t lower.nr(): " << lower.nr()
            << "\n\t lower.nc(): " << lower.nc()
            << "\n\t upper.nr(): " << upper.nr()
            << "\n\t upper.nc(): " << upper.nc()
            );

        typedef op_clamp_m<EXP1,EXP2,EXP3> op;
        return matrix_op<op>(op(m.ref(),lower.ref(),upper.ref()));
    }

// ----------------------------------------------------------------------------------------

    template <typename M>
    struct op_lowerbound : basic_op_m<M>
    {
        typedef typename M::type type;

        op_lowerbound( const M& m_, const type& thresh_) :
            basic_op_m<M>(m_), thresh(thresh_){}

        const type& thresh;

        typedef const typename M::type const_ret_type;
        const static long cost = M::cost + 2;

        const_ret_type apply ( long r, long c) const
        {
            const type temp = this->m(r,c);
            if (temp >= thresh)
                return temp;
            else
                return thresh;
        }
    };

    template <
        typename EXP
        >
    const matrix_op<op_lowerbound<EXP> > lowerbound (
        const matrix_exp<EXP>& m,
        const typename EXP::type& thresh
    )
    {
        typedef op_lowerbound<EXP> op;
        return matrix_op<op>(op(m.ref(), thresh));
    }

// ----------------------------------------------------------------------------------------

    template <typename M>
    struct op_upperbound : basic_op_m<M>
    {
        typedef typename M::type type;

        op_upperbound( const M& m_, const type& thresh_) :
            basic_op_m<M>(m_), thresh(thresh_){}

        const type& thresh;

        typedef const typename M::type const_ret_type;
        const static long cost = M::cost + 2;

        const_ret_type apply ( long r, long c) const
        {
            const type temp = this->m(r,c);
            if (temp <= thresh)
                return temp;
            else
                return thresh;
        }
    };

    template <
        typename EXP
        >
    const matrix_op<op_upperbound<EXP> > upperbound (
        const matrix_exp<EXP>& m,
        const typename EXP::type& thresh
    )
    {
        typedef op_upperbound<EXP> op;
        return matrix_op<op>(op(m.ref(), thresh));
    }

// ----------------------------------------------------------------------------------------

    template <typename M>
    struct op_reshape
    {
        op_reshape(const M& m_, const long& rows_, const long& cols_) : m(m_),rows(rows_),cols(cols_) {}
        const M& m;
        const long rows;
        const long cols;

        const static long cost = M::cost+2;
        const static long NR = 0;
        const static long NC = 0;
        typedef typename M::type type;
        typedef typename M::const_ret_type const_ret_type;
        typedef typename M::mem_manager_type mem_manager_type;
        typedef typename M::layout_type layout_type;

        const_ret_type apply ( long r, long c) const
        {
            const long idx = r*cols + c;
            return m(idx/m.nc(), idx%m.nc());
        }

        long nr () const { return rows; }
        long nc () const { return cols; }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }
    };

    template <
        typename EXP
        >
    const matrix_op<op_reshape<EXP> > reshape (
        const matrix_exp<EXP>& m,
        const long& rows,
        const long& cols
    )
    {
        DLIB_ASSERT(m.size() == rows*cols && rows > 0 && cols > 0,
            "\tconst matrix_exp reshape(m, rows, cols)"
            << "\n\t The size of m must match the dimensions you want to reshape it into."
            << "\n\t m.size():  " << m.size()
            << "\n\t rows*cols: " << rows*cols
            << "\n\t rows:      " << rows
            << "\n\t cols:      " << cols
            );

        typedef op_reshape<EXP> op;
        return matrix_op<op>(op(m.ref(), rows, cols));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP1,
        typename EXP2
        >
    typename disable_if<is_complex<typename EXP1::type>,bool>::type equal (
        const matrix_exp<EXP1>& a,
        const matrix_exp<EXP2>& b,
        const typename EXP1::type eps = 100*std::numeric_limits<typename EXP1::type>::epsilon()
    )
    {
        // check if the dimensions don't match
        if (a.nr() != b.nr() || a.nc() != b.nc())
            return false;

        for (long r = 0; r < a.nr(); ++r)
        {
            for (long c = 0; c < a.nc(); ++c)
            {
                if (std::abs(a(r,c)-b(r,c)) > eps)
                    return false;
            }
        }

        // no non-equal points found so we return true
        return true;
    }

    template <
        typename EXP1,
        typename EXP2
        >
    typename enable_if<is_complex<typename EXP1::type>,bool>::type equal (
        const matrix_exp<EXP1>& a,
        const matrix_exp<EXP2>& b,
        const typename EXP1::type::value_type eps = 100*std::numeric_limits<typename EXP1::type::value_type>::epsilon()
    )
    {
        // check if the dimensions don't match
        if (a.nr() != b.nr() || a.nc() != b.nc())
            return false;

        for (long r = 0; r < a.nr(); ++r)
        {
            for (long c = 0; c < a.nc(); ++c)
            {
                if (std::abs(real(a(r,c)-b(r,c))) > eps ||
                    std::abs(imag(a(r,c)-b(r,c))) > eps)
                    return false;
            }
        }

        // no non-equal points found so we return true
        return true;
    }

// ----------------------------------------------------------------------------------------

    template <typename M1, typename M2>
    struct op_scale_columns
    {
        op_scale_columns(const M1& m1_, const M2& m2_) : m1(m1_), m2(m2_) {}
        const M1& m1;
        const M2& m2;

        const static long cost = M1::cost + M2::cost + 1;
        typedef typename M1::type type;
        typedef const typename M1::type const_ret_type;
        typedef typename M1::mem_manager_type mem_manager_type;
        typedef typename M1::layout_type layout_type;
        const static long NR = M1::NR;
        const static long NC = M1::NC;

        const_ret_type apply ( long r, long c) const { return m1(r,c)*m2(c); }

        long nr () const { return m1.nr(); }
        long nc () const { return m1.nc(); }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const
        { return m1.aliases(item) || m2.aliases(item) ; }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const
        { return m1.destructively_aliases(item) || m2.aliases(item); }
    };

    template <
        typename EXP1,
        typename EXP2
        >
    const matrix_op<op_scale_columns<EXP1,EXP2> > scale_columns (
        const matrix_exp<EXP1>& m,
        const matrix_exp<EXP2>& v
    )
    {
        // Both arguments to this function must contain the same type of element
        COMPILE_TIME_ASSERT((is_same_type<typename EXP1::type,typename EXP2::type>::value == true));
        // The v argument must be a row or column vector.
        COMPILE_TIME_ASSERT((EXP2::NC == 1 || EXP2::NC == 0) || (EXP2::NR == 1 || EXP2::NR == 0));

        // figure out the compile time known length of v
        const long v_len = ((EXP2::NR)*(EXP2::NC) == 0)? 0 : (tmax<EXP2::NR,EXP2::NC>::value);

        // the length of v must match the number of columns in m
        COMPILE_TIME_ASSERT(EXP1::NC == v_len || EXP1::NC == 0 || v_len == 0);

        DLIB_ASSERT(is_vector(v) == true && v.size() == m.nc(),
            "\tconst matrix_exp scale_columns(m, v)"
            << "\n\tv must be a row or column vector and its length must match the number of columns in m"
            << "\n\tm.nr(): " << m.nr()
            << "\n\tm.nc(): " << m.nc()
            << "\n\tv.nr(): " << v.nr()
            << "\n\tv.nc(): " << v.nc()
            );
        typedef op_scale_columns<EXP1,EXP2> op;
        return matrix_op<op>(op(m.ref(),v.ref()));
    }

// ----------------------------------------------------------------------------------------

    template <typename M1, typename M2>
    struct op_scale_columns_diag
    {
        op_scale_columns_diag(const M1& m1_, const M2& m2_) : m1(m1_), m2(m2_) {}
        const M1& m1;
        const M2& m2;

        const static long cost = M1::cost + M2::cost + 1;
        typedef typename M1::type type;
        typedef const typename M1::type const_ret_type;
        typedef typename M1::mem_manager_type mem_manager_type;
        typedef typename M1::layout_type layout_type;
        const static long NR = M1::NR;
        const static long NC = M1::NC;

        const_ret_type apply ( long r, long c) const { return m1(r,c)*m2(c,c); }

        long nr () const { return m1.nr(); }
        long nc () const { return m1.nc(); }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const
        { return m1.aliases(item) || m2.aliases(item) ; }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const
        { return m1.destructively_aliases(item) || m2.aliases(item); }
    };

// turn expressions of the form mat*diagonal_matrix into scale_columns(mat, d)
    template <
        typename EXP1,
        typename EXP2
        >
    const matrix_op<op_scale_columns_diag<EXP1,EXP2> > operator* (
        const matrix_exp<EXP1>& m,
        const matrix_diag_exp<EXP2>& d
    )
    {
        // Both arguments to this function must contain the same type of element
        COMPILE_TIME_ASSERT((is_same_type<typename EXP1::type,typename EXP2::type>::value == true));

        // figure out the compile time known length of d
        const long v_len = ((EXP2::NR)*(EXP2::NC) == 0)? 0 : (tmax<EXP2::NR,EXP2::NC>::value);

        // the length of d must match the number of columns in m
        COMPILE_TIME_ASSERT(EXP1::NC == v_len || EXP1::NC == 0 || v_len == 0);

        DLIB_ASSERT(m.nc() == d.nr(),
            "\tconst matrix_exp operator*(m, d)"
            << "\n\tmatrix dimensions don't match"
            << "\n\tm.nr(): " << m.nr()
            << "\n\tm.nc(): " << m.nc()
            << "\n\td.nr(): " << d.nr()
            << "\n\td.nc(): " << d.nc()
            );
        typedef op_scale_columns_diag<EXP1,EXP2> op;
        return matrix_op<op>(op(m.ref(),d.ref()));
    }

// ----------------------------------------------------------------------------------------

    template <typename M1, typename M2>
    struct op_scale_rows
    {
        op_scale_rows(const M1& m1_, const M2& m2_) : m1(m1_), m2(m2_) {}
        const M1& m1;
        const M2& m2;

        const static long cost = M1::cost + M2::cost + 1;
        typedef typename M1::type type;
        typedef const typename M1::type const_ret_type;
        typedef typename M1::mem_manager_type mem_manager_type;
        typedef typename M1::layout_type layout_type;
        const static long NR = M1::NR;
        const static long NC = M1::NC;

        const_ret_type apply ( long r, long c) const { return m1(r,c)*m2(r); }

        long nr () const { return m1.nr(); }
        long nc () const { return m1.nc(); }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const
        { return m1.aliases(item) || m2.aliases(item) ; }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const
        { return m1.destructively_aliases(item) || m2.aliases(item); }
    };

    template <
        typename EXP1,
        typename EXP2
        >
    const matrix_op<op_scale_rows<EXP1,EXP2> > scale_rows (
        const matrix_exp<EXP1>& m,
        const matrix_exp<EXP2>& v
    )
    {
        // Both arguments to this function must contain the same type of element
        COMPILE_TIME_ASSERT((is_same_type<typename EXP1::type,typename EXP2::type>::value == true));
        // The v argument must be a row or column vector.
        COMPILE_TIME_ASSERT((EXP2::NC == 1 || EXP2::NC == 0) || (EXP2::NR == 1 || EXP2::NR == 0));

        // figure out the compile time known length of v
        const long v_len = ((EXP2::NR)*(EXP2::NC) == 0)? 0 : (tmax<EXP2::NR,EXP2::NC>::value);

        // the length of v must match the number of rows in m
        COMPILE_TIME_ASSERT(EXP1::NR == v_len || EXP1::NR == 0 || v_len == 0);

        DLIB_ASSERT(is_vector(v) == true && v.size() == m.nr(),
            "\tconst matrix_exp scale_rows(m, v)"
            << "\n\tv must be a row or column vector and its length must match the number of rows in m"
            << "\n\tm.nr(): " << m.nr()
            << "\n\tm.nc(): " << m.nc()
            << "\n\tv.nr(): " << v.nr()
            << "\n\tv.nc(): " << v.nc()
            );
        typedef op_scale_rows<EXP1,EXP2> op;
        return matrix_op<op>(op(m.ref(),v.ref()));
    }

// ----------------------------------------------------------------------------------------

    template <typename M1, typename M2>
    struct op_scale_rows_diag
    {
        op_scale_rows_diag(const M1& m1_, const M2& m2_) : m1(m1_), m2(m2_) {}
        const M1& m1;
        const M2& m2;

        const static long cost = M1::cost + M2::cost + 1;
        typedef typename M1::type type;
        typedef const typename M1::type const_ret_type;
        typedef typename M1::mem_manager_type mem_manager_type;
        typedef typename M1::layout_type layout_type;
        const static long NR = M1::NR;
        const static long NC = M1::NC;

        const_ret_type apply ( long r, long c) const { return m1(r,c)*m2(r,r); }

        long nr () const { return m1.nr(); }
        long nc () const { return m1.nc(); }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const
        { return m1.aliases(item) || m2.aliases(item) ; }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const
        { return m1.destructively_aliases(item) || m2.aliases(item); }
    };

// turn expressions of the form diagonal_matrix*mat into scale_rows(mat, d)
    template <
        typename EXP1,
        typename EXP2
        >
    const matrix_op<op_scale_rows_diag<EXP1,EXP2> > operator* (
        const matrix_diag_exp<EXP2>& d,
        const matrix_exp<EXP1>& m
    )
    {
        // Both arguments to this function must contain the same type of element
        COMPILE_TIME_ASSERT((is_same_type<typename EXP1::type,typename EXP2::type>::value == true));

        // figure out the compile time known length of d
        const long v_len = ((EXP2::NR)*(EXP2::NC) == 0)? 0 : (tmax<EXP2::NR,EXP2::NC>::value);

        // the length of d must match the number of rows in m
        COMPILE_TIME_ASSERT(EXP1::NR == v_len || EXP1::NR == 0 || v_len == 0);

        DLIB_ASSERT(d.nc() == m.nr(),
            "\tconst matrix_exp operator*(d, m)"
            << "\n\tThe dimensions of the d and m matrices don't match."
            << "\n\tm.nr(): " << m.nr()
            << "\n\tm.nc(): " << m.nc()
            << "\n\td.nr(): " << d.nr()
            << "\n\td.nc(): " << d.nc()
            );
        typedef op_scale_rows_diag<EXP1,EXP2> op;
        return matrix_op<op>(op(m.ref(),d.ref()));
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    /*
        The idea here is to catch expressions of the form d*M*d where d is diagonal and M
        is some square matrix and turn them into something equivalent to
        pointwise_multiply(diag(d)*trans(diag(d)), M).

        The reason for this is that doing it this way is more numerically stable.  In particular,
        doing 2 matrix multiplies as suggested by d*M*d could result in an asymmetric matrix even
        if M is symmetric to begin with.
    */

    template <typename M1, typename M2, typename M3>
    struct op_diag_m_diag
    {
        // This operator represents M1*M2*M3 where M1 and M3 are diagonal

        op_diag_m_diag(const M1& m1_, const M2& m2_, const M3& m3_) : m1(m1_), m2(m2_), m3(m3_) {}
        const M1& m1;
        const M2& m2;
        const M3& m3;

        const static long cost = M1::cost + M2::cost + M3::cost + 1;
        typedef typename M2::type type;
        typedef const typename M2::type const_ret_type;
        typedef typename M2::mem_manager_type mem_manager_type;
        typedef typename M2::layout_type layout_type;
        const static long NR = M2::NR;
        const static long NC = M2::NC;

        const_ret_type apply ( long r, long c) const { return (m1(r,r)*m3(c,c))*m2(r,c); }

        long nr () const { return m2.nr(); }
        long nc () const { return m2.nc(); }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const
        { return m1.aliases(item) || m2.aliases(item) || m3.aliases(item) ; }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const
        { return m2.destructively_aliases(item) || m1.aliases(item) || m3.aliases(item) ; }
    };

    // catch d*(M*d) = EXP1*EXP2*EXP3
    template <
        typename EXP1,
        typename EXP2,
        typename EXP3
        >
    const matrix_op<op_diag_m_diag<EXP1,EXP2,EXP3> > operator* (
        const matrix_diag_exp<EXP1>& d,
        const matrix_exp<matrix_op<op_scale_columns_diag<EXP2,EXP3> > >& m
    )
    {
        // Both arguments to this function must contain the same type of element
        COMPILE_TIME_ASSERT((is_same_type<typename EXP1::type,typename EXP2::type>::value == true));

        // figure out the compile time known length of d
        const long v_len = ((EXP1::NR)*(EXP1::NC) == 0)? 0 : (tmax<EXP1::NR,EXP1::NC>::value);

        // the length of d must match the number of rows in m
        COMPILE_TIME_ASSERT(EXP2::NR == v_len || EXP2::NR == 0 || v_len == 0);

        DLIB_ASSERT(d.nc() == m.nr(),
            "\tconst matrix_exp operator*(d, m)"
            << "\n\tmatrix dimensions don't match"
            << "\n\td.nr(): " << d.nr()
            << "\n\td.nc(): " << d.nc()
            << "\n\tm.nr(): " << m.nr()
            << "\n\tm.nc(): " << m.nc()
            );
        typedef op_diag_m_diag<EXP1,EXP2,EXP3> op;
        return matrix_op<op>(op(d.ref(), m.ref().op.m1, m.ref().op.m2));
    }

    // catch (d*M)*d = EXP1*EXP2*EXP3
    template <
        typename EXP1,
        typename EXP2,
        typename EXP3
        >
    const matrix_op<op_diag_m_diag<EXP1,EXP2,EXP3> > operator* (
        const matrix_exp<matrix_op<op_scale_rows_diag<EXP2,EXP1> > >& m,
        const matrix_diag_exp<EXP3>& d
    )
    {
        // Both arguments to this function must contain the same type of element
        COMPILE_TIME_ASSERT((is_same_type<typename EXP3::type,typename EXP2::type>::value == true));

        // figure out the compile time known length of d
        const long v_len = ((EXP3::NR)*(EXP3::NC) == 0)? 0 : (tmax<EXP3::NR,EXP3::NC>::value);

        // the length of d must match the number of columns in m
        COMPILE_TIME_ASSERT(EXP2::NC == v_len || EXP2::NC == 0 || v_len == 0);

        DLIB_ASSERT(m.nc() == d.nr(),
            "\tconst matrix_exp operator*(m, d)"
            << "\n\tmatrix dimensions don't match"
            << "\n\tm.nr(): " << m.nr()
            << "\n\tm.nc(): " << m.nc()
            << "\n\td.nr(): " << d.nr()
            << "\n\td.nc(): " << d.nc()
            );
        typedef op_diag_m_diag<EXP1,EXP2,EXP3> op;
        return matrix_op<op>(op(m.ref().op.m2, m.ref().op.m1, d.ref()));
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    struct sort_columns_sort_helper
    {
        template <typename T>
        bool operator() (
            const T& item1,
            const T& item2
        ) const
        {
            return item1.first < item2.first;
        }
    };

    template <
        typename T, long NR, long NC, typename mm, typename l1,
        long NR2, long NC2, typename mm2, typename l2
        >
    void sort_columns (
        matrix<T,NR,NC,mm,l1>& m,
        matrix<T,NR2,NC2,mm2,l2>& v
    )
    {
        COMPILE_TIME_ASSERT(NC2 == 1 || NC2 == 0);
        COMPILE_TIME_ASSERT(NC == NR2 || NC == 0 || NR2 == 0);

        DLIB_ASSERT(is_col_vector(v) == true && v.size() == m.nc(),
            "\tconst matrix_exp sort_columns(m, v)"
            << "\n\tv must be a column vector and its length must match the number of columns in m"
            << "\n\tm.nr(): " << m.nr()
            << "\n\tm.nc(): " << m.nc()
            << "\n\tv.nr(): " << v.nr()
            << "\n\tv.nc(): " << v.nc()
            );

        // Now we have to sort the given vectors in the m matrix according
        // to how big their corresponding v(column index) values are.
        typedef std::pair<T, matrix<T,0,1,mm> > col_pair;
        typedef std_allocator<col_pair, mm> alloc;
        std::vector<col_pair,alloc> colvalues;
        col_pair p;
        for (long r = 0; r < v.nr(); ++r)
        {
            p.first = v(r);
            p.second = colm(m,r);
            colvalues.push_back(p);
        }
        std::sort(colvalues.begin(), colvalues.end(), sort_columns_sort_helper());

        for (long i = 0; i < v.nr(); ++i)
        {
            v(i) = colvalues[i].first;
            set_colm(m,i) = colvalues[i].second;
        }

    }

// ----------------------------------------------------------------------------------------

    template <
        typename T, long NR, long NC, typename mm, typename l1,
        long NR2, long NC2, typename mm2, typename l2
        >
    void rsort_columns (
        matrix<T,NR,NC,mm,l1>& m,
        matrix<T,NR2,NC2,mm2,l2>& v
    )
    {
        COMPILE_TIME_ASSERT(NC2 == 1 || NC2 == 0);
        COMPILE_TIME_ASSERT(NC == NR2 || NC == 0 || NR2 == 0);

        DLIB_ASSERT(is_col_vector(v) == true && v.size() == m.nc(),
            "\tconst matrix_exp rsort_columns(m, v)"
            << "\n\tv must be a column vector and its length must match the number of columns in m"
            << "\n\tm.nr(): " << m.nr()
            << "\n\tm.nc(): " << m.nc()
            << "\n\tv.nr(): " << v.nr()
            << "\n\tv.nc(): " << v.nc()
            );

        // Now we have to sort the given vectors in the m matrix according
        // to how big their corresponding v(column index) values are.
        typedef std::pair<T, matrix<T,0,1,mm> > col_pair;
        typedef std_allocator<col_pair, mm> alloc;
        std::vector<col_pair,alloc> colvalues;
        col_pair p;
        for (long r = 0; r < v.nr(); ++r)
        {
            p.first = v(r);
            p.second = colm(m,r);
            colvalues.push_back(p);
        }
        std::sort(colvalues.rbegin(), colvalues.rend(), sort_columns_sort_helper());

        for (long i = 0; i < v.nr(); ++i)
        {
            v(i) = colvalues[i].first;
            set_colm(m,i) = colvalues[i].second;
        }

    }

// ----------------------------------------------------------------------------------------

    template <typename M1, typename M2>
    struct op_tensor_product
    {
        op_tensor_product(const M1& m1_, const M2& m2_) : m1(m1_),m2(m2_) {}
        const M1& m1;
        const M2& m2;

        const static long cost = M1::cost + M2::cost + 1;
        const static long NR = M1::NR*M2::NR;
        const static long NC = M1::NC*M2::NC;
        typedef typename M1::type type;
        typedef const typename M1::type const_ret_type;
        typedef typename M1::mem_manager_type mem_manager_type;
        typedef typename M1::layout_type layout_type;

        const_ret_type apply ( long r, long c) const
        {
            return m1(r/m2.nr(),c/m2.nc())*m2(r%m2.nr(),c%m2.nc());
        }

        long nr () const { return m1.nr()*m2.nr(); }
        long nc () const { return m1.nc()*m2.nc(); }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const
        { return m1.aliases(item) || m2.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const
        { return m1.aliases(item) || m2.aliases(item); }
    };

    template <
        typename EXP1,
        typename EXP2
        >
    inline const matrix_op<op_tensor_product<EXP1,EXP2> > tensor_product (
        const matrix_exp<EXP1>& a,
        const matrix_exp<EXP2>& b
    )
    {
        COMPILE_TIME_ASSERT((is_same_type<typename EXP1::type,typename EXP2::type>::value == true));
        typedef op_tensor_product<EXP1,EXP2> op;
        return matrix_op<op>(op(a.ref(),b.ref()));
    }

// ----------------------------------------------------------------------------------------

    template <typename M>
    struct op_make_symmetric : basic_op_m<M>
    {
        op_make_symmetric ( const M& m_) : basic_op_m<M>(m_){}

        const static long cost = M::cost+1;
        typedef typename M::type type;
        typedef typename M::const_ret_type const_ret_type;
        const_ret_type apply ( long r, long c) const
        {
            if (r >= c)
                return this->m(r,c);
            else
                return this->m(c,r);
        }
    };

    template <
        typename EXP
        >
    const matrix_op<op_make_symmetric<EXP> > make_symmetric (
        const matrix_exp<EXP>& m
    )
    {
        DLIB_ASSERT(m.nr() == m.nc(),
            "\tconst matrix make_symmetric(m)"
            << "\n\t m must be a square matrix"
            << "\n\t m.nr(): " << m.nr()
            << "\n\t m.nc(): " << m.nc()
            );

        typedef op_make_symmetric<EXP> op;
        return matrix_op<op>(op(m.ref()));
    }

// ----------------------------------------------------------------------------------------

    template <typename M>
    struct op_lowerm : basic_op_m<M>
    {
        op_lowerm( const M& m_) : basic_op_m<M>(m_){}

        const static long cost = M::cost+2;
        typedef typename M::type type;
        typedef const typename M::type const_ret_type;
        const_ret_type apply ( long r, long c) const
        {
            if (r >= c)
                return this->m(r,c);
            else
                return 0;
        }
    };

    template <typename M>
    struct op_lowerm_s : basic_op_m<M>
    {
        typedef typename M::type type;
        op_lowerm_s( const M& m_, const type& s_) : basic_op_m<M>(m_), s(s_){}

        const type s;

        const static long cost = M::cost+2;
        typedef const typename M::type const_ret_type;
        const_ret_type apply ( long r, long c) const
        {
            if (r > c)
                return this->m(r,c);
            else if (r==c)
                return s;
            else
                return 0;
        }
    };

    template <
        typename EXP
        >
    const matrix_op<op_lowerm<EXP> > lowerm (
        const matrix_exp<EXP>& m
    )
    {
        typedef op_lowerm<EXP> op;
        return matrix_op<op>(op(m.ref()));
    }

    template <
        typename EXP
        >
    const matrix_op<op_lowerm_s<EXP> > lowerm (
        const matrix_exp<EXP>& m,
        typename EXP::type s
        )
    {
        typedef op_lowerm_s<EXP> op;
        return matrix_op<op>(op(m.ref(),s));
    }

// ----------------------------------------------------------------------------------------

    template <typename M>
    struct op_upperm : basic_op_m<M>
    {
        op_upperm( const M& m_) : basic_op_m<M>(m_){}

        const static long cost = M::cost+2;
        typedef typename M::type type;
        typedef const typename M::type const_ret_type;
        const_ret_type apply ( long r, long c) const
        {
            if (r <= c)
                return this->m(r,c);
            else
                return 0;
        }
    };

    template <typename M>
    struct op_upperm_s : basic_op_m<M>
    {
        typedef typename M::type type;
        op_upperm_s( const M& m_, const type& s_) : basic_op_m<M>(m_), s(s_){}

        const type s;

        const static long cost = M::cost+2;
        typedef const typename M::type const_ret_type;
        const_ret_type apply ( long r, long c) const
        {
            if (r < c)
                return this->m(r,c);
            else if (r==c)
                return s;
            else
                return 0;
        }
    };

    template <
        typename EXP
        >
    const matrix_op<op_upperm<EXP> > upperm (
        const matrix_exp<EXP>& m
    )
    {
        typedef op_upperm<EXP> op;
        return matrix_op<op>(op(m.ref()));
    }

    template <
        typename EXP
        >
    const matrix_op<op_upperm_s<EXP> > upperm (
        const matrix_exp<EXP>& m,
        typename EXP::type s
        )
    {
        typedef op_upperm_s<EXP> op;
        return matrix_op<op>(op(m.ref(),s));
    }

// ----------------------------------------------------------------------------------------

    template <typename rand_gen>
    inline const matrix<double> randm(
        long nr,
        long nc,
        rand_gen& rnd
    )
    {
        DLIB_ASSERT(nr >= 0 && nc >= 0,
            "\tconst matrix randm(nr, nc, rnd)"
            << "\n\tInvalid inputs to this function"
            << "\n\tnr: " << nr
            << "\n\tnc: " << nc
            );

        matrix<double> m(nr,nc);
        for (long r = 0; r < m.nr(); ++r)
        {
            for (long c = 0; c < m.nc(); ++c)
            {
                m(r,c) = rnd.get_random_double();
            }
        }

        return m;
    }

// ----------------------------------------------------------------------------------------

    inline const matrix<double> randm(
        long nr,
        long nc
    )
    {
        DLIB_ASSERT(nr >= 0 && nc >= 0,
            "\tconst matrix randm(nr, nc)"
            << "\n\tInvalid inputs to this function"
            << "\n\tnr: " << nr
            << "\n\tnc: " << nc
            );

        matrix<double> m(nr,nc);
        // make a double that contains RAND_MAX + the smallest number that still
        // makes the resulting double slightly bigger than static_cast<double>(RAND_MAX)
        double max_val = RAND_MAX;
        max_val += std::numeric_limits<double>::epsilon()*RAND_MAX;

        for (long r = 0; r < m.nr(); ++r)
        {
            for (long c = 0; c < m.nc(); ++c)
            {
                m(r,c) = std::rand()/max_val;
            }
        }

        return m;
    }

// ----------------------------------------------------------------------------------------

    inline const matrix_range_exp<double> linspace (
        double start,
        double end,
        long num
    )
    {
        DLIB_ASSERT(num >= 0,
            "\tconst matrix_exp linspace(start, end, num)"
            << "\n\tInvalid inputs to this function"
            << "\n\tstart: " << start
            << "\n\tend:   " << end
            << "\n\tnum:   " << num
            );

        return matrix_range_exp<double>(start,end,num,false);
    }

// ----------------------------------------------------------------------------------------

    template <typename M>
    struct op_linpiece
    {
        op_linpiece(const double val_, const M& joints_) : joints(joints_), val(val_){}

        const M& joints;
        const double val;

        const static long cost = 10;

        const static long NR = (M::NR*M::NC==0) ? (0) : (M::NR*M::NC-1);
        const static long NC = 1;
        typedef typename M::type type;
        typedef default_memory_manager mem_manager_type;
        typedef row_major_layout layout_type;

        typedef type const_ret_type;
        const_ret_type apply (long i, long ) const
        {
            if (joints(i) < val)
                return std::min<type>(val,joints(i+1)) - joints(i);
            else
                return 0;
        }

        long nr () const { return joints.size()-1; }
        long nc () const { return 1; }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return joints.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return joints.aliases(item); }
    };

    template < typename EXP >
    const matrix_op<op_linpiece<EXP> > linpiece (
        const double val,
        const matrix_exp<EXP>& joints
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(is_vector(joints) && joints.size() >= 2,
            "\t matrix_exp linpiece()"
            << "\n\t Invalid inputs were given to this function "
            << "\n\t is_vector(joints): " << is_vector(joints)
            << "\n\t joints.size():     " << joints.size()
            );
#ifdef ENABLE_ASSERTS
        for (long i = 1; i < joints.size(); ++i)
        {
            DLIB_ASSERT(joints(i-1) < joints(i),
                "\t matrix_exp linpiece()"
                << "\n\t Invalid inputs were given to this function "
                << "\n\t joints("<<i-1<<"): " << joints(i-1)
                << "\n\t joints("<<i<<"): " << joints(i)
            );
        }
#endif

        typedef op_linpiece<EXP> op;
        return matrix_op<op>(op(val,joints.ref()));
    }

// ----------------------------------------------------------------------------------------

    inline const matrix_log_range_exp<double> logspace (
        double start,
        double end,
        long num
    )
    {
        DLIB_ASSERT(num >= 0,
            "\tconst matrix_exp logspace(start, end, num)"
            << "\n\tInvalid inputs to this function"
            << "\n\tstart: " << start
            << "\n\tend:   " << end
            << "\n\tnum:   " << num
            );

        return matrix_log_range_exp<double>(start,end,num);
    }

// ----------------------------------------------------------------------------------------

    template <typename M1, typename M2>
    struct op_cart_prod
    {
        op_cart_prod(const M1& m1_, const M2& m2_) : m1(m1_),m2(m2_) {}
        const M1& m1;
        const M2& m2;

        const static long cost = M1::cost+M2::cost+1;
        typedef typename M1::type type;
        typedef const typename M1::const_ret_type const_ret_type;

        typedef typename M1::mem_manager_type mem_manager_type;
        typedef typename M1::layout_type layout_type;
        const static long NR = M1::NR+M2::NR;
        const static long NC = M1::NC*M2::NC;

        const_ret_type apply ( long r, long c) const
        {
            if (r < m1.nr())
                return m1(r, c/m2.nc());
            else
                return m2(r-m1.nr(), c%m2.nc());
        }

        long nr () const { return m1.nr() + m2.nr(); }
        long nc () const { return m1.nc() * m2.nc(); }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const
        { return m1.aliases(item) || m2.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const
        { return m1.aliases(item) || m2.aliases(item); }
    };

    template <
        typename EXP1,
        typename EXP2
        >
    const matrix_op<op_cart_prod<EXP1,EXP2> > cartesian_product (
        const matrix_exp<EXP1>& a,
        const matrix_exp<EXP2>& b
    )
    {
        COMPILE_TIME_ASSERT((is_same_type<typename EXP1::type,typename EXP2::type>::value == true));

        typedef op_cart_prod<EXP1,EXP2> op;
        return matrix_op<op>(op(a.ref(),b.ref()));
    }

// ----------------------------------------------------------------------------------------

    template <typename M>
    struct op_mat_to_vect
    {
        op_mat_to_vect(const M& m_) : m(m_) {}
        const M& m;

        const static long cost = M::cost+2;
        const static long NR = M::NC*M::NR;
        const static long NC = 1;
        typedef typename M::type type;
        typedef typename M::const_ret_type const_ret_type;
        typedef typename M::mem_manager_type mem_manager_type;
        typedef typename M::layout_type layout_type;

        const_ret_type apply ( long r, long ) const { return m(r/m.nc(), r%m.nc()); }

        long nr () const { return m.size(); }
        long nc () const { return 1; }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }
    };

    template <
        typename EXP
        >
    const matrix_op<op_mat_to_vect<EXP> > reshape_to_column_vector (
        const matrix_exp<EXP>& m
    )
    {
        typedef op_mat_to_vect<EXP> op;
        return matrix_op<op>(op(m.ref()));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        long NR_,
        long NC_,
        typename MM
        >
    struct op_mat_to_vect2
    {
        typedef matrix<T,NR_,NC_,MM,row_major_layout> M;
        op_mat_to_vect2(const M& m_) : m(m_) {}
        const M& m;

        const static long cost = M::cost+2;
        const static long NR = M::NC*M::NR;
        const static long NC = 1;
        typedef typename M::type type;
        typedef typename M::const_ret_type const_ret_type;
        typedef typename M::mem_manager_type mem_manager_type;
        typedef typename M::layout_type layout_type;

        const_ret_type apply ( long r, long ) const { return (&m(0,0))[r]; }

        long nr () const { return m.size(); }
        long nc () const { return 1; }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }
    };

    template <
        typename T,
        long NR,
        long NC,
        typename MM
        >
    const matrix_op<op_mat_to_vect2<T,NR,NC,MM> > reshape_to_column_vector (
        const matrix<T,NR,NC,MM,row_major_layout>& m
    )
    {
        typedef op_mat_to_vect2<T,NR,NC,MM> op;
        return matrix_op<op>(op(m.ref()));
    }

// ----------------------------------------------------------------------------------------

    template <typename M1, typename M2>
    struct op_join_rows
    {
        op_join_rows(const M1& m1_, const M2& m2_) : m1(m1_),m2(m2_) {}
        const M1& m1;
        const M2& m2;

        template <typename T, typename U, bool selection>
        struct type_selector;
        template <typename T, typename U>
        struct type_selector<T,U,true> { typedef T type; };
        template <typename T, typename U>
        struct type_selector<T,U,false> { typedef U type; };

        // If both const_ret_types are references then we should use them as the const_ret_type type
        // but otherwise we should use the normal type.
        typedef typename M1::const_ret_type T1;
        typedef typename M1::type T2;
        typedef typename M2::const_ret_type T3;
        typedef typename type_selector<T1, T2, is_reference_type<T1>::value && is_reference_type<T3>::value>::type const_ret_type;

        const static long cost = M1::cost + M2::cost + 1;
        const static long NR = tmax<M1::NR, M2::NR>::value;
        const static long NC = (M1::NC*M2::NC != 0)? (M1::NC+M2::NC) : (0);
        typedef typename M1::type type;
        typedef typename M1::mem_manager_type mem_manager_type;
        typedef typename M1::layout_type layout_type;

        const_ret_type apply (long r, long c) const
        {
            if (c < m1.nc())
                return m1(r,c);
            else
                return m2(r,c-m1.nc());
        }

        long nr () const { return m1.nr(); }
        long nc () const { return m1.nc()+m2.nc(); }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const
        { return m1.aliases(item) || m2.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const
        { return m1.aliases(item) || m2.aliases(item); }
    };

    template <
        typename EXP1,
        typename EXP2
        >
    inline const matrix_op<op_join_rows<EXP1,EXP2> > join_rows (
        const matrix_exp<EXP1>& a,
        const matrix_exp<EXP2>& b
    )
    {
        COMPILE_TIME_ASSERT((is_same_type<typename EXP1::type,typename EXP2::type>::value == true));
        // You are getting an error on this line because you are trying to join two matrices that
        // don't have the same number of rows
        COMPILE_TIME_ASSERT(EXP1::NR == EXP2::NR || (EXP1::NR*EXP2::NR == 0));

        DLIB_ASSERT(a.nr() == b.nr() || a.size() == 0 || b.size() == 0,
            "\tconst matrix_exp join_rows(const matrix_exp& a, const matrix_exp& b)"
            << "\n\tYou can only use join_rows() if both matrices have the same number of rows"
            << "\n\ta.nr(): " << a.nr()
            << "\n\tb.nr(): " << b.nr()
            << "\n\ta.nc(): " << a.nc()
            << "\n\tb.nc(): " << b.nc()
            );

        typedef op_join_rows<EXP1,EXP2> op;
        return matrix_op<op>(op(a.ref(),b.ref()));
    }

// ----------------------------------------------------------------------------------------

    template <typename M1, typename M2>
    struct op_join_cols
    {
        op_join_cols(const M1& m1_, const M2& m2_) : m1(m1_),m2(m2_) {}
        const M1& m1;
        const M2& m2;

        template <typename T, typename U, bool selection>
        struct type_selector;
        template <typename T, typename U>
        struct type_selector<T,U,true> { typedef T type; };
        template <typename T, typename U>
        struct type_selector<T,U,false> { typedef U type; };

        // If both const_ret_types are references then we should use them as the const_ret_type type
        // but otherwise we should use the normal type.
        typedef typename M1::const_ret_type T1;
        typedef typename M1::type T2;
        typedef typename M2::const_ret_type T3;
        typedef typename type_selector<T1, T2, is_reference_type<T1>::value && is_reference_type<T3>::value>::type const_ret_type;

        const static long cost = M1::cost + M2::cost + 1;
        const static long NC = tmax<M1::NC, M2::NC>::value;
        const static long NR = (M1::NR*M2::NR != 0)? (M1::NR+M2::NR) : (0);
        typedef typename M1::type type;
        typedef typename M1::mem_manager_type mem_manager_type;
        typedef typename M1::layout_type layout_type;

        const_ret_type apply ( long r, long c) const
        {
            if (r < m1.nr())
                return m1(r,c);
            else
                return m2(r-m1.nr(),c);
        }

        long nr () const { return m1.nr()+m2.nr(); }
        long nc () const { return m1.nc(); }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const
        { return m1.aliases(item) || m2.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const
        { return m1.aliases(item) || m2.aliases(item); }
    };

    template <
        typename EXP1,
        typename EXP2
        >
    inline const matrix_op<op_join_cols<EXP1,EXP2> > join_cols (
        const matrix_exp<EXP1>& a,
        const matrix_exp<EXP2>& b
    )
    {
        COMPILE_TIME_ASSERT((is_same_type<typename EXP1::type,typename EXP2::type>::value == true));
        // You are getting an error on this line because you are trying to join two matrices that
        // don't have the same number of columns
        COMPILE_TIME_ASSERT(EXP1::NC == EXP2::NC || (EXP1::NC*EXP2::NC == 0));

        DLIB_ASSERT(a.nc() == b.nc() || a.size() == 0 || b.size() == 0,
            "\tconst matrix_exp join_cols(const matrix_exp& a, const matrix_exp& b)"
            << "\n\tYou can only use join_cols() if both matrices have the same number of columns"
            << "\n\ta.nr(): " << a.nr()
            << "\n\tb.nr(): " << b.nr()
            << "\n\ta.nc(): " << a.nc()
            << "\n\tb.nc(): " << b.nc()
            );

        typedef op_join_cols<EXP1,EXP2> op;
        return matrix_op<op>(op(a.ref(),b.ref()));
    }

// ----------------------------------------------------------------------------------------

    template <typename M>
    struct op_fliplr
    {
        op_fliplr( const M& m_) : m(m_){}

        const M& m;

        const static long cost = M::cost;
        const static long NR = M::NR;
        const static long NC = M::NC;
        typedef typename M::type type;
        typedef typename M::const_ret_type const_ret_type;
        typedef typename M::mem_manager_type mem_manager_type;
        typedef typename M::layout_type layout_type;

        const_ret_type apply (long r, long c) const { return m(r,m.nc()-c-1); }

        long nr () const { return m.nr(); }
        long nc () const { return m.nc(); }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }

    };

    template <
        typename M
        >
    const matrix_op<op_fliplr<M> > fliplr (
        const matrix_exp<M>& m
    )
    {
        typedef op_fliplr<M> op;
        return matrix_op<op>(op(m.ref()));
    }

// ----------------------------------------------------------------------------------------

    template <typename M>
    struct op_flipud
    {
        op_flipud( const M& m_) : m(m_){}

        const M& m;

        const static long cost = M::cost;
        const static long NR = M::NR;
        const static long NC = M::NC;
        typedef typename M::type type;
        typedef typename M::const_ret_type const_ret_type;
        typedef typename M::mem_manager_type mem_manager_type;
        typedef typename M::layout_type layout_type;

        const_ret_type apply (long r, long c) const { return m(m.nr()-r-1,c); }

        long nr () const { return m.nr(); }
        long nc () const { return m.nc(); }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }

    };

    template <
        typename M
        >
    const matrix_op<op_flipud<M> > flipud (
        const matrix_exp<M>& m
    )
    {
        typedef op_flipud<M> op;
        return matrix_op<op>(op(m.ref()));
    }

// ----------------------------------------------------------------------------------------

    template <typename M>
    struct op_flip
    {
        op_flip( const M& m_) : m(m_){}

        const M& m;

        const static long cost = M::cost;
        const static long NR = M::NR;
        const static long NC = M::NC;
        typedef typename M::type type;
        typedef typename M::const_ret_type const_ret_type;
        typedef typename M::mem_manager_type mem_manager_type;
        typedef typename M::layout_type layout_type;

        const_ret_type apply (long r, long c) const { return m(m.nr()-r-1, m.nc()-c-1); }

        long nr () const { return m.nr(); }
        long nc () const { return m.nc(); }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }

    };

    template <
        typename M
        >
    const matrix_op<op_flip<M> > flip (
        const matrix_exp<M>& m
    )
    {
        typedef op_flip<M> op;
        return matrix_op<op>(op(m.ref()));
    }

// ----------------------------------------------------------------------------------------

    template <typename T, long NR, long NC, typename MM, typename L>
    uint32 hash (
        const matrix<T,NR,NC,MM,L>& item,
        uint32 seed = 0
    )
    {
        DLIB_ASSERT_HAS_STANDARD_LAYOUT(T);

        if (item.size() == 0)
            return 0;
        else
            return murmur_hash3(&item(0,0), sizeof(T)*item.size(), seed);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MATRIx_UTILITIES_


dlib C++ Library - noncopyable.h

//  (C) Copyright Beman Dawes 1999-2003. Distributed under the Boost
//  Software License, Version 1.0. (See accompanying file
//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//  Contributed by Dave Abrahams
//  See http://www.boost.org/libs/utility for documentation.

#ifndef DLIB_BOOST_NONCOPYABLE_HPP_INCLUDED
#define DLIB_BOOST_NONCOPYABLE_HPP_INCLUDED

namespace dlib
{
    class noncopyable
    {
        /*!
            This class makes it easier to declare a class as non-copyable.
            If you want to make an object that can't be copied just inherit
            from this object.
        !*/

    protected:
        noncopyable() {}
        ~noncopyable() {}
    private:  // emphasize the following members are private
        noncopyable(const noncopyable&);
        const noncopyable& operator=(const noncopyable&);

    };
}

#endif  // DLIB_BOOST_NONCOPYABLE_HPP_INCLUDED


dlib C++ Library - uintn.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.

#ifndef DLIB_UINtn_
#define DLIB_UINtn_

#include "assert.h"

namespace dlib
{

    /*!
        uint64 is a typedef for an unsigned integer that is exactly 64 bits wide.
        uint32 is a typedef for an unsigned integer that is exactly 32 bits wide.
        uint16 is a typedef for an unsigned integer that is exactly 16 bits wide.
        uint8  is a typedef for an unsigned integer that is exactly 8  bits wide.

        int64 is a typedef for an integer that is exactly 64 bits wide.
        int32 is a typedef for an integer that is exactly 32 bits wide.
        int16 is a typedef for an integer that is exactly 16 bits wide.
        int8  is a typedef for an integer that is exactly 8  bits wide.
    !*/

#ifdef __GNUC__
    typedef unsigned long long uint64;
    typedef long long int64;
#elif defined(__BORLANDC__)
    typedef unsigned __int64 uint64;
    typedef __int64 int64;
#elif defined(_MSC_VER)
    typedef unsigned __int64 uint64;
    typedef __int64 int64;
#else
    typedef unsigned long long uint64;
    typedef long long int64;
#endif

    typedef unsigned short uint16;
    typedef unsigned int   uint32;
    typedef unsigned char  uint8;

    typedef short int16;
    typedef int   int32;
    typedef char  int8;

    // make sure these types have the right sizes on this platform
    COMPILE_TIME_ASSERT(sizeof(uint8)  == 1);
    COMPILE_TIME_ASSERT(sizeof(uint16) == 2);
    COMPILE_TIME_ASSERT(sizeof(uint32) == 4);
    COMPILE_TIME_ASSERT(sizeof(uint64) == 8);

    COMPILE_TIME_ASSERT(sizeof(int8)  == 1);
    COMPILE_TIME_ASSERT(sizeof(int16) == 2);
    COMPILE_TIME_ASSERT(sizeof(int32) == 4);
    COMPILE_TIME_ASSERT(sizeof(int64) == 8);

    template <typename T, size_t s = sizeof(T)>
    struct unsigned_type;
    template <typename T>
    struct unsigned_type<T,1> { typedef uint8 type; };
    template <typename T>
    struct unsigned_type<T,2> { typedef uint16 type; };
    template <typename T>
    struct unsigned_type<T,4> { typedef uint32 type; };
    template <typename T>
    struct unsigned_type<T,8> { typedef uint64 type; };
    /*!
        ensures
            - sizeof(unsigned_type<T>::type) == sizeof(T)
            - unsigned_type<T>::type is an unsigned integral type
    !*/

    template <typename T, typename U>
    T zero_extend_cast(
        const U val
    )
    /*!
        requires
            - U and T are integral types
        ensures
            - let ut be a typedef for unsigned_type<U>::type
            - return static_cast<T>(static_cast<ut>(val));
    !*/
    {
        typedef typename unsigned_type<U>::type ut;
        return static_cast<T>(static_cast<ut>(val));
    }

}

#endif // DLIB_UINtn_


dlib C++ Library - assert.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ASSERt_
#define DLIB_ASSERt_

#include "config.h"
#include <sstream>
#include <iosfwd>
#include "error.h"

// -----------------------------

// Use some stuff from boost here
//  (C) Copyright John Maddock 2001 - 2003.
//  (C) Copyright Darin Adler 2001.
//  (C) Copyright Peter Dimov 2001.
//  (C) Copyright Bill Kempf 2002.
//  (C) Copyright Jens Maurer 2002.
//  (C) Copyright David Abrahams 2002 - 2003.
//  (C) Copyright Gennaro Prota 2003.
//  (C) Copyright Eric Friedman 2003.
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef BOOST_JOIN
#define BOOST_JOIN( X, Y ) BOOST_DO_JOIN( X, Y )
#define BOOST_DO_JOIN( X, Y ) BOOST_DO_JOIN2(X,Y)
#define BOOST_DO_JOIN2( X, Y ) X##Y
#endif

// figure out if the compiler has static_assert.
#if defined(__clang__)
#   if __has_feature(cxx_static_assert)
#       define DLIB_HAS_STATIC_ASSERT
#   endif
#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)) && defined(__GXX_EXPERIMENTAL_CXX0X__)
#   define DLIB_HAS_STATIC_ASSERT
#elif defined(_MSC_VER) && _MSC_VER >= 1600
#   define DLIB_HAS_STATIC_ASSERT
#elif defined(__INTEL_COMPILER) && defined(BOOST_INTEL_STDCXX0X)
#   define DLIB_HAS_STATIC_ASSERT
#endif

// -----------------------------

namespace dlib
{
    template <bool value> struct compile_time_assert;
    template <> struct compile_time_assert<true> { enum {value=1};  };

    template <typename T, typename U> struct assert_are_same_type;
    template <typename T> struct assert_are_same_type<T,T> {enum{value=1};};
    template <typename T, typename U> struct assert_are_not_same_type {enum{value=1}; };
    template <typename T> struct assert_are_not_same_type<T,T> {};

    template <typename T, typename U> struct assert_types_match {enum{value=0};};
    template <typename T> struct assert_types_match<T,T> {enum{value=1};};
}

// gcc 4.8 will warn about unused typedefs.  But we use typedefs in some of the compile
// time assert macros so we need to make it not complain about them "not being used".
#ifdef __GNUC__
#define DLIB_NO_WARN_UNUSED __attribute__ ((unused))
#else
#define DLIB_NO_WARN_UNUSED
#endif

// Use the newer static_assert if it's available since it produces much more readable error
// messages.
#ifdef DLIB_HAS_STATIC_ASSERT
    #define COMPILE_TIME_ASSERT(expression) static_assert(expression, "Failed assertion")
    #define ASSERT_ARE_SAME_TYPE(type1, type2) static_assert(::dlib::assert_types_match<type1,type2>::value, "These types should be the same but aren't.")
    #define ASSERT_ARE_NOT_SAME_TYPE(type1, type2) static_assert(!::dlib::assert_types_match<type1,type2>::value, "These types should NOT be the same.")
#else
    #define COMPILE_TIME_ASSERT(expression) \
        DLIB_NO_WARN_UNUSED typedef char BOOST_JOIN(DLIB_CTA, __LINE__)[::dlib::compile_time_assert<(bool)(expression)>::value]

    #define ASSERT_ARE_SAME_TYPE(type1, type2) \
        DLIB_NO_WARN_UNUSED typedef char BOOST_JOIN(DLIB_AAST, __LINE__)[::dlib::assert_are_same_type<type1,type2>::value]

    #define ASSERT_ARE_NOT_SAME_TYPE(type1, type2) \
        DLIB_NO_WARN_UNUSED typedef char BOOST_JOIN(DLIB_AANST, __LINE__)[::dlib::assert_are_not_same_type<type1,type2>::value]
#endif

// -----------------------------

#if defined DLIB_DISABLE_ASSERTS
    // if DLIB_DISABLE_ASSERTS is on then never enable DLIB_ASSERT no matter what.
    #undef ENABLE_ASSERTS
#endif

#if !defined(DLIB_DISABLE_ASSERTS) && ( defined DEBUG || defined _DEBUG)
    // make sure ENABLE_ASSERTS is defined if we are indeed using them.
    #ifndef ENABLE_ASSERTS
        #define ENABLE_ASSERTS
    #endif
#endif

// -----------------------------

#ifdef __GNUC__
// There is a bug in version 4.4.5 of GCC on Ubuntu which causes GCC to segfault
// when __PRETTY_FUNCTION__ is used within certain templated functions.  So just
// don't use it with this version of GCC.
#  if !(__GNUC__ == 4 && __GNUC_MINOR__ == 4 && __GNUC_PATCHLEVEL__ == 5)
#    define DLIB_FUNCTION_NAME __PRETTY_FUNCTION__
#  else
#    define DLIB_FUNCTION_NAME "unknown function"
#  endif
#elif defined(_MSC_VER)
#define DLIB_FUNCTION_NAME __FUNCSIG__
#else
#define DLIB_FUNCTION_NAME "unknown function"
#endif

#define DLIB_CASSERT(_exp,_message)                                              \
    {if ( !(_exp) )                                                         \
    {                                                                       \
        dlib_assert_breakpoint();                                           \
        std::ostringstream dlib_o_out;                                       \
        dlib_o_out << "\n\nError detected at line " << __LINE__ << ".\n";    \
        dlib_o_out << "Error detected in file " << __FILE__ << ".\n";      \
        dlib_o_out << "Error detected in function " << DLIB_FUNCTION_NAME << ".\n\n";      \
        dlib_o_out << "Failing expression was " << #_exp << ".\n";           \
        dlib_o_out << std::boolalpha << _message << "\n";                    \
        throw dlib::fatal_error(dlib::EBROKEN_ASSERT,dlib_o_out.str());      \
    }}

#ifdef ENABLE_ASSERTS
    #define DLIB_ASSERT(_exp,_message) DLIB_CASSERT(_exp,_message)
    #define DLIB_IF_ASSERT(exp) exp
#else
    #define DLIB_ASSERT(_exp,_message) {}
    #define DLIB_IF_ASSERT(exp)
#endif

// ----------------------------------------------------------------------------------------

    /*!A DLIB_ASSERT_HAS_STANDARD_LAYOUT

        This macro is meant to cause a compiler error if a type doesn't have a simple
        memory layout (like a C struct). In particular, types with simple layouts are
        ones which can be copied via memcpy().

        This was called a POD type in C++03 and in C++0x we are looking to check if
        it is a "standard layout type".  Once we can use C++0x we can change this macro
        to something that uses the std::is_standard_layout type_traits class.
        See: http://www2.research.att.com/~bs/C++0xFAQ.html#PODs
    !*/
    // Use the fact that in C++03 you can't put non-PODs into a union.
#define DLIB_ASSERT_HAS_STANDARD_LAYOUT(type)   \
    union  BOOST_JOIN(DAHSL_,__LINE__) { type TYPE_NOT_STANDARD_LAYOUT; };  \
    DLIB_NO_WARN_UNUSED typedef char BOOST_JOIN(DAHSL2_,__LINE__)[sizeof(BOOST_JOIN(DAHSL_,__LINE__))];

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

// breakpoints
extern "C"
{
    inline void dlib_assert_breakpoint(
    ) {}
    /*!
        ensures
            - this function does nothing
              It exists just so you can put breakpoints on it in a debugging tool.
              It is called only when an DLIB_ASSERT or DLIB_CASSERT fails and is about to
              throw an exception.
    !*/
}

// -----------------------------

#include "stack_trace.h"

#endif // DLIB_ASSERt_


dlib C++ Library - stack_trace.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_STACK_TRACe_
#define DLIB_STACK_TRACe_

/*!
    This file defines 3 things.  Two of them are preprocessor macros that
    enable you to tag functions with the dlib stack trace watcher.  The
    third thing is a function named get_stack_trace() which returns the
    current stack trace in std::string form.

    To enable the stack trace you must #define DLIB_ENABLE_STACK_TRACE.
    When this #define isn't set then the 3 things described above
    still exist but they don't do anything.

    Also note that when the stack trace is enabled it changes the DLIB_ASSERT
    and DLIB_CASSERT macros so that they print stack traces when
    an assert fails.

    See the following example program for details:

    #include <iostream>
    #include <dlib/stack_trace.h>

    void funct2()
    {
        // put this macro at the top of each function you would
        // like to appear in stack traces
        DLIB_STACK_TRACE;

        // you may print the current stack trace as follows.
        std::cout << dlib::get_stack_trace() << endl;
    }

    void funct()
    {
        // This alternate form of DLIB_STACK_TRACE allows you to specify
        // the string used to name the current function.  The other form
        // will usually output an appropriate function name automatically
        // so this may not be needed.
        DLIB_STACK_TRACE_NAMED("funct");
        funct2();
    }

    int main()
    {
        funct();
    }
!*/

#include <string>
#include "assert.h"

// only setup the stack trace stuff if the asserts are enabled (which happens in debug mode
// basically).  Also, this stuff doesn't work if you use NO_MAKEFILE
#if defined(DLIB_ENABLE_STACK_TRACE)
#ifdef NO_MAKEFILE
#error "You can't use the dlib stack trace stuff and NO_MAKEFILE at the same time"
#endif

namespace dlib
{
    const std::string get_stack_trace();
}

// redefine the DLIB_CASSERT macro to include the stack trace
#undef DLIB_CASSERT
#define DLIB_CASSERT(_exp,_message)                                              \
    {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 << "Error occurred in function " << DLIB_FUNCTION_NAME << ".\n\n";      \
        dlib_o_out << "Failing expression was " << #_exp << ".\n";           \
        dlib_o_out << _message << "\n\n";                                      \
        dlib_o_out << "Stack Trace: \n" << dlib::get_stack_trace() << "\n";        \
        dlib_assert_breakpoint();                                           \
        throw dlib::fatal_error(dlib::EBROKEN_ASSERT,dlib_o_out.str());      \
    }}

namespace dlib
{

    class stack_tracer
    {
    public:
        stack_tracer (
            const char* funct_name,
            const char* file_name,
            const int line_number
        );

        ~stack_tracer();

    };
}

#define DLIB_STACK_TRACE_NAMED(x) dlib::stack_tracer dlib_stack_tracer_object(x,__FILE__,__LINE__)
#define DLIB_STACK_TRACE dlib::stack_tracer dlib_stack_tracer_object(DLIB_FUNCTION_NAME,__FILE__,__LINE__)

#else // don't do anything if ENABLE_ASSERTS isn't defined
#define DLIB_STACK_TRACE_NAMED(x)
#define DLIB_STACK_TRACE

namespace dlib
{
    inline const std::string get_stack_trace() { return std::string("stack trace not enabled");}
}

#endif

#endif // DLIB_STACK_TRACe_


dlib C++ Library - platform.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_PLATFORm_
#define DLIB_PLATFORm_

/*!
    This file ensures that:
        - if (we are compiling under a posix platform) then
            - POSIX will be defined
            - if (this is also Mac OS X) then
                - MACOSX will be defined
            - if (this is also HP-UX) then
                - HPUX will be defined
        - if (we are compiling under an MS Windows platform) then
            - WIN32 will be defined
!*/

/*
    A good reference for this sort of information is
    http://predef.sourceforge.net/
*/

// Define WIN32 if this is MS Windows
#ifndef WIN32
    #if defined( _MSC_VER) || defined(__BORLANDC__) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__)
    #define WIN32
    #endif
#endif

#ifndef WIN32
    // since this is the only other platform the library currently supports
    // just assume it is POSIX if it isn't WIN32
    #ifndef POSIX
        #define POSIX
    #endif

    #ifndef HPUX
       #if defined(__hpux ) || defined(hpux) || defined (_hpux)
       #define HPUX
       #endif
    #endif

    #ifndef MACOSX
        #ifdef __MACOSX__
        #define MACOSX
        #endif
        #ifdef __APPLE__
        #define MACOSX
        #endif
    #endif

#endif

#endif // DLIB_PLATFORm_


dlib C++ Library - Miscellaneous

The Library
  • Algorithms
  • API Wrappers
  • Bayesian Nets
  • Compression
  • Containers
  • Graph Tools
  • Image Processing
  • Linear Algebra
  • Machine Learning
  • Metaprogramming
  • Miscellaneous
  • Networking
  • Optimization
  • Parsing

Help/Info
  • Dlib Blog
  • Examples: C++
    • 3D Point Cloud
    • Assignment Learning
    • Base64 Encoder
    • Bayesian Network From Disk
    • Bayesian Network GUI
    • Bayesian Network
    • Bridge
    • BSP
    • C-Support Vector Machine
    • Cmd Line Parser
    • Compress Stream
    • Config File Reader
    • Custom Trainers
    • Directory Navigation
    • Empirical Kernel Map
    • Face Detection
    • Face Landmark Detection
    • FHOG Feature Extraction
    • FHOG Object Detection
    • Graph Labeling
    • GUI
    • Hough Transform
    • HTTP Server
    • Image
    • IO Socket Streams
    • IO Streams Server
    • Kernel Centroid
    • Kernel K-Means Clustering
    • Kernel Ridge Regression
    • Kernel RLS Filtering
    • Kernel RLS Regression
    • KRR Classification
    • Learning to Track
    • Linear Assignment Problems
    • Linear Manifold Regularizer
    • Linear Model Predictive Control
    • Logger Advanced
    • Logger Custom Output
    • Logger
    • Matrix Expressions
    • Matrix
    • Member Function Pointer
    • Model Selection
    • Multiclass Classification
    • Multithreaded Object
    • Neural Network
    • Non-Linear Least Squares
    • Nu-Support Vector Machine
    • Numerical Integration
    • Object Detector Advanced
    • Object Detector
    • One Class Classifiers
    • Online SVM
    • Optimization
    • Parallel For Loops
    • Pipe 2
    • Pipe
    • Quantum Computing
    • Queue
    • Rank Features
    • Relevance Vector Classification
    • Relevance Vector Regression
    • Running Stats
    • Sequence Labeling
    • Sequence Segmentation
    • Sockets
    • Sockstreambuf
    • Sparse Vectors
    • SQLite
    • Std C++ Allocator
    • Structural Support Vector Machines
    • Support Vector Regression
    • SURF
    • SVM-Rank
    • Thread Function
    • Thread Pool
    • Threaded Object
    • Threads
    • Timer
    • Train Object Detector
    • Train Shape Predictor
    • Using Custom Kernels
    • Video Object Tracking
    • Webcam Face Pose Estimation
    • XML Parser
  • Examples: Python
    • Face Detector
    • Face Landmark Detection
    • find candidate object locations
    • Linear Assignment Problems
    • Sequence Segmenter
    • Structural Support Vector Machines
    • SVM-Rank
    • Train Object Detector
    • Train Shape Predictor
    • Video Object Tracking
  • FAQ
  • Forums
  • Home
  • How to compile
  • How to contribute
  • Index
  • Introduction
  • License
  • Python API
  • Suggested Books
  • Who uses dlib?

Current Release
  • Change Log
  • Release Notes
  • Version: 18.18

Last Modified:
Sep 13, 2015
Miscellaneous

This page documents library components that don't really fit in anywhere else. They all follow the same conventions as the rest of the library.

Objects
  • bit_stream
  • bound_function_pointer
  • byte_orderer
  • console_progress_indicator
  • copy_functor
  • default_memory_manager
  • error
  • Fixed_width_integers
    • int16
    • int32
    • int64
    • int8
    • uint16
    • uint32
    • uint64
    • uint8
  • logger
  • member_function_pointer
  • memory_manager
  • memory_manager_global
  • memory_manager_stateless
  • pipe
  • std_allocator
  • sync_extension
  • timeout
  • timer
  • vectorstream

Global Functions
  • deserialize
  • make_mfp
  • serialize
  • TIME_THIS
  • timing code blocks
  • zero_extend_cast

SQLite
  • database
  • simple_queries
    • query_blob
    • query_double
    • query_int64
    • query_int
    • query_object
    • query_text
  • statement
  • transaction

Other
  • dlib_testing_suite
  • MATLAB

[top]

bit_stream

This object represents a middle man between a user and the iostream classes that allows single bits to be read/written easily from/to the iostream classes
More Details...
#include <dlib/bit_stream.h>

Implementations:
bit_stream_kernel_1:
This implementation is done by buffering single bits in the obvious way.
kernel_1a
is a typedef for bit_stream_kernel_1
kernel_1a_c
 is a typedef for kernel_1a that checks its preconditions.

Extensions to bit_stream

bit_stream_multi

This extension gives a bit_stream object the ability to read/write multiple bits at a time.

More Details...

Implementations:
bit_stream_multi_1:
This implementation is done by calling the read/write functions in the bit_stream kernel.
multi_1a
is a typedef for bit_stream_kernel_1 extended by bit_stream_multi_1
multi_1a_c
 is a typedef for multi_1a that checks its preconditions.
[top]

bound_function_pointer

This object represents a function with all its arguments bound to specific objects.

This implementation is done using type erasure and placement new. This means that it never allocates memory on the heap and instead stores everything on the stack.

More Details...
#include <dlib/bound_function_pointer.h>
[top]

byte_orderer

This object provides a simple type safe mechanism to convert data to and from network and host byte orders. I.e. to convert things between big and little endian byte ordering.
More Details...
#include <dlib/byte_orderer.h>
[top]

console_progress_indicator

This object is a tool for reporting how long a task will take to complete.
More Details...
#include <dlib/console_progress_indicator.h>
[top]

copy_functor

This is a templated function object that makes copies of something.
More Details...
#include <dlib/algs.h>
[top]

database

This object is a C++ wrapper around a SQLite database connection handle and therefore represents a SQLite database file.

Note that this wrapper is targeted at SQLite Version 3. To use it you must make sure you link your application with SQLite. However, if you use CMake and dlib's default CMakeLists.txt file then it will get setup automatically. This is assuming sqlite3 is properly installed on your system. On ubuntu you can get it by installing the libsqlite3-dev package. Or you can always download the SQLite source and compile it straight into your application (download the amalgamation).

C++ Example Programs: sqlite_ex.cpp
More Details...
#include <dlib/sqlite.h>
[top]

default_memory_manager

This is a memory manager object which simply calls new and delete directly (i.e. it doesn't really do anything). It is the default memory manager used by most of the objects in dlib.
More Details...
#include <dlib/algs.h>
[top]

deserialize

This is actually a set of overloaded functions which provide the ability to restore an object's state from an input stream. Currently all dlib container classes, non pointer C++ intrinsics, std::string, std::vector, std::map, std::set, std::complex, dlib::bigint, dlib::uint64, dlib::int64, C style arrays, and dlib::vector objects are serializable.

You can also use serialize() and deserialize() to read/write Google protocol buffer objects. However, note that dlib::serialize() writes additional delimiting bytes at the start of each protocol buffer message. We do this because Google protocol buffers are not self-delimiting on their own. This means that you can't write more than one protocol buffer object to an output stream unless you include some kind of delimiter between the messages. So dlib takes care of this for you by prefixing each message with its length in bytes. In particular, the number of bytes is encoded as a 32bit little endian integer.

More Details...
#include <dlib/serialize.h>
[top]

dlib_testing_suite

This library comes with a command line driven regression test suite. All the testing code is located in the dlib/test folder. If you want to build it and test the library on your system you can use the makefile at dlib/test/makefile (you may have to edit it to make it work on your system) or use the CMake CMakeLists.txt file at dlib/test/CMakeLists.txt to build it.

What you may find more useful however is the testing framework itself. It uses a fairly simple and modular design. Each test is contained in its own cpp file and when compiled into the program it automatically shows up in the list of tests to run. If you want to use the testing framework all you need to do is add the files dlib/test/tester.h, dlib/test/tester.cpp, and dlib/test/main.cpp to your project and then add cpp files that contain your tests (see dlib/test/example.cpp and dlib/test/example_args.cpp for some examples).

From the command line you can choose to run all the installed tests, enable or disable the loggers, set various logging levels, specify how many times to run the tests, or pick just one or two tests to run at a time rather than the entire suite. The output of the program, that is, its return value from main() is the number of failed tests. So if every test succeeds then it returns 0.

[top]

error

This is the base exception class from which all exceptions in this library inherit.
More Details...
#include <dlib/error.h>
[top]

int16

This is just a typedef for a 16 bit integer.
More Details...
#include <dlib/uintn.h>
[top]

int32

This is just a typedef for a 32 bit integer.
More Details...
#include <dlib/uintn.h>
[top]

int64

This is just a typedef for a 64 bit integer.
More Details...
#include <dlib/uintn.h>
[top]

int8

This is just a typedef for an 8 bit integer.
More Details...
#include <dlib/uintn.h>
[top]

logger

This component is a logging output stream in the style of the log4j logger available for Java.

C++ Example Programs: logger_ex.cpp, logger_ex_2.cpp, logger_custom_output_ex.cpp, pipe_ex.cpp
More Details...
#include <dlib/logger.h>

Extensions to logger

config_file

This extension provides the configure_loggers_from_file() function which reads a configuration file from disk that sets up all your loggers.

More Details...
extra_logger_headers

This extension contains additional logger headers you may chose to use instead of the default one.

More Details...
[top]

make_mfp

This function is a simple factory for creating member_function_pointer objects without needing to know the necessary template arguments for the member_function_pointer.
More Details...
#include <dlib/member_function_pointer.h>
[top]

MATLAB

dlib contains a tool that makes it easy to call C++ code from MATLAB. It's documented in the examples in the dlib/matlab folder. In particular, the dlib/matlab/example_mex_function.cpp and dlib/matlab/example_mex_callback.cpp examples. You can also easily compile these files using CMake. See the instructions in the README file in the dlib/matlab folder for further details.
[top]

member_function_pointer

This object represents a member function pointer. It is useful because instances of this object can be created without needing to know the type of object whose member function we will be calling.

The implementation of this object is done using type erasure and placement new. This means that it never allocates memory on the heap and instead stores everything on the stack.

C++ Example Programs: member_function_pointer_ex.cpp
More Details...
#include <dlib/member_function_pointer.h>
[top]

memory_manager

This object represents a memory pool.
More Details...
#include <dlib/memory_manager.h>

Implementations:
memory_manager_kernel_1:
This memory manager implementation allocates objects one at a time when there are allocation requests. Then when there is a deallocate request the returning object is placed into a list of free blocks if that list has less than max_pool_size blocks in it. Subsequent allocation requests will be serviced by drawing from the free list whenever it isn't empty. Array allocations, on the other hand, are not managed at all but are passed directly on to new and delete.

When this object's max_pool_size template parameter is set to 0 it simply calls new and delete directly and doesn't function as a memory pool.

kernel_1a
is a typedef for memory_manager_kernel_1 with a max_pool_size of 0
kernel_1b
is a typedef for memory_manager_kernel_1 with a max_pool_size of 10
kernel_1c
is a typedef for memory_manager_kernel_1 with a max_pool_size of 100
kernel_1d
is a typedef for memory_manager_kernel_1 with a max_pool_size of 1000
kernel_1e
is a typedef for memory_manager_kernel_1 with a max_pool_size of 10000
kernel_1f
is a typedef for memory_manager_kernel_1 with a max_pool_size of 100000
memory_manager_kernel_2:
This memory manager implementation allocates memory in blocks of chunk_size*sizeof(T) bytes. All the sizeof(T) sub-blocks are kept in a linked list of free memory blocks and are given out whenever an allocation request occurs. Also, memory is not freed until this object is destructed. Also note that array allocations are not managed at all but are passed directly on to new and delete.
kernel_2a
is a typedef for memory_manager_kernel_2 with a chunk_size of 10
kernel_2b
is a typedef for memory_manager_kernel_2 with a chunk_size of 100
kernel_2c
is a typedef for memory_manager_kernel_2 with a chunk_size of 1000
kernel_2d
is a typedef for memory_manager_kernel_2 with a chunk_size of 10000
kernel_2e
is a typedef for memory_manager_kernel_2 with a chunk_size of 100000
memory_manager_kernel_3:
This memory manager implementation allocates memory in blocks of chunk_size*sizeof(T) bytes. All the sizeof(T) sub-blocks are kept in a linked list of free memory blocks and are given out whenever an allocation request occurs. Note that array allocations are managed. So this object is just like kernel_2 but it also pools memory from array allocations (chunk_size has no effect with respect to array allocations, each array is allocated one at a time). Also, memory is not freed until this object is destructed.
kernel_3a
is a typedef for memory_manager_kernel_3 with a chunk_size of 10
kernel_3b
is a typedef for memory_manager_kernel_3 with a chunk_size of 100
kernel_3c
is a typedef for memory_manager_kernel_3 with a chunk_size of 1000
kernel_3d
is a typedef for memory_manager_kernel_3 with a chunk_size of 10000
kernel_3e
is a typedef for memory_manager_kernel_3 with a chunk_size of 100000
[top]

memory_manager_global

This object represents some kind of global memory manager or memory pool.
More Details...
#include <dlib/memory_manager_global.h>

Implementations:
memory_manager_global_kernel_1:
This is implemented in the obvious way. See the code for details.
kernel_1a
is a typedef for memory_manager_global_kernel_1
[top]

memory_manager_stateless

This object represents some kind of stateless memory manager or memory pool. Stateless means that all instances (instances of the same type that is) of this object are identical and can be used interchangeably. Note that implementations are allowed to have some shared global state such as a global memory pool. This object is also thread safe.
More Details...
#include <dlib/memory_manager_stateless.h>

Implementations:
memory_manager_stateless_kernel_1:
This implementation just calls new and delete. So it doesn't do anything special.
kernel_1a
is a typedef for memory_manager_stateless_kernel_1
memory_manager_stateless_kernel_2:
This implementation uses a global instance of a memory_manager object guarded by a mutex as its implementation.
kernel_2_1a
is a typedef for memory_manager_stateless_kernel_2 that uses memory_manager_1a
kernel_2_1b
is a typedef for memory_manager_stateless_kernel_2 that uses memory_manager_1b
kernel_2_1c
is a typedef for memory_manager_stateless_kernel_2 that uses memory_manager_1c
kernel_2_1d
is a typedef for memory_manager_stateless_kernel_2 that uses memory_manager_1d
kernel_2_1e
is a typedef for memory_manager_stateless_kernel_2 that uses memory_manager_1e
kernel_2_1f
is a typedef for memory_manager_stateless_kernel_2 that uses memory_manager_1f
kernel_2_2a
is a typedef for memory_manager_stateless_kernel_2 that uses memory_manager_2a
kernel_2_2b
is a typedef for memory_manager_stateless_kernel_2 that uses memory_manager_2b
kernel_2_2c
is a typedef for memory_manager_stateless_kernel_2 that uses memory_manager_2c
kernel_2_2d
is a typedef for memory_manager_stateless_kernel_2 that uses memory_manager_2d
kernel_2_2e
is a typedef for memory_manager_stateless_kernel_2 that uses memory_manager_2e
kernel_2_3a
is a typedef for memory_manager_stateless_kernel_2 that uses memory_manager_3a
kernel_2_3b
is a typedef for memory_manager_stateless_kernel_2 that uses memory_manager_3b
kernel_2_3c
is a typedef for memory_manager_stateless_kernel_2 that uses memory_manager_3c
kernel_2_3d
is a typedef for memory_manager_stateless_kernel_2 that uses memory_manager_3d
kernel_2_3e
is a typedef for memory_manager_stateless_kernel_2 that uses memory_manager_3e
[top]

pipe

This is a first in first out queue with a fixed maximum size. It is suitable for passing objects between threads.

This object is optimized for speed, therefore, it uses global swap() to create a zero-copy method for moving objects around. For example, on a computer running Ubuntu 12.04 with a 2.67GHz Intel i7 920 CPU it is possible to pass over 4.4 million std::vector<int> objects a second between two threads. This is regardless of the number of ints in the std::vector objects. In particular, this test was done with 100,000 ints in each std::vector.

Finally, note that you can use the pipe as an efficient method to pass messages between two networked computers by using the bridge.

C++ Example Programs: pipe_ex.cpp, pipe_ex_2.cpp, bridge_ex.cpp
More Details...
#include <dlib/pipe.h>
[top]

serialize

This is actually a set of overloaded functions which provide the ability to save an object's state to an output stream. Currently all dlib container classes, non pointer C++ intrinsics, std::string, std::vector, std::map, std::set, std::complex, dlib::bigint, dlib::uint64, dlib::int64, C style arrays, and dlib::vector objects are serializable.

You can also use serialize() and deserialize() to read/write Google protocol buffer objects. However, note that dlib::serialize() writes additional delimiting bytes at the start of each protocol buffer message. We do this because Google protocol buffers are not self-delimiting on their own. This means that you can't write more than one protocol buffer object to an output stream unless you include some kind of delimiter between the messages. So dlib takes care of this for you by prefixing each message with its length in bytes. In particular, the number of bytes is encoded as a 32bit little endian integer.

More Details...
#include <dlib/serialize.h>
[top]

statement

This object represents a SQL statement which can be executed against a database object. In particular, this object is a C++ wrapper around a SQLite prepared statement.

Note that this wrapper is targeted at SQLite Version 3. To use it you must make sure you link your application with SQLite.

C++ Example Programs: sqlite_ex.cpp
More Details...
#include <dlib/sqlite.h>
[top]

std_allocator

This object is an implementation of an allocator that conforms to the C++ standard requirements for allocator objects. The M template argument is one of the dlib memory manager objects and this allocator implementation will do all of its memory allocations using whatever dlib memory manager you supply.

Thus, using this allocator object you can use any of the dlib memory manager objects with the containers in the STL or with any other object that requires an STL style allocator object.

C++ Example Programs: std_allocator_ex.cpp
More Details...
#include <dlib/std_allocator.h>
[top]

sync_extension

This object represents a general extension to any object. This object gives any object which it extends an integrated rmutex and rsignaler object. The extended object will then be able to be treated as if it was also a rmutex and rsignaler.
More Details...
#include <dlib/sync_extension.h>

Implementations:
sync_extension_kernel_1:
This is implemented using a rmutex and rsignaler in the obvious way.
kernel_1a
is a typedef for sync_extension_kernel_1
[top]

timeout

This object provides a simple way to implement a timeout.
More Details...
#include <dlib/timeout.h>
[top]

timer

This object represents a timer that will call a given member function repeatedly at regular intervals.

The implementation of this object has a single master thread that does all the waiting. This master thread creates and dispatches threads to specific timer objects when they need to run their action functions. When a timer object isn't executing its action function then it doesn't have any thread allocated to it at all. So it is fairly efficient.

C++ Example Programs: timer_ex.cpp
More Details...
#include <dlib/timer.h>
[top]

TIME_THIS

This is a macro function for timing blocks of code. Its form is TIME_THIS(whatever you want to time) It's pretty straight forward. It just prints the time it took to std::cout.

There is another version of this function called TIME_THIS_TO which takes as a parameter an ostream object to write its output to. Its form is TIME_THIS_TO(what you want to time, the output stream);

More Details...
#include <dlib/time_this.h>
[top]

timing code blocks

This is a set of set of functions for timing blocks of code. Unlike TIME_THIS, it can be used to find the cumulative time spent on a block which is executed multiple times.
More Details...
#include <dlib/timing.h>
[top]

transaction

This object is a tool for creating exception safe database transactions.

C++ Example Programs: sqlite_ex.cpp
More Details...
#include <dlib/sqlite.h>
[top]

uint16

This is just a typedef for a 16 bit unsigned integer.
More Details...
#include <dlib/uintn.h>
[top]

uint32

This is just a typedef for a 32 bit unsigned integer.
More Details...
#include <dlib/uintn.h>
[top]

uint64

This is just a typedef for a 64 bit unsigned integer.
More Details...
#include <dlib/uintn.h>
[top]

uint8

This is just a typedef for an 8 bit unsigned integer.
More Details...
#include <dlib/uintn.h>
[top]

vectorstream

This is an iostream object that reads and writes from an in-memory buffer. It functions very much the same way as the std::stringstream object. However, while the std::stringstream holds its buffer internally and it can only be accessed by copying it out, the vectorstream uses an external std::vector<char> as its buffer. That is, it holds a reference to an external vector and does not contain any internal buffers of its own.

This object is useful as a slightly more efficient alternative to the std::stringstream since you can avoid the overhead of copying buffer contents to and from the stream. This is particularly useful when used as a source or target for serialization routines.

More Details...
#include <dlib/vectorstream.h>
[top]

zero_extend_cast

This is a global function that performs a zero extending cast from one integral type to another integral type.
More Details...
#include <dlib/uintn.h>


dlib C++ Library - bit_stream_kernel_abstract.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_BIT_STREAM_KERNEl_ABSTRACT_
#ifdef DLIB_BIT_STREAM_KERNEl_ABSTRACT_

#include <iosfwd>

namespace dlib
{

    class bit_stream
    {

        /*!
            INITIAL VALUE
                is_in_write_mode()  == false
                is_in_read_mode()   == false

            WHAT THIS OBJECT REPRESENTS
                this object is a middle man between a user and the iostream classes.
                it allows single bits to be read/written easily to/from
                the iostream classes

            BUFFERING:
                This object will only read/write single bytes at a time from/to the
                iostream objects. Any buffered bits still in the bit_stream object
                when it is closed or destructed are lost if it is in read mode.  If
                it is in write mode then any remaining bits are guaranteed to be
                written to the output stream by the time it is closed or destructed.
        !*/

    public:

        bit_stream (
        );
        /*!
            ensures
                - #*this is properly initialized
            throws
                - std::bad_alloc
        !*/

        virtual ~bit_stream (
        );
        /*!
            ensures
                - all memory associated with *this has been released
        !*/

        void clear (
        );
        /*!
            ensures
                - #*this has its initial value
            throws
                - std::bad_alloc
                    if this exception is thrown then *this is unusable
                    until clear() is called and succeeds
        !*/

        void set_input_stream (
            std::istream& is
        );
        /*!
            requires
                - is_in_write_mode() == false
                - is_in_read_mode() == false
                - is is ready to give input
            ensures
                - #is_in_write_mode() == false
                - #is_in_read_mode() == true
                - #*this will now be reading from is
            throws
                - std::bad_alloc
        !*/

        void set_output_stream (
            std::ostream& os
        );
        /*!
            requires
                - is_in_write_mode() == false
                - is_in_read_mode() == false
                - os is ready to take output
            ensures
                - #is_in_write_mode() == true
                - #is_in_read_mode() == false
                - #*this will now write to os
            throws
                - std::bad_alloc
        !*/

        void close (
        );
        /*!
            requires
                - is_in_write_mode() == true || is_in_read_mode() == true
            ensures
                - #is_in_write_mode() == false
                - #is_in_read_mode()  == false
        !*/

        bool is_in_write_mode (
        ) const;
        /*!
            ensures
                - returns true if *this is associated with an output stream object
                - returns false otherwise
        !*/

        bool is_in_read_mode (
        ) const;
        /*!
            ensures
                - returns true if *this is associated with an input stream object
                - returns false otherwise
        !*/

        void write (
            int bit
        );
        /*!
            requires
                - is_in_write_mode() == true
                - bit == 0 || bit == 1
            ensures
                - bit will be written to the ostream object associated with *this
            throws
                - std::ios_base::failure
                    if (there was a problem writing to the output stream) then
                    this exception will be thrown.  #*this will be unusable until
                    clear() is called and succeeds
                - any other exception
                    if this exception is thrown then #*this is unusable
                    until clear() is called and succeeds
        !*/

        bool read (
            int& bit
        );
        /*!
            requires
                - is_in_read_mode() == true
            ensures
                - the next bit has been read and placed into #bit
                - returns true if the read was successful, else false
                  (ex. false if EOF has been reached)
            throws
                - any exception
                    if this exception is thrown then #*this is unusable
                    until clear() is called and succeeds
        !*/

        void swap (
            bit_stream& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/

        private:

            // restricted functions
            bit_stream(bit_stream&);        // copy constructor
            bit_stream& operator=(bit_stream&);    // assignment operator

    };

    inline void swap (
        bit_stream& a,
        bit_stream& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

}

#endif // DLIB_BIT_STREAM_KERNEl_ABSTRACT_


dlib C++ Library - bit_stream_multi_abstract.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_BIT_STREAM_MULTi_ABSTRACT_
#ifdef DLIB_BIT_STREAM_MULTi_ABSTRACT_

#include "bit_stream_kernel_abstract.h"

namespace dlib
{
    template <
        typename bit_stream_base
        >
    class bit_stream_multi : public bit_stream_base
    {

        /*!
            REQUIREMENTS ON BIT_STREAM_BASE
                it is an implementation of bit_stream/bit_stream_kernel_abstract.h

            WHAT THIS EXTENSION DOES FOR BIT_STREAM
                this gives a bit_stream object the ability to read/write multible bits
                at a time
        !*/

        public:

        void multi_write (
            unsigned long data,
            int num_to_write
        );
        /*!
            requires
                - is_in_write_mode() == true
                - 0 <= num_to_write <= 32
            ensures
                - num_to_write low order bits from data will be written to the ostream
                - object associated with *this
                  example: if data is 10010 then the bits will be written in the
                  order 1,0,0,1,0
        !*/

        int multi_read (
            unsigned long& data,
            int num_to_read
        );
        /*!
            requires
                - is_in_read_mode() == true
                - 0 <= num_to_read <= 32
            ensures
                - tries to read num_to_read bits into the low order end of #data
                  example:  if the incoming bits were 10010 then data would end
                  up with 10010 as its low order bits
                - all of the bits in #data not filled in by multi_read() are zero
                - returns the number of bits actually read into #data
        !*/

    };

    template <
        typename bit_stream_base
        >
    inline void swap (
        bit_stream_multi<bit_stream_base>& a,
        bit_stream_multi<bit_stream_base>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

}

#endif // DLIB_BIT_STREAM_MULTi_ABSTRACT_


dlib C++ Library - bound_function_pointer_kernel_abstract.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_BOUND_FUNCTION_POINTER_KERNEl_ABSTRACT_
#ifdef DLIB_BOUND_FUNCTION_POINTER_KERNEl_ABSTRACT_

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class bound_function_pointer
    {
        /*!
            INITIAL VALUE
                is_set() == false

            WHAT THIS OBJECT REPRESENTS
                This object represents a function with all its arguments bound to
                specific objects.  For example:

                    void test(int& var) { var = var+1; }

                    bound_function_pointer funct;

                    int a = 4;
                    funct.set(test,a); // bind the variable a to the first argument of the test() function

                    // at this point a == 4
                    funct();
                    // after funct() is called a == 5
        !*/

    public:

        bound_function_pointer (
        );
        /*!
            ensures
                - #*this is properly initialized
        !*/

        bound_function_pointer(
            const bound_function_pointer& item
        );
        /*!
            ensures
                - *this == item
        !*/

        ~bound_function_pointer (
        );
        /*!
            ensures
                - any resources associated with *this have been released
        !*/

        bound_function_pointer& operator=(
            const bound_function_pointer& item
        );
        /*!
            ensures
                - *this == item
        !*/

        void clear(
        );
        /*!
            ensures
                - #*this has its initial value
        !*/

        bool is_set (
        ) const;
        /*!
            ensures
                - if (this->set() has been called) then
                    - returns true
                - else
                    - returns false
        !*/

        operator some_undefined_pointer_type (
        ) const;
        /*!
            ensures
                - if (is_set()) then
                    - returns a non 0 value
                - else
                    - returns a 0 value
        !*/

        bool operator! (
        ) const;
        /*!
            ensures
                - returns !is_set()
        !*/

        void operator () (
        ) const;
        /*!
            requires
                - is_set() == true
            ensures
                - calls the bound function on the object(s) specified by the last
                  call to this->set()
            throws
                - any exception thrown by the function specified by
                  the previous call to this->set().
                    If any of these exceptions are thrown then the call to this
                    function will have no effect on *this.
        !*/

        void swap (
            bound_function_pointer& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/

        // ----------------------

        template <typename F>
        void set (
            F& function_object
        );
        /*!
            requires
                - function_object() is a valid expression
            ensures
                - #is_set() == true
                - calls to this->operator() will call function_object()
                  (This seems pointless but it is a useful base case)
        !*/

        template < typename T>
        void set (
            T& object,
            void (T::*funct)()
        );
        /*!
            requires
                - funct == a valid member function pointer for class T
            ensures
                - #is_set() == true
                - calls to this->operator() will call (object.*funct)()
        !*/

        template < typename T>
        void set (
            const T& object,
            void (T::*funct)()const
        );
        /*!
            requires
                - funct == a valid bound function pointer for class T
            ensures
                - #is_set() == true
                - calls to this->operator() will call (object.*funct)()
        !*/

        void set (
            void (*funct)()
        );
        /*!
            requires
                - funct == a valid function pointer
            ensures
                - #is_set() == true
                - calls to this->operator() will call funct()
        !*/

        // ----------------------

        template <typename F, typename A1 >
        void set (
            F& function_object,
            A1& arg1
        );
        /*!
            requires
                - function_object(arg1) is a valid expression
            ensures
                - #is_set() == true
                - calls to this->operator() will call function_object(arg1)
        !*/

        template < typename T, typename T1, typename A1 >
        void set (
            T& object,
            void (T::*funct)(T1),
            A1& arg1
        );
        /*!
            requires
                - funct == a valid member function pointer for class T
            ensures
                - #is_set() == true
                - calls to this->operator() will call (object.*funct)(arg1)
        !*/

        template < typename T, typename T1, typename A1 >
        void set (
            const T& object,
            void (T::*funct)(T1)const,
            A1& arg1
        );
        /*!
            requires
                - funct == a valid bound function pointer for class T
            ensures
                - #is_set() == true
                - calls to this->operator() will call (object.*funct)(arg1)
        !*/

        template <typename T1, typename A1>
        void set (
            void (*funct)(T1),
            A1& arg1
        );
        /*!
            requires
                - funct == a valid function pointer
            ensures
                - #is_set() == true
                - calls to this->operator() will call funct(arg1)
        !*/

        // ----------------------
        template <typename F, typename A1, typename A2 >
        void set (
            F& function_object,
            A1& arg1,
            A2& arg2
        );
        /*!
            requires
                - function_object(arg1,arg2) is a valid expression
            ensures
                - #is_set() == true
                - calls to this->operator() will call function_object(arg1,arg2)
        !*/

        template < typename T, typename T1, typename A1,
                               typename T2, typename A2>
        void set (
            T& object,
            void (T::*funct)(T1,T2),
            A1& arg1,
            A2& arg2
        );
        /*!
            requires
                - funct == a valid member function pointer for class T
            ensures
                - #is_set() == true
                - calls to this->operator() will call (object.*funct)(arg1,arg2)
        !*/

        template < typename T, typename T1, typename A1,
                               typename T2, typename A2>
        void set (
            const T& object,
            void (T::*funct)(T1,T2)const,
            A1& arg1,
            A2& arg2
        );
        /*!
            requires
                - funct == a valid bound function pointer for class T
            ensures
                - #is_set() == true
                - calls to this->operator() will call (object.*funct)(arg1,arg2)
        !*/

        template <typename T1, typename A1,
                  typename T2, typename A2>
        void set (
            void (*funct)(T1,T2),
            A1& arg1,
            A2& arg2
        );
        /*!
            requires
                - funct == a valid function pointer
            ensures
                - #is_set() == true
                - calls to this->operator() will call funct(arg1,arg2)
        !*/

        // ----------------------

        template <typename F, typename A1, typename A2, typename A3 >
        void set (
            F& function_object,
            A1& arg1,
            A2& arg2,
            A3& arg3
        );
        /*!
            requires
                - function_object(arg1,arg2,arg3) is a valid expression
            ensures
                - #is_set() == true
                - calls to this->operator() will call function_object(arg1,arg2,arg3)
        !*/

        template < typename T, typename T1, typename A1,
                               typename T2, typename A2,
                               typename T3, typename A3>
        void set (
            T& object,
            void (T::*funct)(T1,T2,T3),
            A1& arg1,
            A2& arg2,
            A3& arg3
        );
        /*!
            requires
                - funct == a valid member function pointer for class T
            ensures
                - #is_set() == true
                - calls to this->operator() will call (object.*funct)(arg1,arg2,arg3)
        !*/

        template < typename T, typename T1, typename A1,
                               typename T2, typename A2,
                               typename T3, typename A3>
        void set (
            const T& object,
            void (T::*funct)(T1,T2,T3)const,
            A1& arg1,
            A2& arg2,
            A3& arg3
        );
        /*!
            requires
                - funct == a valid bound function pointer for class T
            ensures
                - #is_set() == true
                - calls to this->operator() will call (object.*funct)(arg1,arg2,arg3)
        !*/

        template <typename T1, typename A1,
                  typename T2, typename A2,
                  typename T3, typename A3>
        void set (
            void (*funct)(T1,T2,T3),
            A1& arg1,
            A2& arg2,
            A3& arg3
        );
        /*!
            requires
                - funct == a valid function pointer
            ensures
                - #is_set() == true
                - calls to this->operator() will call funct(arg1,arg2,arg3)
        !*/

        // ----------------------

        template <typename F, typename A1, typename A2, typename A3, typename A4>
        void set (
            F& function_object,
            A1& arg1,
            A2& arg2,
            A3& arg3,
            A4& arg4
        );
        /*!
            requires
                - function_object(arg1,arg2,arg3,arg4) is a valid expression
            ensures
                - #is_set() == true
                - calls to this->operator() will call function_object(arg1,arg2,arg3,arg4)
        !*/

        template < typename T, typename T1, typename A1,
                               typename T2, typename A2,
                               typename T3, typename A3,
                               typename T4, typename A4>
        void set (
            T& object,
            void (T::*funct)(T1,T2,T3,T4),
            A1& arg1,
            A2& arg2,
            A3& arg3,
            A4& arg4
        );
        /*!
            requires
                - funct == a valid member function pointer for class T
            ensures
                - #is_set() == true
                - calls to this->operator() will call (object.*funct)(arg1,arg2,arg3,arg4)
        !*/

        template < typename T, typename T1, typename A1,
                               typename T2, typename A2,
                               typename T3, typename A3,
                               typename T4, typename A4>
        void set (
            const T& object,
            void (T::*funct)(T1,T2,T3,T4)const,
            A1& arg1,
            A2& arg2,
            A3& arg3,
            A4& arg4
        );
        /*!
            requires
                - funct == a valid bound function pointer for class T
            ensures
                - #is_set() == true
                - calls to this->operator() will call (object.*funct)(arg1,arg2,arg3,arg4)
        !*/

        template <typename T1, typename A1,
                  typename T2, typename A2,
                  typename T3, typename A3,
                  typename T4, typename A4>
        void set (
            void (*funct)(T1,T2,T3,T4),
            A1& arg1,
            A2& arg2,
            A3& arg3,
            A4& arg4
        );
        /*!
            requires
                - funct == a valid function pointer
            ensures
                - #is_set() == true
                - calls to this->operator() will call funct(arg1,arg2,arg3,arg4)
        !*/

    };

// ----------------------------------------------------------------------------------------

    inline void swap (
        bound_function_pointer& a,
        bound_function_pointer& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_BOUND_FUNCTION_POINTER_KERNEl_ABSTRACT_


dlib C++ Library - byte_orderer_kernel_abstract.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_BYTE_ORDEREr_ABSTRACT_
#ifdef DLIB_BYTE_ORDEREr_ABSTRACT_

#include "../algs.h"

namespace dlib
{

    class byte_orderer
    {
        /*!
            INITIAL VALUE
                This object has no state.

            WHAT THIS OBJECT REPRESENTS
                This object simply provides a mechanism to convert data from a
                host machine's own byte ordering to big or little endian and to
                also do the reverse.

                It also provides a pair of functions to convert to/from network byte
                order where network byte order is big endian byte order.  This pair of
                functions does the exact same thing as the host_to_big() and big_to_host()
                functions and is provided simply so that client code can use the most
                self documenting name appropriate.

                Also note that this object is capable of correctly flipping the contents
                of arrays when the arrays are declared on the stack.  e.g.  You can
                say things like:
                int array[10];
                bo.host_to_network(array);
        !*/

    public:

        byte_orderer (
        );
        /*!
            ensures
                - #*this is properly initialized
            throws
                - std::bad_alloc
        !*/

        virtual ~byte_orderer (
        );
        /*!
            ensures
                - any resources associated with *this have been released
        !*/

        bool host_is_big_endian (
        ) const;
        /*!
            ensures
                - if (the host computer is a big endian machine) then
                    - returns true
                - else
                    - returns false
        !*/

        bool host_is_little_endian (
        ) const;
        /*!
            ensures
                - if (the host computer is a little endian machine) then
                    - returns true
                - else
                    - returns false
        !*/

        template <
            typename T
            >
        void host_to_network (
            T& item
        ) const;
        /*!
            ensures
                - #item == the value of item converted from host byte order
                  to network byte order.
        !*/

        template <
            typename T
            >
        void network_to_host (
            T& item
        ) const;
        /*!
            ensures
                - #item == the value of item converted from network byte order
                  to host byte order.
        !*/

        template <
            typename T
            >
        void host_to_big (
            T& item
        ) const;
        /*!
            ensures
                - #item == the value of item converted from host byte order
                  to big endian byte order.
        !*/

        template <
            typename T
            >
        void big_to_host (
            T& item
        ) const;
        /*!
            ensures
                - #item == the value of item converted from big endian byte order
                  to host byte order.
        !*/

        template <
            typename T
            >
        void host_to_little (
            T& item
        ) const;
        /*!
            ensures
                - #item == the value of item converted from host byte order
                  to little endian byte order.
        !*/

        template <
            typename T
            >
        void little_to_host (
            T& item
        ) const;
        /*!
            ensures
                - #item == the value of item converted from little endian byte order
                  to host byte order.
        !*/

    };
}

#endif // DLIB_BYTE_ORDEREr_ABSTRACT_


dlib C++ Library - console_progress_indicator.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_CONSOLE_PROGRESS_INDiCATOR_Hh_
#define DLIB_CONSOLE_PROGRESS_INDiCATOR_Hh_

#include <ctime>
#include <cmath>
#include <limits>
#include <iostream>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class console_progress_indicator
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is a tool for reporting how long a task will take
                to complete.

                For example, consider the following bit of code:

                    console_progress_indicator pbar(100)
                    for (int i = 1; i <= 100; ++i)
                    {
                        pbar.print_status(i);
                        long_running_operation();
                    }

                The above code will print a message to the console each iteration
                which shows how much time is remaining until the loop terminates.
        !*/

    public:

        inline explicit console_progress_indicator (
            double target_value
        );
        /*!
            ensures
                - #target() == target_value
        !*/

        inline void reset (
            double target_value
        );
        /*!
            ensures
                - #target() == target_value
                - performs the equivalent of:
                    *this = console_progress_indicator(target_value)
                    (i.e. resets this object with a new target value)

        !*/

        inline double target (
        ) const;
        /*!
            ensures
                - This object attempts to measure how much time is
                  left until we reach a certain targeted value.  This
                  function returns that targeted value.
        !*/

        inline bool print_status (
            double cur
        );
        /*!
            ensures
                - print_status() assumes it is called with values which are linearly
                  approaching target().  It will attempt to predict how much time is
                  remaining until cur becomes equal to target().
                - prints a status message to the screen which indicates how much
                  more time is left until cur is equal to target()
                - This function throttles the printing so that at most 1 message is printed
                  each second.  Note that it won't print anything to the screen until about
                  one second has elapsed.  This means that the first call to print_status()
                  never prints to the screen.
                - This function returns true if it prints to the screen and false
                  otherwise.
        !*/

    private:

        double target_val;

        time_t start_time;
        double first_val;
        double seen_first_val;
        time_t last_time;

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                               IMPLEMENTATION DETAILS
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    console_progress_indicator::
    console_progress_indicator (
        double target_value
    ) :
        target_val(target_value),
        start_time(0),
        first_val(0),
        seen_first_val(false),
        last_time(0)
    {
    }

// ----------------------------------------------------------------------------------------

    bool console_progress_indicator::
    print_status (
        double cur
    )
    {
        const time_t cur_time = std::time(0);

        // if this is the first time print_status has been called
        // then collect some information and exit.  We will print status
        // on the next call.
        if (!seen_first_val)
        {
            start_time = cur_time;
            last_time = cur_time;
            first_val = cur;
            seen_first_val = true;
            return false;
        }

        if (cur_time != last_time)
        {
            last_time = cur_time;
            double delta_t = static_cast<double>(cur_time - start_time);
            double delta_val = std::abs(cur - first_val);

            // don't do anything if cur is equal to first_val
            if (delta_val < std::numeric_limits<double>::epsilon())
                return false;

            double seconds = delta_t/delta_val * std::abs(target_val - cur);

            std::ios::fmtflags oldflags = std::cout.flags();
            std::cout.flags();
            std::cout.setf(std::ios::fixed,std::ios::floatfield);
            std::streamsize ss;

            if (seconds < 60)
            {
                ss = std::cout.precision(0);
                std::cout << "Time remaining: " << seconds << " seconds.                        \r" << std::flush;
            }
            else if (seconds < 60*60)
            {
                ss = std::cout.precision(2);
                std::cout << "Time remaining: " << seconds/60 << " minutes.                        \r" << std::flush;
            }
            else
            {
                ss = std::cout.precision(2);
                std::cout << "Time remaining: " << seconds/60/60 << " hours.                        \r" << std::flush;
            }

            // restore previous output flags and precision settings
            std::cout.flags(oldflags);
            std::cout.precision(ss);

            return true;
        }

        return false;
    }

// ----------------------------------------------------------------------------------------

    double console_progress_indicator::
    target (
    ) const
    {
        return target_val;
    }

// ----------------------------------------------------------------------------------------

    void console_progress_indicator::
    reset (
        double target_value
    )
    {
        *this = console_progress_indicator(target_value);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_CONSOLE_PROGRESS_INDiCATOR_Hh_


dlib C++ Library - error.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ERROr_
#define DLIB_ERROr_

#include <string>
#include <new>          // for std::bad_alloc
#include <iostream>
#include <cassert>
#include <cstdlib>
#include <exception>

// -------------------------------
// ------ exception classes ------
// -------------------------------

namespace dlib
{

// ----------------------------------------------------------------------------------------

    enum error_type
    {
        EPORT_IN_USE,
        ETIMEOUT,
        ECONNECTION,
        ELISTENER,
        ERESOLVE,
        EMONITOR,
        ECREATE_THREAD,
        ECREATE_MUTEX,
        ECREATE_SIGNALER,
        EUNSPECIFIED,
        EGENERAL_TYPE1,
        EGENERAL_TYPE2,
        EGENERAL_TYPE3,
        EINVALID_OPTION,
        ETOO_FEW_ARGS,
        ETOO_MANY_ARGS,
        ESOCKET,
        ETHREAD,
        EGUI,
        EFATAL,
        EBROKEN_ASSERT,
        EIMAGE_LOAD,
        EDIR_CREATE,
        EINCOMPATIBLE_OPTIONS,
        EMISSING_REQUIRED_OPTION,
        EINVALID_OPTION_ARG,
        EMULTIPLE_OCCURANCES,
        ECONFIG_READER,
        EIMAGE_SAVE,
        ECAST_TO_STRING,
        ESTRING_CAST,
        EUTF8_TO_UTF32,
        EOPTION_PARSE
    };

// ----------------------------------------------------------------------------------------

    // the base exception class
    class error : public std::exception
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is the base exception class for the dlib library.  i.e. all
                exceptions in this library inherit from this class.
        !*/

    public:
        error(
            error_type t,
            const std::string& a
        ): info(a), type(t) {}
        /*!
            ensures
                - #type == t
                - #info == a
        !*/

        error(
            error_type t
        ): type(t) {}
        /*!
            ensures
                - #type == t
                - #info == ""
        !*/

        error(
            const std::string& a
        ): info(a), type(EUNSPECIFIED) {}
        /*!
            ensures
                - #type == EUNSPECIFIED
                - #info == a
        !*/

        error(
        ): type(EUNSPECIFIED) {}
        /*!
            ensures
                - #type == EUNSPECIFIED
                - #info == ""
        !*/

        virtual ~error(
        ) throw() {}
        /*!
            ensures
                - does nothing
        !*/

        const char* what(
        ) const throw()
        /*!
            ensures
                - if (info.size() != 0) then
                    - returns info.c_str()
                - else
                    - returns type_to_string(type)
        !*/
        {
            if (info.size() > 0)
                return info.c_str();
            else
                return type_to_string();
        }

        const char* type_to_string (
        ) const throw()
        /*!
            ensures
                - returns a string that names the contents of the type member.
        !*/
        {
            if ( type == EPORT_IN_USE) return "EPORT_IN_USE";
            else if ( type == ETIMEOUT) return "ETIMEOUT";
            else if ( type == ECONNECTION) return "ECONNECTION";
            else if ( type == ELISTENER) return "ELISTENER";
            else if ( type == ERESOLVE) return "ERESOLVE";
            else if ( type == EMONITOR) return "EMONITOR";
            else if ( type == ECREATE_THREAD) return "ECREATE_THREAD";
            else if ( type == ECREATE_MUTEX) return "ECREATE_MUTEX";
            else if ( type == ECREATE_SIGNALER) return "ECREATE_SIGNALER";
            else if ( type == EUNSPECIFIED) return "EUNSPECIFIED";
            else if ( type == EGENERAL_TYPE1) return "EGENERAL_TYPE1";
            else if ( type == EGENERAL_TYPE2) return "EGENERAL_TYPE2";
            else if ( type == EGENERAL_TYPE3) return "EGENERAL_TYPE3";
            else if ( type == EINVALID_OPTION) return "EINVALID_OPTION";
            else if ( type == ETOO_FEW_ARGS) return "ETOO_FEW_ARGS";
            else if ( type == ETOO_MANY_ARGS) return "ETOO_MANY_ARGS";
            else if ( type == ESOCKET) return "ESOCKET";
            else if ( type == ETHREAD) return "ETHREAD";
            else if ( type == EGUI) return "EGUI";
            else if ( type == EFATAL) return "EFATAL";
            else if ( type == EBROKEN_ASSERT) return "EBROKEN_ASSERT";
            else if ( type == EIMAGE_LOAD) return "EIMAGE_LOAD";
            else if ( type == EDIR_CREATE) return "EDIR_CREATE";
            else if ( type == EINCOMPATIBLE_OPTIONS) return "EINCOMPATIBLE_OPTIONS";
            else if ( type == EMISSING_REQUIRED_OPTION) return "EMISSING_REQUIRED_OPTION";
            else if ( type == EINVALID_OPTION_ARG) return "EINVALID_OPTION_ARG";
            else if ( type == EMULTIPLE_OCCURANCES) return "EMULTIPLE_OCCURANCES";
            else if ( type == ECONFIG_READER) return "ECONFIG_READER";
            else if ( type == EIMAGE_SAVE) return "EIMAGE_SAVE";
            else if ( type == ECAST_TO_STRING) return "ECAST_TO_STRING";
            else if ( type == ESTRING_CAST) return "ESTRING_CAST";
            else if ( type == EUTF8_TO_UTF32) return "EUTF8_TO_UTF32";
            else if ( type == EOPTION_PARSE) return "EOPTION_PARSE";
            else return "undefined error type";
        }

        const std::string info;  // info about the error
        const error_type type; // the type of the error

    private:
        const error& operator=(const error&);
    };

// ----------------------------------------------------------------------------------------

    class fatal_error : public error
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                As the name says, this object represents some kind of fatal error.
                That is, it represents an unrecoverable error and any program that
                throws this exception is, by definition, buggy and needs to be fixed.

                Note that a fatal_error exception can only be thrown once.  The second
                time an application attempts to construct a fatal_error it will be
                immediately aborted and an error message will be printed to std::cerr.
                The reason for this is because the first fatal_error was apparently ignored
                so the second fatal_error is going to make itself impossible to ignore
                by calling abort.  The lesson here is that you should not try to ignore
                fatal errors.

                This is also the exception thrown by the DLIB_ASSERT and DLIB_CASSERT macros.
        !*/

    public:
        fatal_error(
            error_type t,
            const std::string& a
        ): error(t,a) {check_for_previous_fatal_errors();}
        /*!
            ensures
                - #type == t
                - #info == a
        !*/

        fatal_error(
            error_type t
        ): error(t) {check_for_previous_fatal_errors();}
        /*!
            ensures
                - #type == t
                - #info == ""
        !*/

        fatal_error(
            const std::string& a
        ): error(EFATAL,a) {check_for_previous_fatal_errors();}
        /*!
            ensures
                - #type == EFATAL
                - #info == a
        !*/

        fatal_error(
        ): error(EFATAL) {check_for_previous_fatal_errors();}
        /*!
            ensures
                - #type == EFATAL
                - #info == ""
        !*/

    private:

        static inline char* message ()
        {
            static char buf[2000];
            buf[1999] = '\0'; // just to be extra safe
            return buf;
        }

        static inline void dlib_fatal_error_terminate (
        )
        {
            std::cerr << "\n**************************** FATAL ERROR DETECTED ****************************";
            std::cerr << message() << std::endl;
            std::cerr << "******************************************************************************\n" << std::endl;
        }

        void check_for_previous_fatal_errors()
        {
            static bool is_first_fatal_error = true;
            if (is_first_fatal_error == false)
            {
                std::cerr << "\n\n ************************** FATAL ERROR DETECTED ************************** " << std::endl;
                std::cerr << " ************************** FATAL ERROR DETECTED ************************** " << std::endl;
                std::cerr << " ************************** FATAL ERROR DETECTED ************************** \n" << std::endl;
                std::cerr << "Two fatal errors have been detected, the first was inappropriately ignored. \n"
                          << "To prevent further fatal errors from being ignored this application will be \n"
                          << "terminated immediately and you should go fix this buggy program.\n\n"
                          << "The error message from this fatal error was:\n" << this->what() << "\n\n" << std::endl;
                using namespace std;
                assert(false);
                abort();
            }
            else
            {
                // copy the message into the fixed message buffer so that it can be recalled by dlib_fatal_error_terminate
                // if needed.
                char* msg = message();
                unsigned long i;
                for (i = 0; i < 2000-1 && i < this->info.size(); ++i)
                    msg[i] = info[i];
                msg[i] = '\0';

                // set this termination handler so that if the user doesn't catch this dlib::fatal_error that is being
                // thrown then it will eventually be printed to standard error
                std::set_terminate(&dlib_fatal_error_terminate);
            }
            is_first_fatal_error = false;
        }
    };

// ----------------------------------------------------------------------------------------

    class gui_error : public error
    {
    public:
        gui_error(
            error_type t,
            const std::string& a
        ): error(t,a) {}
        /*!
            ensures
                - #type == t
                - #info == a
        !*/

        gui_error(
            error_type t
        ): error(t) {}
        /*!
            ensures
                - #type == t
                - #info == ""
        !*/

        gui_error(
            const std::string& a
        ): error(EGUI,a) {}
        /*!
            ensures
                - #type == EGUI
                - #info == a
        !*/

        gui_error(
        ): error(EGUI) {}
        /*!
            ensures
                - #type == EGUI
                - #info == ""
        !*/
    };

// ----------------------------------------------------------------------------------------

    class socket_error : public error
    {
    public:
        socket_error(
            error_type t,
            const std::string& a
        ): error(t,a) {}
        /*!
            ensures
                - #type == t
                - #info == a
        !*/

        socket_error(
            error_type t
        ): error(t) {}
        /*!
            ensures
                - #type == t
                - #info == ""
        !*/

        socket_error(
            const std::string& a
        ): error(ESOCKET,a) {}
        /*!
            ensures
                - #type == ESOCKET
                - #info == a
        !*/

        socket_error(
        ): error(ESOCKET) {}
        /*!
            ensures
                - #type == ESOCKET
                - #info == ""
        !*/
    };

// ----------------------------------------------------------------------------------------

    class thread_error : public error
    {
    public:
        thread_error(
            error_type t,
            const std::string& a
        ): error(t,a) {}
        /*!
            ensures
                - #type == t
                - #info == a
        !*/

        thread_error(
            error_type t
        ): error(t) {}
        /*!
            ensures
                - #type == t
                - #info == ""
        !*/

        thread_error(
            const std::string& a
        ): error(ETHREAD,a) {}
        /*!
            ensures
                - #type == ETHREAD
                - #info == a
        !*/

        thread_error(
        ): error(ETHREAD) {}
        /*!
            ensures
                - #type == ETHREAD
                - #info == ""
        !*/
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_ERROr_


dlib C++ Library - logger_kernel_abstract.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_LOGGER_KERNEl_ABSTRACT_
#ifdef DLIB_LOGGER_KERNEl_ABSTRACT_

#include "../threads.h"
#include <limits>
#include <string>
#include <iostream>
#include "../uintn.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class log_level
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is a simple named level to log at.  It contains a numeric
                priority and a name to use in the logging messages.
        !*/
    public:
        log_level(
            int priority_,
            const char* name_
        );
        /*!
            ensures
                - #priority = priority_
                - the first 19 characters of name_ are copied into name and name
                  is null terminated.
        !*/

        bool operator< (const log_level& rhs) const { return priority <  rhs.priority; }
        bool operator<=(const log_level& rhs) const { return priority <= rhs.priority; }
        bool operator> (const log_level& rhs) const { return priority >  rhs.priority; }
        bool operator>=(const log_level& rhs) const { return priority >= rhs.priority; }

        int priority;
        char name[20];
    };

    inline std::ostream& operator<< (std::ostream& out, const log_level& item);
    /*!
        ensures
            - performs out << item.name
            - returns out
    !*/

// ----------------------------------------------------------------------------------------

    const log_level LALL  (std::numeric_limits<int>::min(),"ALL");
    const log_level LNONE (std::numeric_limits<int>::max(),"NONE");
    const log_level LTRACE(-100,"TRACE");
    const log_level LDEBUG(0   ,"DEBUG");
    const log_level LINFO (100 ,"INFO ");
    const log_level LWARN (200 ,"WARN ");
    const log_level LERROR(300 ,"ERROR");
    const log_level LFATAL(400 ,"FATAL");

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    void set_all_logging_output_streams (
        std::ostream& out
    );
    /*!
        ensures
            - for all loggers L (even loggers not yet constructed):
                - #L.output_streambuf() == out.rdbuf()
                - Removes any previous output hook from L.  So now the logger
                  L will write all its messages to the given output stream.
        throws
            - std::bad_alloc
    !*/

// ----------------------------------------------------------------------------------------

    typedef void (*print_header_type)(
        std::ostream& out,
        const std::string& logger_name,
        const log_level& l,
        const uint64 thread_id
    );

    void set_all_logging_headers (
        const print_header_type& new_header
    );
    /*!
        ensures
            - for all loggers L (even loggers not yet constructed):
                - #L.logger_header() == new_header
        throws
            - std::bad_alloc
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    void set_all_logging_output_hooks (
        T& object,
        void (T::*hook)(const std::string& logger_name,
                        const log_level& l,
                        const uint64 thread_id,
                        const char* message_to_log)
    );
    /*!
        ensures
            - for all loggers L (even loggers not yet constructed):
                - #L.output_streambuf() == 0
                - performs the equivalent to calling L.set_output_hook(object, hook);
                  (i.e. sets all loggers so that they will use the given hook function)
        throws
            - std::bad_alloc
    !*/

    template <
        typename T
        >
    void set_all_logging_output_hooks (
        T& object
    );
    /*!
        ensures
            - calls set_all_logging_output_hooks(object, &T::log);
    !*/

// ----------------------------------------------------------------------------------------

    void set_all_logging_levels (
        const log_level& new_level
    );
    /*!
        ensures
            - for all loggers L (even loggers not yet constructed):
                - #L.level() == new_level
        throws
            - std::bad_alloc
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    void print_default_logger_header (
        std::ostream& out,
        const std::string& logger_name,
        const log_level& l,
        const uint64 thread_id
    );
    /*!
        requires
            - is not called more than once at a time (i.e. is not called from multiple
              threads at the same time).
        ensures
            - let MS be the number of milliseconds since program start.
            - prints a string to out in the form:  "MS l.name [thread_id] logger_name:"
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class logger
    {
        /*!
            INITIAL VALUE
                - name() == a user supplied value given to the constructor
                - The values of level(), output_streambuf(), logger_header(), and
                  auto_flush() are inherited from the parent of this logger.

            WHAT THIS OBJECT REPRESENTS
                This object represents a logging output stream in the style of the log4j
                logger available for Java.

                Additionally, the logger doesn't perform any memory allocations during
                each logging action.  It just writes directly into the user supplied output
                stream.  Alternatively, if you use a logging output hook no memory allocations
                are performed either.  Logging just goes straight into a memory buffer
                which gets passed to the user supplied logging hook.

            DEFAULTS
                If the user hasn't specified values for the four inherited values level(),
                output_streambuf(), logger_header(), or auto_flush() then the default
                values will be used.  The defaults are as follows:
                - level() == LERROR
                - output_streambuf() == std::cout.rdbuf() (i.e. the default is to log
                  to standard output).
                - logger_header() == print_default_logger_header
                - auto_flush() == true

            THREAD SAFETY
                All methods of this class are thread safe.  Note that it is safe to
                chain calls to operator << such as:
                    log << LINFO << "message " << variable << " more message";
                The logger ensures that the entire statement executes atomically so the
                message won't be broken up by other loggers in other threads.
        !*/

        class logger_stream
        {
        public:

            bool is_enabled (
            ) const;
            /*!
                ensures
                    - returns true if this logger stream will print out items
                      given to it by the << operator.  returns false otherwise.
            !*/

            template <typename T>
            logger_stream& operator << (
                const T& item
            );
            /*!
                ensures
                    - if (is_enabled()) then
                        - writes item to this output stream
                    - returns *this
            !*/
        };

    public:

        logger (
            const std::string& name_
        );
        /*!
            requires
                - name_ != ""
            ensures
                - #*this is properly initialized
                - #name() == name_
            throws
                - std::bad_alloc
                - dlib::thread_error
        !*/

        virtual ~logger (
        );
        /*!
            ensures
                - any resources associated with *this have been released
        !*/

        const std::string& name (
        ) const;
        /*!
            ensures
                - returns the name of this logger
        !*/

        logger_stream operator << (
            const log_level& l
        ) const;
        /*!
            ensures
                - if (l.priority >= level().priority) then
                    - returns a logger_stream with is_enabled() == true.  I.e. this
                      returned stream will write its output to the I/O destination
                      used by this logger object.
                - else
                    - returns a logger stream with is_enabled() == false
            throws
                - std::bad_alloc
        !*/

        bool is_child_of (
            const logger& log
        ) const;
        /*!
            ensures
                - if ( (name().find(log.name() + ".") == 0) || (log.name() == name()) ) then
                    - returns true
                      (i.e. if log.name() + "." is a prefix of name() or if both *this and log
                      have the same name then return true)
                - else
                    - returns false
        !*/

        const log_level level (
        ) const;
        /*!
            ensures
                - returns the current log level of this logger.
        !*/

        void set_level (
            const log_level& new_level
        );
        /*!
            ensures
                - for all loggers L such that L.is_child_of(*this) == true:
                    - #L.level() == new_level
            throws
                - std::bad_alloc
        !*/

        bool auto_flush (
        );
        /*!
            ensures
                - returns true if the output stream is flushed after every logged message.
                  returns false otherwise.  (Note that flushing only does anything if
                  the logger is set to use an output stream rather than a hook)
        !*/

        void set_auto_flush (
            bool enabled
        );
        /*!
            ensures
                - for all loggers L such that L.is_child_of(*this) == true:
                    - #L.auto_flush() == enabled
            throws
                - std::bad_alloc
        !*/

        template <
            typename T
            >
        void set_output_hook (
            T& object,
            void (T::*hook)(const std::string& logger_name,
                            const log_level& l,
                            const uint64 thread_id,
                            const char* message_to_log)
        );
        /*!
            requires
                - hook is a valid pointer to a member function in T
            ensures
                - for all loggers L such that L.is_child_of(*this) == true:
                    - #L.output_streambuf() == 0
                    - #L will not send its log messages to an ostream object anymore.  Instead
                      it will call the given hook member function (i.e. (object.*hook)(name,l,id,msg) )
                      for each message that needs to be logged.
                    - The arguments to the hook function have the following meanings:
                        - logger_name == The name of the logger that is printing the log message.
                        - l == The level of the logger that is printing the log message.
                        - thread_id == A number that uniquely identifies the thread trying to log
                          the message.  Note that this number is unique among all threads, past and
                          present.  Also note that this id is not the same one returned by
                          get_thread_id().
                        - message_to_log == the actual text of the message the user is giving to
                          the logger object to log.
                    - All hook functions will also only be called one at a time. This means
                      that hook functions don't need to be thread safe.
        !*/

        std::streambuf* output_streambuf (
        );
        /*!
            ensures
                - if (an output hook isn't set) then
                    - returns the output stream buffer that this logger writes all
                      messages to.
                - else
                    - returns 0
        !*/

        void set_output_stream (
            std::ostream& out
        );
        /*!
            ensures
                - for all loggers L such that L.is_child_of(*this) == true:
                    - #L.output_streambuf() == out.rdbuf()
                    - Removes any previous output hook from L.  So now the logger
                      L will write all its messages to the given output stream.
            throws
                - std::bad_alloc
        !*/

        print_header_type logger_header (
        ) const;
        /*!
            ensures
                - returns the function that is called to print the header information
                  onto each logged message.  The arguments to the function have the following
                  meanings:
                    - out == The output stream this function writes the header to.
                    - logger_name == The name of the logger that is printing the log message.
                    - l == The level of the logger that is printing the log message.
                    - thread_id == A number that uniquely identifies the thread trying to log
                      the message.  Note that this number is unique among all threads, past and
                      present.  Also note that this id is not the same one returned by
                      get_thread_id().
                - This logger_header function will also only be called once at a time. This means
                  the logger_header function doesn't need to be thread safe.
                - the logger_header function is only used when output_streambuf() != 0
        !*/

        void set_logger_header (
            print_header_type print_header
        );
        /*!
            ensures
                - for all loggers L such that L.is_child_of(*this) == true:
                    - #L.logger_header() == print_header
            throws
                - std::bad_alloc
        !*/

    private:

        // restricted functions
        logger(const logger&);        // copy constructor
        logger& operator=(const logger&);    // assignment operator

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

}

#endif // DLIB_LOGGER_KERNEl_ABSTRACT_


dlib C++ Library - extra_logger_headers.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_EXTRA_LOGGER_HEADERs_
#define DLIB_EXTRA_LOGGER_HEADERs_

#include "logger_kernel_abstract.h"
#include "logger_kernel_1.h"
#include <iostream>
#include <string>
#include "../uintn.h"

// ----------------------------------------------------------------------------------------

namespace dlib
{

    void print_datetime_logger_header (
        std::ostream& out,
        const std::string& logger_name,
        const log_level& l,
        const uint64 thread_id
    );
    /*!
        requires
            - is not called more than once at a time (i.e. is not called from multiple
              threads at the same time).
        ensures
            - let DATE be the current date and time (e.g. Thu Aug 31 16:41:52 2006).
            - prints a string to out in the form:  "l.name (DATE) [thread_id] logger_name:"
    !*/

}

// ----------------------------------------------------------------------------------------

#ifdef NO_MAKEFILE
#include "extra_logger_headers.cpp"
#endif

#endif // DLIB_EXTRA_LOGGER_HEADERs_


dlib C++ Library - logger_config_file.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_LOGGER_CONFIg_FILE_
#define DLIB_LOGGER_CONFIg_FILE_

#include "logger_kernel_abstract.h"
#include "logger_kernel_1.h"
#include <string>
#include "../config_reader.h"

// ----------------------------------------------------------------------------------------

namespace dlib
{
    class logger_config_file_error : public error
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is the exception class used by the configure_loggers_from_file()
                function defined below.
        !*/
    public:
        logger_config_file_error(const std::string& s):error(s){}
    };

    void configure_loggers_from_file (
        const std::string& file_name
    );
    /*!
        ensures
            - configures the loggers with the contents of the file_name file
        throws
            - dlib::logger_config_file_error
                this exception is thrown if there is a problem reading the config file
    !*/

    void configure_loggers_from_file (
        const config_reader& cr
    );
    /*!
        ensures
            - configures the loggers with the contents of cr.  This function is just like
              the above version that reads from a file except that it reads from an in-memory
              config_reader instead.
        throws
            - dlib::logger_config_file_error
                this exception is thrown if there is a problem reading the config file
    !*/

// ----------------------------------------------------------------------------------------

    /*!
        #  -----------------------------------------------
        #  ------------- EXAMPLE CONFIG FILE -------------
        #  -----------------------------------------------

        # The overall format of the config file is the same as the one defined by
        # the config_reader component of this library.

        # This line is a comment line

        # The config file always has a block named logger_config.  This is where all the
        # config data for the loggers reside.
        logger_config
        {
            # This sets all loggers to the level LINFO since it is just inside the
            # logger_config block
            logging_level = info

            # Alternatively we could specify a user defined logging level by
            # supplying a priority number.  The following line would specify
            # that only logging levels at or above 100 are printed.  (note that
            # you would have to comment out the logging_level statement above
            # to avoid a conflict).
            # logging_level = 100

            parent_logger
            {
                # This sets all loggers named "parent_logger" or children of
                # loggers with that name to not log at all (i.e. to logging level
                # LNONE).
                logging_level = none
            }

            parent_logger2
            {
                # set loggers named "parent_logger2" and its children loggers
                # to write their output to a file named out.txt
                output = file out.txt

                child_logger
                {
                    # Set loggers named "parent_logger2.child_logger" and children of loggers
                    # with this name to logging level LALL
                    logging_level = all

                    # Note that this logger will also log to out.txt because that is what
                    # its parent does and we haven't overridden it here with something else.
                    # if we wanted this logger to write to cout instead we could uncomment
                    # the following line:
                    # output = cout
                }
            }
        }

        # So in summary, all logger config stuff goes inside a block named logger_config.  Then
        # inside that block all blocks must be the names of loggers.  There are only two keys,
        # logging_level and output.
        #
        # The valid values of logging_level are:
        #   "LALL", "LNONE", "LTRACE", "LDEBUG", "LINFO", "LWARN", "LERROR", "LFATAL",
        #   "ALL",   "NONE",  "TRACE",  "DEBUG",  "INFO",  "WARN",  "ERROR",  "FATAL",
        #   "all",   "none",  "trace",  "debug",  "info",  "warn",  "error",  "fatal", or
        #   any integral value
        #
        # The valid values of output are:
        #   "cout", "cerr", "clog", or a string of the form "file some_file_name"
        #   which causes the output to be logged to the specified file.
        #
    !*/

}

// ----------------------------------------------------------------------------------------

#ifdef NO_MAKEFILE
#include "logger_config_file.cpp"
#endif

#endif // DLIB_LOGGER_CONFIg_FILE_


dlib C++ Library - member_function_pointer_kernel_abstract.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_MEMBER_FUNCTION_POINTER_KERNEl_ABSTRACT_
#ifdef DLIB_MEMBER_FUNCTION_POINTER_KERNEl_ABSTRACT_

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename PARAM1 = void,
        typename PARAM2 = void,
        typename PARAM3 = void,
        typename PARAM4 = void
        >
    class member_function_pointer;

// ----------------------------------------------------------------------------------------

    template <>
    class member_function_pointer<void,void,void,void>
    {
        /*!
            INITIAL VALUE
                is_set() == false

            WHAT THIS OBJECT REPRESENTS
                This object represents a member function pointer.  It is useful because
                instances of this object can be created without needing to know the type
                of object whose member function we will be calling.

                There are five template specializations of this object.  The first
                represents a pointer to a member function taking no parameters, the
                second represents a pointer to a member function taking one parameter,
                the third to one taking two parameters, and so on.

                You specify the parameters to your member function pointer by filling in
                the PARAM template parameters.  For example:

                    To use a pointer to a function with no parameters you would say:
                        member_function_pointer<> my_pointer;
                    To use a pointer to a function that takes a single int you would say:
                        member_function_pointer<int> my_pointer;
                    To use a pointer to a function that takes an int and then a reference
                    to a string you would say:
                        member_function_pointer<int,string&> my_pointer;

                Also note that the formal comments are only present for the first
                template specialization.  They are all exactly the same except for the
                number of parameters each takes in its member function pointer.
        !*/

    public:
        typedef void param1_type;
        typedef void param2_type;
        typedef void param3_type;
        typedef void param4_type;

        member_function_pointer (
        );
        /*!
            ensures
                - #*this is properly initialized
        !*/

        member_function_pointer(
            const member_function_pointer& item
        );
        /*!
            ensures
                - *this == item
        !*/

        ~member_function_pointer (
        );
        /*!
            ensures
                - any resources associated with *this have been released
        !*/

        member_function_pointer& operator=(
            const member_function_pointer& item
        );
        /*!
            ensures
                - *this == item
        !*/

        bool operator == (
            const member_function_pointer& item
        ) const;
        /*!
            ensures
                - if (is_set() == false && item.is_set() == false) then
                    - returns true
                - else if (both *this and item point to the same member function
                  in the same object instance) then
                    - returns true
                - else
                    - returns false
        !*/

        bool operator != (
            const member_function_pointer& item
        ) const;
        /*!
            ensures
                - returns !(*this == item)
        !*/

        void clear(
        );
        /*!
            ensures
                - #*this has its initial value
        !*/

        bool is_set (
        ) const;
        /*!
            ensures
                - if (this->set() has been called) then
                    - returns true
                - else
                    - returns false
        !*/

        template <
            typename T
            >
        void set (
            T& object,
            void (T::*cb)()
        );
        /*!
            requires
                - cb == a valid member function pointer for class T
            ensures
                - #is_set() == true
                - calls to this->operator() will call (object.*cb)()
        !*/

        template <
            typename T
            >
        void set (
            const T& object,
            void (T::*cb)()const
        );
        /*!
            requires
                - cb == a valid member function pointer for class T
            ensures
                - #is_set() == true
                - calls to this->operator() will call (object.*cb)()
        !*/

        operator some_undefined_pointer_type (
        ) const;
        /*!
            ensures
                - if (is_set()) then
                    - returns a non 0 value
                - else
                    - returns a 0 value
        !*/

        bool operator! (
        ) const;
        /*!
            ensures
                - returns !is_set()
        !*/

        void operator () (
        ) const;
        /*!
            requires
                - is_set() == true
            ensures
                - calls the member function on the object specified by the last
                  call to this->set()
            throws
                - any exception thrown by the member function specified by
                  the previous call to this->set().
                    If any of these exceptions are thrown then the call to this
                    function will have no effect on *this.
        !*/

        void swap (
            member_function_pointer& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <
        typename PARAM1
        >
    class member_function_pointer<PARAM1,void,void,void>
    {
    public:
        typedef PARAM1 param1_type;
        typedef void param2_type;
        typedef void param3_type;
        typedef void param4_type;

        member_function_pointer ();

        member_function_pointer(
            const member_function_pointer& item
        );

        ~member_function_pointer (
        );

        member_function_pointer& operator=(
            const member_function_pointer& item
        );

        bool operator == (
            const member_function_pointer& item
        ) const;

        bool operator != (
            const member_function_pointer& item
        ) const;

        void clear();

        bool is_set () const;

        template <typename T>
        void set (
            T& object,
            void (T::*cb)(PARAM1)
        );

        template <typename T>
        void set (
            const T& object,
            void (T::*cb)(PARAM1)const
        );

        operator some_undefined_pointer_type (
        ) const;

        bool operator! (
        ) const;

        void operator () (
            PARAM1 param1
        ) const;

        void swap (
            member_function_pointer& item
        );

    };

// ----------------------------------------------------------------------------------------

    template <
        typename PARAM1,
        typename PARAM2
        >
    class member_function_pointer<PARAM1,PARAM2,void,void>
    {
    public:
        typedef PARAM1 param1_type;
        typedef PARAM2 param2_type;
        typedef void param3_type;
        typedef void param4_type;

        member_function_pointer ();

        member_function_pointer(
            const member_function_pointer& item
        );

        ~member_function_pointer (
        );

        member_function_pointer& operator=(
            const member_function_pointer& item
        );

        bool operator == (
            const member_function_pointer& item
        ) const;

        bool operator != (
            const member_function_pointer& item
        ) const;

        void clear();

        bool is_set () const;

        template <typename T>
        void set (
            T& object,
            void (T::*cb)(PARAM1,PARAM2)
        );

        template <typename T>
        void set (
            const T& object,
            void (T::*cb)(PARAM1,PARAM2)const
        );

        operator some_undefined_pointer_type (
        ) const;

        bool operator! (
        ) const;

        void operator () (
            PARAM1 param1,
            PARAM2 param2
        ) const;

        void swap (
            member_function_pointer& item
        );

    };

// ----------------------------------------------------------------------------------------

    template <
        typename PARAM1,
        typename PARAM2,
        typename PARAM3
        >
    class member_function_pointer<PARAM1,PARAM2,PARAM3,void>
    {
    public:
        typedef PARAM1 param1_type;
        typedef PARAM2 param2_type;
        typedef PARAM3 param3_type;
        typedef void param4_type;

        member_function_pointer ();

        member_function_pointer(
            const member_function_pointer& item
        );

        ~member_function_pointer (
        );

        member_function_pointer& operator=(
            const member_function_pointer& item
        );

        bool operator == (
            const member_function_pointer& item
        ) const;

        bool operator != (
            const member_function_pointer& item
        ) const;

        void clear();

        bool is_set () const;

        template <typename T>
        void set (
            T& object,
            void (T::*cb)(PARAM1,PARAM2,PARAM3)
        );

        template <typename T>
        void set (
            const T& object,
            void (T::*cb)(PARAM1,PARAM2,PARAM3)const
        );

        operator some_undefined_pointer_type (
        ) const;

        bool operator! (
        ) const;

        void operator () (
            PARAM1 param1,
            PARAM2 param2,
            PARAM2 param3
        ) const;

        void swap (
            member_function_pointer& item
        );

    };

// ----------------------------------------------------------------------------------------

    template <
        typename PARAM1,
        typename PARAM2,
        typename PARAM3,
        typename PARAM4
        >
    class member_function_pointer
    {
    public:
        typedef PARAM1 param1_type;
        typedef PARAM2 param2_type;
        typedef PARAM3 param3_type;
        typedef PARAM4 param4_type;

        member_function_pointer ();

        member_function_pointer(
            const member_function_pointer& item
        );

        ~member_function_pointer (
        );

        member_function_pointer& operator=(
            const member_function_pointer& item
        );

        bool operator == (
            const member_function_pointer& item
        ) const;

        bool operator != (
            const member_function_pointer& item
        ) const;

        void clear();

        bool is_set () const;

        template <typename T>
        void set (
            T& object,
            void (T::*cb)(PARAM1,PARAM2,PARAM3,PARAM4)
        );

        template <typename T>
        void set (
            const T& object,
            void (T::*cb)(PARAM1,PARAM2,PARAM3,PARAM4)const
        );

        operator some_undefined_pointer_type (
        ) const;

        bool operator! (
        ) const;

        void operator () (
            PARAM1 param1,
            PARAM2 param2,
            PARAM2 param3,
            PARAM2 param4
        ) const;

        void swap (
            member_function_pointer& item
        );

    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MEMBER_FUNCTION_POINTER_KERNEl_ABSTRACT_


dlib C++ Library - memory_manager_kernel_abstract.h

// Copyright (C) 2004  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_MEMORY_MANAGER_KERNEl_ABSTRACT_
#ifdef DLIB_MEMORY_MANAGER_KERNEl_ABSTRACT_

#include "../algs.h"

namespace dlib
{
    template <
        typename T
        >
    class memory_manager
    {
        /*!
            REQUIREMENTS ON T
                T must have a default constructor.

            INITIAL VALUE
                get_number_of_allocations() == 0

            WHAT THIS OBJECT REPRESENTS
                This object represents some kind of memory manager or memory pool.
        !*/

        public:

            typedef T type;

            template <typename U>
            struct rebind {
                typedef memory_manager<U> other;
            };

            memory_manager(
            );
            /*!
                ensures
                    - #*this is properly initialized
                throws
                    - std::bad_alloc
            !*/

            virtual ~memory_manager(
            );
            /*!
                ensures
                    - if (get_number_of_allocations() == 0) then
                        - all resources associated with *this have been released.
                    - else
                        - The memory still allocated will not be deleted and this
                          causes a memory leak.
            !*/

            unsigned long get_number_of_allocations (
            ) const;
            /*!
                ensures
                    - returns the current number of outstanding allocations
            !*/

            T* allocate (
            );
            /*!
                ensures
                    - allocates a new object of type T and returns a pointer to it.
                    - #get_number_of_allocations() == get_number_of_allocations() + 1
                throws
                    - std::bad_alloc or any exception thrown by T's constructor.
                        If this exception is thrown then the call to allocate()
                        has no effect on #*this.
            !*/

            void deallocate (
                T* item
            );
            /*!
                requires
                    - item == is a pointer to memory that was obtained from a call to
                      this->allocate(). (i.e. you can't deallocate a pointer you
                      got from a different memory_manager instance.)
                    - the memory pointed to by item hasn't already been deallocated.
                ensures
                    - deallocates the object pointed to by item
                    - #get_number_of_allocations() == get_number_of_allocations() - 1
            !*/

            T* allocate_array (
                unsigned long size
            );
            /*!
                ensures
                    - allocates a new array of size objects of type T and returns a
                      pointer to it.
                    - #get_number_of_allocations() == get_number_of_allocations() + 1
                throws
                    - std::bad_alloc or any exception thrown by T's constructor.
                        If this exception is thrown then the call to allocate()
                        has no effect on #*this.
            !*/

            void deallocate_array (
                T* item
            );
            /*!
                requires
                    - item == is a pointer to memory that was obtained from a call to
                      this->allocate_array(). (i.e. you can't deallocate a pointer you
                      got from a different memory_manager instance and it must be an
                      array.)
                    - the memory pointed to by item hasn't already been deallocated.
                ensures
                    - deallocates the array pointed to by item
                    - #get_number_of_allocations() == get_number_of_allocations() - 1
            !*/

            void swap (
                memory_manager& item
            );
            /*!
                ensures
                    - swaps *this and item
            !*/

        private:

            // restricted functions
            memory_manager(memory_manager&);        // copy constructor
            memory_manager& operator=(memory_manager&);    // assignment operator
    };

    template <
        typename T
        >
    inline void swap (
        memory_manager<T>& a,
        memory_manager<T>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

}

#endif // DLIB_MEMORY_MANAGER_KERNEl_ABSTRACT_


dlib C++ Library - memory_manager_global_kernel_abstract.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_MEMORY_MANAGER_GLOBAl_ABSTRACT_
#ifdef DLIB_MEMORY_MANAGER_GLOBAl_ABSTRACT_

#include "../algs.h"
#include "../memory_manager/memory_manager_kernel_abstract.h"

namespace dlib
{
    template <
        typename T,
        typename factory
        >
    class memory_manager_global
    {
        /*!
            REQUIREMENTS ON T
                T must have a default constructor.

            REQUIREMENTS ON factory
                factory must be defined as follows:
                struct factory
                {
                    template <typename U>
                    struct return_type {
                        typedef typename memory_manager_type<U> type;
                    };

                    template <typename U>
                    static typename return_type<U>::type* get_instance (
                    );
                    / *!
                        ensures
                            - returns a pointer to an instance of a memory_manager object
                              where memory_manager_type implements the interface defined
                              by dlib/memory_manager/memory_manager_kernel_abstract.h
                    !* /
                };

            WHAT THIS OBJECT REPRESENTS
                This object represents some kind of global memory manager or memory pool.
                It is identical to the memory_manager object except that it gets all of
                its allocations from a global instance of a memory_manager object which
                is provided by the factory object's static member get_instance().

            THREAD SAFETY
                This object is, by itself, threadsafe.  However, if you want to use this
                object in multiple threads then you must ensure that your factory is
                threadsafe.  This means its factory::get_instance() method should be
                threadsafe and the memory_manager object it returns must also be threadsafe.
        !*/

        public:

            typedef typename factory::template return_type<T>::type mm_global_type;

            typedef T type;

            template <typename U>
            struct rebind {
                typedef memory_manager_global<U,factory> other;
            };

            memory_manager_global(
            );
            /*!
                ensures
                    - #*this is properly initialized
                    - #get_global_memory_manager() == the memory manager that was
                      returned by a call to factory::get_instance<T>()
                throws
                    - std::bad_alloc
            !*/

            virtual ~memory_manager_global(
            );
            /*!
                ensures
                    - This destructor has no effect on the global memory_manager
                      get_global_memory_manager().
            !*/

            unsigned long get_number_of_allocations (
            ) const;
            /*!
                ensures
                    - returns get_global_memory_manager().get_number_of_allocations()
            !*/

            mm_global_type& get_global_memory_manager (
            );
            /*!
                ensures
                    - returns a reference to the global memory manager instance being
                      used by *this.
            !*/

            T* allocate (
            );
            /*!
                ensures
                    - #get_number_of_allocations() == get_number_of_allocations() + 1
                    - returns get_global_memory_manager().allocate()
                throws
                    - std::bad_alloc or any exception thrown by T's constructor.
                        If this exception is thrown then the call to allocate()
                        has no effect on #*this.
            !*/

            void deallocate (
                T* item
            );
            /*!
                requires
                    - item == is a pointer to memory that was obtained from a call to
                      the get_global_memory_manager() object's allocate() method.
                    - the memory pointed to by item hasn't already been deallocated.
                ensures
                    - calls get_global_memory_manager().deallocate(item)
                    - #get_number_of_allocations() == get_number_of_allocations() - 1
            !*/

            T* allocate_array (
                unsigned long size
            );
            /*!
                ensures
                    - #get_number_of_allocations() == get_number_of_allocations() + 1
                    - returns get_global_memory_manager().allocate_array()
                throws
                    - std::bad_alloc or any exception thrown by T's constructor.
                        If this exception is thrown then the call to allocate_array()
                        has no effect on #*this.
            !*/

            void deallocate_array (
                T* item
            );
            /*!
                requires
                    - item == is a pointer to memory that was obtained from a call to
                      the get_global_memory_manager() object's allocate_array() method.
                    - the memory pointed to by item hasn't already been deallocated.
                ensures
                    - calls get_global_memory_manager().deallocate_array(item)
                    - #get_number_of_allocations() == get_number_of_allocations() - 1
            !*/

            void swap (
                memory_manager_global& item
            );
            /*!
                ensures
                    - swaps *this and item
            !*/

        private:

            // restricted functions
            memory_manager_global(memory_manager_global&);        // copy constructor
            memory_manager_global& operator=(memory_manager_global&);    // assignment operator
    };

    template <
        typename T,
        typename factory
        >
    inline void swap (
        memory_manager_global<T,factory>& a,
        memory_manager_global<T,factory>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

}

#endif // DLIB_MEMORY_MANAGER_GLOBAl_ABSTRACT_


dlib C++ Library - memory_manager_stateless_kernel_abstract.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_MEMORY_MANAGER_STATELESs_ABSTRACT_
#ifdef DLIB_MEMORY_MANAGER_STATELESs_ABSTRACT_

#include "../algs.h"

namespace dlib
{
    template <
        typename T
        >
    class memory_manager_stateless
    {
        /*!
            REQUIREMENTS ON T
                T must have a default constructor.

            WHAT THIS OBJECT REPRESENTS
                This object represents some kind of stateless memory manager or memory pool.
                Stateless means that all instances (instances of the same kernel implementation that is)
                of this object are identical and can be used interchangeably.  Note that
                implementations are allowed to have some shared global state such as a
                global memory pool.

            THREAD SAFETY
                This object is thread safe.  You may access it from any thread at any time
                without synchronizing access.
        !*/

        public:

            typedef T type;
            const static bool is_stateless = true;

            template <typename U>
            struct rebind {
                typedef memory_manager_stateless<U> other;
            };

            memory_manager_stateless(
            );
            /*!
                ensures
                    - #*this is properly initialized
                throws
                    - std::bad_alloc
            !*/

            virtual ~memory_manager_stateless(
            );
            /*!
                ensures
                    - frees any resources used by *this but has no effect on any shared global
                      resources used by the implementation.
            !*/

            T* allocate (
            );
            /*!
                ensures
                    - allocates a new object of type T and returns a pointer to it.
                throws
                    - std::bad_alloc or any exception thrown by T's constructor.
                        If this exception is thrown then the call to allocate()
                        has no effect on #*this.
            !*/

            void deallocate (
                T* item
            );
            /*!
                requires
                    - item == is a pointer to memory that was obtained from a call to
                      allocate(). (i.e. The pointer you are deallocating must have
                      come from the same implementation of memory_manager_stateless
                      that is trying to deallocate it.)
                    - the memory pointed to by item hasn't already been deallocated.
                ensures
                    - deallocates the object pointed to by item
            !*/

            T* allocate_array (
                unsigned long size
            );
            /*!
                ensures
                    - allocates a new array of size objects of type T and returns a
                      pointer to it.
                throws
                    - std::bad_alloc or any exception thrown by T's constructor.
                        If this exception is thrown then the call to allocate()
                        has no effect on #*this.
            !*/

            void deallocate_array (
                T* item
            );
            /*!
                requires
                    - item == is a pointer to memory that was obtained from a call to
                      allocate_array(). (i.e. The pointer you are deallocating must have
                      come from the same implementation of memory_manager_stateless
                      that is trying to deallocate it.)
                    - the memory pointed to by item hasn't already been deallocated.
                ensures
                    - deallocates the array pointed to by item
            !*/

            void swap (
                memory_manager_stateless& item
            );
            /*!
                ensures
                    - this function has no effect on *this or item.  It is just provided
                      to make this object's interface more compatable with the other
                      memory managers.
            !*/

        private:

            // restricted functions
            memory_manager_stateless(memory_manager_stateless&);        // copy constructor
            memory_manager_stateless& operator=(memory_manager_stateless&);    // assignment operator
    };

    template <
        typename T
        >
    inline void swap (
        memory_manager_stateless<T>& a,
        memory_manager_stateless<T>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

}

#endif // DLIB_MEMORY_MANAGER_STATELESs_ABSTRACT_


dlib C++ Library - pipe_kernel_abstract.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_PIPE_KERNEl_ABSTRACT_
#ifdef DLIB_PIPE_KERNEl_ABSTRACT_

#include "../threads.h"

namespace dlib
{

    template <
        typename T
        >
    class pipe
    {
        /*!
            REQUIREMENTS ON T
                T must be swappable by a global swap()
                T must have a default constructor

            INITIAL VALUE
                size() == 0
                is_enabled() == true
                is_enqueue_enabled() == true
                is_dequeue_enabled() == true

            WHAT THIS OBJECT REPRESENTS
                This is a first in first out queue with a fixed maximum size containing
                items of type T.  It is suitable for passing objects between threads.

            THREAD SAFETY
                All methods of this class are thread safe.  You may call them from any
                thread and any number of threads my call them at once.
        !*/

    public:

        typedef T type;

        explicit pipe (
            unsigned long maximum_size
        );
        /*!
            ensures
                - #*this is properly initialized
                - #max_size() == maximum_size
            throws
                - std::bad_alloc
                - dlib::thread_error
        !*/

        virtual ~pipe (
        );
        /*!
            ensures
                - any resources associated with *this have been released
                - disables (i.e. sets is_enabled() == false) this object so that
                  all calls currently blocking on it will return immediately.
        !*/

        void enable (
        );
        /*!
            ensures
                - #is_enabled() == true
        !*/

        void disable (
        );
        /*!
            ensures
                - #is_enabled() == false
                - causes all current and future calls to enqueue(), dequeue(),
                  enqueue_or_timeout() and dequeue_or_timeout() to not block but
                  to return false immediately until enable() is called.
                - causes all current and future calls to wait_until_empty() and
                  wait_for_num_blocked_dequeues() to not block but return
                  immediately until enable() is called.
        !*/

        bool is_enabled (
        ) const;
        /*!
            ensures
                - returns true if this pipe is currently enabled, false otherwise.
        !*/

        void empty (
        );
        /*!
            ensures
                - #size() == 0
        !*/

        void wait_until_empty (
        ) const;
        /*!
            ensures
                - blocks until one of the following is the case:
                    - size() == 0
                    - is_enabled() == false
                    - is_dequeue_enabled() == false
        !*/

        void wait_for_num_blocked_dequeues (
           unsigned long num
        ) const;
        /*!
            ensures
                - blocks until one of the following is the case:
                    - size() == 0 and the number of threads blocked on calls
                      to dequeue() and dequeue_or_timeout() is greater than
                      or equal to num.
                    - is_enabled() == false
                    - is_dequeue_enabled() == false
        !*/

        bool is_enqueue_enabled (
        ) const;
        /*!
            ensures
                - returns true if the enqueue() and enqueue_or_timeout() functions are
                  currently enabled, returns false otherwise.  (note that the higher
                  level is_enabled() function can overrule this one.  So if
                  is_enabled() == false then enqueue functions are still disabled even
                  if is_enqueue_enabled() returns true.  But if is_enqueue_enabled() == false
                  then enqueue functions are always disabled no matter the state of
                  is_enabled())
        !*/

        void disable_enqueue (
        );
        /*!
            ensures
                - #is_enqueue_enabled() == false
                - causes all current and future calls to enqueue() and
                  enqueue_or_timeout() to not block but to return false
                  immediately until enable_enqueue() is called.
        !*/

        void enable_enqueue (
        );
        /*!
            ensures
                - #is_enqueue_enabled() == true
        !*/

        bool is_dequeue_enabled (
        ) const;
        /*!
            ensures
                - returns true if the dequeue() and dequeue_or_timeout() functions are
                  currently enabled, returns false otherwise.  (note that the higher
                  level is_enabled() function can overrule this one.  So if
                  is_enabled() == false then dequeue functions are still disabled even
                  if is_dequeue_enabled() returns true.  But if is_dequeue_enabled() == false
                  then dequeue functions are always disabled no matter the state of
                  is_enabled())
        !*/

        void disable_dequeue (
        );
        /*!
            ensures
                - #is_dequeue_enabled() == false
                - causes all current and future calls to dequeue() and
                  dequeue_or_timeout() to not block but to return false
                  immediately until enable_dequeue() is called.
        !*/

        void enable_dequeue (
        );
        /*!
            ensures
                - #is_dequeue_enabled() == true
        !*/

        unsigned long max_size (
        ) const;
        /*!
            ensures
                - returns the maximum number of objects of type T that this
                  pipe can contain.
        !*/

        unsigned long size (
        ) const;
        /*!
            ensures
                - returns the number of objects of type T that this
                  object currently contains.
        !*/

        bool enqueue (
            T& item
        );
        /*!
            ensures
                - if (size() == max_size()) then
                    - this call to enqueue() blocks until one of the following is the case:
                        - there is room in the pipe for another item
                        - max_size() == 0 and another thread is trying to dequeue from this
                          pipe and we can pass our item object directly to that thread.
                        - someone calls disable()
                        - someone calls disable_enqueue()
                - else
                    - this call does not block.
                - if (this call to enqueue() returns true) then
                    - #is_enabled() == true
                    - #is_enqueue_enabled() == true
                    - if (max_size() == 0) then
                        - using global swap, item was passed directly to a
                          thread attempting to dequeue from this pipe
                    - else
                        - using global swap, item was added into this pipe.
                    - #item is in an undefined but valid state for its type
                - else
                    - item was NOT added into the pipe
                    - #item == item (i.e. the value of item is unchanged)
        !*/

        bool enqueue_or_timeout (
            T& item,
            unsigned long timeout
        );
        /*!
            ensures
                - if (size() == max_size() && timeout > 0) then
                    - this call to enqueue_or_timeout() blocks until one of the following is the case:
                        - there is room in the pipe to add another item
                        - max_size() == 0 and another thread is trying to dequeue from this pipe
                          and we can pass our item object directly to that thread.
                        - someone calls disable()
                        - someone calls disable_enqueue()
                        - timeout milliseconds passes
                - else
                    - this call does not block.
                - if (this call to enqueue() returns true) then
                    - #is_enabled() == true
                    - #is_enqueue_enabled() == true
                    - if (max_size() == 0) then
                        - using global swap, item was passed directly to a
                          thread attempting to dequeue from this pipe
                    - else
                        - using global swap, item was added into this pipe.
                    - #item is in an undefined but valid state for its type
                - else
                    - item was NOT added into the pipe
                    - #item == item (i.e. the value of item is unchanged)
        !*/

        bool dequeue (
            T& item
        );
        /*!
            ensures
                - if (size() == 0) then
                    - this call to dequeue() blocks until one of the following is the case:
                        - there is something in the pipe we can dequeue
                        - max_size() == 0 and another thread is trying to enqueue an item
                          onto this pipe and we can receive our item directly from that thread.
                        - someone calls disable()
                        - someone calls disable_dequeue()
                - else
                    - this call does not block.
                - if (this call to dequeue() returns true) then
                    - #is_enabled() == true
                    - #is_dequeue_enabled() == true
                    - the oldest item that was enqueued into this pipe has been
                      swapped into #item.
                - else
                    - nothing was dequeued from this pipe.
                    - #item == item (i.e. the value of item is unchanged)
        !*/

        bool dequeue_or_timeout (
            T& item,
            unsigned long timeout
        );
        /*!
            ensures
                - if (size() == 0 && timeout > 0) then
                    - this call to dequeue_or_timeout() blocks until one of the following is the case:
                        - there is something in the pipe we can dequeue
                        - max_size() == 0 and another thread is trying to enqueue an item onto this
                          pipe and we can receive our item directly from that thread.
                        - someone calls disable()
                        - someone calls disable_dequeue()
                        - timeout milliseconds passes
                - else
                    - this call does not block.
                - if (this call to dequeue_or_timeout() returns true) then
                    - #is_enabled() == true
                    - #is_dequeue_enabled() == true
                    - the oldest item that was enqueued into this pipe has been
                      swapped into #item.
                - else
                    - nothing was dequeued from this pipe.
                    - #item == item (i.e. the value of item is unchanged)
        !*/

    private:

        // restricted functions
        pipe(const pipe&);        // copy constructor
        pipe& operator=(const pipe&);    // assignment operator

    };

}

#endif // DLIB_PIPE_KERNEl_ABSTRACT_


dlib C++ Library - std_allocator.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_STD_ALLOc_H_
#define DLIB_STD_ALLOc_H_

#include <limits>
#include <memory>
#include "enable_if.h"
#include "algs.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename M
        >
    class std_allocator
    {
        /*!
            REQUIREMENTS ON M
                must be an implementation of memory_manager/memory_manager_kernel_abstract.h or
                must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or
                must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h
                M::type can be set to anything.

            WHAT THIS OBJECT REPRESENTS
                This object is an implementation of an allocator that conforms to the C++ standard
                requirements for allocator objects.  The M template argument is one of the dlib
                memory manager objects and this allocator implementation will do all of its memory allocations
                using whatever dlib memory manager you supply.

                Thus, using this allocator object you can use any of the dlib memory manager objects with
                the containers in the STL or with any other object that requires a C++ allocator object.

                It is important to note that many STL implementations make the assumption that the memory
                allocated by one allocator can be freed by another.  This effectively means that you should
                only use a global or stateless memory manager with the std_allocator.  Either that or you
                have to verify that your version of the STL isn't going to try and allocate and deallocate
                memory with different allocators.
        !*/

    public:
        //type definitions
        typedef std::size_t     size_type;
        typedef std::ptrdiff_t  difference_type;
        typedef T*              pointer;
        typedef const T*        const_pointer;
        typedef T&              reference;
        typedef const T&        const_reference;
        typedef T               value_type;

        //rebind std_allocator to type U
        template <typename U>
        struct rebind {
            typedef std_allocator<U,M> other;
        };

        //return address of values
        pointer address (reference value) const { return &value; }

        const_pointer address (const_reference value) const { return &value; }

        /*constructors and destructor
         *-nothing to do because the std_allocator has no state
        */
        std_allocator() throw() { }

        std_allocator(const std_allocator&) throw() { }

        template <typename U>
        std_allocator (const std_allocator<U,M>&) throw() { }

        ~std_allocator() throw() { }

        //return maximum number of elements that can be allocated
        size_type max_size () const throw()
        {
            //for numeric_limits see Section 4.3, page 59
            return std::numeric_limits<size_t>::max() / sizeof(T);
        }

        //allocate but don't initialize num elements of type T
        pointer allocate (
            size_type num,
            typename std_allocator<void,M>::const_pointer  = 0
        )
        {
            return (pointer) pool.allocate_array(num*sizeof(T));
        }

        // This function is not required by the C++ standard but some versions of the STL
        // distributed with gcc erroneously require it.  See the bug report for further
        // details: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51626
        void construct(pointer p) { return construct(p, value_type()); }

        //initialize elements of allocated storage p with value value
        void construct (pointer p, const T& value)
        {
            //initialize memory with placement new
            new((void*)p)T(value);
        }

        //destroy elements of initialized storage p
        void destroy (pointer p)
        {
            // destroy objects by calling their destructor
            p->~T();
        }

        //deallocate storage p of deleted elements
        void deallocate (pointer p, size_type )
        {
            pool.deallocate_array((char*)p);
        }

        void swap (
            std_allocator& item
        )
        {
            pool.swap(item.pool);
        }

        std_allocator& operator= (const std_allocator&) { return *this;}

    private:
        typename M::template rebind<char>::other pool;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename M
        >
    class std_allocator<void,M>
    {
    public:
        //type definitions
        typedef std::size_t     size_type;
        typedef std::ptrdiff_t  difference_type;
        typedef void*              pointer;
        typedef const void*        const_pointer;
        typedef void               value_type;

        //rebind std_allocator to type U
        template <typename U>
        struct rebind {
            typedef std_allocator<U,M> other;
        };

    };

// ----------------------------------------------------------------------------------------

    template <typename M1, typename M2, typename enabled = void>
    struct std_alloc_compare
    { const static bool are_interchangeable = false; };

    template <typename M1, typename M2>
    struct std_alloc_compare<M1,M2,typename enable_if<is_same_type<typename M1::mm_global_type, typename M2::mm_global_type> >::type>
    { const static bool are_interchangeable = true; };

    template <typename M>
    struct std_alloc_compare<M,M,typename enable_if_c<M::is_stateless>::type>
    { const static bool are_interchangeable = true; };

    //return that all specializations of this std_allocator are interchangeable if they use memory_manager_global
    // instances with the same mm_global_type
    template <typename T1, typename M1, typename T2, typename M2>
    bool operator== (
        const std_allocator<T1,M1>&,
        const std_allocator<T2,M2>&
    ) throw()
    { return std_alloc_compare<M1,M2>::are_interchangeable; }

    template <typename T1, typename M1, typename T2, typename M2>
    bool operator!= (
        const std_allocator<T1,M1>&,
        const std_allocator<T2,M2>&
    ) throw()
    { return !std_alloc_compare<M1,M2>::are_interchangeable; }

// ----------------------------------------------------------------------------------------

    template <typename T, typename M>
    void swap (
        std_allocator<T,M>& a,
        std_allocator<T,M>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_STD_ALLOc_H_


dlib C++ Library - sync_extension_kernel_abstract.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SYNC_EXTENSION_KERNEl_ABSTRACT_
#ifdef DLIB_SYNC_EXTENSION_KERNEl_ABSTRACT_

#include "../threads/threads_kernel_abstract.h"
#include "../threads/rmutex_extension_abstract.h"
#include "../threads/rsignaler_extension_abstract.h"
#include "../algs.h"

namespace dlib
{

    template <
        typename base
        >
    class sync_extension : public base
    {

        /*!
            REQUIREMENTS ON base
                base must have a default constructor
                base must implement swap(base&)

            WHAT THIS OBJECT REPRESENTS
                This object represents a general extension to any object (given the
                restrictions on base).  This object gives any object which it extends
                an integrated rmutex and rsignaler object.  The extended object will
                then be able to be treated as if it was also a rmutex and rsignaler.

                NOTE that just like the threading api, this object does not check
                its requires clauses so be careful with it.

                Also note that swap() does not swap the rmutex and rsignaler objects.
                the rmutex and rsignaler are associated with the object instance itself,
                not with whatever the object represents.
        !*/

        public:

        sync_extension (
        );
        /*!
            ensures
                - #*this is properly initialized
            throws
                - std::bad_alloc
                    this is thrown if there is a problem gathering memory
                - dlib::thread_error
                    this is thrown if there is a problem creating threading objects
                - any exception thrown by the constructor for the parent class base
        !*/

        template <
            typename T
            >
        sync_extension (
            const T& one
        );
        /*!
            ensures
                - #*this is properly initialized
                - the argument one will be passed on to the constructor for the parent
                  class base.
            throws
                - std::bad_alloc
                    this is thrown if there is a problem gathering memory
                - dlib::thread_error
                    this is thrown if there is a problem creating threading objects
                - any exception thrown by the constructor for the parent class base
        !*/

        template <
            typename T,
            typename U
            >
        sync_extension (
            const T& one,
            const T& two
        );
        /*!
            ensures
                - #*this is properly initialized
                - the argument one will be passed on to the constructor for the parent
                  class base as its first argument.
                - the argument two will be passed on to the constructor for the parent
                  class base as its second argument.
            throws
                - std::bad_alloc
                    this is thrown if there is a problem gathering memory
                - dlib::thread_error
                    this is thrown if there is a problem creating threading objects
                - any exception thrown by the constructor for the parent class base
        !*/

        const rmutex& get_mutex (
        ) const;
        /*!
            ensures
                - returns the rmutex embedded in this object
        !*/

        void lock (
        ) const;
        /*!
            requires
                - the thread calling lock() does not already have a lock on *this
            ensures
                - if (*this is currently locked by another thread) then
                    - the thread that called lock() on *this is put to sleep until
                      it becomes available
                - if (*this is currently unlocked) then
                    - #*this becomes locked and the current thread is NOT put to sleep
                      but now "owns" #*this
        !*/

        void unlock (
        ) const;
        /*!
            ensures
                - #*this is unlocked (i.e. other threads may now lock this object)
        !*/

        void wait (
        ) const;
        /*!
            requires
                - *this is locked and owned by the calling thread
            ensures
                - atomically unlocks *this and blocks the calling thread
                - calling thread will wake if another thread calls signal() or broadcast()
                  on *this
                - when wait returns the calling thread again has a lock on #*this
        !*/

        bool wait_or_timeout (
            unsigned long milliseconds
        ) const;
        /*!
            requires
                - *this is locked and owned by the calling thread
            ensures
                - atomically unlocks *this and blocks the calling thread
                - calling thread will wake if another thread calls signal() or broadcast()
                  on *this
                - after the specified number of milliseconds has elapsed the calling thread
                  will wake once *this is free to be locked
                - when wait returns the calling thread again has a lock on #*this

                - returns false if the call to wait_or_timeout timed out
                - returns true if the call did not time out
        !*/

        void signal (
        ) const;
        /*!
            ensures
                - if (at least one thread is waiting on *this) then
                    - at least one of the waiting threads will wake
        !*/

        void broadcast (
        ) const;
        /*!
            ensures
                - any and all threads waiting on *this will wake
        !*/

    };

    template <
        typename base
        >
    inline void swap (
        sync_extension<base>& a,
        sync_extension<base>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

}

#endif // DLIB_SYNC_EXTENSION_KERNEl_ABSTRACT_


dlib C++ Library - timeout_abstract.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_TIMEOUT_KERNEl_ABSTRACT_
#ifdef DLIB_TIMEOUT_KERNEl_ABSTRACT_

#include "../threads.h"

namespace dlib
{

    class timeout
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object provides a simple way to implement a timeout.  An example will
                make its use clear.  Suppose we want to read from a socket but we want to
                terminate the connection if the read takes longer than 10 seconds.  This
                could be accomplished as follows:

                connection* con = a connection from somewhere;
                {
                    // setup a timer that will call con->shutdown() in 10 seconds
                    timeout t(*con,&connection::shutdown,10000);
                    // Now call read on the connection.  If this call to read() takes more
                    // than 10 seconds then the t timeout will trigger and shutdown the
                    // connection.  If read completes in less than 10 seconds then the t
                    // object will be destructed on the next line due to the } and then the
                    // timeout won't trigger.
                    con->read(buf,100);
                }

                Alternatively, if you have a compiler capable of using C++11 lambda
                functions, you can use a syntax like this:
                {
                    timeout t([con](){ con->shutdown(); }, 10000);
                    con->read(buf,100);
                }

                More generally, you can use this with things other than sockets.  For
                example, the following statement will print "Hello world!" after 1000ms:
                    timeout t([](){ cout << "Hello world!" << endl; },  1000);

            THREAD SAFETY
                All methods of this class are thread safe.
        !*/

    public:

        template <
            typename T
            >
        timeout (
            T callback_function,
            unsigned long ms_to_timeout
        );
        /*!
            requires
                - callback_function does not throw
            ensures
                - does not block.
                - #*this is properly initialized
                - if (this object isn't destructed in ms_to_timeout milliseconds) then
                    - callback_function() will be called in ms_to_timeout milliseconds.
            throws
                - std::bad_alloc
                - dlib::thread_error
        !*/

        template <
            typename T
            >
        timeout (
            T& object,
            void (T::*callback_function)(),
            unsigned long ms_to_timeout
        );
        /*!
            requires
                - callback_function does not throw
            ensures
                - does not block.
                - #*this is properly initialized
                - if (this object isn't destructed in ms_to_timeout milliseconds) then
                    - (object.*callback_function)() will be called in ms_to_timeout
                      milliseconds.
            throws
                - std::bad_alloc
                - dlib::thread_error
        !*/

        template <
            typename T,
            typename U
            >
        timeout (
            T& object,
            void (T::*callback_function)(U callback_function_argument),
            unsigned long ms_to_timeout,
            U callback_function_argument
        );
        /*!
            requires
                - callback_function does not throw
            ensures
                - does not block.
                - #*this is properly initialized
                - if (this object isn't destructed in ms_to_timeout milliseconds) then
                    - (object.*callback_function)(callback_function_argument) will be
                      called in ms_to_timeout milliseconds.
            throws
                - std::bad_alloc
                - dlib::thread_error
        !*/

        template <
            typename T
            >
        timeout (
            T& object,
            int (T::*callback_function)(),
            unsigned long ms_to_timeout
        );
        /*!
            requires
                - callback_function does not throw
            ensures
                - does not block.
                - #*this is properly initialized
                - if (this object isn't destructed in ms_to_timeout milliseconds) then
                    - (object.*callback_function)() will be called in ms_to_timeout
                      milliseconds.
            throws
                - std::bad_alloc
                - dlib::thread_error
        !*/

        template <
            typename T,
            typename U
            >
        timeout (
            T& object,
            int (T::*callback_function)(U callback_function_argument),
            unsigned long ms_to_timeout,
            U callback_function_argument
        );
        /*!
            requires
                - callback_function does not throw
            ensures
                - does not block.
                - #*this is properly initialized
                - if (this object isn't destructed in ms_to_timeout milliseconds) then
                    - (object.*callback_function)(callback_function_argument) will be
                      called in ms_to_timeout milliseconds.
            throws
                - std::bad_alloc
                - dlib::thread_error
        !*/

        virtual ~timeout (
        );
        /*!
            requires
                - is not called from inside the callback_function given to the
                  constructor.
            ensures
                - any resources associated with *this have been released
                - if (the callback_function hasn't been called yet) then
                    - the callback_function specified in the constructor will not be called
        !*/

    private:

        // restricted functions
        timeout(const timeout&);        // copy constructor
        timeout& operator=(const timeout&);    // assignment operator

    };

}

#endif // DLIB_TIMEOUT_KERNEl_ABSTRACT_


dlib C++ Library - timer_abstract.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_TIMER_KERNEl_ABSTRACT_
#ifdef DLIB_TIMER_KERNEl_ABSTRACT_

#include "../threads.h"

namespace dlib
{

    template <
        typename T
        >
    class timer
    {
        /*!
            INITIAL VALUE
                is_running()      == false
                delay_time()      == 1000
                action_object()   == The object that is passed into the constructor
                action_function() == The member function pointer that is passed to
                                     the constructor.

            WHAT THIS OBJECT REPRESENTS
                This object represents a timer that will call a given member function
                (the action function) repeatedly at regular intervals and in its own
                thread.

                Note that the delay_time() is measured in milliseconds but you are not
                guaranteed to have that level of resolution.  The actual resolution
                is implementation dependent.

            THREAD SAFETY
                All methods of this class are thread safe.
        !*/

    public:

        typedef void (T::*af_type)();

        timer (
            T& ao,
            af_type af
        );
        /*!
            requires
                - af does not throw
            ensures
                - does not block.
                - #*this is properly initialized
                - #action_object() == ao
                - #action_function() == af
                  (af is a member function pointer to a member in the class T)
            throws
                - std::bad_alloc
                - dlib::thread_error
        !*/

        virtual ~timer (
        );
        /*!
            requires
                - is not called from inside the action_function()
            ensures
                - any resources associated with *this have been released
                - will not call the action_function() anymore.
                - if (the action function is currently executing) then
                    - blocks until it finishes
        !*/

        void clear(
        );
        /*!
            ensures
                - #*this has its initial value
                - does not block
            throws
                - std::bad_alloc or dlib::thread_error
                    If either of these exceptions are thrown then #*this is unusable
                    until clear() is called and succeeds.
        !*/

        af_type action_function (
        ) const;
        /*!
            ensures
                - does not block.
                - returns a pointer to the member function of action_object() that is
                  called by *this.
        !*/

        const T& action_object (
        ) const;
        /*!
            ensures
                - does not block.
                - returns a const reference to the object used to call the member
                  function pointer action_function()
        !*/

        T& action_object (
        );
        /*!
            ensures
                - does not block.
                - returns a non-const reference to the object used to call the member
                  function pointer action_function()
        !*/

        bool is_running (
        ) const;
        /*!
            ensures
                - does not block.
                - if (*this is currently scheduled to call the action_function()) then
                    - returns true
                - else
                    - returns false
        !*/

        unsigned long delay_time (
        ) const;
        /*!
            ensures
                - does not block.
                - returns the amount of time, in milliseconds, that *this will wait between
                  the return of one call to the action_function() and the beginning of the
                  next call to the action_function().
        !*/

        void set_delay_time (
            unsigned long milliseconds
        );
        /*!
            ensures
                - does not block.
                - #delay_time() == milliseconds
            throws
                - std::bad_alloc or dlib::thread_error
                    If either of these exceptions are thrown then #is_running() == false
                    but otherwise this function succeeds
        !*/

        void start (
        );
        /*!
            ensures
                - does not block.
                - if (is_running() == false) then
                    - #is_running() == true
                    - The action_function() will run in another thread.
                    - The first call to the action_function() will occur in roughly
                      delay_time() milliseconds.
                - else
                    - this call to start() has no effect
            throws
                - dlib::thread_error or std::bad_alloc
                    If this exception is thrown then #is_running() == false but
                    otherwise this call to start() has no effect.
        !*/

        void stop (
        );
        /*!
            ensures
                - #is_running() == false
                - does not block.
        !*/

        void stop_and_wait (
        );
        /*!
            ensures
                - #is_running() == false
                - if (the action function is currently executing) then
                    - blocks until it finishes
        !*/

    private:

        // restricted functions
        timer(const timer<T>&);        // copy constructor
        timer<T>& operator=(const timer<T>&);    // assignment operator

    };

}

#endif // DLIB_TIMER_KERNEl_ABSTRACT_


dlib C++ Library - vectorstream_abstract.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_VECTORStREAM_ABSTRACT_Hh_
#ifdef DLIB_VECTORStREAM_ABSTRACT_Hh_

#include <iostream>
#include <vector>

namespace dlib
{
    class vectorstream : public std::iostream
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is an iostream object that reads and writes from an in-memory buffer.
                It functions very much the same way as the std::stringstream object.
                However, while the std::stringstream holds its buffer internally and it can
                only be accessed by copying it out, the vectorstream uses an external
                std::vector<char> as its buffer.  That is, it holds a reference to an
                external vector and does not contain any internal buffers of its own.

                This object is useful as a slightly more efficient alternative to the
                std::stringstream since you can avoid the overhead of copying buffer
                contents to and from the stream.  This is particularly useful when used as
                a source or target for serialization routines.
        !*/

    public:

        vectorstream (
            std::vector<char>& buffer
        );
        /*!
            ensures
                - This object will use the given vector as its read/write buffer.  That is:
                    - Any data written to this stream will be appended to the given buffer
                    - Any data read from this stream is read from the given buffer,
                      starting with buffer[0], then buffer[1], and so on.  Just like
                      std::stringstream, writes to the stream do not move the position of
                      the next byte that will be read from the buffer.
                - This constructor does not copy the buffer.  Only a reference to it will
                  be used.  Therefore, any time data is written to this stream it will
                  immediately show up in the buffer.
        !*/

        std::istream& seekg (
            std::streampos pos
        );
        /*!
            ensures
                - The next read from this object will read from the position buffer[pos],
                  where buffer is the std::vector given to this object's constructor.  Note
                  that if pos >= buffer.size() then the next read will simply return EOF.
                - returns *this
        !*/

    };
}

#endif // DLIB_VECTORStREAM_ABSTRACT_Hh_


dlib C++ Library - serialize.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SERIALIZe_
#define DLIB_SERIALIZe_

/*!
    There are two global functions in the dlib namespace that provide serialization and
    deserialization support.  Their signatures and specifications are as follows:

        void serialize (
            const serializable_type& item,
            std::ostream& out
        );
        /!*
            ensures
                - writes the state of item to the output stream out
                - if (serializable_type implements the enumerable interface) then
                    - item.at_start() == true
            throws
                - serialization_error
                    This exception is thrown if there is some problem which prevents
                    us from successfully writing item to the output stream.
                - any other exception
        *!/

        void deserialize (
            serializable_type& item,
            std::istream& in
        );
        /!*
            ensures
                - #item == a deserialized copy of the serializable_type that was
                  in the input stream in.
                - Reads all the bytes associated with the serialized serializable_type
                  contained inside the input stream and no more.  This means you
                  can serialize multiple objects to an output stream and then read
                  them all back in, one after another, using deserialize().
                - if (serializable_type implements the enumerable interface) then
                    - item.at_start() == true
            throws
                - serialization_error
                    This exception is thrown if there is some problem which prevents
                    us from successfully deserializing item from the input stream.
                    If this exception is thrown then item will have an initial value
                    for its type.
                - any other exception
        *!/

    For convenience, you can also serialize to a file using this syntax:
        serialize("your_file.dat") << some_object << another_object;

    That overwrites the contents of your_file.dat with the serialized data from some_object
    and another_object.  Then to recall the objects from the file you can do:
        deserialize("your_file.dat") >> some_object >> another_object;

    Finally, you can chain as many objects together using the << and >> operators as you
    like.

    This file provides serialization support to the following object types:
        - The C++ base types (NOT including pointer types)
        - std::string
        - std::wstring
        - std::vector
        - std::map
        - std::set
        - std::pair
        - std::complex
        - dlib::uint64
        - dlib::int64
        - float_details
        - enumerable<T> where T is a serializable type
        - map_pair<D,R> where D and R are both serializable types.
        - C style arrays of serializable types
        - Google protocol buffer objects.

    This file provides deserialization support to the following object types:
        - The C++ base types (NOT including pointer types)
        - std::string
        - std::wstring
        - std::vector
        - std::map
        - std::set
        - std::pair
        - std::complex
        - dlib::uint64
        - dlib::int64
        - float_details
        - C style arrays of serializable types
        - Google protocol buffer objects.

    Support for deserialization of objects which implement the enumerable or
    map_pair interfaces is the responsibility of those objects.

    Note that you can deserialize an integer value to any integral type (except for a
    char type) if its value will fit into the target integer type.  I.e.  the types
    short, int, long, unsigned short, unsigned int, unsigned long, and dlib::uint64
    can all receive serialized data from each other so long as the actual serizlied
    value fits within the receiving integral type's range.

    Also note that for any container to be serializable the type of object it contains
    must be serializable.

    FILE STREAMS
        If you are serializing to and from file streams it is important to
        remember to set the file streams to binary mode using the std::ios::binary
        flag.

    INTEGRAL SERIALIZATION FORMAT
        All C++ integral types (except the char types) are serialized to the following
        format:
        The first byte is a control byte.  It tells you if the serialized number is
        positive or negative and also tells you how many of the following bytes are
        part of the number.  The absolute value of the number is stored in little
        endian byte order and follows the control byte.

        The control byte:
            The high order bit of the control byte is a flag that tells you if the
            encoded number is negative or not.  It is set to 1 when the number is
            negative and 0 otherwise.
            The 4 low order bits of the control byte represent an unsigned number
            and tells you how many of the following bytes are part of the encoded
            number.

    bool SERIALIZATION FORMAT
        A bool value is serialized as the single byte character '1' or '0' in ASCII.
        Where '1' indicates true and '0' indicates false.

    FLOATING POINT SERIALIZATION FORMAT
        To serialize a floating point value we convert it into a float_details object and
        then serialize the exponent and mantissa values using dlib's integral serialization
        format.  Therefore, the output is first the exponent and then the mantissa.  Note that
        the mantissa is a signed integer (i.e. there is not a separate sign bit).
!*/

#include "algs.h"
#include "assert.h"
#include <iomanip>
#include <cstddef>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <complex>
#include <map>
#include <set>
#include <limits>
#include "uintn.h"
#include "interfaces/enumerable.h"
#include "interfaces/map_pair.h"
#include "enable_if.h"
#include "unicode.h"
#include "byte_orderer.h"
#include "float_details.h"
#include "smart_pointers/shared_ptr.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class serialization_error : public error
    {
    public:
        serialization_error(const std::string& e):error(e) {}
    };

// ----------------------------------------------------------------------------------------

    namespace ser_helper
    {

        template <
            typename T
            >
        typename enable_if_c<std::numeric_limits<T>::is_signed,bool>::type pack_int (
            T item,
            std::ostream& out
        )
        /*!
            requires
                - T is a signed integral type
            ensures
                - if (no problems occur serializing item) then
                    - writes item to out
                    - returns false
                - else
                    - returns true
        !*/
        {
            COMPILE_TIME_ASSERT(sizeof(T) <= 8);
            unsigned char buf[9];
            unsigned char size = sizeof(T);
            unsigned char neg;
            if (item < 0)
            {
                neg = 0x80;
                item *= -1;
            }
            else
            {
                neg = 0;
            }

            for (unsigned char i = 1; i <= sizeof(T); ++i)
            {
                buf[i] = static_cast<unsigned char>(item&0xFF);
                item >>= 8;
                if (item == 0) { size = i; break; }
            }

            std::streambuf* sbuf = out.rdbuf();
            buf[0] = size|neg;
            if (sbuf->sputn(reinterpret_cast<char*>(buf),size+1) != size+1)
            {
                out.setstate(std::ios::eofbit | std::ios::badbit);
                return true;
            }

            return false;
        }

    // ------------------------------------------------------------------------------------

        template <
            typename T
            >
        typename enable_if_c<std::numeric_limits<T>::is_signed,bool>::type unpack_int (
            T& item,
            std::istream& in
        )
        /*!
            requires
                - T is a signed integral type
            ensures
                - if (there are no problems deserializing item) then
                    - returns false
                    - #item == the value stored in in
                - else
                    - returns true

        !*/
        {
            COMPILE_TIME_ASSERT(sizeof(T) <= 8);

            unsigned char buf[8];
            unsigned char size;
            bool is_negative;

            std::streambuf* sbuf = in.rdbuf();

            item = 0;
            int ch = sbuf->sbumpc();
            if (ch != EOF)
            {
                size = static_cast<unsigned char>(ch);
            }
            else
            {
                in.setstate(std::ios::badbit);
                return true;
            }

            if (size&0x80)
                is_negative = true;
            else
                is_negative = false;
            size &= 0x0F;

            // check if the serialized object is too big
            if (size > sizeof(T))
            {
                return true;
            }

            if (sbuf->sgetn(reinterpret_cast<char*>(&buf),size) != size)
            {
                in.setstate(std::ios::badbit);
                return true;
            }

            for (unsigned char i = size-1; true; --i)
            {
                item <<= 8;
                item |= buf[i];
                if (i == 0)
                    break;
            }

            if (is_negative)
                item *= -1;

            return false;
        }

    // ------------------------------------------------------------------------------------

        template <
            typename T
            >
        typename disable_if_c<std::numeric_limits<T>::is_signed,bool>::type pack_int (
            T item,
            std::ostream& out
        )
        /*!
            requires
                - T is an unsigned integral type
            ensures
                - if (no problems occur serializing item) then
                    - writes item to out
                    - returns false
                - else
                    - returns true
        !*/
        {
            COMPILE_TIME_ASSERT(sizeof(T) <= 8);
            unsigned char buf[9];
            unsigned char size = sizeof(T);

            for (unsigned char i = 1; i <= sizeof(T); ++i)
            {
                buf[i] = static_cast<unsigned char>(item&0xFF);
                item >>= 8;
                if (item == 0) { size = i; break; }
            }

            std::streambuf* sbuf = out.rdbuf();
            buf[0] = size;
            if (sbuf->sputn(reinterpret_cast<char*>(buf),size+1) != size+1)
            {
                out.setstate(std::ios::eofbit | std::ios::badbit);
                return true;
            }

            return false;
        }

    // ------------------------------------------------------------------------------------

        template <
            typename T
            >
        typename disable_if_c<std::numeric_limits<T>::is_signed,bool>::type unpack_int (
            T& item,
            std::istream& in
        )
        /*!
            requires
                - T is an unsigned integral type
            ensures
                - if (there are no problems deserializing item) then
                    - returns false
                    - #item == the value stored in in
                - else
                    - returns true

        !*/
        {
            COMPILE_TIME_ASSERT(sizeof(T) <= 8);

            unsigned char buf[8];
            unsigned char size;

            item = 0;

            std::streambuf* sbuf = in.rdbuf();
            int ch = sbuf->sbumpc();
            if (ch != EOF)
            {
                size = static_cast<unsigned char>(ch);
            }
            else
            {
                in.setstate(std::ios::badbit);
                return true;
            }

            // mask out the 3 reserved bits
            size &= 0x8F;

            // check if an error occurred
            if (size > sizeof(T))
                return true;

            if (sbuf->sgetn(reinterpret_cast<char*>(&buf),size) != size)
            {
                in.setstate(std::ios::badbit);
                return true;
            }

            for (unsigned char i = size-1; true; --i)
            {
                item <<= 8;
                item |= buf[i];
                if (i == 0)
                    break;
            }

            return false;
        }

    }

// ----------------------------------------------------------------------------------------

    #define USE_DEFAULT_INT_SERIALIZATION_FOR(T)  \
        inline void serialize (const T& item, std::ostream& out) \
        { if (ser_helper::pack_int(item,out)) throw serialization_error("Error serializing object of type " + std::string(#T)); }   \
        inline void deserialize (T& item, std::istream& in) \
        { if (ser_helper::unpack_int(item,in)) throw serialization_error("Error deserializing object of type " + std::string(#T)); }

    template <typename T>
    inline bool pack_byte (
        const T& ch,
        std::ostream& out
    )
    {
        std::streambuf* sbuf = out.rdbuf();
        return (sbuf->sputc((char)ch) == EOF);
    }

    template <typename T>
    inline bool unpack_byte (
        T& ch,
        std::istream& in
    )
    {
        std::streambuf* sbuf = in.rdbuf();
        int temp = sbuf->sbumpc();
        if (temp != EOF)
        {
            ch = static_cast<T>(temp);
            return false;
        }
        else
        {
            return true;
        }
    }

    #define USE_DEFAULT_BYTE_SERIALIZATION_FOR(T)  \
        inline void serialize (const T& item,std::ostream& out) \
        { if (pack_byte(item,out)) throw serialization_error("Error serializing object of type " + std::string(#T)); } \
        inline void deserialize (T& item, std::istream& in) \
        { if (unpack_byte(item,in)) throw serialization_error("Error deserializing object of type " + std::string(#T)); }

// ----------------------------------------------------------------------------------------

    USE_DEFAULT_INT_SERIALIZATION_FOR(short)
    USE_DEFAULT_INT_SERIALIZATION_FOR(int)
    USE_DEFAULT_INT_SERIALIZATION_FOR(long)
    USE_DEFAULT_INT_SERIALIZATION_FOR(unsigned short)
    USE_DEFAULT_INT_SERIALIZATION_FOR(unsigned int)
    USE_DEFAULT_INT_SERIALIZATION_FOR(unsigned long)
    USE_DEFAULT_INT_SERIALIZATION_FOR(uint64)
    USE_DEFAULT_INT_SERIALIZATION_FOR(int64)

    USE_DEFAULT_BYTE_SERIALIZATION_FOR(char)
    USE_DEFAULT_BYTE_SERIALIZATION_FOR(signed char)
    USE_DEFAULT_BYTE_SERIALIZATION_FOR(unsigned char)

    // Don't define serialization for wchar_t when using visual studio and
    // _NATIVE_WCHAR_T_DEFINED isn't defined since if it isn't they improperly set
    // wchar_t to be a typedef rather than its own type as required by the C++
    // standard.
#if !defined(_MSC_VER) || _NATIVE_WCHAR_T_DEFINED
    USE_DEFAULT_INT_SERIALIZATION_FOR(wchar_t)
#endif

// ----------------------------------------------------------------------------------------

    inline void serialize(
        const float_details& item,
        std::ostream& out
    )
    {
        serialize(item.mantissa, out);
        serialize(item.exponent, out);
    }

    inline void deserialize(
        float_details& item,
        std::istream& in
    )
    {
        deserialize(item.mantissa, in);
        deserialize(item.exponent, in);
    }

// ----------------------------------------------------------------------------------------

    template <typename T>
    inline void serialize_floating_point (
        const T& item,
        std::ostream& out
    )
    {
        try
        {
            float_details temp = item;
            serialize(temp, out);
        }
        catch (serialization_error& e)
        { throw serialization_error(e.info + "\n   while serializing a floating point number."); }
    }

    template <typename T>
    inline bool old_deserialize_floating_point (
        T& item,
        std::istream& in
    )
    {
        std::ios::fmtflags oldflags = in.flags();
        in.flags();
        std::streamsize ss = in.precision(35);
        if (in.peek() == 'i')
        {
            item = std::numeric_limits<T>::infinity();
            in.get();
            in.get();
            in.get();
        }
        else if (in.peek() == 'n')
        {
            item = -std::numeric_limits<T>::infinity();
            in.get();
            in.get();
            in.get();
            in.get();
        }
        else if (in.peek() == 'N')
        {
            item = std::numeric_limits<T>::quiet_NaN();
            in.get();
            in.get();
            in.get();
        }
        else
        {
            in >> item;
        }
        in.flags(oldflags);
        in.precision(ss);
        return (in.get() != ' ');
    }

    template <typename T>
    inline void deserialize_floating_point (
        T& item,
        std::istream& in
    )
    {
        // check if the serialized data uses the older ASCII based format.  We can check
        // this easily because the new format starts with the integer control byte which
        // always has 0 bits in the positions corresponding to the bitmask 0x70.  Moreover,
        // since the previous format used ASCII numbers we know that no valid bytes can
        // have bit values of one in the positions indicated 0x70.  So this test looks at
        // the first byte and checks if the serialized data uses the old format or the new
        // format.
        if ((in.rdbuf()->sgetc()&0x70) == 0)
        {
            try
            {
                // Use the fast and compact binary serialization format.
                float_details temp;
                deserialize(temp, in);
                item = temp;
            }
            catch (serialization_error& e)
            { throw serialization_error(e.info + "\n   while deserializing a floating point number."); }
        }
        else
        {
            if (old_deserialize_floating_point(item, in))
                throw serialization_error("Error deserializing a floating point number.");
        }
    }

    inline void serialize ( const float& item, std::ostream& out)
    {
        serialize_floating_point(item,out);
    }

    inline void deserialize (float& item, std::istream& in)
    {
        deserialize_floating_point(item,in);
    }

    inline void serialize ( const double& item, std::ostream& out)
    {
        serialize_floating_point(item,out);
    }

    inline void deserialize (double& item, std::istream& in)
    {
        deserialize_floating_point(item,in);
    }

    inline void serialize ( const long double& item, std::ostream& out)
    {
        serialize_floating_point(item,out);
    }

    inline void deserialize ( long double& item, std::istream& in)
    {
        deserialize_floating_point(item,in);
    }

// ----------------------------------------------------------------------------------------
// prototypes

    template <typename domain, typename range, typename compare, typename alloc>
    void serialize (
        const std::map<domain,range, compare, alloc>& item,
        std::ostream& out
    );

    template <typename domain, typename range, typename compare, typename alloc>
    void deserialize (
        std::map<domain, range, compare, alloc>& item,
        std::istream& in
    );

    template <typename domain, typename compare, typename alloc>
    void serialize (
        const std::set<domain, compare, alloc>& item,
        std::ostream& out
    );

    template <typename domain, typename compare, typename alloc>
    void deserialize (
        std::set<domain, compare, alloc>& item,
        std::istream& in
    );

    template <typename T, typename alloc>
    void serialize (
        const std::vector<T,alloc>& item,
        std::ostream& out
    );

    template <typename T, typename alloc>
    void deserialize (
        std::vector<T,alloc>& item,
        std::istream& in
    );

    inline void serialize (
        const std::string& item,
        std::ostream& out
    );

    inline void deserialize (
        std::string& item,
        std::istream& in
    );

    inline void serialize (
        const std::wstring& item,
        std::ostream& out
    );

    inline void deserialize (
        std::wstring& item,
        std::istream& in
    );

    inline void serialize (
        const ustring& item,
        std::ostream& out
    );

    inline void deserialize (
        ustring& item,
        std::istream& in
    );

    template <
        typename T
        >
    inline void serialize (
        const enumerable<T>& item,
        std::ostream& out
    );

    template <
        typename domain,
        typename range
        >
    inline void serialize (
        const map_pair<domain,range>& item,
        std::ostream& out
    );

    template <
        typename T,
        size_t length
        >
    inline void serialize (
        const T (&array)[length],
        std::ostream& out
    );

    template <
        typename T,
        size_t length
        >
    inline void deserialize (
        T (&array)[length],
        std::istream& in
    );

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    inline void serialize (
        bool item,
        std::ostream& out
    )
    {
        if (item)
            out << '1';
        else
            out << '0';

        if (!out)
            throw serialization_error("Error serializing object of type bool");
    }

    inline void deserialize (
        bool& item,
        std::istream& in
    )
    {
        int ch = in.get();
        if (ch != EOF)
        {
            if (ch == '1')
                item = true;
            else if (ch == '0')
                item = false;
            else
                throw serialization_error("Error deserializing object of type bool");
        }
        else
        {
            throw serialization_error("Error deserializing object of type bool");
        }
    }

// ----------------------------------------------------------------------------------------

    template <typename first_type, typename second_type>
    void serialize (
        const std::pair<first_type, second_type>& item,
        std::ostream& out
    )
    {
        try
        {
            serialize(item.first,out);
            serialize(item.second,out);
        }
        catch (serialization_error& e)
        { throw serialization_error(e.info + "\n   while serializing object of type std::pair"); }
    }

    template <typename first_type, typename second_type>
    void deserialize (
        std::pair<first_type, second_type>& item,
        std::istream& in
    )
    {
        try
        {
            deserialize(item.first,in);
            deserialize(item.second,in);
        }
        catch (serialization_error& e)
        { throw serialization_error(e.info + "\n   while deserializing object of type std::pair"); }
    }

// ----------------------------------------------------------------------------------------

    template <typename domain, typename range, typename compare, typename alloc>
    void serialize (
        const std::map<domain,range, compare, alloc>& item,
        std::ostream& out
    )
    {
        try
        {
            const unsigned long size = static_cast<unsigned long>(item.size());

            serialize(size,out);
            typename std::map<domain,range,compare,alloc>::const_iterator i;
            for (i = item.begin(); i != item.end(); ++i)
            {
                serialize(i->first,out);
                serialize(i->second,out);
            }

        }
        catch (serialization_error& e)
        { throw serialization_error(e.info + "\n   while serializing object of type std::map"); }
    }

    template <typename domain, typename range, typename compare, typename alloc>
    void deserialize (
        std::map<domain, range, compare, alloc>& item,
        std::istream& in
    )
    {
        try
        {
            item.clear();

            unsigned long size;
            deserialize(size,in);
            domain d;
            range r;
            for (unsigned long i = 0; i < size; ++i)
            {
                deserialize(d,in);
                deserialize(r,in);
                item[d] = r;
            }
        }
        catch (serialization_error& e)
        { throw serialization_error(e.info + "\n   while deserializing object of type std::map"); }
    }

// ----------------------------------------------------------------------------------------

    template <typename domain, typename compare, typename alloc>
    void serialize (
        const std::set<domain, compare, alloc>& item,
        std::ostream& out
    )
    {
        try
        {
            const unsigned long size = static_cast<unsigned long>(item.size());

            serialize(size,out);
            typename std::set<domain,compare,alloc>::const_iterator i;
            for (i = item.begin(); i != item.end(); ++i)
            {
                serialize(*i,out);
            }

        }
        catch (serialization_error& e)
        { throw serialization_error(e.info + "\n   while serializing object of type std::set"); }
    }

    template <typename domain, typename compare, typename alloc>
    void deserialize (
        std::set<domain, compare, alloc>& item,
        std::istream& in
    )
    {
        try
        {
            item.clear();

            unsigned long size;
            deserialize(size,in);
            domain d;
            for (unsigned long i = 0; i < size; ++i)
            {
                deserialize(d,in);
                item.insert(d);
            }
        }
        catch (serialization_error& e)
        { throw serialization_error(e.info + "\n   while deserializing object of type std::set"); }
    }

// ----------------------------------------------------------------------------------------

    template <typename alloc>
    void serialize (
        const std::vector<bool,alloc>& item,
        std::ostream& out
    )
    {
        std::vector<unsigned char> temp(item.size());
        for (unsigned long i = 0; i < item.size(); ++i)
        {
            if (item[i])
                temp[i] = '1';
            else
                temp[i] = '0';
        }
        serialize(temp, out);
    }

    template <typename alloc>
    void deserialize (
        std::vector<bool,alloc>& item,
        std::istream& in
    )
    {
        std::vector<unsigned char> temp;
        deserialize(temp, in);
        item.resize(temp.size());
        for (unsigned long i = 0; i < temp.size(); ++i)
        {
            if (temp[i] == '1')
                item[i] = true;
            else
                item[i] = false;
        }
    }

// ----------------------------------------------------------------------------------------

    template <typename T, typename alloc>
    void serialize (
        const std::vector<T,alloc>& item,
        std::ostream& out
    )
    {
        try
        {
            const unsigned long size = static_cast<unsigned long>(item.size());

            serialize(size,out);
            for (unsigned long i = 0; i < item.size(); ++i)
                serialize(item[i],out);
        }
        catch (serialization_error& e)
        { throw serialization_error(e.info + "\n   while serializing object of type std::vector"); }
    }

    template <typename T, typename alloc>
    void deserialize (
        std::vector<T, alloc>& item,
        std::istream& in
    )
    {
        try
        {
            unsigned long size;
            deserialize(size,in);
            item.resize(size);
            for (unsigned long i = 0; i < size; ++i)
                deserialize(item[i],in);
        }
        catch (serialization_error& e)
        { throw serialization_error(e.info + "\n   while deserializing object of type std::vector"); }
    }

// ----------------------------------------------------------------------------------------

    template <typename alloc>
    void serialize (
        const std::vector<char,alloc>& item,
        std::ostream& out
    )
    {
        try
        {
            const unsigned long size = static_cast<unsigned long>(item.size());
            serialize(size,out);
            if (item.size() != 0)
                out.write(&item[0], item.size());
        }
        catch (serialization_error& e)
        { throw serialization_error(e.info + "\n   while serializing object of type std::vector"); }
    }

    template <typename alloc>
    void deserialize (
        std::vector<char, alloc>& item,
        std::istream& in
    )
    {
        try
        {
            unsigned long size;
            deserialize(size,in);
            item.resize(size);
            if (item.size() != 0)
                in.read(&item[0], item.size());
        }
        catch (serialization_error& e)
        { throw serialization_error(e.info + "\n   while deserializing object of type std::vector"); }
    }

// ----------------------------------------------------------------------------------------

    template <typename alloc>
    void serialize (
        const std::vector<unsigned char,alloc>& item,
        std::ostream& out
    )
    {
        try
        {
            const unsigned long size = static_cast<unsigned long>(item.size());
            serialize(size,out);
            if (item.size() != 0)
                out.write((char*)&item[0], item.size());
        }
        catch (serialization_error& e)
        { throw serialization_error(e.info + "\n   while serializing object of type std::vector"); }
    }

    template <typename alloc>
    void deserialize (
        std::vector<unsigned char, alloc>& item,
        std::istream& in
    )
    {
        try
        {
            unsigned long size;
            deserialize(size,in);
            item.resize(size);
            if (item.size() != 0)
                in.read((char*)&item[0], item.size());
        }
        catch (serialization_error& e)
        { throw serialization_error(e.info + "\n   while deserializing object of type std::vector"); }
    }

// ----------------------------------------------------------------------------------------

    inline void serialize (
        const std::string& item,
        std::ostream& out
    )
    {
        const unsigned long size = static_cast<unsigned long>(item.size());
        try{ serialize(size,out); }
        catch (serialization_error& e)
        { throw serialization_error(e.info + "\n   while serializing object of type std::string"); }

        out.write(item.c_str(),size);
        if (!out) throw serialization_error("Error serializing object of type std::string");
    }

    inline void deserialize (
        std::string& item,
        std::istream& in
    )
    {
        unsigned long size;
        try { deserialize(size,in); }
        catch (serialization_error& e)
        { throw serialization_error(e.info + "\n   while deserializing object of type std::string"); }

        item.resize(size);
        if (size != 0)
        {
            in.read(&item[0],size);
            if (!in) throw serialization_error("Error deserializing object of type std::string");
        }
    }

// ----------------------------------------------------------------------------------------

    inline void serialize (
        const std::wstring& item,
        std::ostream& out
    )
    {
        const unsigned long size = static_cast<unsigned long>(item.size());
        try{ serialize(size,out); }
        catch (serialization_error& e)
        { throw serialization_error(e.info + "\n   while serializing object of type std::wstring"); }

        for (unsigned long i = 0; i < item.size(); ++i)
            serialize(item[i], out);
        if (!out) throw serialization_error("Error serializing object of type std::wstring");
    }

    inline void deserialize (
        std::wstring& item,
        std::istream& in
    )
    {
        unsigned long size;
        try { deserialize(size,in); }
        catch (serialization_error& e)
        { throw serialization_error(e.info + "\n   while deserializing object of type std::wstring"); }

        item.resize(size);
        for (unsigned long i = 0; i < item.size(); ++i)
            deserialize(item[i],in);

        if (!in) throw serialization_error("Error deserializing object of type std::wstring");
    }

// ----------------------------------------------------------------------------------------

    inline void serialize (
        const ustring& item,
        std::ostream& out
    )
    {
        const unsigned long size = static_cast<unsigned long>(item.size());
        try{ serialize(size,out); }
        catch (serialization_error& e)
        { throw serialization_error(e.info + "\n   while serializing object of type ustring"); }

        for (unsigned long i = 0; i < item.size(); ++i)
            serialize(item[i], out);
        if (!out) throw serialization_error("Error serializing object of type ustring");
    }

    inline void deserialize (
        ustring& item,
        std::istream& in
    )
    {
        unsigned long size;
        try { deserialize(size,in); }
        catch (serialization_error& e)
        { throw serialization_error(e.info + "\n   while deserializing object of type ustring"); }

        item.resize(size);
        for (unsigned long i = 0; i < item.size(); ++i)
            deserialize(item[i],in);

        if (!in) throw serialization_error("Error deserializing object of type ustring");
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    inline void serialize (
        const enumerable<T>& item,
        std::ostream& out
    )
    {
        try
        {
            item.reset();
            serialize(item.size(),out);
            while (item.move_next())
                serialize(item.element(),out);
            item.reset();
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while serializing object of type enumerable");
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range
        >
    inline void serialize (
        const map_pair<domain,range>& item,
        std::ostream& out
    )
    {
        try
        {
            serialize(item.key(),out);
            serialize(item.value(),out);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while serializing object of type map_pair");
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        size_t length
        >
    inline void serialize (
        const T (&array)[length],
        std::ostream& out
    )
    {
        try
        {
            serialize(length,out);
            for (size_t i = 0; i < length; ++i)
                serialize(array[i],out);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while serializing a C style array");
        }
    }

    template <
        size_t length
        >
    inline void serialize (
        const char (&array)[length],
        std::ostream& out
    )
    {
        if (length != 0 && array[length-1] == '\0')
        {
            // If this is a null terminated string then don't serialize the trailing null.
            // We do this so that the serialization format for C-strings is the same as
            // std::string.
            serialize(length-1, out);
            out.write(array, length-1);
            if (!out)
                throw serialization_error("Error serializing a C-style string");
        }
        else
        {
            try
            {
                serialize(length,out);
            }
            catch (serialization_error& e)
            {
                throw serialization_error(e.info + "\n   while serializing a C style array");
            }
            if (length != 0)
                out.write(array, length);
            if (!out)
                throw serialization_error("Error serializing a C-style string");
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        size_t length
        >
    inline void deserialize (
        T (&array)[length],
        std::istream& in
    )
    {
        size_t size;
        try
        {
            deserialize(size,in);
            if (size == length)
            {
                for (size_t i = 0; i < length; ++i)
                    deserialize(array[i],in);
            }
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while deserializing a C style array");
        }

        if (size != length)
            throw serialization_error("Error deserializing a C style array, lengths do not match");
    }

    template <
        size_t length
        >
    inline void deserialize (
        char (&array)[length],
        std::istream& in
    )
    {
        size_t size;
        try
        {
            deserialize(size,in);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while deserializing a C style array");
        }

        if (size == length)
        {
            in.read(array, size);
            if (!in)
                throw serialization_error("Error deserializing a C-style array");
        }
        else if (size+1 == length)
        {
            // In this case we are deserializing a C-style array so we need to add the null
            // terminator.
            in.read(array, size);
            array[size] = '\0';
            if (!in)
                throw serialization_error("Error deserializing a C-style string");
        }
        else
        {
            throw serialization_error("Error deserializing a C style array, lengths do not match");
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    inline void serialize (
        const std::complex<T>& item,
        std::ostream& out
    )
    {
        try
        {
            serialize(item.real(),out);
            serialize(item.imag(),out);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while serializing an object of type std::complex");
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    inline void deserialize (
        std::complex<T>& item,
        std::istream& in
    )
    {
        try
        {
            T real, imag;
            deserialize(real,in);
            deserialize(imag,in);
            item = std::complex<T>(real,imag);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while deserializing an object of type std::complex");
        }
    }

// ----------------------------------------------------------------------------------------

    class proxy_serialize
    {
    public:
        explicit proxy_serialize (
            const std::string& filename
        )
        {
            fout.reset(new std::ofstream(filename.c_str(), std::ios::binary));
            if (!(*fout))
                throw serialization_error("Unable to open " + filename + " for writing.");
        }

        template <typename T>
        inline proxy_serialize& operator<<(const T& item)
        {
            serialize(item, *fout);
            return *this;
        }

    private:
        shared_ptr<std::ofstream> fout;
    };

    class proxy_deserialize
    {
    public:
        explicit proxy_deserialize (
            const std::string& filename
        )
        {
            fin.reset(new std::ifstream(filename.c_str(), std::ios::binary));
            if (!(*fin))
                throw serialization_error("Unable to open " + filename + " for reading.");
        }

        template <typename T>
        inline proxy_deserialize& operator>>(T& item)
        {
            deserialize(item, *fin);
            return *this;
        }

    private:
        shared_ptr<std::ifstream> fin;
    };

    inline proxy_serialize serialize(const std::string& filename)
    { return proxy_serialize(filename); }
    inline proxy_deserialize deserialize(const std::string& filename)
    { return proxy_deserialize(filename); }

// ----------------------------------------------------------------------------------------

}

// forward declare the MessageLite object so we can reference it below.
namespace google
{
    namespace protobuf
    {
        class MessageLite;
    }
}

namespace dlib
{

    /*!A is_protocol_buffer
        This is a template that tells you if a type is a Google protocol buffer object.
    !*/

    template <typename T, typename U = void >
    struct is_protocol_buffer
    {
        static const bool value = false;
    };

    template <typename T>
    struct is_protocol_buffer <T,typename enable_if<is_convertible<T*,::google::protobuf::MessageLite*> >::type  >
    {
        static const bool value = true;
    };

    template <typename T>
    typename enable_if<is_protocol_buffer<T> >::type serialize(const T& item, std::ostream& out)
    {
        // Note that Google protocol buffer messages are not self delimiting
        // (see https://developers.google.com/protocol-buffers/docs/techniques)
        // This means they don't record their length or where they end, so we have
        // to record this information ourselves.  So we save the size as a little endian 32bit
        // integer prefixed onto the front of the message.

        byte_orderer bo;

        // serialize into temp string
        std::string temp;
        if (!item.SerializeToString(&temp))
            throw dlib::serialization_error("Error while serializing a Google Protocol Buffer object.");
        if (temp.size() > std::numeric_limits<uint32>::max())
            throw dlib::serialization_error("Error while serializing a Google Protocol Buffer object, message too large.");

        // write temp to the output stream
        uint32 size = temp.size();
        bo.host_to_little(size);
        out.write((char*)&size, sizeof(size));
        out.write(temp.c_str(), temp.size());
    }

    template <typename T>
    typename enable_if<is_protocol_buffer<T> >::type deserialize(T& item, std::istream& in)
    {
        // Note that Google protocol buffer messages are not self delimiting
        // (see https://developers.google.com/protocol-buffers/docs/techniques)
        // This means they don't record their length or where they end, so we have
        // to record this information ourselves.  So we save the size as a little endian 32bit
        // integer prefixed onto the front of the message.

        byte_orderer bo;

        uint32 size = 0;
        // read the size
        in.read((char*)&size, sizeof(size));
        bo.little_to_host(size);
        if (!in || size == 0)
            throw dlib::serialization_error("Error while deserializing a Google Protocol Buffer object.");

        // read the bytes into temp
        std::string temp;
        temp.resize(size);
        in.read(&temp[0], size);

        // parse temp into item
        if (!in || !item.ParseFromString(temp))
        {
            throw dlib::serialization_error("Error while deserializing a Google Protocol Buffer object.");
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SERIALIZe_


dlib C++ Library - make_mfp_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_MAKE_MFp_ABSTRACT_
#ifdef DLIB_MAKE_MFp_ABSTRACT_

#include "member_function_pointer_kernel_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    member_function_pointer<> make_mfp (
        T& object,
        void (T::*cb)()
    );
    /*!
        requires
            - cb == a valid member function pointer for class T
        ensures
            - returns a member function pointer object MFP such that:
                - MFP.is_set() == true
                - calls to MFP() will call (object.*cb)()
    !*/

    template <
        typename T
        >
    member_function_pointer<> make_mfp (
        const T& object,
        void (T::*cb)()const
    );
    /*!
        requires
            - cb == a valid member function pointer for class T
        ensures
            - returns a member function pointer object MFP such that:
                - MFP.is_set() == true
                - calls to MFP() will call (object.*cb)()
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename A1
        >
    member_function_pointer<A1> make_mfp (
        T& object,
        void (T::*cb)(A1 a1)
    );
    /*!
        requires
            - cb == a valid member function pointer for class T
        ensures
            - returns a member function pointer object MFP such that:
                - MFP.is_set() == true
                - calls to MFP(a1) will call (object.*cb)(a1)
    !*/

    template <
        typename T,
        typename A1
        >
    member_function_pointer<A1> make_mfp (
        const T& object,
        void (T::*cb)(A1 a1)const
    );
    /*!
        requires
            - cb == a valid member function pointer for class T
        ensures
            - returns a member function pointer object MFP such that:
                - MFP.is_set() == true
                - calls to MFP(a1) will call (object.*cb)(a1)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename A1,
        typename A2
        >
    member_function_pointer<A1,A2> make_mfp (
        T& object,
        void (T::*cb)(A1 a1, A2 a2)
    );
    /*!
        requires
            - cb == a valid member function pointer for class T
        ensures
            - returns a member function pointer object MFP such that:
                - MFP.is_set() == true
                - calls to MFP(a1,a2) will call (object.*cb)(a1,a2)
    !*/

    template <
        typename T,
        typename A1,
        typename A2
        >
    member_function_pointer<A1,A2> make_mfp (
        const T& object,
        void (T::*cb)(A1 a1, A2 a2)const
    );
    /*!
        requires
            - cb == a valid member function pointer for class T
        ensures
            - returns a member function pointer object MFP such that:
                - MFP.is_set() == true
                - calls to MFP(a1,a2) will call (object.*cb)(a1,a2)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename A1,
        typename A2,
        typename A3
        >
    member_function_pointer<A1,A2,A3> make_mfp (
        T& object,
        void (T::*cb)(A1 a1, A2 a2, A3 a3)
    );
    /*!
        requires
            - cb == a valid member function pointer for class T
        ensures
            - returns a member function pointer object MFP such that:
                - MFP.is_set() == true
                - calls to MFP(a1,a2,a3) will call (object.*cb)(a1,a2,a3)
    !*/

    template <
        typename T,
        typename A1,
        typename A2,
        typename A3
        >
    member_function_pointer<A1,A2,A3> make_mfp (
        const T& object,
        void (T::*cb)(A1 a1, A2 a2, A3 a3)const
    );
    /*!
        requires
            - cb == a valid member function pointer for class T
        ensures
            - returns a member function pointer object MFP such that:
                - MFP.is_set() == true
                - calls to MFP(a1,a2,a3) will call (object.*cb)(a1,a2,a3)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename A1,
        typename A2,
        typename A3,
        typename A4
        >
    member_function_pointer<A1,A2,A3,A4> make_mfp (
        T& object,
        void (T::*cb)(A1 a1, A2 a2, A3 a3, A4 a4)
    );
    /*!
        requires
            - cb == a valid member function pointer for class T
        ensures
            - returns a member function pointer object MFP such that:
                - MFP.is_set() == true
                - calls to MFP(a1,a2,a3,a4) will call (object.*cb)(a1,a2,a3,a4)
    !*/

    template <
        typename T,
        typename A1,
        typename A2,
        typename A3,
        typename A4
        >
    member_function_pointer<A1,A2,A3,A4> make_mfp (
        const T& object,
        void (T::*cb)(A1 a1, A2 a2, A3 a3, A4 a4)const
    );
    /*!
        requires
            - cb == a valid member function pointer for class T
        ensures
            - returns a member function pointer object MFP such that:
                - MFP.is_set() == true
                - calls to MFP(a1,a2,a3,a4) will call (object.*cb)(a1,a2,a3,a4)
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MAKE_MFp_ABSTRACT_


dlib C++ Library - time_this.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_TIME_THIs_
#define DLIB_TIME_THIs_

#include "platform.h"

#ifndef WIN32

#include <sys/times.h>
#include <limits.h>
#include <unistd.h>
#include <iostream>
// ----------------------------------------------------------------------------------------

#define TIME_THIS_TO(_tt_op,_tt_out)                                                        \
    {                                                                                       \
        clock_t _tt_start, _tt_end;                                                         \
        tms _tt_timesbuf;                                                                   \
        _tt_start = times(&_tt_timesbuf);                                                   \
        _tt_op;                                                                             \
        _tt_end = times(&_tt_timesbuf);                                                     \
        long _tt_ticks = sysconf(_SC_CLK_TCK);                                              \
        if ((double)(_tt_end-_tt_start)/(double)_tt_ticks < 1)                              \
        {                                                                                   \
            _tt_out << "\ntime: "                                                           \
            << (int)(1000*((double)(_tt_end-_tt_start)/(double)_tt_ticks)) << "ms\n";       \
        }                                                                                   \
        else                                                                                \
        {                                                                                   \
            _tt_out << "\ntime: "                                                           \
                      << (double)(_tt_end-_tt_start)/(double)_tt_ticks << "sec\n";          \
        }                                                                                   \
    }                                                                                       \

#define TIME_THIS(_tt_op)  TIME_THIS_TO(_tt_op,std::cout)

// ----------------------------------------------------------------------------------------

#endif

#ifdef WIN32

#include "windows_magic.h"
#include <windows.h>    // for GetTickCount()
#include <iostream>

// ----------------------------------------------------------------------------------------

#define TIME_THIS_TO(_tt_op,_tt_out)                                                        \
    {                                                                                       \
        unsigned long _tt_count = GetTickCount();                                           \
        _tt_op;                                                                             \
        _tt_count = GetTickCount() - _tt_count;                                             \
        if (_tt_count < 1000)                                                               \
        {                                                                                   \
            _tt_out << "\ntime: " << _tt_count << "ms\n";                                   \
        }                                                                                   \
        else                                                                                \
        {                                                                                   \
            _tt_out << "\ntime: " << static_cast<double>(_tt_count)/1000 << "sec\n";        \
        }                                                                                   \
    }                                                                                       \

#define TIME_THIS(_tt_op) TIME_THIS_TO(_tt_op,std::cout)

// ----------------------------------------------------------------------------------------

#endif

#endif // DLIB_TIME_THIs_


dlib C++ Library - timing.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_TImING_Hh_
#define DLIB_TImING_Hh_

#include "misc_api.h"
#include <cstring>
#include "string.h"

#include <iostream>

// ----------------------------------------------------------------------------------------

/*!A timing

    This set of functions is useful for determining how much time is spent
    executing blocks of code.  Consider the following example:

    int main()
    {
        using namespace dlib::timing;
        for (int i = 0; i < 10; ++i)
        {
            // timing block #1
            start(1,"block #1");
            dlib::sleep(500);
            stop(1);

            // timing block #2
            start(2,"block #2");
            dlib::sleep(1000);
            stop(2);
        }

        print();
    }

    This program would output:
        Timing report:
            block #1: 5.0 seconds
            block #2: 10.0 seconds

    So we spent 5 seconds in block #1 and 10 seconds in block #2

    Additionally, note that you can use an RAII style timing block object.  For
    example, if we wanted to find out how much time we spent in a loop a convenient
    way to do this would be as follows:

    int main()
    {
        using namespace dlib::timing;
        for (int i = 0; i < 10; ++i)
        {
            block tb(1, "main loop");

            dlib::sleep(1500);
        }

        print();
    }

    This program would output:
        Timing report:
            block main loop: 15.0 seconds

!*/

// ----------------------------------------------------------------------------------------

namespace dlib
{
    namespace timing
    {
        const int TIME_SLOTS = 500;
        const int NAME_LENGTH = 40;

        inline uint64* time_buf()
        {
            static uint64 buf[TIME_SLOTS] = {0};
            return buf;
        }

        inline char* name_buf(int i, const char* name)
        {
            static char buf[TIME_SLOTS][NAME_LENGTH] = {{0}};
            // if this name buffer is empty then copy name into it
            if (buf[i][0] == '\0')
            {
                using namespace std;
                strncpy(buf[i], name, NAME_LENGTH-1);
                buf[i][NAME_LENGTH-1] = '\0';
            }
            // return the name buffer
            return buf[i];
        }

        inline timestamper& ts()
        {
            static timestamper ts_;
            return ts_;
        }

        inline void start(int i )
        {
            time_buf()[i] -= ts().get_timestamp();
        }

        inline void start(int i, const char* name)
        {
            time_buf()[i] -= ts().get_timestamp();
            name_buf(i,name);
        }

        inline void stop(int i)
        {
            time_buf()[i] += ts().get_timestamp();
        }

        inline void print()
        {
            using namespace std;
            cout << "Timing report: " << endl;

            // figure out how long the longest name is going to be.
            unsigned long max_name_length = 0;
            for (int i = 0; i < TIME_SLOTS; ++i)
            {
                string name;
                // Check if the name buffer is empty.  Use the name it contains if it isn't.
                if (name_buf(i,"")[0] != '\0')
                    name = cast_to_string(i) + ": " + name_buf(i,"");
                else
                    name = cast_to_string(i);
                max_name_length = std::max<unsigned long>(max_name_length, name.size());
            }

            for (int i = 0; i < TIME_SLOTS; ++i)
            {
                if (time_buf()[i] != 0)
                {
                    double time = time_buf()[i]/1000.0;
                    string name;
                    // Check if the name buffer is empty.  Use the name it contains if it isn't.
                    if (name_buf(i,"")[0] != '\0')
                        name = cast_to_string(i) + ": " + name_buf(i,"");
                    else
                        name = cast_to_string(i);

                    // make sure the name is always the same length.  Do so by padding with spaces
                    if (name.size() < max_name_length)
                        name += string(max_name_length-name.size(),' ');

                    if (time < 1000)
                        cout << "  " << name << ": " << time << " milliseconds" << endl;
                    else if (time < 1000*1000)
                        cout << "  " << name << ": " << time/1000.0 << " seconds" << endl;
                    else if (time < 1000*1000*60)
                        cout << "  " << name << ": " << time/1000.0/60.0 << " minutes" << endl;
                    else
                        cout << "  " << name << ": " << time/1000.0/60.0/60.0 << " hours" << endl;
                }
            }
        }

        inline void clear()
        {
            for (int i = 0; i < TIME_SLOTS; ++i)
            {
                // clear timing buffer
                time_buf()[i] = 0;
                // clear name buffer
                name_buf(i,"")[0] = '\0';
            }
        }

        struct block
        {
            /*!
                WHAT THIS OBJECT REPRESENTS
                    This is an RAII tool for calling start() and stop()
            !*/

            block(int i):idx(i) {start(idx);}
            block(int i, const char* str):idx(i) {start(idx,str);}
            ~block() { stop(idx); }
            const int idx;
        };
    }
}

#endif // DLIB_TImING_Hh_


dlib C++ Library - sqlite_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SQLiTE_ABSTRACT_H_
#ifdef DLIB_SQLiTE_ABSTRACT_H_

#include <iostream>
#include <vector>
#include "../algs.h"
#include <sqlite3.h>
#include "../smart_pointers.h"

// ----------------------------------------------------------------------------------------

namespace dlib
{

// ----------------------------------------------------------------------------------------

    struct sqlite_error : public error
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is the exception object used by the SQLite tools to indicate
                that an error has occurred.  Any of the functions defined in this
                file might throw this exception.
        !*/
    };

// ----------------------------------------------------------------------------------------

    class database : noncopyable
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is a C++ wrapper around a SQLite database connection
                handle and therefore represents a SQLite database file.

                Note that this wrapper is targeted at SQLite Version 3.

                Note also that whenever SQLite indicates an error has occurred
                this object will throw the sqlite_error exception.
        !*/

    public:
        database(
        );
        /*!
            ensures
                - #is_open() == false
        !*/

        database (
            const std::string& file
        );
        /*!
            ensures
                - opens the indicated database file or creates a new
                  database with the given name if one doesn't already exist.
                - #get_database_filename() == file
                - #is_open() == true
        !*/

        ~database (
        );
        /*!
            ensures
                - safely disposes of any SQLite database connection.  If
                  any statement objects still exist which reference this database
                  then the SQLite database connection won't be fully closed
                  until those statement objects are also destroyed.  This allows
                  for any destruction order between database and statement objects.
        !*/

        void open (
            const std::string& file
        );
        /*!
            ensures
                - opens the indicated database file or creates a new
                  database with the given name if one doesn't already exist.
                - #get_database_filename() == file
                - #is_open() == true
                - safely disposes of any previous SQLite database connection.  If
                  any statement objects still exist which reference this database
                  then the SQLite database connection won't be fully closed
                  until those statement objects are also destroyed.
        !*/

        bool is_open (
        ) const;
        /*!
            ensures
                - if (this object has an open connection to a SQLite database) then
                    - returns true
                - else
                    - returns false
        !*/

        const std::string& get_database_filename (
        ) const;
        /*!
            requires
                - is_open() == true
            ensures
                - returns the name of the SQLite database file this object
                  currently has open.
        !*/

        void exec (
            const std::string& sql_statement
        );
        /*!
            requires
                - is_open() == true
            ensures
                - executes the supplied SQL statement against this database
        !*/

        int64 last_insert_rowid (
        ) const;
        /*!
            requires
                - is_open() == true
            ensures
                - Each element in a database table has a rowid which uniquely identifies
                  it.  Therefore, this routine returns the rowid of the most recent
                  successful INSERT into the database via this database instance.
                - If an INSERT has not been performed on the current database instance then
                  the return value is 0.  This is true even if the database is not empty.
                - See the sqlite documentation for the full details on how this function
                  behaves: http://www.sqlite.org/c3ref/last_insert_rowid.html
        !*/
    };

// ----------------------------------------------------------------------------------------

    class statement : noncopyable
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object represents a SQL statement which can be executed
                against a database object.  In particular, this object is a
                C++ wrapper around a SQLite prepared statement.

                Note that whenever SQLite indicates an error has occurred this
                object will throw the sqlite_error exception.

            BINDABLE SQL PARAMETERS
                Sometimes you want to execute a bunch of very similar SQL statements.
                For example, you might need to execute many insert statements where each
                statement changes only the value of a field.  Since it is somewhat
                costly to construct a statement object for each SQL operation, SQLite
                supports defining bindable parameters for a statement object.  This allows
                you to reuse the same statement object.

                Therefore, in SQL statements used with SQLite, wherever it is valid to
                include a string literal, one can use a parameter in one of the following
                forms:

                    ?
                    ?NNN
                    :AAA
                    $AAA
                    @AAA

               In the examples above, NNN is an integer value and AAA is an identifier.  A
               parameter initially has a value of NULL.  You can use the bind_*() routines
               to attach values to the parameters.  Each call to a bind_*() routine overrides
               prior bindings on the same parameter.

               Each SQL parameter has a numeric ID which is used to reference it when invoking
               a bind_*() routine.  The leftmost SQL parameter in a statement has an index of 1,
               the next parameter has an index of 2, and so on, except when the following rules
               apply.  When the same named SQL parameter is used more than once, second and
               subsequent occurrences have the same index as the first occurrence.  The index
               for named parameters can be looked up using the get_parameter_id() method if desired.
               The index for "?NNN" parameters is the value of NNN. The NNN value must be between
               1 and get_max_parameter_id().
        !*/

    public:
        statement (
            database& db,
            const std::string sql_statement
        );
        /*!
            requires
                - db.is_open() == true
            ensures
                - The given SQL statement can be executed against the given
                  database by calling exec().
                - #get_sql_string() == sql_statement
        !*/

        ~statement(
        );
        /*!
            ensures
                - any resources associated with this object have been freed.
        !*/

        const std::string& get_sql_string (
        ) const;
        /*!
            ensures
                - returns a copy of the SQL statement used to create this statement object.
        !*/

        void exec(
        );
        /*!
            ensures
                - #get_num_columns() == 0
                - executes the SQL statement get_sql_string() against the database
                  given to this object's constructor.
                - If this was a select statement then you can obtain the resulting
                  rows by calling move_next() and using the get_column_as_*() member
                  functions.
        !*/

    // ----------------------------

        bool move_next (
        );
        /*!
            ensures
                - if (there is a result row for this query) then
                    - #get_num_columns() == the number of columns in the result row.
                    - The get_column_as_*() routines can be used to access the elements
                      of the row data.
                    - returns true
                - else
                    - returns false
                    - #get_num_columns() == 0
        !*/

        unsigned long get_num_columns(
        ) const;
        /*!
            ensures
                - returns the number of columns of data available via the get_column_as_*()
                  routines.
        !*/

        template <
            typename T
            >
        void get_column (
            unsigned long idx,
            T& item
        ) const;
        /*!
            requires
                - idx < get_num_columns()
            ensures
                - This function automatically selects how to extract the column data based
                  on the type of item given. In particular:
                    - if (T is a 32bit or smaller built in integer type) then
                        - #item == get_column_as_int(idx)
                    - else if (T is a 64bit built in integer type) then
                        - #item == get_column_as_int64(idx)
                    - else if (T is float, double, or long double) then
                        - #item == get_column_as_double(idx)
                    - else if (T is std::string) then
                        - #item == get_column_as_text(idx)
                    - else
                        - invokes: get_column_as_object(idx, item)
        !*/

        const std::vector<char> get_column_as_blob (
            unsigned long idx
        ) const;
        /*!
            requires
                - idx < get_num_columns()
            ensures
                - returns the contents of the idx-th column as a binary BLOB.
        !*/

        template <
            typename T
            >
        void get_column_as_object (
            unsigned long idx,
            T& item
        ) const;
        /*!
            requires
                - idx < get_num_columns()
                - item is deserializable
                  (i.e. Calling deserialize(item, some_input_stream) reads an item
                  of type T from the some_input_stream stream)
            ensures
                - gets the contents of the idx-th column as a binary BLOB and then
                  deserializes it into item.
        !*/

        const std::string get_column_as_text (
            unsigned long idx
        ) const;
        /*!
            requires
                - idx < get_num_columns()
            ensures
                - returns the contents of the idx-th column as a text string.
        !*/

        double get_column_as_double (
            unsigned long idx
        ) const;
        /*!
            requires
                - idx < get_num_columns()
            ensures
                - returns the contents of the idx-th column as a double.
        !*/

        int get_column_as_int (
            unsigned long idx
        ) const;
        /*!
            requires
                - idx < get_num_columns()
            ensures
                - returns the contents of the idx-th column as an int.
        !*/

        int64 get_column_as_int64 (
            unsigned long idx
        ) const;
        /*!
            requires
                - idx < get_num_columns()
            ensures
                - returns the contents of the idx-th column as a 64bit int.
        !*/

        const std::string get_column_name (
            unsigned long idx
        ) const;
        /*!
            requires
                - idx < get_num_columns()
            ensures
                - returns the name of the idx-th column.  In particular:
                  The name of a result column is the value of the "AS" clause for
                  that column, if there is an AS clause. If there is no AS clause
                  then the name of the column is unspecified and may change from
                  one release of SQLite to the next.
        !*/

    // ----------------------------

        unsigned long get_max_parameter_id (
        ) const;
        /*!
            ensures
                - returns the max parameter ID value which can be used with the
                  bind_() member functions defined below.
                - In SQLite, the default value of this limit is usually 999.
        !*/

        unsigned long get_parameter_id (
            const std::string& name
        ) const;
        /*!
            ensures
                - if (This SQL statement contains a SQL parameter with the given name) then
                    - returns the parameter_id number which can be used in the bind_*()
                      member functions defined below.
                - else
                    - returns 0
        !*/

        template <
            typename T
            >
        void bind (
            unsigned long parameter_id,
            const T& item
        ) const;
        /*!
            requires
                - 1 <= parameter_id <= get_max_parameter_id()
            ensures
                - This function automatically selects how to bind item to a statement based
                  on the type of item given.  In particular:
                    - if (T is a 32bit or smaller built in integer type) then
                        - invokes: bind_int(parameter_id, item)
                    - else if (T is a 64bit built in integer type) then
                        - invokes: bind_int64(parameter_id, item)
                    - else if (T is float, double, or long double) then
                        - invokes: bind_double(parameter_id, item)
                    - else if (T is std::string) then
                        - invokes: bind_text(parameter_id, item)
                    - else
                        - invokes: bind_object(parameter_id, item)
        !*/

        void bind_blob (
            unsigned long parameter_id,
            const std::vector<char>& item
        );
        /*!
            requires
                - 1 <= parameter_id <= get_max_parameter_id()
            ensures
                - #get_num_columns() == 0
                - binds the value of item into the SQL parameter indicated by
                  parameter_id.
        !*/

        template <
            typename T
            >
        void bind_object (
            unsigned long parameter_id,
            const T& item
        );
        /*!
            requires
                - 1 <= parameter_id <= get_max_parameter_id()
                - item is serializable
                  (i.e. Calling serialize(item, some_output_stream) writes an item
                  of type T to the some_output_stream stream)
            ensures
                - #get_num_columns() == 0
                - binds the value of item into the SQL parameter indicated by
                  parameter_id.  This is performed by serializing item and then
                  binding it as a binary BLOB.
        !*/

        void bind_double (
            unsigned long parameter_id,
            const double& item
        );
        /*!
            requires
                - 1 <= parameter_id <= get_max_parameter_id()
            ensures
                - #get_num_columns() == 0
                - binds the value of item into the SQL parameter indicated by
                  parameter_id.
        !*/

        void bind_int (
            unsigned long parameter_id,
            const int& item
        );
        /*!
            requires
                - 1 <= parameter_id <= get_max_parameter_id()
            ensures
                - #get_num_columns() == 0
                - binds the value of item into the SQL parameter indicated by
                  parameter_id.
        !*/

        void bind_int64 (
            unsigned long parameter_id,
            const int64& item
        );
        /*!
            requires
                - 1 <= parameter_id <= get_max_parameter_id()
            ensures
                - #get_num_columns() == 0
                - binds the value of item into the SQL parameter indicated by
                  parameter_id.
        !*/

        void bind_null (
            unsigned long parameter_id
        );
        /*!
            requires
                - 1 <= parameter_id <= get_max_parameter_id()
            ensures
                - #get_num_columns() == 0
                - binds a NULL to the SQL parameter indicated by parameter_id.
        !*/

        void bind_text (
            unsigned long parameter_id,
            const std::string& item
        );
        /*!
            requires
                - 1 <= parameter_id <= get_max_parameter_id()
            ensures
                - #get_num_columns() == 0
                - binds the value of item into the SQL parameter indicated by
                  parameter_id.
        !*/

    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SQLiTE_ABSTRACT_H_


dlib C++ Library - sqlite_tools_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SQLiTE_TOOLS_ABSTRACT_H_
#ifdef DLIB_SQLiTE_TOOLS_ABSTRACT_H_

#include "sqlite_abstract.h"

// ----------------------------------------------------------------------------------------

namespace dlib
{

    class transaction : noncopyable
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is a tool for creating exception safe
                database transactions.
        !*/

    public:
        transaction (
            database& db
        );
        /*!
            ensures
                - Begins a database transaction which will be rolled back
                  if commit() isn't called eventually.
                - In particular, performs: db.exec("begin transaction");
        !*/

        void commit (
        );
        /*!
            ensures
                - if (commit() hasn't already been called) then
                    - Commits all changes made during this database transaction.
                    - In particular, performs: db.exec("commit");
                - else
                    - does nothing
        !*/

        ~transaction(
        );
        /*!
            ensures
                - if (commit() was never called) then
                    - rolls back any changes made to the database during this transaction.
                    - In particular, performs: db.exec("rollback");
                - else
                    - does nothing
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    void query_object (
        database& db,
        const std::string& query,
        T& item
    );
    /*!
        ensures
            - executes the given SQL query against db.  If the query results in a
              single row and column being returned then the data in the column is
              interpreted as a binary BLOB and deserialized into item.
        throws
            - sqlite_error or serialization_error if an error occurs which prevents
              this operation from succeeding.

    !*/

// ----------------------------------------------------------------------------------------

    std::string query_text (
        database& db,
        const std::string& query
    );
    /*!
        ensures
            - executes the given SQL query against db.  If the query results in a
              single row and column being returned then the data in the column is
              converted to text and returned.
        throws
            - sqlite_error if an error occurs which prevents this operation from
              succeeding.
    !*/

// ----------------------------------------------------------------------------------------

    double query_double (
        database& db,
        const std::string& query
    );
    /*!
        ensures
            - executes the given SQL query against db.  If the query results in a
              single row and column being returned then the data in the column is
              converted to a double and returned.
        throws
            - sqlite_error if an error occurs which prevents this operation from
              succeeding.
    !*/

// ----------------------------------------------------------------------------------------

    int query_int (
        database& db,
        const std::string& query
    );
    /*!
        ensures
            - executes the given SQL query against db.  If the query results in a
              single row and column being returned then the data in the column is
              converted to an int and returned.
        throws
            - sqlite_error if an error occurs which prevents this operation from
              succeeding.
    !*/

// ----------------------------------------------------------------------------------------

    int64 query_int64 (
        database& db,
        const std::string& query
    );
    /*!
        ensures
            - executes the given SQL query against db.  If the query results in a
              single row and column being returned then the data in the column is
              converted to an int64 and returned.
        throws
            - sqlite_error if an error occurs which prevents this operation from
              succeeding.
    !*/

// ----------------------------------------------------------------------------------------

    const std::vector<char> query_blob (
        database& db,
        const std::string& query
    );
    /*!
        ensures
            - executes the given SQL query against db.  If the query results in a
              single row and column being returned then the data in the column is
              returned as a binary BLOB.
        throws
            - sqlite_error if an error occurs which prevents this operation from
              succeeding.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SQLiTE_TOOLS_H_


dlib C++ Library - Networking

The Library
  • Algorithms
  • API Wrappers
  • Bayesian Nets
  • Compression
  • Containers
  • Graph Tools
  • Image Processing
  • Linear Algebra
  • Machine Learning
  • Metaprogramming
  • Miscellaneous
  • Networking
  • Optimization
  • Parsing

Help/Info
  • Dlib Blog
  • Examples: C++
    • 3D Point Cloud
    • Assignment Learning
    • Base64 Encoder
    • Bayesian Network From Disk
    • Bayesian Network GUI
    • Bayesian Network
    • Bridge
    • BSP
    • C-Support Vector Machine
    • Cmd Line Parser
    • Compress Stream
    • Config File Reader
    • Custom Trainers
    • Directory Navigation
    • Empirical Kernel Map
    • Face Detection
    • Face Landmark Detection
    • FHOG Feature Extraction
    • FHOG Object Detection
    • Graph Labeling
    • GUI
    • Hough Transform
    • HTTP Server
    • Image
    • IO Socket Streams
    • IO Streams Server
    • Kernel Centroid
    • Kernel K-Means Clustering
    • Kernel Ridge Regression
    • Kernel RLS Filtering
    • Kernel RLS Regression
    • KRR Classification
    • Learning to Track
    • Linear Assignment Problems
    • Linear Manifold Regularizer
    • Linear Model Predictive Control
    • Logger Advanced
    • Logger Custom Output
    • Logger
    • Matrix Expressions
    • Matrix
    • Member Function Pointer
    • Model Selection
    • Multiclass Classification
    • Multithreaded Object
    • Neural Network
    • Non-Linear Least Squares
    • Nu-Support Vector Machine
    • Numerical Integration
    • Object Detector Advanced
    • Object Detector
    • One Class Classifiers
    • Online SVM
    • Optimization
    • Parallel For Loops
    • Pipe 2
    • Pipe
    • Quantum Computing
    • Queue
    • Rank Features
    • Relevance Vector Classification
    • Relevance Vector Regression
    • Running Stats
    • Sequence Labeling
    • Sequence Segmentation
    • Sockets
    • Sockstreambuf
    • Sparse Vectors
    • SQLite
    • Std C++ Allocator
    • Structural Support Vector Machines
    • Support Vector Regression
    • SURF
    • SVM-Rank
    • Thread Function
    • Thread Pool
    • Threaded Object
    • Threads
    • Timer
    • Train Object Detector
    • Train Shape Predictor
    • Using Custom Kernels
    • Video Object Tracking
    • Webcam Face Pose Estimation
    • XML Parser
  • Examples: Python
    • Face Detector
    • Face Landmark Detection
    • find candidate object locations
    • Linear Assignment Problems
    • Sequence Segmenter
    • Structural Support Vector Machines
    • SVM-Rank
    • Train Object Detector
    • Train Shape Predictor
    • Video Object Tracking
  • FAQ
  • Forums
  • Home
  • How to compile
  • How to contribute
  • Index
  • Introduction
  • License
  • Python API
  • Suggested Books
  • Who uses dlib?

Current Release
  • Change Log
  • Release Notes
  • Version: 18.18

Last Modified:
Sep 13, 2015
Networking

This page documents tools built on top of the dlib sockets API. Therefore, all these tools are focused on providing some kind of higher level networking abstraction or service.

Objects
  • bridge
  • iosockstream
  • linker
  • server
  • server_http
  • server_iostream
  • sockstreambuf

BSP
  • bsp_connect
  • bsp_context
  • bsp_listen
  • bsp_listen_dynamic_port

[top]

bridge

This object is a tool for bridging a pipe object between two network connected applications.

The bridge object is designed to link two pipes together as efficiently as possible. To demonstrate its speed, I ran two experiments where a bridge was used to connect a desktop PC to a laptop, both running Ubuntu 12.04 and connected via gigabit ethernet. The first experiment is to test its bulk transfer speed while the second experiment measures how many separate objects the bridge can transfer each second.

In the first experiment, 1-megapixel images, represented with array<rgb_pixel> objects, were sent. The transfer rate was 112 megabytes/second, saturating the gigabit ethernet link. The second experiment used a pipe<char> and bridge to send individual char variables over the network. In this experiment, I was able to send 3.2 million objects a second (i.e. the receiving end was getting a char back from pipe::dequeue() 3.2 million times each second).

For reference, these experiments were carried out on a desktop with a 2.67GHz Intel Core-i7 CPU and a laptop with a 2.20GHz Intel Core-i7 CPU.

C++ Example Programs: bridge_ex.cpp
More Details...
#include <dlib/bridge.h>
[top]

bsp_connect

This function spawns a BSP job consisting of a number of network hosts as well as the local host.

C++ Example Programs: bsp_ex.cpp
More Details...
#include <dlib/bsp.h>
[top]

bsp_context

This is a tool used to implement algorithms using the Bulk Synchronous Parallel (BSP) computing model. In particular, this object defines the API used for communication between BSP jobs.

C++ Example Programs: bsp_ex.cpp
More Details...
#include <dlib/bsp.h>
[top]

bsp_listen

This function listens for a TCP connection from the bsp_connect routine. Once this connection is established, a user supplied function will be executed and it will then be able to participate in a BSP computation as one of the processing nodes.

C++ Example Programs: bsp_ex.cpp
More Details...
#include <dlib/bsp.h>
[top]

bsp_listen_dynamic_port

This function listens for a TCP connection from the bsp_connect routine. Once this connection is established, a user supplied function will be executed and it will then be able to participate in a BSP computation as one of the processing nodes. This function has the additional ability to select the listening TCP port automatically from the set of available ports.
More Details...
#include <dlib/bsp.h>
[top]

iosockstream

This is an iostream object that reads/writes from a TCP network connection.

C++ Example Programs: iosockstream_ex.cpp
More Details...
#include <dlib/iosockstream.h>
[top]

linker

This object represents something that takes two connections and lets them talk to each other. ie. any incoming data from one connection is passed unaltered to the other and vice versa.
More Details...
#include <dlib/linker.h>
[top]

server

This object represents a server that listens on a port and spawns new threads to handle each new connection. It also manages the connections and threads for you.

C++ Example Programs: sockets_ex.cpp
More Details...
#include <dlib/server.h>
[top]

server_http

This is an extension of the server_iostream object which turns it into a simple HTTP server.

C++ Example Programs: server_http_ex.cpp
More Details...
#include <dlib/server.h>
[top]

server_iostream

This is an extension of the server object that redefines the on_connect() function so that instead of giving you a connection object you get an istream and ostream object.

C++ Example Programs: server_iostream_ex.cpp
More Details...
#include <dlib/server.h>
[top]

sockstreambuf

This object represents a stream buffer for connection objects. If you are considering using this object then you should also take a look at the iosockstream.

C++ Example Programs: sockstreambuf_ex.cpp
More Details...
#include <dlib/sockstreambuf.h>


dlib C++ Library - bridge_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_BRIDGe_ABSTRACT_
#ifdef DLIB_BRIDGe_ABSTRACT_

#include <string>
#include "../pipe/pipe_kernel_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    struct connect_to_ip_and_port
    {
        connect_to_ip_and_port (
            const std::string& ip,
            unsigned short port
        );
        /*!
            requires
                - is_ip_address(ip) == true
                - port != 0
            ensures
                - this object will represent a request to make a TCP connection
                  to the given IP address and port number.
        !*/
    };

    connect_to_ip_and_port connect_to (
        const network_address& addr
    );
    /*!
        requires
            - addr.port != 0
        ensures
            - converts the given network_address object into a connect_to_ip_and_port
              object.
    !*/

    struct listen_on_port
    {
        listen_on_port(
            unsigned short port
        );
        /*!
            requires
                - port != 0
            ensures
                - this object will represent a request to listen on the given
                  port number for incoming TCP connections.
        !*/
    };

    template <
        typename pipe_type
        >
    bridge_transmit_decoration<pipe_type> transmit (
        pipe_type& p
    );
    /*!
        requires
            - pipe_type is some kind of dlib::pipe object
            - the objects in the pipe must be serializable
        ensures
            - Adds a type decoration to the given pipe, marking it as a transmit pipe, and
              then returns it.
    !*/

    template <
        typename pipe_type
        >
    bridge_receive_decoration<pipe_type> receive (
        pipe_type& p
    );
    /*!
        requires
            - pipe_type is some kind of dlib::pipe object
            - the objects in the pipe must be serializable
        ensures
            - Adds a type decoration to the given pipe, marking it as a receive pipe, and
              then returns it.
    !*/

// ----------------------------------------------------------------------------------------

    struct bridge_status
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This simple struct represents the state of a bridge object.  A
                bridge is either connected or not.  If it is connected then it
                is connected to a foreign host with an IP address and port number
                as indicated by this object.
        !*/

        bridge_status(
        );
        /*!
            ensures
                - #is_connected == false
                - #foreign_port == 0
                - #foreign_ip == ""
        !*/

        bool is_connected;
        unsigned short foreign_port;
        std::string foreign_ip;
    };

// ----------------------------------------------------------------------------------------

    class bridge : noncopyable
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is a tool for bridging a dlib::pipe object between
                two network connected applications.

                Note also that this object contains a dlib::logger object
                which will log various events taking place inside a bridge.
                If you want to see these log messages then enable the logger
                named "dlib.bridge".

            BRIDGE PROTOCOL DETAILS
                The bridge object creates a single TCP connection between
                two applications.  Whenever it sends an object from a pipe
                over a TCP connection it sends a byte with the value 1 followed
                immediately by the serialized copy of the object from the pipe.
                The serialization is performed by calling the global serialize()
                function.

                Additionally, a bridge object will periodically send bytes with
                a value of 0 to ensure the TCP connection remains alive.  These
                are just read and ignored.
        !*/

    public:

        bridge (
        );
        /*!
            ensures
                - this object is properly initialized
                - #get_bridge_status().is_connected == false
        !*/

        template <typename T, typename U, typename V>
        bridge (
            T network_parameters,
            U pipe1,
            V pipe2
        );
        /*!
            requires
                - T is of type connect_to_ip_and_port or listen_on_port
                - U and V are of type bridge_transmit_decoration or bridge_receive_decoration,
                  however, U and V must be of different types (i.e. one is a receive type and
                  another a transmit type).
            ensures
                - this object is properly initialized
                - performs: reconfigure(network_parameters, pipe1, pipe2)
                  (i.e. using this constructor is identical to using the default constructor
                  and then calling reconfigure())
        !*/

        template <typename T, typename U>
        bridge (
            T network_parameters,
            U pipe
        );
        /*!
            requires
                - T is of type connect_to_ip_and_port or listen_on_port
                - U is of type bridge_transmit_decoration or bridge_receive_decoration.
            ensures
                - this object is properly initialized
                - performs: reconfigure(network_parameters, pipe)
                  (i.e. using this constructor is identical to using the default constructor
                  and then calling reconfigure())
        !*/

        ~bridge (
        );
        /*!
            ensures
                - blocks until all resources associated with this object have been destroyed.
        !*/

        void clear (
        );
        /*!
            ensures
                - returns this object to its default constructed state.  That is, it will
                  be inactive, neither maintaining a connection nor attempting to acquire one.
                - Any active connections or listening sockets will be closed.
        !*/

        bridge_status get_bridge_status (
        ) const;
        /*!
            ensures
                - returns the current status of this bridge object. In particular, returns
                  an object BS such that:
                    - BS.is_connected == true if and only if the bridge has an active TCP
                      connection to another computer.
                    - if (BS.is_connected) then
                        - BS.foreign_ip == the IP address of the remote host we are connected to.
                        - BS.foreign_port == the port number on the remote host we are connected to.
                    - else if (the bridge has previously been connected to a remote host but hasn't been
                               reconfigured or cleared since) then
                        - BS.foreign_ip == the IP address of the remote host we were connected to.
                        - BS.foreign_port == the port number on the remote host we were connected to.
                    - else
                        - BS.foreign_ip == ""
                        - BS.foreign_port == 0
        !*/

        template < typename T, typename R >
        void reconfigure (
            listen_on_port network_parameters,
            bridge_transmit_decoration<T> transmit_pipe,
            bridge_receive_decoration<R> receive_pipe
        );
        /*!
            ensures
                - This object will begin listening on the port specified by network_parameters
                  for incoming TCP connections.  Any previous bridge state is cleared out.
                - Onces a connection is established we will:
                    - Stop accepting new connections.
                    - Begin dequeuing objects from the transmit pipe and serializing them over
                      the TCP connection.
                    - Begin deserializing objects from the TCP connection and enqueueing them
                      onto the receive pipe.
                - if (the current TCP connection is lost) then
                    - This object goes back to listening for a new connection.
                - if (the receive pipe can contain bridge_status objects) then
                    - Whenever the bridge's status changes the updated bridge_status will be
                      enqueued onto the receive pipe unless the change was a TCP disconnect
                      resulting from a user calling reconfigure(), clear(), or destructing this
                      bridge.  The status contents are defined by get_bridge_status().
            throws
                - socket_error
                  This exception is thrown if we are unable to open the listening socket.
        !*/
        template < typename T, typename R >
        void reconfigure (
            listen_on_port network_parameters,
            bridge_receive_decoration<R> receive_pipe,
            bridge_transmit_decoration<T> transmit_pipe
        );
        /*!
            ensures
                - performs reconfigure(network_parameters, transmit_pipe, receive_pipe)
        !*/
        template < typename T >
        void reconfigure (
            listen_on_port network_parameters,
            bridge_transmit_decoration<T> transmit_pipe
        );
        /*!
            ensures
                - This function is identical to the above two reconfigure() functions
                  except that there is no receive pipe.
        !*/
        template < typename R >
        void reconfigure (
            listen_on_port network_parameters,
            bridge_receive_decoration<R> receive_pipe
        );
        /*!
            ensures
                - This function is identical to the above three reconfigure() functions
                  except that there is no transmit pipe.
        !*/

        template <typename T, typename R>
        void reconfigure (
            connect_to_ip_and_port network_parameters,
            bridge_transmit_decoration<T> transmit_pipe,
            bridge_receive_decoration<R> receive_pipe
        );
        /*!
            ensures
                - This object will begin making TCP connection attempts to the IP address and port
                  specified by network_parameters.  Any previous bridge state is cleared out.
                - Onces a connection is established we will:
                    - Stop attempting new connections.
                    - Begin dequeuing objects from the transmit pipe and serializing them over
                      the TCP connection.
                    - Begin deserializing objects from the TCP connection and enqueueing them
                      onto the receive pipe.
                - if (the current TCP connection is lost) then
                    - This object goes back to attempting to make a TCP connection with the
                      IP address and port specified by network_parameters.
                - if (the receive pipe can contain bridge_status objects) then
                    - Whenever the bridge's status changes the updated bridge_status will be
                      enqueued onto the receive pipe unless the change was a TCP disconnect
                      resulting from a user calling reconfigure(), clear(), or destructing this
                      bridge.  The status contents are defined by get_bridge_status().
        !*/
        template <typename T, typename R>
        void reconfigure (
            connect_to_ip_and_port network_parameters,
            bridge_receive_decoration<R> receive_pipe,
            bridge_transmit_decoration<T> transmit_pipe
        );
        /*!
            ensures
                - performs reconfigure(network_parameters, transmit_pipe, receive_pipe)
        !*/
        template <typename T>
        void reconfigure (
            connect_to_ip_and_port network_parameters,
            bridge_transmit_decoration<T> transmit_pipe
        );
        /*!
            ensures
                - This function is identical to the above two reconfigure() functions
                  except that there is no receive pipe.
        !*/
        template <typename R>
        void reconfigure (
            connect_to_ip_and_port network_parameters,
            bridge_receive_decoration<R> receive_pipe
        );
        /*!
            ensures
                - This function is identical to the above three reconfigure() functions
                  except that there is no transmit pipe.
        !*/

    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_BRIDGe_ABSTRACT_


dlib C++ Library - iosockstream_abstract.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_IOSOCKSTrEAM_ABSTRACT_Hh_
#ifdef DLIB_IOSOCKSTrEAM_ABSTRACT_Hh_

#include "../sockstreambuf/sockstreambuf_abstract.h"

#include <iostream>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class iosockstream : public std::iostream
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is an iostream object that reads/writes from a TCP network connection.

                Note that any attempt to read from this stream will automatically flush the
                stream's output buffers.

            THREAD SAFETY
                It is not safe for multiple threads to make concurrent accesses to the same
                instance of this object (except for calls to shutdown() which are always
                threadsafe).  Therefore, you should mutex lock an instance of this object
                if you need to touch it from multiple threads.
        !*/

    public:

        iosockstream(
        );
        /*!
            ensures
                - #good() == false
        !*/

        iosockstream(
            const network_address& addr
        );
        /*!
            ensures
                - Attempts to connect to the given network address.
                - Calling this constructor is equivalent to calling the default constructor
                  and then invoking open(addr).
                - #good() == true
            throws
                - dlib::socket_error
                    This exception is thrown if there is some problem that prevents us from
                    creating the connection.
        !*/

        iosockstream(
            const network_address& addr,
            unsigned long timeout
        );
        /*!
            ensures
                - Attempts to connect to the given network address.
                - Calling this constructor is equivalent to calling the default constructor
                  and then invoking open(addr, timeout).
                - #good() == true
            throws
                - dlib::socket_error
                    This exception is thrown if there is some problem that prevents us from
                    creating the connection or if timeout milliseconds elapses before the
                    connect is successful.
        !*/

        ~iosockstream(
        );
        /*!
            ensures
                - Invokes close() before destructing the stream.  Therefore, any open
                  connection will be gracefully closed using the default timeout time.
                  This also means any data in the stream will be flushed to the connection.
        !*/

        void open (
            const network_address& addr
        );
        /*!
            ensures
                - This object will attempt to create a TCP connection with the remote host
                  indicated by addr.
                - Any previous connection in this iosockstream is closed by calling close()
                  before we make any new connection.
                - #good() == true
                  (i.e. the error flags are reset by calling open())
            throws
                - dlib::socket_error
                    This exception is thrown if there is some problem that prevents us from
                    creating the connection.
        !*/

        void open (
            const network_address& addr,
            unsigned long timeout
        );
        /*!
            ensures
                - This object will attempt to create a TCP connection with the remote host
                  indicated by addr.
                - Any previous connection in this iosockstream is closed by calling close()
                  before we make any new connection.
                - #good() == true
                  (i.e. the error flags are reset by calling open())
            throws
                - dlib::socket_error
                    This exception is thrown if there is some problem that prevents us from
                    creating the connection or if timeout milliseconds elapses before the
                    connect is successful.
        !*/

        void close(
            unsigned long timeout = 10000
        );
        /*!
            ensures
                - #good() == false
                - if (there is an active TCP connection) then
                    - Flushes any data buffered in the output part of the stream
                      to the connection.
                    - Performs a proper graceful close (i.e. like dlib::close_gracefully()).
                    - Will only wait timeout milliseconds for the buffer flush and graceful
                      close to finish before the connection is terminated forcefully.
                      Therefore, close() will only block for at most timeout milliseconds.
        !*/

        void terminate_connection_after_timeout (
            unsigned long timeout
        );
        /*!
            ensures
                - if (there is an active TCP connection) then
                    - Any operations on this TCP connection will return error or
                      end-of-file once timeout milliseconds have elapsed from this call to
                      terminate_connection_after_timeout().  This is true unless another
                      call to terminate_connection_after_timeout() is made which gives a
                      new time.  In this case, the previous call is forgotten and the
                      timeout is reset.
                    - This timeout only applies to the current TCP connection.  That is, if
                      the iosockstream is closed and a new connection is established, any
                      previous timeouts setup by terminate_connection_after_timeout() do
                      not apply.
                - else
                    - This function has no effect on this object.
        !*/

        void shutdown (
        );
        /*!
            ensures
                - Immediately closes the TCP connection and causes all I/O operations on
                  this object to return an error.
                - It is safe to call this function from any thread, therefore, you can use
                  it to signal when you want a connection to terminate from another thread.
        !*/
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_IOSOCKSTrEAM_ABSTRACT_Hh_


dlib C++ Library - linker_kernel_abstract.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_LINKER_KERNEl_ABSTRACT_
#ifdef DLIB_LINKER_KERNEl_ABSTRACT_

#include "../threads/threads_kernel_abstract.h"
#include "../sockets/sockets_kernel_abstract.h"

namespace dlib
{

    class linker
    {

        /*!
            INITIAL VALUE
                is_running() == false

            WHAT THIS OBJECT REPRESENTS
                This object represents something that takes two connections and lets
                them talk to each other.  i.e. any incoming data from one connection is
                passed unaltered to the other and vice versa.

                note that linker objects are not swappable.

                Also note that when one connection is closed shutdown_outgoing()
                is called on the other to signal that no more data will be sent
                in that direction on the connection.
                (i.e. the FIN packet is effectively also forwarded by the linker object)

            THREAD SAFETY
                all member functions are thread-safe.

        !*/

        public:

            linker(
            );
            /*!
                ensures
                    - #*this is properly initialized
                throws
                    - std::bad_alloc
                    - dlib::thread_error
            !*/

            linker (
                connection& a,
                connection& b
            );
            /*!
                ensures
                    - #*this is properly initialized
                    - immediately invokes link(a,b);
                      (i.e. using this constructor is the same as creating a linker with
                      the default constructor and then immediately invoking link() on it)
                throws
                    - std::bad_alloc
                    - dlib::thread_error
            !*/

            virtual ~linker(
            );
            /*!
                ensures
                    - all resources associated with *this have been released
            !*/

            void clear(
            );
            /*!
                ensures
                    - #*this has its initial value
                    - if (is_running()) then
                        - the two connections being linked will be shutdown()
                throws
                    - std::bad_alloc
                        if this exception is thrown then the linker object is unusable
                        until clear() is called and succeeds and
                        if is_running() then the connections will STILL be shutdown()
                        even though an exception is being thrown
            !*/

            bool is_running(
            ) const;
            /*!
                ensures
                    - returns true if link() is running else
                    - returns false if link() is not running or has released all its
                      resources and is about to terminate
                throws
                    - std::bad_alloc
            !*/

            void link (
                connection& a,
                connection& b
            );
            /*!
                requires
                    - is_running() == false
                ensures
                    - all incoming data from connection a will be forwarded to b
                    - all incoming data from connection b will be forwarded to a
                    - #a and #b will have been shutdown()
                    - link() will block until both of the connections have ended
                      or an error occurs
                throws
                    - std::bad_alloc
                        link() may throw this exception and if it does then the object
                        will be unusable until clear() is called and succeeds and
                        connections a and b will be shutdown()
                    - dlib::socket_error
                        link() will throw a this exception if one of the connections
                        returns an error value (being shutdown is not an error).
                        If this happens then the linker object will be cleared and
                        have its initial value.  note that if this happens then the
                        connections being linked will be shutdown()
                    - dlib::thread_error
                        link() will throw a this exception if there is a problem
                        creating new threads.  Or it may throw this exception if there
                        is a problem creating threading objects. If this happens
                        then the linker object will be cleared and have its initial value.
                        note that if this happens then the connections being linked will
                        be shutdown().
            !*/

        private:

            // restricted functions
            linker(linker&);        // copy constructor
            linker& operator=(linker&);    // assignment operator
    };

}

#endif // DLIB_LINKER_KERNEl_ABSTRACT_


dlib C++ Library - server_kernel_abstract.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SERVER_KERNEL_ABSTRACT_
#ifdef DLIB_SERVER_KERNEL_ABSTRACT_

#include "../threads/threads_kernel_abstract.h"
#include "../sockets/sockets_kernel_abstract.h"
#include <string>

namespace dlib
{
    class server
    {

        /*!
            INITIAL VALUE
                get_listening_ip()           == ""
                get_listening_port()         == 0
                is_running()                 == false
                get_max_connections()        == 1000
                get_graceful_close_timeout() == 500

            CALLBACK FUNCTIONS
            on_connect():
                To use this object inherit from it and define the pure virtual function
                on_connect.  Inside this function is where you will handle each new
                connection.  Note that the connection object passed to on_connect() should
                NOT be closed, just let the function end and it will be gracefully closed
                for you.  Also note that each call to on_connect() is run in its own
                thread.  Also note that on_connect() should NOT throw any exceptions,
                all exceptions must be dealt with inside on_connect() and cannot be
                allowed to leave.

            on_listening_port_assigned():
                This function is called to let the client know that the operating
                system has assigned a port number to the listening port.  This
                happens if a port number of zero was given.  Note that this
                function does not need to be defined.  If you don't care then
                don't define it and it will do nothing.  Note also that this function
                is NOT called in its own thread.  Thus, making it block might hang the
                server.

            WHAT THIS OBJECT REPRESENTS
                This object represents a server that listens on a port and spawns new
                threads to handle each new connection.

                Note that the clear() function does not return until all calls to
                on_connect() have finished and the start() function has been shutdown.
                Also note that when clear() is called all open connection objects
                will be shutdown().

                A note about get_max_connections(): when the maximum number of connections
                has been reached accept() will simply not be called until the number of
                open connections drops below get_max_connections().  This means connections
                will just wait to be serviced, rather than being outright refused.

            THREAD SAFETY
                All member functions are thread-safe.
        !*/

        public:

            server(
            );
            /*!
                ensures
                    - #*this is properly initialized
                throws
                    - std::bad_alloc
                    - dlib::thread_error
            !*/

            virtual ~server(
            );
            /*!
                requires
                    - is not called from any of server's callbacks
                ensures
                    - all resources associated with *this have been released
            !*/

            void clear(
            );
            /*!
                requires
                    - is not called from any of server's callbacks
                ensures
                    - #*this has its initial value
                    - all open connection objects passed to on_connect() are shutdown()
                    - blocks until all calls to on_connect() have finished
                    - blocks until the start() function has released all its resources
                throws
                    - std::bad_alloc
                        if this exception is thrown then the server object is unusable
                        until clear() is called and succeeds
            !*/

            void start (
            );
            /*!
                requires
                    - is_running() == false
                ensures
                    - starts listening on the port and ip specified by get_listening_ip()
                      and #get_listening_port() for new connections.
                    - if (get_listening_port() == 0) then
                        - a port to listen on will be automatically selected
                        - #get_listening_port() == the selected port being used
                    - if (get_listening_ip() == "" ) then
                        - all local IPs will be listened on
                    - blocks until clear() is called or an error occurs
                throws
                    - dlib::socket_error
                        start() will throw this exception if there is some problem binding
                        ports and/or starting the server or if there is a problem
                        accepting new connections while it's running.
                        If this happens then
                            - All open connection objects passed to on_connect() are shutdown()
                              and the exception will not be thrown until all on_connect() calls
                              have terminated.
                            - The server will be cleared and returned to its initial value.
                    - dlib::thread_error
                        start() will throw this exception if there is a problem
                        creating new threads.  Or it may throw this exception if there
                        is a problem creating threading objects.
                        If this happens then
                            - All open connection objects passed to on_connect() are shutdown()
                              and the exception will not be thrown until all on_connect() calls
                              have terminated.
                            - The server will be cleared and returned to its initial value.
                    - std::bad_alloc
                        start() may throw this exception and if it does then the object
                        will be unusable until clear() is called and succeeds
            !*/

            void start_async (
            );
            /*!
                ensures
                    - starts listening on the port and ip specified by get_listening_ip()
                      and #get_listening_port() for new connections.
                    - if (get_listening_port() == 0) then
                        - a port to listen on will be automatically selected
                        - #get_listening_port() == the selected port being used
                    - if (get_listening_ip() == "" ) then
                        - all local IPs will be listened on
                    - does NOT block.  That is, this function will return right away and
                      the server will run on a background thread until clear() or this
                      object's destructor is called (or until some kind of fatal error
                      occurs).
                    - if an error occurs in the background thread while the server is
                      running then it will shut itself down, set is_running() to false, and
                      log the error to a dlib::logger object.
                    - calling start_async() on a running server has no effect.
                throws
                    - dlib::socket_error
                        start_async() will throw this exception if there is some problem binding
                        ports and/or starting the server.
                        If this happens then
                            - The server will be cleared and returned to its initial value.
            !*/

            bool is_running (
            ) const;
            /*!
                ensures
                    - returns true if start() is running
                    - returns false if start() is not running or has released all
                      its resources and is about to terminate
                throws
                    - std::bad_alloc
            !*/

            int get_max_connections (
            ) const;
            /*!
                ensures
                    - returns the maximum number of connections the server will accept
                      at a time.
                    - returns 0 if the server will accept any number of connections
                throws
                    - std::bad_alloc
            !*/

            const std::string get_listening_ip (
            ) const;
            /*!
                ensures
                    - returns the local ip to listen for new connections on
                    - returns "" if ALL local ips are to be listened on
                throws
                    - std::bad_alloc
            !*/

            int get_listening_port (
            ) const;
            /*!
                ensures
                    - returns the local port number to listen for new connections on
                    - returns 0 if the local port number has not yet been set
                throws
                    - std::bad_alloc
            !*/

            void set_listening_port (
                int port
            );
            /*!
                requires
                    - port >= 0
                    - is_running() == false
                ensures
                    - #get_listening_port() == port
                throws
                    - std::bad_alloc
            !*/

            void set_listening_ip (
                const std::string& ip
            );
            /*!
                requires
                    - is_ip_address(ip) == true or ip == ""
                    - is_running() == false
                ensures
                    - #get_listening_ip() == ip
                throws
                    - std::bad_alloc
            !*/

            void set_max_connections (
                int max
            );
            /*!
                requires
                    - max >= 0
                ensures
                    - #get_max_connections() == max
                throws
                    - std::bad_alloc
            !*/

            void set_graceful_close_timeout (
                unsigned long timeout
            );
            /*!
                ensures
                    - #get_graceful_close_timeout() == timeout
            !*/

            unsigned long get_graceful_close_timeout (
            ) const;
            /*!
                ensures
                    - When on_connect() terminates, it will close the connection using
                      close_gracefully().  This is done so that any data still in the
                      operating system's output buffers gets a chance to be properly
                      transmitted to the remote host.  Part of this involves waiting for
                      the remote host to close their end of the connection.  Therefore,
                      get_graceful_close_timeout() returns the timeout, in milliseconds,
                      that we wait for the remote host to close their end of the
                      connection.  This is the timeout value given to close_gracefully().
            !*/

        private:

            virtual void on_connect (
                connection& new_connection
            )=0;
            /*!
                requires
                    - on_connect() is run in its own thread
                    - is_running() == true
                    - the number of current connections < get_max_connection()
                    - new_connection == the new connection to the server which is
                      to be serviced by this call to on_connect()
                ensures
                    - when new_connection is shutdown() on_connect() will terminate
                    - this function will not call clear()
                throws
                    - does not throw any exceptions
            !*/

            // do nothing by default
            virtual void on_listening_port_assigned (
            ) {}
            /*!
                requires
                    - is called if a listening port of zero was specified and
                      an actual port number has just been assigned to the server
                ensures
                    - this function will not block
                    - this function will not call clear()
                throws
                    - does not throw any exceptions
            !*/

            // restricted functions
            server(server&);        // copy constructor
            server& operator=(server&);    // assignment operator
    };

}

#endif // DLIB_SERVER_KERNEL_ABSTRACT_


dlib C++ Library - server_http_abstract.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net), Steven Van Ingelgem
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SERVER_HTTp_ABSTRACT_
#ifdef DLIB_SERVER_HTTp_ABSTRACT_

#include "server_iostream_abstract.h"
#include <iostream>
#include <string>
#include <map>

namespace dlib
{

// -----------------------------------------------------------------------------------------

    template <
        typename Key,
        typename Value,
        typename Comparer = std::less<Key>
        >
    class constmap : public std::map<Key, Value, Comparer>
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is simply an extension to the std::map that allows you
                to use the operator[] accessor with a constant map.
        !*/
    public:

        const Value& operator[](
            const Key& k
        ) const;
        /*!
            ensures
                - if (this->find(k) != this->end()) then
                    - This map contains the given key
                    - return the value associated with the given key
                - else
                    - return a default initialized Value object
        !*/

        Value& operator[](
            const Key& k
        ) { return std::map<Key, Value>::operator [](k); }
        /*!
            ensures
                - This function does the same thing as the normal std::map operator[]
                  function.
                - if (this->find(k) != this->end()) then
                    - This map contains the given key
                    - return the value associated with the given key
                - else
                    - Adds a new entry into the map that is associated with the
                      given key.  The new entry will be default initialized and
                      this function returns a reference to it.
        !*/
    };

    typedef constmap<std::string, std::string> key_value_map;
    // This version of key_value_map treats the key string as being case-insensitive.
    // For example, a key string of "Content-Type" would access the same element as a key
    // of "content-type".
    typedef constmap<std::string, std::string, less_case_insensitive> key_value_map_ci;

// -----------------------------------------------------------------------------------------

    struct incoming_things
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object contains all the various bits of information that describe a
                HTTP request that comes into a web server.

                For a detailed discussion of the fields of this object, see the
                server_http::on_request() method defined later in this file.
        !*/

        incoming_things (
            const std::string& foreign_ip_,
            const std::string& local_ip_,
            unsigned short foreign_port_,
            unsigned short local_port_
        );
        /*!
            ensures
                - #foreign_ip = foreign_ip_
                - #foreign_port = foreign_port_
                - #local_ip = local_ip_
                - #local_port = local_port_
        !*/

        std::string path;
        std::string request_type;
        std::string content_type;
        std::string protocol;
        std::string body;

        key_value_map    queries;
        key_value_map    cookies;
        key_value_map_ci headers;

        std::string    foreign_ip;
        unsigned short foreign_port;
        std::string    local_ip;
        unsigned short local_port;
    };

    struct outgoing_things
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object contains all the various bits of information that describe a
                HTTP response from a web server.

                For a detailed discussion of the fields of this object, see the
                server_http::on_request() method defined later in this file.
        !*/

        outgoing_things(
        );
        /*!
            ensures
                - #http_return == 200
                - #http_return_status == "OK"
        !*/

        key_value_map    cookies;
        key_value_map_ci headers;
        unsigned short   http_return;
        std::string      http_return_status;
    };

// -----------------------------------------------------------------------------------------

    class http_parse_error : public error
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is an exception thrown by the parse_http_request() routine if
                there is a problem.
        !*/
    };

// -----------------------------------------------------------------------------------------

    unsigned long parse_http_request (
        std::istream& in,
        incoming_things& incoming,
        unsigned long max_content_length
    );
    /*!
        ensures
            - Attempts to read a HTTP GET, POST, or PUT request from the given input
              stream.
            - Reads all headers of the request and puts them into #incoming.  In particular,
              this function populates the following fields:
                - #incoming.path
                - #incoming.request_type
                - #incoming.content_type
                - #incoming.protocol
                - #incoming.queries
                - #incoming.cookies
                - #incoming.headers
            - This function also populates the #incoming.body field if and only if the
              Content-Type field is equal to "application/x-www-form-urlencoded".
              Otherwise, the content is not read from the stream.
        throws
            - http_parse_error
                This exception is thrown if the Content-Length coming from the web
                browser is greater than max_content_length or if any other problem
                is detected with the request.
    !*/

    void read_body (
        std::istream& in,
        incoming_things& incoming
    );
    /*!
        requires
            - parse_http_request(in,incoming,max_content_length) has already been called
              and therefore populated the fields of incoming.
        ensures
            - if (incoming.body has already been populated with the content of an HTTP
              request) then
                - this function does nothing
            - else
                - reads the body of the HTTP request into #incoming.body.
    !*/

    void write_http_response (
        std::ostream& out,
        outgoing_things outgoing,
        const std::string& result
    );
    /*!
        ensures
            - Writes an HTTP response, defined by the data in outgoing, to the given output
              stream.
            - The result variable is written out as the content of the response.
    !*/

    void write_http_response (
        std::ostream& out,
        const http_parse_error& e
    );
    /*!
        ensures
            - Writes an HTTP error response based on the information in the exception
              object e.
    !*/

    void write_http_response (
        std::ostream& out,
        const std::exception& e
    );
    /*!
        ensures
            - Writes an HTTP error response based on the information in the exception
              object e.
    !*/

// -----------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------

    class server_http : public server_iostream
    {

        /*!
            WHAT THIS EXTENSION DOES FOR server_iostream
                This extension turns the server object into a simple HTTP server.  It only
                handles HTTP GET, PUT and POST requests and each incoming request triggers
                the on_request() callback.

            COOKIE STRINGS
                The strings returned in the cookies key_value_map should be of the following form:
                    key:   cookie_name
                    value: cookie contents; expires=Fri, 31-Dec-2010 23:59:59 GMT; path=/; domain=.example.net

                You don't have to supply all the extra cookie arguments.  So if you just want to
                set a cookie that will expire when the client's browser is closed you can
                just say something like incoming.cookies["cookie_name"] = "cookie contents";

            HTTP HEADERS
                The HTTP headers in the incoming.headers and outgoing.headers are the name/value pairs
                of HTTP headers.  For example, the HTTP header "Content-Type: text/html" would be
                encoded such that outgoing.headers["Content-Type"] == "text/html".

                Also note that if you wish to change the content type of your response to the
                client you may do so by setting the "Content-Type" header to whatever you like.
                However, setting this field manually is not necessary as it will default to
                "text/html" if you don't explicitly set it to something.
        !*/

    public:

        server_http (
        );
        /*!
            ensures
                - #get_max_content_length() == 10*1024*1024
        !*/

        unsigned long get_max_content_length (
        ) const;
        /*!
            ensures
                - returns the max allowable content length, in bytes, of the post back to
                  the web server.  If a client attempts to send more data than this then an
                  error number 413 is returned back to the client and the request is not
                  processed by the web server.
        !*/

        void set_max_content_length (
            unsigned long max_length
        );
        /*!
            ensures
                - #get_max_content_length() == max_length
        !*/

    private:

        virtual const std::string on_request (
            const incoming_things& incoming,
            outgoing_things& outgoing
        ) = 0;
        /*!
            requires
                - on_request() is called when there is an HTTP GET or POST request to be serviced
                - on_request() is run in its own thread
                - is_running() == true
                - the number of current on_request() functions running < get_max_connection()
                - in incoming:
                    - incoming.path == the path being requested by this request
                    - incoming.request_type == the type of request, GET or POST
                    - incoming.content_type == the content type associated with this request
                    - incoming.protocol == The protocol being used by the web browser (e.g. HTTP/1.1)
                    - incoming.body == a string that contains the data that was posted back to the
                      web server by the client (e.g. The string has the length specified by the
                      Content-Length header).
                    - incoming.body.size() < get_max_content_length()
                    - incoming.queries == a map that contains all the key/value pairs in the query
                      string of this request.  The key and value strings of the query string will
                      have been decoded back into their original form before being sent to this
                      function (i.e. '+' decoded back to ' ' and "%hh" into its corresponding
                      ascii value.  So the URL-encoding is decoded automatically)
                    - incoming.cookies == The set of cookies that came from the client along with
                      this request.  The cookies will have been decoded back to normal form
                      from the URL-encoding.
                    - incoming.headers == a map that contains all the incoming HTTP headers
                      from the client web browser.
                    - incoming.foreign_ip == the foreign ip address for this request
                    - incoming.foreign_port == the foreign port number for this request
                    - incoming.local_ip == the IP of the local interface this request is coming in on
                    - incoming.local_port == the local port number this request is coming in on
                - in outgoing:
                    - outgoing.cookies.size() == 0
                    - outgoing.headers.size() == 0
                    - outgoing.http_return == 200
                    - outgoing.http_return_status == "OK"
            ensures
                - This function returns the HTML page to be displayed as the response to this request.
                - this function will not call clear()
                - #outgoing.cookies == a set of new cookies to pass back to the client along
                  with the result of this request.  (Note that URL-encoding is automatically applied
                  so you don't have to do it yourself)
                - #outgoing.headers == a set of additional headers you wish to appear in the
                  HTTP response to this request.  (This may be empty, the minimum needed headers
                  will be added automatically if you don't set them)
                - outgoing.http_return and outgoing.http_return_status may be set to override the
                  default HTTP return code of 200 OK
            throws
                - throws only exceptions derived from std::exception.  If an exception is thrown
                  then the error string from the exception is returned to the web browser.
        !*/

    // -----------------------------------------------------------------------
    //                        Implementation Notes
    // -----------------------------------------------------------------------

        virtual void on_connect (
            std::istream& in,
            std::ostream& out,
            const std::string& foreign_ip,
            const std::string& local_ip,
            unsigned short foreign_port,
            unsigned short local_port,
            uint64
        )
        /*!
            on_connect() is the function defined by server_iostream which is overloaded by
            server_http.  In particular, the server_http's implementation is shown below.
            In it you can see how the server_http parses the incoming http request, gets a
            response by calling on_request(), and sends it back using the helper routines
            defined at the top of this file.

            Therefore, if you want to modify the behavior of the HTTP server, for example,
            to do some more complex data streaming requiring direct access to the
            iostreams, then you can do so by defining your own on_connect() routine.  In
            particular, the default implementation shown below is a good starting point.
        !*/
        {
            try
            {
                incoming_things incoming(foreign_ip, local_ip, foreign_port, local_port);
                outgoing_things outgoing;

                parse_http_request(in, incoming, get_max_content_length());
                read_body(in, incoming);
                const std::string& result = on_request(incoming, outgoing);
                write_http_response(out, outgoing, result);
            }
            catch (http_parse_error& e)
            {
                write_http_response(out, e);
            }
            catch (std::exception& e)
            {
                write_http_response(out, e);
            }
        }
    };

}

#endif // DLIB_SERVER_HTTp_ABSTRACT_


dlib C++ Library - server_iostream_abstract.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SERVER_IOSTREAm_ABSTRACT_
#ifdef DLIB_SERVER_IOSTREAm_ABSTRACT_

#include "server_kernel_abstract.h"
#include <iostream>
#include <string>
#include "../uintn.h"

namespace dlib
{

    class server_iostream : public server
    {

        /*!
            WHAT THIS EXTENSION DOES FOR server
                This extension redefines the on_connect() function so that
                instead of giving you a connection object you get an istream
                and ostream object.

            THREAD SAFETY
                Note that in on_connect() the input stream in is tied to the output stream
                out.  This means that when you read from in it will modify out and thus
                it is not safe to touch in and out concurrently from different threads
                unless you untie them (which you do by saying in.tie(0);)
        !*/

    protected:

        void shutdown_connection (
            uint64 id
        );
        /*!
            ensures
                - if (there is a connection currently being serviced with the given id) then
                    - the specified connection is shutdown. (i.e. connection::shutdown() is
                      called on it so the iostreams operating on it will return EOF)
        !*/

    private:

        virtual void on_connect (
            std::istream& in,
            std::ostream& out,
            const std::string& foreign_ip,
            const std::string& local_ip,
            unsigned short foreign_port,
            unsigned short local_port,
            uint64 connection_id
        )=0;
        /*!
            requires
                - on_connect() is called when there is a new TCP connection that needs
                  to be serviced.
                - in == the input stream that reads data from the new connection
                - out == the output stream that writes data to the new connection
                - in.tie() == &out (i.e. when you read from in it automatically calls out.flush())
                - foreign_ip == the foreign ip address for this connection
                - foreign_port == the foreign port number for this connection
                - local_ip == the IP of the local interface this connection is using
                - local_port == the local port number for this connection
                - on_connect() is run in its own thread
                - is_running() == true
                - the number of current connections < get_max_connection()
                - connection_id == an integer that uniquely identifies this connection.
                  It can be used by shutdown_connection() to terminate this connection.
            ensures
                - when the iostreams hit EOF on_connect() will terminate.
                  (because this is how clear() signals you the server is shutting down)
                - this function will not call clear()
            throws
                - does not throw any exceptions
        !*/

    };

}

#endif // DLIB_SERVER_IOSTREAm_ABSTRACT_


dlib C++ Library - sockstreambuf_abstract.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_SOCKSTREAMBUF_ABSTRACT_
#ifdef DLIB_SOCKSTREAMBUF_ABSTRACT_

#include <iosfwd>
#include <streambuf>
#include "../sockets/sockets_kernel_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class sockstreambuf : public std::streambuf
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object represents a stream buffer capable of writing to and
                reading from TCP connections.

            NOTE:
                For a sockstreambuf EOF is when the connection has closed or otherwise
                returned some kind of error.

                Also note that any data written to the streambuf may be buffered
                internally.  So if you need to ensure that data is actually sent then you
                should flush the stream.

                A read operation is guaranteed to block until the number of bytes
                requested has arrived on the connection.  It will never keep blocking
                once enough data has arrived.

            THREADING
                Generally speaking, this object has the same kind of threading
                restrictions as a connection object.  those being:
                - Do not try to write to a sockstreambuf from more than one thread.
                - Do not try to read from a sockstreambuf from more than one thread.
                - You may call shutdown() on the connection object and this will
                  cause any reading or writing calls to end.  To the sockstreambuf it
                  will appear the same as hitting EOF.  (note that EOF for a sockstreambuf
                  means that the connection has closed)
                - It is safe to read from and write to the sockstreambuf at the same time
                  from different threads so long as flushes_output_on_read()==false.
                - It is not safe to try to putback a char and read from the stream from
                  different threads
        !*/
    public:
        sockstreambuf (
            connection* con
        );
        /*!
            requires
                - con == a valid connection object
            ensures
                - *this will read from and write to con
                - #flushes_output_on_read() == false
            throws
                - std::bad_alloc
        !*/

        sockstreambuf (
            const scoped_ptr<connection>& con
        );
        /*!
            requires
                - con == a valid connection object
            ensures
                - *this will read from and write to con
                - #flushes_output_on_read() == false
            throws
                - std::bad_alloc
        !*/

        ~sockstreambuf (
        );
        /*!
            requires
                - get_connection() object has not been deleted
            ensures
                - sockstream buffer is destructed but the connection object will
                  NOT be closed.
                - Any buffered data is flushed to the connection.
        !*/

        connection* get_connection (
        );
        /*!
            ensures
                - returns a pointer to the connection object which this buffer
                  reads from and writes to
        !*/

        void flush_output_on_read (
        );
        /*!
            ensures
                - #flushes_output_on_read() == true
        !*/

        bool flushes_output_on_read (
        ) const;
        /*!
            ensures
                - This function returns true if this object will flush its output buffer
                  to the network socket before performing any network read.
                - if (flushes_output_on_read() == true)
                    - It is not safe to make concurrent read and write calls to this object.
        !*/

        void do_not_flush_output_on_read (
        );
        /*!
            ensures
                - #flushes_output_on_read() == false
        !*/

    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SOCKSTREAMBUF_ABSTRACT_


dlib C++ Library - bsp_abstract.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_BsP_ABSTRACT_Hh_
#ifdef DLIB_BsP_ABSTRACT_Hh_

#include "../noncopyable.h"
#include "../sockets/sockets_extensions_abstract.h"
#include <vector>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class bsp_context : noncopyable
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is a tool used to implement algorithms using the Bulk Synchronous
                Parallel (BSP) computing model.  A BSP algorithm is composed of a number of
                processing nodes, each executing in parallel.  The general flow of
                execution in each processing node is the following:
                    1. Do work locally on some data.
                    2. Send some messages to other nodes.
                    3. Receive messages from other nodes.
                    4. Go to step 1 or terminate if complete.

                To do this, each processing node needs an API used to send and receive
                messages.  This API is implemented by the bsp_connect object which provides
                these services to a BSP node.

                Note that BSP processing nodes are spawned using the bsp_connect() and
                bsp_listen() routines defined at the bottom of this file.  For example, to
                start a BSP algorithm consisting of N processing nodes, you would make N-1
                calls to bsp_listen() and one call to bsp_connect().  The call to
                bsp_connect() then initiates the computation on all nodes.

                Finally, note that there is no explicit barrier synchronization function
                you call at the end of step 3.  Instead, you can simply call a method such
                as try_receive() until it returns false.  That is, the bsp_context's
                receive methods incorporate a barrier synchronization that happens once all
                the BSP nodes are blocked on receive calls and there are no more messages
                in flight.

            THREAD SAFETY
                This object is not thread-safe.  In particular, you should only ever have
                one thread that works with an instance of this object.  This means that,
                for example, you should not spawn sub-threads from within a BSP processing
                node and have them invoke methods on this object.  Instead, you should only
                invoke this object's methods from within the BSP processing node's main
                thread (i.e. the thread that executes the user supplied function funct()).
        !*/

    public:

        template <typename T>
        void send(
            const T& item,
            unsigned long target_node_id
        );
        /*!
            requires
                - item is serializable
                - target_node_id < number_of_nodes()
                - target_node_id != node_id()
            ensures
                - sends a copy of item to the node with the given id.
            throws
                - dlib::socket_error:
                    This exception is thrown if there is an error which prevents us from
                    delivering the message to the given node.  One way this might happen is
                    if the target node has already terminated its execution or has lost
                    network connectivity.
        !*/

        template <typename T>
        void broadcast (
            const T& item
        );
        /*!
            ensures
                - item is serializable
                - sends a copy of item to all other processing nodes.
            throws
                - dlib::socket_error
                    This exception is thrown if there is an error which prevents us from
                    delivering a message to one of the other nodes.  This might happen, for
                    example, if one of the nodes has terminated its execution or has lost
                    network connectivity.
        !*/

        unsigned long node_id (
        ) const;
        /*!
            ensures
                - Returns the id of the current processing node.  That is,
                  returns a number N such that:
                    - N < number_of_nodes()
                    - N == the node id of the processing node that called node_id().  This
                      is a number that uniquely identifies the processing node.
        !*/

        unsigned long number_of_nodes (
        ) const;
        /*!
            ensures
                - returns the number of processing nodes participating in the BSP
                  computation.
        !*/

        template <typename T>
        bool try_receive (
            T& item
        );
        /*!
            requires
                - item is serializable
            ensures
                - if (this function returns true) then
                    - #item == the next message which was sent to the calling processing
                      node.
                - else
                    - The following must have been true for this function to return false:
                        - All other nodes were blocked on calls to receive(),
                          try_receive(), or have terminated.
                        - There were not any messages in flight between any nodes.
                        - That is, if all the nodes had continued to block on receive
                          methods then they all would have blocked forever.  Therefore,
                          this function only returns false once there are no more messages
                          to process by any node and there is no possibility of more being
                          generated until control is returned to the callers of receive
                          methods.
                    - When one BSP node's receive method returns because of the above
                      conditions then all of them will also return.  That is, it is NOT the
                      case that just a subset of BSP nodes unblock.  Moreover, they all
                      unblock at the same time.
            throws
                - dlib::socket_error:
                    This exception is thrown if some error occurs which prevents us from
                    communicating with other processing nodes.
                - dlib::serialization_error or any exception thrown by the global
                  deserialize(T) routine:
                    This is thrown if there is a problem in deserialize().  This might
                    happen if the message sent doesn't match the type T expected by
                    try_receive().
        !*/

        template <typename T>
        void receive (
            T& item
        );
        /*!
            requires
                - item is serializable
            ensures
                - #item == the next message which was sent to the calling processing
                  node.
                - This function is just a wrapper around try_receive() that throws an
                  exception if a message is not received (i.e. if try_receive() returns
                  false).
            throws
                - dlib::socket_error:
                    This exception is thrown if some error occurs which prevents us from
                    communicating with other processing nodes or if there was not a message
                    to receive.
                - dlib::serialization_error or any exception thrown by the global
                  deserialize(T) routine:
                    This is thrown if there is a problem in deserialize().  This might
                    happen if the message sent doesn't match the type T expected by
                    receive().
        !*/

        template <typename T>
        bool try_receive (
            T& item,
            unsigned long& sending_node_id
        );
        /*!
            requires
                - item is serializable
            ensures
                - if (this function returns true) then
                    - #item == the next message which was sent to the calling processing
                      node.
                    - #sending_node_id == the node id of the node that sent this message.
                    - #sending_node_id < number_of_nodes()
                - else
                    - The following must have been true for this function to return false:
                        - All other nodes were blocked on calls to receive(),
                          try_receive(), or have terminated.
                        - There were not any messages in flight between any nodes.
                        - That is, if all the nodes had continued to block on receive
                          methods then they all would have blocked forever.  Therefore,
                          this function only returns false once there are no more messages
                          to process by any node and there is no possibility of more being
                          generated until control is returned to the callers of receive
                          methods.
                    - When one BSP node's receive method returns because of the above
                      conditions then all of them will also return.  That is, it is NOT the
                      case that just a subset of BSP nodes unblock.  Moreover, they all
                      unblock at the same time.
            throws
                - dlib::socket_error:
                    This exception is thrown if some error occurs which prevents us from
                    communicating with other processing nodes.
                - dlib::serialization_error or any exception thrown by the global
                  deserialize(T) routine:
                    This is thrown if there is a problem in deserialize().  This might
                    happen if the message sent doesn't match the type T expected by
                    try_receive().
        !*/

        template <typename T>
        void receive (
            T& item,
            unsigned long& sending_node_id
        );
        /*!
            requires
                - item is serializable
            ensures
                - #item == the next message which was sent to the calling processing node.
                - #sending_node_id == the node id of the node that sent this message.
                - #sending_node_id < number_of_nodes()
                - This function is just a wrapper around try_receive() that throws an
                  exception if a message is not received (i.e. if try_receive() returns
                  false).
            throws
                - dlib::socket_error:
                    This exception is thrown if some error occurs which prevents us from
                    communicating with other processing nodes or if there was not a message
                    to receive.
                - dlib::serialization_error or any exception thrown by the global
                  deserialize(T) routine:
                    This is thrown if there is a problem in deserialize().  This might
                    happen if the message sent doesn't match the type T expected by
                    receive().
        !*/

        void receive (
        );
        /*!
            ensures
                - Waits for the following to all be true:
                    - All other nodes were blocked on calls to receive(), try_receive(), or
                      have terminated.
                    - There are not any messages in flight between any nodes.
                    - That is, if all the nodes had continued to block on receive methods
                      then they all would have blocked forever.  Therefore, this function
                      only returns once there are no more messages to process by any node
                      and there is no possibility of more being generated until control is
                      returned to the callers of receive methods.
                - When one BSP node's receive method returns because of the above
                  conditions then all of them will also return.  That is, it is NOT the
                  case that just a subset of BSP nodes unblock.  Moreover, they all unblock
                  at the same time.
            throws
                - dlib::socket_error:
                    This exception is thrown if some error occurs which prevents us from
                    communicating with other processing nodes or if a message is received
                    before this function would otherwise return.

        !*/

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename funct_type
        >
    void bsp_connect (
        const std::vector<network_address>& hosts,
        funct_type funct
    );
    /*!
        requires
            - let CONTEXT be an instance of a bsp_context object.  Then:
                - funct(CONTEXT) must be a valid expression
                  (i.e. funct must be a function or function object)
        ensures
            - This function spawns a BSP job consisting of hosts.size()+1 processing nodes.
            - The processing node with a node ID of 0 will run locally on the machine
              calling bsp_connect().  In particular, this node will execute funct(CONTEXT),
              which is expected to carry out this node's portion of the BSP computation.
            - The other processing nodes are executed on the hosts indicated by the input
              argument.  In particular, this function interprets hosts as a list addresses
              identifying machines running the bsp_listen() or bsp_listen_dynamic_port()
              routines.
            - This call to bsp_connect() blocks until the BSP computation has completed on
              all processing nodes.
        throws
            - dlib::socket_error
                This exception is thrown if there is an error which prevents the BSP
                job from executing.
            - Any exception thrown by funct() will be propagated out of this call to
              bsp_connect().
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename funct_type,
        typename ARG1
        >
    void bsp_connect (
        const std::vector<network_address>& hosts,
        funct_type funct,
        ARG1 arg1
    );
    /*!
        requires
            - let CONTEXT be an instance of a bsp_context object.  Then:
                - funct(CONTEXT,arg1) must be a valid expression
                  (i.e. funct must be a function or function object)
        ensures
            - This function spawns a BSP job consisting of hosts.size()+1 processing nodes.
            - The processing node with a node ID of 0 will run locally on the machine
              calling bsp_connect().  In particular, this node will execute funct(CONTEXT,arg1),
              which is expected to carry out this node's portion of the BSP computation.
            - The other processing nodes are executed on the hosts indicated by the input
              argument.  In particular, this function interprets hosts as a list addresses
              identifying machines running the bsp_listen() or bsp_listen_dynamic_port()
              routines.
            - This call to bsp_connect() blocks until the BSP computation has completed on
              all processing nodes.
        throws
            - dlib::socket_error
                This exception is thrown if there is an error which prevents the BSP
                job from executing.
            - Any exception thrown by funct() will be propagated out of this call to
              bsp_connect().
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename funct_type,
        typename ARG1,
        typename ARG2
        >
    void bsp_connect (
        const std::vector<network_address>& hosts,
        funct_type funct,
        ARG1 arg1,
        ARG2 arg2
    );
    /*!
        requires
            - let CONTEXT be an instance of a bsp_context object.  Then:
                - funct(CONTEXT,arg1,arg2) must be a valid expression
                  (i.e. funct must be a function or function object)
        ensures
            - This function spawns a BSP job consisting of hosts.size()+1 processing nodes.
            - The processing node with a node ID of 0 will run locally on the machine
              calling bsp_connect().  In particular, this node will execute funct(CONTEXT,arg1,arg2),
              which is expected to carry out this node's portion of the BSP computation.
            - The other processing nodes are executed on the hosts indicated by the input
              argument.  In particular, this function interprets hosts as a list addresses
              identifying machines running the bsp_listen() or bsp_listen_dynamic_port()
              routines.
            - This call to bsp_connect() blocks until the BSP computation has completed on
              all processing nodes.
        throws
            - dlib::socket_error
                This exception is thrown if there is an error which prevents the BSP
                job from executing.
            - Any exception thrown by funct() will be propagated out of this call to
              bsp_connect().
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename funct_type,
        typename ARG1,
        typename ARG2,
        typename ARG3
        >
    void bsp_connect (
        const std::vector<network_address>& hosts,
        funct_type funct,
        ARG1 arg1,
        ARG2 arg2,
        ARG3 arg3
    );
    /*!
        requires
            - let CONTEXT be an instance of a bsp_context object.  Then:
                - funct(CONTEXT,arg1,arg2,arg3) must be a valid expression
                  (i.e. funct must be a function or function object)
        ensures
            - This function spawns a BSP job consisting of hosts.size()+1 processing nodes.
            - The processing node with a node ID of 0 will run locally on the machine
              calling bsp_connect().  In particular, this node will execute funct(CONTEXT,arg1,arg2,arg3),
              which is expected to carry out this node's portion of the BSP computation.
            - The other processing nodes are executed on the hosts indicated by the input
              argument.  In particular, this function interprets hosts as a list addresses
              identifying machines running the bsp_listen() or bsp_listen_dynamic_port()
              routines.
            - This call to bsp_connect() blocks until the BSP computation has completed on
              all processing nodes.
        throws
            - dlib::socket_error
                This exception is thrown if there is an error which prevents the BSP
                job from executing.
            - Any exception thrown by funct() will be propagated out of this call to
              bsp_connect().
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename funct_type,
        typename ARG1,
        typename ARG2,
        typename ARG3,
        typename ARG4
        >
    void bsp_connect (
        const std::vector<network_address>& hosts,
        funct_type funct,
        ARG1 arg1,
        ARG2 arg2,
        ARG3 arg3,
        ARG4 arg4
    );
    /*!
        requires
            - let CONTEXT be an instance of a bsp_context object.  Then:
                - funct(CONTEXT,arg1,arg2,arg3,arg4) must be a valid expression
                  (i.e. funct must be a function or function object)
        ensures
            - This function spawns a BSP job consisting of hosts.size()+1 processing nodes.
            - The processing node with a node ID of 0 will run locally on the machine
              calling bsp_connect().  In particular, this node will execute funct(CONTEXT,arg1,arg2,arg3,arg4),
              which is expected to carry out this node's portion of the BSP computation.
            - The other processing nodes are executed on the hosts indicated by the input
              argument.  In particular, this function interprets hosts as a list addresses
              identifying machines running the bsp_listen() or bsp_listen_dynamic_port()
              routines.
            - This call to bsp_connect() blocks until the BSP computation has completed on
              all processing nodes.
        throws
            - dlib::socket_error
                This exception is thrown if there is an error which prevents the BSP
                job from executing.
            - Any exception thrown by funct() will be propagated out of this call to
              bsp_connect().
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename funct_type
        >
    void bsp_listen (
        unsigned short listening_port,
        funct_type funct
    );
    /*!
        requires
            - listening_port != 0
            - let CONTEXT be an instance of a bsp_context object.  Then:
                - funct(CONTEXT) must be a valid expression
                  (i.e. funct must be a function or function object)
        ensures
            - This function listens for a connection from the bsp_connect() routine.  Once
              this connection is established, funct(CONTEXT) will be executed and it will
              then be able to participate in the BSP computation as one of the processing
              nodes.
            - This function will listen on TCP port listening_port for a connection from
              bsp_connect().  Once the connection is established, it will close the
              listening port so it is free for use by other applications.  The connection
              and BSP computation will continue uninterrupted.
            - This call to bsp_listen() blocks until the BSP computation has completed on
              all processing nodes.
        throws
            - dlib::socket_error
                This exception is thrown if there is an error which prevents the BSP
                job from executing.
            - Any exception thrown by funct() will be propagated out of this call to
              bsp_connect().
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename funct_type,
        typename ARG1
        >
    void bsp_listen (
        unsigned short listening_port,
        funct_type funct,
        ARG1 arg1
    );
    /*!
        requires
            - listening_port != 0
            - let CONTEXT be an instance of a bsp_context object.  Then:
                - funct(CONTEXT,arg1) must be a valid expression
                  (i.e. funct must be a function or function object)
        ensures
            - This function listens for a connection from the bsp_connect() routine.  Once
              this connection is established, funct(CONTEXT,arg1) will be executed and it will
              then be able to participate in the BSP computation as one of the processing
              nodes.
            - This function will listen on TCP port listening_port for a connection from
              bsp_connect().  Once the connection is established, it will close the
              listening port so it is free for use by other applications.  The connection
              and BSP computation will continue uninterrupted.
            - This call to bsp_listen() blocks until the BSP computation has completed on
              all processing nodes.
        throws
            - dlib::socket_error
                This exception is thrown if there is an error which prevents the BSP
                job from executing.
            - Any exception thrown by funct() will be propagated out of this call to
              bsp_connect().
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename funct_type,
        typename ARG1,
        typename ARG2
        >
    void bsp_listen (
        unsigned short listening_port,
        funct_type funct,
        ARG1 arg1,
        ARG2 arg2
    );
    /*!
        requires
            - listening_port != 0
            - let CONTEXT be an instance of a bsp_context object.  Then:
                - funct(CONTEXT,arg1,arg2) must be a valid expression
                  (i.e. funct must be a function or function object)
        ensures
            - This function listens for a connection from the bsp_connect() routine.  Once
              this connection is established, funct(CONTEXT,arg1,arg2) will be executed and
              it will then be able to participate in the BSP computation as one of the
              processing nodes.
            - This function will listen on TCP port listening_port for a connection from
              bsp_connect().  Once the connection is established, it will close the
              listening port so it is free for use by other applications.  The connection
              and BSP computation will continue uninterrupted.
            - This call to bsp_listen() blocks until the BSP computation has completed on
              all processing nodes.
        throws
            - dlib::socket_error
                This exception is thrown if there is an error which prevents the BSP
                job from executing.
            - Any exception thrown by funct() will be propagated out of this call to
              bsp_connect().
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename funct_type,
        typename ARG1,
        typename ARG2,
        typename ARG3
        >
    void bsp_listen (
        unsigned short listening_port,
        funct_type funct,
        ARG1 arg1,
        ARG2 arg2,
        ARG3 arg3
    );
    /*!
        requires
            - listening_port != 0
            - let CONTEXT be an instance of a bsp_context object.  Then:
                - funct(CONTEXT,arg1,arg2,arg3) must be a valid expression
                  (i.e. funct must be a function or function object)
        ensures
            - This function listens for a connection from the bsp_connect() routine.  Once
              this connection is established, funct(CONTEXT,arg1,arg2,arg3) will be
              executed and it will then be able to participate in the BSP computation as
              one of the processing nodes.
            - This function will listen on TCP port listening_port for a connection from
              bsp_connect().  Once the connection is established, it will close the
              listening port so it is free for use by other applications.  The connection
              and BSP computation will continue uninterrupted.
            - This call to bsp_listen() blocks until the BSP computation has completed on
              all processing nodes.
        throws
            - dlib::socket_error
                This exception is thrown if there is an error which prevents the BSP
                job from executing.
            - Any exception thrown by funct() will be propagated out of this call to
              bsp_connect().
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename funct_type,
        typename ARG1,
        typename ARG2,
        typename ARG3,
        typename ARG4
        >
    void bsp_listen (
        unsigned short listening_port,
        funct_type funct,
        ARG1 arg1,
        ARG2 arg2,
        ARG3 arg3,
        ARG4 arg4
    );
    /*!
        requires
            - listening_port != 0
            - let CONTEXT be an instance of a bsp_context object.  Then:
                - funct(CONTEXT,arg1,arg2,arg3,arg4) must be a valid expression
                  (i.e. funct must be a function or function object)
        ensures
            - This function listens for a connection from the bsp_connect() routine.  Once
              this connection is established, funct(CONTEXT,arg1,arg2,arg3,arg4) will be
              executed and it will then be able to participate in the BSP computation as
              one of the processing nodes.
            - This function will listen on TCP port listening_port for a connection from
              bsp_connect().  Once the connection is established, it will close the
              listening port so it is free for use by other applications.  The connection
              and BSP computation will continue uninterrupted.
            - This call to bsp_listen() blocks until the BSP computation has completed on
              all processing nodes.
        throws
            - dlib::socket_error
                This exception is thrown if there is an error which prevents the BSP
                job from executing.
            - Any exception thrown by funct() will be propagated out of this call to
              bsp_connect().
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename port_notify_function_type,
        typename funct_type
        >
    void bsp_listen_dynamic_port (
        unsigned short listening_port,
        port_notify_function_type port_notify_function,
        funct_type funct
    );
    /*!
        requires
            - let CONTEXT be an instance of a bsp_context object.  Then:
                - funct(CONTEXT) must be a valid expression
                  (i.e. funct must be a function or function object)
            - port_notify_function((unsigned short) 1234) must be a valid expression
              (i.e. port_notify_function() must be a function or function object taking an
              unsigned short)
        ensures
            - This function listens for a connection from the bsp_connect() routine.  Once
              this connection is established, funct(CONTEXT) will be executed and it will
              then be able to participate in the BSP computation as one of the processing
              nodes.
            - if (listening_port != 0) then
                - This function will listen on TCP port listening_port for a connection
                  from bsp_connect().
            - else
                - An available TCP port number is automatically selected and this function
                  will listen on it for a connection from bsp_connect().
            - Once a listening port is opened, port_notify_function() is called with the
              port number used.  This provides a mechanism to find out what listening port
              has been used if it is automatically selected.  It also allows you to find
              out when the routine has begun listening for an incoming connection from
              bsp_connect().
            - Once a connection is established, we will close the listening port so it is
              free for use by other applications.  The connection and BSP computation will
              continue uninterrupted.
            - This call to bsp_listen_dynamic_port() blocks until the BSP computation has
              completed on all processing nodes.
        throws
            - dlib::socket_error
                This exception is thrown if there is an error which prevents the BSP
                job from executing.
            - Any exception thrown by funct() will be propagated out of this call to
              bsp_connect().
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename port_notify_function_type,
        typename funct_type,
        typename ARG1
        >
    void bsp_listen_dynamic_port (
        unsigned short listening_port,
        port_notify_function_type port_notify_function,
        funct_type funct,
        ARG1 arg1
    );
    /*!
        requires
            - let CONTEXT be an instance of a bsp_context object.  Then:
                - funct(CONTEXT,arg1) must be a valid expression
                  (i.e. funct must be a function or function object)
            - port_notify_function((unsigned short) 1234) must be a valid expression
              (i.e. port_notify_function() must be a function or function object taking an
              unsigned short)
        ensures
            - This function listens for a connection from the bsp_connect() routine.  Once
              this connection is established, funct(CONTEXT,arg1) will be executed and it
              will then be able to participate in the BSP computation as one of the
              processing nodes.
            - if (listening_port != 0) then
                - This function will listen on TCP port listening_port for a connection
                  from bsp_connect().
            - else
                - An available TCP port number is automatically selected and this function
                  will listen on it for a connection from bsp_connect().
            - Once a listening port is opened, port_notify_function() is called with the
              port number used.  This provides a mechanism to find out what listening port
              has been used if it is automatically selected.  It also allows you to find
              out when the routine has begun listening for an incoming connection from
              bsp_connect().
            - Once a connection is established, we will close the listening port so it is
              free for use by other applications.  The connection and BSP computation will
              continue uninterrupted.
            - This call to bsp_listen_dynamic_port() blocks until the BSP computation has
              completed on all processing nodes.
        throws
            - dlib::socket_error
                This exception is thrown if there is an error which prevents the BSP
                job from executing.
            - Any exception thrown by funct() will be propagated out of this call to
              bsp_connect().
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename port_notify_function_type,
        typename funct_type,
        typename ARG1,
        typename ARG2
        >
    void bsp_listen_dynamic_port (
        unsigned short listening_port,
        port_notify_function_type port_notify_function,
        funct_type funct,
        ARG1 arg1,
        ARG2 arg2
    );
    /*!
        requires
            - let CONTEXT be an instance of a bsp_context object.  Then:
                - funct(CONTEXT,arg1,arg2) must be a valid expression
                  (i.e. funct must be a function or function object)
            - port_notify_function((unsigned short) 1234) must be a valid expression
              (i.e. port_notify_function() must be a function or function object taking an
              unsigned short)
        ensures
            - This function listens for a connection from the bsp_connect() routine.  Once
              this connection is established, funct(CONTEXT,arg1,arg2) will be executed and
              it will then be able to participate in the BSP computation as one of the
              processing nodes.
            - if (listening_port != 0) then
                - This function will listen on TCP port listening_port for a connection
                  from bsp_connect().
            - else
                - An available TCP port number is automatically selected and this function
                  will listen on it for a connection from bsp_connect().
            - Once a listening port is opened, port_notify_function() is called with the
              port number used.  This provides a mechanism to find out what listening port
              has been used if it is automatically selected.  It also allows you to find
              out when the routine has begun listening for an incoming connection from
              bsp_connect().
            - Once a connection is established, we will close the listening port so it is
              free for use by other applications.  The connection and BSP computation will
              continue uninterrupted.
            - This call to bsp_listen_dynamic_port() blocks until the BSP computation has
              completed on all processing nodes.
        throws
            - dlib::socket_error
                This exception is thrown if there is an error which prevents the BSP
                job from executing.
            - Any exception thrown by funct() will be propagated out of this call to
              bsp_connect().
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename port_notify_function_type,
        typename funct_type,
        typename ARG1,
        typename ARG2,
        typename ARG3
        >
    void bsp_listen_dynamic_port (
        unsigned short listening_port,
        port_notify_function_type port_notify_function,
        funct_type funct,
        ARG1 arg1,
        ARG2 arg2,
        ARG3 arg3
    );
    /*!
        requires
            - let CONTEXT be an instance of a bsp_context object.  Then:
                - funct(CONTEXT,arg1,arg2,arg3) must be a valid expression
                  (i.e. funct must be a function or function object)
            - port_notify_function((unsigned short) 1234) must be a valid expression
              (i.e. port_notify_function() must be a function or function object taking an
              unsigned short)
        ensures
            - This function listens for a connection from the bsp_connect() routine.  Once
              this connection is established, funct(CONTEXT,arg1,arg2,arg3) will be
              executed and it will then be able to participate in the BSP computation as
              one of the processing nodes.
            - if (listening_port != 0) then
                - This function will listen on TCP port listening_port for a connection
                  from bsp_connect().
            - else
                - An available TCP port number is automatically selected and this function
                  will listen on it for a connection from bsp_connect().
            - Once a listening port is opened, port_notify_function() is called with the
              port number used.  This provides a mechanism to find out what listening port
              has been used if it is automatically selected.  It also allows you to find
              out when the routine has begun listening for an incoming connection from
              bsp_connect().
            - Once a connection is established, we will close the listening port so it is
              free for use by other applications.  The connection and BSP computation will
              continue uninterrupted.
            - This call to bsp_listen_dynamic_port() blocks until the BSP computation has
              completed on all processing nodes.
        throws
            - dlib::socket_error
                This exception is thrown if there is an error which prevents the BSP
                job from executing.
            - Any exception thrown by funct() will be propagated out of this call to
              bsp_connect().
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename port_notify_function_type,
        typename funct_type,
        typename ARG1,
        typename ARG2,
        typename ARG3,
        typename ARG4
        >
    void bsp_listen_dynamic_port (
        unsigned short listening_port,
        port_notify_function_type port_notify_function,
        funct_type funct,
        ARG1 arg1,
        ARG2 arg2,
        ARG3 arg3,
        ARG4 arg4
    );
    /*!
        requires
            - let CONTEXT be an instance of a bsp_context object.  Then:
                - funct(CONTEXT,arg1,arg2,arg3,arg4) must be a valid expression
                  (i.e. funct must be a function or function object)
            - port_notify_function((unsigned short) 1234) must be a valid expression
              (i.e. port_notify_function() must be a function or function object taking an
              unsigned short)
        ensures
            - This function listens for a connection from the bsp_connect() routine.  Once
              this connection is established, funct(CONTEXT,arg1,arg2,arg3,arg4) will be
              executed and it will then be able to participate in the BSP computation as
              one of the processing nodes.
            - if (listening_port != 0) then
                - This function will listen on TCP port listening_port for a connection
                  from bsp_connect().
            - else
                - An available TCP port number is automatically selected and this function
                  will listen on it for a connection from bsp_connect().
            - Once a listening port is opened, port_notify_function() is called with the
              port number used.  This provides a mechanism to find out what listening port
              has been used if it is automatically selected.  It also allows you to find
              out when the routine has begun listening for an incoming connection from
              bsp_connect().
            - Once a connection is established, we will close the listening port so it is
              free for use by other applications.  The connection and BSP computation will
              continue uninterrupted.
            - This call to bsp_listen_dynamic_port() blocks until the BSP computation has
              completed on all processing nodes.
        throws
            - dlib::socket_error
                This exception is thrown if there is an error which prevents the BSP
                job from executing.
            - Any exception thrown by funct() will be propagated out of this call to
              bsp_connect().
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

}

#endif // DLIB_BsP_ABSTRACT_Hh_


dlib C++ Library - Optimization

The Library
  • Algorithms
  • API Wrappers
  • Bayesian Nets
  • Compression
  • Containers
  • Graph Tools
  • Image Processing
  • Linear Algebra
  • Machine Learning
  • Metaprogramming
  • Miscellaneous
  • Networking
  • Optimization
  • Parsing

Help/Info
  • Dlib Blog
  • Examples: C++
    • 3D Point Cloud
    • Assignment Learning
    • Base64 Encoder
    • Bayesian Network From Disk
    • Bayesian Network GUI
    • Bayesian Network
    • Bridge
    • BSP
    • C-Support Vector Machine
    • Cmd Line Parser
    • Compress Stream
    • Config File Reader
    • Custom Trainers
    • Directory Navigation
    • Empirical Kernel Map
    • Face Detection
    • Face Landmark Detection
    • FHOG Feature Extraction
    • FHOG Object Detection
    • Graph Labeling
    • GUI
    • Hough Transform
    • HTTP Server
    • Image
    • IO Socket Streams
    • IO Streams Server
    • Kernel Centroid
    • Kernel K-Means Clustering
    • Kernel Ridge Regression
    • Kernel RLS Filtering
    • Kernel RLS Regression
    • KRR Classification
    • Learning to Track
    • Linear Assignment Problems
    • Linear Manifold Regularizer
    • Linear Model Predictive Control
    • Logger Advanced
    • Logger Custom Output
    • Logger
    • Matrix Expressions
    • Matrix
    • Member Function Pointer
    • Model Selection
    • Multiclass Classification
    • Multithreaded Object
    • Neural Network
    • Non-Linear Least Squares
    • Nu-Support Vector Machine
    • Numerical Integration
    • Object Detector Advanced
    • Object Detector
    • One Class Classifiers
    • Online SVM
    • Optimization
    • Parallel For Loops
    • Pipe 2
    • Pipe
    • Quantum Computing
    • Queue
    • Rank Features
    • Relevance Vector Classification
    • Relevance Vector Regression
    • Running Stats
    • Sequence Labeling
    • Sequence Segmentation
    • Sockets
    • Sockstreambuf
    • Sparse Vectors
    • SQLite
    • Std C++ Allocator
    • Structural Support Vector Machines
    • Support Vector Regression
    • SURF
    • SVM-Rank
    • Thread Function
    • Thread Pool
    • Threaded Object
    • Threads
    • Timer
    • Train Object Detector
    • Train Shape Predictor
    • Using Custom Kernels
    • Video Object Tracking
    • Webcam Face Pose Estimation
    • XML Parser
  • Examples: Python
    • Face Detector
    • Face Landmark Detection
    • find candidate object locations
    • Linear Assignment Problems
    • Sequence Segmenter
    • Structural Support Vector Machines
    • SVM-Rank
    • Train Object Detector
    • Train Shape Predictor
    • Video Object Tracking
  • FAQ
  • Forums
  • Home
  • How to compile
  • How to contribute
  • Index
  • Introduction
  • License
  • Python API
  • Suggested Books
  • Who uses dlib?

Current Release
  • Change Log
  • Release Notes
  • Version: 18.18

Last Modified:
Sep 13, 2015
Optimization

This page documents library components that attempt to find the minimum or maximum of a user supplied function. An introduction to the general purpose non-linear optimizers in this section can be found here. For an example showing how to use the non-linear least squares routines look here.

General Purpose Optimizers
  • find_max
  • find_max_bobyqa
  • find_max_box_constrained
  • find_max_single_variable
  • find_max_trust_region
  • find_max_using_approximate_derivatives
  • find_min
  • find_min_bobyqa
  • find_min_box_constrained
  • find_min_single_variable
  • find_min_trust_region
  • find_min_using_approximate_derivatives

Special Purpose Optimizers
  • find_max_factor_graph_nmplp
  • find_max_factor_graph_potts
  • find_max_factor_graph_viterbi
  • find_max_parse_cky
  • max_cost_assignment
  • max_sum_submatrix
  • min_cut
  • mpc
  • oca
  • solve_least_squares
  • solve_least_squares_lm
  • solve_qp2_using_smo
  • solve_qp3_using_smo
  • solve_qp4_using_smo
  • solve_qp_using_smo
  • solve_trust_region_subproblem

Strategies
  • bfgs_search_strategy
  • cg_search_strategy
  • gradient_norm_stop_strategy
  • lbfgs_search_strategy
  • newton_search_strategy
  • objective_delta_stop_strategy

Helper Routines
  • backtracking_line_search
  • clamp_function
  • derivative
  • find_trees_not_rooted_with_tag
  • graph_cut_score
  • lagrange_poly_min_extrap
  • line_search
  • make_line_search_function
  • negate_function
  • parse_tree_to_string
  • poly_min_extrap
  • potts_model_score

[top]

backtracking_line_search

Performs a line search on a given function and returns the input that makes the function significantly smaller. This implementation uses a basic Armijo backtracking search with polynomial interpolation.
More Details...
#include <dlib/optimization.h>
[top]

bfgs_search_strategy

This object represents a strategy for determining which direction a line search should be carried out along. This particular object is an implementation of the BFGS quasi-newton method for determining this direction.

This method uses an amount of memory that is quadratic in the number of variables to be optimized. It is generally very effective but if your problem has a very large number of variables then it isn't appropriate. Instead, you should try the lbfgs_search_strategy.

C++ Example Programs: optimization_ex.cpp
More Details...
#include <dlib/optimization.h>
[top]

cg_search_strategy

This object represents a strategy for determining which direction a line search should be carried out along. This particular object is an implementation of the Polak-Ribiere conjugate gradient method for determining this direction.

This method uses an amount of memory that is linear in the number of variables to be optimized. So it is capable of handling problems with a very large number of variables. However, it is generally not as good as the L-BFGS algorithm (see the lbfgs_search_strategy class).

C++ Example Programs: optimization_ex.cpp
More Details...
#include <dlib/optimization.h>
[top]

clamp_function

This is a function that takes another function, f(x), as input and returns a new function object, g(x), such that g(x) == f(clamp(x,x_lower,x_upper)) where x_lower and x_upper are vectors of box constraints which are applied to x.
More Details...
#include <dlib/optimization.h>
[top]

derivative

This is a function that takes another function as input and returns a function object that numerically computes the derivative of the input function.
More Details...
#include <dlib/optimization.h>
[top]

find_max

Performs an unconstrained maximization of a nonlinear function using some search strategy (e.g. bfgs_search_strategy).
More Details...
#include <dlib/optimization.h>
[top]

find_max_bobyqa

This function is identical to the find_min_bobyqa routine except that it negates the objective function before performing optimization. Thus this function will attempt to find the maximizer of the objective rather than the minimizer.

Note that BOBYQA only works on functions of two or more variables. So if you need to perform derivative-free optimization on a function of a single variable then you should use the find_max_single_variable function.

C++ Example Programs: optimization_ex.cpp, model_selection_ex.cpp
More Details...
#include <dlib/optimization.h>
[top]

find_max_box_constrained

Performs a box constrained maximization of a nonlinear function using some search strategy (e.g. bfgs_search_strategy). This function uses a backtracking line search along with a gradient projection step to handle the box constraints.
More Details...
#include <dlib/optimization.h>
[top]

find_max_factor_graph_nmplp

This function is a tool for approximately solving the MAP problem in a graphical model or factor graph with pairwise potential functions. That is, it attempts to solve a certain kind of optimization problem which can be defined as follows:
   maximize: f(X)
   where X is a set of integer valued variables and f(X) can be written
   as the sum of functions which each involve only two variables from X.
If the graph is tree-structured then this routine always gives the exact solution to the MAP problem. However, for graphs with cycles, the solution may be approximate.

This function is an implementation of the NMPLP algorithm introduced in the following papers:
Fixing Max-Product: Convergent Message Passing Algorithms for MAP LP-Relaxations (2008) by Amir Globerson and Tommi Jaakkola
Introduction to dual decomposition for inference (2011) by David Sontag, Amir Globerson, and Tommi Jaakkola

More Details...
#include <dlib/optimization.h>
[top]

find_max_factor_graph_potts

This is a set of overloaded functions for exactly solving the MAP problem in a Potts model. This type of model is useful when you have a problem which can be modeled as a bunch of binary decisions on some variables, but you have some kind of labeling consistency constraint. This means that there is some penalty for giving certain pairs of variables different labels. So in addition to trying to figure out how to best label each variable on its own, you have to worry about making the labels pairwise consistent in some sense. The find_max_factor_graph_potts() routine can be used to find the most probable/highest scoring labeling for this type of model.

The implementation of this routine is based on the min_cut object.

More Details...
#include <dlib/graph_cuts.h>
[top]

find_max_factor_graph_viterbi

This function is a tool for exactly solving the MAP problem in a chain-structured graphical model or factor graph. In particular, it is an implementation of the classic Viterbi algorithm for finding the maximizing assignment. In addition to basic first order Markov models, this function is also capable of finding the MAP assignment for higher order Markov models.
More Details...
#include <dlib/optimization.h>
[top]

find_max_parse_cky

This function implements the CKY parsing algorithm. In particular, it finds the maximum scoring binary parse tree that parses an input sequence of tokens.
More Details...
#include <dlib/optimization.h>
[top]

find_max_single_variable

Performs a bound constrained maximization of a nonlinear function. The function must be of a single variable. Derivatives are not required.
More Details...
#include <dlib/optimization.h>
[top]

find_max_trust_region

Performs an unconstrained maximization of a nonlinear function using a trust region method.
More Details...
#include <dlib/optimization.h>
[top]

find_max_using_approximate_derivatives

Performs an unconstrained maximization of a nonlinear function using some search strategy (e.g. bfgs_search_strategy). This version doesn't take a gradient function but instead numerically approximates the gradient.
More Details...
#include <dlib/optimization.h>
[top]

find_min

Performs an unconstrained minimization of a nonlinear function using some search strategy (e.g. bfgs_search_strategy).

C++ Example Programs: optimization_ex.cpp
More Details...
#include <dlib/optimization.h>
[top]

find_min_bobyqa

This function defines the dlib interface to the BOBYQA software developed by M.J.D Powell. BOBYQA is a method for optimizing a function in the absence of derivative information. Powell described it as a method that seeks the least value of a function of many variables, by applying a trust region method that forms quadratic models by interpolation. There is usually some freedom in the interpolation conditions, which is taken up by minimizing the Frobenius norm of the change to the second derivative of the model, beginning with the zero matrix. The values of the variables are constrained by upper and lower bounds.

The following paper, published in 2009 by Powell, describes the detailed working of the BOBYQA algorithm.

The BOBYQA algorithm for bound constrained optimization without derivatives by M.J.D. Powell

Note that BOBYQA only works on functions of two or more variables. So if you need to perform derivative-free optimization on a function of a single variable then you should use the find_min_single_variable function.

C++ Example Programs: optimization_ex.cpp, model_selection_ex.cpp
More Details...
#include <dlib/optimization.h>
[top]

find_min_box_constrained

Performs a box constrained minimization of a nonlinear function using some search strategy (e.g. bfgs_search_strategy). This function uses a backtracking line search along with a gradient projection step to handle the box constraints.

C++ Example Programs: optimization_ex.cpp
More Details...
#include <dlib/optimization.h>
[top]

find_min_single_variable

Performs a bound constrained minimization of a nonlinear function. The function must be of a single variable. Derivatives are not required.
More Details...
#include <dlib/optimization.h>
[top]

find_min_trust_region

Performs an unconstrained minimization of a nonlinear function using a trust region method.

C++ Example Programs: optimization_ex.cpp
More Details...
#include <dlib/optimization.h>
[top]

find_min_using_approximate_derivatives

Performs an unconstrained minimization of a nonlinear function using some search strategy (e.g. bfgs_search_strategy). This version doesn't take a gradient function but instead numerically approximates the gradient.

C++ Example Programs: optimization_ex.cpp
More Details...
#include <dlib/optimization.h>
[top]

find_trees_not_rooted_with_tag

Finds all the largest non-overlapping parse trees in tree that are not rooted with a particular tag.

This function is useful when you want to cut a parse tree into a bunch of sub-trees and you know that the top level of the tree is all composed of the same kind of tag. So if you want to just "slice off" the top of the tree where this tag lives then this function is useful for doing that.

More Details...
#include <dlib/optimization.h>
[top]

gradient_norm_stop_strategy

This object represents a strategy for deciding if an optimization algorithm should terminate. This particular object looks at the norm (i.e. the length) of the current gradient vector and stops if it is smaller than a user given threshold.
More Details...
#include <dlib/optimization.h>
[top]

graph_cut_score

This routine computes the score for a candidate graph cut. This is the quantity minimized by the min_cut algorithm.
More Details...
#include <dlib/graph_cuts.h>
[top]

lagrange_poly_min_extrap

This function finds the second order polynomial that interpolates a set of points and returns the minimum of that polynomial.
More Details...
#include <dlib/optimization.h>
[top]

lbfgs_search_strategy

This object represents a strategy for determining which direction a line search should be carried out along. This particular object is an implementation of the L-BFGS quasi-newton method for determining this direction.

This method uses an amount of memory that is linear in the number of variables to be optimized. This makes it an excellent method to use when an optimization problem has a large number of variables.

C++ Example Programs: optimization_ex.cpp
More Details...
#include <dlib/optimization.h>
[top]

line_search

Performs a gradient based line search on a given function and returns the input that makes the function significantly smaller. This implements the classic line search method using the strong Wolfe conditions with a bracketing and then sectioning phase, both using polynomial interpolation.
More Details...
#include <dlib/optimization.h>
[top]

make_line_search_function

This is a function that takes another function f(x) as input and returns a function object l(z) = f(start + z*direction). It is useful for turning multi-variable functions into single-variable functions for use with the line_search or backtracking_line_search routines.
More Details...
#include <dlib/optimization.h>
[top]

max_cost_assignment

This function is an implementation of the Hungarian algorithm (also know as the Kuhn-Munkres algorithm) which runs in O(N^3) time. It solves the optimal assignment problem. For example, suppose you have an equal number of workers and jobs and you need to decide which workers to assign to which jobs. Some workers are better at certain jobs than others. So you would like to find out how to assign them all to jobs such that overall productivity is maximized. You can use this routine to solve this problem and others like it.

Note that dlib also contains a machine learning method for learning the cost function needed to use the Hungarian algorithm.

C++ Example Programs: max_cost_assignment_ex.cpp
Python Example Programs: max_cost_assignment.py
More Details...
#include <dlib/optimization.h>
[top]

max_sum_submatrix

This function finds the submatrix within a user supplied matrix which has the largest sum. It then zeros out that submatrix and repeats the process until no more maximal submatrices can be found.
More Details...
#include <dlib/optimization.h>
[top]

min_cut

This is a function object which can be used to find the min cut on a graph. The implementation is based on the method described in the following paper:
An Experimental Comparison of Min-Cut/Max-Flow Algorithms for Energy Minimization in Vision, by Yuri Boykov and Vladimir Kolmogorov, in PAMI 2004.

More Details...
#include <dlib/graph_cuts.h>
[top]

mpc

This object implements a linear model predictive controller. In particular, it solves a certain quadratic program using the method described in the paper:
A Fast Gradient method for embedded linear predictive control (2011) by Markus Kogel and Rolf Findeisen

C++ Example Programs: mpc_ex.cpp
More Details...
#include <dlib/control.h>
[top]

negate_function

This is a function that takes another function as input and returns a function object that computes the negation of the input function.
More Details...
#include <dlib/optimization.h>
[top]

newton_search_strategy

This object represents a strategy for determining which direction a line search should be carried out along. This particular routine is an implementation of the newton method for determining this direction. That means using it requires you to supply a method for creating hessian matrices for the problem you are trying to optimize.

Note also that this is actually a helper function for creating newton_search_strategy_obj objects.

C++ Example Programs: optimization_ex.cpp
More Details...
#include <dlib/optimization.h>
[top]

objective_delta_stop_strategy

This object represents a strategy for deciding if an optimization algorithm should terminate. This particular object looks at the change in the objective function from one iteration to the next and bases its decision on how large this change is. If the change is below a user given threshold then the search stops.

C++ Example Programs: optimization_ex.cpp
More Details...
#include <dlib/optimization.h>
[top]

oca

This object is a tool for solving the following optimization problem:
   Minimize: f(w) == 0.5*||w||^2 + C*R(w)

   Where R(w) is a user-supplied convex function and C > 0.  Optionally,
   this object can also add non-negativity constraints to some or all
   of the elements of w.

Or it can alternatively solve:
   Minimize: f(w) == 0.5*||w-prior||^2 + C*R(w)

   Where prior is a user supplied vector and R(w) has the same
   interpretation as above.

For a detailed discussion you should consult the following papers from the Journal of Machine Learning Research:
Optimized Cutting Plane Algorithm for Large-Scale Risk Minimization by Vojtech Franc, Soren Sonnenburg; 10(Oct):2157--2192, 2009.
Bundle Methods for Regularized Risk Minimization by Choon Hui Teo, S.V.N. Vishwanthan, Alex J. Smola, Quoc V. Le; 11(Jan):311-365, 2010.

More Details...
#include <dlib/optimization.h>
[top]

parse_tree_to_string

This is a set of functions useful for converting a parse tree output by find_max_parse_cky into a bracketed string suitable for displaying the parse tree.
More Details...
#include <dlib/optimization.h>
[top]

poly_min_extrap

This function finds the 2nd or 3rd degree polynomial that interpolates a set of points and returns the minimum of that polynomial.
More Details...
#include <dlib/optimization.h>
[top]

potts_model_score

This routine computes the model score for a Potts problem and a candidate labeling. This score is the quantity maximised by the find_max_factor_graph_potts routine.
More Details...
#include <dlib/graph_cuts.h>
[top]

solve_least_squares

This is a function for solving non-linear least squares problems. It uses a method which combines the traditional Levenberg-Marquardt technique with a quasi-newton approach. It is appropriate for large residual problems (i.e. problems where the terms in the least squares function, the residuals, don't go to zero but remain large at the solution)

C++ Example Programs: least_squares_ex.cpp
More Details...
#include <dlib/optimization.h>
[top]

solve_least_squares_lm

This is a function for solving non-linear least squares problems. It uses the traditional Levenberg-Marquardt technique. It is appropriate for small residual problems (i.e. problems where the terms in the least squares function, the residuals, go to zero at the solution)

C++ Example Programs: least_squares_ex.cpp
More Details...
#include <dlib/optimization.h>
[top]

solve_qp2_using_smo

This function solves the following quadratic program:
   Minimize: f(alpha) == 0.5*trans(alpha)*Q*alpha
   subject to the following constraints:
      sum(alpha) == nu*y.size()
      0 <= min(alpha) && max(alpha) <= 1
      trans(y)*alpha == 0

   Where all elements of y must be equal to +1 or -1 and f is convex.
   This means that Q should be symmetric and positive-semidefinite.

This object implements the strategy used by the LIBSVM tool. The following papers can be consulted for additional details:
  • Chang and Lin, Training {nu}-Support Vector Classifiers: Theory and Algorithms
  • Chih-Chung Chang and Chih-Jen Lin, LIBSVM : a library for support vector machines, 2001. Software available at http://www.csie.ntu.edu.tw/~cjlin/libsvm

More Details...
#include <dlib/optimization.h>
[top]

solve_qp3_using_smo

This function solves the following quadratic program:
   Minimize: f(alpha) == 0.5*trans(alpha)*Q*alpha + trans(p)*alpha
   subject to the following constraints:
        for all i such that y(i) == +1:  0 <= alpha(i) <= Cp
        for all i such that y(i) == -1:  0 <= alpha(i) <= Cn
        trans(y)*alpha == B

   Where all elements of y must be equal to +1 or -1 and f is convex.
   This means that Q should be symmetric and positive-semidefinite.

This object implements the strategy used by the LIBSVM tool. The following papers can be consulted for additional details:
  • Chih-Chung Chang and Chih-Jen Lin, LIBSVM : a library for support vector machines, 2001. Software available at http://www.csie.ntu.edu.tw/~cjlin/libsvm
  • Working Set Selection Using Second Order Information for Training Support Vector Machines by Fan, Chen, and Lin. In the Journal of Machine Learning Research 2005.

More Details...
#include <dlib/optimization.h>
[top]

solve_qp4_using_smo

This function solves the following quadratic program:
   Minimize: f(alpha,lambda) == 0.5*trans(alpha)*Q*alpha - trans(alpha)*b +
                                0.5*trans(lambda)*lambda - trans(lambda)*A*alpha
   subject to the following constraints:
      sum(alpha)  == C
      min(alpha)  >= 0
      min(lambda) >= 0
   Where f is convex.  This means that Q should be positive-semidefinite.

More Details...
#include <dlib/optimization.h>
[top]

solve_qp_using_smo

This function solves the following quadratic program:
   Minimize: f(alpha) == 0.5*trans(alpha)*Q*alpha - trans(alpha)*b
   subject to the following constraints:
      sum(alpha) == C
      min(alpha) >= 0
   Where f is convex.  This means that Q should be symmetric and positive-semidefinite.

More Details...
#include <dlib/optimization.h>
[top]

solve_trust_region_subproblem

This function solves the following optimization problem:
Minimize: f(p) == 0.5*trans(p)*B*p + trans(g)*p
subject to the following constraint:
   length(p) <= radius

More Details...
#include <dlib/optimization.h>


dlib C++ Library - optimization_abstract.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_OPTIMIZATIOn_ABSTRACT_
#ifdef DLIB_OPTIMIZATIOn_ABSTRACT_

#include <cmath>
#include <limits>
#include "../matrix/matrix_abstract.h"
#include "../algs.h"
#include "optimization_search_strategies_abstract.h"
#include "optimization_stop_strategies_abstract.h"
#include "optimization_line_search_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                    Functions that transform other functions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename funct
        >
    class central_differences;
    /*!
        This is a function object that represents the derivative of some other
        function.

        Note that if funct is a function of a double then the derivative of
        funct is just a double but if funct is a function of a dlib::matrix (i.e. a
        function of many variables) then its derivative is a gradient vector (a column
        vector in particular).
    !*/

    template <
        typename funct
        >
    const central_differences<funct> derivative(
        const funct& f,
        double eps
    );
    /*!
        requires
            - f == a function that returns a scalar
            - f must have one of the following forms:
                - double f(double)
                - double f(dlib::matrix)  (where the matrix is a column vector)
                - double f(T, dlib::matrix)  (where the matrix is a column vector.  In
                  this case the derivative of f is taken with respect to the second argument.)
            - eps > 0
        ensures
            - returns a function that represents the derivative of the function f.  It
              is approximated numerically by:
                  (f(x+eps)-f(x-eps))/(2*eps)
    !*/

    template <
        typename funct
        >
    const central_differences<funct> derivative(
        const funct& f
    );
    /*!
        ensures
            - returns derivative(f, 1e-7)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename funct,
        typename EXP1,
        typename EXP2
        >
    clamped_function_object<funct,EXP1,EXP2> clamp_function (
        const funct& f,
        const matrix_exp<EXP1>& x_lower,
        const matrix_exp<EXP2>& x_upper
    );
    /*!
        requires
            - f == a function that takes a matrix and returns a scalar value.  Moreover, f
              must be capable of taking in matrices with the same dimensions as x_lower and
              x_upper.  So f(x_lower) must be a valid expression that evaluates to a scalar
              value.
            - x_lower.nr() == x_upper.nr() && x_lower.nc() == x_upper.nc()
              (i.e. x_lower and x_upper must have the same dimensions)
            - x_lower and x_upper must contain the same type of elements.
        ensures
            - returns a function object that represents the function g(x) where
              g(x) == f(clamp(x,x_lower,x_upper))
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                    Functions that perform unconstrained optimization
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename search_strategy_type,
        typename stop_strategy_type,
        typename funct,
        typename funct_der,
        typename T
        >
    double find_min (
        search_strategy_type search_strategy,
        stop_strategy_type stop_strategy,
        const funct& f,
        const funct_der& der,
        T& x,
        double min_f
    );
    /*!
        requires
            - search_strategy == an object that defines a search strategy such as one
              of the objects from dlib/optimization/optimization_search_strategies_abstract.h
            - stop_strategy == an object that defines a stop strategy such as one of
              the objects from dlib/optimization/optimization_stop_strategies_abstract.h
            - f(x) must be a valid expression that evaluates to a double
            - der(x) must be a valid expression that evaluates to the derivative of f() at x.
            - is_col_vector(x) == true
        ensures
            - Performs an unconstrained minimization of the function f() using the given
              search_strategy and starting from the initial point x.
            - The function is optimized until stop_strategy decides that an acceptable
              point has been found or f(#x) < min_f.
            - #x == the value of x that was found to minimize f()
            - returns f(#x).
            - When this function makes calls to f() and der() it always does so by
              first calling f() and then calling der().  That is, these two functions
              are always called in pairs with f() being called first and then der()
              being called second.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename search_strategy_type,
        typename stop_strategy_type,
        typename funct,
        typename funct_der,
        typename T
        >
    double find_max (
        search_strategy_type search_strategy,
        stop_strategy_type stop_strategy,
        const funct& f,
        const funct_der& der,
        T& x,
        double max_f
    );
    /*!
        requires
            - search_strategy == an object that defines a search strategy such as one
              of the objects from dlib/optimization/optimization_search_strategies_abstract.h
            - stop_strategy == an object that defines a stop strategy such as one of
              the objects from dlib/optimization/optimization_stop_strategies_abstract.h
            - f(x) must be a valid expression that evaluates to a double
            - der(x) must be a valid expression that evaluates to the derivative of f() at x.
            - is_col_vector(x) == true
        ensures
            - Performs an unconstrained maximization of the function f() using the given
              search_strategy and starting from the initial point x.
            - The function is optimized until stop_strategy decides that an acceptable
              point has been found or f(#x) > max_f.
            - #x == the value of x that was found to maximize f()
            - returns f(#x).
            - When this function makes calls to f() and der() it always does so by
              first calling f() and then calling der().  That is, these two functions
              are always called in pairs with f() being called first and then der()
              being called second.
            - Note that this function solves the maximization problem by converting it
              into a minimization problem.  Therefore, the values of f and its derivative
              reported to the stopping strategy will be negated.  That is, stop_strategy
              will see -f() and -der().  All this really means is that the status messages
              from a stopping strategy in verbose mode will display a negated objective
              value.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename search_strategy_type,
        typename stop_strategy_type,
        typename funct,
        typename T
        >
    double find_min_using_approximate_derivatives (
        search_strategy_type search_strategy,
        stop_strategy_type stop_strategy,
        const funct& f,
        T& x,
        double min_f,
        double derivative_eps = 1e-7
    );
    /*!
        requires
            - search_strategy == an object that defines a search strategy such as one
              of the objects from dlib/optimization/optimization_search_strategies_abstract.h
            - stop_strategy == an object that defines a stop strategy such as one of
              the objects from dlib/optimization/optimization_stop_strategies_abstract.h
            - f(x) must be a valid expression that evaluates to a double
            - is_col_vector(x) == true
            - derivative_eps > 0
        ensures
            - Performs an unconstrained minimization of the function f() using the given
              search_strategy and starting from the initial point x.
            - The function is optimized until stop_strategy decides that an acceptable
              point has been found or f(#x) < min_f.
            - #x == the value of x that was found to minimize f()
            - returns f(#x).
            - Uses the dlib::derivative(f,derivative_eps) function to compute gradient
              information.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename search_strategy_type,
        typename stop_strategy_type,
        typename funct,
        typename T
        >
    double find_max_using_approximate_derivatives (
        search_strategy_type search_strategy,
        stop_strategy_type stop_strategy,
        const funct& f,
        T& x,
        double max_f,
        double derivative_eps = 1e-7
    );
    /*!
        requires
            - search_strategy == an object that defines a search strategy such as one
              of the objects from dlib/optimization/optimization_search_strategies_abstract.h
            - stop_strategy == an object that defines a stop strategy such as one of
              the objects from dlib/optimization/optimization_stop_strategies_abstract.h
            - f(x) must be a valid expression that evaluates to a double
            - is_col_vector(x) == true
            - derivative_eps > 0
        ensures
            - Performs an unconstrained maximization of the function f() using the given
              search_strategy and starting from the initial point x.
            - The function is optimized until stop_strategy decides that an acceptable
              point has been found or f(#x) > max_f.
            - #x == the value of x that was found to maximize f()
            - returns f(#x).
            - Uses the dlib::derivative(f,derivative_eps) function to compute gradient
              information.
            - Note that this function solves the maximization problem by converting it
              into a minimization problem.  Therefore, the values of f and its derivative
              reported to the stopping strategy will be negated.  That is, stop_strategy
              will see -f() and -der().  All this really means is that the status messages
              from a stopping strategy in verbose mode will display a negated objective
              value.
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                  Functions that perform box constrained optimization
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename search_strategy_type,
        typename stop_strategy_type,
        typename funct,
        typename funct_der,
        typename T,
        typename EXP1,
        typename EXP2
        >
    double find_min_box_constrained (
        search_strategy_type search_strategy,
        stop_strategy_type stop_strategy,
        const funct& f,
        const funct_der& der,
        T& x,
        const matrix_exp<EXP1>& x_lower,
        const matrix_exp<EXP2>& x_upper
    );
    /*!
        requires
            - search_strategy == an object that defines a search strategy such as one
              of the objects from dlib/optimization/optimization_search_strategies_abstract.h
            - stop_strategy == an object that defines a stop strategy such as one of
              the objects from dlib/optimization/optimization_stop_strategies_abstract.h
            - f(x) must be a valid expression that evaluates to a double
            - der(x) must be a valid expression that evaluates to the derivative of f() at x.
            - is_col_vector(x) == true
            - is_col_vector(x_lower) == true
            - is_col_vector(x_upper) == true
            - x.size() == x_lower.size() == x_upper.size()
              (i.e. x, x_lower, and x_upper need to all be column vectors of the same dimensionality)
            - min(x_upper-x_lower) > 0
              (i.e. x_upper must contain upper bounds relative to x_lower)
        ensures
            - Performs a box constrained minimization of the function f() using the given
              search_strategy and starting from the initial point x.  That is, we try to
              find the x value that minimizes f(x) but is also within the box constraints
              specified by x_lower and x_upper.  That is, we ensure that #x satisfies:
                - min(#x - x_lower) >= 0 && min(x_upper - #x) >= 0
            - This function uses a backtracking line search along with a gradient projection
              step to handle the box constraints.
            - The function is optimized until stop_strategy decides that an acceptable
              point has been found.
            - #x == the value of x that was found to minimize f() within the given box
              constraints.
            - returns f(#x).
            - The last call to f() will be made with f(#x).
            - When calling f() and der(), the input passed to them will always be inside
              the box constraints defined by x_lower and x_upper.
            - When calling der(x), it will always be the case that the last call to f() was
              made with the same x value.  This means that you can reuse any intermediate
              results from the previous call to f(x) inside der(x) rather than recomputing
              them inside der(x).
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename search_strategy_type,
        typename stop_strategy_type,
        typename funct,
        typename funct_der,
        typename T
        >
    double find_min_box_constrained (
        search_strategy_type search_strategy,
        stop_strategy_type stop_strategy,
        const funct& f,
        const funct_der& der,
        T& x,
        const double x_lower,
        const double x_upper
    );
    /*!
        requires
            - search_strategy == an object that defines a search strategy such as one
              of the objects from dlib/optimization/optimization_search_strategies_abstract.h
            - stop_strategy == an object that defines a stop strategy such as one of
              the objects from dlib/optimization/optimization_stop_strategies_abstract.h
            - f(x) must be a valid expression that evaluates to a double
            - der(x) must be a valid expression that evaluates to the derivative of f() at x.
            - is_col_vector(x) == true
            - x_lower < x_upper
        ensures
            - This function is identical to find_min_box_constrained() as defined above
              except that it takes x_lower and x_upper as doubles rather than column
              vectors.  In this case, all variables have the same lower bound of x_lower
              and similarly have the same upper bound of x_upper.  Therefore, this is just
              a convenience function for calling find_max_box_constrained() when all
              variables have the same bound constraints.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename search_strategy_type,
        typename stop_strategy_type,
        typename funct,
        typename funct_der,
        typename T,
        typename EXP1,
        typename EXP2
        >
    double find_max_box_constrained (
        search_strategy_type search_strategy,
        stop_strategy_type stop_strategy,
        const funct& f,
        const funct_der& der,
        T& x,
        const matrix_exp<EXP1>& x_lower,
        const matrix_exp<EXP2>& x_upper
    );
    /*!
        requires
            - search_strategy == an object that defines a search strategy such as one
              of the objects from dlib/optimization/optimization_search_strategies_abstract.h
            - stop_strategy == an object that defines a stop strategy such as one of
              the objects from dlib/optimization/optimization_stop_strategies_abstract.h
            - f(x) must be a valid expression that evaluates to a double
            - der(x) must be a valid expression that evaluates to the derivative of f() at x.
            - is_col_vector(x) == true
            - is_col_vector(x_lower) == true
            - is_col_vector(x_upper) == true
            - x.size() == x_lower.size() == x_upper.size()
              (i.e. x, x_lower, and x_upper need to all be column vectors of the same dimensionality)
            - min(x_upper-x_lower) > 0
              (i.e. x_upper must contain upper bounds relative to x_lower)
        ensures
            - Performs a box constrained maximization of the function f() using the given
              search_strategy and starting from the initial point x.  That is, we try to
              find the x value that maximizes f(x) but is also within the box constraints
              specified by x_lower and x_upper.  That is, we ensure that #x satisfies:
                - min(#x - x_lower) >= 0 && min(x_upper - #x) >= 0
            - This function uses a backtracking line search along with a gradient projection
              step to handle the box constraints.
            - The function is optimized until stop_strategy decides that an acceptable
              point has been found.
            - #x == the value of x that was found to maximize f() within the given box
              constraints.
            - returns f(#x).
            - The last call to f() will be made with f(#x).
            - When calling f() and der(), the input passed to them will always be inside
              the box constraints defined by x_lower and x_upper.
            - When calling der(x), it will always be the case that the last call to f() was
              made with the same x value.  This means that you can reuse any intermediate
              results from the previous call to f(x) inside der(x) rather than recomputing
              them inside der(x).
            - Note that this function solves the maximization problem by converting it
              into a minimization problem.  Therefore, the values of f and its derivative
              reported to the stopping strategy will be negated.  That is, stop_strategy
              will see -f() and -der().  All this really means is that the status messages
              from a stopping strategy in verbose mode will display a negated objective
              value.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename search_strategy_type,
        typename stop_strategy_type,
        typename funct,
        typename funct_der,
        typename T
        >
    double find_max_box_constrained (
        search_strategy_type search_strategy,
        stop_strategy_type stop_strategy,
        const funct& f,
        const funct_der& der,
        T& x,
        const double x_lower,
        const double x_upper
    );
    /*!
        requires
            - search_strategy == an object that defines a search strategy such as one
              of the objects from dlib/optimization/optimization_search_strategies_abstract.h
            - stop_strategy == an object that defines a stop strategy such as one of
              the objects from dlib/optimization/optimization_stop_strategies_abstract.h
            - f(x) must be a valid expression that evaluates to a double
            - der(x) must be a valid expression that evaluates to the derivative of f() at x.
            - is_col_vector(x) == true
            - x_lower < x_upper
        ensures
            - This function is identical to find_max_box_constrained() as defined above
              except that it takes x_lower and x_upper as doubles rather than column
              vectors.  In this case, all variables have the same lower bound of x_lower
              and similarly have the same upper bound of x_upper.  Therefore, this is just
              a convenience function for calling find_max_box_constrained() when all
              variables have the same bound constraints.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_OPTIMIZATIOn_ABSTRACT_


dlib C++ Library - optimization_bobyqa_abstract.h

// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_OPTIMIZATIOn_BOBYQA_ABSTRACT_Hh_
#ifdef DLIB_OPTIMIZATIOn_BOBYQA_ABSTRACT_Hh_

#include "../matrix.h"

// ----------------------------------------------------------------------------------------

/*
    This file defines the dlib interface to the BOBYQA software developed by M.J.D Powell.
    BOBYQA is a method for optimizing a function in the absence of derivative information.
    Powell described it as a method that seeks the least value of a function of many
    variables, by applying a trust region method that forms quadratic models by
    interpolation.  There is usually some freedom in the interpolation conditions,
    which is taken up by minimizing the Frobenius norm of the change to the second
    derivative of the model, beginning with the zero matrix. The values of the variables
    are constrained by upper and lower bounds.

    The following paper, published in 2009 by Powell, describes the
    detailed working of the BOBYQA algorithm.

        The BOBYQA algorithm for bound constrained optimization
        without derivatives by M.J.D. Powell
*/

// ----------------------------------------------------------------------------------------

namespace dlib
{
    class bobyqa_failure : public error;
    /*!
        This is the exception class used by the functions defined in this file.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename funct,
        typename T,
        typename U
        >
    double find_min_bobyqa (
        const funct& f,
        T& x,
        long npt,
        const U& x_lower,
        const U& x_upper,
        const double rho_begin,
        const double rho_end,
        const long max_f_evals
    );
    /*!
        requires
            - f(x) must be a valid expression that evaluates to a double
            - is_col_vector(x) == true
            - is_col_vector(x_lower) == true
            - is_col_vector(x_upper) == true
            - x.size() == x_lower.size() == x_upper.size()
            - x.size() > 1
            - x.size() + 2 <= npt <= (x.size()+1)*(x.size()+2)/2
            - 0 < rho_end < rho_begin
            - min(x_upper - x_lower) > 2*rho_begin
              (i.e. the lower and upper bounds on each x element must be larger than 2*rho_begin)
            - min(x - x_lower) >= 0 && min(x_upper - x) >= 0
              (i.e. the given x should be within the bounds defined by x_lower and x_upper)
            - max_f_evals > 1
        ensures
            - Performs a constrained minimization of the function f() starting from
              the initial point x.
            - The BOBYQA algorithm uses a number of interpolating points to perform its
              work.  The npt argument controls how many points get used.  Typically,
              a good value to use is 2*x.size()+1.
            - #x == the value of x (within the bounds defined by x_lower and x_upper) that
              was found to minimize f().  More precisely:
                - min(#x - x_lower) >= 0 && min(x_upper - #x) >= 0
            - returns f(#x).
            - rho_begin and rho_end are used as the initial and final values of a trust
              region radius.  Typically, rho_begin should be about one tenth of the greatest
              expected change to a variable, while rho_end should indicate the accuracy that
              is required in the final values of the variables.
        throws
            - bobyqa_failure
                This exception is thrown if the algorithm is unable to make progress towards
                solving the problem.  This may occur because the algorithm detects excessive
                numerical errors or because max_f_evals of f() have occurred without reaching
                convergence.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename funct,
        typename T,
        typename U
        >
    double find_max_bobyqa (
        const funct& f,
        T& x,
        long npt,
        const U& x_lower,
        const U& x_upper,
        const double rho_begin,
        const double rho_end,
        const long max_f_evals
    );
    /*!
        This function is identical to the find_min_bobyqa() routine defined above
        except that it negates the f() function before performing optimization.
        Thus this function will attempt to find the maximizer of f() rather than
        the minimizer.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_OPTIMIZATIOn_BOBYQA_ABSTRACT_Hh_


dlib C++ Library - optimization_line_search_abstract.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_OPTIMIZATIOn_ABSTRACT_
#ifdef DLIB_OPTIMIZATIOn_ABSTRACT_

#include <cmath>
#include <limits>
#include "../matrix/matrix_abstract.h"
#include "../algs.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename funct,
        typename T
        >
    class line_search_funct;
    /*!
        This object is a function object that represents a line search function.

        Moreover, it represents a function with the signature:
            double l(double x)
    !*/

    template <
        typename funct,
        typename T
        >
    const line_search_funct<funct,T> make_line_search_function (
        const funct& f,
        const T& start,
        const T& direction
    );
    /*!
        requires
            - is_col_vector(start) && is_col_vector(direction) && start.size() == direction.size()
              (i.e. start and direction should be column vectors of the same size)
            - f must return either a double or a column vector the same length as start
            - f(start + 1.5*direction) should be a valid expression
        ensures
            - if (f returns a double) then
                - returns a line search function that computes l(x) == f(start + x*direction)
            - else
                - returns a line search function that computes l(x) == dot(f(start + x*direction),direction).
                  That is, we assume f is the derivative of some other function and that what
                  f returns is a gradient vector.
                  So the following two expressions both create the derivative of l(x):
                    - derivative(make_line_search_function(funct,start,direction))
                    - make_line_search_function(derivative(funct),start,direction)
    !*/

    template <
        typename funct,
        typename T
        >
    const line_search_funct<funct,T> make_line_search_function (
        const funct& f,
        const T& start,
        const T& direction,
        double& f_out
    );
    /*!
        This function is identical to the above three argument version of make_line_search_function()
        except that, if f() outputs a double, every time f() is evaluated its output is also stored
        into f_out.
    !*/

    template <
        typename funct,
        typename T
        >
    const line_search_funct<funct,T> make_line_search_function (
        const funct& f,
        const T& start,
        const T& direction,
        T& gradient_out
    );
    /*!
        This function is identical to the above three argument version of make_line_search_function()
        except that, if f() outputs a column vector, every time f() is evaluated its output is also
        stored into gradient_out.
    !*/

// ----------------------------------------------------------------------------------------

    inline double poly_min_extrap (
        double f0,
        double d0,
        double f1,
        double d1
    );
    /*!
        ensures
            - let c(x) be a 3rd degree polynomial such that:
                - c(0) == f0
                - c(1) == f1
                - derivative of c(x) at x==0 is d0
                - derivative of c(x) at x==1 is d1
            - returns the point in the range [0,1] that minimizes the polynomial c(x)
    !*/

// ----------------------------------------------------------------------------------------

    inline double poly_min_extrap (
        double f0,
        double d0,
        double f1
    );
    /*!
        ensures
            - let c(x) be a 2nd degree polynomial such that:
                - c(0) == f0
                - c(1) == f1
                - derivative of c(x) at x==0 is d0
            - returns the point in the range [0,1] that minimizes the polynomial c(x)
    !*/

// ----------------------------------------------------------------------------------------

    inline double poly_min_extrap (
        double f0,
        double d0,
        double x1,
        double f_x1,
        double x2,
        double f_x2
    )
    /*!
        requires
            - 0 < x1 < x2
        ensures
            - let f(x) be a 3rd degree polynomial such that:
                - f(0) == f0
                - derivative of f(x) at x==0 is d0
                - f(x1) == f_x1
                - f(x2) == f_x2
            - returns the point in the range [0,x2] that minimizes the polynomial f(x)
    !*/

// ----------------------------------------------------------------------------------------

    inline double lagrange_poly_min_extrap (
        double p1,
        double p2,
        double p3,
        double f1,
        double f2,
        double f3
    );
    /*!
        requires
            - f1 >= f2 <= f3
            - p1 < p2 < p3
        ensures
            - let c(x) be the second order Lagrange polynomial that interpolates the
              points p1, p2, and p3 where c(p1)==f1, c(p2)==f2, and c(p3)==f3
            - this function returns the point in the range [p1,p3] that minimizes
              the polynomial c(x)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename funct,
        typename funct_der
        >
    double line_search (
        const funct& f,
        const double f0,
        const funct_der& der,
        const double d0,
        double rho,
        double sigma,
        double min_f,
        unsigned long max_iter
    )
    /*!
        requires
            - 0 < rho < sigma < 1
            - f and der are scalar functions of scalars
              (e.g. line_search_funct objects)
            - der is the derivative of f
            - f0 == f(0)
            - d0 == der(0)
            - max_iter > 0
        ensures
            - Performs a line search and uses the strong Wolfe conditions to decide when
              the search can stop.
                - rho == the parameter of the Wolfe sufficient decrease condition
                - sigma == the parameter of the Wolfe curvature condition
                - max_iter == the maximum number of iterations allowable.  After this
                  many evaluations of f() line_search() is guaranteed to terminate.
            - returns a value alpha such that f(alpha) is significantly closer to
              the minimum of f than f(0).
            - It is assumed that the minimum possible value of f(x) is min_f.  So if
              an alpha is found such that f(alpha) <= min_f then the search stops
              immediately.
            - This function is also optimized for the case where der(0) is negative.  I.e.
              positive values of the argument to f() should be in a descent direction.
            - When this function makes calls to f() and der() it always does so by
              first calling f() and then calling der().  That is, these two functions
              are always called in pairs with f() being called first and then der()
              being called second.
    !*/

    /*
        A good discussion of the Wolfe conditions and line search algorithms in
        general can be found in the book Practical Methods of Optimization by R. Fletcher
        and also in the more recent book Numerical Optimization by Nocedal and Wright.
    */

// ----------------------------------------------------------------------------------------

    template <
        typename funct
        >
    double backtracking_line_search (
        const funct& f,
        double f0,
        double d0,
        double alpha,
        double rho,
        unsigned long max_iter
    );
    /*!
        requires
            - 0 < rho < 1
            - f is a scalar function of scalars
              (e.g. a line_search_funct object)
            - f0 == f(0)
            - d0 == the derivative of f() at f(0).
            - max_iter > 0
        ensures
            - Performs a backtracking line search and uses the Armijo sufficient decrease
              rule to decide when the search can stop.
                - rho == the parameter of the sufficient decrease condition.
                - max_iter == the maximum number of iterations allowable.  After this many
                  evaluations of f() backtracking_line_search() is guaranteed to terminate.
            - The line search starts with the input alpha value and then backtracks until
              it finds a good enough alpha value.  Once found, it returns the alpha value
              such that f(alpha) is significantly closer to the minimum of f than f(0).
            - The returned value of alpha will always be the last value of alpha which was
              passed to f().  That is, it will always be the case that the last call to f()
              made by backtracking_line_search() was f(alpha) where alpha is the return
              value from this function.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename funct
        >
    const negate_function_object<funct> negate_function(
        const funct& f
    );
    /*!
        requires
            - f == a function that returns a scalar
        ensures
            - returns a function that represents the negation of f.  That is,
              the returned function object represents g(x) == -f(x)
    !*/

// ----------------------------------------------------------------------------------------

    class optimize_single_variable_failure : public error;
    /*!
        This is the exception class used by the functions defined below.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename funct
        >
    double find_min_single_variable (
        const funct& f,
        double& starting_point,
        const double begin = -1e200,
        const double end = 1e200,
        const double eps = 1e-3,
        const long max_iter = 100,
        const double initial_search_radius = 1
    )
    /*!
        requires
            - eps > 0
            - max_iter > 1
            - begin <= starting_point <= end
            - f must be a function of a double that returns a double
              (e.g. f(starting_point) should be a valid expression that evaluates to a double)
            - initial_search_radius > 0
        ensures
            - Finds a point P such that:
                - P is a local minimum of the function f().
                - begin <= P <= end
            - Evaluates f() no more than max_iter times
            - Stops searching when the window around the minimum point is smaller than eps.
              The search will begin with the given starting_point and expand out to the
              left and right by initial_search_radius sized steps.  So if you think the
              minimum is likely to be found within X distance from the starting_point then
              set initial_search_radius to X.
            - #starting_point == P
            - returns f(P)
        throws
            - optimize_single_variable_failure
                This exception is thrown if max_iter iterations are performed without
                determining the min point to the requested accuracy of eps.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename funct
        >
    double find_max_single_variable (
        const funct& f,
        double& starting_point,
        const double begin = -1e200,
        const double end = 1e200,
        const double eps = 1e-3,
        const long max_iter = 100,
        const double initial_search_radius = 1
    )
    /*!
        requires
            - eps > 0
            - max_iter > 1
            - begin <= starting_point <= end
            - f must be a function of a double that returns a double
              (e.g. f(starting_point) should be a valid expression that evaluates to a double)
            - initial_search_radius > 0
        ensures
            - Finds a point P such that:
                - P is a local maximum of the function f().
                - begin <= P <= end
            - Evaluates f() no more than max_iter times
            - Stops searching when the window around the maximum point is smaller than eps.
              The search will begin with the given starting_point and expand out to the
              left and right by initial_search_radius sized steps.  So if you think the
              maximum is likely to be found within X distance from the starting_point then
              set initial_search_radius to X.
            - #starting_point == P
            - returns f(P)
        throws
            - optimize_single_variable_failure
                This exception is thrown if max_iter iterations are performed without
                determining the max point to the requested accuracy of eps.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_OPTIMIZATIOn_ABSTRACT_


dlib C++ Library - optimization_trust_region_abstract.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_OPTIMIZATION_TRUST_REGIoN_H_ABSTRACTh_
#ifdef DLIB_OPTIMIZATION_TRUST_REGIoN_H_ABSTRACTh_

#include "../matrix/matrix_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename EXP1,
        typename EXP2,
        typename T, long NR, long NC, typename MM, typename L
        >
    unsigned long solve_trust_region_subproblem (
        const matrix_exp<EXP1>& B,
        const matrix_exp<EXP2>& g,
        const typename EXP1::type radius,
        matrix<T,NR,NC,MM,L>& p,
        double eps,
        unsigned long max_iter
    );
    /*!
        requires
            - B == trans(B)
              (i.e. B should be a symmetric matrix)
            - B.nr() == B.nc()
            - is_col_vector(g) == true
            - g.size() == B.nr()
            - p is capable of containing a column vector the size of g
              (i.e. p = g; should be a legal expression)
            - radius > 0
            - eps > 0
            - max_iter > 0
        ensures
            - This function solves the following optimization problem:
                Minimize: f(p) == 0.5*trans(p)*B*p + trans(g)*p
                subject to the following constraint:
                    - length(p) <= radius
            - returns the number of iterations performed.  If this method fails to converge
              to eps accuracy then the number returned will be max_iter+1.
            - if (this function didn't terminate due to hitting the max_iter iteration limit) then
                - if this function returns 0 or 1 then we are not hitting the radius bound Otherwise,
                  the radius constraint is active and std::abs(length(#p)-radius)/radius <= eps.
    !*/

// ----------------------------------------------------------------------------------------

    class function_model
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object defines the interface for a function model
                used by the trust-region optimizers defined below.

                In particular, this object represents a function f() and
                its associated derivative and hessian.

        !*/

    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;
        /*!
            ensures
                - returns f(x)
                  (i.e. evaluates this model at the given point and returns the value)
        !*/

        void get_derivative_and_hessian (
            const column_vector& x,
            column_vector& d,
            general_matrix& h
        ) const;
        /*!
            ensures
                - #d == the derivative of f() at x
                - #h == the hessian matrix of f() at x
                - is_col_vector(#d) == true
                - #d.size() == x.size()
                - #h.nr() == #h.nc() == x.size()
                - #h == trans(#h)
        !*/
    };

// ----------------------------------------------------------------------------------------

    template <
        typename stop_strategy_type,
        typename funct_model
        >
    double find_min_trust_region (
        stop_strategy_type stop_strategy,
        const funct_model& model,
        typename funct_model::column_vector& x,
        double radius = 1
    );
    /*!
        requires
            - stop_strategy == an object that defines a stop strategy such as one of
              the objects from dlib/optimization/optimization_stop_strategies_abstract.h
            - is_col_vector(x) == true
            - radius > 0
            - model must be an object with an interface as defined by the function_model
              example object shown above.
        ensures
            - Performs an unconstrained minimization of the function defined by model
              starting from the initial point x.  This function uses a trust region
              algorithm to perform the minimization.  The radius parameter defines
              the initial size of the trust region.
            - The function is optimized until stop_strategy decides that an acceptable
              point has been found or the trust region subproblem fails to make progress.
            - #x == the value of x that was found to minimize model()
            - returns model(#x).
            - When this function makes calls to model.get_derivative_and_hessian() it always
              does so by first calling model() and then calling model.get_derivative_and_hessian().
              That is, any call to model.get_derivative_and_hessian(val) will always be
              preceded by a call to model(val) with the same value.  This way you can reuse
              any redundant computations performed by model() and model.get_derivative_and_hessian()
              as appropriate.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename stop_strategy_type,
        typename funct_model
        >
    double find_max_trust_region (
        stop_strategy_type stop_strategy,
        const funct_model& model,
        typename funct_model::column_vector& x,
        double radius = 1
    );
    /*!
        requires
            - stop_strategy == an object that defines a stop strategy such as one of
              the objects from dlib/optimization/optimization_stop_strategies_abstract.h
            - is_col_vector(x) == true
            - radius > 0
            - model must be an object with an interface as defined by the function_model
              example object shown above.
        ensures
            - Performs an unconstrained maximization of the function defined by model
              starting from the initial point x.  This function uses a trust region
              algorithm to perform the maximization.  The radius parameter defines
              the initial size of the trust region.
            - The function is optimized until stop_strategy decides that an acceptable
              point has been found or the trust region subproblem fails to make progress.
            - #x == the value of x that was found to maximize model()
            - returns model(#x).
            - When this function makes calls to model.get_derivative_and_hessian() it always
              does so by first calling model() and then calling model.get_derivative_and_hessian().
              That is, any call to model.get_derivative_and_hessian(val) will always be
              preceded by a call to model(val) with the same value.  This way you can reuse
              any redundant computations performed by model() and model.get_derivative_and_hessian()
              as appropriate.
            - Note that this function solves the maximization problem by converting it
              into a minimization problem.  Therefore, the values of model() and its derivative
              reported to the stopping strategy will be negated.  That is, stop_strategy
              will see -model() and -derivative.  All this really means is that the status
              messages from a stopping strategy in verbose mode will display a negated objective
              value.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_OPTIMIZATION_TRUST_REGIoN_H_ABSTRACTh_


dlib C++ Library - find_max_factor_graph_nmplp_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_FIND_MAX_FACTOR_GRAPH_nMPLP_ABSTRACT_Hh_
#ifdef DLIB_FIND_MAX_FACTOR_GRAPH_nMPLP_ABSTRACT_Hh_

#include <vector>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class map_problem
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object represents a factor graph or graphical model.  In
                particular, this object defines the interface a MAP problem on
                a factor graph must implement if it is to be solved using the
                find_max_factor_graph_nmplp() routine defined at the bottom of this file.

                Note that there is no dlib::map_problem object.  What you are
                looking at here is simply the interface definition for a map problem.
                You must implement your own version of this object for the problem
                you wish to solve and then pass it to the find_max_factor_graph_nmplp() routine.

                Note also that a factor graph should not have any nodes which are
                neighbors with themselves.  Additionally, the graph is undirected. This
                mean that if A is a neighbor of B then B must be a neighbor of A for
                the map problem to be valid.

                Finally, note that the "neighbor" relationship between nodes means the
                following:  Two nodes are neighbors if and only if there is a potential
                function (implemented by the factor_value() method) which operates on
                the nodes.
        !*/

    public:

        class node_iterator
        {
            /*!
                WHAT THIS OBJECT REPRESENTS
                    This is a simple forward iterator for iterating over
                    the nodes/variables in this factor graph.

                    Note that you can't dereference the iterator and
                    obtain a value.  That is, the iterator is opaque to
                    the user.  It is used only as an argument to the other
                    methods defined in this interface.
            !*/

        public:
            node_iterator(
            );
            /*!
                ensures
                    - constructs an iterator in an undefined state
            !*/

            node_iterator(
                const node_iterator& item
            );
            /*!
                ensures
                    - #*this is a copy of item
            !*/

            node_iterator& operator= (
                const node_iterator& item
            );
            /*!
                ensures
                    - #*this is a copy of item
                    - returns #*this
            !*/

            bool operator== (
                const node_iterator& item
            ) const;
            /*!
                ensures
                    - returns true if *this and item both reference
                      the same node in the factor graph and false
                      otherwise.
            !*/

            bool operator!= (
                const node_iterator& item
            ) const;
            /*!
                ensures
                    - returns false if *this and item both reference
                      the same node in the factor graph and true
                      otherwise.
            !*/

            node_iterator& operator++(
            );
            /*!
                ensures
                    - advances *this to the next node in the factor graph.
                    - returns a reference to the updated *this
                      (i.e. this is the ++object form of the increment operator)
            !*/
        };

        class neighbor_iterator
        {
            /*!
                WHAT THIS OBJECT REPRESENTS
                    This is a simple forward iterator for iterating over
                    the nodes/variables in this factor graph.  This version
                    of the iterator is used for iterating over the neighbors
                    of another node in the graph.
            !*/

        public:
            neighbor_iterator(
            );
            /*!
                ensures
                    - constructs an iterator in an undefined state
            !*/

            neighbor_iterator(
                const neighbor_iterator& item
            );
            /*!
                ensures
                    - #*this is a copy of item
            !*/

            neighbor_iterator& operator= (
                const neighbor_iterator& item
            );
            /*!
                ensures
                    - #*this is a copy of item
                    - returns #*this
            !*/

            bool operator== (
                const neighbor_iterator& item
            ) const;
            /*!
                ensures
                    - returns true if *this and item both reference
                      the same node in the factor graph and false
                      otherwise.
            !*/

            bool operator!= (
                const neighbor_iterator& item
            ) const;
            /*!
                ensures
                    - returns false if *this and item both reference
                      the same node in the factor graph and true
                      otherwise.
            !*/

            neighbor_iterator& operator++(
            );
            /*!
                ensures
                    - advances *this to the next node in the factor graph.
                    - returns a reference to the updated *this
                      (i.e. this is the ++object form of the increment operator)
            !*/
        };

        unsigned long number_of_nodes (
        ) const;
        /*!
            ensures
                - returns the number of nodes in the factor graph.  Or in other words,
                  returns the number of variables in the MAP problem.
        !*/

        node_iterator begin(
        ) const;
        /*!
            ensures
                - returns an iterator to the first node in the graph.  If no such
                  node exists then returns end().
        !*/

        node_iterator end(
        ) const;
        /*!
            ensures
                - returns an iterator to one past the last node in the graph.
        !*/

        neighbor_iterator begin(
            const node_iterator& it
        ) const;
        /*!
            requires
                - it == a valid iterator (i.e. it must be in the range [begin(), end()))
            ensures
                - returns an iterator to the first neighboring node of the node
                  referenced by it.  If no such node exists then returns end(it).
        !*/

        neighbor_iterator begin(
            const neighbor_iterator& it
        ) const;
        /*!
            requires
                - it == a valid iterator. (i.e. it must be in the range
                  [begin(i), end(i)) where i is some valid iterator. )
            ensures
                - returns an iterator to the first neighboring node of the node
                  referenced by it.  If no such node exists then returns end(it).
        !*/

        neighbor_iterator end(
            const node_iterator& it
        ) const;
        /*!
            requires
                - it == a valid iterator (i.e. it must be in the range [begin(), end()))
            ensures
                - returns an iterator to one past the last neighboring node of the node
                  referenced by it.
        !*/

        neighbor_iterator end(
            const neighbor_iterator& it
        ) const;
        /*!
            requires
                - it == a valid iterator. (i.e. it must be in the range
                  [begin(i), end(i)) where i is some valid iterator. )
            ensures
                - returns an iterator to one past the last neighboring node of the node
                  referenced by it.
        !*/

        unsigned long node_id (
            const node_iterator& it
        ) const;
        /*!
            requires
                - it == a valid iterator (i.e. it must be in the range [begin(), end()))
            ensures
                - returns a number ID such that:
                    - 0 <= ID < number_of_nodes()
                    - ID == a number which uniquely identifies the node pointed to by it.
        !*/

        unsigned long node_id (
            const neighbor_iterator& it
        ) const;
        /*!
            requires
                - it == a valid iterator. (i.e. it must be in the range
                  [begin(i), end(i)) where i is some valid iterator. )
            ensures
                - returns a number ID such that:
                    - 0 <= ID < number_of_nodes()
                    - ID == a number which uniquely identifies the node pointed to by it.
        !*/

        unsigned long num_states (
            const node_iterator& it
        ) const;
        /*!
            requires
                - it == a valid iterator (i.e. it must be in the range [begin(), end()))
            ensures
                - returns the number of states attainable by the node/variable referenced by it.
        !*/

        unsigned long num_states (
            const neighbor_iterator& it
        ) const;
        /*!
            requires
                - it == a valid iterator. (i.e. it must be in the range
                  [begin(i), end(i)) where i is some valid iterator. )
            ensures
                - returns the number of states attainable by the node/variable referenced by it.
        !*/

        // The next four functions all have the same contract.
        double factor_value (const node_iterator& it1,     const node_iterator& it2,     unsigned long s1, unsigned long s2) const;
        double factor_value (const neighbor_iterator& it1, const node_iterator& it2,     unsigned long s1, unsigned long s2) const;
        double factor_value (const node_iterator& it1,     const neighbor_iterator& it2, unsigned long s1, unsigned long s2) const;
        double factor_value (const neighbor_iterator& it1, const neighbor_iterator& it2, unsigned long s1, unsigned long s2) const;
        /*!
            requires
                - it1 == a valid iterator
                - it2 == a valid iterator
                - 0 <= s1 < num_states(it1)
                - 0 <= s2 < num_states(it2)
                - it1 and it2 reference nodes which are neighbors in the factor graph
            ensures
                - returns the value of the factor/potential function for the given pair of
                  nodes, defined by it1 and it2, for the case where they take on the values
                  s1 and s2 respectively.
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <
        typename map_problem
        >
    void find_max_factor_graph_nmplp (
        const map_problem& prob,
        std::vector<unsigned long>& map_assignment,
        unsigned long max_iter,
        double eps
    );
    /*!
        requires
            - for all valid i: prob.num_states(i) >= 2
            - map_problem == an object with an interface compatible with the map_problem
              object defined at the top of this file.
            - eps > 0
        ensures
            - This function is a tool for approximately solving the given MAP problem in a graphical
              model or factor graph with pairwise potential functions.  That is, it attempts
              to solve a certain kind of optimization problem which can be defined as follows:
                 maximize: f(X)
                 where X is a set of integer valued variables and f(X) can be written as the
                 sum of functions which each involve only two variables from X.  In reference
                 to the prob object, the nodes in prob represent the variables in X and the
                 functions which are summed are represented by prob.factor_value().
            - #map_assignment == the result of the optimization.
            - #map_assignment.size() == prob.number_of_nodes()
            - for all valid i:
                - #map_assignment[prob.node_id(i)] < prob.num_states(i)
                - #map_assignment[prob.node_id(i)] == The approximate MAP assignment for node/variable i.
            - eps controls the stopping condition, smaller values of eps lead to more accurate
              solutions of the relaxed linear program but may take more iterations.  Note that
              the algorithm will never execute more than max_iter iterations regardless of
              the setting of eps.
            - If the graph is tree-structured then this routine always gives the exact solution
              to the MAP problem.  However, for graphs with cycles, the solution may be approximate.

            - This function is an implementation of the NMPLP algorithm introduced in the
              following papers:
                Fixing Max-Product: Convergent Message Passing Algorithms for MAP LP-Relaxations (2008)
                by Amir Globerson and Tommi Jaakkola

                Introduction to dual decomposition for inference (2011)
                by David Sontag, Amir Globerson, and Tommi Jaakkola
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_FIND_MAX_FACTOR_GRAPH_nMPLP_ABSTRACT_Hh_


dlib C++ Library - find_max_factor_graph_potts_abstract.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_FIND_MAX_FACTOR_GRAPH_PoTTS_ABSTRACT_Hh_
#ifdef DLIB_FIND_MAX_FACTOR_GRAPH_PoTTS_ABSTRACT_Hh_

#include "../matrix.h"
#include "min_cut_abstract.h"
#include "../graph_utils.h"
#include "../array2d/array2d_kernel_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class potts_problem
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object represents a boolean valued factor graph or graphical model
                that can be efficiently operated on using graph cuts.  In particular, this
                object defines the interface a MAP problem on a factor graph must
                implement if it is to be solved using the find_max_factor_graph_potts()
                routine defined at the bottom of this file.

                Note that there is no dlib::potts_problem object.  What you are looking
                at here is simply the interface definition for a Potts problem.  You must
                implement your own version of this object for the problem you wish to
                solve and then pass it to the find_max_factor_graph_potts() routine.

                Note also that a factor graph should not have any nodes which are
                neighbors with themselves.  Additionally, the graph is undirected. This
                mean that if A is a neighbor of B then B must be a neighbor of A for
                the MAP problem to be valid.
        !*/

    public:

        unsigned long number_of_nodes (
        ) const;
        /*!
            ensures
                - returns the number of nodes in the factor graph.  Or in other words,
                  returns the number of variables in the MAP problem/Potts model.
        !*/

        unsigned long number_of_neighbors (
            unsigned long idx
        ) const;
        /*!
            requires
                - idx < number_of_nodes()
            ensures
                - returns the number of neighbors of node idx.
        !*/

        // This is an optional variable which specifies a number that is always
        // greater than or equal to number_of_neighbors(idx).  If you don't know
        // the value at compile time then either don't include max_number_of_neighbors
        // in your potts_problem object or set it to 0.
        const static unsigned long max_number_of_neighbors = 0;

        unsigned long get_neighbor (
            unsigned long idx,
            unsigned long n
        ) const;
        /*!
            requires
                - idx < number_of_nodes()
                - n < number_of_neighbors(idx)
            ensures
                - returns the node index value of the n-th neighbor of
                  the node with index value idx.
                - The neighbor relationship is reciprocal.  That is, if
                  get_neighbor(A,i)==B then there is a value of j such
                  that get_neighbor(B,j)==A.
                - A node is never its own neighbor.  That is, there is
                  no i such that get_neighbor(idx,i)==idx.
        !*/

        unsigned long get_neighbor_idx (
            unsigned long idx1,
            unsigned long idx2
        ) const;
        /*!
            requires
                - idx1 < number_of_nodes()
                - idx2 < number_of_nodes()
            ensures
                - This function is basically the inverse of get_neighbor().
                - returns a number IDX such that:
                    - get_neighbor(idx1,IDX) == idx2
                    - IDX < number_of_neighbors(idx1)
        !*/

        void set_label (
            const unsigned long& idx,
            node_label value
        );
        /*!
            requires
                - idx < number_of_nodes()
            ensures
                - #get_label(idx) == value
        !*/

        node_label get_label (
            const unsigned long& idx
        ) const;
        /*!
            requires
                - idx < number_of_nodes()
            ensures
                - returns the current label for the idx-th node.  This is a value which is
                  0 if the node's label is false and is any other value if it is true.

                  Note that this value is not used by factor_value() or factor_value_disagreement().
                  It is simply here to provide a mechanism for find_max_factor_graph_potts()
                  to return its labeled result.  Additionally, the reason it returns a
                  node_label rather than a bool is because doing it this way facilitates
                  use of a graph cut algorithm for the solution of the MAP problem.  For
                  more of an explanation you should read the paper referenced by the min_cut
                  object.
        !*/

        // This typedef should be for a type like int or double.  It
        // must also be capable of representing signed values.
        typedef an_integer_or_real_type value_type;

        value_type factor_value (
            unsigned long idx
        ) const;
        /*!
            requires
                - idx < number_of_nodes()
            ensures
                - returns a value which indicates how "good" it is to assign the idx-th
                  node the label of true.  The larger the value, the more desirable it is
                  to give it this label.  Similarly, a negative value indicates that it is
                  better to give the node a label of false.
                - It is valid for the returned value to be positive or negative infinity.
                  A value of positive infinity indicates that the idx-th node must be labeled
                  true while negative infinity means it must be labeled false.
        !*/

        value_type factor_value_disagreement (
            unsigned long idx1,
            unsigned long idx2
        ) const;
        /*!
            requires
                - idx1 < number_of_nodes()
                - idx2 < number_of_nodes()
                - idx1 != idx2
                - the idx1-th node and idx2-th node are neighbors in the graph.  That is,
                  get_neighbor(idx1,i)==idx2 for some value of i.
            ensures
                - returns a number >= 0.  This is the penalty for giving node idx1 and idx2
                  different labels.  Larger values indicate a larger penalty.
                - this function is symmetric.  That is, it is true that:
                  factor_value_disagreement(i,j) == factor_value_disagreement(j,i)
                - It is valid for the returned value to be positive infinity.  Returning
                  infinity indicates that the idx1-th and idx2-th nodes must share the same
                  label.
        !*/

    };

// ----------------------------------------------------------------------------------------

    class potts_grid_problem
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is a specialization of a potts_problem to the case where
                the graph is a regular grid where each node is connected to its four
                neighbors.  An example of this is an image where each pixel is a node
                and is connected to its four immediate neighboring pixels.  Therefore,
                this object defines the interface this special kind of MAP problem
                must implement if it is to be solved by the find_max_factor_graph_potts(potts_grid_problem,array2d)
                routine defined at the end of this file.

                Note that all nodes always have four neighbors, even nodes on the edge
                of the graph.  This is because these border nodes are connected to
                the border nodes on the other side of the graph.  That is, the graph
                "wraps" around at the borders.
        !*/

    public:

        // This typedef should be for a type like int or double.  It
        // must also be capable of representing signed values.
        typedef an_integer_or_real_type value_type;

        long nr(
        ) const;
        /*!
            ensures
                - returns the number of rows in the grid
        !*/

        long nc(
        ) const;
        /*!
            ensures
                - returns the number of columns in the grid
        !*/

        value_type factor_value (
            unsigned long idx
        ) const;
        /*!
            requires
                - idx < nr()*nc()
            ensures
                - The grid is represented in row-major-order format.  Therefore, idx
                  identifies a node according to its position in the row-major-order
                  representation of the grid graph.  Or in other words, idx corresponds
                  to the following row and column location in the graph:
                    - row == idx/nc()
                    - col == idx%nc()
                - returns a value which indicates how "good" it is to assign the idx-th
                  node the label of true.  The larger the value, the more desirable it is
                  to give it this label.  Similarly, a negative value indicates that it is
                  better to give the node a label of false.
                - It is valid for the returned value to be positive or negative infinity.
                  A value of positive infinity indicates that the idx-th node must be labeled
                  true while negative infinity means it must be labeled false.
        !*/

        value_type factor_value_disagreement (
            unsigned long idx1,
            unsigned long idx2
        ) const;
        /*!
            requires
                - idx1 < nr()*nc()
                - idx2 < nr()*nc()
                - idx1 != idx2
                - the idx1-th node and idx2-th node are neighbors in the grid graph.
            ensures
                - The grid is represented in row-major-order format.  Therefore, idx1 and
                  idx2 identify nodes according to their positions in the row-major-order
                  representation of the grid graph.  For example, idx1 corresponds
                  to the following row and column location in the graph:
                    - row == idx1/nc()
                    - col == idx1%nc()
                - returns a number >= 0.  This is the penalty for giving node idx1 and idx2
                  different labels.  Larger values indicate a larger penalty.
                - this function is symmetric.  That is, it is true that:
                  factor_value_disagreement(i,j) == factor_value_disagreement(j,i)
                - It is valid for the returned value to be positive infinity.  Returning
                  infinity indicates that the idx1-th and idx2-th nodes must share the same
                  label.
        !*/
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename potts_problem
        >
    typename potts_problem::value_type potts_model_score (
        const potts_problem& prob
    );
    /*!
        requires
            - potts_problem == an object with an interface compatible with the potts_problem
              object defined at the top of this file.
            - for all valid i and j:
                - prob.factor_value_disagreement(i,j) >= 0
                - prob.factor_value_disagreement(i,j) == prob.factor_value_disagreement(j,i)
        ensures
            - computes the model score for the given potts_problem.  We define this
              precisely below:
                - let L(i) == the boolean label of the i-th variable in prob.  Or in other
                  words, L(i) == (prob.get_label(i) != 0).
                - let F == the sum of values of prob.factor_value(i) for only i values
                  where L(i) == true.
                - Let D == the sum of values of prob.factor_value_disagreement(i,j)
                  for only i and j values which meet the following conditions:
                    - i and j are neighbors in the graph defined by prob, that is,
                      it is valid to call prob.factor_value_disagreement(i,j).
                    - L(i) != L(j)
                    - i < j
                      (i.e. We want to make sure to only count the edge between i and j once)

                - Then this function returns F - D
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename graph_type
        >
    typename graph_type::edge_type potts_model_score (
        const graph_type& g,
        const std::vector<node_label>& labels
    );
    /*!
        requires
            - graph_type is an implementation of dlib/graph/graph_kernel_abstract.h
            - graph_type::edge_type is some signed type such as int or double
            - graph_type::type must be the same type as graph_type::edge_type
            - graph_contains_length_one_cycle(g) == false
            - for all valid i and j:
                - edge(g,i,j) >= 0
        ensures
            - This function does the same thing as the version of potts_model_score()
              defined above, except that this version operates on a dlib::graph
              instead of a potts_problem object.
            - computes the model score for the given graph and labeling.  We define this
              precisely below:
                - let L(i) == the boolean label of the i-th variable in g.  Or in other
                  words, L(i) == (labels[i] != 0).
                - let F == the sum of values of g.node(i).data for only i values
                  where L(i) == true.
                - Let D == the sum of values of edge(g,i,j) for only i and j
                  values which meet the following conditions:
                    - i and j are neighbors in the graph defined by g, that is,
                      it is valid to call edge(g,i,j).
                    - L(i) != L(j)
                    - i < j
                      (i.e. We want to make sure to only count the edge between i and j once)

                - Then this function returns F - D
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename potts_grid_problem,
        typename mem_manager
        >
    typename potts_grid_problem::value_type potts_model_score (
        const potts_grid_problem& prob,
        const array2d<node_label,mem_manager>& labels
    );
    /*!
        requires
            - prob.nr() == labels.nr()
            - prob.nc() == labels.nc()
            - potts_grid_problem == an object with an interface compatible with the
              potts_grid_problem object defined above.
            - for all valid i and j:
                - prob.factor_value_disagreement(i,j) >= 0
                - prob.factor_value_disagreement(i,j) == prob.factor_value_disagreement(j,i)
        ensures
            - computes the model score for the given potts_grid_problem.  We define this
              precisely below:
                - let L(i) == the boolean label of the i-th variable in prob.  Or in other
                  words, L(i) == (labels[i/labels.nc()][i%labels.nc()] != 0).
                - let F == the sum of values of prob.factor_value(i) for only i values
                  where L(i) == true.
                - Let D == the sum of values of prob.factor_value_disagreement(i,j)
                  for only i and j values which meet the following conditions:
                    - i and j are neighbors in the graph defined by prob, that is,
                      it is valid to call prob.factor_value_disagreement(i,j).
                    - L(i) != L(j)
                    - i < j
                      (i.e. We want to make sure to only count the edge between i and j once)

                - Then this function returns F - D
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename potts_problem
        >
    void find_max_factor_graph_potts (
        potts_problem& prob
    );
    /*!
        requires
            - potts_problem == an object with an interface compatible with the potts_problem
              object defined at the top of this file.
            - for all valid i and j:
                - prob.factor_value_disagreement(i,j) >= 0
                - prob.factor_value_disagreement(i,j) == prob.factor_value_disagreement(j,i)
        ensures
            - This function is a tool for exactly solving the MAP problem in a Potts
              model.  In particular, this means that this function finds the assignments
              to all the labels in prob which maximizes potts_model_score(#prob).
            - The optimal labels are stored in #prob.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename graph_type
        >
    void find_max_factor_graph_potts (
        const graph_type& g,
        std::vector<node_label>& labels
    );
    /*!
        requires
            - graph_type is an implementation of dlib/graph/graph_kernel_abstract.h
            - graph_type::edge_type is some signed type such as int or double
            - graph_type::type must be the same type as graph_type::edge_type
            - graph_contains_length_one_cycle(g) == false
            - for all valid i and j:
                - edge(g,i,j) >= 0
        ensures
            - This routine simply converts g into a potts_problem and calls the
              version of find_max_factor_graph_potts() defined above on it.  Therefore,
              this routine is just a convenience wrapper that lets you use a dlib::graph
              to represent a potts problem.  This means that this function maximizes
              the value of potts_model_score(g, #labels).
            - #labels.size() == g.number_of_nodes()
            - for all valid i:
                - #labels[i] == the optimal label for g.node(i)
            - The correspondence between g and a potts_problem is the following:
                - the factor_value() for a node is stored in g.node(i).data.
                - the factor_value_disagreement(i,j) is stored in edge(g,i,j).
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename potts_grid_problem,
        typename mem_manager
        >
    void find_max_factor_graph_potts (
        const potts_grid_problem& prob,
        array2d<node_label,mem_manager>& labels
    );
    /*!
        requires
            - potts_grid_problem == an object with an interface compatible with the
              potts_grid_problem object defined above.
            - for all valid i and j:
                - prob.factor_value_disagreement(i,j) >= 0
                - prob.factor_value_disagreement(i,j) == prob.factor_value_disagreement(j,i)
        ensures
            - This routine solves a version of a potts problem where the graph is a
              regular grid where each node is connected to its four immediate neighbors.
              In particular, this means that this function finds the assignments
              to all the labels in prob which maximizes potts_model_score(prob,#labels).
            - The optimal labels are stored in #labels.
            - #labels.nr() == prob.nr()
            - #labels.nc() == prob.nc()
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//    The following functions and interface definitions are convenience routines for use
//    with the potts grid problem version of find_max_factor_graph_potts() defined above.
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    struct single_image_model
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object defines a slightly more convenient interface for creating
                potts_grid_problems which operate on an image.  In this case, the goal
                is to assign a binary label to each pixel in an image.  In particular,
                this object defines the interface used by the make_potts_grid_problem()
                routine defined below.

                In the following comments, we will refer to the image supplied to
                make_potts_grid_problem() as IMG.
        !*/

        // This typedef should be for a type like int or double.  It
        // must also be capable of representing signed values.
        typedef an_integer_or_real_type value_type;

        template <typename pixel_type>
        value_type factor_value (
            const pixel_type& v
        ) const;
        /*!
            requires
                - v is a pixel value from IMG.
            ensures
                - returns a value which indicates how "good" it is to assign the location
                  in IMG corresponding to v with the label of true.  The larger the value,
                  the more desirable it is to give it this label.  Similarly, a negative
                  value indicates that it is better to give the node a label of false.
                - It is valid for the returned value to be positive or negative infinity.
                  A value of positive infinity indicates that the pixel must be labeled
                  true while negative infinity means it must be labeled false.
        !*/

        template <typename pixel_type>
        value_type factor_value_disagreement (
            const pixel_type& v1,
            const pixel_type& v2
        ) const;
        /*!
            requires
                - v1 and v2 are pixel values from neighboring pixels in the IMG image.
            ensures
                - returns a number >= 0.  This is the penalty for giving neighboring pixels
                  with values v1 and v2 different labels.  Larger values indicate a larger
                  penalty.
                - this function is symmetric.  That is, it is true that:
                  factor_value_disagreement(i,j) == factor_value_disagreement(j,i)
                - It is valid for the returned value to be positive infinity.  Returning
                  infinity indicates that the idx1-th and idx2-th nodes must share the same
                  label.
        !*/
    };

// ----------------------------------------------------------------------------------------

    struct pair_image_model
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object defines a slightly more convenient interface for creating
                potts_grid_problems which operate on a pair of identically sized images.
                In this case, the goal is to assign a label to each pixel in the first
                image of the pair.  In particular, this object defines the interface
                used by the make_potts_grid_problem() routine defined below.

                In the following comments, we will refer to the two images supplied to
                make_potts_grid_problem() as IMG1 and IMG2.  The goal of the potts
                problem will be to assign labels to each pixel in IMG1 (IMG2 is
                not labeled, it is simply used as a place to keep auxiliary data).
        !*/

        // This typedef should be for a type like int or double.  It
        // must also be capable of representing signed values.
        typedef an_integer_or_real_type value_type;

        template <typename pixel_type1, typename pixel_type2>
        value_type factor_value (
            const pixel_type1& v1,
            const pixel_type2& v2
        ) const;
        /*!
            requires
                - v1 and v2 are corresponding pixels from IMG1 and IMG2 respectively.
                  That is, both pixel values have the same coordinates in the images.
                  So for example, if v1 is the value of IMG1[4][5] then v2 is the value
                  of IMG2[4][5].
            ensures
                - returns a value which indicates how "good" it is to assign the location
                  in IMG1 corresponding to v1 with the label of true.  The larger the value,
                  the more desirable it is to give it this label.  Similarly, a negative
                  value indicates that it is better to give the node a label of false.
                - It is valid for the returned value to be positive or negative infinity.
                  A value of positive infinity indicates that the pixel must be labeled
                  true while negative infinity means it must be labeled false.
        !*/

        template <typename pixel_type>
        value_type factor_value_disagreement (
            const pixel_type& v1,
            const pixel_type& v2
        ) const;
        /*!
            requires
                - v1 and v2 are pixel values from neighboring pixels in the IMG1 image.
            ensures
                - returns a number >= 0.  This is the penalty for giving neighboring pixels
                  with values v1 and v2 different labels.  Larger values indicate a larger
                  penalty.
                - this function is symmetric.  That is, it is true that:
                  factor_value_disagreement(i,j) == factor_value_disagreement(j,i)
                - It is valid for the returned value to be positive infinity.  Returning
                  infinity indicates that the idx1-th and idx2-th nodes must share the same
                  label.
        !*/
    };

// ----------------------------------------------------------------------------------------

    template <
        typename single_image_model,
        typename pixel_type,
        typename mem_manager
        >
    potts_grid_problem make_potts_grid_problem (
        const single_image_model& model,
        const array2d<pixel_type,mem_manager>& img
    );
    /*!
        requires
            - single_image_model == an object with an interface compatible with the
              single_image_model object defined above.
            - for all valid i and j:
                - model.factor_value_disagreement(i,j) >= 0
                - model.factor_value_disagreement(i,j) == model.factor_value_disagreement(j,i)
        ensures
            - returns a potts_grid_problem which can be solved using the
              find_max_factor_graph_potts(prob,array2d) routine defined above.  That is,
              given an image to store the labels, the following statement would solve the
              potts problem defined by the given model and image:
                find_max_factor_graph_potts(make_potts_grid_problem(model,img),labels);
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename pair_image_model,
        typename pixel_type1,
        typename pixel_type2,
        typename mem_manager
        >
    potts_grid_problem make_potts_grid_problem (
        const pair_image_model& model,
        const array2d<pixel_type1,mem_manager>& img1,
        const array2d<pixel_type2,mem_manager>& img2
    );
    /*!
        requires
            - get_rect(img1) == get_rect(img2)
              (i.e. img1 and img2 have the same dimensions)
            - pair_image_model == an object with an interface compatible with the
              pair_image_model object defined above.
            - for all valid i and j:
                - model.factor_value_disagreement(i,j) >= 0
                - model.factor_value_disagreement(i,j) == model.factor_value_disagreement(j,i)
        ensures
            - returns a potts_grid_problem which can be solved using the
              find_max_factor_graph_potts(prob,array2d) routine defined above.  That is,
              given an image to store the labels, the following statement would solve the
              potts problem defined by the given model and pair of images:
                find_max_factor_graph_potts(make_potts_grid_problem(model,img1,img2),labels);
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_FIND_MAX_FACTOR_GRAPH_PoTTS_ABSTRACT_Hh_


dlib C++ Library - find_max_factor_graph_viterbi_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_FIND_MAX_FACTOR_GRAPH_VITERBi_ABSTRACT_Hh_
#ifdef DLIB_FIND_MAX_FACTOR_GRAPH_VITERBi_ABSTRACT_Hh_

#include <vector>
#include "../matrix.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class map_problem
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object represents a chain-structured factor graph or graphical
                model.  In particular, this object defines the interface a MAP problem
                on a factor graph must implement if it is to be solved using the
                find_max_factor_graph_viterbi() routine defined at the bottom of this file.

                Note that there is no dlib::map_problem object.  What you are looking
                at here is simply the interface definition for a map problem.  You must
                implement your own version of this object for the problem you wish to
                solve and then pass it to the find_max_factor_graph_viterbi() routine.
        !*/

    public:

        unsigned long order (
        ) const;
        /*!
            ensures
                - returns the order of this model.  The order has the following interpretation:
                  This model can represent a high order Markov chain.  If order()==1 then map_problem
                  represents a basic chain-structured graph where nodes only depend on their immediate
                  neighbors.  However, high order Markov models can also be used by setting order() > 1.
        !*/

        unsigned long num_states (
        ) const;
        /*!
            ensures
                - returns the number of states attainable by each variable/node in the graph.
        !*/

        unsigned long number_of_nodes (
        ) const;
        /*!
            ensures
                - returns the number of nodes in the factor graph.  Or in other words,
                  returns the number of variables in the MAP problem.
        !*/

        template <
            typename EXP
            >
        double factor_value (
            unsigned long node_id,
            const matrix_exp<EXP>& node_states
        ) const;
        /*!
            requires
                - EXP::type == unsigned long
                  (i.e. node_states contains unsigned longs)
                - node_id < number_of_nodes()
                - node_states.size() == min(node_id, order()) + 1
                - is_vector(node_states) == true
                - max(node_states) < num_states()
            ensures
                - In a chain-structured graph, each node has a potential function associated with
                  it.  The potential function operates on the variable given by the node as well
                  as the order() previous variables.  Therefore, factor_value() returns the value
                  of the factor/potential function associated with node node_id where the following
                  nodes take on the values defined below:
                    - node_states(0) == the value of the node with ID node_id
                    - node_states(i) == the value of the node with ID node_id-i
                - It is ok for this function to return a value of -std::numeric_limits<double>::infinity().
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <
        typename map_problem
        >
    void find_max_factor_graph_viterbi (
        const map_problem& prob,
        std::vector<unsigned long>& map_assignment
    );
    /*!
        requires
            - prob.num_states() > 0
            - std::pow(prob.num_states(), prob.order()) < std::numeric_limits<unsigned long>::max()
              (i.e. The Viterbi algorithm is exponential in the order of the map problem.  So don't
              make order too large.)
            - map_problem == an object with an interface compatible with the map_problem
              object defined at the top of this file.
        ensures
            - This function is a tool for exactly solving the MAP problem in a chain-structured
              graphical model or factor graph.  That is, it attempts to solve a certain kind of
              optimization problem which can be defined as follows:
                - Let X denote a set of prob.number_of_nodes() integer valued variables, each taking
                  a value in the range [0, prob.num_states()).
                - Let X(i) = the ith variable in X.
                - Let F(i) = factor_value_i(X(i), X(i-1), ..., X(i-prob.order()))
                  (This is the value returned by prob.factor_value(i, node_states).  Note that
                  each factor's value function operates on at most prob.order()+1 variables.
                  Moreover, the variables are adjacent and hence the graph is "chain-structured".)

                 Then this function finds the assignments to the X variables which
                 maximizes: sum over all valid i: F(i)

            - #map_assignment == the result of the optimization.
            - #map_assignment.size() == prob.number_of_nodes()
            - for all valid i:
                - #map_assignment[i] < prob.num_states()
                - #map_assignment[i] == The MAP assignment for node/variable i.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_FIND_MAX_FACTOR_GRAPH_VITERBi_ABSTRACT_Hh_


dlib C++ Library - find_max_parse_cky_abstract.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_FIND_MAX_PARsE_CKY_ABSTRACT_Hh_
#ifdef DLIB_FIND_MAX_PARsE_CKY_ABSTRACT_Hh_

#include <vector>
#include <string>
#include "../algs.h"
#include "../serialize.h"

namespace dlib
{

// -----------------------------------------------------------------------------------------

    template <
        typename T
        >
    struct constituent
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object represents the linguistic idea of a constituent, that is, a
                group of words that functions as a single unit.  In particular, it
                represents a combination of two constituents into a new constituent.

                Additionally, a constituent object represents a range of words relative to
                some std::vector of words.  The range is from [begin, end) (i.e. including
                begin but not including end, so using the normal C++ iterator notation).
                Moreover, a constituent is always composed of two parts, each having a tag.
                Therefore, the left part is composed of the words in the range [begin,k)
                and has tag left_tag while the right part of the constituent contains the
                words in the range [k,end) and has the tag right_tag.

                The tags are user defined objects of type T.  In general, they are used to
                represent syntactic categories such as noun phrase, verb phrase, etc.
        !*/

        unsigned long begin, end, k;
        T left_tag;
        T right_tag;
    };

    template <
        typename T
        >
    void serialize(
        const constituent<T>& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

    template <
        typename T
        >
    void deserialize(
        constituent<T>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// -----------------------------------------------------------------------------------------

    /*!A END_OF_TREE is used to indicate that parse_tree_element::left or
         parse_tree_element::right doesn't point to another subtree.
    !*/
    const unsigned long END_OF_TREE = 0xFFFFFFFF;

// -----------------------------------------------------------------------------------------

    template <
        typename T
        >
    struct parse_tree_element
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is used to represent a node in a binary parse tree.  An entire
                parse tree is represented by a std::vector of parse_tree_element objects.
                We follow the convention that the first element of this vector is always
                the root of the entire tree.

                The fields of this object have the following interpretations:
                    - c == the constituent spanned by this node in the parse tree.
                      Therefore, the node spans the words in the range [c.begin, c.end).
                    - tag == the syntactic category of this node in the parse tree.
                    - score == the score or log likelihood for this parse tree.  In
                      general, this is the sum of scores of all the production rules used
                      to build the tree rooted at the current node.
                    - let PT denote the vector of parse_tree_elements that defines an
                      entire parse tree.  Then we have:
                        - if (left != END_OF_TREE) then
                            - PT[left] == the left sub-tree of the current node.
                            - PT[left] spans the words [c.begin, c.k)
                            - PT[left].tag == c.left_tag
                        - else
                            - there is no left sub-tree

                        - if (right != END_OF_TREE) then
                            - PT[right] == the right sub-tree of the current node.
                            - PT[right] spans the words [c.k, c.end)
                            - PT[right].tag == c.right_tag
                        - else
                            - there is no right sub-tree
        !*/

        constituent<T> c;
        T tag;
        double score;

        unsigned long left;
        unsigned long right;
    };

    template <
        typename T
        >
    void serialize (
        const parse_tree_element<T>& item,
        std::ostream& out
    );
    /*!
        provides serialization support
    !*/

    template <
        typename T
        >
    void deserialize (
        parse_tree_element<T>& item,
        std::istream& in
    );
    /*!
        provides deserialization support
    !*/

// -----------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------

    void example_production_rule_function (
        const std::vector<T>& words,
        const constituent<T>& c,
        std::vector<std::pair<T,double> >& possible_tags
    )
    /*!
        requires
            - 0 <= c.begin < c.k < c.end <= words.size()
            - possible_tags.size() == 0
        ensures
            - Finds all the syntactic categories that can be used to label c and puts those
              categories, along with their scores, into possible_tags.  Or in other words,
              this function determines which production rules can be used to turn the left
              and right sub-constituents in c into a single constituent.  The contents of c
              have the following interpretations:
                - The left sub-constituent has syntactic category c.left_tag
                - for all i such that c.begin <= i < c.k:
                    - words[i] is part of the left sub-constituent.
                - The right sub-constituent has syntactic category c.right_tag
                - for all i such that c.k <= i < c.end:
                    - words[i] is part of the right sub-constituent.

            - Note that example_production_rule_function() is not a real function.  It is
              here just to show you how to define production rule producing functions for
              use with the find_max_parse_cky() routine defined below.
    !*/

    template <
        typename T,
        typename production_rule_function
        >
    void find_max_parse_cky (
        const std::vector<T>& words,
        const production_rule_function& production_rules,
        std::vector<parse_tree_element<T> >& parse_tree
    );
    /*!
        requires
            - production_rule_function == a function or function object with the same
              interface as example_production_rule_function defined above.
            - It must be possible to store T objects in a std::map.
        ensures
            - Uses the CKY algorithm to find the most probable/highest scoring binary parse
              tree of the given vector of words.
            - if (#parse_tree.size() == 0) then
                - There is no parse tree, using the given production_rules, that can cover
                  the given word sequence.
            - else
                - #parse_tree == the highest scoring parse tree that covers all the
                  elements of words.
                - #parse_tree[0] == the root node of the parse tree.
                - #parse_tree[0].score == the score of the parse tree.  This is the sum of
                  the scores of all production rules used to construct the tree.
                - #parse_tree[0].begin == 0
                - #parse_tree[0].end == words.size()
            - This function uses production_rules() to find out what the allowed production
              rules are.  That is, production_rules() defines all properties of the grammar
              used by find_max_parse_cky().
    !*/

// -----------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------

    class parse_tree_to_string_error : public error
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is the exception thrown by parse_tree_to_string() and
                parse_tree_to_string_tagged() if the inputs are discovered to be invalid.
        !*/
    };

// -----------------------------------------------------------------------------------------

    template <
        typename T,
        typename U
        >
    std::string parse_tree_to_string (
        const std::vector<parse_tree_element<T> >& tree,
        const std::vector<U>& words,
        const unsigned long root_idx = 0
    );
    /*!
        requires
            - It must be possible to print U objects to an ostream using operator<<
              (typically, U would be something like std::string)
        ensures
            - Interprets tree as a parse tree defined over the given sequence of words.
            - returns a bracketed string that represents the parse tree over the words.
              For example, suppose the following parse tree is input:

                        /\
                       /  \
                      /\   \
                     /  \   \
                   the dog  ran

              Then the output would be the string "[[the dog] ran]"
            - Only the sub-tree rooted at tree[root_idx] will be output.  If root_idx >=
              tree.size() then the empty string is returned.
        throws
            - parse_tree_to_string_error
                This exception is thrown if an invalid tree is detected.  This might happen
                if the tree refers to elements of words that don't exist because words is
                shorted than it is supposed to be.
    !*/

// -----------------------------------------------------------------------------------------

    template <
        typename T,
        typename U
        >
    std::string parse_tree_to_string_tagged (
        const std::vector<parse_tree_element<T> >& tree,
        const std::vector<U>& words,
        const unsigned long root_idx = 0
    );
    /*!
        requires
            - It must be possible to print T objects to an ostream using operator<<
            - It must be possible to print U objects to an ostream using operator<<
              (typically, U would be something like std::string)
        ensures
            - This function does the same thing as parse_tree_to_string() except that it
              also includes the parse_tree_element::tag object in the output.  Therefore,
              the tag of each bracket will be included as the first token inside the
              bracket.  For example, suppose the following parse tree is input (where tags
              are shown at the vertices):

                        S
                        /\
                      NP  \
                      /\   \
                     /  \   \
                   the dog  ran

              Then the output would be the string "[S [NP the dog] ran]"
            - Only the sub-tree rooted at tree[root_idx] will be output.  If root_idx >=
              tree.size() then the empty string is returned.
        throws
            - parse_tree_to_string_error
                This exception is thrown if an invalid tree is detected.  This might happen
                if the tree refers to elements of words that don't exist because words is
                shorted than it is supposed to be.
    !*/

// -----------------------------------------------------------------------------------------

    template <
        typename T,
        typename U
        >
    std::string parse_trees_to_string (
        const std::vector<parse_tree_element<T> >& tree,
        const std::vector<U>& words,
        const T& tag_to_skip
    );
    /*!
        requires
            - It must be possible to print U objects to an ostream using operator<<
              (typically, U would be something like std::string)
        ensures
            - This function behaves just like parse_tree_to_string() except that it will
              not print the brackets (i.e. []) for the top most parts of the tree which
              have tags equal to tag_to_skip.  It will however print all the words.
              Therefore, this function only includes brackets on the subtrees which begin
              with a tag other than tag_to_skip.
        throws
            - parse_tree_to_string_error
                This exception is thrown if an invalid tree is detected.  This might happen
                if the tree refers to elements of words that don't exist because words is
                shorted than it is supposed to be.
    !*/

// -----------------------------------------------------------------------------------------

    template <
        typename T,
        typename U
        >
    std::string parse_trees_to_string_tagged (
        const std::vector<parse_tree_element<T> >& tree,
        const std::vector<U>& words,
        const T& tag_to_skip
    );
    /*!
        requires
            - It must be possible to print T objects to an ostream using operator<<
            - It must be possible to print U objects to an ostream using operator<<
              (typically, U would be something like std::string)
        ensures
            - This function behaves just like parse_tree_to_string_tagged() except that it
              will not print the brackets (i.e. []) for the top most parts of the tree
              which have tags equal to tag_to_skip.  It will however print all the words.
              Therefore, this function only includes brackets on the subtrees which begin
              with a tag other than tag_to_skip.
        throws
            - parse_tree_to_string_error
                This exception is thrown if an invalid tree is detected.  This might happen
                if the tree refers to elements of words that don't exist because words is
                shorted than it is supposed to be.
    !*/

// -----------------------------------------------------------------------------------------

    template <
        typename T
        >
    void find_trees_not_rooted_with_tag (
        const std::vector<parse_tree_element<T> >& tree,
        const T& tag,
        std::vector<unsigned long>& tree_roots
    );
    /*!
        requires
            - objects of type T must be comparable using operator==
        ensures
            - Finds all the largest non-overlapping trees in tree that are not rooted with
              the given tag.
            - find_trees_not_rooted_with_tag() is useful when you want to cut a parse tree
              into a bunch of sub-trees and you know that the top level of the tree is all
              composed of the same kind of tag.  So if you want to just "slice off" the top
              of the tree where this tag lives then this function is useful for doing that.
            - #tree_roots.size() == the number of sub-trees found.
            - for all valid i:
                - tree[#tree_roots[i]].tag != tag
            - To make the operation of this function clearer, here are a few examples of
              what it will do:
                - if (tree[0].tag != tag) then
                    - #tree_roots.size() == 0
                    - #tree_roots[0] == 0
                - else if (tree[0].tag == tag but its immediate children's tags are not equal to tag) then
                    - #tree_roots.size() == 2
                    - #tree_roots[0] == tree[0].left
                    - #tree_roots[1] == tree[0].right
    !*/

// -----------------------------------------------------------------------------------------

}

#endif // DLIB_FIND_MAX_PARsE_CKY_ABSTRACT_Hh_


dlib C++ Library - max_cost_assignment_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_MAX_COST_ASSIgNMENT_ABSTRACT_Hh_
#ifdef DLIB_MAX_COST_ASSIgNMENT_ABSTRACT_Hh_

#include "../matrix.h"
#include <vector>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <typename EXP>
    typename EXP::type assignment_cost (
        const matrix_exp<EXP>& cost,
        const std::vector<long>& assignment
    );
    /*!
        requires
            - cost.nr() == cost.nc()
            - for all valid i:
                - 0 <= assignment[i] < cost.nr()
        ensures
            - Interprets cost as a cost assignment matrix. That is, cost(i,j)
              represents the cost of assigning i to j.
            - Interprets assignment as a particular set of assignments. That is,
              i is assigned to assignment[i].
            - returns the cost of the given assignment. That is, returns
              a number which is:
                sum over i: cost(i,assignment[i])
    !*/

// ----------------------------------------------------------------------------------------

    template <typename EXP>
    std::vector<long> max_cost_assignment (
        const matrix_exp<EXP>& cost
    );
    /*!
        requires
            - EXP::type == some integer type (e.g. int)
              (i.e. cost must contain integers rather than floats or doubles)
            - cost.nr() == cost.nc()
        ensures
            - Finds and returns the solution to the following optimization problem:

                Maximize: f(A) == assignment_cost(cost, A)
                Subject to the following constraints:
                    - The elements of A are unique. That is, there aren't any
                      elements of A which are equal.
                    - A.size() == cost.nr()

            - This function implements the O(N^3) version of the Hungarian algorithm
              where N is the number of rows in the cost matrix.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MAX_COST_ASSIgNMENT_ABSTRACT_Hh_


dlib C++ Library - max_sum_submatrix_abstract.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_MAX_SUM_SUBMaTRIX_ABSTRACT_Hh_
#ifdef DLIB_MAX_SUM_SUBMaTRIX_ABSTRACT_Hh_

#include "../matrix.h"
#include <vector>
#include "../geometry.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename EXP
        >
    std::vector<rectangle> max_sum_submatrix(
        const matrix_exp<EXP>& mat,
        unsigned long max_rects,
        double thresh = 0
    );
    /*!
        requires
            - thresh >= 0
            - mat.size() != 0
        ensures
            - This function finds the submatrix within mat which has the largest sum.  It then
              zeros out that submatrix and repeats the process until no more maximal submatrices can
              be found.  The std::vector returned will be ordered so that the rectangles with the
              largest sum come first.
            - Each submatrix must have a sum greater than thresh.  If no such submatrix exists then
              the algorithm terminates and returns an empty std::vector.
            - At most max_rects rectangles are returned.

            - This function is basically an implementation of the efficient subwindow search (I-ESS)
              algorithm presented in the following paper:
                Efficient Algorithms for Subwindow Search in Object Detection and Localization
                by Senjian An, Patrick Peursum, Wanquan Liu and Svetha Venkatesh
                In CVPR 2009
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MAX_SUM_SUBMaTRIX_ABSTRACT_Hh_


dlib C++ Library - min_cut_abstract.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_MIN_CuT_ABSTRACT_Hh_
#ifdef DLIB_MIN_CuT_ABSTRACT_Hh_

#include "../graph_utils.h"

// ----------------------------------------------------------------------------------------

namespace dlib
{
    /*!A node_label
        The node_label type is the type used to label which part of a graph cut
        a node is on.  It is used by all the graph cut tools.  The three possible
        values of a node label are SOURCE_CUT, SINK_CUT, or FREE_NODE.
    !*/

    typedef unsigned char node_label;
    const node_label SOURCE_CUT = 0;
    const node_label SINK_CUT = 254;
    const node_label FREE_NODE = 255;

// ----------------------------------------------------------------------------------------

    class flow_graph
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object represents a flow capacity graph for use with the
                min_cut algorithm defined below.  In particular, this object
                is a kind of directed graph where the edge weights specify the
                flow capacities.

                Note that there is no dlib::flow_graph object.  What you are
                looking at here is simply the interface definition for a graph
                which can be used with the min_cut algorithm.  You must implement
                your own version of this object for the graph you wish to work with
                and then pass it to the min_cut::operator() routine.

                It's also worth pointing out that this graph has symmetric edge
                connections.  That is, if there is an edge from node A to node B
                then there must also be an edge from node B to node A.
        !*/

    public:

        class out_edge_iterator
        {
            /*!
                WHAT THIS OBJECT REPRESENTS
                    This is a simple forward iterator for iterating over the neighbors
                    of a node in the graph.  It also represents the fact that the neighbors
                    are on the end of an outgoing edge.  That is, the edge represents
                    the amount of flow which can flow towards the neighbor.
            !*/

        public:
            out_edge_iterator(
            );
            /*!
                ensures
                    - constructs an iterator in an undefined state.  It can't
                      be used until assigned with a valid iterator.
            !*/

            out_edge_iterator(
                const out_edge_iterator& item
            );
            /*!
                ensures
                    - #*this is a copy of item
            !*/

            out_edge_iterator& operator=(
                const out_edge_iterator& item
            );
            /*!
                ensures
                    - #*this is a copy of item
                    - returns #*this
            !*/

            bool operator!= (
                const out_edge_iterator& item
            ) const;
            /*!
                requires
                    - *this and item are iterators over the neighbors for the
                      same node.
                ensures
                    - returns false if *this and item both reference the same
                      node in the graph and true otherwise.
            !*/

            out_edge_iterator& operator++(
            );
            /*!
                ensures
                    - advances *this to the next neighbor node.
                    - returns a reference to the updated *this
                      (i.e. this is the ++object form of the increment operator)
            !*/
        };

        class in_edge_iterator
        {
            /*!
                WHAT THIS OBJECT REPRESENTS
                    This is a simple forward iterator for iterating over the neighbors
                    of a node in the graph.  It also represents the fact that the neighbors
                    are on the end of an incoming edge.  That is, the edge represents
                    the amount of flow which can flow out of the neighbor node.
            !*/

        public:

            in_edge_iterator(
            );
            /*!
                ensures
                    - constructs an iterator in an undefined state.  It can't
                      be used until assigned with a valid iterator.
            !*/

            in_edge_iterator(
                const in_edge_iterator& item
            );
            /*!
                ensures
                    - #*this is a copy of item
            !*/

            in_edge_iterator& operator=(
                const in_edge_iterator& item
            );
            /*!
                ensures
                    - #*this is a copy of item
                    - returns #*this
            !*/

            bool operator!= (
                const in_edge_iterator& item
            ) const;
            /*!
                requires
                    - *this and item are iterators over the neighbors for the
                      same node.
                ensures
                    - returns false if *this and item both reference the same
                      node in the graph and true otherwise.
            !*/

            in_edge_iterator& operator++(
            );
            /*!
                ensures
                    - advances *this to the next neighbor node.
                    - returns a reference to the updated *this
                      (i.e. this is the ++object form of the increment operator)
            !*/
        };

        unsigned long number_of_nodes (
        ) const;
        /*!
            ensures
                - returns the number of nodes in the graph.
        !*/

        out_edge_iterator out_begin(
            const unsigned long& idx
        ) const;
        /*!
            requires
                - idx < number_of_nodes()
            ensures
                - returns an iterator pointing to the first neighboring node of
                  the idx-th node.  If no such node exists then returns out_end(idx).
                - The returned iterator also represents the directed edge going from
                  node idx to the neighbor.
        !*/

        in_edge_iterator in_begin(
            const unsigned long& idx
        ) const;
        /*!
            requires
                - idx < number_of_nodes()
            ensures
                - returns an iterator pointing to the first neighboring node of
                  the idx-th node.  If no such node exists then returns in_end(idx).
                - The returned iterator also represents the directed edge going from
                  the neighbor to node idx.
        !*/

        out_edge_iterator out_end(
            const unsigned long& idx
        ) const;
        /*!
            requires
                - idx < number_of_nodes()
            ensures
                - returns an iterator to one past the last neighboring node of
                  the idx-th node.
        !*/

        in_edge_iterator in_end(
            const unsigned long& idx
        ) const;
        /*!
            requires
                - idx < number_of_nodes()
            ensures
                - returns an iterator to one past the last neighboring node of
                  the idx-th node.
        !*/

        unsigned long node_id (
            const out_edge_iterator& it
        ) const;
        /*!
            requires
                - it == a valid iterator (i.e. it must be in the range [out_begin(idx), out_end(idx))
                  for some valid idx)
            ensures
                - returns a number IDX such that:
                    - 0 <= IDX < number_of_nodes()
                    - IDX == The index which uniquely identifies the node pointed to by the
                      iterator it.  This number can be used with any member function in this
                      object which expect a node index.  (e.g. get_label(IDX) == the label for the
                      node pointed to by it)
        !*/

        unsigned long node_id (
            const in_edge_iterator& it
        ) const;
        /*!
            requires
                - it == a valid iterator (i.e. it must be in the range [in_begin(idx), in_end(idx))
                  for some valid idx)
            ensures
                - returns a number IDX such that:
                    - 0 <= IDX < number_of_nodes()
                    - IDX == The index which uniquely identifies the node pointed to by the
                      iterator it.  This number can be used with any member function in this
                      object which expect a node index.  (e.g. get_label(IDX) == the label for the
                      node pointed to by it)
        !*/

        // This typedef should be for a type like int or double.  It
        // must also be capable of representing signed values.
        typedef an_integer_or_real_type edge_type;

        edge_type get_flow (
            const unsigned long& idx1,
            const unsigned long& idx2
        ) const;
        /*!
            requires
                - idx1 < number_of_nodes()
                - idx2 < number_of_nodes()
                - idx1 and idx2 are neighbors in the graph
            ensures
                - returns the residual flow capacity from the idx1-th node to the idx2-th node.
                - It is valid for this function to return a floating point value of infinity.
                  This value means this edge has an unlimited capacity.
        !*/

        edge_type get_flow (
            const out_edge_iterator& it
        ) const;
        /*!
            requires
                - it == a valid iterator (i.e. it must be in the range [out_begin(idx), out_end(idx))
                  for some valid idx)
            ensures
                - let IDX = node_id(it)
                - it represents the directed edge from a node, call it H, to the node IDX. Therefore,
                  this function returns get_flow(H,IDX)
                - It is valid for this function to return a floating point value of infinity.
                  This value means this edge has an unlimited capacity.
        !*/

        edge_type get_flow (
            const in_edge_iterator& it
        ) const;
        /*!
            requires
                - it == a valid iterator (i.e. it must be in the range [in_begin(idx), in_end(idx))
                  for some valid idx)
            ensures
                - let IDX = node_id(it)
                - it represents the directed edge from node IDX to another node, call it H. Therefore,
                  this function returns get_flow(IDX,H)
                - It is valid for this function to return a floating point value of infinity.
                  This value means this edge has an unlimited capacity.
        !*/

        void adjust_flow (
            const unsigned long& idx1,
            const unsigned long& idx2,
            const edge_type& value
        );
        /*!
            requires
                - idx1 < number_of_nodes()
                - idx2 < number_of_nodes()
                - idx1 and idx2 are neighbors in the graph
            ensures
                - #get_flow(idx1,idx2) == get_flow(idx1,idx2) + value
                - #get_flow(idx2,idx1) == get_flow(idx2,idx1) - value
        !*/

        void set_label (
            const unsigned long& idx,
            node_label value
        );
        /*!
            requires
                - idx < number_of_nodes()
            ensures
                - #get_label(idx) == value
        !*/

        node_label get_label (
            const unsigned long& idx
        ) const;
        /*!
            requires
                - idx < number_of_nodes()
            ensures
                - returns the label for the idx-th node in the graph.
        !*/

    };

// ----------------------------------------------------------------------------------------

    template <
        typename flow_graph
        >
    typename flow_graph::edge_type graph_cut_score (
        const flow_graph& g
    );
    /*!
        requires
            - flow_graph == an object with an interface compatible with the flow_graph
              object defined at the top of this file, or, an implementation of
              dlib/directed_graph/directed_graph_kernel_abstract.h.
        ensures
            - returns the sum of the outgoing flows from nodes with a label of SOURCE_CUT
              to nodes with a label != SOURCE_CUT.  Note that for a directed_graph object,
              the labels are stored in the node's data field.
    !*/

// ----------------------------------------------------------------------------------------

    class min_cut
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is a function object which can be used to find the min cut
                on a graph.

                The implementation is based on the method described in the following
                paper:
                    An Experimental Comparison of Min-Cut/Max-Flow Algorithms for
                    Energy Minimization in Vision, by Yuri Boykov and Vladimir Kolmogorov,
                    in PAMI 2004.

        !*/

    public:

        min_cut(
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        template <
            typename flow_graph
            >
        void operator() (
            flow_graph& g,
            const unsigned long source_node,
            const unsigned long sink_node
        ) const;
        /*!
            requires
                - flow_graph == an object with an interface compatible with the flow_graph
                  object defined at the top of this file.
                - source_node != sink_node
                - source_node < g.number_of_nodes()
                - sink_node < g.number_of_nodes()
                - for all valid i and j:
                    - g.get_flow(i,j) >= 0
                      (i.e. all the flow capacities/edge weights are non-negative)
                - g does not contain any self loops.  That is, no nodes are neighbors with
                  themselves.
            ensures
                - Finds the minimum cut on the given graph.  That is, this function finds
                  a labeling of nodes in g such that graph_cut_score(g) would be minimized.  Note
                  that the flow values in #g are modified by this algorithm so if you want
                  to obtain the min cut score you must call min_cut::operator(), then copy
                  the flow values back into #g, and then call graph_cut_score(#g).  But in most
                  cases you don't care about the value of the min cut score, rather, you
                  just want the labels in #g.
                - #g.get_label(source_node) == SOURCE_CUT
                - #g.get_label(sink_node) == SINK_CUT
                - for all valid i:
                    - #g.get_label(i) == SOURCE_CUT, SINK_CUT, or FREE_NODE
                    - if (#g.get_label(i) == SOURCE_CUT) then
                        - The minimum cut of g places node i into the source side of the cut.
                    - if (#g.get_label(i) == SINK_CUT) then
                        - The minimum cut of g places node i into the sink side of the cut.
                    - if (#g.get_label(i) == FREE_NODE) then
                        - Node i can be labeled SOURCE_CUT or SINK_CUT.  Both labelings
                          result in the same cut score.
                - When interpreting g as a graph of flow capacities from the source_node
                  to the sink_node we can say that the min cut problem is equivalent to
                  the max flow problem.  This equivalent problem is to find out how to push
                  as much "flow" from the source node to the sink node as possible.
                  Upon termination, #g will contain the final flow residuals in addition to
                  the graph cut labels.  That is, for all valid i and j:
                    - #g.get_flow(i,j) == the residual flow capacity left after the max
                      possible amount of flow is passing from the source node to the sink
                      node.  For example, this means that #g.get_flow(i,j) == 0 whenever
                      node i is in the SOURCE_CUT and j is in the SINK_CUT.
                    - #g.get_flow(i,j) >= 0
        !*/

        template <
            typename directed_graph
            >
        void operator() (
            directed_graph& g,
            const unsigned long source_node,
            const unsigned long sink_node
        ) const;
        /*!
            requires
                - directed_graph == an implementation of dlib/directed_graph/directed_graph_kernel_abstract.h
                - directed_graph::type == node_label
                - directed_graph::edge_type == and integer or double type
                - source_node != sink_node
                - source_node < g.number_of_nodes()
                - sink_node < g.number_of_nodes()
                - for all valid i and j:
                    - edge(g,i,j) >= 0
                      (i.e. all the flow capacities/edge weights are positive)
                - graph_contains_length_one_cycle(g) == false
                - graph_has_symmetric_edges(g) == true
            ensures
                - This routine simply converts g into a flow graph and calls the version
                  of operator() defined above.  Note that the conversion is done in O(1)
                  time, it's just an interface adaptor.
                - edge weights in g correspond to network flows while the .data field of
                  each node in g corresponds to the graph node labels.
                - upon termination, the flows and labels in g will have been modified
                  as described in the above operator() routine.
        !*/
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MIN_CuT_ABSTRACT_Hh_


dlib C++ Library - mpc_abstract.h

// Copyright (C) 2015  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_MPC_ABSTRACT_Hh_
#ifdef DLIB_MPC_ABSTRACT_Hh_

#include "../matrix.h"

namespace dlib
{
    template <
        long S_,
        long I_,
        unsigned long horizon_
        >
    class mpc
    {
        /*!
            REQUIREMENTS ON horizon_
                horizon_ > 0

            REQUIREMENTS ON S_
                S_ >= 0

            REQUIREMENTS ON I_
                I_ >= 0

            WHAT THIS OBJECT REPRESENTS
                This object implements a linear model predictive controller.  To explain
                what that means, suppose you have some process you want to control and the
                process dynamics are described by the linear equation:
                    x_{i+1} = A*x_i + B*u_i + C
                That is, the next state the system goes into is a linear function of its
                current state (x_i) and the current control (u_i) plus some constant bias
                or disturbance.

                A model predictive controller can find the control (u) you should apply to
                drive the state (x) to some reference value, or alternatively to make the
                state track some reference time-varying sequence.  It does this by
                simulating the process for horizon_ time steps and selecting the control
                that leads to the best performance over the next horizon_ steps.

                To be precise, each time you ask this object for a control, it solves the
                following quadratic program:

                    min    sum_i trans(x_i-target_i)*Q*(x_i-target_i) + trans(u_i)*R*u_i
                  x_i,u_i

                    such that: x_0     == current_state
                               x_{i+1} == A*x_i + B*u_i + C
                               lower <= u_i <= upper
                               0 <= i < horizon_

                and reports u_0 as the control you should take given that you are currently
                in current_state.  Q and R are user supplied matrices that define how we
                penalize variations away from the target state as well as how much we want
                to avoid generating large control signals.

                Finally, the algorithm we use to solve this quadratic program is based
                largely on the method described in:
                  A Fast Gradient method for embedded linear predictive control (2011)
                  by Markus Kogel and Rolf Findeisen
        !*/

    public:

        const static long S = S_;
        const static long I = I_;
        const static unsigned long horizon = horizon_;

        mpc(
        );
        /*!
            ensures
                - #get_max_iterations() == 0
                - The A,B,C,Q,R,lower, and upper parameter matrices are filled with zeros.
                  Therefore, to use this object you must initialize it via the constructor
                  that supplies these parameters.
        !*/

        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
        );
        /*!
            requires
                - A.nr() > 0
                - B.nc() > 0
                - A.nr() == A.nc() == B.nr() == C.nr() == Q.nr()
                - B.nc() == R.nr() == lower.nr() == upper.nr()
                - min(Q) >= 0
                - min(R) > 0
                - min(upper-lower) >= 0
            ensures
                - #get_A() == A
                - #get_B() == B
                - #get_C() == C
                - #get_Q() == Q
                - #get_R() == R
                - #get_lower_constraints() == lower
                - #get_upper_constraints() == upper
                - for all valid i:
                    - get_target(i) == a vector of all zeros
                    - get_target(i).size() == A.nr()
                - #get_max_iterations() == 10000
                - #get_epsilon() == 0.01
        !*/

        const matrix<double,S,S>& get_A (
        ) const;
        /*!
            ensures
                - returns the A matrix from the quadratic program defined above.
        !*/

        const matrix<double,S,I>& get_B (
        ) const;
        /*!
            ensures
                - returns the B matrix from the quadratic program defined above.
        !*/

        const matrix<double,S,1>& get_C (
        ) const;
        /*!
            ensures
                - returns the C matrix from the quadratic program defined above.
        !*/

        const matrix<double,S,1>& get_Q (
        ) const;
        /*!
            ensures
                - returns the diagonal of the Q matrix from the quadratic program defined
                  above.
        !*/

        const matrix<double,I,1>& get_R (
        ) const;
        /*!
            ensures
                - returns the diagonal of the R matrix from the quadratic program defined
                  above.
        !*/

        const matrix<double,I,1>& get_lower_constraints (
        ) const;
        /*!
            ensures
                - returns the lower matrix from the quadratic program defined above.  All
                  controls generated by this object will have values no less than this
                  lower bound.  That is, any control u will satisfy min(u-lower) >= 0.
        !*/

        const matrix<double,I,1>& get_upper_constraints (
        ) const;
        /*!
            ensures
                - returns the upper matrix from the quadratic program defined above.  All
                  controls generated by this object will have values no larger than this
                  upper bound.  That is, any control u will satisfy min(upper-u) >= 0.
        !*/

        const matrix<double,S,1>& get_target (
            const unsigned long time
        ) const;
        /*!
            requires
                - time < horizon
            ensures
                - This object will try to find the control sequence that results in the
                  process obtaining get_target(time) state at the indicated time.  Note
                  that the next time instant after "right now" is time 0.
        !*/

        void set_target (
            const matrix<double,S,1>& val,
            const unsigned long time
        );
        /*!
            requires
                - time < horizon
            ensures
                - #get_target(time) == val
        !*/

        void set_target (
            const matrix<double,S,1>& val
        );
        /*!
            ensures
                - for all valid t:
                    - #get_target(t) == val
        !*/

        void set_last_target (
            const matrix<double,S,1>& val
        );
        /*!
            ensures
                - performs: set_target(val, horizon-1)
        !*/

        unsigned long get_max_iterations (
        ) const;
        /*!
            ensures
                - When operator() is called it solves an optimization problem to
                  get_epsilon() precision to determine the next control action.  In
                  particular, we run the optimizer until the magnitude of each element of
                  the gradient vector is less than get_epsilon() or until
                  get_max_iterations() solver iterations have been executed.
        !*/

        void set_max_iterations (
            unsigned long max_iter
        );
        /*!
            ensures
                - #get_max_iterations() == max_iter
        !*/

        void set_epsilon (
            double eps
        );
        /*!
            requires
                - eps > 0
            ensures
                - #get_epsilon() == eps
        !*/

        double get_epsilon (
        ) const;
        /*!
            ensures
                - When operator() is called it solves an optimization problem to
                  get_epsilon() precision to determine the next control action.  In
                  particular, we run the optimizer until the magnitude of each element of
                  the gradient vector is less than get_epsilon() or until
                  get_max_iterations() solver iterations have been executed.  This means
                  that smaller epsilon values will give more accurate outputs but may take
                  longer to compute.
        !*/

        matrix<double,I,1> operator() (
            const matrix<double,S,1>& current_state
        );
        /*!
            requires
                - min(R) > 0
                - A.nr() == current_state.size()
            ensures
                - Solves the model predictive control problem defined by the arguments to
                  this objects constructor, assuming that the starting state is given by
                  current_state.  Then we return the control that should be taken in the
                  current state that best optimizes the quadratic objective function
                  defined above.
                - We also shift over the target states so that you only need to update the
                  last one (if you are using non-zero target states) via a call to
                  set_last_target()).  In particular, for all valid t, it will be the case
                  that:
                    - #get_target(t) == get_target(t+1)
                    - #get_target(horizon-1) == get_target(horizon-1)
        !*/

    };

}

#endif // DLIB_MPC_ABSTRACT_Hh_


dlib C++ Library - optimization_oca_abstract.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_OPTIMIZATION_OCA_ABsTRACT_Hh_
#ifdef DLIB_OPTIMIZATION_OCA_ABsTRACT_Hh_

// ----------------------------------------------------------------------------------------

namespace dlib
{
    template <typename matrix_type>
    class oca_problem
    {
        /*!
            REQUIREMENTS ON matrix_type
                - matrix_type == a dlib::matrix capable of storing column vectors

            WHAT THIS OBJECT REPRESENTS
                This object is the interface used to define the optimization
                problems solved by the oca optimizer defined later in this file.

                OCA solves optimization problems with the following form:
                    Minimize: f(w) == 0.5*length_squared(w) + C*R(w)

                    Where R(w) is a user-supplied convex function and C > 0.  Optionally,
                    there can also be non-negativity constraints on some or all of the
                    elements of w.

                Or it can alternatively solve:
                    Minimize: f(w) == 0.5*length_squared(w-prior) + C*R(w)

                    Where prior is a user supplied vector and R(w) has the same
                    interpretation as above.

                Note that the stopping condition must be provided by the user
                in the form of the optimization_status() function.
        !*/

    public:

        typedef typename matrix_type::type scalar_type;

        virtual ~oca_problem() {}

        virtual bool risk_has_lower_bound (
            scalar_type& lower_bound
        ) const { return false; }
        /*!
            ensures
                - if (R(w) >= a constant for all values of w) then
                    - returns true
                    - #lower_bound == the constant that lower bounds R(w)
                - else
                    - returns false
        !*/

        virtual bool optimization_status (
            scalar_type current_objective_value,
            scalar_type current_error_gap,
            scalar_type current_risk_value,
            scalar_type current_risk_gap,
            unsigned long num_cutting_planes,
            unsigned long num_iterations
        ) const = 0;
        /*!
            requires
                - This function is called by the OCA optimizer each iteration.
                - current_objective_value == the current value of the objective function f(w)
                - current_error_gap == The bound on how much lower the objective function
                  can drop before we reach the optimal point.  At the optimal solution the
                  error gap is equal to 0.
                - current_risk_value == the current value of the R(w) term of the objective function.
                - current_risk_gap == the bound on how much lower the risk term can go.  At the optimal
                  solution the risk gap is zero.
                - num_cutting_planes == the number of cutting planes the algorithm is currently using.
                - num_iterations == A count of the total number of iterations that have executed
                  since we started running the optimization.
            ensures
                - If it is appropriate to terminate the optimization then this function returns true
                  and false otherwise.
        !*/

        virtual scalar_type get_c (
        ) const = 0;
        /*!
            ensures
                - returns the C parameter
        !*/

        virtual long get_num_dimensions (
        ) const = 0;
        /*!
            ensures
                - returns the number of free variables in this optimization problem
        !*/

        virtual void get_risk (
            matrix_type& current_solution,
            scalar_type& risk_value,
            matrix_type& risk_subgradient
        ) const = 0;
        /*!
            requires
                - is_col_vector(current_solution) == true
                - current_solution.size() == get_num_dimensions()
            ensures
                - #current_solution will be set to one of the following:
                    - current_solution (i.e. it won't be modified at all)
                    - The result of a line search passing through current_solution.
                - #risk_value == R(#current_solution)
                - #risk_subgradient == an element of the subgradient of R() at the
                  point #current_solution
                - Note that #risk_value and #risk_subgradient are NOT multiplied by get_c()
        !*/

    };

// ----------------------------------------------------------------------------------------

    class oca
    {
        /*!
            INITIAL VALUE
                - get_subproblem_epsilon() == 1e-2
                - get_subproblem_max_iterations() == 50000
                - get_inactive_plane_threshold() == 20

            WHAT THIS OBJECT REPRESENTS
                This object is a tool for solving the optimization problem defined above
                by the oca_problem abstract class.

                For reference, OCA solves optimization problems with the following form:
                    Minimize: f(w) == 0.5*length_squared(w) + C*R(w)

                    Where R(w) is a user-supplied convex function and C > 0.  Optionally,
                    this object can also add non-negativity constraints to some or all
                    of the elements of w.

                Or it can alternatively solve:
                    Minimize: f(w) == 0.5*length_squared(w-prior) + C*R(w)

                    Where prior is a user supplied vector and R(w) has the same
                    interpretation as above.

                For a detailed discussion you should consult the following papers
                from the Journal of Machine Learning Research:
                    Optimized Cutting Plane Algorithm for Large-Scale Risk Minimization
                        Vojtech Franc, Soren Sonnenburg; 10(Oct):2157--2192, 2009.

                    Bundle Methods for Regularized Risk Minimization
                        Choon Hui Teo, S.V.N. Vishwanthan, Alex J. Smola, Quoc V. Le; 11(Jan):311-365, 2010.
        !*/
    public:

        oca (
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        template <
            typename matrix_type
            >
        typename matrix_type::type operator() (
            const oca_problem<matrix_type>& problem,
            matrix_type& w,
            unsigned long num_nonnegative = 0,
            unsigned long force_weight_to_1 = std::numeric_limits<unsigned long>::max()
        ) const;
        /*!
            requires
                - problem.get_c() > 0
                - problem.get_num_dimensions() > 0
            ensures
                - solves the given oca problem and stores the solution in #w.  In particular,
                  this function solves:
                    Minimize: f(w) == 0.5*length_squared(w) + C*R(w)
                - The optimization algorithm runs until problem.optimization_status()
                  indicates it is time to stop.
                - returns the objective value at the solution #w
                - if (num_nonnegative != 0) then
                    - Adds the constraint that #w(i) >= 0 for all i < num_nonnegative.
                      That is, the first num_nonnegative elements of #w will always be
                      non-negative.  This includes the copies of w passed to get_risk()
                      in the form of the current_solution vector as well as the final
                      output of this function.
                - if (force_weight_to_1 < problem.get_num_dimensions()) then
                    - The optimizer enforces the following constraints:
                        - #w(force_weight_to_1) == 1
                        - for all i > force_weight_to_1:
                            - #w(i) == 0
                        - That is, the element in the weight vector at the index indicated
                          by force_weight_to_1 will have a value of 1 upon completion of
                          this function, while all subsequent elements of w will have
                          values of 0.
        !*/

        template <
            typename matrix_type
            >
        typename matrix_type::type operator() (
            const oca_problem<matrix_type>& problem,
            matrix_type& w,
            const matrix_type& prior
        ) const;
        /*!
            requires
                - problem.get_c() > 0
                - problem.get_num_dimensions() > 0
                - is_col_vector(prior) == true
                - prior.size() == problem.get_num_dimensions()
            ensures
                - solves the given oca problem and stores the solution in #w.
                - In this mode, we solve a version of the problem with a different
                  regularizer.  In particular, this function solves:
                    Minimize: f(w) == 0.5*length_squared(w-prior) + C*R(w)
                - The optimization algorithm runs until problem.optimization_status()
                  indicates it is time to stop.
                - returns the objective value at the solution #w
        !*/

        void set_subproblem_epsilon (
            double eps
        );
        /*!
            requires
                - eps > 0
            ensures
                - #get_subproblem_epsilon() == eps
        !*/

        double get_subproblem_epsilon (
        ) const;
        /*!
            ensures
                - returns the accuracy used in solving the quadratic programming
                  subproblem that is part of the overall OCA algorithm.
        !*/

        void set_subproblem_max_iterations (
            unsigned long sub_max_iter
        );
        /*!
            requires
                - sub_max_iter > 0
            ensures
                - #get_subproblem_max_iterations() == sub_max_iter
        !*/

        unsigned long get_subproblem_max_iterations (
        ) const;
        /*!
            ensures
                - returns the maximum number of iterations this object will perform
                  while attempting to solve each quadratic programming subproblem.
        !*/

        void set_inactive_plane_threshold (
            unsigned long inactive_thresh
        );
        /*!
            requires
                - inactive_thresh > 0
            ensures
                - #get_inactive_plane_threshold() == inactive_thresh
        !*/

        unsigned long get_inactive_plane_threshold (
        ) const;
        /*!
            ensures
                - As OCA runs it builds up a set of cutting planes.  Typically
                  cutting planes become inactive after a certain point and can then
                  be removed.  This function returns the number of iterations of
                  inactivity required before a cutting plane is removed.
        !*/

    };
}

// ----------------------------------------------------------------------------------------

#endif // DLIB_OPTIMIZATION_OCA_ABsTRACT_Hh_


dlib C++ Library - optimization_least_squares_abstract.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_OPTIMIZATIOn_LEAST_SQUARES_ABSTRACT_
#ifdef DLIB_OPTIMIZATIOn_LEAST_SQUARES_ABSTRACT_

#include "../matrix/matrix_abstract.h"
#include "optimization_trust_region_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename stop_strategy_type,
        typename funct_type,
        typename funct_der_type,
        typename vector_type,
        typename T
        >
    double solve_least_squares (
        stop_strategy_type stop_strategy,
        const funct_type& f,
        const funct_der_type& der,
        const vector_type& list,
        T& x,
        double radius = 1
    );
    /*!
        requires
            - stop_strategy == an object that defines a stop strategy such as one of
              the objects from dlib/optimization/optimization_stop_strategies_abstract.h
            - list == a matrix or something convertible to a matrix via mat()
              such as a std::vector.
            - is_vector(list) == true
            - list.size() > 0
            - is_col_vector(x) == true
            - radius > 0
            - for all valid i:
                - f(list(i),x) must be a valid expression that evaluates to a floating point value.
                - der(list(i),x) must be a valid expression that evaluates to the derivative of f(list(i),x)
                  with respect to x. This derivative must take the form of a column vector.
        ensures
            - This function performs an unconstrained minimization of the least squares
              function g(x) defined by:
                - g(x) = sum over all i: 0.5*pow( f(list(i),x), 2 )
            - This method combines the Levenberg-Marquardt method with a quasi-newton method
              for approximating the second order terms of the hessian and is appropriate for
              large residual problems (i.e. problems where the f() function isn't driven to 0).
              In particular, it uses the method of Dennis, Gay, and Welsch as described in
              Numerical Optimization by Nocedal and Wright (second edition).
            - Since this is a trust region algorithm, the radius parameter defines the initial
              size of the trust region.
            - The function is optimized until stop_strategy decides that an acceptable
              point has been found or the trust region subproblem fails to make progress.
            - #x == the value of x that was found to minimize g()
            - returns g(#x).
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename stop_strategy_type,
        typename funct_type,
        typename funct_der_type,
        typename vector_type,
        typename T
        >
    double solve_least_squares_lm (
        stop_strategy_type stop_strategy,
        const funct_type& f,
        const funct_der_type& der,
        const vector_type& list,
        T& x,
        double radius = 1
    );
    /*!
        requires
            - stop_strategy == an object that defines a stop strategy such as one of
              the objects from dlib/optimization/optimization_stop_strategies_abstract.h
            - list == a matrix or something convertible to a matrix via mat()
              such as a std::vector.
            - is_vector(list) == true
            - list.size() > 0
            - is_col_vector(x) == true
            - radius > 0
            - for all valid i:
                - f(list(i),x) must be a valid expression that evaluates to a floating point value.
                - der(list(i),x) must be a valid expression that evaluates to the derivative of f(list(i),x)
                  with respect to x.  This derivative must take the form of a column vector.
        ensures
            - This function performs an unconstrained minimization of the least squares
              function g(x) defined by:
                - g(x) = sum over all i: 0.5*pow( f(list(i),x), 2 )
            - This method implements a plain Levenberg-Marquardt approach for approximating
              the hessian of g().  Therefore, it is most appropriate for small residual problems
              (i.e. problems where f() goes to 0 at the solution).
            - Since this is a trust region algorithm, the radius parameter defines the initial
              size of the trust region.
            - The function is optimized until stop_strategy decides that an acceptable
              point has been found or the trust region subproblem fails to make progress.
            - #x == the value of x that was found to minimize g()
            - returns g(#x).
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_OPTIMIZATIOn_LEAST_SQUARES_ABSTRACT_


dlib C++ Library - optimization_solve_qp2_using_smo_abstract.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_OPTIMIZATION_SOLVE_QP2_USING_SMO_ABSTRACT_H_
#ifdef DLIB_OPTIMIZATION_SOLVE_QP2_USING_SMO_ABSTRACT_H_

#include "../matrix/matrix_abstract.h"
#include "../algs.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class invalid_nu_error : public dlib::error
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is an exception class used to indicate that a
                value of nu given to the solve_qp2_using_smo object is incompatible
                with the constraints of the quadratic program.

                this->nu will be set to the invalid value of nu used.
        !*/

    public:
        invalid_nu_error(const std::string& msg, double nu_) : dlib::error(msg), nu(nu_) {};
        const double nu;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    typename T::type maximum_nu (
        const T& y
    );
    /*!
        requires
            - T == a matrix object or an object convertible to a matrix via mat()
            - is_col_vector(y) == true
            - y.size() > 1
            - sum((y == +1) + (y == -1)) == y.size()
              (i.e. all elements of y must be equal to +1 or -1)
        ensures
            - returns the maximum valid nu that can be used with solve_qp2_using_smo and
              the given y vector.
              (i.e. 2.0*min(sum(y == +1), sum(y == -1))/y.size())
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_type
        >
    class solve_qp2_using_smo
    {
        /*!
            REQUIREMENTS ON matrix_type
                Must be some type of dlib::matrix.

            WHAT THIS OBJECT REPRESENTS
                This object is a tool for solving the following quadratic programming
                problem using the sequential minimal optimization algorithm:

                  Minimize: f(alpha) == 0.5*trans(alpha)*Q*alpha
                  subject to the following constraints:
                    - sum(alpha) == nu*y.size()
                    - 0 <= min(alpha) && max(alpha) <= 1
                    - trans(y)*alpha == 0

                  Where all elements of y must be equal to +1 or -1 and f is convex.
                  This means that Q should be symmetric and positive-semidefinite.

                This object implements the strategy used by the LIBSVM tool.  The following papers
                can be consulted for additional details:
                    - Chang and Lin, Training {nu}-Support Vector Classifiers: Theory and Algorithms
                    - Chih-Chung Chang and Chih-Jen Lin, LIBSVM : a library for support vector
                      machines, 2001. Software available at http://www.csie.ntu.edu.tw/~cjlin/libsvm
        !*/

    public:

        typedef typename matrix_type::mem_manager_type mem_manager_type;
        typedef typename matrix_type::type scalar_type;
        typedef typename matrix_type::layout_type layout_type;
        typedef matrix<scalar_type,0,0,mem_manager_type,layout_type> general_matrix;
        typedef matrix<scalar_type,0,1,mem_manager_type,layout_type> column_matrix;

        template <
            typename EXP1,
            typename EXP2,
            long NR
            >
        unsigned long operator() (
            const matrix_exp<EXP1>& Q,
            const matrix_exp<EXP2>& y,
            const scalar_type nu,
            matrix<scalar_type,NR,1,mem_manager_type, layout_type>& alpha,
            scalar_type eps
        );
        /*!
            requires
                - Q.nr() == Q.nc()
                - is_col_vector(y) == true
                - y.size() == Q.nr()
                - y.size() > 1
                - sum((y == +1) + (y == -1)) == y.size()
                  (i.e. all elements of y must be equal to +1 or -1)
                - alpha must be capable of representing a vector of size y.size() elements
                - 0 < nu <= 1
                - eps > 0
            ensures
                - This function solves the quadratic program defined in this class's main comment.
                - The solution to the quadratic program will be stored in #alpha.
                - #alpha.size() == y.size()
                - This function uses an implementation of the sequential minimal optimization
                  algorithm.  It runs until the KKT violation is less than eps.  So eps controls
                  how accurate the solution is and smaller values result in better solutions.
                  (a reasonable eps is usually about 1e-3)
                - #get_gradient() == Q*(#alpha)
                  (i.e. stores the gradient of f() at #alpha in get_gradient())
                - returns the number of iterations performed.
            throws
                - invalid_nu_error
                  This exception is thrown if nu >= maximum_nu(y).
                  (some values of nu cause the constraints to become impossible to satisfy.
                  If this is detected then an exception is thrown).
        !*/

        const column_matrix& get_gradient (
        ) const;
        /*!
            ensures
                - returns the gradient vector at the solution of the last problem solved
                  by this object.  If no problem has been solved then returns an empty
                  vector.
        !*/

    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_OPTIMIZATION_SOLVE_QP2_USING_SMO_ABSTRACT_H_


dlib C++ Library - optimization_solve_qp3_using_smo_abstract.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_OPTIMIZATION_SOLVE_QP3_USING_SMO_ABSTRACT_H_
#ifdef DLIB_OPTIMIZATION_SOLVE_QP3_USING_SMO_ABSTRACT_H_

#include "../matrix/matrix_abstract.h"
#include "../algs.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class invalid_qp3_error : public dlib::error
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is an exception class used to indicate that the values
                of B, Cp, and Cn given to the solve_qp3_using_smo object are incompatible
                with the constraints of the quadratic program.

                this->B, this->Cp, and this->Cn will be set to the invalid values used.
        !*/

    public:
        invalid_qp3_error( const std::string& msg, double B_, double Cp_, double Cn_) :
            dlib::error(msg), B(B_), Cp(Cp_), Cn(Cn_) {};

        const double B;
        const double Cp;
        const double Cn;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_type
        >
    class solve_qp3_using_smo
    {
        /*!
            REQUIREMENTS ON matrix_type
                Must be some type of dlib::matrix.

            WHAT THIS OBJECT REPRESENTS
                This object is a tool for solving the following quadratic programming
                problem using the sequential minimal optimization algorithm:

                  Minimize: f(alpha) == 0.5*trans(alpha)*Q*alpha + trans(p)*alpha
                  subject to the following constraints:
                    - for all i such that y(i) == +1:  0 <= alpha(i) <= Cp
                    - for all i such that y(i) == -1:  0 <= alpha(i) <= Cn
                    - trans(y)*alpha == B

                  Where all elements of y must be equal to +1 or -1 and f is convex.
                  This means that Q should be symmetric and positive-semidefinite.

                This object implements the strategy used by the LIBSVM tool.  The following papers
                can be consulted for additional details:
                    - Chih-Chung Chang and Chih-Jen Lin, LIBSVM : a library for support vector
                      machines, 2001. Software available at http://www.csie.ntu.edu.tw/~cjlin/libsvm
                    - Working Set Selection Using Second Order Information for Training Support Vector Machines by
                      Fan, Chen, and Lin.  In the Journal of Machine Learning Research 2005.
        !*/

    public:

        typedef typename matrix_type::mem_manager_type mem_manager_type;
        typedef typename matrix_type::type scalar_type;
        typedef typename matrix_type::layout_type layout_type;
        typedef matrix<scalar_type,0,0,mem_manager_type,layout_type> general_matrix;
        typedef matrix<scalar_type,0,1,mem_manager_type,layout_type> column_matrix;

        template <
            typename EXP1,
            typename EXP2,
            typename EXP3,
            long NR
            >
        unsigned long operator() (
            const matrix_exp<EXP1>& Q,
            const matrix_exp<EXP2>& p,
            const matrix_exp<EXP3>& y,
            const scalar_type B,
            const scalar_type Cp,
            const scalar_type Cn,
            matrix<scalar_type,NR,1,mem_manager_type, layout_type>& alpha,
            scalar_type eps
        );
        /*!
            requires
                - Q.nr() == Q.nc()
                - is_col_vector(y) == true
                - is_col_vector(p) == true
                - p.size() == y.size() == Q.nr()
                - y.size() > 0
                - sum((y == +1) + (y == -1)) == y.size()
                  (i.e. all elements of y must be equal to +1 or -1)
                - alpha must be capable of representing a vector of size y.size() elements
                - Cp > 0
                - Cn > 0
                - eps > 0
            ensures
                - This function solves the quadratic program defined in this class's main comment.
                - The solution to the quadratic program will be stored in #alpha.
                - #alpha.size() == y.size()
                - This function uses an implementation of the sequential minimal optimization
                  algorithm.  It runs until the KKT violation is less than eps.  So eps controls
                  how accurate the solution is and smaller values result in better solutions.
                  (a reasonable eps is usually about 1e-3)
                - #get_gradient() == Q*(#alpha)
                  (i.e. stores the gradient of f() at #alpha in get_gradient())
                - returns the number of iterations performed.
            throws
                - invalid_qp3_error
                  This exception is thrown if the given parameters cause the constraints
                  of the quadratic programming problem to be impossible to satisfy.
        !*/

        const column_matrix& get_gradient (
        ) const;
        /*!
            ensures
                - returns the gradient vector at the solution of the last problem solved
                  by this object.  If no problem has been solved then returns an empty
                  vector.
        !*/

    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_OPTIMIZATION_SOLVE_QP3_USING_SMO_ABSTRACT_H_


dlib C++ Library - optimization_solve_qp_using_smo_abstract.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_OPTIMIZATION_SOLVE_QP_UsING_SMO_ABSTRACT_Hh_
#ifdef DLIB_OPTIMIZATION_SOLVE_QP_UsING_SMO_ABSTRACT_Hh_

#include "../matrix.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename EXP1,
        typename EXP2,
        typename T, long NR, long NC, typename MM, typename L
        >
    unsigned long solve_qp_using_smo (
        const matrix_exp<EXP1>& Q,
        const matrix_exp<EXP2>& b,
        matrix<T,NR,NC,MM,L>& alpha,
        T eps,
        unsigned long max_iter
    );
    /*!
        requires
            - Q.nr() == Q.nc()
            - is_col_vector(b) == true
            - is_col_vector(alpha) == true
            - b.size() == alpha.size() == Q.nr()
            - alpha.size() > 0
            - min(alpha) >= 0
            - eps > 0
            - max_iter > 0
        ensures
            - Let C == sum(alpha) (i.e. C is the sum of the alpha values you
              supply to this function)
            - This function solves the following quadratic program:
                Minimize: f(alpha) == 0.5*trans(alpha)*Q*alpha - trans(alpha)*b
                subject to the following constraints:
                    - sum(alpha) == C (i.e. the sum of alpha values doesn't change)
                    - min(alpha) >= 0 (i.e. all alpha values are nonnegative)
                Where f is convex.  This means that Q should be positive-semidefinite.
            - The solution to the above QP will be stored in #alpha.
            - This function uses a simple implementation of the sequential minimal
              optimization algorithm.  It starts the algorithm with the given alpha
              and it works on the problem until the duality gap (i.e. how far away
              we are from the optimum solution) is less than eps.  So eps controls
              how accurate the solution is and smaller values result in better solutions.
            - At most max_iter iterations of optimization will be performed.
            - returns the number of iterations performed.  If this method fails to
              converge to eps accuracy then the number returned will be max_iter+1.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename EXP1,
        typename EXP2,
        typename EXP3,
        typename T, long NR, long NC, typename MM, typename L
        >
    unsigned long solve_qp4_using_smo (
        const matrix_exp<EXP1>& A,
        const matrix_exp<EXP2>& Q,
        const matrix_exp<EXP3>& b,
        matrix<T,NR,NC,MM,L>& alpha,
        T eps,
        unsigned long max_iter
    );
    /*!
        requires
            - A.nc() == alpha.size()
            - Q.nr() == Q.nc()
            - is_col_vector(b) == true
            - is_col_vector(alpha) == true
            - b.size() == alpha.size() == Q.nr()
            - alpha.size() > 0
            - min(alpha) >= 0
            - eps > 0
            - max_iter > 0
        ensures
            - Let C == sum(alpha) (i.e. C is the sum of the alpha values you
              supply to this function)
            - This function solves the following quadratic program:
                Minimize: f(alpha,lambda) == 0.5*trans(alpha)*Q*alpha - trans(alpha)*b +
                                             0.5*trans(lambda)*lambda - trans(lambda)*A*alpha
                subject to the following constraints:
                    - sum(alpha)  == C (i.e. the sum of alpha values doesn't change)
                    - min(alpha)  >= 0 (i.e. all alpha values are nonnegative)
                    - min(lambda) >= 0 (i.e. all lambda values are nonnegative)
                Where f is convex.  This means that Q should be positive-semidefinite.
            - The solution to the above QP will be stored in #alpha.  The optimal
              lambda is not output since its value is given by the following expression:
                lowerbound(A*alpha,0)
            - This function uses a simple implementation of the sequential minimal
              optimization algorithm.  It starts the algorithm with the given alpha
              and it works on the problem until the duality gap (i.e. how far away
              we are from the optimum solution) is less than eps.  So eps controls
              how accurate the solution is and smaller values result in better solutions.
            - At most max_iter iterations of optimization will be performed.
            - returns the number of iterations performed.  If this method fails to
              converge to eps accuracy then the number returned will be max_iter+1.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_OPTIMIZATION_SOLVE_QP_UsING_SMO_ABSTRACT_Hh_


dlib C++ Library - optimization_search_strategies_abstract.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_OPTIMIZATIOn_SEARCH_STRATEGIES_ABSTRACT_
#ifdef DLIB_OPTIMIZATIOn_SEARCH_STRATEGIES_ABSTRACT_

#include <cmath>
#include <limits>
#include "../matrix/matrix_abstract.h"
#include "../algs.h"

namespace dlib
{
    /*
        A good discussion of the search strategies in this file can be found in the
        following book:  Numerical Optimization by Nocedal and Wright.
    */

// ----------------------------------------------------------------------------------------

    class cg_search_strategy
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object represents a strategy for determining which direction
                a line search should be carried out along.  This particular object
                is an implementation of the Polak-Ribiere conjugate gradient method
                for determining this direction.

                This method uses an amount of memory that is linear in the number
                of variables to be optimized.  So it is capable of handling problems
                with a very large number of variables.  However, it is generally
                not as good as the L-BFGS algorithm (which is defined below in
                the lbfgs_search_strategy class).
        !*/

    public:
        cg_search_strategy(
        );
        /*!
            ensures
                - This object is properly initialized and ready to generate
                  search directions.
        !*/

        double get_wolfe_rho (
        ) const;
        /*!
            ensures
                - returns the value of the Wolfe rho parameter that should be used when
                  this search strategy is used with the line_search() function.
        !*/

        double get_wolfe_sigma (
        ) const;
        /*!
            ensures
                - returns the value of the Wolfe sigma parameter that should be used when
                  this search strategy is used with the line_search() function.
        !*/

        unsigned long get_max_line_search_iterations (
        ) const;
        /*!
            ensures
                - returns the value of the max iterations parameter that should be used when
                  this search strategy is used with the line_search() function.
        !*/

        template <typename T>
        const matrix<double,0,1>& get_next_direction (
            const T& x,
            const double funct_value,
            const T& funct_derivative
        );
        /*!
            requires
                - this function is only called once per search iteration
                - for some objective function f():
                    - x == the search point for the current iteration
                    - funct_value == f(x)
                    - funct_derivative == derivative(f)(x)
            ensures
                - Assuming that a line search is going to be conducted starting from the point x,
                  this function returns the direction in which the search should proceed.
        !*/

    };

// ----------------------------------------------------------------------------------------

    class bfgs_search_strategy
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object represents a strategy for determining which direction
                a line search should be carried out along.  This particular object
                is an implementation of the BFGS quasi-newton method for determining
                this direction.

                This method uses an amount of memory that is quadratic in the number
                of variables to be optimized.  It is generally very effective but
                if your problem has a very large number of variables then it isn't
                appropriate.  Instead You should try the lbfgs_search_strategy.
        !*/

    public:
        bfgs_search_strategy(
        );
        /*!
            ensures
                - This object is properly initialized and ready to generate
                  search directions.
        !*/

        double get_wolfe_rho (
        ) const;
        /*!
            ensures
                - returns the value of the Wolfe rho parameter that should be used when
                  this search strategy is used with the line_search() function.
        !*/

        double get_wolfe_sigma (
        ) const;
        /*!
            ensures
                - returns the value of the Wolfe sigma parameter that should be used when
                  this search strategy is used with the line_search() function.
        !*/

        unsigned long get_max_line_search_iterations (
        ) const;
        /*!
            ensures
                - returns the value of the max iterations parameter that should be used when
                  this search strategy is used with the line_search() function.
        !*/

        template <typename T>
        const matrix<double,0,1>& get_next_direction (
            const T& x,
            const double funct_value,
            const T& funct_derivative
        );
        /*!
            requires
                - this function is only called once per search iteration
                - for some objective function f():
                    - x == the search point for the current iteration
                    - funct_value == f(x)
                    - funct_derivative == derivative(f)(x)
            ensures
                - Assuming that a line search is going to be conducted starting from the point x,
                  this function returns the direction in which the search should proceed.
        !*/
    };

// ----------------------------------------------------------------------------------------

    class lbfgs_search_strategy
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object represents a strategy for determining which direction
                a line search should be carried out along.  This particular object
                is an implementation of the L-BFGS quasi-newton method for determining
                this direction.

                This method uses an amount of memory that is linear in the number
                of variables to be optimized.  This makes it an excellent method
                to use when an optimization problem has a large number of variables.
        !*/
    public:
        explicit lbfgs_search_strategy(
            unsigned long max_size
        );
        /*!
            requires
                - max_size > 0
            ensures
                - This object is properly initialized and ready to generate
                  search directions.
                - L-BFGS works by remembering a certain number of position and gradient
                  pairs.  It uses this remembered information to compute search directions.
                  The max_size argument determines how many of these pairs will be remembered.
                  Typically, using between 3 and 30 pairs performs well for many problems.
        !*/

        double get_wolfe_rho (
        ) const;
        /*!
            ensures
                - returns the value of the Wolfe rho parameter that should be used when
                  this search strategy is used with the line_search() function.
        !*/

        double get_wolfe_sigma (
        ) const;
        /*!
            ensures
                - returns the value of the Wolfe sigma parameter that should be used when
                  this search strategy is used with the line_search() function.
        !*/

        unsigned long get_max_line_search_iterations (
        ) const;
        /*!
            ensures
                - returns the value of the max iterations parameter that should be used when
                  this search strategy is used with the line_search() function.
        !*/

        template <typename T>
        const matrix<double,0,1>& get_next_direction (
            const T& x,
            const double funct_value,
            const T& funct_derivative
        );
        /*!
            requires
                - this function is only called once per search iteration
                - for some objective function f():
                    - x == the search point for the current iteration
                    - funct_value == f(x)
                    - funct_derivative == derivative(f)(x)
            ensures
                - Assuming that a line search is going to be conducted starting from the point x,
                  this function returns the direction in which the search should proceed.
        !*/
    };

// ----------------------------------------------------------------------------------------

    template <
        typename hessian_funct
        >
    class newton_search_strategy_obj
    {
        /*!
            REQUIREMENTS ON hessian_funct
                Objects of hessian_funct type must be function objects which
                take a single argument and return a dlib::matrix of doubles.  The
                single argument must be a dlib::matrix capable of representing
                column vectors of doubles.  hessian_funct must also be copy
                constructable.

            WHAT THIS OBJECT REPRESENTS
                This object represents a strategy for determining which direction
                a line search should be carried out along.  This particular object
                is an implementation of the newton method for determining this
                direction.  That is, it uses the following formula to determine
                the direction:
                    search_direction = -inv(hessian(x))*derivative
        !*/
    public:
        explicit newton_search_strategy_obj(
            const hessian_funct& hess
        );
        /*!
            ensures
                - This object is properly initialized and ready to generate
                  search directions.
                - hess will be used by this object to generate the needed hessian
                  matrices every time get_next_direction() is called.
        !*/

        double get_wolfe_rho (
        ) const;
        /*!
            ensures
                - returns the value of the Wolfe rho parameter that should be used when
                  this search strategy is used with the line_search() function.
        !*/

        double get_wolfe_sigma (
        ) const;
        /*!
            ensures
                - returns the value of the Wolfe sigma parameter that should be used when
                  this search strategy is used with the line_search() function.
        !*/

        unsigned long get_max_line_search_iterations (
        ) const;
        /*!
            ensures
                - returns the value of the max iterations parameter that should be used when
                  this search strategy is used with the line_search() function.
        !*/

        template <typename T>
        const matrix<double,0,1> get_next_direction (
            const T& x,
            const double funct_value,
            const T& funct_derivative
        );
        /*!
            requires
                - for some objective function f():
                    - x == the search point for the current iteration
                    - funct_value == f(x)
                    - funct_derivative == derivative(f)(x)
            ensures
                - Assuming that a line search is going to be conducted starting from the
                  point x, this function returns the direction in which the search should
                  proceed.
                - In particular, the search direction will be given by:
                    - search_direction = -inv(hessian(x))*funct_derivative
        !*/

    };

    template <typename hessian_funct>
    newton_search_strategy_obj<hessian_funct> newton_search_strategy (
        hessian_funct hessian
    ) { return newton_search_strategy_obj<hessian_funct>(hessian); }
    /*!
        ensures
            - constructs and returns a newton_search_strategy_obj.
              This function is just a helper to make the syntax for creating
              these objects a little simpler.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_OPTIMIZATIOn_SEARCH_STRATEGIES_ABSTRACT_


dlib C++ Library - optimization_stop_strategies_abstract.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_OPTIMIZATIOn_STOP_STRATEGIES_ABSTRACT_
#ifdef DLIB_OPTIMIZATIOn_STOP_STRATEGIES_ABSTRACT_

#include <cmath>
#include <limits>
#include "../matrix/matrix_abstract.h"
#include "../algs.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class objective_delta_stop_strategy
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object represents a strategy for deciding if an optimization
                algorithm should terminate.   This particular object looks at the
                change in the objective function from one iteration to the next and
                bases its decision on how large this change is.  If the change
                is below a user given threshold then the search stops.
        !*/

    public:
        explicit objective_delta_stop_strategy (
            double min_delta = 1e-7
        );
        /*!
            requires
                - min_delta >= 0
            ensures
                - This stop strategy object will only consider a search to be complete
                  if a change in an objective function from one iteration to the next
                  is less than min_delta.
        !*/

        objective_delta_stop_strategy (
            double min_delta,
            unsigned long max_iter
        );
        /*!
            requires
                - min_delta >= 0
                - max_iter > 0
            ensures
                - This stop strategy object will only consider a search to be complete
                  if a change in an objective function from one iteration to the next
                  is less than min_delta or more than max_iter iterations has been
                  executed.
        !*/

        objective_delta_stop_strategy& be_verbose(
        );
        /*!
            ensures
                - causes this object to print status messages to standard out
                  every time should_continue_search() is called.
                - returns *this
        !*/

        template <typename T>
        bool should_continue_search (
            const T& x,
            const double funct_value,
            const T& funct_derivative
        );
        /*!
            requires
                - this function is only called once per search iteration
                - for some objective function f():
                    - x == the search point for the current iteration
                    - funct_value == f(x)
                    - funct_derivative == derivative(f)(x)
            ensures
                - returns true if the point x doest not satisfy the stopping condition and
                  false otherwise.
        !*/

    };

// ----------------------------------------------------------------------------------------

    class gradient_norm_stop_strategy
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object represents a strategy for deciding if an optimization
                algorithm should terminate.   This particular object looks at the
                norm (i.e. the length) of the current gradient vector and stops
                if it is smaller than a user given threshold.
        !*/

    public:
        explicit gradient_norm_stop_strategy (
            double min_norm = 1e-7
        );
        /*!
            requires
                - min_norm >= 0
            ensures
                - This stop strategy object will only consider a search to be complete
                  if the current gradient norm is less than min_norm
        !*/

        gradient_norm_stop_strategy (
            double min_norm,
            unsigned long max_iter
        );
        /*!
            requires
                - min_norm >= 0
                - max_iter > 0
            ensures
                - This stop strategy object will only consider a search to be complete
                  if the current gradient norm is less than min_norm or more than
                  max_iter iterations has been executed.
        !*/

        gradient_norm_stop_strategy& be_verbose(
        );
        /*!
            ensures
                - causes this object to print status messages to standard out
                  every time should_continue_search() is called.
                - returns *this
        !*/

        template <typename T>
        bool should_continue_search (
            const T& x,
            const double funct_value,
            const T& funct_derivative
        );
        /*!
            requires
                - this function is only called once per search iteration
                - for some objective function f():
                    - x == the search point for the current iteration
                    - funct_value == f(x)
                    - funct_derivative == derivative(f)(x)
            ensures
                - returns true if the point x doest not satisfy the stopping condition and
                  false otherwise.
        !*/

    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_OPTIMIZATIOn_STOP_STRATEGIES_ABSTRACT_


dlib C++ Library - Parsing

The Library
  • Algorithms
  • API Wrappers
  • Bayesian Nets
  • Compression
  • Containers
  • Graph Tools
  • Image Processing
  • Linear Algebra
  • Machine Learning
  • Metaprogramming
  • Miscellaneous
  • Networking
  • Optimization
  • Parsing

Help/Info
  • Dlib Blog
  • Examples: C++
    • 3D Point Cloud
    • Assignment Learning
    • Base64 Encoder
    • Bayesian Network From Disk
    • Bayesian Network GUI
    • Bayesian Network
    • Bridge
    • BSP
    • C-Support Vector Machine
    • Cmd Line Parser
    • Compress Stream
    • Config File Reader
    • Custom Trainers
    • Directory Navigation
    • Empirical Kernel Map
    • Face Detection
    • Face Landmark Detection
    • FHOG Feature Extraction
    • FHOG Object Detection
    • Graph Labeling
    • GUI
    • Hough Transform
    • HTTP Server
    • Image
    • IO Socket Streams
    • IO Streams Server
    • Kernel Centroid
    • Kernel K-Means Clustering
    • Kernel Ridge Regression
    • Kernel RLS Filtering
    • Kernel RLS Regression
    • KRR Classification
    • Learning to Track
    • Linear Assignment Problems
    • Linear Manifold Regularizer
    • Linear Model Predictive Control
    • Logger Advanced
    • Logger Custom Output
    • Logger
    • Matrix Expressions
    • Matrix
    • Member Function Pointer
    • Model Selection
    • Multiclass Classification
    • Multithreaded Object
    • Neural Network
    • Non-Linear Least Squares
    • Nu-Support Vector Machine
    • Numerical Integration
    • Object Detector Advanced
    • Object Detector
    • One Class Classifiers
    • Online SVM
    • Optimization
    • Parallel For Loops
    • Pipe 2
    • Pipe
    • Quantum Computing
    • Queue
    • Rank Features
    • Relevance Vector Classification
    • Relevance Vector Regression
    • Running Stats
    • Sequence Labeling
    • Sequence Segmentation
    • Sockets
    • Sockstreambuf
    • Sparse Vectors
    • SQLite
    • Std C++ Allocator
    • Structural Support Vector Machines
    • Support Vector Regression
    • SURF
    • SVM-Rank
    • Thread Function
    • Thread Pool
    • Threaded Object
    • Threads
    • Timer
    • Train Object Detector
    • Train Shape Predictor
    • Using Custom Kernels
    • Video Object Tracking
    • Webcam Face Pose Estimation
    • XML Parser
  • Examples: Python
    • Face Detector
    • Face Landmark Detection
    • find candidate object locations
    • Linear Assignment Problems
    • Sequence Segmenter
    • Structural Support Vector Machines
    • SVM-Rank
    • Train Object Detector
    • Train Shape Predictor
    • Video Object Tracking
  • FAQ
  • Forums
  • Home
  • How to compile
  • How to contribute
  • Index
  • Introduction
  • License
  • Python API
  • Suggested Books
  • Who uses dlib?

Current Release
  • Change Log
  • Release Notes
  • Version: 18.18

Last Modified:
Sep 13, 2015
Parsing

This page documents the objects and functions that in some way deal with parsing or otherwise manipulating text. Everything here follows the same conventions as the rest of the library.

Objects
  • base64
  • basic_utf8_ifstream
  • cmd_line_parser
  • config_reader
  • cpp_pretty_printer
  • cpp_tokenizer
  • tokenizer
  • unichar
  • ustring
  • xml_parser

Global Functions
  • cast_to_string
  • cast_to_wstring
  • convert_utf8_to_utf32
  • is_combining_char
  • left_substr
  • lpad
  • ltrim
  • narrow
  • pad
  • pad_int_with_zeros
  • right_substr
  • rpad
  • rtrim
  • split
  • split_on_first
  • split_on_last
  • strings_equal_ignore_case
  • string_assign
  • string_cast
  • tolower
  • toupper
  • trim
  • wrap_string

[top]

base64

This object allows you to encode and decode data to and from the Base64 Content-Transfer-Encoding defined in section 6.8 of rfc2045.

C++ Example Programs: file_to_code_ex.cpp
More Details...
#include <dlib/base64.h>
[top]

basic_utf8_ifstream

This object represents an input file stream much like the normal std::ifstream except that it knows how to read UTF-8 data. So when you read characters out of this stream it will automatically convert them from the UTF-8 multibyte encoding into a fixed width wide character encoding.

There are also two typedefs of this object. The first is utf8_wifstream which is a typedef for wchar_t as the wide character to read into. The second is utf8_uifstream which uses unichar instead of wchar_t.

More Details...
#include <dlib/unicode.h>
[top]

cast_to_string

cast_to_string is a templated function which makes it easy to convert arbitrary objects to std::string strings. The types supported are any types that can be written to std::ostream via operator<<.
More Details...
#include <dlib/string.h>
[top]

cast_to_wstring

cast_to_string is a templated function which makes it easy to convert arbitrary objects to std::wstring strings. The types supported are any types that can be written to std::wostream via operator<<.
More Details...
#include <dlib/string.h>
[top]

cmd_line_parser

This object allows you to easily parse a command line. Note that the documentation for the cmd_line_parser_option (the object returned by the parser's .option() function) is in a separate file.

Note also that there are standard typedefs for the ASCII and wide character versions of the cmd_line_parser template. These are the command_line_parser and wcommand_line_parser types respectively.

C++ Example Programs: compress_stream_ex.cpp, train_object_detector.cpp
More Details...
#include <dlib/cmd_line_parser.h>

Extensions to cmd_line_parser

get_option

This extension provides a convenience function for accessing the options to a command line argument or a config_reader. It is automatically #included when using the command line parser or config reader.

More Details...
[top]

config_reader

This object represents something which is intended to be used to read text configuration files.

C++ Example Programs: config_reader_ex.cpp
More Details...
#include <dlib/config_reader.h>

Extensions to config_reader

config_reader_thread_safe

This object extends a normal config_reader by simply wrapping all its member functions inside mutex locks to make it safe to use in a threaded program.

More Details...
[top]

convert_utf8_to_utf32

This is a global function that can convert UTF-8 strings into strings of 32bit unichar characters.
More Details...
#include <dlib/unicode.h>
[top]

cpp_pretty_printer

This object represents an HTML pretty printer for C++ source code.
More Details...
#include <dlib/cpp_pretty_printer.h>

Implementations:
cpp_pretty_printer_kernel_1:
This is implemented by using the cpp_tokenizer object. This is the pretty printer I use on all the source in this library. It applies a color scheme, turns include directives such as #include "file.h" into links to file.h.html and puts HTML anchor points on function and class declarations. It also looks for comments starting with /*!A and puts an anchor before the comment using the word following the A as the name of the anchor.
kernel_1a
is a typedef for cpp_pretty_printer_kernel_1
cpp_pretty_printer_kernel_2:
This is implemented by using the cpp_tokenizer object. It applies a black and white color scheme suitable for printing on a black and white printer. It also places the document title prominently at the top of the pretty printed source file.
kernel_2a
is a typedef for cpp_pretty_printer_kernel_2
[top]

cpp_tokenizer

This object represents a simple tokenizer for C++ source code.
More Details...
#include <dlib/cpp_tokenizer.h>

Implementations:
cpp_tokenizer_kernel_1:
This is implemented by using the tokenizer object in the obvious way.
kernel_1a
is a typedef for cpp_tokenizer_kernel_1
kernel_1a_c
 is a typedef for kernel_1a that checks its preconditions.
[top]

is_combining_char

This is a global function that can tell you if a character is a Unicode combining character or not.
More Details...
#include <dlib/unicode.h>
[top]

left_substr

This is a function to return the part of a string to the left of a user supplied delimiter.
More Details...
#include <dlib/string.h>
[top]

lpad

This is a function to pad whitespace (or user specified characters) onto the left most end of a string.
More Details...
#include <dlib/string.h>
[top]

ltrim

This is a function to remove the whitespace (or user specified characters) from the left most end of a string.
More Details...
#include <dlib/string.h>
[top]

narrow

This is a function for converting a string of type std::string or std::wstring to a plain std::string.
More Details...
#include <dlib/string.h>
[top]

pad

This is a function to pad whitespace (or user specified characters) onto the ends of a string.
More Details...
#include <dlib/string.h>
[top]

pad_int_with_zeros

Converts an integer into a string and pads it with leading zeros.
More Details...
#include <dlib/string.h>
[top]

right_substr

This is a function to return the part of a string to the right of a user supplied delimiter.
More Details...
#include <dlib/string.h>
[top]

rpad

This is a function to pad whitespace (or user specified characters) onto the right most end of a string.
More Details...
#include <dlib/string.h>
[top]

rtrim

This is a function to remove the whitespace (or user specified characters) from the right most end of a string.
More Details...
#include <dlib/string.h>
[top]

split

Breaks a string into a sequence of substrings delimited by a user specified set of characters.
More Details...
#include <dlib/string.h>
[top]

split_on_first

Breaks a string into two parts. The split point is selected based on the first occurrence of a delimiter character.
More Details...
#include <dlib/string.h>
[top]

split_on_last

Breaks a string into two parts. The split point is selected based on the last occurrence of a delimiter character.
More Details...
#include <dlib/string.h>
[top]

strings_equal_ignore_case

This is a pair of functions to do a case insensitive comparison between strings.
More Details...
#include <dlib/string.h>
[top]

string_assign

string_assign is an object which makes it easy to convert strings to other types. The types supported are any types that can be read by the basic_istream operator>>. It also supports casting between wstring, string, and ustring objects. Since string_assign is a simple stateless object there is a global instance of it called dlib::sa.

C++ Example Programs: config_reader_ex.cpp
More Details...
#include <dlib/string.h>
[top]

string_cast

string_cast is a templated function which makes it easy to convert strings to other types. The types supported are any types that can be read by the basic_istream operator>>. It also supports casting between wstring, string, and ustring objects.
More Details...
#include <dlib/string.h>
[top]

tokenizer

This object represents a simple tokenizer for textual data.
More Details...
#include <dlib/tokenizer.h>

Implementations:
tokenizer_kernel_1:
This is implemented in the obvious way.
kernel_1a
is a typedef for tokenizer_kernel_1
kernel_1a_c
 is a typedef for kernel_1a that checks its preconditions.
[top]

tolower

This is a function to convert a string to all lowercase.
More Details...
#include <dlib/string.h>
[top]

toupper

This is a function to convert a string to all uppercase.
More Details...
#include <dlib/string.h>
[top]

trim

This is a function to remove the whitespace (or user specified characters) from the ends of a string.
More Details...
#include <dlib/string.h>
[top]

unichar

This is a typedef for an unsigned 32bit integer which we use to store Unicode values.
More Details...
#include <dlib/unicode.h>
[top]

ustring

This is a typedef for a std::basic_string<unichar>. That is, it is a typedef for a string object that stores unichar Unicode characters.
More Details...
#include <dlib/unicode.h>
[top]

wrap_string

wrap_string is a function that takes a string and breaks it into a number of lines of a given length. You can use this to make a string fit nicely into a command prompt window for example.
More Details...
#include <dlib/string.h>
[top]

xml_parser

This object represents a simple SAX style event driven XML parser. It takes its input from an input stream object and sends events to all registered document_handler and error_handler objects.

The xml_parser object also uses the interface classes document_handler and error_handler. Subclasses of these classes are passed to the xml_parser which generates events while it's parsing and sends them to the appropriate handler.

C++ Example Programs: xml_parser_ex.cpp
More Details...
#include <dlib/xml_parser.h>


dlib C++ Library - base64_kernel_abstract.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_BASE64_KERNEl_ABSTRACT_
#ifdef DLIB_BASE64_KERNEl_ABSTRACT_

#include "../algs.h"
#include <iosfwd>

namespace dlib
{

    class base64
    {
        /*!
            INITIAL VALUE
                - line_ending() == LF

            WHAT THIS OBJECT REPRESENTS
                This object consists of the two functions encode and decode.
                These functions allow you to encode and decode data to and from
                the Base64 Content-Transfer-Encoding defined in section 6.8 of
                rfc2045.
        !*/

    public:

        class decode_error : public dlib::error {};

        base64 (
        );
        /*!
            ensures
                - #*this is properly initialized
            throws
                - std::bad_alloc
        !*/

        virtual ~base64 (
        );
        /*!
            ensures
                - all memory associated with *this has been released
        !*/

        enum line_ending_type
        {
            CR,  // i.e. "\r"
            LF,  // i.e. "\n"
            CRLF // i.e. "\r\n"
        };

        line_ending_type line_ending (
        ) const;
        /*!
            ensures
                - returns the type of end of line bytes the encoder
                  will use when encoding data to base64 blocks.  Note that
                  the ostream object you use might apply some sort of transform
                  to line endings as well.  For example, C++ ofstream objects
                  usually convert '\n' into whatever a normal newline is for
                  your platform unless you open a file in binary mode.  But
                  aside from file streams the ostream objects usually don't
                  modify the data you pass to them.
        !*/

        void set_line_ending (
            line_ending_type eol_style
        );
        /*!
            ensures
                - #line_ending() == eol_style
        !*/

        void encode (
            std::istream& in,
            std::ostream& out
        ) const;
        /*!
            ensures
                - reads all data from in (until EOF is reached) and encodes it
                  and writes it to out
            throws
                - std::ios_base::failure
                    if there was a problem writing to out then this exception will
                    be thrown.
                - any other exception
                    this exception may be thrown if there is any other problem
        !*/

        void decode (
            std::istream& in,
            std::ostream& out
        ) const;
        /*!
            ensures
                - reads data from in (until EOF is reached), decodes it,
                  and writes it to out.
            throws
                - std::ios_base::failure
                    if there was a problem writing to out then this exception will
                    be thrown.
                - decode_error
                    if an error was detected in the encoded data that prevented
                    it from being correctly decoded then this exception is
                    thrown.
                - any other exception
                    this exception may be thrown if there is any other problem
        !*/

    private:

        // restricted functions
        base64(base64&);        // copy constructor
        base64& operator=(base64&);    // assignment operator

    };

}

#endif // DLIB_BASE64_KERNEl_ABSTRACT_


dlib C++ Library - unicode_abstract.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net), and Nils Labugt
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_UNICODe_ABSTRACT_H_
#ifdef DLIB_UNICODe_ABSTRACT_H_

#include "../uintn.h"
#include "../error.h"
#include <string>
#include <fstream>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    // a typedef for an unsigned 32bit integer to hold our UNICODE characters
    typedef uint32 unichar;

    // a typedef for a string object to hold our UNICODE strings
    typedef std::basic_string<unichar> ustring;

// ----------------------------------------------------------------------------------------

    template <typename T>
    bool is_combining_char(
        const T ch_
    );
    /*!
        ensures
            - if (ch_ is a unicode combining character) then
                - returns true
            - else
                - returns false
    !*/

    bool is_surrogate(
        unichar ch
    );
    /*!
        ensures
            - if (ch is a unicode surrogate character) then
                - returns true
            - else
                - returns false
    !*/

    unichar surrogate_pair_to_unichar(
        unichar first,
        unichar second
    );
    /*!
        requires
            - 0xD800 <= first < 0xDC00
            - 0xDC00 <= second < 0xE000
            - is_surrogate(first) == true
            - is_surrogate(second) == true
        ensures
            - converts two surrogates into one unicode character
    !*/

    void unichar_to_surrogate_pair(
        unichar ch,
        unichar& first,
        unichar& second
    );
    /*!
        requires
            - ch >= 0x10000 (i.e. is not in Basic Multilingual Plane)
        ensures
            - surrogate_pair_to_unichar(#first,#second) == ch
              (i.e. converts ch into two surrogate characters)
    !*/

// ----------------------------------------------------------------------------------------

    class invalid_utf8_error : public error
    {
    public:
        invalid_utf8_error():error(EUTF8_TO_UTF32) {}
    };

    const ustring convert_utf8_to_utf32 (
        const std::string& str
    );
    /*!
        ensures
            - if (str is a valid UTF-8 encoded string) then
                - returns a copy of str that has been converted into a
                  unichar string
            - else
                - throws invalid_utf8_error
    !*/

// ----------------------------------------------------------------------------------------

    const ustring convert_wstring_to_utf32 (
        const std::wstring &wstr
    );
    /*!
        requires
            - wstr is a valid UTF-16 string when sizeof(wchar_t) == 2
            - wstr is a valid UTF-32 string when sizeof(wchar_t) == 4
        ensures
            - converts wstr into UTF-32 string
    !*/

// ----------------------------------------------------------------------------------------

    const std::wstring convert_utf32_to_wstring (
        const ustring &str
    );
    /*!
        requires
            - str is a valid UTF-32 encoded string
        ensures
            - converts str into wstring whose encoding is UTF-16 when sizeof(wchar_t) == 2
            - converts str into wstring whose encoding is UTF-32 when sizeof(wchar_t) == 4
    !*/

// ----------------------------------------------------------------------------------------

    const std::wstring convert_mbstring_to_wstring (
        const std::string &str
    );
    /*!
        requires
            - str is a valid multibyte string whose encoding is same as current locale setting
        ensures
            - converts str into wstring whose encoding is UTF-16 when sizeof(wchar_t) == 2
            - converts str into wstring whose encoding is UTF-32 when sizeof(wchar_t) == 4
    !*/

// ----------------------------------------------------------------------------------------

    const std::string convert_wstring_to_mbstring (
        const std::wstring &src
    );
    /*!
        requires
            - str is a valid wide character string string whose encoding is same as current
              locale setting
        ensures
            - returns a multibyte encoded version of the given string
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename charT
        >
    class basic_utf8_ifstream : public std::basic_istream<charT>
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object represents an input file stream much like the
                normal std::ifstream except that it knows how to read UTF-8
                data.  So when you read characters out of this stream it will
                automatically convert them from the UTF-8 multibyte encoding
                into a fixed width wide character encoding.
        !*/

    public:

        basic_utf8_ifstream (
        );
        /*!
            ensures
                - constructs an input stream that isn't yet associated with
                  a file.
        !*/

        basic_utf8_ifstream (
            const char* file_name,
            std::ios_base::openmode mode = std::ios::in
        );
        /*!
            ensures
                - tries to open the given file for reading by this stream
                - mode is interpreted exactly the same was as the open mode
                  argument used by std::ifstream.
        !*/

        basic_utf8_ifstream (
            const std::string& file_name,
            std::ios_base::openmode mode = std::ios::in
        );
        /*!
            ensures
                - tries to open the given file for reading by this stream
                - mode is interpreted exactly the same was as the open mode
                  argument used by std::ifstream.
        !*/

        void open(
            const std::string& file_name,
            std::ios_base::openmode mode = std::ios::in
        );
        /*!
            ensures
                - tries to open the given file for reading by this stream
                - mode is interpreted exactly the same was as the open mode
                  argument used by std::ifstream.
        !*/

        void open (
            const char* file_name,
            std::ios_base::openmode mode = std::ios::in
        );
        /*!
            ensures
                - tries to open the given file for reading by this stream
                - mode is interpreted exactly the same was as the open mode
                  argument used by std::ifstream.
        !*/

        void close (
        );
        /*!
            ensures
                - any file opened by this stream has been closed
        !*/
    };

    typedef basic_utf8_ifstream<unichar> utf8_uifstream;
    typedef basic_utf8_ifstream<wchar_t> utf8_wifstream;

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_UNICODe_ABSTRACT_H_


dlib C++ Library - cmd_line_parser_kernel_abstract.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_CMD_LINE_PARSER_KERNEl_ABSTRACT_
#ifdef DLIB_CMD_LINE_PARSER_KERNEl_ABSTRACT_

#include "../algs.h"
#include <string>
#include "../interfaces/enumerable.h"
#include "../interfaces/cmd_line_parser_option.h"
#include <vector>
#include <iostream>

namespace dlib
{

    template <
        typename charT
        >
    class cmd_line_parser : public enumerable<cmd_line_parser_option<charT> >
    {
        /*!
            REQUIREMENTS ON charT
                Must be an integral type suitable for storing characters.  (e.g. char
                or wchar_t)

            INITIAL VALUE
                - parsed_line() == false
                - option_is_defined(x) == false, for all values of x
                - get_group_name() == ""

            ENUMERATION ORDER
                The enumerator will enumerate over all the options defined in *this
                in alphebetical order according to the name of the option.

            POINTERS AND REFERENCES TO INTERNAL DATA
                parsed_line(), option_is_defined(), option(), number_of_arguments(),
                operator[](), and swap() functions do not invalidate pointers or
                references to internal data.  All other functions have no such guarantee.

            WHAT THIS OBJECT REPRESENTS
                This object represents a command line parser.
                The command lines must match the following BNF.

                command_line     ::= <program_name> { <options> | <arg> } [ -- {<word>} ]
                program_name     ::= <word>
                arg              ::= any <word> that does not start with -
                option_arg       ::= <sword>
                option_name      ::= <char>
                long_option_name ::= <char> {<char> | - }
                options          ::= <bword> - <option_name> {<option_name>}  {<option_arg>}  |
                                     <bword> -- <long_option_name> [=<option_arg>] {<bword> <option_arg>}
                char             ::= any character other than - or =
                word             ::= any string from argv where argv is the second
                                     parameter to main()
                sword            ::= any suffix of a string from argv where argv is the
                                     second parameter to main()
                bword            ::= This is an empty string which denotes the begining of a
                                     <word>.

                Options with arguments:
                    An option with N arguments will consider the next N swords to be
                    its arguments.

                    so for example, if we have an option o that expects 2 arguments
                    then the following are a few legal examples:

                        program -o arg1 arg2 general_argument
                        program -oarg1 arg2 general_argument

                    arg1 and arg2 are associated with the option o and general_argument
                    is not.

                Arguments not associated with an option:
                    An argument that is not associated with an option is considered a
                    general command line argument and is indexed by operator[] defined
                    by the cmd_line_parser object.  Additionally, if the string
                    "--" appears in the command line all by itself then all words
                    following it are considered to be general command line arguments.

                    Consider the following two examples involving a command line and
                    a cmd_line_parser object called parser.

                    Example 1:
                        command line: program general_arg1 -o arg1 arg2 general_arg2
                        Then the following is true (assuming the o option is defined
                        and takes 2 arguments).

                        parser[0] == "general_arg1"
                        parser[1] == "general_arg2"
                        parser.number_of_arguments() == 2
                        parser.option("o").argument(0) == "arg1"
                        parser.option("o").argument(1) == "arg2"
                        parser.option("o").count() == 1

                    Example 2:
                        command line: program general_arg1 -- -o arg1 arg2 general_arg2
                        Then the following is true (the -- causes everything following
                        it to be treated as a general argument).

                        parser[0] == "general_arg1"
                        parser[1] == "-o"
                        parser[2] == "arg1"
                        parser[3] == "arg2"
                        parser[4] == "general_arg2"
                        parser.number_of_arguments() == 5
                        parser.option("o").count() == 0
        !*/

    public:

        typedef charT char_type;
        typedef std::basic_string<charT> string_type;
        typedef cmd_line_parser_option<charT> option_type;

        // exception class
        class cmd_line_parse_error : public dlib::error
        {
            /*!
                GENERAL
                    This exception is thrown if there is an error detected in a
                    command line while it is being parsed.  You can consult this
                    object's type and item members to determine the nature of the
                    error. (note that the type member is inherited from dlib::error).

                INTERPRETING THIS EXCEPTION
                    - if (type == EINVALID_OPTION) then
                        - There was an undefined option on the command line
                        - item == The invalid option that was on the command line
                    - if (type == ETOO_FEW_ARGS) then
                        - An option was given on the command line but it was not
                          supplied with the required number of arguments.
                        - item == The name of this option.
                        - num == The number of arguments expected by this option.
                    - if (type == ETOO_MANY_ARGS) then
                        - An option was given on the command line such as --option=arg
                          but this option doesn't take any arguments.
                        - item == The name of this option.
            !*/
        public:
            const std::basic_string<charT> item;
            const unsigned long num;
        };

    // --------------------------

        cmd_line_parser (
        );
        /*!
            ensures
                - #*this is properly initialized
            throws
                - std::bad_alloc
        !*/

        virtual ~cmd_line_parser (
        );
        /*!
            ensures
                 - all memory associated with *this has been released
        !*/

        void clear(
        );
        /*!
            ensures
                - #*this has its initial value
            throws
                - std::bad_alloc
                    if this exception is thrown then #*this is unusable
                    until clear() is called and succeeds
        !*/

        void parse (
            int argc,
            const charT** argv
        );
        /*!
            requires
                - argv == an array of strings that was obtained from the second argument
                          of the function main().
                          (i.e. argv[0] should be the <program> token, argv[1] should be
                          an <options> or <arg> token, etc.)
                - argc == the number of strings in argv
            ensures
                - parses the command line given by argc and argv
                - #parsed_line() == true
                - #at_start() == true
            throws
                - std::bad_alloc
                    if this exception is thrown then #*this is unusable until clear()
                    is called successfully
                - cmd_line_parse_error
                    This exception is thrown if there is an error parsing the command line.
                    If this exception is thrown then #parsed_line() == false and all
                    options will have their count() set to 0 but otherwise there will
                    be no effect (i.e. all registered options will remain registered).
        !*/

        void parse (
            int argc,
            charT** argv
        );
        /*!
            This just calls this->parse(argc,argv) and performs the necessary const_cast
            on argv.
        !*/

        bool parsed_line(
        ) const;
        /*!
            ensures
                - returns true if parse() has been called successfully
                - returns false otherwise
        !*/

        bool option_is_defined (
            const string_type& name
        ) const;
        /*!
            ensures
                - returns true if the option has been added to the parser object
                  by calling add_option(name).
                - returns false otherwise
        !*/

        void add_option (
            const string_type& name,
            const string_type& description,
            unsigned long number_of_arguments = 0
        );
        /*!
            requires
                - parsed_line() == false
                - option_is_defined(name) == false
                - name does not contain any ' ', '\t', '\n', or '=' characters
                - name[0] != '-'
                - name.size() > 0
            ensures
                - #option_is_defined(name) == true
                - #at_start() == true
                - #option(name).count() == 0
                - #option(name).description() == description
                - #option(name).number_of_arguments() == number_of_arguments
                - #option(name).group_name() == get_group_name()
            throws
                - std::bad_alloc
                    if this exception is thrown then the add_option() function has no
                    effect
        !*/

        const option_type& option (
            const string_type& name
        ) const;
        /*!
            requires
                - option_is_defined(name) == true
            ensures
                - returns the option specified by name
        !*/

        unsigned long number_of_arguments(
        ) const;
        /*!
            requires
                - parsed_line() == true
            ensures
                - returns the number of arguments present in the command line.
                  This count does not include options or their arguments.  Only
                  arguments unrelated to any option are counted.
        !*/

        const string_type& operator[] (
            unsigned long N
        ) const;
        /*!
            requires
                - parsed_line() == true
                - N < number_of_arguments()
            ensures
                - returns the Nth command line argument
        !*/

        void swap (
            cmd_line_parser& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/

        void print_options (
            std::basic_ostream<char_type>& out
        ) const;
        /*!
            ensures
                - prints all the command line options to out.
                - #at_start() == true
            throws
                - any exception.
                    if an exception is thrown then #at_start() == true but otherwise
                    it will have no effect on the state of #*this.
        !*/

        void print_options (
        ) const;
        /*!
            ensures
                - prints all the command line options to cout.
                - #at_start() == true
            throws
                - any exception.
                    if an exception is thrown then #at_start() == true but otherwise
                    it will have no effect on the state of #*this.
        !*/

        string_type get_group_name (
        ) const;
        /*!
            ensures
                - returns the current group name.  This is the group new options will be
                  added into when added via add_option().
                - The group name of an option is used by print_options().  In particular,
                  it groups all options with the same group name together and displays them
                  under a title containing the text of the group name.  This allows you to
                  group similar options together in the output of print_options().
                - A group name of "" (i.e. the empty string) means that no group name is
                  set.
        !*/

        void set_group_name (
            const string_type& group_name
        );
        /*!
            ensures
                - #get_group_name() == group_name
        !*/

    // -------------------------------------------------------------
    //                    Input Validation Tools
    // -------------------------------------------------------------

        class cmd_line_check_error : public dlib::error
        {
            /*!
                This is the exception thrown by the check_*() routines if they find a
                command line error.  The interpretation of the member variables is defined
                below in each check_*() routine.
            !*/

        public:
            const string_type opt;
            const string_type opt2;
            const string_type arg;
            const std::vector<string_type> required_opts;
        };

        template <
            typename T
            >
        void check_option_arg_type (
            const string_type& option_name
        ) const;
        /*!
            requires
                - parsed_line() == true
                - option_is_defined(option_name) == true
                - T is not a pointer type
            ensures
                - all the arguments for the given option are convertible
                  by string_cast<T>() to an object of type T.
            throws
                - std::bad_alloc
                - cmd_line_check_error
                    This exception is thrown if the ensures clause could not be satisfied.
                    The exception's members will be set as follows:
                        - type == EINVALID_OPTION_ARG
                        - opt == option_name
                        - arg == the text of the offending argument
        !*/

        template <
            typename T
            >
        void check_option_arg_range (
            const string_type& option_name,
            const T& first,
            const T& last
        ) const;
        /*!
            requires
                - parsed_line() == true
                - option_is_defined(option_name) == true
                - first <= last
                - T is not a pointer type
            ensures
                - all the arguments for the given option are convertible
                  by string_cast<T>() to an object of type T and the resulting value is
                  in the range first to last inclusive.
            throws
                - std::bad_alloc
                - cmd_line_check_error
                    This exception is thrown if the ensures clause could not be satisfied.
                    The exception's members will be set as follows:
                        - type == EINVALID_OPTION_ARG
                        - opt == option_name
                        - arg == the text of the offending argument
        !*/

        template <
            typename T,
            size_t length
            >
        void check_option_arg_range (
            const string_type& option_name,
            const T (&arg_set)[length]
        ) const;
        /*!
            requires
                - parsed_line() == true
                - option_is_defined(option_name) == true
                - T is not a pointer type
            ensures
                - for each argument to the given option:
                    - this argument is convertible by string_cast<T>() to an object of
                      type T and the resulting value is equal to some element in the
                      arg_set array.
            throws
                - std::bad_alloc
                - cmd_line_check_error
                    This exception is thrown if the ensures clause could not be satisfied.
                    The exception's members will be set as follows:
                        - type == EINVALID_OPTION_ARG
                        - opt == option_name
                        - arg == the text of the offending argument
        !*/

        template <
            size_t length
            >
        void check_option_arg_range (
            const string_type& option_name,
            const char_type* (&arg_set)[length]
        ) const;
        /*!
            requires
                - parsed_line() == true
                - option_is_defined(option_name) == true
            ensures
                - for each argument to the given option:
                    - there is a string in the arg_set array that is equal to this argument.
            throws
                - std::bad_alloc
                - cmd_line_check_error
                    This exception is thrown if the ensures clause could not be satisfied.
                    The exception's members will be set as follows:
                        - type == EINVALID_OPTION_ARG
                        - opt == option_name
                        - arg == the text of the offending argument
        !*/

        template <
            size_t length
            >
        void check_one_time_options (
            const char_type* (&option_set)[length]
        ) const;
        /*!
            requires
                - parsed_line() == true
                - for all valid i:
                    - option_is_defined(option_set[i]) == true
            ensures
                - all the options in the option_set array occur at most once on the
                  command line.
            throws
                - std::bad_alloc
                - cmd_line_check_error
                    This exception is thrown if the ensures clause could not be satisfied.
                    The exception's members will be set as follows:
                        - type == EMULTIPLE_OCCURANCES
                        - opt == the option that occurred more than once on the command line.
        !*/

        void check_incompatible_options (
            const string_type& option_name1,
            const string_type& option_name2
        ) const;
        /*!
            requires
                - parsed_line() == true
                - option_is_defined(option_name1) == true
                - option_is_defined(option_name2) == true
            ensures
                - option(option_name1).count() == 0 || option(option_name2).count() == 0
                  (i.e. at most, only one of the options is currently present)
            throws
                - std::bad_alloc
                - cmd_line_check_error
                    This exception is thrown if the ensures clause could not be satisfied.
                    The exception's members will be set as follows:
                        - type == EINCOMPATIBLE_OPTIONS
                        - opt == option_name1
                        - opt2 == option_name2
        !*/

        template <
            size_t length
            >
        void check_incompatible_options (
            const char_type* (&option_set)[length]
        ) const;
        /*!
            requires
                - parsed_line() == true
                - for all valid i:
                    - option_is_defined(option_set[i]) == true
            ensures
                - At most only one of the options in the array option_set has a count()
                  greater than 0.  (i.e. at most, only one of the options is currently present)
            throws
                - std::bad_alloc
                - cmd_line_check_error
                    This exception is thrown if the ensures clause could not be satisfied.
                    The exception's members will be set as follows:
                        - type == EINCOMPATIBLE_OPTIONS
                        - opt == One of the incompatible options found.
                        - opt2 == The next incompatible option found.
        !*/

        void check_sub_option (
            const string_type& parent_option,
            const string_type& sub_option
        ) const;
        /*!
            requires
                - parsed_line() == true
                - option_is_defined(parent_option) == true
                - option_is_defined(sub_option) == true
            ensures
                - if (option(parent_option).count() == 0) then
                    - option(sub_option).count() == 0
            throws
                - std::bad_alloc
                - cmd_line_check_error
                    This exception is thrown if the ensures clause could not be satisfied.
                    The exception's members will be set as follows:
                        - type == EMISSING_REQUIRED_OPTION
                        - opt == sub_option.
                        - required_opts == a vector that contains only parent_option.
        !*/

        template <
            size_t length
            >
        void check_sub_options (
            const char_type* (&parent_option_set)[length],
            const string_type& sub_option
        ) const;
        /*!
            requires
                - parsed_line() == true
                - option_is_defined(sub_option) == true
                - for all valid i:
                    - option_is_defined(parent_option_set[i] == true
            ensures
                - if (option(sub_option).count() > 0) then
                    - At least one of the options in the array parent_option_set has a count()
                      greater than 0. (i.e. at least one of the options in parent_option_set
                      is currently present)
            throws
                - std::bad_alloc
                - cmd_line_check_error
                    This exception is thrown if the ensures clause could not be satisfied.
                    The exception's members will be set as follows:
                        - type == EMISSING_REQUIRED_OPTION
                        - opt == the first option from the sub_option that is present.
                        - required_opts == a vector containing everything from parent_option_set.
        !*/

        template <
            size_t length
            >
        void check_sub_options (
            const string_type& parent_option,
            const char_type* (&sub_option_set)[length]
        ) const;
        /*!
            requires
                - parsed_line() == true
                - option_is_defined(parent_option) == true
                - for all valid i:
                    - option_is_defined(sub_option_set[i]) == true
            ensures
                - if (option(parent_option).count() == 0) then
                    - for all valid i:
                        - option(sub_option_set[i]).count() == 0
            throws
                - std::bad_alloc
                - cmd_line_check_error
                    This exception is thrown if the ensures clause could not be satisfied.
                    The exception's members will be set as follows:
                        - type == EMISSING_REQUIRED_OPTION
                        - opt == the first option from the sub_option_set that is present.
                        - required_opts == a vector that contains only parent_option.
        !*/

        template <
            size_t parent_length,
            size_t sub_length
            >
        void check_sub_options (
            const char_type* (&parent_option_set)[parent_length],
            const char_type* (&sub_option_set)[sub_length]
        ) const;
        /*!
            requires
                - parsed_line() == true
                - for all valid i:
                    - option_is_defined(parent_option_set[i] == true
                - for all valid j:
                    - option_is_defined(sub_option_set[j]) == true
            ensures
                - for all valid j:
                    - if (option(sub_option_set[j]).count() > 0) then
                        - At least one of the options in the array parent_option_set has a count()
                          greater than 0. (i.e. at least one of the options in parent_option_set
                          is currently present)
            throws
                - std::bad_alloc
                - cmd_line_check_error
                    This exception is thrown if the ensures clause could not be satisfied.
                    The exception's members will be set as follows:
                        - type == EMISSING_REQUIRED_OPTION
                        - opt == the first option from the sub_option_set that is present.
                        - required_opts == a vector containing everything from parent_option_set.
        !*/

    private:

        // restricted functions
        cmd_line_parser(cmd_line_parser&);        // copy constructor
        cmd_line_parser& operator=(cmd_line_parser&);    // assignment operator

    };

// -----------------------------------------------------------------------------------------

    typedef cmd_line_parser<char>    command_line_parser;
    typedef cmd_line_parser<wchar_t> wcommand_line_parser;

// -----------------------------------------------------------------------------------------

    template <
        typename charT
        >
    inline void swap (
        cmd_line_parser<charT>& a,
        cmd_line_parser<charT>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

// -----------------------------------------------------------------------------------------

}

#endif // DLIB_CMD_LINE_PARSER_KERNEl_ABSTRACT_


dlib C++ Library - get_option_abstract.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_GET_OPTiON_ABSTRACT_Hh_
#ifdef DLIB_GET_OPTiON_ABSTRACT_Hh_

#inclue <string>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class option_parse_error : public error
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is the exception thrown by the get_option() functions.  It is
                thrown when the option string given by a command line parser or
                config reader can't be converted into the type T.
        !*/
    };

// ----------------------------------------------------------------------------------------

    template <
        typename config_reader_type,
        typename T
        >
    T get_option (
        const config_reader_type& cr,
        const std::string& option_name,
        T default_value
    );
    /*!
        requires
            - T is a type which can be read from an input stream
            - config_reader_type == an implementation of config_reader/config_reader_kernel_abstract.h
        ensures
            - option_name is used to index into the given config_reader.
            - if (cr contains an entry corresponding to option_name) then
                - converts the string value in cr corresponding to option_name into
                  an object of type T and returns it.
            - else
                - returns default_value
            - The scheme for indexing into cr based on option_name is best
              understood by looking at a few examples:
                - an option name of "name" corresponds to cr["name"]
                - an option name of "block1.name" corresponds to cr.block("block1")["name"]
                - an option name of "block1.block2.name" corresponds to cr.block("block1").block("block2")["name"]
        throws
            - option_parse_error
              This exception is thrown if we attempt but fail to convert the string value
              in cr into an object of type T.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename command_line_parser_type,
        typename T
        >
    T get_option (
        const command_line_parser_type& parser,
        const std::string& option_name,
        T default_value
    );
    /*!
        requires
            - parser.option_is_defined(option_name) == true
            - parser.option(option_name).number_of_arguments() == 1
            - T is a type which can be read from an input stream
            - command_line_parser_type == an implementation of cmd_line_parser/cmd_line_parser_kernel_abstract.h
        ensures
            - if (parser.option(option_name)) then
                - converts parser.option(option_name).argument() into an object
                  of type T and returns it.  That is, the string argument to this
                  command line option is converted into a T and returned.
            - else
                - returns default_value
        throws
            - option_parse_error
              This exception is thrown if we attempt but fail to convert the string
              argument into an object of type T.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename command_line_parser_type,
        typename config_reader_type,
        typename T
        >
    T get_option (
        const command_line_parser_type& parser,
        const config_reader_type& cr,
        const std::string& option_name,
        T default_value
    );
    /*!
        requires
            - parser.option_is_defined(option_name) == true
            - parser.option(option_name).number_of_arguments() == 1
            - T is a type which can be read from an input stream
            - command_line_parser_type == an implementation of cmd_line_parser/cmd_line_parser_kernel_abstract.h
            - config_reader_type == an implementation of config_reader/config_reader_kernel_abstract.h
        ensures
            - if (parser.option(option_name)) then
                - returns get_option(parser, option_name, default_value)
            - else
                - returns get_option(cr, option_name, default_value)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename command_line_parser_type,
        typename config_reader_type,
        typename T
        >
    T get_option (
        const config_reader_type& cr,
        const command_line_parser_type& parser,
        const std::string& option_name,
        T default_value
    );
    /*!
        requires
            - parser.option_is_defined(option_name) == true
            - parser.option(option_name).number_of_arguments() == 1
            - T is a type which can be read from an input stream
            - command_line_parser_type == an implementation of cmd_line_parser/cmd_line_parser_kernel_abstract.h
            - config_reader_type == an implementation of config_reader/config_reader_kernel_abstract.h
        ensures
            - if (parser.option(option_name)) then
                - returns get_option(parser, option_name, default_value)
            - else
                - returns get_option(cr, option_name, default_value)
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_GET_OPTiON_ABSTRACT_Hh_


dlib C++ Library - config_reader_kernel_abstract.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_CONFIG_READER_KERNEl_ABSTRACT_
#ifdef DLIB_CONFIG_READER_KERNEl_ABSTRACT_

#include <string>
#include <iosfwd>

namespace dlib
{

    class config_reader
    {

        /*!
            INITIAL VALUE
                - there aren't any keys defined for this object
                - there aren't any blocks defined for this object

            POINTERS AND REFERENCES TO INTERNAL DATA
                The destructor, clear(), and load_from() invalidate pointers
                and references to internal data.  All other functions are guaranteed
                to NOT invalidate pointers or references to internal data.

            WHAT THIS OBJECT REPRESENTS
                This object represents something which is intended to be used to read
                text configuration files that are defined by the following EBNF (with
                config_file as the starting symbol):

                config_file    = block;
                block          = { key_value_pair | sub_block };
                key_value_pair = key_name, "=", value;
                sub_block      = block_name, "{", block, "}";

                key_name       = identifier;
                block_name     = identifier;
                value          = matches any string of text that ends with a newline character, # or }.
                                 note that the trailing newline, # or } is not part of the value though.
                identifier     = Any string that matches the following regular expression:
                                 [a-zA-Z][a-zA-Z0-9_-\.]*
                                 i.e. Any string that starts with a letter and then is continued
                                 with any number of letters, numbers, _ . or - characters.

                Whitespace and comments are ignored.  A comment is text that starts with # (but not \#
                since the \ escapes the # so that you can have a # symbol in a value if you want) and
                ends in a new line.  You can also escape a } (e.g. "\}") if you want to have one in a
                value.

                Note that in a value the leading and trailing white spaces are stripped off but any
                white space inside the value is preserved.

                Also note that all key_names and block_names within a block syntax group must be unique
                but don't have to be globally unique.  I.e. different blocks can reuse names.

                EXAMPLE CONFIG FILES:

                    Example 1:
                        #comment.  This line is ignored because it starts with #

                        #here we have key1 which will have the value of "my value"
                        key1 = my value

                        another_key=  another value  # this is another key called "another_key" with
                                                     # a value of "another value"

                        # this key's value is the empty string.  I.e. ""
                        key2=

                    Example 2:
                        #this example illustrates the use of blocks
                        some_key = blah blah

                        # now here is a block
                        our_block
                        {
                            # here we can define some keys and values that are local to this block.
                            a_key = something
                            foo = bar
                            some_key = more stuff  # note that it is ok to name our key this even though
                                                   # there is a key called some_key above.  This is because
                                                   # we are doing so inside a different block
                        }

                        another_block { foo = bar2 }  # this block has only one key and is all on a single line
        !*/

    public:

        // exception classes
        class config_reader_error : public dlib::error
        {
            /*!
                GENERAL
                    This exception is thrown if there is an error while parsing the
                    config file.  The type member of this exception will be set
                    to ECONFIG_READER.

                INTERPRETING THIS EXCEPTION
                    - line_number == the line number the parser was at when the
                      error occurred.
                    - if (redefinition) then
                        - The key or block name on line line_number has already
                          been defined in this scope which is an error.
                    - else
                        - Some other general syntax error was detected
            !*/
        public:
            const unsigned long line_number;
            const bool redefinition;
        };

        class file_not_found : public dlib::error
        {
            /*!
                GENERAL
                    This exception is thrown if the config file can't be opened for
                    some reason.  The type member of this exception will be set
                    to ECONFIG_READER.

                INTERPRETING THIS EXCEPTION
                    - file_name == the name of the config file which we failed to open
            !*/
        public:
            const std::string file_name;
        };

        class config_reader_access_error : public dlib::error
        {
            /*!
                GENERAL
                    This exception is thrown if you try to access a key or
                    block that doesn't exist inside a config reader.  The type
                    member of this exception will be set to ECONFIG_READER.
            !*/
        public:
            config_reader_access_error(
                const std::string& block_name_,
                const std::string& key_name_
            );
            /*!
                ensures
                    - #block_name == block_name_
                    - #key_name == key_name_
            !*/

            const std::string block_name;
            const std::string key_name;
        };

    // --------------------------

        config_reader(
        );
        /*!
            ensures
                - #*this is properly initialized
                - This object will not have any keys or blocks defined in it.
            throws
                - std::bad_alloc
                - config_reader_error
        !*/

        config_reader(
            std::istream& in
        );
        /*!
            ensures
                - #*this is properly initialized
                - reads the config file to parse from the given input stream,
                  parses it and loads this object up with all the sub blocks and
                  key/value pairs it finds.
                - before the load is performed, the previous state of the config file
                  reader is erased.  So after the load the config file reader will contain
                  only information from the given config file.
                - This object will represent the top most block of the config file.
            throws
                - std::bad_alloc
                - config_reader_error
        !*/

        config_reader(
            const std::string& config_file
        );
        /*!
            ensures
                - #*this is properly initialized
                - parses the config file named by the config_file string.  Specifically,
                  parses it and loads this object up with all the sub blocks and
                  key/value pairs it finds in the file.
                - before the load is performed, the previous state of the config file
                  reader is erased.  So after the load the config file reader will contain
                  only information from the given config file.
                - This object will represent the top most block of the config file.
            throws
                - std::bad_alloc
                - config_reader_error
                - file_not_found
        !*/

        virtual ~config_reader(
        );
        /*!
            ensures
                - all memory associated with *this has been released
        !*/

        void clear(
        );
        /*!
            ensures
                - #*this has its initial value
            throws
                - std::bad_alloc
                    If this exception is thrown then *this is unusable
                    until clear() is called and succeeds
        !*/

        void load_from (
            std::istream& in
        );
        /*!
            ensures
                - reads the config file to parse from the given input stream,
                  parses it and loads this object up with all the sub blocks and
                  key/value pairs it finds.
                - before the load is performed, the previous state of the config file
                  reader is erased.  So after the load the config file reader will contain
                  only information from the given config file.
                - *this will represent the top most block of the config file contained
                  in the input stream in.
            throws
                - std::bad_alloc
                    If this exception is thrown then *this is unusable
                    until clear() is called and succeeds
                - config_reader_error
                    If this exception is thrown then this object will
                    revert to its initial value.
        !*/

        void load_from (
            const std::string& config_file
        );
        /*!
            ensures
                - parses the config file named by the config_file string.  Specifically,
                  parses it and loads this object up with all the sub blocks and
                  key/value pairs it finds in the file.
                - before the load is performed, the previous state of the config file
                  reader is erased.  So after the load the config file reader will contain
                  only information from the given config file.
                - This object will represent the top most block of the config file.
            throws
                - std::bad_alloc
                    If this exception is thrown then *this is unusable
                    until clear() is called and succeeds
                - config_reader_error
                    If this exception is thrown then this object will
                    revert to its initial value.
                - file_not_found
                    If this exception is thrown then this object will
                    revert to its initial value.
        !*/

        bool is_key_defined (
            const std::string& key_name
        ) const;
        /*!
            ensures
                - if (there is a key with the given name defined within this config_reader's block) then
                    - returns true
                - else
                    - returns false
        !*/

        bool is_block_defined (
            const std::string& block_name
        ) const;
        /*!
            ensures
                - if (there is a sub block with the given name defined within this config_reader's block) then
                    - returns true
                - else
                    - returns false
        !*/

        typedef config_reader this_type;
        const this_type& block (
            const std::string& block_name
        ) const;
        /*!
            ensures
                - if (is_block_defined(block_name) == true) then
                    - returns a const reference to the config_reader that represents the given named sub block
                - else
                    - throws config_reader_access_error
            throws
                - config_reader_access_error
                    if this exception is thrown then its block_name field will be set to the
                    given block_name string.
        !*/

        const std::string& operator[] (
            const std::string& key_name
        ) const;
        /*!
            ensures
                - if (is_key_defined(key_name) == true) then
                    - returns a const reference to the value string associated with the given key in
                      this config_reader's block.
                - else
                    - throws config_reader_access_error
            throws
                - config_reader_access_error
                    if this exception is thrown then its key_name field will be set to the
                    given key_name string.
        !*/

        template <
            typename queue_of_strings
            >
        void get_keys (
            queue_of_strings& keys
        ) const;
        /*!
            requires
                - queue_of_strings is an implementation of queue/queue_kernel_abstract.h
                  with T set to std::string, or std::vector<std::string>, or
                  dlib::std_vector_c<std::string>
            ensures
                - #keys == a collection containing all the keys defined in this config_reader's block.
                  (i.e. for all strings str in keys it is the case that is_key_defined(str) == true)
        !*/

        template <
            typename queue_of_strings
            >
        void get_blocks (
            queue_of_strings& blocks
        ) const;
        /*!
            requires
                - queue_of_strings is an implementation of queue/queue_kernel_abstract.h
                  with T set to std::string, or std::vector<std::string>, or
                  dlib::std_vector_c<std::string>
            ensures
                - #blocks == a collection containing the names of all the blocks defined in this
                  config_reader's block.
                  (i.e. for all strings str in blocks it is the case that is_block_defined(str) == true)
        !*/

    private:

        // restricted functions
        config_reader(config_reader&);        // copy constructor
        config_reader& operator=(config_reader&);    // assignment operator

    };

}

#endif // DLIB_CONFIG_READER_KERNEl_ABSTRACT_


dlib C++ Library - config_reader_thread_safe_abstract.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_CONFIG_READER_THREAD_SAFe_ABSTRACT_
#ifdef DLIB_CONFIG_READER_THREAD_SAFe_ABSTRACT_

#include <string>
#include <iosfwd>
#include "config_reader_kernel_abstract.h"
#include "../threads/threads_kernel_abstract.h"

namespace dlib
{

    class config_reader_thread_safe
    {

        /*!
            WHAT THIS EXTENSION DOES FOR config_reader
                This object extends a normal config_reader by simply wrapping all
                its member functions inside mutex locks to make it safe to use
                in a threaded program.

                So this object provides an interface identical to the one defined
                in the config_reader/config_reader_kernel_abstract.h file except that
                the rmutex returned by get_mutex() is always locked when this
                object's member functions are called.
        !*/

    public:

        const rmutex& get_mutex (
        ) const;
        /*!
            ensures
                - returns the rmutex used to make this object thread safe.  i.e. returns
                  the rmutex that is locked when this object's functions are called.
        !*/

    };

}

#endif // DLIB_CONFIG_READER_THREAD_SAFe_ABSTRACT_


dlib C++ Library - cpp_pretty_printer_kernel_abstract.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_CPP_PRETTY_PRINTER_KERNEl_ABSTRACT_
#ifdef DLIB_CPP_PRETTY_PRINTER_KERNEl_ABSTRACT_

#include <string>
#include <ioswfd>

namespace dlib
{

    class cpp_pretty_printer
    {
        /*!
            INITIAL VALUE
                This object does not have any state associated with it.

            WHAT THIS OBJECT REPRESENTS
                This object represents an HTML pretty printer for C++ source code.

        !*/

    public:

        cpp_pretty_printer (
        );
        /*!
            ensures
                - #*this is properly initialized
            throws
                - std::bad_alloc
        !*/

        virtual ~cpp_pretty_printer (
        );
        /*!
            ensures
                - any resources associated with *this have been released
        !*/

        void print (
            std::istream& in,
            std::ostream& out,
            const std::string& title
        ) const;
        /*!
            ensures
                - treats data from in as C++ source code and pretty prints it in
                  HTML and writes it to out.
                - The title of the HTML document writen to out will be title
            throws
                - std::ios_base::failure
                    If there was a problem writing to out then this exception will
                    be thrown.
                - any other exception
                    This exception may be thrown if there is any other problem.
        !*/

        void print_and_number (
            std::istream& in,
            std::ostream& out,
            const std::string& title
        ) const;
        /*!
            ensures
                - treats data from in as C++ source code and pretty prints it in
                  HTML with line numbers and writes it to out.
                - The title of the HTML document writen to out will be title
            throws
                - std::ios_base::failure
                    If there was a problem writing to out then this exception will
                    be thrown.
                - any other exception
                    This exception may be thrown if there is any other problem.
        !*/

    private:

        // restricted functions
        cpp_pretty_printer(const cpp_pretty_printer&);        // copy constructor
        cpp_pretty_printer& operator=(const cpp_pretty_printer&);    // assignment operator

    };

}

#endif // DLIB_CPP_PRETTY_PRINTER_KERNEl_ABSTRACT_


dlib C++ Library - cpp_tokenizer_kernel_abstract.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_CPP_TOKENIZER_KERNEl_ABSTRACT_
#ifdef DLIB_CPP_TOKENIZER_KERNEl_ABSTRACT_

#include <string>
#include <ioswfd>

namespace dlib
{

    class cpp_tokenizer
    {
        /*!
            INITIAL VALUE
                stream_is_set() == false

            WHAT THIS OBJECT REPRESENTS
                This object represents a simple tokenizer for C++ source code.

            BUFFERING
                This object is allowed to buffer data from the input stream.
                Thus if you clear it or switch streams (via calling set_stream())
                any buffered data will be lost.

            TOKENS
                When picking out tokens the cpp_tokenizer will always extract the
                longest token it can.  For example, if faced with the string
                "AAA" it will consider the three As to be a single IDENTIFIER
                token not three smaller IDENTIFIER tokens.

                Also note that no characters in the input stream are discarded.
                They will all be returned in the text of some token.
                Additionally, each character will never be returned more than once.
                This means that if you concatenated all returned tokens it would exactly
                reproduce the contents of the input stream.

                The tokens are defined as follows:

                END_OF_FILE
                    This token represents the end of file.  It doesn't have any
                    actual characters associated with it.

                KEYWORD
                    This token matches a C++ keyword.  (This includes the preprocessor
                    directives).

                COMMENT
                    This token matches a C++ comment.

                SINGLE_QUOTED_TEXT
                    This token matches the text of any single quoted literal.
                    For example, 'a' would be a match and the text of this token
                    would be the single character a.

                DOUBLE_QUOTED_TEXT
                    This token matches the text of any double quoted string.
                    For example, "C++" would be a match and the text of this token
                    would be the three character string C++.

                WHITE_SPACE
                    This is a multi character token.  It is defined as a sequence of
                    one or more spaces, carrage returns, newlines, and tabs.  I.e. It
                    is composed of characters from the following string " \r\n\t".

                IDENTIFIER
                    This token matches any C++ identifier that isn't matched by any
                    of the above tokens.   (A C++ identifier being a string matching
                    the regular expression [_$a-zA-Z][_$a-zA-Z0-9]*).

                NUMBER
                    This token matches any C++ numerical constant.

                OTHER
                    This matches anything that isn't part of one of the above tokens.
                    It is always a single character.
        !*/

    public:

        enum
        {
            END_OF_FILE,
            KEYWORD,
            COMMENT,
            SINGLE_QUOTED_TEXT,
            DOUBLE_QUOTED_TEXT,
            IDENTIFIER,
            OTHER,
            NUMBER,
            WHITE_SPACE
        };

        cpp_tokenizer (
        );
        /*!
            ensures
                - #*this is properly initialized
            throws
                - std::bad_alloc
        !*/

        virtual ~cpp_tokenizer (
        );
        /*!
            ensures
                - any resources associated with *this have been released
        !*/

        void clear(
        );
        /*!
            ensures
                - #*this has its initial value
            throws
                - std::bad_alloc
                    If this exception is thrown then #*this is unusable
                    until clear() is called and succeeds.
        !*/

        void set_stream (
            std::istream& in
        );
        /*!
            ensures
                - #*this will read data from in and tokenize it
                - #stream_is_set() == true
                - #get_stream() == in
        !*/

        bool stream_is_set (
        ) const;
        /*!
            ensures
                - returns true if a stream has been associated with *this by calling
                  set_stream()
        !*/

        std::istream& get_stream (
        ) const;
        /*!
            requires
                - stream_is_set() == true
            ensures
                - returns a reference to the istream object that *this is reading
                  from.
        !*/

        void get_token (
            int& type,
            std::string& token
        );
        /*!
            requires
                - stream_is_set() == true
            ensures
                - #token == the next token from the input stream get_stream()
                - #type == the type of the token in #token
            throws
                - bad_alloc
                    If this exception is thrown then the call to this function will
                    have no effect on *this but the values of #type and #token will be
                    undefined.  Additionally, some characters may have been read
                    from the stream get_stream() and lost.
        !*/

        int peek_type (
        ) const;
        /*!
            requires
                - stream_is_set() == true
            ensures
                - returns the type of the token that will be returned from
                  the next call to get_token()
            throws
                - bad_alloc
                    If this exception is thrown then the call to this function will
                    have no effect on *this.  However, some characters may have been
                    read from the stream get_stream() and lost.
        !*/

        const std::string& peek_token (
        ) const;
        /*!
            requires
                - stream_is_set() == true
            ensures
                - returns the text of the token that will be returned from
                  the next call to get_token()
            throws
                - bad_alloc
                    If this exception is thrown then the call to this function will
                    have no effect on *this.  However, some characters may have been
                    read from the stream get_stream() and lost.
        !*/

        void swap (
            cpp_tokenizer& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/

    private:

        // restricted functions
        cpp_tokenizer(const cpp_tokenizer&);        // copy constructor
        cpp_tokenizer& operator=(const cpp_tokenizer&);    // assignment operator

    };

    inline void swap (
        cpp_tokenizer& a,
        cpp_tokenizer& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

}

#endif // DLIB_CPP_TOKENIZER_KERNEl_ABSTRACT_


dlib C++ Library - tokenizer_kernel_abstract.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_TOKENIZER_KERNEl_ABSTRACT_
#ifdef DLIB_TOKENIZER_KERNEl_ABSTRACT_

#include <string>
#include <ioswfd>

namespace dlib
{

    class tokenizer
    {
        /*!
            INITIAL VALUE
                stream_is_set() == false
                get_identifier_head() == "_" + lowercase_letters() + uppercase_letters()
                get_identifier_body() == "_" + lowercase_letters() + uppercase_letters() +
                                         numbers()

            WHAT THIS OBJECT REPRESENTS
                This object represents a simple tokenizer for textual data.

            BUFFERING
                This object is allowed to buffer data from the input stream.
                Thus if you clear it or switch streams (via calling set_stream())
                any buffered data will be lost.

            TOKENS
                When picking out tokens the tokenizer will always extract the
                longest token it can.  For example, if faced with the string
                "555" it will consider the three 5s to be a single NUMBER
                token not three smaller NUMBER tokens.

                Also note that no characters in the input stream are discarded.
                They will all be returned in the text of some token.
                Additionally, each character will never be returned more than once.
                This means that if you concatenated all returned tokens it would exactly
                reproduce the contents of the input stream.

                The tokens are defined as follows:

                END_OF_LINE
                    This is a single character token and is always the '\n'
                    character.

                END_OF_FILE
                    This token represents the end of file.  It doesn't have any
                    actual characters associated with it.

                IDENTIFIER
                    This is a multi-character token.  It is defined as a string that
                    begins with a character from get_identifier_head() and is
                    followed by any number of characters from get_identifier_body().

                NUMBER
                    This is a multi-character token.  It is defined as a sequence of
                    numbers.

                WHITE_SPACE
                    This is a multi character token.  It is defined as a sequence of
                    one or more spaces, carrage returns, and tabs.  I.e. It is
                    composed of characters from the following string " \r\t".

                CHAR
                    This is a single character token.  It matches anything that isn't
                    part of one of the above tokens.
        !*/

    public:

        enum
        {
            END_OF_LINE,
            END_OF_FILE,
            IDENTIFIER,
            CHAR,
            NUMBER,
            WHITE_SPACE
        };

        tokenizer (
        );
        /*!
            ensures
                - #*this is properly initialized
            throws
                - std::bad_alloc
        !*/

        virtual ~tokenizer (
        );
        /*!
            ensures
                - any resources associated with *this have been released
        !*/

        void clear(
        );
        /*!
            ensures
                - #*this has its initial value
            throws
                - std::bad_alloc
                    If this exception is thrown then #*this is unusable
                    until clear() is called and succeeds.
        !*/

        void set_stream (
            std::istream& in
        );
        /*!
            ensures
                - #*this will read data from in and tokenize it
                - #stream_is_set() == true
                - #get_stream() == in
        !*/

        bool stream_is_set (
        ) const;
        /*!
            ensures
                - returns true if a stream has been associated with *this by calling
                  set_stream()
        !*/

        std::istream& get_stream (
        ) const;
        /*!
            requires
                - stream_is_set() == true
            ensures
                - returns a reference to the istream object that *this is reading
                  from.
        !*/

        void get_token (
            int& type,
            std::string& token
        );
        /*!
            requires
                - stream_is_set() == true
            ensures
                - #token == the next token from the input stream get_stream()
                - #type == the type of the token in #token
            throws
                - bad_alloc
                    If this exception is thrown then the call to this function will
                    have no effect on *this but the values of #type and #token will be
                    undefined.  Additionally, some characters may have been read
                    from the stream get_stream() and lost.
        !*/

        int peek_type (
        ) const;
        /*!
            requires
                - stream_is_set() == true
            ensures
                - returns the type of the token that will be returned from
                  the next call to get_token()
            throws
                - bad_alloc
                    If this exception is thrown then the call to this function will
                    have no effect on *this.  However, some characters may have been
                    read from the stream get_stream() and lost.
        !*/

        const std::string& peek_token (
        ) const;
        /*!
            requires
                - stream_is_set() == true
            ensures
                - returns the text of the token that will be returned from
                  the next call to get_token()
            throws
                - bad_alloc
                    If this exception is thrown then the call to this function will
                    have no effect on *this.  However, some characters may have been
                    read from the stream get_stream() and lost.
        !*/

        void set_identifier_token (
            const std::string& head,
            const std::string& body
        );
        /*!
            requires
                - head.find_first_of(" \r\t\n0123456789") == std::string::npos
                  (i.e. head doesn't contain any characters from the string
                  " \r\t\n0123456789").
                - body.find_frst_of(" \r\t\n") == std::string::npos
                  (i.e. body doesn't contain any characters from the string " \r\t\n").
            ensures
                - #get_identifier_head() == head
                - #get_identifier_body() == body
            throws
                - std::bad_alloc
                    If this exception is thrown then #*this is unusable
                    until clear() is called and succeeds.
        !*/

        const std::string get_identifier_head (
        ) const;
        /*!
            ensures
                - returns a string containing the characters that can be the start
                  of an IDENTIFIER token.
            throws
                - std::bad_alloc
                    If this exception is thrown then the call to this function
                    has no effect.
        !*/

        const std::string get_identifier_body (
        ) const;
        /*!
            ensures
                - returns a string containing the characters that can appear in the
                  body of an IDENTIFIER token.
            throws
                - std::bad_alloc
                    If this exception is thrown then the call to this function
                    has no effect.
        !*/

        const std::string lowercase_letters (
        ) const;
        /*!
            ensures
                - returns "abcdefghijklmnopqrstuvwxyz"
            throws
                - std::bad_alloc
                    If this exception is thrown then the call to this function
                    has no effect.
        !*/

        const std::string uppercase_letters (
        ) const;
        /*!
            ensures
                - returns "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
            throws
                - std::bad_alloc
                    If this exception is thrown then the call to this function
                    has no effect.
        !*/

        const std::string numbers (
        ) const;
        /*!
            ensures
                - returns "0123456789"
            throws
                - std::bad_alloc
                    If this exception is thrown then the call to this function
                    has no effect.
        !*/

        void swap (
            tokenizer& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/

    private:

        // restricted functions
        tokenizer(const tokenizer&);        // copy constructor
        tokenizer& operator=(const tokenizer&);    // assignment operator

    };

    inline void swap (
        tokenizer& a,
        tokenizer& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

}

#endif // DLIB_TOKENIZER_KERNEl_ABSTRACT_


dlib C++ Library - xml_parser_kernel_abstract.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_XML_PARSER_KERNEl_ABSTRACT_
#ifdef DLIB_XML_PARSER_KERNEl_ABSTRACT_

#include <string>
#include <iosfwd>
#include "xml_parser_kernel_interfaces.h"

namespace dlib
{

    class xml_parser
    {

        /*!
            INITIAL VALUE
                no objects are registered to receive events

            WHAT THIS OBJECT REPRESENTS
                This object represents a simple SAX style event driven XML parser.
                It takes its input from an input stream object and sends events to all
                registered document_handler and error_handler objects.

                note that this xml parser ignores all DTD related XML markup.  It will
                parse XML documents with DTD's but it just won't check if the document
                is valid.  This also means that entity references may not be used except
                for the predefined ones which are as follows:
                    &amp;
                    &lt;
                    &gt;
                    &apos;
                    &quot;

                also note that there is no interpreting of entity references inside
                a CDATA section or inside of tags, they are only interpreted inside
                normal non-markup data.

                This parser considers the end of the xml document to be the closing
                tag of the root tag (as opposed to using EOF as the end of the
                document).  This is a deviation from the xml standard.

                Aside from ignoring DTD stuff and entity references everywhere but
                data, and the above comment regarding EOF, this parser should conform
                to the rest of the XML standard.
        !*/

        public:

            xml_parser(
            );
            /*!
                ensures
                    - #*this is properly initialized
                throws
                    - std::bad_alloc
            !*/

            virtual ~xml_parser(
            );
            /*!
                ensures
                    - all memory associated with *this has been released
            !*/

            void clear(
            );
            /*!
                ensures
                    - #*this has its initial value
                throws
                    - std::bad_alloc
                        if this exception is thrown then *this is unusable
                        until clear() is called and succeeds
            !*/

            void parse (
                std::istream& in
            );
            /*!
                requires
                    - in.fail() == false
                ensures
                    - the data from the input stream in will be parsed and the appropriate
                      events will be generated
                    - parsing will stop when the parser has reached the closing tag
                      for the xml document or EOF (which ever comes first). Note that
                      hitting EOF first is a fatal error.
                throws
                    - std::bad_alloc
                        if parse() throws then it will be unusable until clear() is
                        called and succeeds
                    - other exceptions
                        document_handlers and error_handlers my throw any exception.  If
                        they throw while parse() is running then parse() will let the
                        exception propagate out and the xml_parser object will be unusable
                        until clear() is called and succeeds.    note that end_document()
                        is still called.
            !*/

            void add_document_handler (
                document_handler& item
            );
            /*!
                ensures
                    - item will now receive document events from the parser
                throws
                    - std::bad_alloc
                        if add_document_handler() throws then it has no effect
            !*/

            void add_error_handler (
                error_handler& item
            );
            /*!
                ensures
                    - item will now receive error events from the parser
                throws
                    - std::bad_alloc
                        if add_error_handler() throws then it has no effect
            !*/

            void swap (
                xml_parser& item
            );
            /*!
                ensures
                    - swaps *this and item
            !*/

        private:

            // restricted functions
            xml_parser(xml_parser&);        // copy constructor
            xml_parser& operator=(xml_parser&);    // assignment operator

    };

    inline void swap (
        xml_parser& a,
        xml_parser& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class xml_parse_error : public error
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is the exception object thrown by the parse_xml() routines defined
                below.
        !*/
    };

// ----------------------------------------------------------------------------------------

    void parse_xml (
        std::istream& in,
        document_handler& dh,
        error_handler& eh
    );
    /*!
        ensures
            - makes an xml_parser and tells it to parse the given input stream using the
              supplied document_handler and error_handler.
    !*/

    void parse_xml (
        std::istream& in,
        error_handler& eh,
        document_handler& dh
    )
    /*!
        ensures
            - makes an xml_parser and tells it to parse the given input stream using the
              supplied document_handler and error_handler.
    !*/

    void parse_xml (
        std::istream& in,
        error_handler& eh
    );
    /*!
        ensures
            - makes an xml_parser and tells it to parse the given input stream using the
              supplied error_handler.
    !*/

    void parse_xml (
        std::istream& in,
        document_handler& dh
    );
    /*!
        ensures
            - makes an xml_parser and tells it to parse the given input stream using the
              supplied document_handler.
            - Uses a default error handler that will throw an xml_parse_error exception
              if a fatal parsing error is encountered.
        throws
            - xml_parse_error
                Thrown if a fatal parsing error is encountered.
    !*/

// ----------------------------------------------------------------------------------------

    void parse_xml (
        const std::string& filename,
        document_handler& dh,
        error_handler& eh
    );
    /*!
        ensures
            - makes an xml_parser and tells it to parse the given input file using the
              supplied error_handler and document_handler.
        throws
            - xml_parse_error
                Thrown if there is a problem parsing the input file.
    !*/

    void parse_xml (
        const std::string& filename,
        error_handler& eh,
        document_handler& dh
    );
    /*!
        ensures
            - makes an xml_parser and tells it to parse the given input file using the
              supplied error_handler and document_handler.
        throws
            - xml_parse_error
                Thrown if there is a problem parsing the input file.
    !*/

    void parse_xml (
        const std::string& filename,
        error_handler& eh
    );
    /*!
        ensures
            - makes an xml_parser and tells it to parse the given input file using the
              supplied error_handler.
        throws
            - xml_parse_error
                Thrown if there is a problem parsing the input file.
    !*/

    void parse_xml (
        const std::string& filename,
        document_handler& dh
    );
    /*!
        ensures
            - makes an xml_parser and tells it to parse the given input file using the
              supplied document_handler.
            - Uses a default error handler that will throw an xml_parse_error exception
              if a fatal parsing error is encountered.
        throws
            - xml_parse_error
                Thrown if there is a problem parsing the input file.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_XML_PARSER_KERNEl_ABSTRACT_


dlib C++ Library - string_abstract.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_STRINg_ABSTRACT_
#ifdef DLIB_STRINg_ABSTRACT_

#include <string>
#include <iostream>
#include <vector>
#include "../error.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class string_cast_error : public error
    {
    public:
        string_cast_error():error(ECAST_TO_STRING) {}
    };

    template <
        typename T,
        typename charT,
        typename traits,
        typename alloc
        >
    const T string_cast (
        const std::basic_string<charT,traits,alloc>& str
    );
    /*!
        requires
            - T is not a pointer type
        ensures
            - returns str converted to T
        throws
            - string_cast_error
                This exception is thrown if string_cast() is unable to convert
                str into a T.  Also, string_cast_error::info == str
    !*/

// ----------------------------------------------------------------------------------------

    class string_assign
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is a simple tool which provides an alternative syntax for using
                the string_cast() function.  It can be understood by considering
                the following example:

                    string_assign sa;
                    int val;
                    double dval;

                    val  = sa = "1234";   // executes: val = string_cast<int>("1234");
                    dval = sa = "3.141";  // executes: val = string_cast<double>("3.141");

                After executing, val will be equal to 1234 and dval will be 3.141.
                Note that you can use string_assign to assign to any type which you could
                use with string_cast(), except for std::basic_string, assigning to this
                type is ambiguous for boring technical reasons.  But there isn't much
                point in using this tool to assign from one string to another so it doesn't
                matter.

                Additionally, note that there is a global instance of this object, dlib::sa.
                So you never have to create a string_assign object yourself.  Finally, this
                object is totally stateless and threadsafe.
        !*/
    };

    const string_assign sa = string_assign();

// ----------------------------------------------------------------------------------------

    class cast_to_string_error : public error
    {
    public:
        cast_to_string_error():error(ECAST_TO_STRING) {}
    };

    template <
        typename T
        >
    const std::string cast_to_string (
        const T& item
    );
    /*!
        requires
            - T is not a pointer type
        ensures
            - returns item converted to std::string
        throws
            - cast_to_string_error
                This exception is thrown if cast_to_string() is unable to convert
                item into a std::string.
    !*/

    template <
        typename T
        >
    const std::wstring cast_to_wstring (
        const T& item
    );
    /*!
        requires
            - T is not a pointer type
        ensures
            - returns item converted to std::wstring
        throws
            - cast_to_string_error
                This exception is thrown if cast_to_string() is unable to convert
                item into a std::string.
    !*/

// ----------------------------------------------------------------------------------------

    std::string pad_int_with_zeros (
        int i,
        unsigned long width = 6
    );
    /*!
        ensures
            - converts i into a string of at least width characters in length.  If
              necessary, the string will be padded with leading zeros to get
              to width characters.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    const std::string narrow (
        const std::basic_string<charT,traits,alloc>& str
    );
    /*!
        ensures
            - returns str as a std::string by converting every character in it to a char.
              Note that any characters that do not have a mapping to type char will be
              converted to a space.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    const std::basic_string<charT,traits,alloc> wrap_string (
        const std::basic_string<charT,traits,alloc>& str,
        const unsigned long first_pad = 0,
        const unsigned long rest_pad = 0,
        const unsigned long max_per_line = 79
    );
    /*!
        requires
            - first_pad < max_per_line
            - rest_pad < max_per_line
            - rest_pad >= first_pad
        ensures
            - returns a copy of str S such that:
                - S is broken up into lines separated by the \n character.
                - The first line starts with first_pad space characters.
                - The second and all subsequent lines start with rest_pad space characters.
                - The first line is no longer than max_per_line - (rest_pad-first_pad) characters.
                - The second and all subsequent lines are no longer than max_per_line characters.
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename traits
        typename alloc
        >
    const std::basic_string<char,traits,alloc> tolower (
        const std::basic_string<char,traits,alloc>& str
    );
    /*!
        ensures
            - returns a copy of str S such that:
                - #S.size() == str.size()
                - #S[i] == std::tolower(str[i])
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename traits,
        typename alloc
        >
    const std::basic_string<char,traits,alloc> toupper (
        const std::basic_string<char,traits,alloc>& str
    );
    /*!
        ensures
            - returns a copy of str S such that:
                - #S.size() == str.size()
                - #S[i] == std::toupper(str[i])
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename traits,
        typename alloc
        >
    bool strings_equal_ignore_case (
        const std::basic_string<char,traits,alloc>& str1,
        const std::basic_string<char,traits,alloc>& str2
    );
    /*!
        ensures
            - returns tolower(str1) == tolower(str2)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename traits,
        typename alloc
        >
    bool strings_equal_ignore_case (
        const std::basic_string<char,traits,alloc>& str1,
        const std::basic_string<char,traits,alloc>& str2,
        unsigned long num
    );
    /*!
        ensures
            - returns tolower(str1.substr(0,num)) == tolower(str2.substr(0,num))
              (i.e. only compares the first num characters)
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    const std::basic_string<charT,traits,alloc> ltrim (
        const std::basic_string<charT,traits,alloc>& str,
        const std::basic_string<charT,traits,alloc>& trim_chars
    );
    /*!
        ensures
            - returns a copy of str with any leading trim_chars
              from the left side of the string removed.
    !*/

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    const std::basic_string<charT,traits,alloc> ltrim (
        const std::basic_string<charT,traits,alloc>& str,
        const charT* trim_chars = _dT(charT," \t\r\n")
    );
    /*!
        requires
            - trim_chars == a valid null-terminated C string
        ensures
            - returns ltrim(str, std::basic_string<charT,traits,alloc>(trim_chars))
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    const std::basic_string<charT,traits,alloc> rtrim (
        const std::basic_string<charT,traits,alloc>& str,
        const std::basic_string<charT,traits,alloc>& trim_chars
    );
    /*!
        ensures
            - returns a copy of str with any trailing trim_chars
              from the right side of the string removed.
    !*/

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    const std::basic_string<charT,traits,alloc> rtrim (
        const std::basic_string<charT,traits,alloc>& str,
        const charT* trim_chars = _dT(charT," \t\r\n")
    );
    /*!
        requires
            - trim_chars == a valid null-terminated C string
        ensures
            - returns rtrim(str, std::basic_string<charT,traits,alloc>(trim_chars))
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    const std::basic_string<charT,traits,alloc> trim (
        const std::basic_string<charT,traits,alloc>& str,
        const std::basic_string<charT,traits,alloc>& trim_chars
    );
    /*!
        ensures
            - returns a copy of str with any leading or trailing trim_chars
              from the ends of the string removed.
    !*/

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    const std::basic_string<charT,traits,alloc> trim (
        const std::basic_string<charT,traits,alloc>& str,
        const charT* trim_chars = _dT(charT," \t\r\n")
    );
    /*!
        requires
            - trim_chars == a valid null-terminated C string
        ensures
            - returns trim(str, std::basic_string<charT,traits,alloc>(trim_chars))
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    const std::basic_string<charT,traits,alloc> rpad (
        const std::basic_string<charT,traits,alloc>& str,
        long pad_length,
        const std::basic_string<charT,traits,alloc>& pad_string
    );
    /*!
        ensures
            - if (pad_length <= str.size()) then
                - returns str
            - else
                - let P be a string defined as follows:
                    - P.size() == pad_length - str.size()
                    - P == (pad_string + pad_string + ... + pad_string).substr(0,pad_length - str.size())
                      (i.e. P == a string with the above specified size that contains just
                      repitions of the pad_string)
                - returns the string str + P
    !*/

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    const std::basic_string<charT,traits,alloc> rpad (
        const std::basic_string<charT,traits,alloc>& str,
        long pad_length,
        const charT* pad_string = _dT(charT," ")
    );
    /*!
        requires
            - pad_string == a valid null-terminated C string
        ensures
            - returns rpad(str, pad_length, std::basic_string<charT,traits,alloc>(pad_string))
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    const std::basic_string<charT,traits,alloc> lpad (
        const std::basic_string<charT,traits,alloc>& str,
        long pad_length,
        const std::basic_string<charT,traits,alloc>& pad_string
    );
    /*!
        ensures
            - if (pad_length <= str.size()) then
                - returns str
            - else
                - let P be a string defined as follows:
                    - P.size() == pad_length - str.size()
                    - P == (pad_string + pad_string + ... + pad_string).substr(0,pad_length - str.size())
                      (i.e. P == a string with the above specified size that contains just
                      repitions of the pad_string)
                - returns the string P + str
    !*/

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    const std::basic_string<charT,traits,alloc> lpad (
        const std::basic_string<charT,traits,alloc>& str,
        long pad_length,
        const charT* pad_string = _dT(charT," ")
    );
    /*!
        requires
            - pad_string == a valid null-terminated C string
        ensures
            - returns lpad(str, pad_length, std::basic_string<charT,traits,alloc>(pad_string))
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    const std::basic_string<charT,traits,alloc> pad (
        const std::basic_string<charT,traits,alloc>& str,
        long pad_length,
        const std::basic_string<charT,traits,alloc>& pad_string
    );
    /*!
        ensures
            - let str_size == static_cast<long>(str.size())
            - returns rpad( lpad(str, (pad_length-str_size)/2 + str_size, pad_string),
                            pad_length,
                            pad_string);
    !*/

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    const std::basic_string<charT,traits,alloc> pad (
        const std::basic_string<charT,traits,alloc>& str,
        long pad_length,
        const charT* pad_string = _dT(charT," ")
    );
    /*!
        requires
            - pad_string == a valid null-terminated C string
        ensures
            - returns pad(str, pad_length, std::basic_string<charT,traits,alloc>(pad_string))
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    const std::basic_string<charT,traits,alloc> left_substr (
        const std::basic_string<charT,traits,alloc>& str,
        const std::basic_string<charT,traits,alloc>& delim
    );
    /*!
        ensures
            - let delim_pos = str.find_first_of(delim)
            - returns str.substr(0,delim_pos)
    !*/

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    const std::basic_string<charT,traits,alloc> left_substr (
        const std::basic_string<charT,traits,alloc>& str,
        const charT* delim = _dT(charT," \n\r\t")
    );
    /*!
        requires
            - delim == a valid null-terminated C string
        ensures
            - returns left_substr(str, std::basic_string<charT,traits,alloc>(delim))
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    const std::basic_string<charT,traits,alloc> right_substr (
        const std::basic_string<charT,traits,alloc>& str,
        const std::basic_string<charT,traits,alloc>& delim
    );
    /*!
        ensures
            - let delim_pos = str.find_last_of(delim)
            - if (delim_pos == std::string::npos) then
                - returns ""
            - else
                - returns str.substr(delim_pos+1)
    !*/

    template <
        typename charT,
        typename traits
        typename alloc
        >
    const std::basic_string<charT,traits,alloc> right_substr (
        const std::basic_string<charT,traits,alloc>& str,
        const charT* delim = _dT(charT," \n\r\t")
    );
    /*!
        requires
            - delim == a valid null-terminated C string
        ensures
            - returns right_substr(str, std::basic_string<charT,traits,alloc>(delim))
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    std::pair<std::basic_string<charT,traits,alloc>, std::basic_string<charT,traits,alloc> >
    split_on_first (
        const std::basic_string<charT,traits,alloc>& str,
        const charT* delim = _dT(charT, " \n\r\t")
    );
    /*!
        ensures
            - This function splits string into two parts, the split is based on the first
              occurrence of any character from delim.
            - let delim_pos = str.find_first_of(delim)
            - if (delim_pos == std::string::npos) then
                - returns make_pair(str,"")
            - else
                - return make_pair(str.substr(0, delim_pos), str.substr(delim_pos+1));
    !*/

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    std::pair<std::basic_string<charT,traits,alloc>, std::basic_string<charT,traits,alloc> >
    split_on_first (
        const std::basic_string<charT,traits,alloc>& str,
        const std::basic_string<charT,traits,alloc>& delim
    );
    /*!
        requires
            - delim == a valid null-terminated C string
        ensures
            - returns split_on_first(str, delim.c_str())
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    std::pair<std::basic_string<charT,traits,alloc>, std::basic_string<charT,traits,alloc> >
    split_on_last (
        const std::basic_string<charT,traits,alloc>& str,
        const charT* delim = _dT(charT, " \n\r\t")
    );
    /*!
        ensures
            - This function splits string into two parts, the split is based on the last
              occurrence of any character from delim.
            - let delim_pos = str.find_last_of(delim)
            - if (delim_pos == std::string::npos) then
                - returns make_pair(str,"")
            - else
                - return make_pair(str.substr(0, delim_pos), str.substr(delim_pos+1));
    !*/

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    std::pair<std::basic_string<charT,traits,alloc>, std::basic_string<charT,traits,alloc> >
    split_on_last (
        const std::basic_string<charT,traits,alloc>& str,
        const std::basic_string<charT,traits,alloc>& delim
    );
    /*!
        requires
            - delim == a valid null-terminated C string
        ensures
            - returns split_on_last(str, delim.c_str())
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    const std::vector<std::basic_string<charT,traits,alloc> > split (
        const std::basic_string<charT,traits,alloc>& str,
        const std::basic_string<charT,traits,alloc>& delim
    );
    /*!
        ensures
            - Breaks the given string str into a sequence of substrings delimited
              by characters in delim and returns the results.
            - returns a vector V such that:
                - V.size() == the number of substrings found in str.
                - for all i: V[i] == The ith substring.  Note that it will not contain
                  any delimiter characters (i.e. characters in delim).  It will also
                  never be an empty string.
                - V contains the substrings in the order in which they appear in str.
                  That is, V[0] contains the first substring, V[1] the second, and
                  so on.
    !*/

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    const std::vector<std::basic_string<charT,traits,alloc> > split (
        const std::basic_string<charT,traits,alloc>& str,
        const charT* delim = _dT(charT," \n\r\t")
    );
    /*!
        requires
            - trim_chars == a valid null-terminated C string
        ensures
            - returns split(str, std::basic_string<charT,traits,alloc>(delim))
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_STRINg_ABSTRACT_


dlib C++ Library - 3d_point_cloud_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example illustrating the use of the perspective_window tool
    in the dlib C++ Library.  It is a simple tool for displaying 3D point
    clouds on the screen.

*/

#include <dlib/gui_widgets.h>
#include <dlib/image_transforms.h>
#include <cmath>

using namespace dlib;
using namespace std;

// ----------------------------------------------------------------------------------------

int main()
{
    // Let's make a point cloud that looks like a 3D spiral.
    std::vector<perspective_window::overlay_dot> points;
    dlib::rand rnd;
    for (double i = 0; i < 20; i+=0.001)
    {
        // Get a point on a spiral
        dlib::vector<double> val(sin(i),cos(i),i/4);

        // Now add some random noise to it
        dlib::vector<double> temp(rnd.get_random_gaussian(),
                                  rnd.get_random_gaussian(),
                                  rnd.get_random_gaussian());
        val += temp/20;

        // Pick a color based on how far we are along the spiral
        rgb_pixel color = colormap_jet(i,0,20);

        // And add the point to the list of points we will display
        points.push_back(perspective_window::overlay_dot(val, color));
    }

    // Now finally display the point cloud.
    perspective_window win;
    win.set_title("perspective_window 3D point cloud");
    win.add_overlay(points);
    win.wait_until_closed();
}

//  ----------------------------------------------------------------------------


dlib C++ Library - assignment_learning_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example illustrating the use of the dlib machine learning tools for
    learning to solve the assignment problem.

    Many tasks in computer vision or natural language processing can be thought of
    as assignment problems.  For example, in a computer vision application where
    you are trying to track objects moving around in video, you likely need to solve
    an association problem every time you get a new video frame.  That is, each new
    frame will contain objects (e.g. people, cars, etc.) and you will want to
    determine which of these objects are actually things you have seen in previous
    frames.

    The assignment problem can be optimally solved using the well known Hungarian
    algorithm.  However, this algorithm requires the user to supply some function
    which measures the "goodness" of an individual association.  In many cases the
    best way to measure this goodness isn't obvious and therefore machine learning
    methods are used.

    The remainder of this example will show you how to learn a goodness function
    which is optimal, in a certain sense, for use with the Hungarian algorithm.  To
    do this, we will make a simple dataset of example associations and use them to
    train a supervised machine learning method.

    Finally, note that there is a whole example program dedicated to assignment
    learning problems where you are trying to make an object tracker.  So if that is
    what you are interested in then take a look at the learning_to_track_ex.cpp
    example program.
*/

#include <iostream>
#include <dlib/svm_threaded.h>

using namespace std;
using namespace dlib;

// ----------------------------------------------------------------------------------------

/*
    In an association problem, we will talk about the "Left Hand Set" (LHS) and the
    "Right Hand Set" (RHS).  The task will be to learn to map all elements of LHS to
    unique elements of RHS.  If an element of LHS can't be mapped to a unique element of
    RHS for some reason (e.g. LHS is bigger than RHS) then it can also be mapped to the
    special -1 output, indicating no mapping to RHS.

    So the first step is to define the type of elements in each of these sets.  In the
    code below we will use column vectors in both LHS and RHS.  However, in general,
    they can each contain any type you like.  LHS can even contain a different type
    than RHS.
*/

typedef dlib::matrix<double,0,1> column_vector;

// This type represents a pair of LHS and RHS.  That is, sample_type::first
// contains a left hand set and sample_type::second contains a right hand set.
typedef std::pair<std::vector<column_vector>, std::vector<column_vector> > sample_type;

// This type will contain the association information between LHS and RHS.  That is,
// it will determine which elements of LHS map to which elements of RHS.
typedef std::vector<long> label_type;

// In this example, all our LHS and RHS elements will be 3-dimensional vectors.
const unsigned long num_dims = 3;

void make_data (
    std::vector<sample_type>& samples,
    std::vector<label_type>& labels
);
/*!
    ensures
        - This function creates a training dataset of 5 example associations.
        - #samples.size() == 5
        - #labels.size() == 5
        - for all valid i:
            - #samples[i].first == a left hand set
            - #samples[i].second == a right hand set
            - #labels[i] == a set of integers indicating how to map LHS to RHS.  To be
              precise:
                - #samples[i].first.size() == #labels[i].size()
                - for all valid j:
                    -1 <= #labels[i][j] < #samples[i].second.size()
                    (A value of -1 indicates that #samples[i].first[j] isn't associated with anything.
                    All other values indicate the associating element of #samples[i].second)
                - All elements of #labels[i] which are not equal to -1 are unique.  That is,
                  multiple elements of #samples[i].first can't associate to the same element
                  in #samples[i].second.
!*/

// ----------------------------------------------------------------------------------------

struct feature_extractor
{
    /*!
        Recall that our task is to learn the "goodness of assignment" function for
        use with the Hungarian algorithm.  The dlib tools assume this function
        can be written as:
            match_score(l,r) == dot(w, PSI(l,r)) + bias
        where l is an element of LHS, r is an element of RHS, w is a parameter vector,
        bias is a scalar value, and PSI() is a user supplied feature extractor.

        This feature_extractor is where we implement PSI().  How you implement this
        is highly problem dependent.
    !*/

    // The type of feature vector returned from get_features().  This must be either
    // a dlib::matrix or a sparse vector.
    typedef column_vector feature_vector_type;

    // The types of elements in the LHS and RHS sets
    typedef column_vector lhs_element;
    typedef column_vector rhs_element;

    unsigned long num_features() const
    {
        // Return the dimensionality of feature vectors produced by get_features()
        return num_dims;
    }

    void get_features (
        const lhs_element& left,
        const rhs_element& right,
        feature_vector_type& feats
    ) const
    /*!
        ensures
            - #feats == PSI(left,right)
              (i.e. This function computes a feature vector which, in some sense,
              captures information useful for deciding if matching left to right
              is "good").
    !*/
    {
        // Let's just use the squared difference between each vector as our features.
        // However, it should be emphasized that how to compute the features here is very
        // problem dependent.
        feats = squared(left - right);
    }

};

// We need to define serialize() and deserialize() for our feature extractor if we want
// to be able to serialize and deserialize our learned models.  In this case the
// implementation is empty since our feature_extractor doesn't have any state.  But you
// might define more complex feature extractors which have state that needs to be saved.
void serialize   (const feature_extractor& , std::ostream& ) {}
void deserialize (feature_extractor&       , std::istream& ) {}

// ----------------------------------------------------------------------------------------

int main()
{
    try
    {
        // Get a small bit of training data.
        std::vector<sample_type> samples;
        std::vector<label_type> labels;
        make_data(samples, labels);

        structural_assignment_trainer<feature_extractor> trainer;
        // This is the common SVM C parameter.  Larger values encourage the
        // trainer to attempt to fit the data exactly but might overfit.
        // In general, you determine this parameter by cross-validation.
        trainer.set_c(10);
        // This trainer can use multiple CPU cores to speed up the training.
        // So set this to the number of available CPU cores.
        trainer.set_num_threads(4);

        // Do the training and save the results in assigner.
        assignment_function<feature_extractor> assigner = trainer.train(samples, labels);

        // Test the assigner on our data.  The output will indicate that it makes the
        // correct associations on all samples.
        cout << "Test the learned assignment function: " << endl;
        for (unsigned long i = 0; i < samples.size(); ++i)
        {
            // Predict the assignments for the LHS and RHS in samples[i].
            std::vector<long> predicted_assignments = assigner(samples[i]);
            cout << "true labels:      " << trans(mat(labels[i]));
            cout << "predicted labels: " << trans(mat(predicted_assignments)) << endl;
        }

        // We can also use this tool to compute the percentage of assignments predicted correctly.
        cout << "training accuracy: " << test_assignment_function(assigner, samples, labels) << endl;

        // Since testing on your training data is a really bad idea, we can also do 5-fold cross validation.
        // Happily, this also indicates that all associations were made correctly.
        randomize_samples(samples, labels);
        cout << "cv accuracy:       " << cross_validate_assignment_trainer(trainer, samples, labels, 5) << endl;

        // Finally, the assigner can be serialized to disk just like most dlib objects.
        serialize("assigner.dat") << assigner;

        // recall from disk
        deserialize("assigner.dat") >> assigner;
    }
    catch (std::exception& e)
    {
        cout << "EXCEPTION THROWN" << endl;
        cout << e.what() << endl;
    }
}

// ----------------------------------------------------------------------------------------

void make_data (
    std::vector<sample_type>& samples,
    std::vector<label_type>& labels
)
{
    // Make four different vectors.  We will use them to make example assignments.
    column_vector A(num_dims), B(num_dims), C(num_dims), D(num_dims);
    A = 1,0,0;
    B = 0,1,0;
    C = 0,0,1;
    D = 0,1,1;

    std::vector<column_vector> lhs;
    std::vector<column_vector> rhs;
    label_type mapping;

    // In all the assignments to follow, we will only say an element of the LHS
    // matches an element of the RHS if the two are equal.  So A matches with A,
    // B with B, etc.  But never A with C, for example.
    // ------------------------

    lhs.resize(3);
    lhs[0] = A;
    lhs[1] = B;
    lhs[2] = C;

    rhs.resize(3);
    rhs[0] = B;
    rhs[1] = A;
    rhs[2] = C;

    mapping.resize(3);
    mapping[0] = 1;  // lhs[0] matches rhs[1]
    mapping[1] = 0;  // lhs[1] matches rhs[0]
    mapping[2] = 2;  // lhs[2] matches rhs[2]

    samples.push_back(make_pair(lhs,rhs));
    labels.push_back(mapping);

    // ------------------------

    lhs[0] = C;
    lhs[1] = A;
    lhs[2] = B;

    rhs[0] = A;
    rhs[1] = B;
    rhs[2] = D;

    mapping[0] = -1;  // The -1 indicates that lhs[0] doesn't match anything in rhs.
    mapping[1] = 0;   // lhs[1] matches rhs[0]
    mapping[2] = 1;   // lhs[2] matches rhs[1]

    samples.push_back(make_pair(lhs,rhs));
    labels.push_back(mapping);

    // ------------------------

    lhs[0] = A;
    lhs[1] = B;
    lhs[2] = C;

    rhs.resize(4);
    rhs[0] = C;
    rhs[1] = B;
    rhs[2] = A;
    rhs[3] = D;

    mapping[0] = 2;
    mapping[1] = 1;
    mapping[2] = 0;

    samples.push_back(make_pair(lhs,rhs));
    labels.push_back(mapping);

    // ------------------------

    lhs.resize(2);
    lhs[0] = B;
    lhs[1] = C;

    rhs.resize(3);
    rhs[0] = C;
    rhs[1] = A;
    rhs[2] = D;

    mapping.resize(2);
    mapping[0] = -1;
    mapping[1] = 0;

    samples.push_back(make_pair(lhs,rhs));
    labels.push_back(mapping);

    // ------------------------

    lhs.resize(3);
    lhs[0] = D;
    lhs[1] = B;
    lhs[2] = C;

    // rhs will be empty.  So none of the items in lhs can match anything.
    rhs.resize(0);

    mapping.resize(3);
    mapping[0] = -1;
    mapping[1] = -1;
    mapping[2] = -1;

    samples.push_back(make_pair(lhs,rhs));
    labels.push_back(mapping);

}


dlib C++ Library - file_to_code_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*
    This is an example illustrating the use of the compress_stream and
    base64 components from the dlib C++ Library.

    It reads in a file from the disk and compresses it in an in memory buffer and
    then converts that buffer into base64 text.  The final step is to output to
    the screen some C++ code that contains this base64 encoded text and can decompress
    it back into its original form.
*/

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <cstdlib>
#include <dlib/compress_stream.h>
#include <dlib/base64.h>

using namespace std;
using namespace dlib;

int main(int argc, char** argv)
{
    if (argc != 2)
    {
        cout << "You must give a file name as the argument to this program.\n" << endl;
        cout << "This program reads in a file from the disk and compresses\n"
             << "it in an in memory buffer and then converts that buffer \n"
             << "into base64 text.  The final step is to output to the screen\n"
             << "some C++ code that contains this base64 encoded text and can\n"
             << "decompress it back into its original form.\n" << endl;

        return EXIT_FAILURE;
    }

    // open the file the user specified on the command line
    ifstream fin(argv[1], ios::binary);
    if (!fin) {
        cout << "can't open file " << argv[1] << endl;
        return EXIT_FAILURE;
    }

    ostringstream sout;
    istringstream sin;

    // this is the object we will use to do the base64 encoding
    base64 base64_coder;
    // this is the object we will use to do the data compression
    compress_stream::kernel_1ea compressor;

    // compress the contents of the file and store the results in the string stream sout
    compressor.compress(fin,sout);
    sin.str(sout.str());
    sout.clear();
    sout.str("");

    // now base64 encode the compressed data
    base64_coder.encode(sin,sout);

    sin.clear();
    sin.str(sout.str());
    sout.str("");

    // the following is a little funny looking but all it does is output some C++ code
    // that contains the compressed/base64 data and the C++ code that can decode it back
    // into its original form.
    sout << "#include <sstream>\n";
    sout << "#include <dlib/compress_stream.h>\n";
    sout << "#include <dlib/base64.h>\n";
    sout << "\n";
    sout << "// This function returns the contents of the file '" << argv[1] << "'\n";
    sout << "const std::string get_decoded_string()\n";
    sout << "{\n";
    sout << "    dlib::base64 base64_coder;\n";
    sout << "    dlib::compress_stream::kernel_1ea compressor;\n";
    sout << "    std::ostringstream sout;\n";
    sout << "    std::istringstream sin;\n\n";

    sout << "    // The base64 encoded data from the file '" << argv[1] << "' we want to decode and return.\n";
    string temp;
    getline(sin,temp);
    while (sin && temp.size() > 0)
    {
        sout << "    sout << \"" << temp << "\";\n";
        getline(sin,temp);
    }

    sout << "\n";
    sout << "    // Put the data into the istream sin\n";
    sout << "    sin.str(sout.str());\n";
    sout << "    sout.str(\"\");\n\n";
    sout << "    // Decode the base64 text into its compressed binary form\n";
    sout << "    base64_coder.decode(sin,sout);\n";
    sout << "    sin.clear();\n";
    sout << "    sin.str(sout.str());\n";
    sout << "    sout.str(\"\");\n\n";
    sout << "    // Decompress the data into its original form\n";
    sout << "    compressor.decompress(sin,sout);\n\n";
    sout << "    // Return the decoded and decompressed data\n";
    sout << "    return sout.str();\n";
    sout << "}\n";

    // finally output our encoded data and its C++ code to the screen
    cout << sout.str() << endl;


dlib C++ Library - bayes_net_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*
    This is an example illustrating the use of the Bayesian Network
    inference utilities found in the dlib C++ library.

    In this example all the nodes in the Bayesian network are
    boolean variables.  That is, they take on either the value
    0 or the value 1.

    The network contains 4 nodes and looks as follows:

        B     C
        \\   //
         \/ \/
           A
           ||
           \/
            D

    The probabilities of each node are summarized below.  (The probability
    of each node being 0 is not listed since it is just P(X=0) = 1-p(X=1) )

        p(B=1) = 0.01

        p(C=1) = 0.001

        p(A=1 | B=0, C=0) = 0.01
        p(A=1 | B=0, C=1) = 0.5
        p(A=1 | B=1, C=0) = 0.9
        p(A=1 | B=1, C=1) = 0.99

        p(D=1 | A=0) = 0.2
        p(D=1 | A=1) = 0.5

*/

#include <dlib/bayes_utils.h>
#include <dlib/graph_utils.h>
#include <dlib/graph.h>
#include <dlib/directed_graph.h>
#include <iostream>

using namespace dlib;
using namespace std;

// ----------------------------------------------------------------------------------------

int main()
{
    try
    {
        // There are many useful convenience functions in this namespace.  They all
        // perform simple access or modify operations on the nodes of a bayesian network.
        // You don't have to use them but they are convenient and they also will check for
        // various errors in your bayesian network when your application is built with
        // the DEBUG or ENABLE_ASSERTS preprocessor definitions defined.  So their use
        // is recommended.  In fact, most of the global functions used in this example
        // program are from this namespace.
        using namespace bayes_node_utils;

        // This statement declares a bayesian network called bn.  Note that a bayesian network
        // in the dlib world is just a directed_graph object that contains a special kind
        // of node called a bayes_node.
        directed_graph<bayes_node>::kernel_1a_c bn;

        // Use an enum to make some more readable names for our nodes.
        enum nodes
        {
            A = 0,
            B = 1,
            C = 2,
            D = 3
        };

        // The next few blocks of code setup our bayesian network.

        // The first thing we do is tell the bn object how many nodes it has
        // and also add the three edges.  Again, we are using the network
        // shown in ASCII art at the top of this file.
        bn.set_number_of_nodes(4);
        bn.add_edge(A, D);
        bn.add_edge(B, A);
        bn.add_edge(C, A);

        // Now we inform all the nodes in the network that they are binary
        // nodes.  That is, they only have two possible values.
        set_node_num_values(bn, A, 2);
        set_node_num_values(bn, B, 2);
        set_node_num_values(bn, C, 2);
        set_node_num_values(bn, D, 2);

        assignment parent_state;
        // Now we will enter all the conditional probability information for each node.
        // Each node's conditional probability is dependent on the state of its parents.
        // To specify this state we need to use the assignment object.  This assignment
        // object allows us to specify the state of each nodes parents.

        // Here we specify that p(B=1) = 0.01
        // parent_state is empty in this case since B is a root node.
        set_node_probability(bn, B, 1, parent_state, 0.01);
        // Here we specify that p(B=0) = 1-0.01
        set_node_probability(bn, B, 0, parent_state, 1-0.01);

        // Here we specify that p(C=1) = 0.001
        // parent_state is empty in this case since B is a root node.
        set_node_probability(bn, C, 1, parent_state, 0.001);
        // Here we specify that p(C=0) = 1-0.001
        set_node_probability(bn, C, 0, parent_state, 1-0.001);

        // This is our first node that has parents. So we set the parent_state
        // object to reflect that A has both B and C as parents.
        parent_state.add(B, 1);
        parent_state.add(C, 1);
        // Here we specify that p(A=1 | B=1, C=1) = 0.99
        set_node_probability(bn, A, 1, parent_state, 0.99);
        // Here we specify that p(A=0 | B=1, C=1) = 1-0.99
        set_node_probability(bn, A, 0, parent_state, 1-0.99);

        // Here we use the [] notation because B and C have already
        // been added into parent state.
        parent_state[B] = 1;
        parent_state[C] = 0;
        // Here we specify that p(A=1 | B=1, C=0) = 0.9
        set_node_probability(bn, A, 1, parent_state, 0.9);
        set_node_probability(bn, A, 0, parent_state, 1-0.9);

        parent_state[B] = 0;
        parent_state[C] = 1;
        // Here we specify that p(A=1 | B=0, C=1) = 0.5
        set_node_probability(bn, A, 1, parent_state, 0.5);
        set_node_probability(bn, A, 0, parent_state, 1-0.5);

        parent_state[B] = 0;
        parent_state[C] = 0;
        // Here we specify that p(A=1 | B=0, C=0) = 0.01
        set_node_probability(bn, A, 1, parent_state, 0.01);
        set_node_probability(bn, A, 0, parent_state, 1-0.01);

        // Here we set probabilities for node D.
        // First we clear out parent state so that it doesn't have any of
        // the assignments for the B and C nodes used above.
        parent_state.clear();
        parent_state.add(A,1);
        // Here we specify that p(D=1 | A=1) = 0.5
        set_node_probability(bn, D, 1, parent_state, 0.5);
        set_node_probability(bn, D, 0, parent_state, 1-0.5);

        parent_state[A] = 0;
        // Here we specify that p(D=1 | A=0) = 0.2
        set_node_probability(bn, D, 1, parent_state, 0.2);
        set_node_probability(bn, D, 0, parent_state, 1-0.2);

        // We have now finished setting up our bayesian network.  So let's compute some
        // probability values.  The first thing we will do is compute the prior probability
        // of each node in the network.  To do this we will use the join tree algorithm which
        // is an algorithm for performing exact inference in a bayesian network.

        // First we need to create an undirected graph which contains set objects at each node and
        // edge.  This long declaration does the trick.
        typedef dlib::set<unsigned long>::compare_1b_c set_type;
        typedef graph<set_type, set_type>::kernel_1a_c join_tree_type;
        join_tree_type join_tree;

        // Now we need to populate the join_tree with data from our bayesian network.  The next
        // function calls do this.  Explaining exactly what they do is outside the scope of this
        // example.  Just think of them as filling join_tree with information that is useful
        // later on for dealing with our bayesian network.
        create_moral_graph(bn, join_tree);
        create_join_tree(join_tree, join_tree);

        // Now that we have a proper join_tree we can use it to obtain a solution to our
        // bayesian network.  Doing this is as simple as declaring an instance of
        // the bayesian_network_join_tree object as follows:
        bayesian_network_join_tree solution(bn, join_tree);

        // now print out the probabilities for each node
        cout << "Using the join tree algorithm:\n";
        cout << "p(A=1) = " << solution.probability(A)(1) << endl;
        cout << "p(A=0) = " << solution.probability(A)(0) << endl;
        cout << "p(B=1) = " << solution.probability(B)(1) << endl;
        cout << "p(B=0) = " << solution.probability(B)(0) << endl;
        cout << "p(C=1) = " << solution.probability(C)(1) << endl;
        cout << "p(C=0) = " << solution.probability(C)(0) << endl;
        cout << "p(D=1) = " << solution.probability(D)(1) << endl;
        cout << "p(D=0) = " << solution.probability(D)(0) << endl;
        cout << "\n\n\n";

        // Now to make things more interesting let's say that we have discovered that the C
        // node really has a value of 1.  That is to say, we now have evidence that
        // C is 1.  We can represent this in the network using the following two function
        // calls.
        set_node_value(bn, C, 1);
        set_node_as_evidence(bn, C);

        // Now we want to compute the probabilities of all the nodes in the network again
        // given that we now know that C is 1.  We can do this as follows:
        bayesian_network_join_tree solution_with_evidence(bn, join_tree);

        // now print out the probabilities for each node
        cout << "Using the join tree algorithm:\n";
        cout << "p(A=1 | C=1) = " << solution_with_evidence.probability(A)(1) << endl;
        cout << "p(A=0 | C=1) = " << solution_with_evidence.probability(A)(0) << endl;
        cout << "p(B=1 | C=1) = " << solution_with_evidence.probability(B)(1) << endl;
        cout << "p(B=0 | C=1) = " << solution_with_evidence.probability(B)(0) << endl;
        cout << "p(C=1 | C=1) = " << solution_with_evidence.probability(C)(1) << endl;
        cout << "p(C=0 | C=1) = " << solution_with_evidence.probability(C)(0) << endl;
        cout << "p(D=1 | C=1) = " << solution_with_evidence.probability(D)(1) << endl;
        cout << "p(D=0 | C=1) = " << solution_with_evidence.probability(D)(0) << endl;
        cout << "\n\n\n";

        // Note that when we made our solution_with_evidence object we reused our join_tree object.
        // This saves us the time it takes to calculate the join_tree object from scratch.  But
        // it is important to note that we can only reuse the join_tree object if we haven't changed
        // the structure of our bayesian network.  That is, if we have added or removed nodes or
        // edges from our bayesian network then we must recompute our join_tree.  But in this example
        // all we did was change the value of a bayes_node object (we made node C be evidence)
        // so we are ok.

        // Next this example will show you how to use the bayesian_network_gibbs_sampler object
        // to perform approximate inference in a bayesian network.  This is an algorithm
        // that doesn't give you an exact solution but it may be necessary to use in some
        // instances.  For example, the join tree algorithm used above, while fast in many
        // instances, has exponential runtime in some cases.  Moreover, inference in bayesian
        // networks is NP-Hard for general networks so sometimes the best you can do is
        // find an approximation.
        // However, it should be noted that the gibbs sampler does not compute the correct
        // probabilities if the network contains a deterministic node.  That is, if any
        // of the conditional probability tables in the bayesian network have a probability
        // of 1.0 for something the gibbs sampler should not be used.

        // This Gibbs sampler algorithm works by randomly sampling possibles values of the
        // network.  So to use it we should set the network to some initial state.

        set_node_value(bn, A, 0);
        set_node_value(bn, B, 0);
        set_node_value(bn, D, 0);

        // We will leave the C node with a value of 1 and keep it as an evidence node.

        // First create an instance of the gibbs sampler object
        bayesian_network_gibbs_sampler sampler;

        // To use this algorithm all we do is go into a loop for a certain number of times
        // and each time through we sample the bayesian network.  Then we count how
        // many times a node has a certain state.  Then the probability of that node
        // having that state is just its count/total times through the loop.

        // The following code illustrates the general procedure.
        unsigned long A_count = 0;
        unsigned long B_count = 0;
        unsigned long C_count = 0;
        unsigned long D_count = 0;

        // The more times you let the loop run the more accurate the result will be.  Here we loop
        // 2000 times.
        const long rounds = 2000;
        for (long i = 0; i < rounds; ++i)
        {
            sampler.sample_graph(bn);

            if (node_value(bn, A) == 1)
                ++A_count;
            if (node_value(bn, B) == 1)
                ++B_count;
            if (node_value(bn, C) == 1)
                ++C_count;
            if (node_value(bn, D) == 1)
                ++D_count;
        }

        cout << "Using the approximate Gibbs Sampler algorithm:\n";
        cout << "p(A=1 | C=1) = " << (double)A_count/(double)rounds << endl;
        cout << "p(B=1 | C=1) = " << (double)B_count/(double)rounds << endl;
        cout << "p(C=1 | C=1) = " << (double)C_count/(double)rounds << endl;
        cout << "p(D=1 | C=1) = " << (double)D_count/(double)rounds << endl;
    }
    catch (std::exception& e)
    {
        cout << "exception thrown: " << endl;
        cout << e.what() << endl;
        cout << "hit enter to terminate" << endl;
        cin.get();


dlib C++ Library - bayes_net_from_disk_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*
    This is an example illustrating the use of the Bayesian Network
    inference utilities found in the dlib C++ library.  In this example
    we load a saved Bayesian Network from disk.
*/

#include <dlib/bayes_utils.h>
#include <dlib/graph_utils.h>
#include <dlib/graph.h>
#include <dlib/directed_graph.h>
#include <iostream>
#include <fstream>

using namespace dlib;
using namespace std;

// ----------------------------------------------------------------------------------------

int main(int argc, char** argv)
{
    try
    {
        // This statement declares a bayesian network called bn.  Note that a bayesian network
        // in the dlib world is just a directed_graph object that contains a special kind
        // of node called a bayes_node.
        directed_graph<bayes_node>::kernel_1a_c bn;

        if (argc != 2)
        {
            cout << "You must supply a file name on the command line.  The file should "
                 << "contain a serialized Bayesian Network" << endl;
            return 1;
        }

        ifstream fin(argv[1],ios::binary);

        // Note that the saved networks produced by the bayes_net_gui_ex.cpp example can be deserialized
        // into a network.  So you can make your networks using that GUI if you like.
        cout << "Loading the network from disk..." << endl;
        deserialize(bn, fin);

        cout << "Number of nodes in the network: " << bn.number_of_nodes() << endl;

        // Let's compute some probability values using the loaded network using the join tree (aka. Junction
        // Tree) algorithm.

        // First we need to create an undirected graph which contains set objects at each node and
        // edge.  This long declaration does the trick.
        typedef graph<dlib::set<unsigned long>::compare_1b_c, dlib::set<unsigned long>::compare_1b_c>::kernel_1a_c join_tree_type;
        join_tree_type join_tree;

        // Now we need to populate the join_tree with data from our bayesian network.  The next two
        // function calls do this.  Explaining exactly what they do is outside the scope of this
        // example.  Just think of them as filling join_tree with information that is useful
        // later on for dealing with our bayesian network.
        create_moral_graph(bn, join_tree);
        create_join_tree(join_tree, join_tree);

        // Now we have a proper join_tree we can use it to obtain a solution to our
        // bayesian network.  Doing this is as simple as declaring an instance of
        // the bayesian_network_join_tree object as follows:
        bayesian_network_join_tree solution(bn, join_tree);

        // now print out the probabilities for each node
        cout << "Using the join tree algorithm:\n";
        for (unsigned long i = 0; i < bn.number_of_nodes(); ++i)
        {
            // print out the probability distribution for node i.
            cout << "p(node " << i <<") = " << solution.probability(i);
        }
    }
    catch (exception& e)
    {
        cout << "exception thrown: " << e.what() << endl;
        return 1;


dlib C++ Library - bayes_net_gui_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*
    This is a rather involved example illustrating the use of the GUI api from
    the dlib C++ Library.   This program is a fully functional utility for
    creating Bayesian Networks.  It allows the user to graphically draw the network,
    save/load the network to/from disk, and also to calculate the posterior
    probability of any node in the network given a set of evidence.

    This is not the first dlib example program you should be looking at.  If you
    want to see a simpler GUI example please look at the gui_api_ex.cpp or
    image_ex.cpp example.

    If you want to understand how to use the Bayesian Network utilities in the library
    you should definitely look at the bayes_net_ex.cpp example program.  It gives a
    comprehensive introduction to creating and manipulating Bayesian Networks.  If you
    want to see how to load a saved network from disk and use it in a non-GUI application
    then look at the bayes_net_from_disk_ex.cpp example.

    Now all of that being said, if you have already looked at the other relevant
    examples and want to see a more in-depth example then by all means, continue reading. :)
*/

#include <dlib/gui_widgets.h>
#include <sstream>
#include <string>
#include <dlib/directed_graph.h>
#include <dlib/string.h>
#include <dlib/bayes_utils.h>
#include <dlib/smart_pointers.h>
#include <dlib/set.h>
#include <dlib/graph_utils.h>
#include <dlib/stl_checked.h>

using namespace std;
using namespace dlib;
using namespace dlib::bayes_node_utils;

//  ----------------------------------------------------------------------------

typedef directed_graph<bayes_node>::kernel_1a_c directed_graph_type;
typedef directed_graph<bayes_node>::kernel_1a_c::node_type node_type;
typedef graph<dlib::set<unsigned long>::compare_1b_c, dlib::set<unsigned long>::compare_1b_c>::kernel_1a_c join_tree_type;

//  ----------------------------------------------------------------------------

class main_window : public drawable_window
{
    /*!
        INITIAL VALUE
            This window starts out hidden and with an empty Bayesian Network

        WHAT THIS OBJECT REPRESENTS
            This object is the main window of a utility for drawing Bayesian Networks.
            It allows you to draw a directed graph and to set the conditional probability
            tables up for each node in the network.  It also allows you to compute the
            posterior probability of each node.  And finally, it lets you save and load
            networks from file
    !*/
public:
    main_window();
    ~main_window();

private:

    // Private helper methods

    void initialize_node_cpt_if_necessary ( unsigned long index );
    void load_selected_node_tables_into_cpt_grid ();
    void load_selected_node_tables_into_ppt_grid ();
    void no_node_selected ();

    // Event handlers

    void on_cpt_grid_modified(unsigned long row, unsigned long col);
    void on_evidence_toggled ();
    void on_graph_modified ();
    void on_menu_file_open ();
    void on_menu_file_quit ();
    void on_menu_file_save ();
    void on_menu_file_save_as ();
    void on_menu_help_about ();
    void on_menu_help_help ();
    void on_node_deleted ();
    void on_node_deselected ( unsigned long n );
    void on_node_selected (unsigned long n);
    void on_open_file_selected ( const std::string& file_name);
    void on_save_file_selected ( const std::string& file_name);
    void on_sel_node_evidence_modified ();
    void on_sel_node_num_values_modified ();
    void on_sel_node_text_modified ();
    void on_window_resized ();
    void recalculate_probabilities ();

    // Member data

    const rgb_pixel color_non_evidence;
    const rgb_pixel color_default_bg;
    const rgb_pixel color_evidence;
    const rgb_pixel color_error;
    const rgb_pixel color_gray;
    bool graph_modified_since_last_recalc;

    button btn_calculate;
    check_box sel_node_is_evidence;
    directed_graph_drawer<directed_graph_type> graph_drawer;
    label sel_node_index;
    label sel_node_num_values_label;
    label sel_node_text_label;
    label sel_node_evidence_label;
    menu_bar mbar;
    named_rectangle selected_node_rect;
    tabbed_display tables;
    text_field sel_node_num_values;
    text_field sel_node_text;
    text_field sel_node_evidence;
    text_grid cpt_grid;
    text_grid ppt_grid;
    unsigned long selected_node_index;
    bool node_is_selected;
    widget_group cpt_group;
    widget_group ppt_group;

    scoped_ptr<bayesian_network_join_tree> solution;
    join_tree_type join_tree;
    // The std_vector_c is an object identical to the std::vector except that it checks
    // all its preconditions and throws a dlib::fatal_error if they are violated.
    std_vector_c<assignment> cpt_grid_assignments;
    std::string graph_file_name;
};

// ----------------------------------------------------------------------------------------

int main()
{
    // create our window
    main_window my_window;

    // tell our window to put itself on the screen
    my_window.show();

    // wait until the user closes this window before we let the program
    // terminate.
    my_window.wait_until_closed();
}

// ----------------------------------------------------------------------------------------

#ifdef WIN32
//  If you use main() as your entry point when building a program on MS Windows then
//  there will be a black console window associated with your application.  If you
//  want your application to not have this console window then you need to build
//  using the WinMain() entry point as shown below and also set your compiler to
//  produce a "Windows" project instead of a "Console" project.  In visual studio
//  this can be accomplished by going to project->properties->general configuration->
//  Linker->System->SubSystem and selecting Windows instead of Console.
//
int WINAPI WinMain (HINSTANCE, HINSTANCE, PSTR cmds, int)
{
    main();
    return 0;
}
#endif

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//               Methods from the main_window object
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

main_window::
main_window(
) :
    color_non_evidence(0,0,0),
    color_default_bg(255,255,255),
    color_evidence(100,200,100),
    color_error(255,0,0),
    color_gray(210,210,210),
    graph_modified_since_last_recalc(true),
    btn_calculate(*this),
    sel_node_is_evidence(*this),
    graph_drawer(*this),
    sel_node_index(*this),
    sel_node_num_values_label (*this),
    sel_node_text_label(*this),
    sel_node_evidence_label(*this),
    mbar(*this),
    selected_node_rect(*this),
    tables(*this),
    sel_node_num_values(*this),
    sel_node_text(*this),
    sel_node_evidence(*this),
    cpt_grid(*this),
    ppt_grid(*this),
    selected_node_index(0),
    node_is_selected(false),
    cpt_group(*this),
    ppt_group(*this)
{
    // Note that all the GUI widgets take a reference to the window that contains them
    // as their constructor argument.  This is a universal feature of GUI widgets in the
    // dlib library.

    set_title("Bayesian Network Utility");

    // position the widget that is responsible for drawing the directed graph, the graph_drawer,
    // just below the mbar (menu bar) widget.
    graph_drawer.set_pos(5,mbar.bottom()+5);
    set_size(750,400);

    // register the event handlers with their respective widgets
    btn_calculate.set_click_handler              (*this, &main_window::recalculate_probabilities);
    cpt_grid.set_text_modified_handler           (*this, &main_window::on_cpt_grid_modified);
    graph_drawer.set_graph_modified_handler      (*this, &main_window::on_graph_modified);
    graph_drawer.set_node_deleted_handler        (*this, &main_window::on_node_deleted);
    graph_drawer.set_node_deselected_handler     (*this, &main_window::on_node_deselected);
    graph_drawer.set_node_selected_handler       (*this, &main_window::on_node_selected);
    sel_node_evidence.set_text_modified_handler  (*this, &main_window::on_sel_node_evidence_modified);
    sel_node_is_evidence.set_click_handler       (*this, &main_window::on_evidence_toggled);
    sel_node_num_values.set_text_modified_handler(*this, &main_window::on_sel_node_num_values_modified);
    sel_node_text.set_text_modified_handler      (*this, &main_window::on_sel_node_text_modified);

    // now set the text of some of our buttons and labels
    btn_calculate.set_name("Recalculate posterior probability table");
    selected_node_rect.set_name("Selected node");
    sel_node_evidence_label.set_text("evidence value:");
    sel_node_is_evidence.set_name("is evidence");
    sel_node_num_values_label.set_text("Number of values: ");
    sel_node_text_label.set_text("Node label:");

    // Now setup the tabbed display.  It will have two tabs, one for the conditional
    // probability table and one for the posterior probability table.
    tables.set_number_of_tabs(2);
    tables.set_tab_name(0,"Conditional probability table");
    tables.set_tab_name(1,"Posterior probability table");
    cpt_group.add(cpt_grid,0,0);
    ppt_group.add(ppt_grid,0,0);
    tables.set_tab_group(0,cpt_group);
    tables.set_tab_group(1,ppt_group);

    // Now setup the menu bar.  We will have two menus.  A File and Help menu.
    mbar.set_number_of_menus(2);
    mbar.set_menu_name(0,"File",'F');
    mbar.set_menu_name(1,"Help",'H');

    // add the entries to the File menu.
    mbar.menu(0).add_menu_item(menu_item_text("Open",   *this, &main_window::on_menu_file_open,    'O'));
    mbar.menu(0).add_menu_item(menu_item_separator());
    mbar.menu(0).add_menu_item(menu_item_text("Save",   *this, &main_window::on_menu_file_save,    'S'));
    mbar.menu(0).add_menu_item(menu_item_text("Save As",*this, &main_window::on_menu_file_save_as, 'a'));
    mbar.menu(0).add_menu_item(menu_item_separator());
    mbar.menu(0).add_menu_item(menu_item_text("Quit",   *this, &main_window::on_menu_file_quit,    'Q'));

    // Add the entries to the Help menu.
    mbar.menu(1).add_menu_item(menu_item_text("Help",   *this, &main_window::on_menu_help_help,    'e'));
    mbar.menu(1).add_menu_item(menu_item_text("About",  *this, &main_window::on_menu_help_about,   'A'));

    // call our helper functions and window resize event to get the widgets
    // to all arrange themselves correctly in our window.
    no_node_selected();
    on_window_resized();
}

// ----------------------------------------------------------------------------------------

main_window::
~main_window(
)
{
    // You should always call close_window() in the destructor of window
    // objects to ensure that no events will be sent to this window while
    // it is being destructed.
    close_window();
}

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//               Private methods from the main_window object
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

void main_window::
load_selected_node_tables_into_ppt_grid (
)
{
    // This function just takes the currently selected graph node and loads
    // its posterior probabilities into the ppt_graph widget.
    node_type& node = graph_drawer.graph_node(selected_node_index);
    ppt_grid.set_grid_size(2,node.data.table().num_values());

    // load the top row of the table into the grid.  This row is the "title bar" row
    // that tells you what each column contains.
    for (unsigned long col = 0; col < node.data.table().num_values(); ++col)
    {
        ppt_grid.set_text(0,col,"P(node=" + cast_to_string(col) + ")");
        ppt_grid.set_background_color(0,col,rgb_pixel(150,150,250));
        ppt_grid.set_editable(0,col,false);
    }

    // If we have a solution to the network on hand then load the probabilities
    // from that into the table
    if (solution)
    {
        // get the probability distribution for the currently selected node out
        // of the solution.
        const matrix<double,1> prob = solution->probability(selected_node_index);

        // now load the probabilities into the ppt_grid so the user can see them.
        for (unsigned long col = 0; col < node.data.table().num_values(); ++col)
        {
            ppt_grid.set_text(1,col,cast_to_string(prob(col)));
        }
    }

    // make the second row of the table non-editable have a color that indicates
    // that to the user
    for (unsigned long col = 0; col < node.data.table().num_values(); ++col)
    {
        ppt_grid.set_background_color(1,col,color_gray);
        ppt_grid.set_editable(1,col,false);
    }
}

// ----------------------------------------------------------------------------------------

void main_window::
load_selected_node_tables_into_cpt_grid (
)
{
    // This function just takes the conditional probability table in the
    // currently selected graph node and puts it into the cpt_grid widget.

    node_type& node = graph_drawer.graph_node(selected_node_index);

    initialize_node_cpt_if_necessary(selected_node_index);
    cpt_grid_assignments.clear();

    // figure out how many rows there should be in the cpt
    unsigned long cpt_rows = 1;
    for (unsigned long i = 0; i < node.number_of_parents(); ++i)
    {
        cpt_rows *= node.parent(i).data.table().num_values();
    }

    unsigned long cpt_cols = node.data.table().num_values();

    cpt_grid.set_grid_size(cpt_rows+1, cpt_cols+ node.number_of_parents());
    const unsigned long num_cols = cpt_grid.number_of_columns();

    // fill in the top row of the grid that shows which parent node the left hand columns go with
    assignment a(node_first_parent_assignment(graph_drawer.graph(),selected_node_index));
    unsigned long col = 0;
    a.reset();
    while (a.move_next())
    {
        cpt_grid.set_text(0,col,cast_to_string(a.element().key()) + ": " + graph_drawer.node_label(a.element().key()) );
        cpt_grid.set_background_color(0,col,rgb_pixel(120,210,210));
        cpt_grid.set_editable(0,col,false);
        ++col;
    }

    // fill in the top row of the grid that shows which probability the right hand columns go with
    for (col = node.number_of_parents(); col < num_cols; ++col)
    {
        cpt_grid.set_text(0,col,"P(node=" + cast_to_string(col-node.number_of_parents()) + ")");
        cpt_grid.set_background_color(0,col,rgb_pixel(150,150,250));
        cpt_grid.set_editable(0,col,false);
    }

    // now loop over all the possible parent assignments for this node
    const unsigned long num_values = node.data.table().num_values();
    unsigned long row = 1;
    do
    {
        col = 0;

        // fill in the left side of the grid row that shows what the parent assignment is
        a.reset();
        while (a.move_next())
        {
            cpt_grid.set_text(row,col,cast_to_string(a.element().value()));
            cpt_grid.set_background_color(row,col,rgb_pixel(180,255,255));
            cpt_grid.set_editable(row,col,false);

            ++col;
        }

        // fill in the right side of the grid row that shows what the conditional probabilities are
        for (unsigned long value = 0; value < num_values; ++value)
        {
            const double prob = node.data.table().probability(value,a);
            cpt_grid.set_text(row,col,cast_to_string(prob));
            ++col;
        }

        // save this assignment so we can use it later to modify the node's
        // conditional probability table if the user modifies the cpt_grid
        cpt_grid_assignments.push_back(a);
        ++row;
    } while (node_next_parent_assignment(graph_drawer.graph(),selected_node_index,a));

}

// ----------------------------------------------------------------------------------------

void main_window::
initialize_node_cpt_if_necessary (
    unsigned long index
)
{
    node_type& node = graph_drawer.graph_node(index);

    // if the cpt for this node isn't properly filled out then let's clear it out
    // and populate it with some reasonable default values
    if (node_cpt_filled_out(graph_drawer.graph(), index) == false)
    {
        node.data.table().empty_table();

        const unsigned long num_values = node.data.table().num_values();

        // loop over all the possible parent assignments for this node and fill them out
        // with reasonable default values
        assignment a(node_first_parent_assignment(graph_drawer.graph(), index));
        do
        {
            // set the first value to have probability 1
            node.data.table().set_probability(0, a, 1.0);

            // set all the other values to have probability 0
            for (unsigned long value = 1; value < num_values; ++value)
                node.data.table().set_probability(value, a, 0);

        } while (node_next_parent_assignment(graph_drawer.graph(), index,a));
    }
}

// ----------------------------------------------------------------------------------------

void main_window::
no_node_selected (
)
{
    // Make it so that no node is selected on the gui.  Do this by disabling things
    // and clearing out text fields and so forth.

    node_is_selected = false;
    tables.disable();
    sel_node_evidence.disable();
    sel_node_is_evidence.disable();
    sel_node_index.disable();
    sel_node_evidence_label.disable();
    sel_node_text_label.disable();
    sel_node_text.disable();
    sel_node_index.set_text("index:");
    sel_node_num_values_label.disable();
    sel_node_num_values.disable();
    cpt_grid.set_grid_size(0,0);
    ppt_grid.set_grid_size(0,0);

    sel_node_is_evidence.set_unchecked();
    sel_node_text.set_text("");
    sel_node_num_values.set_text("");
    sel_node_evidence.set_text("");
    sel_node_num_values.set_background_color(color_default_bg);
    sel_node_evidence.set_background_color(color_default_bg);
}

// ----------------------------------------------------------------------------------------

void main_window::
recalculate_probabilities (
)
{
    // clear out the current solution
    solution.reset();
    if (graph_is_connected(graph_drawer.graph()) == false)
    {
        message_box("Error","Your graph has nodes that are completely disconnected from the other nodes.\n"
                    "You must connect them somehow");
    }
    else if (graph_drawer.graph().number_of_nodes() > 0)
    {
        if (graph_modified_since_last_recalc)
        {
            // make sure all the cpts are filled out
            const unsigned long num_nodes = graph_drawer.graph().number_of_nodes();
            for (unsigned long i = 0; i < num_nodes; ++i)
            {
                initialize_node_cpt_if_necessary(i);
            }

            // remake the join tree for this graph
            create_moral_graph(graph_drawer.graph(), join_tree);
            create_join_tree(join_tree, join_tree);
            graph_modified_since_last_recalc = false;
        }

        // create a solution to this bayesian network using the join tree algorithm
        solution.reset(new bayesian_network_join_tree(graph_drawer.graph(), join_tree));

        if (node_is_selected)
        {
            load_selected_node_tables_into_ppt_grid();
        }
    }
}

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//               Event handling methods from the main_window object
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

// This event is called when the user selects a file with a saved
// bayesian network in it.
void main_window::
on_open_file_selected (
    const std::string& file_name
)
{
    try
    {
        no_node_selected();
        ifstream fin(file_name.c_str(), ios::binary);
        graph_drawer.load_graph(fin);
        graph_file_name = file_name;
        set_title("Bayesian Network Utility - " + right_substr(file_name,"\\/"));
    }
    catch (...)
    {
        message_box("Error", "Unable to load graph file " + file_name);
    }
}

// ----------------------------------------------------------------------------------------

// This event is called when the user selects from the menu bar File->Open
void main_window::
on_menu_file_open (
)
{
    // display a file chooser window and when the user choses a file
    // call the on_open_file_selected() function
    open_existing_file_box(*this, &main_window::on_open_file_selected);
}

// ----------------------------------------------------------------------------------------

// This event is called when the user selects from the menu bar File->Save
void main_window::
on_menu_file_save (
)
{
    // if we don't currently have any file name associated with our graph
    if (graph_file_name.size() == 0)
    {
        // display a file chooser window and when the user choses a file
        // call the on_save_file_selected() function
        save_file_box(*this, &main_window::on_save_file_selected);
    }
    else
    {
        // we know what file to open so just do that and save the graph to it
        ofstream fout(graph_file_name.c_str(), ios::binary);
        graph_drawer.save_graph(fout);
    }
}

// ----------------------------------------------------------------------------------------

// This event is called when the user choses which file to save the graph to
void main_window::
on_save_file_selected (
    const std::string& file_name
)
{
    ofstream fout(file_name.c_str(), ios::binary);
    graph_drawer.save_graph(fout);
    graph_file_name = file_name;
    set_title("Bayesian Network Utility - " + right_substr(file_name,"\\/"));
}

// ----------------------------------------------------------------------------------------

// This event is called when the user selects from the menu bar File->Save As
void main_window::
on_menu_file_save_as (
)
{
    // display a file chooser window and when the user choses a file
    // call the on_save_file_selected() function
    save_file_box(*this, &main_window::on_save_file_selected);
}

// ----------------------------------------------------------------------------------------

// This event is called when the user selects from the menu bar File->Quit
void main_window::
on_menu_file_quit (
)
{
    close_window();
}

// ----------------------------------------------------------------------------------------

// This event is called when the user selects from the menu bar Help->Help
void main_window::
on_menu_help_help (
)
{
    message_box("Help",
                "To create new nodes right click on the drawing area.\n"
                "To create edges select the parent node and then shift+left click on the child node.\n"
                "To remove nodes or edges select them by left clicking and then press the delete key.");
}

// ----------------------------------------------------------------------------------------

// This event is called when the user selects from the menu bar Help->About
void main_window::
on_menu_help_about (
)
{
    message_box("About","This application is the GUI front end to the dlib C++ Library's\n"
                "Bayesian Network inference utilities\n\n"
                "Version 1.2\n\n"
                "See http://dlib.net for updates");
}

// ----------------------------------------------------------------------------------------

// This event is called when the user modifies the graph_drawer widget.  That is,
// when the user adds or removes an edge or node in the graph.
void main_window::
on_graph_modified (
)
{
    // make note of the modification
    graph_modified_since_last_recalc = true;
    // clear out the solution object since we will need to recalculate it
    // since the graph changed
    solution.reset();
}

// ----------------------------------------------------------------------------------------

// This event is called when the user modifies the evidence value for a node
void main_window::
on_sel_node_evidence_modified (
)
{
    // make a reference to the node in the graph that is currently selected
    node_type& node = graph_drawer.graph_node(selected_node_index);
    unsigned long value;
    try
    {
        // get the numerical value of the new evidence value.  Here we are taking
        // the string from the text field and casting it to an unsigned long.
        value = sa = trim(sel_node_evidence.text());
    }
    catch (string_cast_error&)
    {
        // if the user put something that isn't an integer into the
        // text field then make it have a different background color
        // so that they can easily see this.
        sel_node_evidence.set_background_color(color_error);
        return;
    }

    // validate the input from the user and store it in the selected node
    // if it is ok
    if (value >= node.data.table().num_values())
    {
        sel_node_evidence.set_background_color(color_error);
    }
    else
    {
        node.data.set_value(value);
        sel_node_evidence.set_background_color(color_default_bg);
    }

    // clear out the solution to the graph since we now need
    // to recalculate it.
    solution.reset();
}

// ----------------------------------------------------------------------------------------

// This event is called when the user modifies the number of evidence values for
// a node.
void main_window::
on_sel_node_num_values_modified (
)
{
    // make a reference to the node in the graph that is currently selected
    node_type& node = graph_drawer.graph_node(selected_node_index);

    unsigned long num_values;
    try
    {
        // get the number of values out of the text field.
        num_values = sa = trim(sel_node_num_values.text());
    }
    catch (string_cast_error&)
    {
        sel_node_num_values.set_background_color(color_error);
        return;
    }

    // validate the input from the user to make sure it is something reasonable
    if (num_values < 2 || num_values > 100)
    {
        sel_node_num_values.set_background_color(color_error);
    }
    else
    {
        // update the graph
        node.data.table().set_num_values(num_values);
        graph_modified_since_last_recalc = true;
        sel_node_num_values.set_background_color(color_default_bg);

        on_sel_node_evidence_modified();
        // also make sure the evidence value of this node makes sense still
        if (node.data.is_evidence() && node.data.value() >= num_values)
        {
            // just set it to zero
            node.data.set_value(0);
        }

    }

    solution.reset();

    // call these functions so that the conditional and posterior probability
    // tables get updated
    load_selected_node_tables_into_cpt_grid();
    load_selected_node_tables_into_ppt_grid();
}

// ----------------------------------------------------------------------------------------

// This event is called when the user modifies the cpt_grid (i.e. the conditional
// probability table widget)
void main_window::
on_cpt_grid_modified(unsigned long row, unsigned long col)
{
    node_type& node = graph_drawer.graph_node(selected_node_index);
    solution.reset();

    double prob;
    try
    {
        // get the new value out of the table
        prob = sa = cpt_grid.text(row,col);
    }
    catch (string_cast_error&)
    {
        cpt_grid.set_background_color(row,col,color_error);
        return;
    }

    // validate the value
    if (prob < 0 || prob > 1)
    {
        cpt_grid.set_background_color(row,col,color_error);
        return;
    }

    // the value of this node that is having its conditional probability
    // updated
    const unsigned long cur_val = col-node.number_of_parents();

    node.data.table().set_probability(cur_val, cpt_grid_assignments[row-1], prob);

    // sum the probabilities in the cpt and modify the last one such that they all
    // sum to 1.  We are excluding either the first or last element from the sum
    // because we are going to set it equal to 1-sum below.
    double sum = 0;
    if (cur_val != node.data.table().num_values()-1)
    {
        for (unsigned long i = 0; i < node.data.table().num_values()-1; ++i)
            sum += node.data.table().probability(i, cpt_grid_assignments[row-1]);
    }
    else
    {
        for (unsigned long i = 1; i < node.data.table().num_values(); ++i)
            sum += node.data.table().probability(i, cpt_grid_assignments[row-1]);
    }

    // make sure all the probabilities sum to 1
    if (sum > 1.0)
    {
        cpt_grid.set_background_color(row,cpt_grid.number_of_columns()-1,color_error);
    }
    else
    {
        // edit one of the other elements in the table to ensure that the probabilities still sum to 1
        if (cur_val == node.data.table().num_values()-1)
        {
            node.data.table().set_probability(0, cpt_grid_assignments[row-1], 1-sum);
            cpt_grid.set_text(row,node.number_of_parents(),cast_to_string(1-sum));
        }
        else
        {
            node.data.table().set_probability(node.data.table().num_values()-1, cpt_grid_assignments[row-1], 1-sum);
            cpt_grid.set_text(row,cpt_grid.number_of_columns()-1,cast_to_string(1-sum));
        }

        cpt_grid.set_background_color(row,cpt_grid.number_of_columns()-1,color_default_bg);
        cpt_grid.set_background_color(row,col,color_default_bg);
    }

}

// ----------------------------------------------------------------------------------------

// This event is called when the user resizes the main_window.  Note that unlike the other
// events, this event is part of the drawable_window base class that main_window inherits from.
// So you won't see any statements in the constructor that say "register the main_window::on_window_resized function"
void main_window::
on_window_resized ()
{
    // when you override any of the drawable_window events you have to make sure you
    // call the drawable_window's version of them because it needs to process
    // the events as well.  So we do that here.
    drawable_window::on_window_resized();

    // The rest of this function positions the widgets on the window
    unsigned long width,height;
    get_size(width,height);

    // Don't do anything if the user just made the window too small.  That is, leave
    // the widgets where they are.
    if (width < 500 || height < 350)
        return;

    // Set the size of the probability tables and the drawing area for the graph
    graph_drawer.set_size(width-370,height-10-mbar.height());
    cpt_grid.set_size((width-graph_drawer.width())-35,height-237);
    ppt_grid.set_size((width-graph_drawer.width())-35,height-237);
    // tell the tabbed display to make itself just the right size to contain
    // the two probability tables.
    tables.fit_to_contents();

    // Now position all the widgets in the window.  Note that much of the positioning
    // is relative to other widgets.  This part of the code I just figured out by
    // trying stuff and rerunning the program to see if it looked nice.
    sel_node_index.set_pos(graph_drawer.right()+14,graph_drawer.top()+18);
    sel_node_text_label.set_pos(sel_node_index.left(),sel_node_index.bottom()+5);
    sel_node_text.set_pos(sel_node_text_label.right()+5,sel_node_index.bottom());
    sel_node_num_values_label.set_pos(sel_node_index.left(), sel_node_text.bottom()+5);
    sel_node_num_values.set_pos(sel_node_num_values_label.right(), sel_node_text.bottom()+5);
    sel_node_is_evidence.set_pos(sel_node_index.left(),sel_node_num_values.bottom()+5);
    sel_node_evidence_label.set_pos(sel_node_index.left(),sel_node_is_evidence.bottom()+5);
    sel_node_evidence.set_pos(sel_node_evidence_label.right()+5,sel_node_is_evidence.bottom());
    tables.set_pos(sel_node_index.left(),sel_node_evidence.bottom()+5);
    sel_node_evidence.set_width(tables.right()-sel_node_evidence.left()+1);
    sel_node_text.set_width(tables.right()-sel_node_text.left()+1);
    sel_node_num_values.set_width(tables.right()-sel_node_num_values.left()+1);

    // Tell the named rectangle to position itself such that it fits around the
    // tabbed display that contains the probability tables and the label at the top of the
    // screen.
    selected_node_rect.wrap_around(sel_node_index.get_rect()+
                                   tables.get_rect());

    // finally set the button to be at the bottom of the named rectangle
    btn_calculate.set_pos(selected_node_rect.left(), selected_node_rect.bottom()+5);
}

// ----------------------------------------------------------------------------------------

// This event is called by the graph_drawer widget when the user selects a node
void main_window::
on_node_selected (unsigned long n)
{
    // make a reference to the selected node
    node_type& node = graph_drawer.graph_node(n);

    // enable all the widgets related to the selected node
    selected_node_index = n;
    node_is_selected = true;
    tables.enable();
    sel_node_is_evidence.enable();
    sel_node_index.enable();
    sel_node_evidence_label.enable();
    sel_node_text_label.enable();
    sel_node_text.enable();
    sel_node_num_values_label.enable();
    sel_node_num_values.enable();

    // make sure the num_values field of the node's cpt is set to something valid.
    // So default it to 2 if it isn't set already.
    if (node.data.table().num_values() < 2)
    {
        node.data.table().set_num_values(2);
        graph_modified_since_last_recalc = true;
    }

    // setup the evidence check box and input field
    sel_node_index.set_text("index: " + cast_to_string(n));
    if (graph_drawer.graph_node(n).data.is_evidence())
    {
        sel_node_is_evidence.set_checked();
        sel_node_evidence.enable();
        sel_node_evidence.set_text(cast_to_string(graph_drawer.graph_node(n).data.value()));
    }
    else
    {
        sel_node_is_evidence.set_unchecked();
        sel_node_evidence.disable();
        sel_node_evidence.set_text("");
    }

    sel_node_num_values.set_text(cast_to_string(node_num_values(graph_drawer.graph(),n)));

    sel_node_text.set_text(graph_drawer.node_label(n));

    load_selected_node_tables_into_cpt_grid();
    load_selected_node_tables_into_ppt_grid();
}

// ----------------------------------------------------------------------------------------

// This event is called when the user toggles the "is evidence" check box
void main_window::
on_evidence_toggled (
)
{
    if (sel_node_is_evidence.is_checked())
    {
        graph_drawer.graph_node(selected_node_index).data.set_as_evidence();
        sel_node_evidence.enable();
        sel_node_evidence.set_text(cast_to_string(graph_drawer.graph_node(selected_node_index).data.value()));

        graph_drawer.set_node_color(selected_node_index, color_evidence);
    }
    else
    {
        graph_drawer.graph_node(selected_node_index).data.set_as_nonevidence();
        sel_node_evidence.disable();
        sel_node_evidence.set_text("");
        sel_node_evidence.set_background_color(color_default_bg);
        graph_drawer.set_node_color(selected_node_index, color_non_evidence);
    }
    solution.reset();
}

// ----------------------------------------------------------------------------------------

// This event is called when the user causes no node to be selected
void main_window::
on_node_deselected ( unsigned long  )
{
    no_node_selected();
}

// ----------------------------------------------------------------------------------------

// This event is called when the user causes a node to be deleted
void main_window::
on_node_deleted (  )
{
    no_node_selected();
}

// ----------------------------------------------------------------------------------------

// This event is called when the user changes the text in the "node label" text field
void main_window::
on_sel_node_text_modified (
)
{
    // set the selected node's text to match whatever the user just typed in
    graph_drawer.set_node_label(selected_node_index,sel_node_text.text());
}

// ----------------------------------------------------------------------------------------


dlib C++ Library - bridge_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt

/*
    This is an example showing how to use the bridge object from from the
    dlib C++ Library to send messages via TCP/IP.

    In particular, this example will walk you through four progressively
    more complex use cases of the bridge object.  Note that this example
    program assumes you are already familiar with the pipe object and at
    least the contents of the pipe_ex_2.cpp example program.
*/

// =========== Example program output ===========
/*
     ---- Running example 1 ----
    dequeued value: 1
    dequeued value: 2
    dequeued value: 3

     ---- Running example 2 ----
    dequeued value: 1
    dequeued value: 2
    dequeued value: 3

     ---- Running example 3 ----
    dequeued int:    1
    dequeued int:    2
    dequeued struct: 3   some string

     ---- Running example 4 ----
    bridge 1 status: is_connected: true
    bridge 1 status: foreign_ip:   127.0.0.1
    bridge 1 status: foreign_port: 43156
    bridge 2 status: is_connected: true
    bridge 2 status: foreign_ip:   127.0.0.1
    bridge 2 status: foreign_port: 12345
    dequeued int:    1
    dequeued int:    2
    dequeued struct: 3   some string
    bridge 1 status: is_connected: false
    bridge 1 status: foreign_ip:   127.0.0.1
    bridge 1 status: foreign_port: 12345
*/

#include <dlib/bridge.h>
#include <dlib/type_safe_union.h>
#include <iostream>

using namespace dlib;
using namespace std;

// ----------------------------------------------------------------------------------------

void run_example_1();
void run_example_2();
void run_example_3();
void run_example_4();

// ----------------------------------------------------------------------------------------

int main()
{
    run_example_1();
    run_example_2();
    run_example_3();
    run_example_4();
}

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

void run_example_1(
)
{
    cout << "\n ---- Running example 1 ---- " << endl;

    /*
        The idea of the bridge is basically to allow two different dlib::pipe objects
        to be connected together via a TCP connection.  This is best illustrated by
        the following short example.  In it we create two pipes, in and out.  When
        an object is enqueued into the out pipe it will be automatically sent
        through a TCP connection and once received at the other end it will be
        inserted into the in pipe.
    */
    dlib::pipe<int> in(4), out(4);

    // This bridge will listen on port 12345 for an incoming TCP connection.  Then
    // it will read data from that connection and put it into the in pipe.
    bridge b2(listen_on_port(12345), receive(in));

    // This bridge will initiate a TCP connection and then start dequeuing
    // objects from out and transmitting them over the connection.
    bridge b1(connect_to_ip_and_port("127.0.0.1", 12345), transmit(out));

    // As an aside, in a real program, each of these bridges and pipes would be in a
    // separate application.  But to make this example self contained they are both
    // right here.

    // Now let's put some things into the out pipe
    int value = 1;
    out.enqueue(value);

    value = 2;
    out.enqueue(value);

    value = 3;
    out.enqueue(value);

    // Now those 3 ints can be dequeued from the in pipe.  They will show up
    // in the same order they were inserted into the out pipe.
    in.dequeue(value);
    cout << "dequeued value: "<< value << endl;
    in.dequeue(value);
    cout << "dequeued value: "<< value << endl;
    in.dequeue(value);
    cout << "dequeued value: "<< value << endl;
}

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

void run_example_2(
)
{
    cout << "\n ---- Running example 2 ---- " << endl;

    /*
        This example makes a simple echo server on port 12345.  When an object
        is inserted into the out pipe it will be sent over a TCP connection, get
        put into the echo pipe and then immediately read out of the echo pipe and
        sent back over the TCP connection where it will finally be placed into the in
        pipe.
    */

    dlib::pipe<int> in(4), out(4), echo(4);

    // Just like TCP connections, a bridge can send data both directions.  The directionality
    // of a pipe is indicated by the receive() and transmit() type decorations.  Also, the order
    // they are listed doesn't matter.
    bridge echo_bridge(listen_on_port(12345), receive(echo), transmit(echo));

    // Note that you can also specify the ip and port as a string by using connect_to().
    bridge b1(connect_to("127.0.0.1:12345"), transmit(out), receive(in));

    int value = 1;
    out.enqueue(value);

    value = 2;
    out.enqueue(value);

    value = 3;
    out.enqueue(value);

    in.dequeue(value);
    cout << "dequeued value: "<< value << endl;
    in.dequeue(value);
    cout << "dequeued value: "<< value << endl;
    in.dequeue(value);
    cout << "dequeued value: "<< value << endl;
}

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

struct my_example_object
{
    /*
        All objects passing through a dlib::bridge must be serializable.  This
        means there must exist global functions called serialize() and deserialize()
        which can convert an object into a bit stream and then reverse the process.

        This example object illustrates how this is done.
    */

    int value;
    std::string str;
};

void serialize (const my_example_object& item, std::ostream& out)
{
    /*
        serialize() just needs to write the state of item to the output stream.
        You can do this however you like.  Below, I'm using the serialize functions
        for int and std::string which come with dlib.  But again, you can do whatever
        you want here.
    */
    dlib::serialize(item.value, out);
    dlib::serialize(item.str, out);
}

void deserialize (my_example_object& item, std::istream& in)
{
    /*
        deserialize() is just the inverse of serialize().  Again, you can do
        whatever you want here so long as it correctly reconstructs item.  This
        also means that deserialize() must always consume as many bytes as serialize()
        generates.
    */
    dlib::deserialize(item.value, in);
    dlib::deserialize(item.str, in);
}

// ----------------------------------------------------------------------------------------

void run_example_3(
)
{
    cout << "\n ---- Running example 3 ---- " << endl;

    /*
        In this example we will just send ints and my_example_object objects
        over a TCP connection.  Since we are sending more than one type of
        object through a pipe we will need to use the type_safe_union.
    */

    typedef type_safe_union<int, my_example_object> tsu_type;

    dlib::pipe<tsu_type> in(4), out(4);

    // Note that we don't have to start the listening bridge first.  If b2
    // fails to make a connection it will just keep trying until successful.
    bridge b2(connect_to("127.0.0.1:12345"), receive(in));
    // We don't have to configure a bridge in it's constructor.  If it's
    // more convenient we can do so by calling reconfigure() instead.
    bridge b1;
    b1.reconfigure(listen_on_port(12345), transmit(out));

    tsu_type msg;

    msg = 1;
    out.enqueue(msg);

    msg = 2;
    out.enqueue(msg);

    msg.get<my_example_object>().value = 3;
    msg.get<my_example_object>().str = "some string";
    out.enqueue(msg);

    // dequeue the three objects we sent and print them on the screen.
    for (int i = 0; i < 3; ++i)
    {
        in.dequeue(msg);
        if (msg.contains<int>())
        {
            cout << "dequeued int:    "<< msg.get<int>() << endl;
        }
        else if (msg.contains<my_example_object>())
        {
            cout << "dequeued struct: "<< msg.get<my_example_object>().value << "   "
                                       << msg.get<my_example_object>().str << endl;
        }
    }
}

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

void run_example_4(
)
{
    cout << "\n ---- Running example 4 ---- " << endl;

    /*
        This final example is the same as example 3 except we will also now be getting
        status messages from the bridges.  These bridge_status messages tell us the
        state of the TCP connection associated with a bridge.  Is it connected or not?
        Who it is connected to?

        The way you get these status messages is by ensuring that your receive pipe is
        capable of storing bridge_status objects.  If it is then the bridge will
        automatically insert bridge_status messages into your receive pipe whenever
        there is a status change.

        There are only two kinds of status changes.  The establishment of a connection
        or the closing of a connection.   Also, a connection which closes due to you
        calling clear(), reconfigure(), or destructing a bridge does not generate a
        status message since, in this case, you already know about it and just want
        the bridge to destroy itself as quickly as possible.
    */

    typedef type_safe_union<int, my_example_object, bridge_status> tsu_type;

    dlib::pipe<tsu_type> in(4), out(4);
    dlib::pipe<bridge_status> b1_status(4);

    // setup both bridges to have receive pipes capable of holding bridge_status messages.
    bridge b1(listen_on_port(12345), transmit(out), receive(b1_status));
    // Note that we can also use a hostname with connect_to() instead of supplying an IP address.
    bridge b2(connect_to("localhost:12345"), receive(in));

    tsu_type msg;
    bridge_status bs;

    // Once a connection is established it will generate a status message from each bridge.
    // Let's get those and print them.
    b1_status.dequeue(bs);
    cout << "bridge 1 status: is_connected: " << boolalpha << bs.is_connected << endl;
    cout << "bridge 1 status: foreign_ip:   " << bs.foreign_ip << endl;
    cout << "bridge 1 status: foreign_port: " << bs.foreign_port << endl;

    in.dequeue(msg);
    bs = msg.get<bridge_status>();
    cout << "bridge 2 status: is_connected: " << bs.is_connected << endl;
    cout << "bridge 2 status: foreign_ip:   " << bs.foreign_ip << endl;
    cout << "bridge 2 status: foreign_port: " << bs.foreign_port << endl;

    msg = 1;
    out.enqueue(msg);

    msg = 2;
    out.enqueue(msg);

    msg.get<my_example_object>().value = 3;
    msg.get<my_example_object>().str = "some string";
    out.enqueue(msg);

    // Read the 3 things we sent over the connection.
    for (int i = 0; i < 3; ++i)
    {
        in.dequeue(msg);
        if (msg.contains<int>())
        {
            cout << "dequeued int:    "<< msg.get<int>() << endl;
        }
        else if (msg.contains<my_example_object>())
        {
            cout << "dequeued struct: "<< msg.get<my_example_object>().value << "   "
                                       << msg.get<my_example_object>().str << endl;
        }
    }

    // cause bridge 1 to shutdown completely.  This will close the connection and
    // therefore bridge 2 will generate a status message indicating the connection
    // just closed.
    b1.clear();
    in.dequeue(msg);
    bs = msg.get<bridge_status>();
    cout << "bridge 1 status: is_connected: " << bs.is_connected << endl;
    cout << "bridge 1 status: foreign_ip:   " << bs.foreign_ip << endl;
    cout << "bridge 1 status: foreign_port: " << bs.foreign_port << endl;
}

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------


dlib C++ Library -

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example illustrating the use of the Bulk Synchronous Parallel (BSP)
    processing tools from the dlib C++ Library.  These tools allow you to easily setup a
    number of processes running on different computers which cooperate to compute some
    result.

    In this example, we will use the BSP tools to find the minimizer of a simple function.
    In particular, we will setup a nested grid search where different parts of the grid are
    searched in parallel by different processes.

    To run this program you should do the following (supposing you want to use three BSP
    nodes to do the grid search and, to make things easy, you will run them all on your
    current computer):

        1. Open three command windows and navigate each to the folder containing the
           compiled bsp_ex.cpp program.  Let's call these window 1, window 2, and window 3.

        2. In window 1 execute this command:
             ./bsp_ex -l12345
           This will start a listening BSP node that listens on port 12345.  The BSP node
           won't do anything until we tell all the nodes to start running in step 4 below.

        3.  In window 2 execute this command:
             ./bsp_ex -l12346
           This starts another listening BSP node.  Note that since we are running this
           example all on one computer you need to use different listening port numbers
           for each listening node.

        4. In window 3 execute this command:
             ./bsp_ex localhost:12345 localhost:12346
           This will start a BSP node that connects to the others and gets them all running.
           Additionally, as you will see when we go over the code below, it will also print
           the final output of the BSP process, which is the minimizer of our test function.
           Once it terminates, all the other BSP nodes will also automatically terminate.
*/

#include <dlib/cmd_line_parser.h>
#include <dlib/bsp.h>
#include <dlib/matrix.h>

#include <iostream>

using namespace std;
using namespace dlib;

// ----------------------------------------------------------------------------------------

// These are the functions executed by the BSP nodes.  They are defined below.
void bsp_job_node_0      (bsp_context& bsp, double& min_value, double& optimal_x);
void bsp_job_other_nodes (bsp_context& bsp, long grid_resolution);

// ----------------------------------------------------------------------------------------

int main(int argc, char** argv)
{
    try
    {
        // Use the dlib command_line_parser to parse the command line.  See the
        // compress_stream_ex.cpp example program for an introduction to the command line
        // parser.
        command_line_parser parser;
        parser.add_option("h","Display this help message.");
        parser.add_option("l","Run as a listening BSP node.",1);
        parser.parse(argc, argv);
        parser.check_option_arg_range("l", 1, 65535);

        // Print a help message if the user gives -h on the command line.
        if (parser.option("h"))
        {
            // display all the command line options
            cout << "Usage: bsp_ex (-l port | <list of hosts>)\n";
            parser.print_options();
            return 0;
        }

        // If the command line contained -l
        if (parser.option("l"))
        {
            // Get the argument to -l
            const unsigned short listening_port = get_option(parser, "l", 0);
            cout << "Listening on port " << listening_port << endl;

            const long grid_resolution = 100;

            // bsp_listen() starts a listening BSP job.  This means that it will wait until
            // someone calls bsp_connect() and connects to it before it starts running.
            // However, once it starts it will call bsp_job_other_nodes() which will then
            // do all the real work.
            //
            // The first argument is the port to listen on.  The second argument is the
            // function which it should run to do all the work.  The other arguments are
            // optional and allow you to pass values into the bsp_job_other_nodes()
            // routine.  In this case, we are passing the grid_resolution to
            // bsp_job_other_nodes().
            bsp_listen(listening_port, bsp_job_other_nodes, grid_resolution);
        }
        else
        {
            if (parser.number_of_arguments() == 0)
            {
                cout << "You must give some listening BSP nodes as arguments to this program!" << endl;
                return 0;
            }

            // Take the hostname:port strings from the command line and put them into the
            // vector of hosts.
            std::vector<network_address> hosts;
            for (unsigned long i = 0; i < parser.number_of_arguments(); ++i)
                hosts.push_back(parser[i]);

            double min_value, optimal_x;

            // Calling bsp_connect() does two things.  First, it tells all the BSP jobs
            // listed in the hosts vector to start running.  Second, it starts a locally
            // running BSP job that executes bsp_job_node_0() and passes it any arguments
            // listed after bsp_job_node_0.  So in this case it passes it the 3rd and 4th
            // arguments.
            //
            // Note also that we use dlib::ref() which causes these arguments to be passed
            // by reference.  This means that bsp_job_node_0() will be able to modify them
            // and we will see the results here in main() after bsp_connect() terminates.
            bsp_connect(hosts, bsp_job_node_0, dlib::ref(min_value), dlib::ref(optimal_x));

            // bsp_connect() and bsp_listen() block until all the BSP nodes have terminated.
            // Therefore, we won't get to this part of the code until the BSP processing
            // has finished.  But once we do we can print the results like so:
            cout << "optimal_x: "<< optimal_x << endl;
            cout << "min_value: "<< min_value << endl;
        }

    }
    catch (std::exception& e)
    {
        cout << "error in main(): " << e.what() << endl;
    }
}

// ----------------------------------------------------------------------------------------

/*
    We are going to use the BSP tools to find the minimum of f(x).  Note that
    it's minimizer is at x == 2.0.
*/
double f (double x)
{
    return std::pow(x-2.0, 2.0);
}

// ----------------------------------------------------------------------------------------

void bsp_job_node_0 (bsp_context& bsp, double& min_value, double& optimal_x)
{
    // This function is called by bsp_connect().  In general, any BSP node can do anything
    // you want.  However, in this example we use this node as a kind of controller for the
    // other nodes.  In particular, since we are doing a nested grid search, this node's
    // job will be to collect results from other nodes and then decide which part of the
    // number line subsequent iterations should focus on.
    //
    // Also, each BSP node has a node ID number.  You can determine it by calling
    // bsp.node_id().  However, the node spawned by a call to bsp_connect() always has a
    // node ID of 0 (hence the name of this function).  Additionally, all functions
    // executing a BSP task always take a bsp_context as their first argument.  This object
    // is the interface that allows BSP jobs to communicate with each other.

    // Now let's get down to work.  Recall that we are trying to find the x value that
    // minimizes the f(x) defined above.  The grid search will start out by considering the
    // range [-1e100, 1e100] on the number line.  It will progressively narrow this window
    // until it has located the minimizer of f(x) to within 1e-15 of its true value.
    double left = -1e100;
    double right = 1e100;

    min_value = std::numeric_limits<double>::infinity();
    double interval_width = std::abs(right-left);

    // keep going until the window is smaller than 1e-15.
    while (right-left > 1e-15)
    {
        // At the start of each loop, we broadcast the current window to all the other BSP
        // nodes.  They will each search a separate part of the window and then report back
        // the smallest values they found in their respective sub-windows.
        //
        // Also, you can send/broadcast/receive anything that has global serialize() and
        // deserialize() routines defined for it.  Dlib comes with serialization functions
        // for a lot of types by default, so we don't have to define anything for this
        // example program.  However, if you want to send an object you defined then you
        // will need to write your own serialization functions.  See the documentation for
        // dlib's serialize() routine or the bridge_ex.cpp example program for an example.
        bsp.broadcast(left);
        bsp.broadcast(right);

        // Receive the smallest values found from the other BSP nodes.
        for (unsigned int k = 1; k < bsp.number_of_nodes(); ++k)
        {
            // The other nodes will send std::pairs of x/f(x) values.  So that is what we
            // receive.
            std::pair<double,double> val;
            bsp.receive(val);
            // save the smallest result.
            if (val.second < min_value)
            {
                min_value = val.second;
                optimal_x = val.first;
            }
        }

        // Now narrow the search window by half.
        interval_width *= 0.5;
        left  = optimal_x - interval_width/2;
        right = optimal_x + interval_width/2;
    }
}

// ----------------------------------------------------------------------------------------

void bsp_job_other_nodes (bsp_context& bsp, long grid_resolution)
{
    // This is the BSP job called by bsp_listen().  In these jobs we will receive window
    // ranges from the controller node, search our sub-window, and then report back the
    // location of the best x value we found.

    double left, right;

    // The try_receive() function will either return true with the next message or return
    // false if there aren't any more messages in flight between nodes and all other BSP
    // nodes are blocked on calls to receive or have terminated.  That is, try_receive()
    // only returns false if waiting for a message would result in all the BSP nodes
    // waiting forever.
    //
    // Therefore, try_receive() serves both as a message receiving tool as well as an
    // implicit form of barrier synchronization.  In this case, we use it to know when to
    // terminate.  That is, we know it is time to terminate if all the messages between
    // nodes have been received and all nodes are inactive due to either termination or
    // being blocked on a receive call.  This will happen once the controller node above
    // terminates since it will result in all the other nodes inevitably becoming blocked
    // on this try_receive() line with no messages to process.
    while (bsp.try_receive(left))
    {
        bsp.receive(right);

        // Compute a sub-window range for us to search.  We use our node's ID value and the
        // total number of nodes to select a subset of the [left, right] window.  We will
        // store the grid points from our sub-window in values_to_check.
        const double l = (bsp.node_id()-1)/(bsp.number_of_nodes()-1.0);
        const double r = bsp.node_id()    /(bsp.number_of_nodes()-1.0);
        const double width = right-left;
        // Select grid_resolution number of points which are linearly spaced throughout our
        // sub-window.
        const matrix<double> values_to_check = linspace(left+l*width, left+r*width, grid_resolution);

        // Search all the points in values_to_check and figure out which one gives the
        // minimum value of f().
        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);
            }
        }

        // Report back the identity of the best point we found in our sub-window.  Note
        // that the second argument to send(), the 0, is the node ID to send to.  In this
        // case we send our results back to the controller node.
        bsp.send(make_pair(best_x, best_val), 0);
    }
}

// ----------------------------------------------------------------------------------------


dlib C++ Library - svm_c_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example illustrating the use of the support vector machine
    utilities from the dlib C++ Library.  In particular, we show how to use the
    C parametrization of the SVM in this example.

    This example creates a simple set of data to train on and then shows
    you how to use the cross validation and svm training functions
    to find a good decision function that can classify examples in our
    data set.

    The data used in this example will be 2 dimensional data and will
    come from a distribution where points with a distance less than 10
    from the origin are labeled +1 and all other points are labeled
    as -1.

*/

#include <iostream>
#include <dlib/svm.h>

using namespace std;
using namespace dlib;

int main()
{
    // The svm functions use column vectors to contain a lot of the data on
    // which they operate. So the first thing we do here is declare a convenient
    // typedef.

    // This typedef declares a matrix with 2 rows and 1 column.  It will be the
    // object that contains each of our 2 dimensional samples.   (Note that if
    // you wanted more than 2 features in this vector you can simply change the
    // 2 to something else.  Or if you don't know how many features you want
    // until runtime then you can put a 0 here and use the matrix.set_size()
    // member function)
    typedef matrix<double, 2, 1> sample_type;

    // This is a typedef for the type of kernel we are going to use in this
    // example.  In this case I have selected the radial basis kernel that can
    // operate on our 2D sample_type objects.  You can use your own custom
    // kernels with these tools as well, see custom_trainer_ex.cpp for an
    // example.
    typedef radial_basis_kernel<sample_type> kernel_type;

    // Now we make objects to contain our samples and their respective labels.
    std::vector<sample_type> samples;
    std::vector<double> labels;

    // Now let's put some data into our samples and labels objects.  We do this
    // by looping over a bunch of points and labeling them according to their
    // distance from the origin.
    for (int r = -20; r <= 20; ++r)
    {
        for (int c = -20; c <= 20; ++c)
        {
            sample_type samp;
            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) <= 10)
                labels.push_back(+1);
            else
                labels.push_back(-1);

        }
    }

    // Here we normalize all the samples by subtracting their mean and dividing
    // by their standard deviation.  This is generally a good idea since it
    // often heads off numerical stability problems and also prevents one large
    // feature from smothering others.  Doing this doesn't matter much in this
    // example so I'm just doing this here so you can see an easy way to
    // accomplish it.
    vector_normalizer<sample_type> normalizer;
    // Let the normalizer learn the mean and standard deviation of the samples.
    normalizer.train(samples);
    // now normalize each sample
    for (unsigned long i = 0; i < samples.size(); ++i)
        samples[i] = normalizer(samples[i]);

    // Now that we have some data we want to train on it.  However, there are
    // two parameters to the training.  These are the C and gamma parameters.
    // Our choice for these parameters will influence how good the resulting
    // decision function is.  To test how good a particular choice of these
    // parameters are we can use the cross_validate_trainer() function to perform
    // n-fold cross validation on our training data.  However, there is a
    // problem with the way we have sampled our distribution above.  The problem
    // is that there is a definite ordering to the samples.  That is, the first
    // half of the samples look like they are from a different distribution than
    // the second half.  This would screw up the cross validation process but we
    // can fix it by randomizing the order of the samples with the following
    // function call.
    randomize_samples(samples, labels);

    // here we make an instance of the svm_c_trainer object that uses our kernel
    // type.
    svm_c_trainer<kernel_type> trainer;

    // Now we loop over some different C and gamma values to see how good they
    // are.  Note that this is a very simple way to try out a few possible
    // parameter choices.  You should look at the model_selection_ex.cpp program
    // for examples of more sophisticated strategies for determining good
    // parameter choices.
    cout << "doing cross validation" << endl;
    for (double gamma = 0.00001; gamma <= 1; gamma *= 5)
    {
        for (double C = 1; C < 100000; C *= 5)
        {
            // tell the trainer the parameters we want to use
            trainer.set_kernel(kernel_type(gamma));
            trainer.set_c(C);

            cout << "gamma: " << gamma << "    C: " << C;
            // Print out the cross validation accuracy for 3-fold cross validation using
            // the current gamma and C.  cross_validate_trainer() returns a row vector.
            // The first element of the vector is the fraction of +1 training examples
            // correctly classified and the second number is the fraction of -1 training
            // examples correctly classified.
            cout << "     cross validation accuracy: "
                 << cross_validate_trainer(trainer, samples, labels, 3);
        }
    }

    // From looking at the output of the above loop it turns out that good
    // values for C and gamma for this problem are 5 and 0.15625 respectively.
    // So that is what we will use.

    // Now we train on the full set of data and obtain the resulting decision
    // function.  The decision function will return values >= 0 for samples it
    // predicts are in the +1 class and numbers < 0 for samples it predicts to
    // be in the -1 class.
    trainer.set_kernel(kernel_type(0.15625));
    trainer.set_c(5);
    typedef decision_function<kernel_type> dec_funct_type;
    typedef normalized_function<dec_funct_type> funct_type;

    // Here we are making an instance of the normalized_function object.  This
    // object provides a convenient way to store the vector normalization
    // information along with the decision function we are going to learn.
    funct_type learned_function;
    learned_function.normalizer = normalizer;  // save normalization information
    learned_function.function = trainer.train(samples, labels); // perform the actual SVM training and save the results

    // print out the number of support vectors in the resulting decision function
    cout << "\nnumber of support vectors in our learned_function is "
         << learned_function.function.basis_vectors.size() << endl;

    // Now let's try this decision_function on some samples we haven't seen before.
    sample_type sample;

    sample(0) = 3.123;
    sample(1) = 2;
    cout << "This is a +1 class example, the classifier output is " << learned_function(sample) << endl;

    sample(0) = 3.123;
    sample(1) = 9.3545;
    cout << "This is a +1 class example, the classifier output is " << learned_function(sample) << endl;

    sample(0) = 13.123;
    sample(1) = 9.3545;
    cout << "This is a -1 class example, the classifier output is " << learned_function(sample) << endl;

    sample(0) = 13.123;
    sample(1) = 0;
    cout << "This is a -1 class example, the classifier output is " << learned_function(sample) << endl;

    // We can also train a decision function that reports a well conditioned
    // probability instead of just a number > 0 for the +1 class and < 0 for the
    // -1 class.  An example of doing that follows:
    typedef probabilistic_decision_function<kernel_type> probabilistic_funct_type;
    typedef normalized_function<probabilistic_funct_type> pfunct_type;

    pfunct_type learned_pfunct;
    learned_pfunct.normalizer = normalizer;
    learned_pfunct.function = train_probabilistic_decision_function(trainer, samples, labels, 3);
    // Now we have a function that returns the probability that a given sample is of the +1 class.

    // print out the number of support vectors in the resulting decision function.
    // (it should be the same as in the one above)
    cout << "\nnumber of support vectors in our learned_pfunct is "
         << learned_pfunct.function.decision_funct.basis_vectors.size() << endl;

    sample(0) = 3.123;
    sample(1) = 2;
    cout << "This +1 class example should have high probability.  Its probability is: "
         << learned_pfunct(sample) << endl;

    sample(0) = 3.123;
    sample(1) = 9.3545;
    cout << "This +1 class example should have high probability.  Its probability is: "
         << learned_pfunct(sample) << endl;

    sample(0) = 13.123;
    sample(1) = 9.3545;
    cout << "This -1 class example should have low probability.  Its probability is: "
         << learned_pfunct(sample) << endl;

    sample(0) = 13.123;
    sample(1) = 0;
    cout << "This -1 class example should have low probability.  Its probability is: "
         << learned_pfunct(sample) << endl;

    // Another thing that is worth knowing is that just about everything in dlib
    // is serializable.  So for example, you can save the learned_pfunct object
    // to disk and recall it later like so:
    serialize("saved_function.dat") << learned_pfunct;

    // Now let's open that file back up and load the function object it contains.
    deserialize("saved_function.dat") >> learned_pfunct;

    // Note that there is also an example program that comes with dlib called
    // the file_to_code_ex.cpp example.  It is a simple program that takes a
    // file and outputs a piece of C++ code that is able to fully reproduce the
    // file's contents in the form of a std::string object.  So you can use that
    // along with the std::istringstream to save learned decision functions
    // inside your actual C++ code files if you want.

    // Lastly, note that the decision functions we trained above involved well
    // over 200 basis vectors.  Support vector machines in general tend to find
    // decision functions that involve a lot of basis vectors.  This is
    // significant because the more basis vectors in a decision function, the
    // longer it takes to classify new examples.  So dlib provides the ability
    // to find an approximation to the normal output of a trainer using fewer
    // basis vectors.

    // Here we determine the cross validation accuracy when we approximate the
    // output using only 10 basis vectors.  To do this we use the reduced2()
    // function.  It takes a trainer object and the number of basis vectors to
    // use and returns a new trainer object that applies the necessary post
    // processing during the creation of decision function objects.
    cout << "\ncross validation accuracy with only 10 support vectors: "
         << cross_validate_trainer(reduced2(trainer,10), samples, labels, 3);

    // Let's print out the original cross validation score too for comparison.
    cout << "cross validation accuracy with all the original support vectors: "
         << cross_validate_trainer(trainer, samples, labels, 3);

    // When you run this program you should see that, for this problem, you can
    // reduce the number of basis vectors down to 10 without hurting the cross
    // validation accuracy.

    // To get the reduced decision function out we would just do this:
    learned_function.function = reduced2(trainer,10).train(samples, labels);
    // And similarly for the probabilistic_decision_function:
    learned_pfunct.function = train_probabilistic_decision_function(reduced2(trainer,10), samples, labels, 3);


dlib C++ Library - compress_stream_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example illustrating the use of the compress_stream and
    cmd_line_parser components from the dlib C++ Library.

    This example implements a simple command line compression utility.

    The output from the program when the -h option is given is:

        Usage: compress_stream_ex (-c|-d|-l) --in input_file --out output_file
        Options:
          -c            Indicates that we want to compress a file.
          -d            Indicates that we want to decompress a file.
          --in <arg>    This option takes one argument which specifies the name of the
                        file we want to compress/decompress.
          --out <arg>   This option takes one argument which specifies the name of the
                        output file.

        Miscellaneous Options:
          -h            Display this help message.
          -l <arg>      Set the compression level [1-3], 3 is max compression, default
                        is 2.

*/

#include <dlib/compress_stream.h>
#include <dlib/cmd_line_parser.h>
#include <iostream>
#include <fstream>
#include <string>

// I am making a typedefs for the versions of compress_stream I want to use.
typedef dlib::compress_stream::kernel_1da cs1;
typedef dlib::compress_stream::kernel_1ea cs2;
typedef dlib::compress_stream::kernel_1ec cs3;

using namespace std;
using namespace dlib;

int main(int argc, char** argv)
{
    try
    {
        command_line_parser parser;

        // first I will define the command line options I want.
        // Add a -c option and tell the parser what the option is for.
        parser.add_option("c","Indicates that we want to compress a file.");
        parser.add_option("d","Indicates that we want to decompress a file.");
        // add a --in option that takes 1 argument
        parser.add_option("in","This option takes one argument which specifies the name of the file we want to compress/decompress.",1);
        // add a --out option that takes 1 argument
        parser.add_option("out","This option takes one argument which specifies the name of the output file.",1);
        // In the code below, we use the parser.print_options() method to print all our
        // options to the screen.  We can tell it that we would like some options to be
        // grouped together by calling set_group_name() before adding those options.  In
        // general, you can make as many groups as you like by calling set_group_name().
        // However, here we make only one named group.
        parser.set_group_name("Miscellaneous Options");
        parser.add_option("h","Display this help message.");
        parser.add_option("l","Set the compression level [1-3], 3 is max compression, default is 2.",1);

        // now I will parse the command line
        parser.parse(argc,argv);

        // Now I will use the parser to validate some things about the command line.
        // If any of the following checks fail then an exception will be thrown and it will
        // contain a message that tells the user what the problem was.

        // First I want to check that none of the options were given on the command line
        // more than once.  To do this I define an array that contains the options
        // that shouldn't appear more than once and then I just call check_one_time_options()
        const char* one_time_opts[] = {"c", "d", "in", "out", "h", "l"};
        parser.check_one_time_options(one_time_opts);
        // Here I'm checking that the user didn't pick both the c and d options at the
        // same time.
        parser.check_incompatible_options("c", "d");

        // Here I'm checking that the argument to the l option is an integer in the range 1 to 3.
        // That is, it should be convertible to an int by dlib::string_assign and be either
        // 1, 2, or 3.  Note that if you wanted to allow floating point values in the range 1 to
        // 3 then you could give a range 1.0 to 3.0 or explicitly supply a type of float or double
        // to the template argument of the check_option_arg_range() function.
        parser.check_option_arg_range("l", 1, 3);

        // The 'l' option is a sub-option of the 'c' option. That is, you can only select the
        // compression level when compressing.  This command below checks that the listed
        // sub options are always given in the presence of their parent options.
        const char* c_sub_opts[] = {"l"};
        parser.check_sub_options("c", c_sub_opts);

        // check if the -h option was given on the command line
        if (parser.option("h"))
        {
            // display all the command line options
            cout << "Usage: compress_stream_ex (-c|-d|-l) --in input_file --out output_file\n";
            // This function prints out a nicely formatted list of
            // all the options the parser has
            parser.print_options();
            return 0;
        }

        // Figure out what the compression level should be.  If the user didn't supply
        // this command line option then a value of 2 will be used.
        int compression_level = get_option(parser,"l",2);

        // make sure one of the c or d options was given
        if (!parser.option("c") && !parser.option("d"))
        {
            cout << "Error in command line:\n   You must specify either the c option or the d option.\n";
            cout << "\nTry the -h option for more information." << endl;
            return 0;
        }

        string in_file;
        string out_file;

        // check if the user told us the input file and if they did then
        // get the file name
        if (parser.option("in"))
        {
            in_file = parser.option("in").argument();
        }
        else
        {
            cout << "Error in command line:\n   You must specify an input file.\n";
            cout << "\nTry the -h option for more information." << endl;
            return 0;
        }

        // check if the user told us the output file and if they did then
        // get the file name
        if (parser.option("out"))
        {
            out_file = parser.option("out").argument();
        }
        else
        {
            cout << "Error in command line:\n   You must specify an output file.\n";
            cout << "\nTry the -h option for more information." << endl;
            return 0;
        }

        // open the files we will be reading from and writing to
        ifstream fin(in_file.c_str(),ios::binary);
        ofstream fout(out_file.c_str(),ios::binary);

        // make sure the files opened correctly
        if (!fin)
        {
            cout << "Error opening file " << in_file << ".\n";
            return 0;
        }

        if (!fout)
        {
            cout << "Error creating file " << out_file << ".\n";
            return 0;
        }

        // now perform the actual compression or decompression.
        if (parser.option("c"))
        {
            // save the compression level to the output file
            serialize(compression_level, fout);

            switch (compression_level)
            {
                case 1:
                    {
                        cs1 compressor;
                        compressor.compress(fin,fout);
                    }break;
                case 2:
                    {
                        cs2 compressor;
                        compressor.compress(fin,fout);
                    }break;
                case 3:
                    {
                        cs3 compressor;
                        compressor.compress(fin,fout);
                    }break;
            }
        }
        else
        {
            // obtain the compression level from the input file
            deserialize(compression_level, fin);

            switch (compression_level)
            {
                case 1:
                    {
                        cs1 compressor;
                        compressor.decompress(fin,fout);
                    }break;
                case 2:
                    {
                        cs2 compressor;
                        compressor.decompress(fin,fout);
                    }break;
                case 3:
                    {
                        cs3 compressor;
                        compressor.decompress(fin,fout);
                    }break;
                default:
                    {
                        cout << "Error in compressed file, invalid compression level" << endl;
                    }break;
            }
        }

    }
    catch (exception& e)
    {
        // Note that this will catch any cmd_line_parse_error exceptions and print
        // the default message.
        cout << e.what() << endl;


dlib C++ Library - config_reader_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example illustrating the use of the config_reader component
    from the dlib C++ Library.

    This example uses the config_reader to load a config file and then
    prints out the values of various fields in the file.
*/

#include <dlib/config_reader.h>
#include <iostream>
#include <fstream>
#include <vector>

using namespace std;
using namespace dlib;

// ----------------------------------------------------------------------------------------
// For reference, the contents of the config file used in this example is reproduced below:
/*

# This is an example config file.  Note that # is used to create a comment.

# At its most basic level a config file is just a bunch of key/value pairs.
# So for example:
key1 = value2
dlib = a C++ library

# You can also define "sub blocks" in your config files like so
user1
{
    # Inside a sub block you can list more key/value pairs.
    id = 42
    name = davis

    # you can also nest sub-blocks as deep as you want
    details
    {
        editor = vim
        home_dir = /home/davis
    }
}
user2 {
    id = 1234
    name = joe
    details {
        editor = emacs
        home_dir = /home/joe
    }
}

*/
// ----------------------------------------------------------------------------------------

void print_config_reader_contents (
    const config_reader& cr,
    int depth = 0
);
/*
    This is a simple function that recursively walks through everything in
    a config reader and prints it to the screen.
*/

// ----------------------------------------------------------------------------------------

int main()
{
    try
    {
        config_reader cr("config.txt");

        // Use our recursive function to print everything in the config file.
        print_config_reader_contents(cr);

        // Now let's access some of the fields of the config file directly.  You
        // use [] for accessing key values and .block() for accessing sub-blocks.

        // Print out the string value assigned to key1 in the config file
        cout << cr["key1"] << endl;

        // Print out the name field inside the user1 sub-block
        cout << cr.block("user1")["name"] << endl;
        // Now print out the editor field in the details block
        cout << cr.block("user1").block("details")["editor"] << endl;

        // Note that you can use get_option() to easily convert fields into
        // non-string types.  For example, the config file has an integer id
        // field that can be converted into an int like so:
        int id1 = get_option(cr,"user1.id",0);
        int id2 = get_option(cr,"user2.id",0);
        cout << "user1's id is " << id1 << endl;
        cout << "user2's id is " << id2 << endl;
        // The third argument to get_option() is the default value returned if
        // the config reader doesn't contain a corresponding entry.  So for
        // example, the following prints 321 since there is no user3.
        int id3 = get_option(cr,"user3.id",321);
        cout << "user3's id is " << id3 << endl;

    }
    catch (exception& e)
    {
        // Finally, note that the config_reader throws exceptions if the config
        // file is corrupted or if you ask it for a key or block that doesn't exist.
        // Here we print out any such error messages.
        cout << e.what() << endl;
    }
}

// ----------------------------------------------------------------------------------------

void print_config_reader_contents (
    const config_reader& cr,
    int depth
)
{
    // Make a string with depth*4 spaces in it.
    const string padding(depth*4, ' ');

    // We can obtain a list of all the keys and sub-blocks defined
    // at the current level in the config reader like so:
    vector<string> keys, blocks;
    cr.get_keys(keys);
    cr.get_blocks(blocks);

    // Now print all the key/value pairs
    for (unsigned long i = 0; i < keys.size(); ++i)
        cout << padding << keys[i] << " = " << cr[keys[i]] << endl;

    // Now print all the sub-blocks.
    for (unsigned long i = 0; i < blocks.size(); ++i)
    {
        // First print the block name
        cout << padding << blocks[i] << " { " << endl;
        // Now recursively print the contents of the sub block.  Note that the cr.block()
        // function returns another config_reader that represents the sub-block.
        print_config_reader_contents(cr.block(blocks[i]), depth+1);
        cout << padding << "}" << endl;
    }
}

// ----------------------------------------------------------------------------------------


dlib C++ Library - custom_trainer_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*
    This example program shows you how to create your own custom binary classification
    trainer object and use it with the multiclass classification tools in the dlib C++
    library.  This example assumes you have already become familiar with the concepts
    introduced in the multiclass_classification_ex.cpp example program.

    In this example we will create a very simple trainer object that takes a binary
    classification problem and produces a decision rule which says a test point has the
    same class as whichever centroid it is closest to.

    The multiclass training dataset will consist of four classes.  Each class will be a blob
    of points in one of the quadrants of the cartesian plane.   For fun, we will use
    std::string labels and therefore the labels of these classes will be the following:
        "upper_left",
        "upper_right",
        "lower_left",
        "lower_right"
*/

#include <dlib/svm_threaded.h>

#include <iostream>
#include <vector>

#include <dlib/rand.h>

using namespace std;
using namespace dlib;

// Our data will be 2-dimensional data. So declare an appropriate type to contain these points.
typedef matrix<double,2,1> sample_type;

// ----------------------------------------------------------------------------------------

struct custom_decision_function
{
    /*!
        WHAT THIS OBJECT REPRESENTS
            This object is the representation of our binary decision rule.
    !*/

    // centers of the two classes
    sample_type positive_center, negative_center;

    double operator() (
        const sample_type& x
    ) const
    {
        // if x is closer to the positive class then return +1
        if (length(positive_center - x) < length(negative_center - x))
            return +1;
        else
            return -1;
    }
};

// Later on in this example we will save our decision functions to disk.  This
// pair of routines is needed for this functionality.
void serialize (const custom_decision_function& item, std::ostream& out)
{
    // write the state of item to the output stream
    serialize(item.positive_center, out);
    serialize(item.negative_center, out);
}

void deserialize (custom_decision_function& item, std::istream& in)
{
    // read the data from the input stream and store it in item
    deserialize(item.positive_center, in);
    deserialize(item.negative_center, in);
}

// ----------------------------------------------------------------------------------------

class simple_custom_trainer
{
    /*!
        WHAT THIS OBJECT REPRESENTS
            This is our example custom binary classifier trainer object.  It simply
            computes the means of the +1 and -1 classes, puts them into our
            custom_decision_function, and returns the results.

            Below we define the train() function.  I have also included the
            requires/ensures definition for a generic binary classifier's train()
    !*/
public:

    custom_decision_function train (
        const std::vector<sample_type>& samples,
        const std::vector<double>& labels
    ) const
    /*!
        requires
            - is_binary_classification_problem(samples, labels) == true
              (e.g. labels consists of only +1 and -1 values, samples.size() == labels.size())
        ensures
            - returns a decision function F with the following properties:
                - if (new_x is a sample predicted have +1 label) then
                    - F(new_x) >= 0
                - else
                    - F(new_x) < 0
    !*/
    {
        sample_type positive_center, negative_center;

        // compute sums of each class
        positive_center = 0;
        negative_center = 0;
        for (unsigned long i = 0; i < samples.size(); ++i)
        {
            if (labels[i] == +1)
                positive_center += samples[i];
            else // this is a -1 sample
                negative_center += samples[i];
        }

        // divide by number of +1 samples
        positive_center /= sum(mat(labels) == +1);
        // divide by number of -1 samples
        negative_center /= sum(mat(labels) == -1);

        custom_decision_function df;
        df.positive_center = positive_center;
        df.negative_center = negative_center;

        return df;
    }
};

// ----------------------------------------------------------------------------------------

void generate_data (
    std::vector<sample_type>& samples,
    std::vector<string>& labels
);
/*!
    ensures
        - make some four class data as described above.
        - each class will have 50 samples in it
!*/

// ----------------------------------------------------------------------------------------

int main()
{
    std::vector<sample_type> samples;
    std::vector<string> labels;

    // First, get our labeled set of training data
    generate_data(samples, labels);

    cout << "samples.size(): "<< samples.size() << endl;

    // Define the trainer we will use.  The second template argument specifies the type
    // of label used, which is string in this case.
    typedef one_vs_one_trainer<any_trainer<sample_type>, string> ovo_trainer;

    ovo_trainer trainer;

    // Now tell the one_vs_one_trainer that, by default, it should use the simple_custom_trainer
    // to solve the individual binary classification subproblems.
    trainer.set_trainer(simple_custom_trainer());

    // Next, to make things a little more interesting, we will setup the one_vs_one_trainer
    // to use kernel ridge regression to solve the upper_left vs lower_right binary classification
    // subproblem.
    typedef radial_basis_kernel<sample_type> rbf_kernel;
    krr_trainer<rbf_kernel> rbf_trainer;
    rbf_trainer.set_kernel(rbf_kernel(0.1));
    trainer.set_trainer(rbf_trainer, "upper_left", "lower_right");

    // Now let's do 5-fold cross-validation using the one_vs_one_trainer we just setup.
    // As an aside, always shuffle the order of the samples before doing cross validation.
    // For a discussion of why this is a good idea see the svm_ex.cpp example.
    randomize_samples(samples, labels);
    cout << "cross validation: \n" << cross_validate_multiclass_trainer(trainer, samples, labels, 5) << endl;
    // This dataset is very easy and everything is correctly classified.  Therefore, the output of
    // cross validation is the following confusion matrix.
    /*
        50  0  0  0
         0 50  0  0
         0  0 50  0
         0  0  0 50
    */

    // We can also obtain the decision rule as always.
    one_vs_one_decision_function<ovo_trainer> df = trainer.train(samples, labels);

    cout << "predicted label: "<< df(samples[0])  << ", true label: "<< labels[0] << endl;
    cout << "predicted label: "<< df(samples[90]) << ", true label: "<< labels[90] << endl;
    // The output is:
    /*
        predicted label: upper_right, true label: upper_right
        predicted label: lower_left, true label: lower_left
    */

    // Finally, let's save our multiclass decision rule to disk.  Remember that we have
    // to specify the types of binary decision function used inside the one_vs_one_decision_function.
    one_vs_one_decision_function<ovo_trainer,
            custom_decision_function,                             // This is the output of the simple_custom_trainer
            decision_function<radial_basis_kernel<sample_type> >  // This is the output of the rbf_trainer
        > df2, df3;

    df2 = df;
    // save to a file called df.dat
    serialize("df.dat") << df2;

    // load the function back in from disk and store it in df3.
    deserialize("df.dat") >> df3;

    // Test df3 to see that this worked.
    cout << endl;
    cout << "predicted label: "<< df3(samples[0])  << ", true label: "<< labels[0] << endl;
    cout << "predicted label: "<< df3(samples[90]) << ", true label: "<< labels[90] << endl;
    // Test df3 on the samples and labels and print the confusion matrix.
    cout << "test deserialized function: \n" << test_multiclass_decision_function(df3, samples, labels) << endl;

}

// ----------------------------------------------------------------------------------------

void generate_data (
    std::vector<sample_type>& samples,
    std::vector<string>& labels
)
{
    const long num = 50;

    sample_type m;

    dlib::rand rnd;

    // add some points in the upper right quadrant
    m = 10, 10;
    for (long i = 0; i < num; ++i)
    {
        samples.push_back(m + randm(2,1,rnd));
        labels.push_back("upper_right");
    }

    // add some points in the upper left quadrant
    m = -10, 10;
    for (long i = 0; i < num; ++i)
    {
        samples.push_back(m + randm(2,1,rnd));
        labels.push_back("upper_left");
    }

    // add some points in the lower right quadrant
    m = 10, -10;
    for (long i = 0; i < num; ++i)
    {
        samples.push_back(m + randm(2,1,rnd));
        labels.push_back("lower_right");
    }

    // add some points in the lower left quadrant
    m = -10, -10;
    for (long i = 0; i < num; ++i)
    {
        samples.push_back(m + randm(2,1,rnd));
        labels.push_back("lower_left");
    }

}

// ----------------------------------------------------------------------------------------


dlib C++ Library - dir_nav_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example illustrating the use of the dir_nav component from the dlib C++ Library.
    It prints a listing of all directories and files in the users
    current working directory or the directory specified on the command line.

*/

#include <iostream>
#include <iomanip>
#include <dlib/dir_nav.h>
#include <vector>
#include <algorithm>

using namespace std;
using namespace dlib;

int main(int argc, char** argv)
{
    try
    {
        string loc;
        if (argc == 2)
            loc = argv[1];
        else
            loc = ".";  // if no argument is given then use the current working dir.

        directory test(loc);

        cout << "directory: " << test.name() << endl;
        cout << "full path: " << test.full_name() << endl;
        cout << "is root:   " << ((test.is_root())?"yes":"no") << endl;

        // get all directories and files in test
        std::vector<directory> dirs = test.get_dirs();
        std::vector<file> files = test.get_files();

        // sort the files and directories
        sort(files.begin(), files.end());
        sort(dirs.begin(), dirs.end());

        cout << "\n\n\n";

        // print all the subdirectories
        for (unsigned long i = 0; i < dirs.size(); ++i)
            cout << "        <DIR>    " << dirs[i].name() << "\n";

        // print all the subfiles
        for (unsigned long i = 0; i < files.size(); ++i)
            cout << setw(13) << files[i].size() << "    " << files[i].name() << "\n";

        cout << "\n\nnumber of dirs:  " << dirs.size() << endl;
        cout << "number of files: " << files.size() << endl;

    }
    catch (file::file_not_found& e)
    {
        cout << "file not found or accessible: " << e.info << endl;
    }
    catch (directory::dir_not_found& e)
    {
        cout << "dir not found or accessible: " << e.info << endl;
    }
    catch (directory::listing_error& e)
    {
        cout << "listing error: " << e.info << endl;


dlib C++ Library - empirical_kernel_map_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example illustrating the use of the empirical_kernel_map
    from the dlib C++ Library.

    This example program assumes you are familiar with some general elements of
    the library.  In particular, you should have at least read the svm_ex.cpp
    and matrix_ex.cpp examples.

    Most of the machine learning algorithms in dlib are some flavor of "kernel machine".
    This means they are all simple linear algorithms that have been formulated such
    that the only way they look at the data given by a user is via dot products between
    the data samples.  These algorithms are made more useful via the application of the
    so-called kernel trick.  This trick is to replace the dot product with a user
    supplied function which takes two samples and returns a real number.  This function
    is the kernel that is required by so many algorithms.  The most basic kernel is the
    linear_kernel which is simply a normal dot product.  More interesting, however,
    are kernels which first apply some nonlinear transformation to the user's data samples
    and then compute a dot product.  In this way, a simple algorithm that finds a linear
    plane to separate data (e.g. the SVM algorithm) can be made to solve complex
    nonlinear learning problems.

    An important element of the kernel trick is that these kernel functions perform
    the nonlinear transformation implicitly.  That is, if you look at the implementations
    of these kernel functions you won't see code that transforms two input vectors in
    some way and then computes their dot products.  Instead you will see a simple function
    that takes two input vectors and just computes a single real number via some simple
    process.  You can basically think of this as an optimization.  Imagine that originally
    we wrote out the entire procedure to perform the nonlinear transformation and then
    compute the dot product but then noticed we could cancel a few terms here and there
    and simplify the whole thing down into a more compact and easily evaluated form.
    The result is a nice function that computes what we want but we no longer get to see
    what those nonlinearly transformed input vectors are.

    The empirical_kernel_map is a tool that undoes this.  It allows you to obtain these
    nonlinearly transformed vectors.  It does this by taking a set of data samples from
    the user (referred to as basis samples), applying the nonlinear transformation to all
    of them, and then constructing a set of orthonormal basis vectors which spans the space
    occupied by those transformed input samples.  Then if we wish to obtain the nonlinear
    version of any data sample we can simply project it onto this orthonormal basis and
    we obtain a regular vector of real numbers which represents the nonlinearly transformed
    version of the data sample.  The empirical_kernel_map has been formulated to use only
    dot products between data samples so it is capable of performing this service for any
    user supplied kernel function.

    The empirical_kernel_map is useful because it is often difficult to formulate an
    algorithm in a way that uses only dot products.  So the empirical_kernel_map lets
    us easily kernelize any algorithm we like by using this object during a preprocessing
    step.  However, it should be noted that the algorithm is only practical when used
    with at most a few thousand basis samples.  Fortunately, most datasets live in
    subspaces that are relatively low dimensional.  So for these datasets, using the
    empirical_kernel_map is practical assuming an appropriate set of basis samples can be
    selected by the user.  To help with this dlib supplies the linearly_independent_subset_finder.
    I also often find that just picking a random subset of the data as a basis works well.

    In what follows, we walk through the process of creating an empirical_kernel_map,
    projecting data to obtain the nonlinearly transformed vectors, and then doing a
    few interesting things with the data.
*/

#include <dlib/svm.h>
#include <dlib/rand.h>
#include <iostream>
#include <vector>

using namespace std;
using namespace dlib;

// ----------------------------------------------------------------------------------------

// First let's make a typedef for the kind of samples we will be using.
typedef matrix<double, 0, 1> sample_type;

// We will be using the radial_basis_kernel in this example program.
typedef radial_basis_kernel<sample_type> kernel_type;

// ----------------------------------------------------------------------------------------

void generate_concentric_circles (
    std::vector<sample_type>& samples,
    std::vector<double>& labels,
    const int num_points
);
/*!
    requires
        - num_points > 0
    ensures
        - generates two circles centered at the point (0,0), one of radius 1 and
          the other of radius 5.  These points are stored into samples.  labels will
          tell you if a given samples is from the smaller circle (its label will be 1)
          or from the larger circle (its label will be 2).
        - each circle will be made up of num_points
!*/

// ----------------------------------------------------------------------------------------

void test_empirical_kernel_map (
    const std::vector<sample_type>& samples,
    const std::vector<double>& labels,
    const empirical_kernel_map<kernel_type>& ekm
);
/*!
    This function computes various interesting things with the empirical_kernel_map.
    See its implementation below for details.
!*/

// ----------------------------------------------------------------------------------------

int main()
{
    std::vector<sample_type> samples;
    std::vector<double> labels;

    // Declare an instance of the kernel we will be using.
    const kernel_type kern(0.1);

    // create a dataset with two concentric circles.  There will be 100 points on each circle.
    generate_concentric_circles(samples, labels, 100);

    empirical_kernel_map<kernel_type> ekm;

    // Here we create an empirical_kernel_map using all of our data samples as basis samples.
    cout << "\n\nBuilding an empirical_kernel_map with " << samples.size() << " basis samples." << endl;
    ekm.load(kern, samples);
    cout << "Test the empirical_kernel_map when loaded with every sample." << endl;
    test_empirical_kernel_map(samples, labels, ekm);

    // create a new dataset with two concentric circles.  There will be 1000 points on each circle.
    generate_concentric_circles(samples, labels, 1000);
    // Rather than use all 2000 samples as basis samples we are going to use the
    // linearly_independent_subset_finder to pick out a good basis set.  The idea behind this
    // object is to try and find the 40 or so samples that best spans the subspace containing all the
    // data.
    linearly_independent_subset_finder<kernel_type> lisf(kern, 40);
    // populate lisf with samples.  We have configured it to allow at most 40 samples but this function
    // may determine that fewer samples are necessary to form a good basis.  In this example program
    // it will select only 26.
    fill_lisf(lisf, samples);

    // Now reload the empirical_kernel_map but this time using only our small basis
    // selected using the linearly_independent_subset_finder.
    cout << "\n\nBuilding an empirical_kernel_map with " << lisf.size() << " basis samples." << endl;
    ekm.load(lisf);
    cout << "Test the empirical_kernel_map when loaded with samples from the lisf object." << endl;
    test_empirical_kernel_map(samples, labels, ekm);

    cout << endl;
}

// ----------------------------------------------------------------------------------------

void test_empirical_kernel_map (
    const std::vector<sample_type>& samples,
    const std::vector<double>& labels,
    const empirical_kernel_map<kernel_type>& ekm
)
{

    std::vector<sample_type> projected_samples;

    // The first thing we do is compute the nonlinearly projected vectors using the
    // empirical_kernel_map.
    for (unsigned long i = 0; i < samples.size(); ++i)
    {
        projected_samples.push_back(ekm.project(samples[i]));
    }

    // Note that a kernel matrix is just a matrix M such that M(i,j) == kernel(samples[i],samples[j]).
    // So below we are computing the normal kernel matrix as given by the radial_basis_kernel and the
    // input samples.  We also compute the kernel matrix for all the projected_samples as given by the
    // linear_kernel.  Note that the linear_kernel just computes normal dot products.  So what we want to
    // see is that the dot products between all the projected_samples samples are the same as the outputs
    // of the kernel function for their respective untransformed input samples.  If they match then
    // we know that the empirical_kernel_map is working properly.
    const matrix<double> normal_kernel_matrix = kernel_matrix(ekm.get_kernel(), samples);
    const matrix<double> new_kernel_matrix = kernel_matrix(linear_kernel<sample_type>(), projected_samples);

    cout << "Max kernel matrix error: " << max(abs(normal_kernel_matrix - new_kernel_matrix)) << endl;
    cout << "Mean kernel matrix error: " << mean(abs(normal_kernel_matrix - new_kernel_matrix)) << endl;
    /*
        Example outputs from these cout statements.
        For the case where we use all samples as basis samples:
            Max kernel matrix error: 7.32747e-15
            Mean kernel matrix error: 7.47789e-16

        For the case where we use only 26 samples as basis samples:
            Max kernel matrix error: 0.000953573
            Mean kernel matrix error: 2.26008e-05

        Note that if we use enough basis samples we can perfectly span the space of input samples.
        In that case we get errors that are essentially just rounding noise (Moreover, using all the
        samples is always enough since they are always within their own span).  Once we start
        to use fewer basis samples we may begin to get approximation error.  In the second case we
        used 26 and we can see that the data doesn't really lay exactly in a 26 dimensional subspace.
        But it is pretty close.
    */

    // Now let's do something more interesting.  The following loop finds the centroids
    // of the two classes of data.
    sample_type class1_center;
    sample_type class2_center;
    for (unsigned long i = 0; i < projected_samples.size(); ++i)
    {
        if (labels[i] == 1)
            class1_center += projected_samples[i];
        else
            class2_center += projected_samples[i];
    }

    const int points_per_class = samples.size()/2;
    class1_center /= points_per_class;
    class2_center /= points_per_class;

    // Now classify points by which center they are nearest.  Recall that the data
    // is made up of two concentric circles.  Normally you can't separate two concentric
    // circles by checking which points are nearest to each center since they have the same
    // centers.  However, the kernel trick makes the data separable and the loop below will
    // perfectly classify each data point.
    for (unsigned long i = 0; i < projected_samples.size(); ++i)
    {
        double distance_to_class1 = length(projected_samples[i] - class1_center);
        double distance_to_class2 = length(projected_samples[i] - class2_center);

        bool predicted_as_class_1 = (distance_to_class1 < distance_to_class2);

        // Now print a message for any misclassified points.
        if (predicted_as_class_1 == true && labels[i] != 1)
            cout << "A point was misclassified" << endl;

        if (predicted_as_class_1 == false && labels[i] != 2)
            cout << "A point was misclassified" << endl;
    }

    // Next, note that classifying a point based on its distance between two other
    // points is the same thing as using the plane that lies between those two points
    // as a decision boundary.  So let's compute that decision plane and use it to classify
    // all the points.

    sample_type plane_normal_vector = class1_center - class2_center;
    // The point right in the center of our two classes should be on the deciding plane, not
    // on one side or the other.  This consideration brings us to the formula for the bias.
    double bias = dot((class1_center+class2_center)/2, plane_normal_vector);

    // Now classify points by which side of the plane they are on.
    for (unsigned long i = 0; i < projected_samples.size(); ++i)
    {
        double side = dot(plane_normal_vector, projected_samples[i]) - bias;

        bool predicted_as_class_1 = (side > 0);

        // Now print a message for any misclassified points.
        if (predicted_as_class_1 == true && labels[i] != 1)
            cout << "A point was misclassified" << endl;

        if (predicted_as_class_1 == false && labels[i] != 2)
            cout << "A point was misclassified" << endl;
    }

    // It would be nice to convert this decision rule into a normal decision_function object and
    // dispense with the empirical_kernel_map.  Happily, it is possible to do so.  Consider the
    // following example code:
    decision_function<kernel_type> dec_funct = ekm.convert_to_decision_function(plane_normal_vector);
    // The dec_funct now computes dot products between plane_normal_vector and the projection
    // of any sample point given to it.  All that remains is to account for the bias.
    dec_funct.b = bias;

    // now classify points by which side of the plane they are on.
    for (unsigned long i = 0; i < samples.size(); ++i)
    {
        double side = dec_funct(samples[i]);

        // And let's just check that the dec_funct really does compute the same thing as the previous equation.
        double side_alternate_equation = dot(plane_normal_vector, projected_samples[i]) - bias;
        if (abs(side-side_alternate_equation) > 1e-14)
            cout << "dec_funct error: " << abs(side-side_alternate_equation) << endl;

        bool predicted_as_class_1 = (side > 0);

        // Now print a message for any misclassified points.
        if (predicted_as_class_1 == true && labels[i] != 1)
            cout << "A point was misclassified" << endl;

        if (predicted_as_class_1 == false && labels[i] != 2)
            cout << "A point was misclassified" << endl;
    }

}

// ----------------------------------------------------------------------------------------

void generate_concentric_circles (
    std::vector<sample_type>& samples,
    std::vector<double>& labels,
    const int num
)
{
    sample_type m(2,1);
    samples.clear();
    labels.clear();

    dlib::rand rnd;

    // make some samples near the origin
    double radius = 1.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));

        samples.push_back(m);
        labels.push_back(1);
    }

    // make some samples in a circle around the origin but far away
    radius = 5.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));

        samples.push_back(m);
        labels.push_back(2);
    }
}

// ----------------------------------------------------------------------------------------


dlib C++ Library - face_detection_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This example program shows how to find frontal human faces in an image.  In
    particular, this program shows how you can take a list of images from the
    command line and display each on the screen with red boxes overlaid on each
    human face.

    The examples/faces folder contains some jpg images of people.  You can run
    this program on them and see the detections by executing the following command:
        ./face_detection_ex faces/*.jpg

    This face detector is made using the now classic Histogram of Oriented
    Gradients (HOG) feature combined with a linear classifier, an image pyramid,
    and sliding window detection scheme.  This type of object detector is fairly
    general and capable of detecting many types of semi-rigid objects in
    addition to human faces.  Therefore, if you are interested in making your
    own object detectors then read the fhog_object_detector_ex.cpp example
    program.  It shows how to use the machine learning tools which were used to
    create dlib's face detector.

    Finally, note that the face detector is fastest when compiled with at least
    SSE2 instructions enabled.  So if you are using a PC with an Intel or AMD
    chip then you should enable at least SSE2 instructions.  If you are using
    cmake to compile this program you can enable them by using one of the
    following commands when you create the build project:
        cmake path_to_dlib_root/examples -DUSE_SSE2_INSTRUCTIONS=ON
        cmake path_to_dlib_root/examples -DUSE_SSE4_INSTRUCTIONS=ON
        cmake path_to_dlib_root/examples -DUSE_AVX_INSTRUCTIONS=ON
    This will set the appropriate compiler options for GCC, clang, Visual
    Studio, or the Intel compiler.  If you are using another compiler then you
    need to consult your compiler's manual to determine how to enable these
    instructions.  Note that AVX is the fastest but requires a CPU from at least
    2011.  SSE4 is the next fastest and is supported by most current machines.
*/

#include <dlib/image_processing/frontal_face_detector.h>
#include <dlib/gui_widgets.h>
#include <dlib/image_io.h>
#include <iostream>

using namespace dlib;
using namespace std;

// ----------------------------------------------------------------------------------------

int main(int argc, char** argv)
{
    try
    {
        if (argc == 1)
        {
            cout << "Give some image files as arguments to this program." << endl;
            return 0;
        }

        frontal_face_detector detector = get_frontal_face_detector();
        image_window win;

        // Loop over all the images provided on the command line.
        for (int i = 1; i < argc; ++i)
        {
            cout << "processing image " << argv[i] << endl;
            array2d<unsigned char> img;
            load_image(img, argv[i]);
            // Make the image bigger by a factor of two.  This is useful since
            // the face detector looks for faces that are about 80 by 80 pixels
            // or larger.  Therefore, if you want to find faces that are smaller
            // than that then you need to upsample the image as we do here by
            // calling pyramid_up().  So this will allow it to detect faces that
            // are at least 40 by 40 pixels in size.  We could call pyramid_up()
            // again to find even smaller faces, but note that every time we
            // upsample the image we make the detector run slower since it must
            // process a larger image.
            pyramid_up(img);

            // Now tell the face detector to give us a list of bounding boxes
            // around all the faces it can find in the image.
            std::vector<rectangle> dets = detector(img);

            cout << "Number of faces detected: " << dets.size() << endl;
            // Now we show the image on the screen and the face detections as
            // red overlay boxes.
            win.clear_overlay();
            win.set_image(img);
            win.add_overlay(dets, rgb_pixel(255,0,0));

            cout << "Hit enter to process the next image..." << endl;
            cin.get();
        }
    }
    catch (exception& e)
    {
        cout << "\nexception thrown!" << endl;
        cout << e.what() << endl;
    }
}

// ----------------------------------------------------------------------------------------


dlib C++ Library - face_landmark_detection_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This example program shows how to find frontal human faces in an image and
    estimate their pose.  The pose takes the form of 68 landmarks.  These are
    points on the face such as the corners of the mouth, along the eyebrows, on
    the eyes, and so forth.

    This face detector is made using the classic Histogram of Oriented
    Gradients (HOG) feature combined with a linear classifier, an image pyramid,
    and sliding window detection scheme.  The pose estimator was created by
    using dlib's implementation of the paper:
        One Millisecond Face Alignment with an Ensemble of Regression Trees by
        Vahid Kazemi and Josephine Sullivan, CVPR 2014
    and was trained on the iBUG 300-W face landmark dataset.

    Also, note that you can train your own models using dlib's machine learning
    tools.  See train_shape_predictor_ex.cpp to see an example.

    Finally, note that the face detector is fastest when compiled with at least
    SSE2 instructions enabled.  So if you are using a PC with an Intel or AMD
    chip then you should enable at least SSE2 instructions.  If you are using
    cmake to compile this program you can enable them by using one of the
    following commands when you create the build project:
        cmake path_to_dlib_root/examples -DUSE_SSE2_INSTRUCTIONS=ON
        cmake path_to_dlib_root/examples -DUSE_SSE4_INSTRUCTIONS=ON
        cmake path_to_dlib_root/examples -DUSE_AVX_INSTRUCTIONS=ON
    This will set the appropriate compiler options for GCC, clang, Visual
    Studio, or the Intel compiler.  If you are using another compiler then you
    need to consult your compiler's manual to determine how to enable these
    instructions.  Note that AVX is the fastest but requires a CPU from at least
    2011.  SSE4 is the next fastest and is supported by most current machines.
*/

#include <dlib/image_processing/frontal_face_detector.h>
#include <dlib/image_processing/render_face_detections.h>
#include <dlib/image_processing.h>
#include <dlib/gui_widgets.h>
#include <dlib/image_io.h>
#include <iostream>

using namespace dlib;
using namespace std;

// ----------------------------------------------------------------------------------------

int main(int argc, char** argv)
{
    try
    {
        // This example takes in a shape model file and then a list of images to
        // process.  We will take these filenames in as command line arguments.
        // Dlib comes with example images in the examples/faces folder so give
        // those as arguments to this program.
        if (argc == 1)
        {
            cout << "Call this program like this:" << endl;
            cout << "./face_landmark_detection_ex shape_predictor_68_face_landmarks.dat faces/*.jpg" << endl;
            cout << "\nYou can get the shape_predictor_68_face_landmarks.dat file from:\n";
            cout << "http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2" << endl;
            return 0;
        }

        // We need a face detector.  We will use this to get bounding boxes for
        // each face in an image.
        frontal_face_detector detector = get_frontal_face_detector();
        // And we also need a shape_predictor.  This is the tool that will predict face
        // landmark positions given an image and face bounding box.  Here we are just
        // loading the model from the shape_predictor_68_face_landmarks.dat file you gave
        // as a command line argument.
        shape_predictor sp;
        deserialize(argv[1]) >> sp;

        image_window win, win_faces;
        // Loop over all the images provided on the command line.
        for (int i = 2; i < argc; ++i)
        {
            cout << "processing image " << argv[i] << endl;
            array2d<rgb_pixel> img;
            load_image(img, argv[i]);
            // Make the image larger so we can detect small faces.
            pyramid_up(img);

            // Now tell the face detector to give us a list of bounding boxes
            // around all the faces in the image.
            std::vector<rectangle> dets = detector(img);
            cout << "Number of faces detected: " << dets.size() << endl;

            // Now we will go ask the shape_predictor to tell us the pose of
            // each face we detected.
            std::vector<full_object_detection> shapes;
            for (unsigned long j = 0; j < dets.size(); ++j)
            {
                full_object_detection shape = sp(img, dets[j]);
                cout << "number of parts: "<< shape.num_parts() << endl;
                cout << "pixel position of first part:  " << shape.part(0) << endl;
                cout << "pixel position of second part: " << shape.part(1) << endl;
                // You get the idea, you can get all the face part locations if
                // you want them.  Here we just store them in shapes so we can
                // put them on the screen.
                shapes.push_back(shape);
            }

            // Now let's view our face poses on the screen.
            win.clear_overlay();
            win.set_image(img);
            win.add_overlay(render_face_detections(shapes));

            // We can also extract copies of each face that are cropped, rotated upright,
            // and scaled to a standard size as shown here:
            dlib::array<array2d<rgb_pixel> > face_chips;
            extract_image_chips(img, get_face_chip_details(shapes), face_chips);
            win_faces.set_image(tile_images(face_chips));

            cout << "Hit enter to process the next image..." << endl;
            cin.get();
        }
    }
    catch (exception& e)
    {
        cout << "\nexception thrown!" << endl;
        cout << e.what() << endl;
    }
}

// ----------------------------------------------------------------------------------------


dlib C++ Library - fhog_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example illustrating the use of the extract_fhog_features() routine from
    the dlib C++ Library.

    The extract_fhog_features() routine performs the style of HOG feature extraction
    described in the paper:
        Object Detection with Discriminatively Trained Part Based Models by
        P. Felzenszwalb, R. Girshick, D. McAllester, D. Ramanan
        IEEE Transactions on Pattern Analysis and Machine Intelligence, Vol. 32, No. 9, Sep. 2010
    This means that it takes an input image and outputs Felzenszwalb's
    31 dimensional version of HOG features.  We show its use below.
*/

#include <dlib/gui_widgets.h>
#include <dlib/image_io.h>
#include <dlib/image_transforms.h>

using namespace std;
using namespace dlib;

//  ----------------------------------------------------------------------------

int main(int argc, char** argv)
{
    try
    {
        // Make sure the user entered an argument to this program.  It should be the
        // filename for an image.
        if (argc != 2)
        {
            cout << "error, you have to enter a BMP file as an argument to this program" << endl;
            return 1;
        }

        // Here we declare an image object that can store color rgb_pixels.
        array2d<rgb_pixel> img;

        // Now load the image file into our image.  If something is wrong then
        // load_image() will throw an exception.  Also, if you linked with libpng
        // and libjpeg then load_image() can load PNG and JPEG files in addition
        // to BMP files.
        load_image(img, argv[1]);

        // Now convert the image into a FHOG feature image.  The output, hog, is a 2D array
        // of 31 dimensional vectors.
        array2d<matrix<float,31,1> > hog;
        extract_fhog_features(img, hog);

        cout << "hog image has " << hog.nr() << " rows and " << hog.nc() << " columns." << endl;

        // Let's see what the image and FHOG features look like.
        image_window win(img);
        image_window winhog(draw_fhog(hog));

        // Another thing you might want to do is map between the pixels in img and the
        // cells in the hog image.  dlib provides the image_to_fhog() and fhog_to_image()
        // routines for this.  Their use is demonstrated in the following loop which
        // responds to the user clicking on pixels in the image img.
        point p;  // A 2D point, used to represent pixel locations.
        while (win.get_next_double_click(p))
        {
            point hp = image_to_fhog(p);
            cout << "The point " << p << " in the input image corresponds to " << hp << " in hog space." << endl;
            cout << "FHOG features at this point: " << trans(hog[hp.y()][hp.x()]) << endl;
        }

        // Finally, sometimes you want to get a planar representation of the HOG features
        // rather than the explicit vector (i.e. interlaced) representation used above.
        dlib::array<array2d<float> > planar_hog;
        extract_fhog_features(img, planar_hog);
        // Now we have an array of 31 float valued image planes, each representing one of
        // the dimensions of the HOG feature vector.
    }
    catch (exception& e)
    {
        cout << "exception thrown: " << e.what() << endl;
    }
}

//  ----------------------------------------------------------------------------


dlib C++ Library - fhog_object_detector_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This example program shows how you can use dlib to make an object detector
    for things like faces, pedestrians, and any other semi-rigid object.  In
    particular, we go though the steps to train the kind of sliding window
    object detector first published by Dalal and Triggs in 2005 in the paper
    Histograms of Oriented Gradients for Human Detection.

    Note that this program executes fastest when compiled with at least SSE2
    instructions enabled.  So if you are using a PC with an Intel or AMD chip
    then you should enable at least SSE2 instructions.  If you are using cmake
    to compile this program you can enable them by using one of the following
    commands when you create the build project:
        cmake path_to_dlib_root/examples -DUSE_SSE2_INSTRUCTIONS=ON
        cmake path_to_dlib_root/examples -DUSE_SSE4_INSTRUCTIONS=ON
        cmake path_to_dlib_root/examples -DUSE_AVX_INSTRUCTIONS=ON
    This will set the appropriate compiler options for GCC, clang, Visual
    Studio, or the Intel compiler.  If you are using another compiler then you
    need to consult your compiler's manual to determine how to enable these
    instructions.  Note that AVX is the fastest but requires a CPU from at least
    2011.  SSE4 is the next fastest and is supported by most current machines.

*/

#include <dlib/svm_threaded.h>
#include <dlib/gui_widgets.h>
#include <dlib/image_processing.h>
#include <dlib/data_io.h>

#include <iostream>
#include <fstream>

using namespace std;
using namespace dlib;

// ----------------------------------------------------------------------------------------

int main(int argc, char** argv)
{

    try
    {
        // In this example we are going to train a face detector based on the
        // small faces dataset in the examples/faces directory.  So the first
        // thing we do is load that dataset.  This means you need to supply the
        // path to this faces folder as a command line argument so we will know
        // where it is.
        if (argc != 2)
        {
            cout << "Give the path to the examples/faces directory as the argument to this" << endl;
            cout << "program.  For example, if you are in the examples folder then execute " << endl;
            cout << "this program by running: " << endl;
            cout << "   ./fhog_object_detector_ex faces" << endl;
            cout << endl;
            return 0;
        }
        const std::string faces_directory = argv[1];
        // The faces directory contains a training dataset and a separate
        // testing dataset.  The training data consists of 4 images, each
        // annotated with rectangles that bound each human face.  The idea is
        // to use this training data to learn to identify human faces in new
        // images.
        //
        // Once you have trained an object detector it is always important to
        // test it on data it wasn't trained on.  Therefore, we will also load
        // a separate testing set of 5 images.  Once we have a face detector
        // created from the training data we will see how well it works by
        // running it on the testing images.
        //
        // So here we create the variables that will hold our dataset.
        // images_train will hold the 4 training images and face_boxes_train
        // holds the locations of the faces in the training images.  So for
        // example, the image images_train[0] has the faces given by the
        // rectangles in face_boxes_train[0].
        dlib::array<array2d<unsigned char> > images_train, images_test;
        std::vector<std::vector<rectangle> > face_boxes_train, face_boxes_test;

        // Now we load the data.  These XML files list the images in each
        // dataset and also contain the positions of the face boxes.  Obviously
        // you can use any kind of input format you like so long as you store
        // the data into images_train and face_boxes_train.  But for convenience
        // dlib comes with tools for creating and loading XML image dataset
        // files.  Here you see how to load the data.  To create the XML files
        // you can use the imglab tool which can be found in the tools/imglab
        // folder.  It is a simple graphical tool for labeling objects in images
        // with boxes.  To see how to use it read the tools/imglab/README.txt
        // file.
        load_image_dataset(images_train, face_boxes_train, faces_directory+"/training.xml");
        load_image_dataset(images_test, face_boxes_test, faces_directory+"/testing.xml");

        // Now we do a little bit of pre-processing.  This is optional but for
        // this training data it improves the results.  The first thing we do is
        // increase the size of the images by a factor of two.  We do this
        // because it will allow us to detect smaller faces than otherwise would
        // be practical (since the faces are all now twice as big).  Note that,
        // in addition to resizing the images, these functions also make the
        // appropriate adjustments to the face boxes so that they still fall on
        // top of the faces after the images are resized.
        upsample_image_dataset<pyramid_down<2> >(images_train, face_boxes_train);
        upsample_image_dataset<pyramid_down<2> >(images_test,  face_boxes_test);
        // Since human faces are generally left-right symmetric we can increase
        // our training dataset by adding mirrored versions of each image back
        // into images_train.  So this next step doubles the size of our
        // training dataset.  Again, this is obviously optional but is useful in
        // many object detection tasks.
        add_image_left_right_flips(images_train, face_boxes_train);
        cout << "num training images: " << images_train.size() << endl;
        cout << "num testing images:  " << images_test.size() << endl;

        // Finally we get to the training code.  dlib contains a number of
        // object detectors.  This typedef tells it that you want to use the one
        // based on Felzenszwalb's version of the Histogram of Oriented
        // Gradients (commonly called HOG) detector.  The 6 means that you want
        // it to use an image pyramid that downsamples the image at a ratio of
        // 5/6.  Recall that HOG detectors work by creating an image pyramid and
        // then running the detector over each pyramid level in a sliding window
        // fashion.
        typedef scan_fhog_pyramid<pyramid_down<6> > image_scanner_type;
        image_scanner_type scanner;
        // The sliding window detector will be 80 pixels wide and 80 pixels tall.
        scanner.set_detection_window_size(80, 80);
        structural_object_detection_trainer<image_scanner_type> trainer(scanner);
        // Set this to the number of processing cores on your machine.
        trainer.set_num_threads(4);
        // The trainer is a kind of support vector machine and therefore has the usual SVM
        // C parameter.  In general, a bigger C encourages it to fit the training data
        // better but might lead to overfitting.  You must find the best C value
        // empirically by checking how well the trained detector works on a test set of
        // images you haven't trained on.  Don't just leave the value set at 1.  Try a few
        // different C values and see what works best for your data.
        trainer.set_c(1);
        // We can tell the trainer to print it's progress to the console if we want.
        trainer.be_verbose();
        // The trainer will run until the "risk gap" is less than 0.01.  Smaller values
        // make the trainer solve the SVM optimization problem more accurately but will
        // take longer to train.  For most problems a value in the range of 0.1 to 0.01 is
        // plenty accurate.  Also, when in verbose mode the risk gap is printed on each
        // iteration so you can see how close it is to finishing the training.
        trainer.set_epsilon(0.01);

        // Now we run the trainer.  For this example, it should take on the order of 10
        // seconds to train.
        object_detector<image_scanner_type> detector = trainer.train(images_train, face_boxes_train);

        // Now that we have a face detector we can test it.  The first statement tests it
        // on the training data.  It will print the precision, recall, and then average precision.
        cout << "training results: " << test_object_detection_function(detector, images_train, face_boxes_train) << endl;
        // However, to get an idea if it really worked without overfitting we need to run
        // it on images it wasn't trained on.  The next line does this.  Happily, we see
        // that the object detector works perfectly on the testing images.
        cout << "testing results:  " << test_object_detection_function(detector, images_test, face_boxes_test) << endl;

        // If you have read any papers that use HOG you have probably seen the nice looking
        // "sticks" visualization of a learned HOG detector.  This next line creates a
        // window with such a visualization of our detector.  It should look somewhat like
        // a face.
        image_window hogwin(draw_fhog(detector), "Learned fHOG detector");

        // Now for the really fun part.  Let's display the testing images on the screen and
        // show the output of the face detector overlaid on each image.  You will see that
        // it finds all the faces without false alarming on any non-faces.
        image_window win;
        for (unsigned long i = 0; i < images_test.size(); ++i)
        {
            // Run the detector and get the face detections.
            std::vector<rectangle> dets = detector(images_test[i]);
            win.clear_overlay();
            win.set_image(images_test[i]);
            win.add_overlay(dets, rgb_pixel(255,0,0));
            cout << "Hit enter to process the next image..." << endl;
            cin.get();
        }

        // Like everything in dlib, you can save your detector to disk using the
        // serialize() function.
        serialize("face_detector.svm") << detector;

        // Then you can recall it using the deserialize() function.
        object_detector<image_scanner_type> detector2;
        deserialize("face_detector.svm") >> detector2;

        // Now let's talk about some optional features of this training tool as well as some
        // important points you should understand.
        //
        // The first thing that should be pointed out is that, since this is a sliding
        // window classifier, it can't output an arbitrary rectangle as a detection.  In
        // this example our sliding window is 80 by 80 pixels and is run over an image
        // pyramid.  This means that it can only output detections that are at least 80 by
        // 80 pixels in size (recall that this is why we upsampled the images after loading
        // them).  It also means that the aspect ratio of the outputs is 1.  So if,
        // for example, you had a box in your training data that was 200 pixels by 10
        // pixels then it would simply be impossible for the detector to learn to detect
        // it.  Similarly, if you had a really small box it would be unable to learn to
        // detect it.
        //
        // So the training code performs an input validation check on the training data and
        // will throw an exception if it detects any boxes that are impossible to detect
        // given your setting of scanning window size and image pyramid resolution.  You
        // can use a statement like:
        //   remove_unobtainable_rectangles(trainer, images_train, face_boxes_train)
        // to automatically discard these impossible boxes from your training dataset
        // before running the trainer.  This will avoid getting the "impossible box"
        // exception.  However, I would recommend you be careful that you are not throwing
        // away truth boxes you really care about.  The remove_unobtainable_rectangles()
        // will return the set of removed rectangles so you can visually inspect them and
        // make sure you are OK that they are being removed.
        //
        // Next, note that any location in the images not marked with a truth box is
        // implicitly treated as a negative example.  This means that when creating
        // training data it is critical that you label all the objects you want to detect.
        // So for example, if you are making a face detector then you must mark all the
        // faces in each image.  However, sometimes there are objects in images you are
        // unsure about or simply don't care if the detector identifies or not.  For these
        // objects you can pass in a set of "ignore boxes" as a third argument to the
        // trainer.train() function.  The trainer will simply disregard any detections that
        // happen to hit these boxes.
        //
        // Another useful thing you can do is evaluate multiple HOG detectors together. The
        // benefit of this is increased testing speed since it avoids recomputing the HOG
        // features for each run of the detector.  You do this by storing your detectors
        // into a std::vector and then invoking evaluate_detectors() like so:
        std::vector<object_detector<image_scanner_type> > my_detectors;
        my_detectors.push_back(detector);
        std::vector<rectangle> dets = evaluate_detectors(my_detectors, images_train[0]);
        //
        //
        // Finally, you can add a nuclear norm regularizer to the SVM trainer.  Doing has
        // two benefits.  First, it can cause the learned HOG detector to be composed of
        // separable filters and therefore makes it execute faster when detecting objects.
        // It can also help with generalization since it tends to make the learned HOG
        // filters smoother.  To enable this option you call the following function before
        // you create the trainer object:
        //    scanner.set_nuclear_norm_regularization_strength(1.0);
        // The argument determines how important it is to have a small nuclear norm.  A
        // bigger regularization strength means it is more important.  The smaller the
        // nuclear norm the smoother and faster the learned HOG filters will be, but if the
        // regularization strength value is too large then the SVM will not fit the data
        // well.  This is analogous to giving a C value that is too small.
        //
        // You can see how many separable filters are inside your detector like so:
        cout << "num filters: "<< num_separable_filters(detector) << endl;
        // You can also control how many filters there are by explicitly thresholding the
        // singular values of the filters like this:
        detector = threshold_filter_singular_values(detector,0.1);
        // That removes filter components with singular values less than 0.1.  The bigger
        // this number the fewer separable filters you will have and the faster the
        // detector will run.  However, a large enough threshold will hurt detection
        // accuracy.

    }
    catch (exception& e)
    {
        cout << "\nexception thrown!" << endl;
        cout << e.what() << endl;
    }
}

// ----------------------------------------------------------------------------------------


dlib C++ Library - graph_labeling_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example illustrating the use of the graph_labeler and
    structural_graph_labeling_trainer objects.

    Suppose you have a bunch of objects and you need to label each of them as true or
    false.  Suppose further that knowing the labels of some of these objects tells you
    something about the likely label of the others.  This is common in a number of domains.
    For example, in image segmentation problems you need to label each pixel, and knowing
    the labels of neighboring pixels gives you information about the likely label since
    neighboring pixels will often have the same label.

    We can generalize this problem by saying that we have a graph and our task is to label
    each node in the graph as true or false.  Additionally, the edges in the graph connect
    nodes which are likely to share the same label.  In this example program, each node
    will have a feature vector which contains information which helps tell if the node
    should be labeled as true or false.  The edges also contain feature vectors which give
    information indicating how strong the edge's labeling consistency constraint should be.
    This is useful since some nodes will have uninformative feature vectors and the only
    way to tell how they should be labeled is by looking at their neighbor's labels.

    Therefore, this program will show you how to learn two things using machine learning.
    The first is a linear classifier which operates on each node and predicts if it should
    be labeled as true or false.  The second thing is a linear function of the edge
    vectors.  This function outputs a penalty for giving two nodes connected by an edge
    differing labels.  The graph_labeler object puts these two things together and uses
    them to compute a labeling which takes both into account.  In what follows, we will use
    a structural SVM method to find the parameters of these linear functions which minimize
    the number of mistakes made by a graph_labeler.

    Finally, you might also consider reading the book Structured Prediction and Learning in
    Computer Vision by Sebastian Nowozin and Christoph H. Lampert since it contains a good
    introduction to machine learning methods such as the algorithm implemented by the
    structural_graph_labeling_trainer.
*/

#include <dlib/svm_threaded.h>
#include <iostream>

using namespace std;
using namespace dlib;

// ----------------------------------------------------------------------------------------

// The first thing we do is define the kind of graph object we will be using.
// Here we are saying there will be 2-D vectors at each node and 1-D vectors at
// each edge.  (You should read the matrix_ex.cpp example program for an introduction
// to the matrix object.)
typedef matrix<double,2,1> node_vector_type;
typedef matrix<double,1,1> edge_vector_type;
typedef graph<node_vector_type, edge_vector_type>::kernel_1a_c graph_type;

// ----------------------------------------------------------------------------------------

template <
    typename graph_type,
    typename labels_type
    >
void make_training_examples(
    dlib::array<graph_type>& samples,
    labels_type& labels
)
{
    /*
        This function makes 3 graphs we will use for training.   All of them
        will contain 4 nodes and have the structure shown below:

          (0)-----(1)
           |       |
           |       |
           |       |
          (3)-----(2)

        In this example, each node has a 2-D vector.  The first element of this vector
        is 1 when the node should have a label of false while the second element has
        a value of 1 when the node should have a label of true.  Additionally, the
        edge vectors will contain a value of 1 when the nodes connected by the edge
        should share the same label and a value of 0 otherwise.

        We want to see that the machine learning method is able to figure out how
        these features relate to the labels.  If it is successful it will create a
        graph_labeler which can predict the correct labels for these and other
        similarly constructed graphs.

        Finally, note that these tools require all values in the edge vectors to be >= 0.
        However, the node vectors may contain both positive and negative values.
    */

    samples.clear();
    labels.clear();

    std::vector<bool> label;
    graph_type g;

    // ---------------------------
    g.set_number_of_nodes(4);
    label.resize(g.number_of_nodes());
    // store the vector [0,1] into node 0.  Also label it as true.
    g.node(0).data = 0, 1; label[0] = true;
    // store the vector [0,0] into node 1.
    g.node(1).data = 0, 0; label[1] = true;  // Note that this node's vector doesn't tell us how to label it.
                                             // We need to take the edges into account to get it right.
    // store the vector [1,0] into node 2.
    g.node(2).data = 1, 0; label[2] = false;
    // store the vector [0,0] into node 3.
    g.node(3).data = 0, 0; label[3] = false;

    // Add the 4 edges as shown in the ASCII art above.
    g.add_edge(0,1);
    g.add_edge(1,2);
    g.add_edge(2,3);
    g.add_edge(3,0);

    // set the 1-D vector for the edge between node 0 and 1 to the value of 1.
    edge(g,0,1) = 1;
    // set the 1-D vector for the edge between node 1 and 2 to the value of 0.
    edge(g,1,2) = 0;
    edge(g,2,3) = 1;
    edge(g,3,0) = 0;
    // output the graph and its label.
    samples.push_back(g);
    labels.push_back(label);

    // ---------------------------
    g.set_number_of_nodes(4);
    label.resize(g.number_of_nodes());
    g.node(0).data = 0, 1; label[0] = true;
    g.node(1).data = 0, 1; label[1] = true;
    g.node(2).data = 1, 0; 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);

    // This time, we have strong edges between all the nodes.  The machine learning
    // tools will have to learn that when the node information conflicts with the
    // edge constraints that the node information should dominate.
    edge(g,0,1) = 1;
    edge(g,1,2) = 1;
    edge(g,2,3) = 1;
    edge(g,3,0) = 1;
    samples.push_back(g);
    labels.push_back(label);
    // ---------------------------

    g.set_number_of_nodes(4);
    label.resize(g.number_of_nodes());
    g.node(0).data = 1, 0; label[0] = false;
    g.node(1).data = 1, 0; label[1] = false;
    g.node(2).data = 1, 0; label[2] = false;
    g.node(3).data = 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) = 0;
    edge(g,1,2) = 0;
    edge(g,2,3) = 1;
    edge(g,3,0) = 0;
    samples.push_back(g);
    labels.push_back(label);
    // ---------------------------

}

// ----------------------------------------------------------------------------------------

int main()
{
    try
    {
        // Get the training samples we defined above.
        dlib::array<graph_type> samples;
        std::vector<std::vector<bool> > labels;
        make_training_examples(samples, labels);

        // Create a structural SVM trainer for graph labeling problems.  The vector_type
        // needs to be set to a type capable of holding node or edge vectors.
        typedef matrix<double,0,1> vector_type;
        structural_graph_labeling_trainer<vector_type> trainer;
        // This is the usual SVM C parameter.  Larger values make the trainer try
        // harder to fit the training data but might result in overfitting.  You
        // should set this value to whatever gives the best cross-validation results.
        trainer.set_c(10);

        // Do 3-fold cross-validation and print the results.  In this case it will
        // indicate that all nodes were correctly classified.
        cout << "3-fold cross-validation: " << cross_validate_graph_labeling_trainer(trainer, samples, labels, 3) << endl;

        // Since the trainer is working well.  Let's have it make a graph_labeler
        // based on the training data.
        graph_labeler<vector_type> labeler = trainer.train(samples, labels);

        /*
            Let's try the graph_labeler on a new test graph.  In particular, let's
            use one with 5 nodes as shown below:

            (0 F)-----(1 T)
              |         |
              |         |
              |         |
            (3 T)-----(2 T)------(4 T)

            I have annotated each node with either T or F to indicate the correct
            output (true or false).
        */
        graph_type g;
        g.set_number_of_nodes(5);
        g.node(0).data = 1, 0;  // Node data indicates a false node.
        g.node(1).data = 0, 1;  // Node data indicates a true node.
        g.node(2).data = 0, 0;  // Node data is ambiguous.
        g.node(3).data = 0, 0;  // Node data is ambiguous.
        g.node(4).data = 0.1, 0; // Node data slightly indicates a false node.

        g.add_edge(0,1);
        g.add_edge(1,2);
        g.add_edge(2,3);
        g.add_edge(3,0);
        g.add_edge(2,4);

        // Set the edges up so nodes 1, 2, 3, and 4 are all strongly connected.
        edge(g,0,1) = 0;
        edge(g,1,2) = 1;
        edge(g,2,3) = 1;
        edge(g,3,0) = 0;
        edge(g,2,4) = 1;

        // The output of this shows all the nodes are correctly labeled.
        cout << "Predicted labels: " << endl;
        std::vector<bool> temp = labeler(g);
        for (unsigned long i = 0; i < temp.size(); ++i)
            cout << " " << i << ": " << temp[i] << endl;

        // Breaking the strong labeling consistency link between node 1 and 2 causes
        // nodes 2, 3, and 4 to flip to false.  This is because of their connection
        // to node 4 which has a small preference for false.
        edge(g,1,2) = 0;
        cout << "Predicted labels: " << endl;
        temp = labeler(g);
        for (unsigned long i = 0; i < temp.size(); ++i)
            cout << " " << i << ": " << temp[i] << endl;
    }
    catch (std::exception& e)
    {
        cout << "Error, an exception was thrown!" << endl;
        cout << e.what() << endl;


dlib C++ Library - gui_api_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example illustrating the use of the gui api from the dlib C++ Library.

    This is a pretty simple example.  It makes a window with a user
    defined widget (a draggable colored box) and a button.  You can drag the
    box around or click the button which increments a counter.
*/

#include <dlib/gui_widgets.h>
#include <sstream>
#include <string>

using namespace std;
using namespace dlib;

//  ----------------------------------------------------------------------------

class color_box : public draggable
{
    /*
        Here I am defining a custom drawable widget that is a colored box that
        you can drag around on the screen.  draggable is a special kind of drawable
        object that, as the name implies, is draggable by the user via the mouse.
        To make my color_box draggable all I need to do is inherit from 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),
        red(red_),
        green(green_),
        blue(blue_)
    {
        rect = area;
        set_draggable_area(rectangle(10,10,400,400));

        // Whenever you make your own drawable widget (or inherit from any drawable widget
        // or interface such as draggable) you have to remember to call this function to
        // enable the events.  The idea here is that you can perform whatever setup you
        // need to do to get your object into a valid state without needing to worry about
        // event handlers triggering before you are ready.
        enable_events();
    }

    ~color_box (
    )
    {
        // Disable all further events for this drawable object.  We have to do this
        // because we don't want any events (like draw()) coming to this object while or
        // after it has been destructed.
        disable_events();

        // Tell the parent window to redraw its area that previously contained this
        // drawable object.
        parent.invalidate_rectangle(rect);
    }

private:

    void draw (
        const canvas& c
    ) const
    {
        // The canvas is an object that represents a part of the parent window
        // that needs to be redrawn.

        // The first thing I usually do is check if the draw call is for part
        // of the window that overlaps with my widget.  We don't have to do this
        // but it is usually good to do as a speed hack.  Also, the reason
        // I don't have it set to only give you draw calls when it does indeed
        // overlap is because you might want to do some drawing outside of your
        // widget's rectangle.  But usually you don't want to do that :)
        rectangle area = c.intersect(rect);
        if (area.is_empty() == true)
            return;

        // This simple widget is just going to draw a box on the screen.
        fill_rect(c,rect,rgb_pixel(red,green,blue));
    }
};

//  ----------------------------------------------------------------------------

class win : public drawable_window
{
    /*
        Here I am going to define our window.  In general, you can define as
        many window types as you like and make as many instances of them as you want.
        In this example I am only making one though.
    */
public:
    win(
    ) : // All widgets take their parent window as an argument to their constructor.
        c(*this),
        b(*this),
        cb(*this,rectangle(100,100,200,200),0,0,255), // the color_box will be blue and 101 pixels wide and tall
        mbar(*this)
    {
        // tell our button to put itself at the position (10,60).
        b.set_pos(10,60);
        b.set_name("button");

        // let's put the label 5 pixels below the button
        c.set_pos(b.left(),b.bottom()+5);

        // set which function should get called when the button gets clicked.  In this case we want
        // the on_button_clicked member to be called on *this.
        b.set_click_handler(*this,&win::on_button_clicked);
        // Alternatively, if you have a compiler which supports the lambda functions from the
        // new C++ standard then you can use a lambda function instead of telling the click
        // handler to call one of the member functions.  So for example, you could do this
        // instead (uncomment the code if you have C++0x support):
        /*
        b.set_click_handler([&](){
                ++counter;
                ostringstream sout;
                sout << "Counter: " << counter;
                c.set_text(sout.str());
                });
        */
        // In general, all the functions which register events can take either member
        // functions or lambda functions.

        // Let's also make a simple menu bar.
        // First we say how many menus we want in our menu bar.  In this example we only want 1.
        mbar.set_number_of_menus(1);
        // Now we set the name of our menu.  The 'M' means that the M in Menu will be underlined
        // and the user will be able to select it by hitting alt+M
        mbar.set_menu_name(0,"Menu",'M');

        // Now we add some items to the menu.  Note that items in a menu are listed in the
        // order in which they were added.

        // First let's make a menu item that does the same thing as our button does when it is clicked.
        // Again, the 'C' means the C in Click is underlined in the menu.
        mbar.menu(0).add_menu_item(menu_item_text("Click Button!",*this,&win::on_button_clicked,'C'));
        // let's add a separator (i.e. a horizontal separating line) to the menu
        mbar.menu(0).add_menu_item(menu_item_separator());
        // Now let's make a menu item that calls show_about when the user selects it.
        mbar.menu(0).add_menu_item(menu_item_text("About",*this,&win::show_about,'A'));

        // set the size of this window
        set_size(430,380);

        counter = 0;

        set_title("dlib gui example");
        show();
    }

    ~win(
    )
    {
        // You should always call close_window() in the destructor of window
        // objects to ensure that no events will be sent to this window while
        // it is being destructed.
        close_window();
    }

private:

    void on_button_clicked (
    )
    {
        // when someone clicks our button it will increment the counter and
        // display it in our label c.
        ++counter;
        ostringstream sout;
        sout << "counter: " << counter;
        c.set_text(sout.str());
    }

    void show_about(
    )
    {
        message_box("About","This is a dlib gui example program");
    }

    unsigned long counter;
    label c;
    button b;
    color_box cb;
    menu_bar mbar;
};

//  ----------------------------------------------------------------------------

int main()
{
    // create our window
    win my_window;

    // wait until the user closes this window before we let the program
    // terminate.
    my_window.wait_until_closed();

    return 0;
}

//  ----------------------------------------------------------------------------

// Normally, if you built this application on MS Windows in Visual Studio you
// would see a black console window pop up when you ran it.  The following
// #pragma directives tell Visual Studio to not include a console window along
// with your application.  However, if you prefer to have the console pop up as
// well then simply remove these #pragma statements.
#ifdef _MSC_VER
#   pragma comment( linker, "/entry:mainCRTStartup" )
#   pragma comment( linker, "/SUBSYSTEM:WINDOWS" )
#endif

//  ----------------------------------------------------------------------------


dlib C++ Library - hough_transform_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example illustrating the use of the Hough transform tool in the
    dlib C++ Library.

    In this example we are going to draw a line on an image and then use the
    Hough transform to detect the location of the line.  Moreover, we do this in
    a loop that changes the line's position slightly each iteration, which gives
    a pretty animation of the Hough transform in action.
*/

#include <dlib/gui_widgets.h>
#include <dlib/image_transforms.h>

using namespace dlib;

int main()
{
    // First let's make a 400x400 image.  This will form the input to the Hough transform.
    array2d<unsigned char> img(400,400);
    // Now we make a hough_transform object.  The 300 here means that the Hough transform
    // will operate on a 300x300 subwindow of its input image.
    hough_transform ht(300);

    image_window win, win2;
    double angle1 = 0;
    double angle2 = 0;
    while(true)
    {
        // Generate a line segment that is rotating around inside the image.  The line is
        // generated based on the values in angle1 and angle2. So each iteration creates a
        // slightly different line.
        angle1 += pi/130;
        angle2 += pi/400;
        const point cent = center(get_rect(img));
        // A point 90 pixels away from the center of the image but rotated by angle1.
        const point arc = rotate_point(cent, cent + point(90,0), angle1);
        // Now make a line that goes though arc but rotate it by angle2.
        const point l = rotate_point(arc, arc + point(500,0), angle2);
        const point r = rotate_point(arc, arc - point(500,0), angle2);

        // Next, blank out the input image and then draw our line on it.
        assign_all_pixels(img, 0);
        draw_line(img, l, r, 255);

        const point offset(50,50);
        array2d<int> himg;
        // pick the window inside img on which we will run the Hough transform.
        const rectangle box = translate_rect(get_rect(ht),offset);
        // Now let's compute the hough transform for a subwindow in the image.  In
        // particular, we run it on the 300x300 subwindow with an upper left corner at the
        // pixel point(50,50).  The output is stored in himg.
        ht(img, box, himg);
        // Now that we have the transformed image, the Hough image pixel with the largest
        // value should indicate where the line is.  So we find the coordinates of the
        // largest pixel:
        point p = max_point(mat(himg));
        // And then ask the ht object for the line segment in the original image that
        // corresponds to this point in Hough transform space.
        std::pair<point,point> line = ht.get_line(p);

        // Finally, let's display all these things on the screen.  We copy the original
        // input image into a color image and then draw the detected line on top in red.
        array2d<rgb_pixel> temp;
        assign_image(temp, img);
        // Note that we must offset the output line to account for our offset subwindow.
        // We do this by just adding in the offset to the line endpoints.
        draw_line(temp, line.first+offset, line.second+offset, rgb_pixel(255,0,0));
        win.clear_overlay();
        win.set_image(temp);
        // Also show the subwindow we ran the Hough transform on as a green box.  You will
        // see that the detected line is exactly contained within this box and also
        // overlaps the original line.
        win.add_overlay(box, rgb_pixel(0,255,0));

        // We can also display the Hough transform itself using the jet color scheme.
        win2.set_image(jet(himg));


dlib C++ Library - server_http_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This example illustrates the use of the HTTP extension to the server object
    from the dlib C++ Library.
    It creates a server that always responds with a simple HTML form.

    To view the page this program displays you should go to http://localhost:5000

*/

#include <iostream>
#include <sstream>
#include <string>
#include <dlib/server.h>

using namespace dlib;
using namespace std;

class web_server : public server_http
{
    const std::string on_request (
        const incoming_things& incoming,
        outgoing_things& outgoing
    )
    {
        ostringstream sout;
        // We are going to send back a page that contains an HTML form with two text input fields.
        // One field called name.  The HTML form uses the post method but could also use the get
        // method (just change method='post' to method='get').
        sout << " <html> <body> "
            << "<form action='/form_handler' method='post'> "
            << "User Name: <input name='user' type='text'><br>  "
            << "User password: <input name='pass' type='text'> <input type='submit'> "
            << " </form>";

        // Write out some of the inputs to this request so that they show up on the
        // resulting web page.
        sout << "<br>  path = "         << incoming.path << endl;
        sout << "<br>  request_type = " << incoming.request_type << endl;
        sout << "<br>  content_type = " << incoming.content_type << endl;
        sout << "<br>  protocol = "     << incoming.protocol << endl;
        sout << "<br>  foreign_ip = "   << incoming.foreign_ip << endl;
        sout << "<br>  foreign_port = " << incoming.foreign_port << endl;
        sout << "<br>  local_ip = "     << incoming.local_ip << endl;
        sout << "<br>  local_port = "   << incoming.local_port << endl;
        sout << "<br>  body = \""       << incoming.body << "\"" << endl;

        // If this request is the result of the user submitting the form then echo back
        // the submission.
        if (incoming.path == "/form_handler")
        {
            sout << "<h2> Stuff from the query string </h2>" << endl;
            sout << "<br>  user = " << incoming.queries["user"] << endl;
            sout << "<br>  pass = " << incoming.queries["pass"] << endl;

            // save these form submissions as cookies.
            outgoing.cookies["user"] = incoming.queries["user"];
            outgoing.cookies["pass"] = incoming.queries["pass"];
        }

        // Echo any cookies back to the client browser
        sout << "<h2>Cookies the web browser sent to the server</h2>";
        for ( key_value_map::const_iterator ci = incoming.cookies.begin(); ci != incoming.cookies.end(); ++ci )
        {
            sout << "<br/>" << ci->first << " = " << ci->second << endl;
        }

        sout << "<br/><br/>";

        sout << "<h2>HTTP Headers the web browser sent to the server</h2>";
        // Echo out all the HTTP headers we received from the client web browser
        for ( key_value_map_ci::const_iterator ci = incoming.headers.begin(); ci != incoming.headers.end(); ++ci )
        {
            sout << "<br/>" << ci->first << ": " << ci->second << endl;
        }

        sout << "</body> </html>";

        return sout.str();
    }

};

int main()
{
    try
    {
        // create an instance of our web server
        web_server our_web_server;

        // make it listen on port 5000
        our_web_server.set_listening_port(5000);
        // Tell the server to begin accepting connections.
        our_web_server.start_async();

        cout << "Press enter to end this program" << endl;
        cin.get();
    }
    catch (exception& e)
    {
        cout << e.what() << endl;


dlib C++ Library - image_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example illustrating the use of the GUI API as well as some
    aspects of image manipulation from the dlib C++ Library.

    This is a pretty simple example.  It takes a BMP file on the command line
    and opens it up, runs a simple edge detection algorithm on it, and
    displays the results on the screen.
*/

#include <dlib/gui_widgets.h>
#include <dlib/image_io.h>
#include <dlib/image_transforms.h>
#include <fstream>

using namespace std;
using namespace dlib;

//  ----------------------------------------------------------------------------

int main(int argc, char** argv)
{
    try
    {
        // make sure the user entered an argument to this program
        if (argc != 2)
        {
            cout << "error, you have to enter a BMP file as an argument to this program" << endl;
            return 1;
        }

        // Here we declare an image object that can store rgb_pixels.  Note that in
        // dlib there is no explicit image object, just a 2D array and
        // various pixel types.
        array2d<rgb_pixel> img;

        // Now load the image file into our image.  If something is wrong then
        // load_image() will throw an exception.  Also, if you linked with libpng
        // and libjpeg then load_image() can load PNG and JPEG files in addition
        // to BMP files.
        load_image(img, argv[1]);

        // Now let's use some image functions.  First let's blur the image a little.
        array2d<unsigned char> blurred_img;
        gaussian_blur(img, blurred_img);

        // Now find the horizontal and vertical gradient images.
        array2d<short> horz_gradient, vert_gradient;
        array2d<unsigned char> edge_image;
        sobel_edge_detector(blurred_img, horz_gradient, vert_gradient);

        // now we do the non-maximum edge suppression step so that our edges are nice and thin
        suppress_non_maximum_edges(horz_gradient, vert_gradient, edge_image);

        // Now we would like to see what our images look like.  So let's use a
        // window to display them on the screen.  (Note that you can zoom into
        // the window by holding CTRL and scrolling the mouse wheel)
        image_window my_window(edge_image, "Normal Edge Image");

        // We can also easily display the edge_image as a heatmap or using the jet color
        // scheme like so.
        image_window win_hot(heatmap(edge_image));
        image_window win_jet(jet(edge_image));

        // also make a window to display the original image
        image_window my_window2(img, "Original Image");

        // Sometimes you want to get input from the user about which pixels are important
        // for some task.  You can do this easily by trapping user clicks as shown below.
        // This loop executes every time the user double clicks on some image pixel and it
        // will terminate once the user closes the window.
        point p;
        while (my_window.get_next_double_click(p))
        {
            cout << "User double clicked on pixel:         " << p << endl;
            cout << "edge pixel value at this location is: " << (int)edge_image[p.y()][p.x()] << endl;
        }

        // wait until the user closes the windows before we let the program
        // terminate.
        win_hot.wait_until_closed();
        my_window2.wait_until_closed();

        // Finally, note that you can access the elements of an image using the normal [row][column]
        // operator like so:
        cout << horz_gradient[0][3] << endl;
        cout << "number of rows in image:    " << horz_gradient.nr() << endl;
        cout << "number of columns in image: " << horz_gradient.nc() << endl;
    }
    catch (exception& e)
    {
        cout << "exception thrown: " << e.what() << endl;
    }
}

//  ----------------------------------------------------------------------------


dlib C++ Library - iosockstream_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example illustrating the use of the iosockstream object from the
    dlib C++ Library.

    This program simply connects to www.google.com at port 80 and requests the
    main Google web page.  It then prints what it gets back from Google to the
    screen.

    For those of you curious about HTTP check out the excellent introduction at
    http://www.jmarshall.com/easy/http/
*/

#include <dlib/iosockstream.h>
#include <iostream>

using namespace std;
using namespace dlib;

int main()
{
    try
    {
        // Connect to Google's web server which listens on port 80.  If this
        // fails it will throw a dlib::socket_error exception.
        iosockstream stream("www.google.com:80");

        // At this point, we can use stream the same way we would use any other
        // C++ iostream object.  So to test it out, let's make a HTTP GET request
        // for the main Google page.
        stream << "GET / HTTP/1.0\r\n\r\n";

        // Here we print each character we get back one at a time.
        while (stream.peek() != EOF)
        {
            cout << (char)stream.get();
        }
    }
    catch (exception& e)
    {
        cout << e.what() << endl;


dlib C++ Library - server_iostream_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example illustrating the use of the server_iostream object from
    the dlib C++ Library.

    This is a simple echo server.  It listens on port 1234 for incoming
    connections and just echos back any text it receives, but in upper case.  So
    basically it is the same as the sockets_ex.cpp example program  except it
    uses iostreams.

    To test it out you can just open a command prompt and type:
    telnet localhost 1234

    Then you can type away.

*/

#include <dlib/server.h>
#include <iostream>

using namespace dlib;
using namespace std;

class serv : public server_iostream
{

    void on_connect  (
        std::istream& in,
        std::ostream& out,
        const std::string& foreign_ip,
        const std::string& local_ip,
        unsigned short foreign_port,
        unsigned short local_port,
        uint64 connection_id
    )
    {
        // The details of the connection are contained in the last few arguments to
        // on_connect().  For more information, see the documentation for the
        // server_iostream.  However, the main arguments of interest are the two streams.
        // Here we also print the IP address of the remote machine.
        cout << "Got a connection from " << foreign_ip << endl;

        // Loop until we hit the end of the stream.  This happens when the connection
        // terminates.
        while (in.peek() != EOF)
        {
            // get the next character from the client
            char ch = in.get();

            // now echo it back to them
            out << (char)toupper(ch);
        }
    }

};

int main()
{
    try
    {
        serv our_server;

        // set up the server object we have made
        our_server.set_listening_port(1234);
        // Tell the server to begin accepting connections.
        our_server.start_async();

        cout << "Press enter to end this program" << endl;
        cin.get();
    }
    catch (exception& e)
    {
        cout << e.what() << endl;


dlib C++ Library - kcentroid_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*
    This is an example illustrating the use of the kcentroid object
    from the dlib C++ Library.

    The kcentroid object is an implementation of an algorithm that recursively
    computes the centroid (i.e. average) of a set of points.  The interesting
    thing about dlib::kcentroid is that it does so in a kernel induced feature
    space.  This means that you can use it as a non-linear one-class classifier.
    So you might use it to perform online novelty detection (although, it has
    other uses, see the svm_pegasos or kkmeans examples for example).

    This example will train an instance of it on points from the sinc function.

*/

#include <iostream>
#include <vector>

#include <dlib/svm.h>
#include <dlib/statistics.h>

using namespace std;
using namespace dlib;

// Here is the sinc function we will be trying to learn with the kcentroid
// object.
double sinc(double x)
{
    if (x == 0)
        return 1;
    return sin(x)/x;
}

int main()
{
    // Here we declare that our samples will be 2 dimensional column vectors.
    // (Note that if you don't know the dimensionality of your vectors at compile time
    // you can change the 2 to a 0 and then set the size at runtime)
    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 kcentroid has 3 parameters
    // you need to set.  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 the centroid estimation.  Generally, smaller values
    // give better results but cause the algorithm to attempt to use more dictionary vectors
    // (and thus run slower and use more memory).  The third argument, however, is the
    // maximum number of dictionary vectors a kcentroid is allowed to use.  So you can use
    // it to control the runtime complexity.
    kcentroid<kernel_type> test(kernel_type(0.1),0.01, 15);

    // 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);
    }

    running_stats<double> rs;

    // Now let's 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.
    cout << "Points that are on the sinc function:\n";
    m(0) = -1.5; m(1) = sinc(m(0)); cout << "   " << test(m) << endl;  rs.add(test(m));
    m(0) = -1.5; m(1) = sinc(m(0)); cout << "   " << test(m) << endl;  rs.add(test(m));
    m(0) = -0;   m(1) = sinc(m(0)); cout << "   " << test(m) << endl;  rs.add(test(m));
    m(0) = -0.5; m(1) = sinc(m(0)); cout << "   " << test(m) << endl;  rs.add(test(m));
    m(0) = -4.1; m(1) = sinc(m(0)); cout << "   " << test(m) << endl;  rs.add(test(m));
    m(0) = -1.5; m(1) = sinc(m(0)); cout << "   " << test(m) << endl;  rs.add(test(m));
    m(0) = -0.5; m(1) = sinc(m(0)); cout << "   " << test(m) << endl;  rs.add(test(m));

    cout << endl;
    // Let's 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.
    cout << "Points that are NOT on the sinc function:\n";
    m(0) = -1.5; m(1) = sinc(m(0))+4;   cout << "   " << test(m) << " is " << rs.scale(test(m)) << " standard deviations from sinc." << endl;
    m(0) = -1.5; m(1) = sinc(m(0))+3;   cout << "   " << test(m) << " is " << rs.scale(test(m)) << " standard deviations from sinc." << endl;
    m(0) = -0;   m(1) = -sinc(m(0));    cout << "   " << test(m) << " is " << rs.scale(test(m)) << " standard deviations from sinc." << endl;
    m(0) = -0.5; m(1) = -sinc(m(0));    cout << "   " << test(m) << " is " << rs.scale(test(m)) << " standard deviations from sinc." << endl;
    m(0) = -4.1; m(1) = sinc(m(0))+2;   cout << "   " << test(m) << " is " << rs.scale(test(m)) << " standard deviations from sinc." << endl;
    m(0) = -1.5; m(1) = sinc(m(0))+0.9; cout << "   " << test(m) << " is " << rs.scale(test(m)) << " standard deviations from sinc." << endl;
    m(0) = -0.5; m(1) = sinc(m(0))+1;   cout << "   " << test(m) << " is " << rs.scale(test(m)) << " standard deviations from sinc." << endl;

    // And finally print out the mean and standard deviation of points that are actually from sinc().
    cout << "\nmean: " << rs.mean() << endl;
    cout << "standard deviation: " << rs.stddev() << endl;

    // The output is as follows:
    /*
        Points that are on the sinc function:
            0.869913
            0.869913
            0.873408
            0.872807
            0.870432
            0.869913
            0.872807

        Points that are NOT on the sinc function:
            1.06366 is 119.65 standard deviations from sinc.
            1.02212 is 93.8106 standard deviations from sinc.
            0.921382 is 31.1458 standard deviations from sinc.
            0.918439 is 29.3147 standard deviations from sinc.
            0.931428 is 37.3949 standard deviations from sinc.
            0.898018 is 16.6121 standard deviations from sinc.
            0.914425 is 26.8183 standard deviations from sinc.

            mean: 0.871313
            standard deviation: 0.00160756
    */

    // So we can see that in this example the kcentroid object correctly indicates that
    // the non-sinc points are definitely not points from the sinc function.


dlib C++ Library - kkmeans_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*
    This is an example illustrating the use of the kkmeans object
    and spectral_cluster() routine from the dlib C++ Library.

    The kkmeans object is an implementation of a kernelized k-means clustering
    algorithm.  It is implemented by using the kcentroid object to represent
    each center found by the usual k-means clustering algorithm.

    So this object allows you to perform non-linear clustering in the same way
    a svm classifier finds non-linear decision surfaces.

    This example will make points from 3 classes and perform kernelized k-means
    clustering on those points.  It will also do the same thing using spectral
    clustering.

    The classes are as follows:
        - points very close to the origin
        - points on the circle of radius 10 around the origin
        - points that are on a circle of radius 4 but not around the origin at all
*/

#include <iostream>
#include <vector>

#include <dlib/clustering.h>
#include <dlib/rand.h>

using namespace std;
using namespace dlib;

int main()
{
    // Here we declare that our samples will be 2 dimensional column vectors.
    // (Note that if you don't know the dimensionality of your vectors at compile time
    // you can change the 2 to a 0 and then set the size at runtime)
    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.  It is the object used to
    // represent each of the centers used for clustering.  The kcentroid has 3 parameters
    // you need to set.  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 attempt to use more dictionary vectors
    // (and thus run slower and use more memory).  The third argument, however, is the
    // maximum number of dictionary vectors a kcentroid is allowed to use.  So you can use
    // it to control the runtime complexity.
    kcentroid<kernel_type> kc(kernel_type(0.1),0.01, 8);

    // 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;

    // 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);
    }

    // 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());

    // now run the k-means algorithm on our set of samples.
    test.train(samples,initial_centers);

    // 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)
    {
        cout << test(samples[i]) << " ";
        cout << test(samples[i+num]) << " ";
        cout << test(samples[i+2*num]) << "\n";
    }

    // Now print out how many dictionary vectors each center used.  Note that
    // the maximum number of 8 was reached.  If you went back to the kcentroid
    // constructor and changed the 8 to some bigger number you would see that these
    // numbers would go up.  However, 8 is all we need to correctly cluster this dataset.
    cout << "num dictionary vectors for center 0: " << test.get_kcentroid(0).dictionary_size() << endl;
    cout << "num dictionary vectors for center 1: " << test.get_kcentroid(1).dictionary_size() << endl;
    cout << "num dictionary vectors for center 2: " << test.get_kcentroid(2).dictionary_size() << endl;

    // Finally, we can also solve the same kind of non-linear clustering problem with
    // spectral_cluster().  The output is a vector that indicates which cluster each sample
    // belongs to.  Just like with kkmeans, it assigns each point to the correct cluster.
    std::vector<unsigned long> assignments = spectral_cluster(kernel_type(0.1), samples, 3);
    cout << mat(assignments) << endl;


dlib C++ Library - krr_regression_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*
    This is an example illustrating the use of the kernel ridge regression
    object from the dlib C++ Library.

    This example will train on data from the sinc function.

*/

#include <iostream>
#include <vector>

#include <dlib/svm.h>

using namespace std;
using namespace dlib;

// Here is the sinc function we will be trying to learn with kernel ridge regression
double sinc(double x)
{
    if (x == 0)
        return 1;
    return sin(x)/x;
}

int main()
{
    // Here we declare that our samples will be 1 dimensional column vectors.
    typedef matrix<double,1,1> sample_type;

    // Now sample some points from the sinc() function
    sample_type m;
    std::vector<sample_type> samples;
    std::vector<double> labels;
    for (double x = -10; x <= 4; x += 1)
    {
        m(0) = x;
        samples.push_back(m);
        labels.push_back(sinc(x));
    }

    // 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 krr_trainer object.  This is the
    // object that we will later use to do the training.
    krr_trainer<kernel_type> trainer;

    // Here we set the kernel we want to use for training.   The radial_basis_kernel
    // has a parameter called gamma that we need to determine.  As a rule of thumb, a good
    // gamma to try is 1.0/(mean squared distance between your sample points).  So
    // below we are using a similar value computed from at most 2000 randomly selected
    // samples.
    const double gamma = 3.0/compute_mean_squared_distance(randomly_subsample(samples, 2000));
    cout << "using gamma of " << gamma << endl;
    trainer.set_kernel(kernel_type(gamma));

    // now train a function based on our sample points
    decision_function<kernel_type> test = trainer.train(samples, labels);

    // now we output the value of the sinc function for a few test points as well as the
    // value predicted by our regression.
    m(0) = 2.5; cout << sinc(m(0)) << "   " << test(m) << endl;
    m(0) = 0.1; cout << sinc(m(0)) << "   " << test(m) << endl;
    m(0) = -4;  cout << sinc(m(0)) << "   " << test(m) << endl;
    m(0) = 5.0; cout << sinc(m(0)) << "   " << test(m) << endl;

    // The output is as follows:
    //using gamma of 0.075
    //    0.239389   0.239389
    //    0.998334   0.998362
    //    -0.189201   -0.189254
    //    -0.191785   -0.186618

    // The first column is the true value of the sinc function and the second
    // column is the output from the krr estimate.

    // Note that the krr_trainer has the ability to tell us the leave-one-out predictions
    // for each sample.
    std::vector<double> loo_values;
    trainer.train(samples, labels, loo_values);
    cout << "mean squared LOO error: " << mean_squared_error(labels,loo_values) << endl;
    cout << "R^2 LOO value:          " << r_squared(labels,loo_values) << endl;
    // Which outputs the following:
    // mean squared LOO error: 8.29575e-07
    // R^2 LOO value:          0.999995

    // Another thing that is worth knowing is that just about everything in dlib is serializable.
    // So for example, you can save the test object to disk and recall it later like so:
    serialize("saved_function.dat") << test;

    // Now let's open that file back up and load the function object it contains.
    deserialize("saved_function.dat") >> test;


dlib C++ Library - krls_filter_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*
    This is an example illustrating the use of the krls object
    from the dlib C++ Library.

    The krls object allows you to perform online regression.  This
    example will use the krls object to perform filtering of a signal
    corrupted by uniformly distributed noise.
*/

#include <iostream>

#include <dlib/svm.h>
#include <dlib/rand.h>

using namespace std;
using namespace dlib;

// Here is the function we will be trying to learn with the krls
// object.
double sinc(double x)
{
    if (x == 0)
        return 1;

    // also add in x just to make this function a little more complex
    return sin(x)/x + x;
}

int main()
{
    // 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 (because it tries
    // to use more "dictionary vectors" to represent the function it is learning.
    // 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.
    //
    // The last argument is the maximum number of dictionary vectors the algorithm is allowed
    // to use.  The default value for this field is 1,000,000 which is large enough that you
    // won't ever hit it in practice.  However, here we have set it to the much smaller value
    // of 7.  This means that once the krls object accumulates 7 dictionary vectors it will
    // start discarding old ones in favor of new ones as it goes through the training process.
    // In other words, the algorithm "forgets" about old training data and focuses on recent
    // training samples. So the bigger the maximum dictionary size the longer its memory will
    // be.  But in this example program we are doing filtering so we only care about the most
    // recent data.  So using a small value is appropriate here since it will result in much
    // faster filtering and won't introduce much error.
    krls<kernel_type> test(kernel_type(0.05),0.001,7);

    dlib::rand rnd;

    // Now let's loop over a big range of values from the sinc() function.  Each time
    // adding some random noise to the data we send to the krls object for training.
    sample_type m;
    double mse_noise = 0;
    double mse = 0;
    double count = 0;
    for (double x = -20; x <= 20; x += 0.01)
    {
        m(0) = x;
        // get a random number between -0.5 and 0.5
        const double noise = rnd.get_random_double()-0.5;

        // train on this new sample
        test.train(m, sinc(x)+noise);

        // once we have seen a bit of data start measuring the mean squared prediction error.
        // Also measure the mean squared error due to the noise.
        if (x > -19)
        {
            ++count;
            mse += pow(sinc(x) - test(m),2);
            mse_noise += pow(noise,2);
        }
    }

    mse /= count;
    mse_noise /= count;

    // Output the ratio of the error from the noise and the mean squared prediction error.
    cout << "prediction error:                   " << mse << endl;
    cout << "noise:                              " << mse_noise << endl;
    cout << "ratio of noise to prediction error: " << mse_noise/mse << endl;

    // When the program runs it should print the following:
    //    prediction error:                   0.00735201
    //    noise:                              0.0821628
    //    ratio of noise to prediction error: 11.1756

    // And we see that the noise has been significantly reduced by filtering the points
    // through the krls object.


dlib C++ Library - krls_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*
    This is an example illustrating the use of the krls object
    from the dlib C++ Library.

    The krls object allows you to perform online regression.  This
    example will train an instance of it on the sinc function.

*/

#include <iostream>
#include <vector>

#include <dlib/svm.h>

using namespace std;
using namespace dlib;

// 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;
}

int main()
{
    // Here we declare that our samples will be 1 dimensional column vectors.  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.  (Note that if you don't know the
    // dimensionality of your vectors at compile time you can change the first number to
    // a 0 and then set the size at runtime)
    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);

    // now we train our object on a few samples of the sinc function.
    sample_type m;
    for (double x = -10; x <= 4; x += 1)
    {
        m(0) = x;
        test.train(m, sinc(x));
    }

    // 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; cout << sinc(m(0)) << "   " << test(m) << endl;
    m(0) = 0.1; cout << sinc(m(0)) << "   " << test(m) << endl;
    m(0) = -4;  cout << sinc(m(0)) << "   " << test(m) << endl;
    m(0) = 5.0; cout << sinc(m(0)) << "   " << test(m) << endl;

    // The output is as follows:
    // 0.239389   0.239362
    // 0.998334   0.998333
    // -0.189201   -0.189201
    // -0.191785   -0.197267

    // The first column is the true value of the sinc function and the second
    // column is the output from the krls estimate.

    // Another thing that is worth knowing is that just about everything in dlib is serializable.
    // So for example, you can save the test object to disk and recall it later like so:
    serialize("saved_krls_object.dat") << test;

    // Now let's open that file back up and load the krls object it contains.
    deserialize("saved_krls_object.dat") >> test;

    // If you don't want to save the whole krls object (it might be a bit large)
    // you can save just the decision function it has learned so far.  You can get
    // the decision function out of it by calling test.get_decision_function() and
    // then you can serialize that object instead.  E.g.
    decision_function<kernel_type> funct = test.get_decision_function();
    serialize("saved_krls_function.dat") << funct;


dlib C++ Library - krr_classification_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example illustrating the use of the kernel ridge regression
    object from the dlib C++ Library.

    This example creates a simple set of data to train on and then shows
    you how to use the kernel ridge regression tool to find a good decision
    function that can classify examples in our data set.

    The data used in this example will be 2 dimensional data and will
    come from a distribution where points with a distance less than 13
    from the origin are labeled +1 and all other points are labeled
    as -1.  All together, the dataset will contain 10201 sample points.

*/

#include <iostream>
#include <dlib/svm.h>

using namespace std;
using namespace dlib;

int main()
{
    // This typedef declares a matrix with 2 rows and 1 column.  It will be the
    // object that contains each of our 2 dimensional samples.   (Note that if you wanted
    // more than 2 features in this vector you can simply change the 2 to something else.
    // Or if you don't know how many features you want until runtime then you can put a 0
    // here and use the matrix.set_size() member function)
    typedef matrix<double, 2, 1> sample_type;

    // This is a typedef for the type of kernel we are going to use in this example.
    // In this case I have selected the radial basis kernel that can operate on our
    // 2D sample_type objects
    typedef radial_basis_kernel<sample_type> kernel_type;

    // Now we make objects to contain our samples and their respective labels.
    std::vector<sample_type> samples;
    std::vector<double> labels;

    // Now let's put some data into our samples and labels objects.  We do this
    // by looping over a bunch of points and labeling them according to their
    // distance from the origin.
    for (double r = -20; r <= 20; r += 0.4)
    {
        for (double c = -20; c <= 20; c += 0.4)
        {
            sample_type samp;
            samp(0) = r;
            samp(1) = c;
            samples.push_back(samp);

            // if this point is less than 13 from the origin
            if (sqrt((double)r*r + c*c) <= 13)
                labels.push_back(+1);
            else
                labels.push_back(-1);

        }
    }

    cout << "samples generated: " << samples.size() << endl;
    cout << "  number of +1 samples: " << sum(mat(labels) > 0) << endl;
    cout << "  number of -1 samples: " << sum(mat(labels) < 0) << endl;

    // Here we normalize all the samples by subtracting their mean and dividing by their standard deviation.
    // This is generally a good idea since it often heads off numerical stability problems and also
    // prevents one large feature from smothering others.  Doing this doesn't matter much in this example
    // so I'm just doing this here so you can see an easy way to accomplish this with
    // the library.
    vector_normalizer<sample_type> normalizer;
    // let the normalizer learn the mean and standard deviation of the samples
    normalizer.train(samples);
    // now normalize each sample
    for (unsigned long i = 0; i < samples.size(); ++i)
        samples[i] = normalizer(samples[i]);

    // here we make an instance of the krr_trainer object that uses our kernel type.
    krr_trainer<kernel_type> trainer;

    // The krr_trainer has the ability to perform leave-one-out cross-validation.
    // It does this to automatically determine the regularization parameter.  Since
    // we are performing classification instead of regression we should be sure to
    // call use_classification_loss_for_loo_cv().  This function tells it to measure
    // errors in terms of the number of classification mistakes instead of mean squared
    // error between decision function output values and labels.
    trainer.use_classification_loss_for_loo_cv();

    // Now we loop over some different gamma values to see how good they are.
    cout << "\ndoing leave-one-out cross-validation" << endl;
    for (double gamma = 0.000001; gamma <= 1; gamma *= 5)
    {
        // tell the trainer the parameters we want to use
        trainer.set_kernel(kernel_type(gamma));

        // loo_values will contain the LOO predictions for each sample.  In the case
        // of perfect prediction it will end up being a copy of labels.
        std::vector<double> loo_values;
        trainer.train(samples, labels, loo_values);

        // Print gamma and the fraction of samples correctly classified during LOO cross-validation.
        const double classification_accuracy = mean_sign_agreement(labels, loo_values);
        cout << "gamma: " << gamma << "     LOO accuracy: " << classification_accuracy << endl;
    }

    // From looking at the output of the above loop it turns out that a good value for
    // gamma for this problem is 0.000625.  So that is what we will use.
    trainer.set_kernel(kernel_type(0.000625));
    typedef decision_function<kernel_type> dec_funct_type;
    typedef normalized_function<dec_funct_type> funct_type;

    // Here we are making an instance of the normalized_function object.  This object provides a convenient
    // way to store the vector normalization information along with the decision function we are
    // going to learn.
    funct_type learned_function;
    learned_function.normalizer = normalizer;  // save normalization information
    learned_function.function = trainer.train(samples, labels); // perform the actual training and save the results

    // print out the number of basis vectors in the resulting decision function
    cout << "\nnumber of basis vectors in our learned_function is "
         << learned_function.function.basis_vectors.size() << endl;

    // Now let's try this decision_function on some samples we haven't seen before.
    // The decision function will return values >= 0 for samples it predicts
    // are in the +1 class and numbers < 0 for samples it predicts to be in the -1 class.
    sample_type sample;

    sample(0) = 3.123;
    sample(1) = 2;
    cout << "This is a +1 class example, the classifier output is " << learned_function(sample) << endl;

    sample(0) = 3.123;
    sample(1) = 9.3545;
    cout << "This is a +1 class example, the classifier output is " << learned_function(sample) << endl;

    sample(0) = 13.123;
    sample(1) = 9.3545;
    cout << "This is a -1 class example, the classifier output is " << learned_function(sample) << endl;

    sample(0) = 13.123;
    sample(1) = 0;
    cout << "This is a -1 class example, the classifier output is " << learned_function(sample) << endl;

    // We can also train a decision function that reports a well conditioned probability
    // instead of just a number > 0 for the +1 class and < 0 for the -1 class.  An example
    // of doing that follows:
    typedef probabilistic_decision_function<kernel_type> probabilistic_funct_type;
    typedef normalized_function<probabilistic_funct_type> pfunct_type;

    // The train_probabilistic_decision_function() is going to perform 3-fold cross-validation.
    // So it is important that the +1 and -1 samples be distributed uniformly across all the folds.
    // calling randomize_samples() will make sure that is the case.
    randomize_samples(samples, labels);

    pfunct_type learned_pfunct;
    learned_pfunct.normalizer = normalizer;
    learned_pfunct.function = train_probabilistic_decision_function(trainer, samples, labels, 3);
    // Now we have a function that returns the probability that a given sample is of the +1 class.

    // print out the number of basis vectors in the resulting decision function.
    // (it should be the same as in the one above)
    cout << "\nnumber of basis vectors in our learned_pfunct is "
         << learned_pfunct.function.decision_funct.basis_vectors.size() << endl;

    sample(0) = 3.123;
    sample(1) = 2;
    cout << "This +1 class example should have high probability.  Its probability is: "
         << learned_pfunct(sample) << endl;

    sample(0) = 3.123;
    sample(1) = 9.3545;
    cout << "This +1 class example should have high probability.  Its probability is: "
         << learned_pfunct(sample) << endl;

    sample(0) = 13.123;
    sample(1) = 9.3545;
    cout << "This -1 class example should have low probability.  Its probability is: "
         << learned_pfunct(sample) << endl;

    sample(0) = 13.123;
    sample(1) = 0;
    cout << "This -1 class example should have low probability.  Its probability is: "
         << learned_pfunct(sample) << endl;

    // Another thing that is worth knowing is that just about everything in dlib is serializable.
    // So for example, you can save the learned_pfunct object to disk and recall it later like so:
    serialize("saved_function.dat") << learned_pfunct;

    // Now let's open that file back up and load the function object it contains.
    deserialize("saved_function.dat") >> learned_pfunct;


dlib C++ Library - learning_to_track_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*
    This example shows how you can use the dlib machine learning tools to make
    an object tracker.  Depending on your tracking application there can be a
    lot of components to a tracker.  However, a central element of many trackers
    is the "detection to track" association step and this is the part of the
    tracker we discuss in this example.  Therefore, in the code below we define
    simple detection and track structures and then go through the steps needed
    to learn, using training data, how to best associate detections to tracks.

    It should be noted that these tools are implemented essentially as wrappers
    around the more general assignment learning tools present in dlib.  So if
    you want to get an idea of how they work under the covers you should read
    the assignment_learning_ex.cpp example program and its supporting
    documentation.  However, to just use the learning-to-track tools you won't
    need to understand these implementation details.
*/

#include <iostream>
#include <dlib/svm_threaded.h>
#include <dlib/rand.h>

using namespace std;
using namespace dlib;

// ----------------------------------------------------------------------------------------

struct detection
{
    /*
        When you use these tools you need to define two structures.  One represents a
        detection and another a track.  In this example we call these structures detection
        and track but you can name them however you like.  Moreover, You can put anything
        you want in your detection structure.  The only requirement is that detection be
        copyable and contain a public typedef named track_type that tells us the track type
        meant for use with this detection object.
    */
    typedef struct track track_type;

    // Again, note that this field is NOT REQUIRED by the dlib tools.  You can put whatever
    // you want in your detection object.  Here we are including a column vector of
    // measurements from the sensor that generated the detection.  In this example we don't
    // have a real sensor so we will simulate a very basic one using a random number
    // generator.   But the idea is that you should be able to use the contents of your
    // detection to somehow tell which track it goes with.  So these numbers should contain
    // some identifying information about the real world object that caused this detection.
    matrix<double,0,1> measurements;
};

struct track
{
    /*
        Here we define our corresponding track object.  This object has more requirements
        than the detection.  In particular, the dlib machine learning tools require it to
        have the following elements:
            - A typedef named feature_vector_type
            - It should be copyable and default constructable
            - The three functions: get_similarity_features(), update_track(), and propagate_track()

        Just like the detection object, you can also add any additional fields you like.
        In this example we keep it simple and say that a track maintains only a copy of the
        most recent sensor measurements it has seen and also a number telling us how long
        it has been since the track was updated with a detection.
    */

    // This type should be a dlib::matrix capable of storing column vectors or an
    // unsorted sparse vector type such as std::vector<std::pair<unsigned long,double>>.
    typedef matrix<double,0,1> feature_vector_type;

    track()
    {
        time_since_last_association = 0;
    }

    void get_similarity_features(const detection& det, feature_vector_type& feats) const
    {
        /*
            The get_similarity_features() function takes a detection and outputs a feature
            vector that tells the machine learning tools how "similar" the detection is to
            the track.  The idea here is to output a set of numbers (i.e. the contents of
            feats) that can be used to decide if det should be associated with this track.
            In this example we output the difference between the last sensor measurements
            for this track and the detection's measurements.  This works since we expect
            the sensor measurements to be relatively constant for each track because that's
            how our simple sensor simulator in this example works.  However, in a real
            world application it's likely to be much more complex.  But here we keep things
            simple.

            It should also be noted that get_similarity_features() must always output
            feature vectors with the same number of dimensions.  Finally, the machine
            learning tools are going to learn a linear function of feats and use that to
            predict if det should associate to this track.  So try and define features that
            you think would work in a linear function.  There are all kinds of ways to do
            this.  If you want to get really clever about it you can even use kernel
            methods like the empirical_kernel_map (see empirical_kernel_map_ex.cpp).  I
            would start out with something simple first though.
        */
        feats = abs(last_measurements - det.measurements);
    }

    void update_track(const detection& det)
    {
        /*
            This function is called when the dlib tools have decided that det should be
            associated with this track.  So the point of update_track() is to, as the name
            suggests, update the track with the given detection.  In general, you can do
            whatever you want in this function.  Here we simply record the last measurement
            state and reset the time since last association.
        */
        last_measurements = det.measurements;
        time_since_last_association = 0;
    }

    void propagate_track()
    {
        /*
            This function is called when the dlib tools have decided, for the current time
            step, that none of the available detections associate with this track.  So the
            point of this function is to perform a track update without a detection.  To
            say that another way.  Every time you ask the dlib tools to perform detection
            to track association they will update each track by calling either
            update_track() or propagate_track().  Which function they call depends on
            whether or not a detection was associated to the track.
        */
        ++time_since_last_association;
    }

    matrix<double,0,1> last_measurements;
    unsigned long time_since_last_association;
};

// ----------------------------------------------------------------------------------------

/*
    Now that we have defined our detection and track structures we are going to define our
    sensor simulator.  In it we will imagine that there are num_objects things in the world
    and those things generate detections from our sensor.  Moreover, each detection from
    the sensor comes with a measurement vector with num_properties elements.

    So the first function, initialize_object_properties(), just randomly generates
    num_objects and saves them in a global variable.  Then when we are generating
    detections we will output copies of these objects that have been corrupted by a little
    bit of random noise.
*/

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()
{
    for (unsigned long i = 0; i < object_properties.size(); ++i)
        object_properties[i] = randm(num_properties,1,rnd);
}

// So here is our function that samples a detection from our simulated sensor.  You tell it
// what object you want to sample a detection from and it returns a detection from that
// object.
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;
}

// ----------------------------------------------------------------------------------------

typedef std::vector<labeled_detection<detection> > detections_at_single_time_step;
typedef std::vector<detections_at_single_time_step> track_history;

track_history make_random_tracking_data_for_training()
{
    /*
        Since we are using machine learning we need some training data.  This function
        samples data from our sensor and creates labeled track histories.  In these track
        histories, each detection is labeled with its true track ID.  The goal of the
        machine learning tools will then be to learn to associate all the detections with
        the same ID to the same track object.
    */

    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(0);
        dets[0].label = 0;

        // sample a detection from object 1
        dets[1].det = sample_detection_from_sensor(1);
        dets[1].label = 1;

        // sample a detection from object 2
        dets[2].det = sample_detection_from_sensor(2);
        dets[2].label = 2;

        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(0);
        dets[0].label = 0;

        // sample a detection from object 3
        dets[1].det = sample_detection_from_sensor(3);
        dets[1].label = 3;

        data.push_back(dets);
    }

    return data;
}

// ----------------------------------------------------------------------------------------

std::vector<detection> make_random_detections(long num_dets)
{
    /*
        Finally, when we test the tracker we learned we will need to sample regular old
        unlabeled detections.  This function helps us do that.
    */
    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(i);
    }
    return dets;
}

// ----------------------------------------------------------------------------------------

int main()
{
    initialize_object_properties();

    // Get some training data.  Here we sample 5 independent track histories.  In a real
    // world problem you would get this kind of data by, for example, collecting data from
    // your sensor on 5 separate days where you did an independent collection each day.
    // You can train a model with just one track history but the more you have the better.
    std::vector<track_history> data;
    data.push_back(make_random_tracking_data_for_training());
    data.push_back(make_random_tracking_data_for_training());
    data.push_back(make_random_tracking_data_for_training());
    data.push_back(make_random_tracking_data_for_training());
    data.push_back(make_random_tracking_data_for_training());

    structural_track_association_trainer trainer;
    // Note that the machine learning tools have a parameter.  This is the usual SVM C
    // parameter that controls the trade-off between trying to fit the training data or
    // producing a "simpler" solution.  You need to try a few different values of this
    // parameter to find out what setting works best for your problem (try values in the
    // range 0.001 to 1000000).
    trainer.set_c(100);
    // Now do the training.
    track_association_function<detection> assoc = trainer.train(data);

    // We can test the accuracy of the learned association function on some track history
    // data.  Here we test it on the data we trained on.  It outputs a single number that
    // measures the fraction of detections which were correctly associated to their tracks.
    // So a value of 1 indicates perfect tracking and a value of 0 indicates totally wrong
    // tracking.
    cout << "Association accuracy on training data: "<< test_track_association_function(assoc, data) << endl;
    // It's very important to test the output of a machine learning method on data it
    // wasn't trained on.  You can do that by calling test_track_association_function() on
    // held out data.  You can also use cross-validation like so:
    cout << "Association accuracy from 5-fold CV:   "<< cross_validate_track_association_trainer(trainer, data, 5) << endl;
    // Unsurprisingly, the testing functions show that the assoc function we learned
    // perfectly associates all detections to tracks in this easy data.

    // OK.  So how do you use this assoc thing?  Let's use it to do some tracking!

    // tracks contains all our current tracks.  Initially it is empty.
    std::vector<track> tracks;
    cout << "number of tracks: "<< tracks.size() << endl;

    // Sample detections from 3 objects.
    std::vector<detection> dets = make_random_detections(3);
    // Calling assoc(), the function we just learned, performs the detection to track
    // association.  It will also call each track's update_track() function with the
    // associated detection.  For tracks that don't get a detection, it calls
    // propagate_track().
    assoc(tracks, dets);
    // Now there are 3 things in tracks.
    cout << "number of tracks: "<< tracks.size() << endl;

    // Run the tracker for a few more time steps...
    dets = make_random_detections(3);
    assoc(tracks, dets);
    cout << "number of tracks: "<< tracks.size() << endl;

    dets = make_random_detections(3);
    assoc(tracks, dets);
    cout << "number of tracks: "<< tracks.size() << endl;

    // Now another object has appeared!  There are 4 objects now.
    dets = make_random_detections(4);
    assoc(tracks, dets);
    // Now there are 4 tracks instead of 3!
    cout << "number of tracks: "<< tracks.size() << endl;

    // That 4th object just vanished.  Let's look at the time_since_last_association values
    // for each track.  We will see that one of the tracks isn't getting updated with
    // detections anymore since the object it corresponds to is no longer present.
    dets = make_random_detections(3);
    assoc(tracks, dets);
    cout << "number of tracks: "<< tracks.size() << endl;
    for (unsigned long i = 0; i < tracks.size(); ++i)
        cout << "   time since last association: "<< tracks[i].time_since_last_association << endl;

    dets = make_random_detections(3);
    assoc(tracks, dets);
    cout << "number of tracks: "<< tracks.size() << endl;
    for (unsigned long i = 0; i < tracks.size(); ++i)
        cout << "   time since last association: "<< tracks[i].time_since_last_association << endl;

    // Finally, you can save your track_association_function to disk like so:
    serialize("track_assoc.svm") << assoc;

    // And recall it from disk later like so:
    deserialize("track_assoc.svm") >> assoc;
}

// ----------------------------------------------------------------------------------------


dlib C++ Library - max_cost_assignment_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

 This simple example shows how to call dlib's optimal linear assignment problem solver.
 It is an implementation of the famous Hungarian algorithm and is quite fast, operating in
 O(N^3) time.

*/

#include <dlib/optimization/max_cost_assignment.h>
#include <iostream>

using namespace std;
using namespace dlib;

int main ()
{
    // Let's imagine you need to assign N people to N jobs.  Additionally, each person will make
    // your company a certain amount of money at each job, but each person has different skills
    // so they are better at some jobs and worse at others.  You would like to find the best way
    // to assign people to these jobs.  In particular, you would like to maximize the amount of
    // money the group makes as a whole.  This is an example of an assignment problem and is
    // what is solved by the max_cost_assignment() routine.
    //
    // So in this example, let's imagine we have 3 people and 3 jobs.  We represent the amount of
    // money each person will produce at each job with a cost matrix.  Each row corresponds to a
    // person and each column corresponds to a job.  So for example, below we are saying that
    // person 0 will make $1 at job 0, $2 at job 1, and $6 at job 2.
    matrix<int> cost(3,3);
    cost = 1, 2, 6,
           5, 3, 6,
           4, 5, 0;

    // To find out the best assignment of people to jobs we just need to call this function.
    std::vector<long> assignment = max_cost_assignment(cost);

    // This prints optimal assignments:  [2, 0, 1] which indicates that we should assign
    // the person from the first row of the cost matrix to job 2, the middle row person to
    // job 0, and the bottom row person to job 1.
    for (unsigned int i = 0; i < assignment.size(); i++)
        cout << assignment[i] << std::endl;

    // This prints optimal cost:  16.0
    // which is correct since our optimal assignment is 6+5+5.
    cout << "optimal cost: " << assignment_cost(cost, assignment) << endl;


dlib C++ Library - linear_manifold_regularizer_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example illustrating the use of the linear_manifold_regularizer
    and empirical_kernel_map from the dlib C++ Library.

    This example program assumes you are familiar with some general elements of
    the library.  In particular, you should have at least read the svm_ex.cpp
    and matrix_ex.cpp examples.  You should also have read the empirical_kernel_map_ex.cpp
    example program as the present example builds upon it.

    This program shows an example of what is called semi-supervised learning.
    That is, a small amount of labeled data is augmented with a large amount
    of unlabeled data.  A learning algorithm is then run on all the data
    and the hope is that by including the unlabeled data we will end up with
    a better result.

    In this particular example we will generate 200,000 sample points of
    unlabeled data along with 2 samples of labeled data.  The sample points
    will be drawn randomly from two concentric circles.  One labeled data
    point will be drawn from each circle.  The goal is to learn to
    correctly separate the two circles using only the 2 labeled points
    and the unlabeled data.

    To do this we will first run an approximate form of k nearest neighbors
    to determine which of the unlabeled samples are closest together.  We will
    then make the manifold assumption, that is, we will assume that points close
    to each other should share the same classification label.

    Once we have determined which points are near neighbors we will use the
    empirical_kernel_map and linear_manifold_regularizer to transform all the
    data points into a new vector space where any linear rule will have similar
    output for points which we have decided are near neighbors.

    Finally, we will classify all the unlabeled data according to which of
    the two labeled points are nearest.  Normally this would not work but by
    using the manifold assumption we will be able to successfully classify
    all the unlabeled data.

    For further information on this subject you should begin with the following
    paper as it discusses a very similar application of manifold regularization.

        Beyond the Point Cloud: from Transductive to Semi-supervised Learning
        by Vikas Sindhwani, Partha Niyogi, and Mikhail Belkin

                    ******** SAMPLE PROGRAM OUTPUT ********

    Testing manifold regularization with an intrinsic_regularization_strength of 0.
    number of edges generated: 49998
    Running simple test...
    error: 0.37022
    error: 0.44036
    error: 0.376715
    error: 0.307545
    error: 0.463455
    error: 0.426065
    error: 0.416155
    error: 0.288295
    error: 0.400115
    error: 0.46347

    Testing manifold regularization with an intrinsic_regularization_strength of 10000.
    number of edges generated: 49998
    Running simple test...
    error: 0
    error: 0
    error: 0
    error: 0
    error: 0
    error: 0
    error: 0
    error: 0
    error: 0
    error: 0

*/

#include <dlib/manifold_regularization.h>
#include <dlib/svm.h>
#include <dlib/rand.h>
#include <dlib/statistics.h>
#include <iostream>
#include <vector>
#include <ctime>

using namespace std;
using namespace dlib;

// ----------------------------------------------------------------------------------------

// First let's make a typedef for the kind of samples we will be using.
typedef matrix<double, 0, 1> sample_type;

// We will be using the radial_basis_kernel in this example program.
typedef radial_basis_kernel<sample_type> kernel_type;

// ----------------------------------------------------------------------------------------

void generate_circle (
    std::vector<sample_type>& samples,
    double radius,
    const long num
);
/*!
    requires
        - num > 0
        - radius > 0
    ensures
        - generates num points centered at (0,0) with the given radius.  Adds these
          points into the given samples vector.
!*/

// ----------------------------------------------------------------------------------------

void test_manifold_regularization (
    const double intrinsic_regularization_strength
);
/*!
    ensures
        - Runs an example test using the linear_manifold_regularizer with the given
          intrinsic_regularization_strength.
!*/

// ----------------------------------------------------------------------------------------

int main()
{
    // Run the test without any manifold regularization.
    test_manifold_regularization(0);

    // Run the test with manifold regularization.  You can think of this number as
    // a measure of how much we trust the manifold assumption.  So if you are really
    // confident that you can select neighboring points which should have the same
    // classification then make this number big.
    test_manifold_regularization(10000.0);
}

// ----------------------------------------------------------------------------------------

void test_manifold_regularization (
    const double intrinsic_regularization_strength
)
{
    cout << "Testing manifold regularization with an intrinsic_regularization_strength of "
         << intrinsic_regularization_strength << ".\n";

    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 = 100000;

    // create a large dataset with two concentric circles.  There will be 100000 points on each circle
    // for a total of 200000 samples.
    generate_circle(samples, 2, num_points);  // circle of radius 2
    generate_circle(samples, 4, num_points);  // circle of radius 4

    // Create a set of sample_pairs that tells us which samples are "close" and should thus
    // be classified similarly.  These edges will be used to define the manifold regularizer.
    // To find these edges we use a simple function that samples point pairs randomly and
    // returns the top 5% with the shortest edges.
    std::vector<sample_pair> edges;
    find_percent_shortest_edges_randomly(samples, squared_euclidean_distance(), 0.05, 1000000, time(0), edges);

    cout << "number of edges generated: " << edges.size() << endl;

    empirical_kernel_map<kernel_type> ekm;

    // Since the circles are not linearly separable we will use an empirical kernel map to
    // map them into a space where they are separable.  We create an empirical_kernel_map
    // using a random subset of our data samples as basis samples.  Note, however, that even
    // though the circles are linearly separable in this new space given by the empirical_kernel_map
    // we still won't be able to correctly classify all the points given just the 2 labeled examples.
    // We will need to make use of the nearest neighbor information stored in edges.  To do that
    // we will use the linear_manifold_regularizer.
    ekm.load(kern, randomly_subsample(samples, 50));

    // 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;
    // use_gaussian_weights is a function object that tells lmr how to weight each edge.  In this
    // case we let the weight decay as edges get longer.  So shorter edges are more important than
    // longer edges.
    lmr.build(samples, edges, use_gaussian_weights(0.1));
    const matrix<double> T = lmr.get_transformation_matrix(intrinsic_regularization_strength);

    // 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.  That is, we will have: proj(x) == T*ekm.project(x).
    projection_function<kernel_type> proj = ekm.get_projection_function();
    proj.weights = T*proj.weights;

    cout << "Running simple test..." << endl;

    // 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.  We 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)
    {
        std::vector<sample_type> test_points;
        // generate a random point from the radius 2 circle
        generate_circle(test_points, 2, 1);
        // generate a random point from the radius 4 circle
        generate_circle(test_points, 4, 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;
        }

        cout << "error: "<< num_wrong/samples.size() << endl;
    }

    cout << endl;
}

// ----------------------------------------------------------------------------------------

dlib::rand rnd;

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);
    }
}

// ----------------------------------------------------------------------------------------


dlib C++ Library - mpc_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example illustrating the use of the linear model predictive
    control tool from the dlib C++ Library.  To explain what it does, suppose
    you have some process you want to control and the process dynamics are
    described by the linear equation:
        x_{i+1} = A*x_i + B*u_i + C
    That is, the next state the system goes into is a linear function of its
    current state (x_i) and the current control (u_i) plus some constant bias or
    disturbance.

    A model predictive controller can find the control (u) you should apply to
    drive the state (x) to some reference value, which is what we show in this
    example.  In particular, we will simulate a simple vehicle moving around in
    a planet's gravity.  We will use MPC to get the vehicle to fly to and then
    hover at a certain point in the air.

*/

#include <dlib/gui_widgets.h>
#include <dlib/control.h>
#include <dlib/image_transforms.h>

using namespace std;
using namespace dlib;

//  ----------------------------------------------------------------------------

int main()
{
    const int STATES = 4;
    const int CONTROLS = 2;

    // The first thing we do is setup our vehicle dynamics model (A*x + B*u + C).
    // Our state space (the x) will have 4 dimensions, the 2D vehicle position
    // and also the 2D velocity.  The control space (u) will be just 2 variables
    // which encode the amount of force we apply to the vehicle along each axis.
    // Therefore, the A matrix defines a simple constant velocity model.
    matrix<double,STATES,STATES> A;
    A = 1, 0, 1, 0,  // next_pos = pos + velocity
        0, 1, 0, 1,  // next_pos = pos + velocity
        0, 0, 1, 0,  // next_velocity = velocity
        0, 0, 0, 1;  // next_velocity = velocity

    // Here we say that the control variables effect only the velocity. That is,
    // the control applies an acceleration to the vehicle.
    matrix<double,STATES,CONTROLS> B;
    B = 0, 0,
        0, 0,
        1, 0,
        0, 1;

    // Let's also say there is a small constant acceleration in one direction.
    // This is the force of gravity in our model.
    matrix<double,STATES,1> C;
    C = 0,
        0,
        0,
        0.1;

    const int HORIZON = 30;
    // Now we need to setup some MPC specific parameters.  To understand them,
    // let's first talk about how MPC works.  When the MPC tool finds the "best"
    // control to apply it does it by simulating the process for HORIZON time
    // steps and selecting the control that leads to the best performance over
    // the next HORIZON steps.
    //
    // To be precise, each time you ask it for a control, it solves the
    // following quadratic program:
    //
    //     min     sum_i trans(x_i-target_i)*Q*(x_i-target_i) + trans(u_i)*R*u_i
    //    x_i,u_i
    //
    //     such that: x_0     == current_state
    //                x_{i+1} == A*x_i + B*u_i + C
    //                lower <= u_i <= upper
    //                0 <= i < HORIZON
    //
    // and reports u_0 as the control you should take given that you are currently
    // in current_state.  Q and R are user supplied matrices that define how we
    // penalize variations away from the target state as well as how much we want
    // to avoid generating large control signals.  We also allow you to specify
    // upper and lower bound constraints on the controls.  The next few lines
    // define these parameters for our simple example.

    matrix<double,STATES,1> Q;
    // Setup Q so that the MPC only cares about matching the target position and
    // ignores the velocity.
    Q = 1, 1, 0, 0;

    matrix<double,CONTROLS,1> R, lower, upper;
    R = 1, 1;
    lower = -0.5, -0.5;
    upper =  0.5,  0.5;

    // Finally, create the MPC controller.
    mpc<STATES,CONTROLS,HORIZON> controller(A,B,C,Q,R,lower,upper);

    // Let's tell the controller to send our vehicle to a random location.  It
    // will try to find the controls that makes the vehicle just hover at this
    // target position.
    dlib::rand rnd;
    matrix<double,STATES,1> target;
    target = rnd.get_random_double()*400,rnd.get_random_double()*400,0,0;
    controller.set_target(target);

    // Now let's start simulating our vehicle.  Our vehicle moves around inside
    // a 400x400 unit sized world.
    matrix<rgb_pixel> world(400,400);
    image_window win;
    matrix<double,STATES,1> current_state;
    // And we start it at the center of the world with zero velocity.
    current_state = 200,200,0,0;

    int iter = 0;
    while(!win.is_closed())
    {
        // Find the best control action given our current state.
        matrix<double,CONTROLS,1> action = controller(current_state);
        cout << "best control: " << trans(action);

        // Now draw our vehicle on the world.  We will draw the vehicle as a
        // black circle and its target position as a green circle.
        assign_all_pixels(world, rgb_pixel(255,255,255));
        const dpoint pos = point(current_state(0),current_state(1));
        const dpoint goal = point(target(0),target(1));
        draw_solid_circle(world, goal, 9, rgb_pixel(100,255,100));
        draw_solid_circle(world, pos, 7, 0);
        // We will also draw the control as a line showing which direction the
        // vehicle's thruster is firing.
        draw_line(world, pos, pos-50*action, rgb_pixel(255,0,0));
        win.set_image(world);

        // Take a step in the simulation
        current_state = A*current_state + B*action + C;
        dlib::sleep(100);

        // Every 100 iterations change the target to some other random location.
        ++iter;
        if (iter > 100)
        {
            iter = 0;
            target = rnd.get_random_double()*400,rnd.get_random_double()*400,0,0;
            controller.set_target(target);
        }
    }
}

//  ----------------------------------------------------------------------------


dlib C++ Library - logger_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt

/*

    This is a simple example illustrating the use of the logger object from
    the dlib C++ Library.

    The output of this program looks like this:

    0 INFO  [0] example: This is an informational message.
    0 DEBUG [0] example: The integer variable is set to 8
    0 WARN  [0] example: The variable is bigger than 4!  Its value is 8
    0 INFO  [0] example: we are going to sleep for half a second.
  503 INFO  [0] example: we just woke up
  503 INFO  [0] example: program ending

    The first column shows the number of milliseconds since program start at the time
    the message was printed, then the logging level of the message, then the thread that
    printed the message, then the logger's name and finally the message itself.

*/

#include <dlib/logger.h>
#include <dlib/misc_api.h>

using namespace dlib;

// Create a logger object somewhere.  It is usually convenient to make it at the global scope
// which is what I am doing here.  The following statement creates a logger that is named example.
logger dlog("example");

int main()
{
    // Every logger has a logging level (given by dlog.level()).  Each log message is tagged with a
    // level and only levels equal to or higher than dlog.level() will be printed.  By default all
    // loggers start with level() == LERROR.  In this case I'm going to set the lowest level LALL
    // which means that dlog will print all logging messages it gets.
    dlog.set_level(LALL);

    // print our first message.  It will go to cout because that is the default.
    dlog << LINFO << "This is an informational message.";

    // now print a debug message.
    int variable = 8;
    dlog << LDEBUG << "The integer variable is set to " << variable;

    // the logger can be used pretty much like any ostream object.  But you have to give a logging
    // level first.  But after that you can chain << operators like normal.

    if (variable > 4)
        dlog << LWARN << "The variable is bigger than 4!  Its value is " << variable;

    dlog << LINFO << "we are going to sleep for half a second.";
    // sleep for half a second
    dlib::sleep(500);
    dlog << LINFO << "we just woke up";

    dlog << LINFO << "program ending";


dlib C++ Library - logger_ex_2.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt

/*

    This is a somewhat complex example illustrating the use of the logger object
    from the dlib C++ Library.  It will demonstrate using multiple loggers and threads.

    The output of this program looks like this:
    0 INFO  [0] example: This is an informational message.
    0 WARN  [0] example: The variable is bigger than 4!  Its value is 8
    0 INFO  [0] example: make two threads
    0 WARN  [0] example.test_class: warning!  someone called warning()!
    0 INFO  [0] example: we are going to sleep for half a second.
    0 INFO  [1] example.thread: entering our thread
    0 WARN  [1] example.test_class: warning!  someone called warning()!
    0 INFO  [2] example.thread: entering our thread
    0 WARN  [2] example.test_class: warning!  someone called warning()!
  203 INFO  [1] example.thread: exiting our thread
  203 INFO  [2] example.thread: exiting our thread
  503 INFO  [0] example: we just woke up
  503 INFO  [0] example: program ending

*/

#include <dlib/logger.h>
#include <dlib/misc_api.h>
#include <dlib/threads.h>

using namespace dlib;

/*
    Here we create three loggers.  Note that it is the case that:
        - logp.is_child_of(logp) == true
        - logt.is_child_of(logp) == true
        - logc.is_child_of(logp) == true

    logp is the child of itself because all loggers are their own children :)  But the other
    two are child loggers of logp because their names start with logp.name() + "." which means
    that whenever you set a property on a logger it will also set that same property on all of
    the logger's children.
*/
logger logp("example");
logger logt("example.thread");
logger logc("example.test_class");

class test
{
public:
    test ()
    {
        // this message won't get logged because LINFO is too low
        logc << LINFO << "constructed a test object";
    }

    ~test ()
    {
        // this message won't get logged because LINFO is too low
        logc << LINFO << "destructed a test object";
    }

    void warning ()
    {
        logc << LWARN << "warning!  someone called warning()!";
    }
};

void thread (void*)
{
    logt << LINFO << "entering our thread";

    test mytest;
    mytest.warning();

    dlib::sleep(200);

    logt << LINFO << "exiting our thread";
}

void setup_loggers (
)
{
    // Create a logger that has the same name as our root logger logp.  This isn't very useful in
    // this example program but if you had loggers defined in other files then you might not have
    // easy access to them when starting up your program and setting log levels.  This mechanism
    // allows you to manipulate the properties of any logger so long as you know its name.
    logger temp_log("example");

    // For this example I don't want to log debug messages so I'm setting the logging level of
    // All our loggers to LINFO.  Note that this statement sets all three of our loggers to this
    // logging level because they are all children of temp_log.
    temp_log.set_level(LINFO);

    // In addition I only want the example.test_class to print LWARN or higher messages so I'm going
    // to set that here too.  Note that we set this value after calling temp_log.set_level(). If we
    // did it the other way around the set_level() call on temp_log would set logc_temp.level() and
    // logc.level() back to LINFO since temp_log is a parent of logc_temp.
    logger logc_temp("example.test_class");
    logc_temp.set_level(LWARN);

    // Finally, note that you can also configure your loggers from a text config file.
    // See the documentation for the configure_loggers_from_file() function for details.
}

int main()
{
    setup_loggers();

    // print our first message.  It will go to cout because that is the default.
    logp << LINFO << "This is an informational message.";

    int variable = 8;

    // Here is a debug message.  It won't print though because its log level is too low (it is below LINFO).
    logp << LDEBUG << "The integer variable is set to " << variable;

    if (variable > 4)
        logp << LWARN << "The variable is bigger than 4!  Its value is " << variable;

    logp << LINFO << "make two threads";
    create_new_thread(thread,0);
    create_new_thread(thread,0);

    test mytest;
    mytest.warning();

    logp << LINFO << "we are going to sleep for half a second.";
    // sleep for half a second
    dlib::sleep(500);
    logp << LINFO << "we just woke up";

    logp << LINFO << "program ending";

    // It is also worth pointing out that the logger messages are atomic.  This means, for example, that
    // in the above log statements that involve a string literal and a variable, no other thread can
    // come in and print a log message in-between the literal string and the variable.  This is good
    // because it means your messages don't get corrupted.  However, this also means that you shouldn't
    // make any function calls inside a logging statement if those calls might try to log a message
    // themselves since the atomic nature of the logger would cause your application to deadlock.


dlib C++ Library - logger_custom_output_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt

/*

    This is an example showing how to control where the dlib::logger sends its messages.
    This is done by creating a "hook" class that is called whenever any of the loggers want
    to log a message.  The hook class then outputs the messages using any method you like.

    Prior to reading this example, you should understand the basics of the dlib::logger.
    So you should have already read the logger_ex.cpp and logger_ex_2.cpp example programs.

*/

#include <dlib/logger.h>

using namespace dlib;
using namespace std;

class my_hook
{
public:
    my_hook(
    )
    {
        fout.open("my_log_file.txt");
    }

    void log (
        const string& logger_name,
        const log_level& ll,
        const uint64 thread_id,
        const char* message_to_log
    )
    {
        // Log all messages from any logger to our log file.
        fout << ll << " ["<<thread_id<<"] " << logger_name << ": " << message_to_log << endl;

        // But only log messages that are of LINFO priority or higher to the console.
        if (ll >= LINFO)
            cout << ll << " ["<<thread_id<<"] " << logger_name << ": " << message_to_log << endl;
    }

private:
    ofstream fout;
};

int main()
{
    my_hook hook;
    // This tells all dlib loggers to send their logging events to the hook object.  That
    // is, any time a logger generates a message it will call hook.log() with the message
    // contents.  Additionally, hook.log() will also only be called from one thread at a
    // time so it is safe to use this kind of hook in a multi-threaded program with many
    // loggers in many threads.
    set_all_logging_output_hooks(hook);
    // It should also be noted that the hook object must not be destructed while the
    // loggers are still in use.  So it is a good idea to declare the hook object
    // somewhere where it will live the entire lifetime of the program, as we do here.

    logger dlog("main");
    // Tell the dlog logger to emit a message for all logging events rather than its
    // default behavior of only logging LERROR or above.
    dlog.set_level(LALL);

    // All these message go to my_log_file.txt, but only the last two go to the console.
    dlog << LDEBUG << "This is a debugging message.";
    dlog << LINFO  << "This is an informational message.";
    dlog << LERROR << "An error message!";


dlib C++ Library - matrix_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt

/*
    This is an example illustrating the use of the matrix object
    from the dlib C++ Library.
*/

#include <iostream>
#include <dlib/matrix.h>

using namespace dlib;
using namespace std;

// ----------------------------------------------------------------------------------------

int main()
{
    // Let's begin this example by using the library to solve a simple
    // linear system.
    //
    // We will find the value of x such that y = M*x where
    //
    //      3.5
    // y =  1.2
    //      7.8
    //
    // and M is
    //
    //      54.2   7.4   12.1
    // M =  1      2     3
    //      5.9    0.05  1

    // First let's declare these 3 matrices.
    // This declares a matrix that contains doubles and has 3 rows and 1 column.
    // Moreover, it's size is a compile time constant since we put it inside the <>.
    matrix<double,3,1> y;
    // Make a 3 by 3 matrix of doubles for the M matrix.  In this case, M is
    // sized at runtime and can therefore be resized later by calling M.set_size().
    matrix<double> M(3,3);

    // You may be wondering why someone would want to specify the size of a
    // matrix at compile time when you don't have to.  The reason is two fold.
    // First, there is often a substantial performance improvement, especially
    // for small matrices, because it enables a number of optimizations that
    // otherwise would be impossible.  Second, the dlib::matrix object checks
    // these compile time sizes to ensure that the matrices are being used
    // correctly.  For example, if you attempt to compile the expression y*y you
    // will get a compiler error since that is not a legal matrix operation (the
    // matrix dimensions don't make sense as a matrix multiplication).  So if
    // you know the size of a matrix at compile time then it is always a good
    // idea to let the compiler know about it.

    // Now we need to initialize the y and M matrices and we can do so like this:
    M = 54.2,  7.4,  12.1,
        1,     2,    3,
        5.9,   0.05, 1;

    y = 3.5,
        1.2,
        7.8;

    // The solution to y = M*x can be obtained by multiplying the inverse of M
    // with y.  As an aside, you should *NEVER* use the auto keyword to capture
    // the output from a matrix expression.  So don't do this: auto x = inv(M)*y;
    // To understand why, read the matrix_expressions_ex.cpp example program.
    matrix<double> x = inv(M)*y;

    cout << "x: \n" << x << endl;

    // We can check that it really worked by plugging x back into the original equation
    // and subtracting y to see if we get a column vector with values all very close
    // to zero (Which is what happens.  Also, the values may not be exactly zero because
    // there may be some numerical error and round off).
    cout << "M*x - y: \n" << M*x - y << endl;

    // Also note that we can create run-time sized column or row vectors like so
    matrix<double,0,1> runtime_sized_column_vector;
    matrix<double,1,0> runtime_sized_row_vector;
    // and then they are sized by saying
    runtime_sized_column_vector.set_size(3);

    // Similarly, the x matrix can be resized by calling set_size(num rows, num columns).  For example
    x.set_size(3,4);  // x now has 3 rows and 4 columns.

    // The elements of a matrix are accessed using the () operator like so:
    cout << M(0,1) << endl;
    // The above expression prints out the value 7.4.  That is, the value of
    // the element at row 0 and column 1.

    // If we have a matrix that is a row or column vector.  That is, it contains either
    // a single row or a single column then we know that any access is always either
    // to row 0 or column 0 so we can omit that 0 and use the following syntax.
    cout << y(1) << endl;
    // The above expression prints out the value 1.2

    // Let's compute the sum of elements in the M matrix.
    double M_sum = 0;
    // loop over all the rows
    for (long r = 0; r < M.nr(); ++r)
    {
        // loop over all the columns
        for (long c = 0; c < M.nc(); ++c)
        {
            M_sum += M(r,c);
        }
    }
    cout << "sum of all elements in M is " << M_sum << endl;

    // The above code is just to show you how to loop over the elements of a matrix.  An
    // easier way to find this sum is to do the following:
    cout << "sum of all elements in M is " << sum(M) << endl;

    // Note that you can always print a matrix to an output stream by saying:
    cout << M << endl;
    // which will print:
    //   54.2  7.4 12.1
    //      1    2    3
    //    5.9 0.05    1

    // However, if you want to print using comma separators instead of spaces you can say:
    cout << csv << M << endl;
    // and you will instead get this as output:
    //   54.2, 7.4, 12.1
    //   1, 2, 3
    //   5.9, 0.05, 1

    // Conversely, you can also read in a matrix that uses either space, tab, or comma
    // separated values by uncommenting the following:
    // cin >> M;

    // -----------------------------  Comparison with MATLAB ------------------------------
    // Here I list a set of Matlab commands and their equivalent expressions using the dlib
    // matrix.  Note that there are a lot more functions defined for the dlib::matrix.  See
    // the HTML documentation for a full listing.

    matrix<double> A, B, C, D, E;
    matrix<int> Aint;
    matrix<long> Blong;

    // MATLAB: A = eye(3)
    A = identity_matrix<double>(3);

    // MATLAB: B = ones(3,4)
    B = ones_matrix<double>(3,4);

    // MATLAB: B = rand(3,4)
    B = randm(3,4);

    // MATLAB: C = 1.4*A
    C = 1.4*A;

    // MATLAB: D = A.*C
    D = pointwise_multiply(A,C);

    // MATLAB: E = A * B
    E = A*B;

    // MATLAB: E = A + B
    E = A + C;

    // MATLAB: E = A + 5
    E = A + 5;

    // MATLAB: E = E'
    E = trans(E);  // Note that if you want a conjugate transpose then you need to say conj(trans(E))

    // MATLAB: E = B' * B
    E = trans(B)*B;

    double var;
    // MATLAB: var = A(1,2)
    var = A(0,1); // dlib::matrix is 0 indexed rather than starting at 1 like Matlab.

    // MATLAB: C = round(C)
    C = round(C);

    // MATLAB: C = floor(C)
    C = floor(C);

    // MATLAB: C = ceil(C)
    C = ceil(C);

    // MATLAB: C = diag(B)
    C = diag(B);

    // MATLAB: B = cast(A, "int32")
    Aint = matrix_cast<int>(A);

    // MATLAB: A = B(1,:)
    A = rowm(B,0);

    // MATLAB: A = B([1:2],:)
    A = rowm(B,range(0,1));

    // MATLAB: A = B(:,1)
    A = colm(B,0);

    // MATLAB: A = [1:5]
    Blong = range(1,5);

    // MATLAB: A = [1:2:5]
    Blong = range(1,2,5);

    // MATLAB: A = B([1:3], [1:2])
    A = subm(B, range(0,2), range(0,1));
    // or equivalently
    A = subm(B, rectangle(0,0,1,2));

    // MATLAB: A = B([1:3], [1:2:4])
    A = subm(B, range(0,2), range(0,2,3));

    // MATLAB: B(:,:) = 5
    B = 5;
    // or equivalently
    set_all_elements(B,5);

    // MATLAB: B([1:2],[1,2]) = 7
    set_subm(B,range(0,1), range(0,1)) = 7;

    // MATLAB: B([1:3],[2:3]) = A
    set_subm(B,range(0,2), range(1,2)) = A;

    // MATLAB: B(:,1) = 4
    set_colm(B,0) = 4;

    // MATLAB: B(:,[1:2]) = 4
    set_colm(B,range(0,1)) = 4;

    // MATLAB: B(:,1) = B(:,2)
    set_colm(B,0) = colm(B,1);

    // MATLAB: B(1,:) = 4
    set_rowm(B,0) = 4;

    // MATLAB: B(1,:) = B(2,:)
    set_rowm(B,0) = rowm(B,1);

    // MATLAB: var = det(E' * E)
    var = det(trans(E)*E);

    // MATLAB: C = pinv(E)
    C = pinv(E);

    // MATLAB: C = inv(E)
    C = inv(E);

    // MATLAB: [A,B,C] = svd(E)
    svd(E,A,B,C);

    // MATLAB: A = chol(E,'lower')
    A = chol(E);

    // MATLAB: var = min(min(A))
    var = min(A);
}

// ----------------------------------------------------------------------------------------


dlib C++ Library - matrix_expressions_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt

/*
    This example contains a detailed discussion of the template expression
    technique used to implement the matrix tools in the dlib C++ library.

    It also gives examples showing how a user can create their own custom
    matrix expressions.

    Note that you should be familiar with the dlib::matrix before reading
    this example.  So if you haven't done so already you should read the
    matrix_ex.cpp example program.
*/

#include <iostream>
#include <dlib/matrix.h>

using namespace dlib;
using namespace std;

// ----------------------------------------------------------------------------------------

void custom_matrix_expressions_example();

// ----------------------------------------------------------------------------------------

int main()
{

    // Declare some variables used below
    matrix<double,3,1> y;
    matrix<double,3,3> M;
    matrix<double> x;

    // set all elements to 1
    y = 1;
    M = 1;

    // -------------------------  Template Expressions -----------------------------
    // Now I will discuss the "template expressions" technique and how it is
    // used in the matrix object.  First consider the following expression:
    x = y + y;

    /*
        Normally this expression results in machine code that looks, at a high
        level, like the following:
            temp = y + y;
            x = temp

        Temp is a temporary matrix returned by the overloaded + operator.
        temp then contains the result of adding y to itself.  The assignment
        operator copies the value of temp into x and temp is then destroyed while
        the blissful C++ user never sees any of this.

        This is, however, totally inefficient.  In the process described above
        you have to pay for the cost of constructing a temporary matrix object
        and allocating its memory.  Then you pay the additional cost of copying
        it over to x.  It also gets worse when you have more complex expressions
        such as x = round(y + y + y + M*y) which would involve the creation and copying
        of 5 temporary matrices.

        All these inefficiencies are removed by using the template expressions
        technique.  The basic idea is as follows, instead of having operators and
        functions return temporary matrix objects you return a special object that
        represents the expression you wish to perform.

        So consider the expression x = y + y again.  With dlib::matrix what happens
        is the expression y+y returns a matrix_exp object instead of a temporary matrix.
        The construction of a matrix_exp does not allocate any memory or perform any
        computations.  The matrix_exp however has an interface that looks just like a
        dlib::matrix object and when you ask it for the value of one of its elements
        it computes that value on the spot.  Only in the assignment operator does
        someone ask the matrix_exp for these values so this avoids the use of any
        temporary matrices.  Thus the statement x = y + y is equivalent to the following
        code:
            // loop over all elements in y matrix
            for (long r = 0; r < y.nr(); ++r)
                for (long c = 0; c < y.nc(); ++c)
                    x(r,c) = y(r,c) + y(r,c);

        This technique works for expressions of arbitrary complexity.  So if you typed
        x = round(y + y + y + M*y) it would involve no temporary matrices being created
        at all.  Each operator takes and returns only matrix_exp objects.  Thus, no
        computations are performed until the assignment operator requests the values
        from the matrix_exp it receives as input.  This also means that statements such as:
            auto x = round(y + y + y + M*y)
        will not work properly because x would be a matrix expression that references
        parts of the expression round(y + y + y + M*y) but those expression parts will
        immediately go out of scope so x will contain references to non-existing sub
        matrix expressions.  This is very bad, so you should never use auto to store
        the result of a matrix expression.  Always store the output in a matrix object
        like so:
            matrix<double> x = round(y + y + y + M*y)

        In terms of implementation, there is a slight complication in all of this.  It
        is for statements that involve the multiplication of a complex matrix_exp such
        as the following:
    */
        x = M*(M+M+M+M+M+M+M);
    /*
        According to the discussion above, this statement would compute the value of
        M*(M+M+M+M+M+M+M) totally without any temporary matrix objects.  This sounds
        good but we should take a closer look.  Consider that the + operator is
        invoked 6 times.  This means we have something like this:

        x = M * (matrix_exp representing M+M+M+M+M+M+M);

        M is being multiplied with a quite complex matrix_exp.  Now recall that when
        you ask a matrix_exp what the value of any of its elements are it computes
        their values *right then*.

        If you think on what is involved in performing a matrix multiply you will
        realize that each element of a matrix is accessed M.nr() times.  In the
        case of our above expression the cost of accessing an element of the
        matrix_exp on the right hand side is the cost of doing 6 addition operations.

        Thus, it would be faster to assign M+M+M+M+M+M+M to a temporary matrix and then
        multiply that by M.  This is exactly what the dlib::matrix does under the covers.
        This is because it is able to spot expressions where the introduction of a
        temporary is needed to speed up the computation and it will automatically do this
        for you.

        Another complication that is dealt with automatically is aliasing.  All matrix
        expressions are said to "alias" their contents.  For example, consider
        the following expressions:
           M + M
           M * M

        We say that the expressions (M + M) and (M * M) alias M.  Additionally, we say that
        the expression (M * M) destructively aliases M.

        To understand why we say (M * M) destructively aliases M consider what would happen
        if we attempted to evaluate it without first assigning (M * M) to a temporary matrix.
        That is, if we attempted to perform the following:
            for (long r = 0; r < M.nr(); ++r)
                for (long c = 0; c < M.nc(); ++c)
                    M(r,c) = rowm(M,r)*colm(M,c);

        It is clear that the result would be corrupted and M wouldn't end up with the right
        values in it.  So in this case we must perform the following:
            temp = M*M;
            M = temp;

        This sort of interaction is what defines destructive aliasing.  Whenever we are
        assigning a matrix expression to a destination that is destructively aliased by
        the expression we need to introduce a temporary.  The dlib::matrix is capable of
        recognizing the two forms of aliasing and introduces temporary matrices only when
        necessary.
    */

    // Next we discuss how to create custom matrix expressions.   In what follows we
    // will define three different matrix expressions and show their use.
    custom_matrix_expressions_example();
}

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

template <typename M>
struct example_op_trans
{
    /*!
        This object defines a matrix expression that represents a transposed matrix.
        As discussed above, constructing this object doesn't compute anything.  It just
        holds a reference to a matrix and presents an interface which defines
        matrix transposition.
    !*/

    // Here we simply hold a reference to the matrix we are supposed to be the transpose of.
    example_op_trans( const M& m_) : m(m_){}
    const M& m;

    // The cost field is used by matrix multiplication code to decide if a temporary needs to
    // be introduced.  It represents the computational cost of evaluating an element of the
    // matrix expression.  In this case we say that the cost of obtaining an element of the
    // transposed matrix is the same as obtaining an element of the original matrix (since
    // transpose doesn't really compute anything).
    const static long cost = M::cost;

    // Here we define the matrix expression's compile-time known dimensions.  Since this
    // is a transpose we define them to be the reverse of M's dimensions.
    const static long NR = M::NC;
    const static long NC = M::NR;

    // Define the type of element in this matrix expression.  Also define the
    // memory manager type used and the layout.  Usually we use the same types as the
    // input matrix.
    typedef typename M::type type;
    typedef typename M::mem_manager_type mem_manager_type;
    typedef typename M::layout_type layout_type;

    // This is where the action is.  This function is what defines the value of an element of
    // this matrix expression.  Here we are saying that m(c,r) == trans(m)(r,c) which is just
    // the definition of transposition.  Note also that we must define the return type from this
    // function as a typedef.  This typedef lets us either return our argument by value or by
    // reference.  In this case we use the same type as the underlying m matrix.  Later in this
    // example program you will see two other options.
    typedef typename M::const_ret_type const_ret_type;
    const_ret_type apply (long r, long c) const { return m(c,r); }

    // Define the run-time defined dimensions of this matrix.
    long nr () const { return m.nc(); }
    long nc () const { return m.nr(); }

    // Recall the discussion of aliasing.  Each matrix expression needs to define what
    // kind of aliasing it introduces so that we know when to introduce temporaries.  The
    // aliases() function indicates that the matrix transpose expression aliases item if
    // and only if the m matrix aliases item.
    template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }
    // This next function indicates that the matrix transpose expression also destructively
    // aliases anything m aliases.  I.e. transpose has destructive aliasing.
    template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }

};

// Here we define a simple function that creates and returns transpose expressions.  Note that the
// matrix_op<> template is a matrix_exp object and exists solely to reduce the amount of boilerplate
// you have to write to create a matrix expression.
template < typename M >
const matrix_op<example_op_trans<M> > example_trans (
    const matrix_exp<M>& m
)
{
    typedef example_op_trans<M> op;
    // m.ref() returns a reference to the object of type M contained in the matrix expression m.
    return matrix_op<op>(op(m.ref()));
}

// ----------------------------------------------------------------------------------------

template <typename T>
struct example_op_vector_to_matrix
{
    /*!
        This object defines a matrix expression that holds a reference to a std::vector<T>
        and makes it look like a column vector.  Thus it enables you to use a std::vector
        as if it was a dlib::matrix.

    !*/
    example_op_vector_to_matrix( const std::vector<T>& vect_) : vect(vect_){}

    const std::vector<T>& vect;

    // This expression wraps direct memory accesses so we use the lowest possible cost.
    const static long cost = 1;

    const static long NR = 0; // We don't know the length of the vector until runtime.  So we put 0 here.
    const static long NC = 1; // We do know that it only has one column (since it's a vector)
    typedef T type;
    // Since the std::vector doesn't use a dlib memory manager we list the default one here.
    typedef default_memory_manager mem_manager_type;
    // The layout type also doesn't really matter in this case.  So we list row_major_layout
    // since it is a good default.
    typedef row_major_layout layout_type;

    // Note that we define const_ret_type to be a reference type.  This way we can
    // return the contents of the std::vector by reference.
    typedef const T& const_ret_type;
    const_ret_type apply (long r, long ) const { return vect[r]; }

    long nr () const { return vect.size(); }
    long nc () const { return 1; }

    // This expression never aliases anything since it doesn't contain any matrix expression (it
    // contains only a std::vector which doesn't count since you can't assign a matrix expression
    // to a std::vector object).
    template <typename U> bool aliases               ( const matrix_exp<U>& ) const { return false; }
    template <typename U> bool destructively_aliases ( const matrix_exp<U>& ) const { return false; }
};

template < typename T >
const matrix_op<example_op_vector_to_matrix<T> > example_vector_to_matrix (
    const std::vector<T>& vector
)
{
    typedef example_op_vector_to_matrix<T> op;
    return matrix_op<op>(op(vector));
}

// ----------------------------------------------------------------------------------------

template <typename M, typename T>
struct example_op_add_scalar
{
    /*!
        This object defines a matrix expression that represents a matrix with a single
        scalar value added to all its elements.
    !*/

    example_op_add_scalar( const M& m_, const T& val_) : m(m_), val(val_){}

    // A reference to the matrix
    const M& m;
    // A copy of the scalar value that should be added to each element of m
    const T val;

    // This time we add 1 to the cost since evaluating an element of this
    // expression means performing 1 addition operation.
    const static long cost = M::cost + 1;
    const static long NR = M::NR;
    const static long NC = M::NC;
    typedef typename M::type type;
    typedef typename M::mem_manager_type mem_manager_type;
    typedef typename M::layout_type layout_type;

    // Note that we declare const_ret_type to be a non-reference type.  This is important
    // since apply() computes a new temporary value and thus we can't return a reference
    // to it.
    typedef type const_ret_type;
    const_ret_type apply (long r, long c) const { return m(r,c) + val; }

    long nr () const { return m.nr(); }
    long nc () const { return m.nc(); }

    // This expression aliases anything m aliases.
    template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }
    // Unlike the transpose expression.  This expression only destructively aliases something if m does.
    // So this expression has the regular non-destructive kind of aliasing.
    template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.destructively_aliases(item); }

};

template < typename M, typename T >
const matrix_op<example_op_add_scalar<M,T> > add_scalar (
    const matrix_exp<M>& m,
    T val
)
{
    typedef example_op_add_scalar<M,T> op;
    return matrix_op<op>(op(m.ref(), val));
}

// ----------------------------------------------------------------------------------------

void custom_matrix_expressions_example(
)
{
    matrix<double> x(2,3);
    x = 1, 1, 1,
        2, 2, 2;

    cout << x << endl;

    // Finally, let's use the matrix expressions we defined above.

    // prints the transpose of x
    cout << example_trans(x) << endl;

    // prints this:
    //   11 11 11
    //   12 12 12
    cout << add_scalar(x, 10) << endl;

    // matrix expressions can be nested, even the user defined ones.
    // the following statement prints this:
    //   11 12
    //   11 12
    //   11 12
    cout << example_trans(add_scalar(x, 10)) << endl;

    // Since we setup the alias detection correctly we can even do this:
    x = example_trans(add_scalar(x, 10));
    cout << "new x:\n" << x << endl;

    cout << "Do some testing with the example_vector_to_matrix() function: " << endl;
    std::vector<float> vect;
    vect.push_back(1);
    vect.push_back(3);
    vect.push_back(5);

    // Now let's treat our std::vector like a matrix and print some things.
    cout << example_vector_to_matrix(vect) << endl;
    cout << add_scalar(example_vector_to_matrix(vect), 10) << endl;

    /*
        As an aside, note that dlib contains functions equivalent to the ones we
        defined above.  They are:
            - dlib::trans()
            - dlib::mat() (converts things into matrices)
            - operator+ (e.g. you can say my_mat + 1)

        Also, if you are going to be creating your own matrix expression you should also
        look through the matrix code in the dlib/matrix folder.  There you will find
        many other examples of matrix expressions.
    */
}

// ----------------------------------------------------------------------------------------


dlib C++ Library - member_function_pointer_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt

/*
    This is an example illustrating the use of the member_function_pointer object
    from the dlib C++ Library.

*/

#include <iostream>
#include <dlib/member_function_pointer.h>

using namespace dlib;
using namespace std;

// ----------------------------------------------------------------------------------------

class example_object
{
public:

    void do_something (
    )
    {
        cout << "hello world" << endl;
    }

    void print_this_number (
        int num
    )
    {
        cout << "number you gave me = " << num << endl;
    }

};

// ----------------------------------------------------------------------------------------

int main()
{
    // create a pointer that can point to member functions that take no arguments
    member_function_pointer<> mfp1;

    // create a pointer that can point to member functions that take a single int argument
    member_function_pointer<int> mfp2;

    example_object obj;

    // now we set the mfp1 pointer to point to the member function do_something()
    // on the obj object.
    mfp1.set(obj, &example_object::do_something);

    // now we set the mfp1 pointer to point to the member function print_this_number()
    // on the obj object.
    mfp2.set(obj, &example_object::print_this_number);

    // Now we can call the function this pointer points to.  This calls the function
    // obj.do_something() via our member function pointer.
    mfp1();

    // Now we can call the function this pointer points to.  This calls the function
    // obj.print_this_number(5) via our member function pointer.
    mfp2(5);

    // The above example shows a very simple use of the member_function_pointer.
    // A more interesting use of the member_function_pointer is in the implementation
    // of callbacks or event handlers.  For example, when you register an event
    // handler for a dlib::button click it uses a member_function_pointer
    // internally to save and later call your event handler.
}

// ----------------------------------------------------------------------------------------


dlib C++ Library - model_selection_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example that shows some reasonable ways you can perform
    model selection with the dlib C++ Library.

    It will create a simple set of data and then show you how to use
    the cross validation and optimization routines to determine good model
    parameters for the purpose of training an svm to classify the sample data.

    The data used in this example will be 2 dimensional data and will
    come from a distribution where points with a distance less than 10
    from the origin are labeled +1 and all other points are labeled
    as -1.

    As an side, you should probably read the svm_ex.cpp and matrix_ex.cpp example
    programs before you read this one.
*/

#include <iostream>
#include <dlib/svm.h>

using namespace std;
using namespace dlib;

// The svm functions use column vectors to contain a lot of the data on which they
// operate. So the first thing we do here is declare a convenient typedef.

// This typedef declares a matrix with 2 rows and 1 column.  It will be the
// object that contains each of our 2 dimensional samples.
typedef matrix<double, 2, 1> sample_type;

// This is a typedef for the type of kernel we are going to use in this example.
// In this case I have selected the radial basis kernel that can operate on our
// 2D sample_type objects
typedef radial_basis_kernel<sample_type> kernel_type;

class cross_validation_objective
{
    /*!
        WHAT THIS OBJECT REPRESENTS
            This object is a simple function object that takes a set of model
            parameters and returns a number indicating how "good" they are.  It
            does this by performing 10 fold cross validation on our dataset
            and reporting the accuracy.

            See below in main() for how this object gets used.
    !*/
public:

    cross_validation_objective (
        const std::vector<sample_type>& samples_,
        const std::vector<double>& labels_
    ) : samples(samples_), labels(labels_) {}

    double operator() (
        const matrix<double>& params
    ) const
    {
        // Pull out the two SVM model parameters.  Note that, in this case,
        // I have setup the parameter search to operate in log scale so we have
        // to remember to call exp() to put the parameters back into a normal scale.
        const double gamma = exp(params(0));
        const double nu    = exp(params(1));

        // Make an SVM trainer and tell it what the parameters are supposed to be.
        svm_nu_trainer<kernel_type> trainer;
        trainer.set_kernel(kernel_type(gamma));
        trainer.set_nu(nu);

        // Finally, perform 10-fold cross validation and then print and return the results.
        matrix<double> result = cross_validate_trainer(trainer, samples, labels, 10);
        cout << "gamma: " << setw(11) << gamma << "  nu: " << setw(11) << nu <<  "  cross validation accuracy: " << result;

        // Here I'm returning the harmonic mean between the accuracies of each class.
        // However, you could do something else.  For example, you might care a lot more
        // about correctly predicting the +1 class, so you could penalize results that
        // didn't obtain a high accuracy on that class.  You might do this by using
        // something like a weighted version of the F1-score (see http://en.wikipedia.org/wiki/F1_score).
        return 2*prod(result)/sum(result);
    }

    const std::vector<sample_type>& samples;
    const std::vector<double>& labels;

};

int main()
{
    try
    {

        // Now we make objects to contain our samples and their respective labels.
        std::vector<sample_type> samples;
        std::vector<double> labels;

        // Now let's put some data into our samples and labels objects.  We do this
        // by looping over a bunch of points and labeling them according to their
        // distance from the origin.
        for (double r = -20; r <= 20; r += 0.8)
        {
            for (double c = -20; c <= 20; c += 0.8)
            {
                sample_type samp;
                samp(0) = r;
                samp(1) = c;
                samples.push_back(samp);

                // if this point is less than 10 from the origin
                if (sqrt(r*r + c*c) <= 10)
                    labels.push_back(+1);
                else
                    labels.push_back(-1);

            }
        }

        cout << "Generated " << samples.size() << " points" << endl;

        // Here we normalize all the samples by subtracting their mean and dividing by their standard deviation.
        // This is generally a good idea since it often heads off numerical stability problems and also
        // prevents one large feature from smothering others.  Doing this doesn't matter much in this example
        // so I'm just doing this here so you can see an easy way to accomplish this with
        // the library.
        vector_normalizer<sample_type> normalizer;
        // let the normalizer learn the mean and standard deviation of the samples
        normalizer.train(samples);
        // now normalize each sample
        for (unsigned long i = 0; i < samples.size(); ++i)
            samples[i] = normalizer(samples[i]);

        // Now that we have some data we want to train on it.  However, there are two parameters to the
        // training.  These are the nu and gamma parameters.  Our choice for these parameters will
        // influence how good the resulting decision function is.  To test how good a particular choice
        // of these parameters is we can use the cross_validate_trainer() function to perform n-fold cross
        // validation on our training data.  However, there is a problem with the way we have sampled
        // our distribution above.  The problem is that there is a definite ordering to the samples.
        // That is, the first half of the samples look like they are from a different distribution
        // than the second half.  This would screw up the cross validation process but we can
        // fix it by randomizing the order of the samples with the following function call.
        randomize_samples(samples, labels);

        // The nu parameter has a maximum value that is dependent on the ratio of the +1 to -1
        // labels in the training data.  This function finds that value.  The 0.999 is here because
        // the maximum allowable nu is strictly less than the value returned by maximum_nu().  So
        // rather than dealing with that below we can just back away from it a little bit here and then
        // not worry about it.
        const double max_nu = 0.999*maximum_nu(labels);

        // The first kind of model selection we will do is a simple grid search.  That is, below we just
        // generate a fixed grid of points (each point represents one possible setting of the model parameters)
        // and test each via cross validation.

        // This code generates a 4x4 grid of logarithmically spaced points.  The result is a matrix
        // with 2 rows and 16 columns where each column represents one of our points.
        matrix<double> params = cartesian_product(logspace(log10(5.0), log10(1e-5), 4),  // gamma parameter
                                                  logspace(log10(max_nu), log10(1e-5), 4) // nu parameter
                                                  );
        // As an aside, if you wanted to do a grid search over points of dimensionality more than two
        // you would just nest calls to cartesian_product().  You can also use linspace() to generate
        // linearly spaced points if that is more appropriate for the parameters you are working with.

        // Next we loop over all the points we generated and check how good each is.
        cout << "Doing a grid search" << endl;
        matrix<double> best_result(2,1);
        best_result = 0;
        double best_gamma = 0.1, best_nu;
        for (long col = 0; col < params.nc(); ++col)
        {
            // pull out the current set of model parameters
            const double gamma = params(0, col);
            const double nu    = params(1, col);

            // setup a training object using our current parameters
            svm_nu_trainer<kernel_type> trainer;
            trainer.set_kernel(kernel_type(gamma));
            trainer.set_nu(nu);

            // Finally, do 10 fold cross validation and then check if the results are the best we have seen so far.
            matrix<double> result = cross_validate_trainer(trainer, samples, labels, 10);
            cout << "gamma: " << setw(11) << gamma << "  nu: " << setw(11) << nu <<  "  cross validation accuracy: " << result;

            // save the best results
            if (sum(result) > sum(best_result))
            {
                best_result = result;
                best_gamma = gamma;
                best_nu = nu;
            }
        }

        cout << "\n best result of grid search: " << sum(best_result) << endl;
        cout << " best gamma: " << best_gamma << "   best nu: " << best_nu << endl;

        // Grid search is a very simple brute force method.  Below we try out the BOBYQA algorithm.
        // It is a routine that performs optimization of a function in the absence of derivatives.

        cout << "\n\n Try the BOBYQA algorithm" << endl;

        // We need to supply a starting point for the optimization.  Here we are using the best
        // result of the grid search.  Generally, you want to try and give a reasonable starting
        // point due to the possibility of the optimization getting stuck in a local maxima.
        params.set_size(2,1);
        params = best_gamma, // initial gamma
                 best_nu;    // initial nu

        // We also need to supply lower and upper bounds for the search.
        matrix<double> lower_bound(2,1), upper_bound(2,1);
        lower_bound = 1e-7,   // smallest allowed gamma
                      1e-7;   // smallest allowed nu
        upper_bound = 100,    // largest allowed gamma
                      max_nu; // largest allowed nu

        // For the gamma and nu SVM parameters it is generally a good idea to search
        // in log space.  So I'm just converting them into log space here before
        // we start the optimization.
        params = log(params);
        lower_bound = log(lower_bound);
        upper_bound = log(upper_bound);

        // Finally, ask BOBYQA to look for the best set of parameters.  Note that we are using the
        // cross validation function object defined at the top of the file.
        double best_score = find_max_bobyqa(
            cross_validation_objective(samples, labels), // Function to maximize
            params,                                      // starting point
            params.size()*2 + 1,                         // See BOBYQA docs, generally size*2+1 is a good setting for this
            lower_bound,                                 // lower bound
            upper_bound,                                 // upper bound
            min(upper_bound-lower_bound)/10,             // search radius
            0.01,                                        // desired accuracy
            100                                          // max number of allowable calls to cross_validation_objective()
            );

        // Don't forget to convert back from log scale to normal scale
        params = exp(params);

        cout << " best result of BOBYQA: " << best_score << endl;
        cout << " best gamma: " << params(0) << "   best nu: " << params(1) << endl;

        // Also note that the find_max_bobyqa() function only works for optimization problems
        // with 2 variables or more.  If you only have a single variable then you should use
        // the find_max_single_variable() function.

    }
    catch (exception& e)
    {
        cout << e.what() << endl;


dlib C++ Library - multiclass_classification_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*
    This is an example illustrating the use of the multiclass classification tools
    from the dlib C++ Library.  Specifically, this example will make points from
    three classes and show you how to train a multiclass classifier to recognize
    these three classes.

    The classes are as follows:
        - class 1: points very close to the origin
        - class 2: points on the circle of radius 10 around the origin
        - class 3: points that are on a circle of radius 4 but not around the origin at all
*/

#include <dlib/svm_threaded.h>

#include <iostream>
#include <vector>

#include <dlib/rand.h>

using namespace std;
using namespace dlib;

// Our data will be 2-dimensional data. So declare an appropriate type to contain these points.
typedef matrix<double,2,1> sample_type;

// ----------------------------------------------------------------------------------------

void generate_data (
    std::vector<sample_type>& samples,
    std::vector<double>& labels
);
/*!
    ensures
        - make some 3 class data as described above.
        - Create 60 points from class 1
        - Create 70 points from class 2
        - Create 80 points from class 3
!*/

// ----------------------------------------------------------------------------------------

int main()
{
    try
    {
        std::vector<sample_type> samples;
        std::vector<double> labels;

        // First, get our labeled set of training data
        generate_data(samples, labels);

        cout << "samples.size(): "<< samples.size() << endl;

        // The main object in this example program is the one_vs_one_trainer.  It is essentially
        // a container class for regular binary classifier trainer objects.  In particular, it
        // uses the any_trainer object to store any kind of trainer object that implements a
        // .train(samples,labels) function which returns some kind of learned decision function.
        // It uses these binary classifiers to construct a voting multiclass classifier.  If
        // there are N classes then it trains N*(N-1)/2 binary classifiers, one for each pair of
        // labels, which then vote on the label of a sample.
        //
        // In this example program we will work with a one_vs_one_trainer object which stores any
        // kind of trainer that uses our sample_type samples.
        typedef one_vs_one_trainer<any_trainer<sample_type> > ovo_trainer;

        // Finally, make the one_vs_one_trainer.
        ovo_trainer trainer;

        // Next, we will make two different binary classification trainer objects.  One
        // which uses kernel ridge regression and RBF kernels and another which uses a
        // support vector machine and polynomial kernels.  The particular details don't matter.
        // The point of this part of the example is that you can use any kind of trainer object
        // with the one_vs_one_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));

        // Now tell the one_vs_one_trainer that, by default, it should use the rbf_trainer
        // to solve the individual binary classification subproblems.
        trainer.set_trainer(rbf_trainer);
        // We can also get more specific.  Here we tell the one_vs_one_trainer to use the
        // poly_trainer to solve the class 1 vs class 2 subproblem.  All the others will
        // still be solved with the rbf_trainer.
        trainer.set_trainer(poly_trainer, 1, 2);

        // Now let's do 5-fold cross-validation using the one_vs_one_trainer we just setup.
        // As an aside, always shuffle the order of the samples before doing cross validation.
        // For a discussion of why this is a good idea see the svm_ex.cpp example.
        randomize_samples(samples, labels);
        cout << "cross validation: \n" << cross_validate_multiclass_trainer(trainer, samples, labels, 5) << endl;
        // The output is shown below.  It is the confusion matrix which describes the results.  Each row
        // corresponds to a class of data and each column to a prediction.  Reading from top to bottom,
        // the rows correspond to the class labels if the labels have been listed in sorted order.  So the
        // top row corresponds to class 1, the middle row to class 2, and the bottom row to class 3.  The
        // columns are organized similarly, with the left most column showing how many samples were predicted
        // as members of class 1.
        //
        // So in the results below we can see that, for the class 1 samples, 60 of them were correctly predicted
        // to be members of class 1 and 0 were incorrectly classified.  Similarly, the other two classes of data
        // are perfectly classified.
        /*
            cross validation:
            60  0  0
            0 70  0
            0  0 80
        */

        // Next, if you wanted to obtain the decision rule learned by a one_vs_one_trainer you
        // would store it into a one_vs_one_decision_function.
        one_vs_one_decision_function<ovo_trainer> df = trainer.train(samples, labels);

        cout << "predicted label: "<< df(samples[0])  << ", true label: "<< labels[0] << endl;
        cout << "predicted label: "<< df(samples[90]) << ", true label: "<< labels[90] << endl;
        // The output is:
        /*
            predicted label: 2, true label: 2
            predicted label: 1, true label: 1
        */

        // If you want to save a one_vs_one_decision_function to disk, you can do
        // so.  However, you must declare what kind of decision functions it contains.
        one_vs_one_decision_function<ovo_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;

        // Put df into df2 and then save df2 to disk.  Note that we could have also said
        // df2 = trainer.train(samples, labels);  But doing it this way avoids retraining.
        df2 = df;
        serialize("df.dat") << df2;

        // load the function back in from disk and store it in df3.
        deserialize("df.dat") >> df3;

        // Test df3 to see that this worked.
        cout << endl;
        cout << "predicted label: "<< df3(samples[0])  << ", true label: "<< labels[0] << endl;
        cout << "predicted label: "<< df3(samples[90]) << ", true label: "<< labels[90] << endl;
        // Test df3 on the samples and labels and print the confusion matrix.
        cout << "test deserialized function: \n" << test_multiclass_decision_function(df3, samples, labels) << endl;

        // Finally, if you want to get the binary classifiers from inside a multiclass decision
        // function you can do it by calling get_binary_decision_functions() like so:
        one_vs_one_decision_function<ovo_trainer>::binary_function_table functs;
        functs = df.get_binary_decision_functions();
        cout << "number of binary decision functions in df: " << functs.size() << endl;
        // The functs object is a std::map which maps pairs of labels to binary decision
        // functions.  So we can access the individual decision functions like so:
        decision_function<poly_kernel> df_1_2 = any_cast<decision_function<poly_kernel> >(functs[make_unordered_pair(1,2)]);
        decision_function<rbf_kernel>  df_1_3 = any_cast<decision_function<rbf_kernel>  >(functs[make_unordered_pair(1,3)]);
        // df_1_2 contains the binary decision function that votes for class 1 vs. 2.
        // Similarly, df_1_3 contains the classifier that votes for 1 vs. 3.

        // Note that the multiclass decision function doesn't know what kind of binary
        // decision functions it contains.  So we have to use any_cast to explicitly cast
        // them back into the concrete type.  If you make a mistake and try to any_cast a
        // binary decision function into the wrong type of function any_cast will throw a
        // bad_any_cast exception.
    }
    catch (std::exception& e)
    {
        cout << "exception thrown!" << endl;
        cout << e.what() << endl;
    }
}

// ----------------------------------------------------------------------------------------

void generate_data (
    std::vector<sample_type>& samples,
    std::vector<double>& 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 training samples
        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 training samples
        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 training samples
        samples.push_back(m);
        labels.push_back(3);
    }
}

// ----------------------------------------------------------------------------------------


dlib C++ Library - multithreaded_object_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example illustrating the use of the multithreaded_object.

    This is a very simple example.  It creates 3 threads that
    just print messages to the screen.

    Example program output:
    0 INFO  [1] mto: thread1(): hurray threads!
    0 INFO  [2] mto: thread2(): hurray threads!
    0 INFO  [3] mto: thread2(): hurray threads!
  700 INFO  [1] mto: thread1(): hurray threads!
  800 INFO  [2] mto: thread2(): hurray threads!
  801 INFO  [3] mto: thread2(): hurray threads!
 1400 INFO  [1] mto: thread1(): hurray threads!
 1604 INFO  [2] mto: thread2(): hurray threads!
 1605 INFO  [3] mto: thread2(): hurray threads!
 2100 INFO  [1] mto: thread1(): hurray threads!
 2409 INFO  [2] mto: thread2(): hurray threads!
 2409 INFO  [3] mto: thread2(): hurray threads!
 2801 INFO  [1] mto: thread1(): hurray threads!
 3001 INFO  [0] mto: paused threads
 6001 INFO  [0] mto: starting threads back up from paused state
 6001 INFO  [2] mto: thread2(): hurray threads!
 6001 INFO  [1] mto: thread1(): hurray threads!
 6001 INFO  [3] mto: thread2(): hurray threads!
 6705 INFO  [1] mto: thread1(): hurray threads!
 6805 INFO  [2] mto: thread2(): hurray threads!
 6805 INFO  [3] mto: thread2(): hurray threads!
 7405 INFO  [1] mto: thread1(): hurray threads!
 7609 INFO  [2] mto: thread2(): hurray threads!
 7609 INFO  [3] mto: thread2(): hurray threads!
 8105 INFO  [1] mto: thread1(): hurray threads!
 8413 INFO  [2] mto: thread2(): hurray threads!
 8413 INFO  [3] mto: thread2(): hurray threads!
 8805 INFO  [1] mto: thread1(): hurray threads!

  The first column is the number of milliseconds since program start, the second
  column is the logging level, the third column is the thread id, and the rest
  is the log message.
*/

#include <iostream>
#include <dlib/threads.h>
#include <dlib/misc_api.h>  // for dlib::sleep
#include <dlib/logger.h>

using namespace std;
using namespace dlib;

logger dlog("mto");

class my_object : public multithreaded_object
{
public:
    my_object()
    {
        // register which functions we want to run as threads.  We want one thread running
        // thread1() and two threads to run thread2().  So we will have a total of 3 threads
        // running.
        register_thread(*this,&my_object::thread1);
        register_thread(*this,&my_object::thread2);
        register_thread(*this,&my_object::thread2);

        // start all our registered threads going by calling the start() function
        start();
    }

    ~my_object()
    {
        // Tell the thread() function to stop.  This will cause should_stop() to
        // return true so the thread knows what to do.
        stop();

        // Wait for the threads to stop before letting this object destruct itself.
        // Also note, you are *required* to wait for the threads to end before
        // letting this object destruct itself.
        wait();
    }

private:

    void thread1()
    {
        // This is a thread.  It will loop until it is told that it should terminate.
        while (should_stop() == false)
        {
            dlog << LINFO << "thread1(): hurray threads!";
            dlib::sleep(700);
        }
    }

    void thread2()
    {
        // This is a thread.  It will loop until it is told that it should terminate.
        while (should_stop() == false)
        {
            dlog << LINFO << "thread2(): hurray threads!";
            dlib::sleep(800);
        }
    }

};

int main()
{
    // tell the logger to output all messages
    dlog.set_level(LALL);

    // Create an instance of our multi-threaded object.
    my_object t;

    dlib::sleep(3000);

    // Tell the multi-threaded object to pause its threads.  This causes the
    // threads to block on their next calls to should_stop().
    t.pause();
    dlog << LINFO << "paused threads";

    dlib::sleep(3000);
    dlog << LINFO << "starting threads back up from paused state";

    // Tell the threads to unpause themselves.  This causes should_stop() to unblock
    // and to let the threads continue.
    t.start();

    dlib::sleep(3000);

    // Let the program end.  When t is destructed it will gracefully terminate your
    // threads because we have set the destructor up to do so.


dlib C++ Library - mlp_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example illustrating the use of the multilayer perceptron
    from the dlib C++ Library.

    This example creates a simple set of data to train on and shows
    you how to train a mlp object on that data.

    The data used in this example will be 2 dimensional data and will
    come from a distribution where points with a distance less than 10
    from the origin are labeled 1 and all other points are labeled
    as 0.

*/

#include <iostream>
#include <dlib/mlp.h>

using namespace std;
using namespace dlib;

int main()
{
    // The mlp takes column vectors as input and gives column vectors as output.  The dlib::matrix
    // object is used to represent the column vectors. So the first thing we do here is declare
    // a convenient typedef for the matrix object we will be using.

    // This typedef declares a matrix with 2 rows and 1 column.  It will be the
    // object that contains each of our 2 dimensional samples.   (Note that if you wanted
    // more than 2 features in this vector you can simply change the 2 to something else)
    typedef matrix<double, 2, 1> sample_type;

    // make an instance of a sample matrix so we can use it below
    sample_type sample;

    // Create a multi-layer perceptron network.   This network has 2 nodes on the input layer
    // (which means it takes column vectors of length 2 as input) and 5 nodes in the first
    // hidden layer.  Note that the other 4 variables in the mlp's constructor are left at
    // their default values.
    mlp::kernel_1a_c net(2,5);

    // Now let's put some data into our sample and train on it.  We do this
    // by looping over 41*41 points and labeling them according to their
    // distance from the origin.
    for (int i = 0; i < 1000; ++i)
    {
        for (int r = -20; r <= 20; ++r)
        {
            for (int c = -20; c <= 20; ++c)
            {
                sample(0) = r;
                sample(1) = c;

                // if this point is less than 10 from the origin
                if (sqrt((double)r*r + c*c) <= 10)
                    net.train(sample,1);
                else
                    net.train(sample,0);
            }
        }
    }

    // Now we have trained our mlp.  Let's see how well it did.
    // Note that if you run this program multiple times you will get different results. This
    // is because the mlp network is randomly initialized.

    // each of these statements prints out the output of the network given a particular sample.

    sample(0) = 3.123;
    sample(1) = 4;
    cout << "This sample should be close to 1 and it is classified as a " << net(sample) << endl;

    sample(0) = 13.123;
    sample(1) = 9.3545;
    cout << "This sample should be close to 0 and it is classified as a " << net(sample) << endl;

    sample(0) = 13.123;
    sample(1) = 0;
    cout << "This sample should be close to 0 and it is classified as a " << net(sample) << endl;


dlib C++ Library - least_squares_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example illustrating the use the general purpose non-linear
    least squares optimization routines from the dlib C++ Library.

    This example program will demonstrate how these routines can be used for data fitting.
    In particular, we will generate a set of data and then use the least squares
    routines to infer the parameters of the model which generated the data.
*/

#include <dlib/optimization.h>
#include <iostream>
#include <vector>

using namespace std;
using namespace dlib;

// ----------------------------------------------------------------------------------------

typedef matrix<double,2,1> input_vector;
typedef matrix<double,3,1> parameter_vector;

// ----------------------------------------------------------------------------------------

// We will use this function to generate data.  It represents a function of 2 variables
// and 3 parameters.   The least squares procedure will be used to infer the values of
// the 3 parameters based on a set of input/output pairs.
double model (
    const input_vector& input,
    const parameter_vector& params
)
{
    const double p0 = params(0);
    const double p1 = params(1);
    const double p2 = params(2);

    const double i0 = input(0);
    const double i1 = input(1);

    const double temp = p0*i0 + p1*i1 + p2;

    return temp*temp;
}

// ----------------------------------------------------------------------------------------

// This function is the "residual" for a least squares problem.   It takes an input/output
// pair and compares it to the output of our model and returns the amount of error.  The idea
// is to find the set of parameters which makes the residual small on all the data pairs.
double residual (
    const std::pair<input_vector, double>& data,
    const parameter_vector& params
)
{
    return model(data.first, params) - data.second;
}

// ----------------------------------------------------------------------------------------

// This function is the derivative of the residual() function with respect to the parameters.
parameter_vector residual_derivative (
    const std::pair<input_vector, double>& data,
    const parameter_vector& params
)
{
    parameter_vector der;

    const double p0 = params(0);
    const double p1 = params(1);
    const double p2 = params(2);

    const double i0 = data.first(0);
    const double i1 = data.first(1);

    const double temp = p0*i0 + p1*i1 + p2;

    der(0) = i0*2*temp;
    der(1) = i1*2*temp;
    der(2) = 2*temp;

    return der;
}

// ----------------------------------------------------------------------------------------

int main()
{
    try
    {
        // randomly pick a set of parameters to use in this example
        const parameter_vector params = 10*randm(3,1);
        cout << "params: " << trans(params) << endl;

        // Now let's generate a bunch of input/output pairs according to our model.
        std::vector<std::pair<input_vector, double> > data_samples;
        input_vector input;
        for (int i = 0; i < 1000; ++i)
        {
            input = 10*randm(2,1);
            const double output = model(input, params);

            // save the pair
            data_samples.push_back(make_pair(input, output));
        }

        // Before we do anything, let's make sure that our derivative function defined above matches
        // the approximate derivative computed using central differences (via derivative()).
        // If this value is big then it means we probably typed the derivative function incorrectly.
        cout << "derivative error: " << length(residual_derivative(data_samples[0], params) -
                                               derivative(residual)(data_samples[0], params) ) << endl;

        // Now let's use the solve_least_squares_lm() routine to figure out what the
        // parameters are based on just the data_samples.
        parameter_vector x;
        x = 1;

        cout << "Use Levenberg-Marquardt" << endl;
        // Use the Levenberg-Marquardt method to determine the parameters which
        // minimize the sum of all squared residuals.
        solve_least_squares_lm(objective_delta_stop_strategy(1e-7).be_verbose(),
                               residual,
                               residual_derivative,
                               data_samples,
                               x);

        // Now x contains the solution.  If everything worked it will be equal to params.
        cout << "inferred parameters: "<< trans(x) << endl;
        cout << "solution error:      "<< length(x - params) << endl;
        cout << endl;

        x = 1;
        cout << "Use Levenberg-Marquardt, approximate derivatives" << endl;
        // If we didn't create the residual_derivative function then we could
        // have used this method which numerically approximates the derivatives for you.
        solve_least_squares_lm(objective_delta_stop_strategy(1e-7).be_verbose(),
                               residual,
                               derivative(residual),
                               data_samples,
                               x);

        // Now x contains the solution.  If everything worked it will be equal to params.
        cout << "inferred parameters: "<< trans(x) << endl;
        cout << "solution error:      "<< length(x - params) << endl;
        cout << endl;

        x = 1;
        cout << "Use Levenberg-Marquardt/quasi-newton hybrid" << endl;
        // This version of the solver uses a method which is appropriate for problems
        // where the residuals don't go to zero at the solution.  So in these cases
        // it may provide a better answer.
        solve_least_squares(objective_delta_stop_strategy(1e-7).be_verbose(),
                            residual,
                            residual_derivative,
                            data_samples,
                            x);

        // Now x contains the solution.  If everything worked it will be equal to params.
        cout << "inferred parameters: "<< trans(x) << endl;
        cout << "solution error:      "<< length(x - params) << endl;

    }
    catch (std::exception& e)
    {
        cout << e.what() << endl;
    }
}

// Example output:
/*
params: 8.40188 3.94383 7.83099

derivative error: 9.78267e-06
Use Levenberg-Marquardt
iteration: 0   objective: 2.14455e+10
iteration: 1   objective: 1.96248e+10
iteration: 2   objective: 1.39172e+10
iteration: 3   objective: 1.57036e+09
iteration: 4   objective: 2.66917e+07
iteration: 5   objective: 4741.9
iteration: 6   objective: 0.000238674
iteration: 7   objective: 7.8815e-19
iteration: 8   objective: 0
inferred parameters: 8.40188 3.94383 7.83099

solution error:      0

Use Levenberg-Marquardt, approximate derivatives
iteration: 0   objective: 2.14455e+10
iteration: 1   objective: 1.96248e+10
iteration: 2   objective: 1.39172e+10
iteration: 3   objective: 1.57036e+09
iteration: 4   objective: 2.66917e+07
iteration: 5   objective: 4741.87
iteration: 6   objective: 0.000238701
iteration: 7   objective: 1.0571e-18
iteration: 8   objective: 4.12469e-22
inferred parameters: 8.40188 3.94383 7.83099

solution error:      5.34754e-15

Use Levenberg-Marquardt/quasi-newton hybrid
iteration: 0   objective: 2.14455e+10
iteration: 1   objective: 1.96248e+10
iteration: 2   objective: 1.3917e+10
iteration: 3   objective: 1.5572e+09
iteration: 4   objective: 2.74139e+07
iteration: 5   objective: 5135.98
iteration: 6   objective: 0.000285539
iteration: 7   objective: 1.15441e-18
iteration: 8   objective: 3.38834e-23
inferred parameters: 8.40188 3.94383 7.83099

solution error:      1.77636e-15
*/


dlib C++ Library - svm_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example illustrating the use of the support vector machine
    utilities from the dlib C++ Library.

    This example creates a simple set of data to train on and then shows
    you how to use the cross validation and svm training functions
    to find a good decision function that can classify examples in our
    data set.

    The data used in this example will be 2 dimensional data and will
    come from a distribution where points with a distance less than 10
    from the origin are labeled +1 and all other points are labeled
    as -1.

*/

#include <iostream>
#include <dlib/svm.h>

using namespace std;
using namespace dlib;

int main()
{
    // The svm functions use column vectors to contain a lot of the data on which they
    // operate. So the first thing we do here is declare a convenient typedef.

    // This typedef declares a matrix with 2 rows and 1 column.  It will be the object that
    // contains each of our 2 dimensional samples.   (Note that if you wanted more than 2
    // features in this vector you can simply change the 2 to something else.  Or if you
    // don't know how many features you want until runtime then you can put a 0 here and
    // use the matrix.set_size() member function)
    typedef matrix<double, 2, 1> sample_type;

    // This is a typedef for the type of kernel we are going to use in this example.  In
    // this case I have selected the radial basis kernel that can operate on our 2D
    // sample_type objects
    typedef radial_basis_kernel<sample_type> kernel_type;

    // Now we make objects to contain our samples and their respective labels.
    std::vector<sample_type> samples;
    std::vector<double> labels;

    // Now let's put some data into our samples and labels objects.  We do this by looping
    // over a bunch of points and labeling them according to their distance from the
    // origin.
    for (int r = -20; r <= 20; ++r)
    {
        for (int c = -20; c <= 20; ++c)
        {
            sample_type samp;
            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) <= 10)
                labels.push_back(+1);
            else
                labels.push_back(-1);

        }
    }

    // Here we normalize all the samples by subtracting their mean and dividing by their
    // standard deviation.  This is generally a good idea since it often heads off
    // numerical stability problems and also prevents one large feature from smothering
    // others.  Doing this doesn't matter much in this example so I'm just doing this here
    // so you can see an easy way to accomplish this with the library.
    vector_normalizer<sample_type> normalizer;
    // let the normalizer learn the mean and standard deviation of the samples
    normalizer.train(samples);
    // now normalize each sample
    for (unsigned long i = 0; i < samples.size(); ++i)
        samples[i] = normalizer(samples[i]);

    // Now that we have some data we want to train on it.  However, there are two
    // parameters to the training.  These are the nu and gamma parameters.  Our choice for
    // these parameters will influence how good the resulting decision function is.  To
    // test how good a particular choice of these parameters is we can use the
    // cross_validate_trainer() function to perform n-fold cross validation on our training
    // data.  However, there is a problem with the way we have sampled our distribution
    // above.  The problem is that there is a definite ordering to the samples.  That is,
    // the first half of the samples look like they are from a different distribution than
    // the second half.  This would screw up the cross validation process but we can fix it
    // by randomizing the order of the samples with the following function call.
    randomize_samples(samples, labels);

    // The nu parameter has a maximum value that is dependent on the ratio of the +1 to -1
    // labels in the training data.  This function finds that value.
    const double max_nu = maximum_nu(labels);

    // here we make an instance of the svm_nu_trainer object that uses our kernel type.
    svm_nu_trainer<kernel_type> trainer;

    // Now we loop over some different nu and gamma values to see how good they are.  Note
    // that this is a very simple way to try out a few possible parameter choices.  You
    // should look at the model_selection_ex.cpp program for examples of more sophisticated
    // strategies for determining good parameter choices.
    cout << "doing cross validation" << endl;
    for (double gamma = 0.00001; gamma <= 1; gamma *= 5)
    {
        for (double nu = 0.00001; nu < max_nu; nu *= 5)
        {
            // tell the trainer the parameters we want to use
            trainer.set_kernel(kernel_type(gamma));
            trainer.set_nu(nu);

            cout << "gamma: " << gamma << "    nu: " << nu;
            // Print out the cross validation accuracy for 3-fold cross validation using
            // the current gamma and nu.  cross_validate_trainer() returns a row vector.
            // The first element of the vector is the fraction of +1 training examples
            // correctly classified and the second number is the fraction of -1 training
            // examples correctly classified.
            cout << "     cross validation accuracy: " << cross_validate_trainer(trainer, samples, labels, 3);
        }
    }

    // From looking at the output of the above loop it turns out that a good value for nu
    // and gamma for this problem is 0.15625 for both.  So that is what we will use.

    // Now we train on the full set of data and obtain the resulting decision function.  We
    // use the value of 0.15625 for nu and gamma.  The decision function will return values
    // >= 0 for samples it predicts are in the +1 class and numbers < 0 for samples it
    // predicts to be in the -1 class.
    trainer.set_kernel(kernel_type(0.15625));
    trainer.set_nu(0.15625);
    typedef decision_function<kernel_type> dec_funct_type;
    typedef normalized_function<dec_funct_type> funct_type;

    // Here we are making an instance of the normalized_function object.  This object
    // provides a convenient way to store the vector normalization information along with
    // the decision function we are going to learn.
    funct_type learned_function;
    learned_function.normalizer = normalizer;  // save normalization information
    learned_function.function = trainer.train(samples, labels); // perform the actual SVM training and save the results

    // print out the number of support vectors in the resulting decision function
    cout << "\nnumber of support vectors in our learned_function is "
         << learned_function.function.basis_vectors.size() << endl;

    // Now let's try this decision_function on some samples we haven't seen before.
    sample_type sample;

    sample(0) = 3.123;
    sample(1) = 2;
    cout << "This is a +1 class example, the classifier output is " << learned_function(sample) << endl;

    sample(0) = 3.123;
    sample(1) = 9.3545;
    cout << "This is a +1 class example, the classifier output is " << learned_function(sample) << endl;

    sample(0) = 13.123;
    sample(1) = 9.3545;
    cout << "This is a -1 class example, the classifier output is " << learned_function(sample) << endl;

    sample(0) = 13.123;
    sample(1) = 0;
    cout << "This is a -1 class example, the classifier output is " << learned_function(sample) << endl;

    // We can also train a decision function that reports a well conditioned probability
    // instead of just a number > 0 for the +1 class and < 0 for the -1 class.  An example
    // of doing that follows:
    typedef probabilistic_decision_function<kernel_type> probabilistic_funct_type;
    typedef normalized_function<probabilistic_funct_type> pfunct_type;

    pfunct_type learned_pfunct;
    learned_pfunct.normalizer = normalizer;
    learned_pfunct.function = train_probabilistic_decision_function(trainer, samples, labels, 3);
    // Now we have a function that returns the probability that a given sample is of the +1 class.

    // print out the number of support vectors in the resulting decision function.
    // (it should be the same as in the one above)
    cout << "\nnumber of support vectors in our learned_pfunct is "
         << learned_pfunct.function.decision_funct.basis_vectors.size() << endl;

    sample(0) = 3.123;
    sample(1) = 2;
    cout << "This +1 class example should have high probability.  Its probability is: "
         << learned_pfunct(sample) << endl;

    sample(0) = 3.123;
    sample(1) = 9.3545;
    cout << "This +1 class example should have high probability.  Its probability is: "
         << learned_pfunct(sample) << endl;

    sample(0) = 13.123;
    sample(1) = 9.3545;
    cout << "This -1 class example should have low probability.  Its probability is: "
         << learned_pfunct(sample) << endl;

    sample(0) = 13.123;
    sample(1) = 0;
    cout << "This -1 class example should have low probability.  Its probability is: "
         << learned_pfunct(sample) << endl;

    // Another thing that is worth knowing is that just about everything in dlib is
    // serializable.  So for example, you can save the learned_pfunct object to disk and
    // recall it later like so:
    serialize("saved_function.dat") << learned_pfunct;

    // Now let's open that file back up and load the function object it contains.
    deserialize("saved_function.dat") >> learned_pfunct;

    // Note that there is also an example program that comes with dlib called the
    // file_to_code_ex.cpp example.  It is a simple program that takes a file and outputs a
    // piece of C++ code that is able to fully reproduce the file's contents in the form of
    // a std::string object.  So you can use that along with the std::istringstream to save
    // learned decision functions inside your actual C++ code files if you want.

    // Lastly, note that the decision functions we trained above involved well over 200
    // basis vectors.  Support vector machines in general tend to find decision functions
    // that involve a lot of basis vectors.  This is significant because the more basis
    // vectors in a decision function, the longer it takes to classify new examples.  So
    // dlib provides the ability to find an approximation to the normal output of a trainer
    // using fewer basis vectors.

    // Here we determine the cross validation accuracy when we approximate the output using
    // only 10 basis vectors.  To do this we use the reduced2() function.  It takes a
    // trainer object and the number of basis vectors to use and returns a new trainer
    // object that applies the necessary post processing during the creation of decision
    // function objects.
    cout << "\ncross validation accuracy with only 10 support vectors: "
         << cross_validate_trainer(reduced2(trainer,10), samples, labels, 3);

    // Let's print out the original cross validation score too for comparison.
    cout << "cross validation accuracy with all the original support vectors: "
         << cross_validate_trainer(trainer, samples, labels, 3);

    // When you run this program you should see that, for this problem, you can reduce the
    // number of basis vectors down to 10 without hurting the cross validation accuracy.

    // To get the reduced decision function out we would just do this:
    learned_function.function = reduced2(trainer,10).train(samples, labels);
    // And similarly for the probabilistic_decision_function:
    learned_pfunct.function = train_probabilistic_decision_function(reduced2(trainer,10), samples, labels, 3);


dlib C++ Library - integrate_function_adapt_simp_ex.cpp

// The contents of this file are in the public domain.  See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This example demonstrates the usage of the numerical quadrature function
    integrate_function_adapt_simp().  This function takes as input a single variable
    function, the endpoints of a domain over which the function will be integrated, and a
    tolerance parameter.  It outputs an approximation of the integral of this function over
    the specified domain.  The algorithm is based on the adaptive Simpson method outlined in:

        Numerical Integration method based on the adaptive Simpson method in
        Gander, W. and W. Gautschi, "Adaptive Quadrature – Revisited,"
        BIT, Vol. 40, 2000, pp. 84-101

*/

#include <iostream>
#include <dlib/matrix.h>
#include <dlib/numeric_constants.h>
#include <dlib/numerical_integration.h>

using namespace std;
using namespace dlib;

// Here we the set of functions that we wish to integrate and comment in the domain of
// integration.

// x in [0,1]
double gg1(double x)
{
    return pow(e,x);
}

// x in [0,1]
double gg2(double x)
{
    return x*x;
}

// x in [0, pi]
double gg3(double x)
{
    return 1/(x*x + cos(x)*cos(x));
}

// x in [-pi, pi]
double gg4(double x)
{
    return sin(x);
}

// x in [0,2]
double gg5(double x)
{
    return 1/(1 + x*x);
}

int main()
{
    // We first define a tolerance parameter.  Roughly speaking, a lower tolerance will
    // result in a more accurate approximation of the true integral.  However, there are
    // instances where too small of a tolerance may yield a less accurate approximation
    // than a larger tolerance.  We recommend taking the tolerance to be in the
    // [1e-10, 1e-8] region.

    double tol = 1e-10;

    // Here we compute the integrals of the five functions defined above using the same
    // tolerance level for each.

    double m1 = integrate_function_adapt_simp(&gg1, 0.0, 1.0, tol);
    double m2 = integrate_function_adapt_simp(&gg2, 0.0, 1.0, tol);
    double m3 = integrate_function_adapt_simp(&gg3, 0.0, pi, tol);
    double m4 = integrate_function_adapt_simp(&gg4, -pi, pi, tol);
    double m5 = integrate_function_adapt_simp(&gg5, 0.0, 2.0, tol);

    // We finally print out the values of each of the approximated integrals to ten
    // significant digits.

    cout << "\nThe integral of exp(x) for x in [0,1] is "          << std::setprecision(10) <<  m1  << endl;
    cout << "The integral of x^2 for in [0,1] is "                 << std::setprecision(10) <<  m2  << endl;
    cout << "The integral of 1/(x^2 + cos(x)^2) for in [0,pi] is " << std::setprecision(10) <<  m3  << endl;
    cout << "The integral of sin(x) for in [-pi,pi] is "           << std::setprecision(10) <<  m4  << endl;
    cout << "The integral of 1/(1+x^2) for in [0,2] is "           << std::setprecision(10) <<  m5  << endl;
    cout << endl;

    return 0;


dlib C++ Library - object_detector_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example illustrating the use of dlib's bag-of-visual-word based
    tools for detecting objects in images.  In this example we will create three
    simple images, each containing some white squares.  We will then use the
    sliding window classifier tools to learn to detect these squares.

    If the objects you want to detect are somewhat rigid in appearance (e.g.
    faces, pedestrians, etc.) then you should try the methods shown in the
    fhog_object_detector_ex.cpp example program before trying to use the
    bag-of-visual-word tools shown in this example.
*/

#include <dlib/svm_threaded.h>
#include <dlib/gui_widgets.h>
#include <dlib/array.h>
#include <dlib/array2d.h>
#include <dlib/image_keypoint.h>
#include <dlib/image_processing.h>

#include <iostream>
#include <fstream>

using namespace std;
using namespace dlib;

// ----------------------------------------------------------------------------------------

template <
    typename image_array_type
    >
void make_simple_test_data (
    image_array_type& images,
    std::vector<std::vector<rectangle> >& object_locations
)
/*!
    ensures
        - #images.size() == 3
        - #object_locations.size() == 3
        - Creates some simple images to test the object detection routines.  In particular,
          this function creates images with white 70x70 squares in them.  It also stores
          the locations of these squares in object_locations.
        - for all valid i:
            - object_locations[i] == A list of all the white rectangles present in images[i].
!*/
{
    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)
            {
                images[i][r][c] = put_in_range(0,255,images[i][r][c] + 40*rnd.get_random_gaussian());
            }
        }
    }
}

// ----------------------------------------------------------------------------------------

int main()
{
    try
    {
        // The first thing we do is create the set of 3 images discussed above.
        dlib::array<array2d<unsigned char> > images;
        std::vector<std::vector<rectangle> > object_locations;
        make_simple_test_data(images, object_locations);

        /*
            This next block of code specifies the type of sliding window classifier we will
            be using to detect the white squares.  The most important thing here is the
            scan_image_pyramid template.  Instances of this template represent the core
            of a sliding window classifier.  To go into more detail, the sliding window
            classifiers used by this object have three parts:
                   1. The underlying feature extraction.  See the dlib documentation for a detailed
                      discussion of how the hashed_feature_image and hog_image feature extractors
                      work.  However, to understand this example, all you need to know is that the
                      feature extractor associates a vector with each location in an image.  This
                      vector is supposed to capture information which describes how parts of the
                      image look.  Importantly, it should do this in a way that is relevant to the
                      problem you are trying to solve.

                   2. A detection template.  This is a rectangle which defines the shape of a
                      sliding window (i.e. the object_box), as well as a set of rectangular feature
                      extraction regions inside it.  This set of regions defines the spatial
                      structure of the overall feature extraction within a sliding window.  In
                      particular, each location of a sliding window has a feature vector
                      associated with it.  This feature vector is defined as follows:
                        - Let N denote the number of feature extraction zones.
                        - Let M denote the dimensionality of the vectors output by Feature_extractor_type
                          objects.
                        - Let F(i) == the M dimensional vector which is the sum of all vectors
                          given by our Feature_extractor_type object inside the ith feature extraction
                          zone.
                        - Then the feature vector for a sliding window is an M*N dimensional vector
                          [F(1) F(2) F(3) ... F(N)] (i.e. it is a concatenation of the N vectors).
                          This feature vector can be thought of as a collection of N "bags of features",
                          each bag coming from a spatial location determined by one of the rectangular
                          feature extraction zones.

                   3. A weight vector and a threshold value.  The dot product between the weight
                      vector and the feature vector for a sliding window location gives the score
                      of the window.  If this score is greater than the threshold value then the
                      window location is output as a detection.  You don't need to determine these
                      parameters yourself.  They are automatically populated by the
                      structural_object_detection_trainer.

                The sliding window classifiers described above are applied to every level of an
                image pyramid.  So you need to tell scan_image_pyramid what kind of pyramid you want
                to use.  In this case we are using pyramid_down<2> which downsamples each pyramid
                layer by half (if you want to use a finer image pyramid then just change the
                template argument to a larger value.  For example, using pyramid_down<5> would
                downsample each layer by a ratio of 5 to 4).

                Finally, some of the feature extraction zones are allowed to move freely within the
                object box.  This means that when we are sliding the classifier over an image, some
                feature extraction zones are stationary (i.e. always in the same place relative to
                the object box) while others are allowed to move anywhere within the object box.  In
                particular, the movable regions are placed at the locations that maximize the score
                of the classifier.  Note further that each of the movable feature extraction zones
                must pass a threshold test for it to be included.  That is, if the score that a
                movable zone would contribute to the overall score for a sliding window location is
                not positive then that zone is not included in the feature vector (i.e. its part of
                the feature vector is set to zero.  This way the length of the feature vector stays
                constant).  This movable region construction allows us to represent objects with
                parts that move around relative to the object box.  For example, a human has hands
                but they aren't always in the same place relative to a person's bounding box.
                However, to keep this example program simple, we will only be using stationary
                feature extraction regions.
        */
        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;

        // The hashed_feature_image in the scanner needs to be supplied with a hash function capable
        // of hashing the outputs of the hog_image.  Calling this function will set it up for us.  The
        // 10 here indicates that it will hash HOG vectors into the range [0, pow(2,10)).  Therefore,
        // the feature vectors output by the hashed_feature_image will have dimension pow(2,10).
        setup_hashed_features(scanner, images, 10);
        // We should also tell the scanner to use the uniform feature weighting scheme
        // since it works best on the data in this example.  If you don't call this
        // function then it will use a slightly different weighting scheme which can give
        // improved results on many normal image types.
        use_uniform_feature_weights(scanner);

        // We also need to setup the detection templates the scanner will use.  It is important that
        // we add detection templates which are capable of matching all the output boxes we want to learn.
        // For example, if object_locations contained a rectangle with a height to width ratio of 10 but
        // we only added square detection templates then it would be impossible to detect this non-square
        // rectangle.  The setup_grid_detection_templates_verbose() routine will take care of this for us by
        // looking at the contents of object_locations and automatically picking an appropriate set.  Also,
        // the final arguments indicate that we want our detection templates to have 4 feature extraction
        // regions laid out in a 2x2 regular grid inside each sliding window.
        setup_grid_detection_templates_verbose(scanner, object_locations, 2, 2);

        // Now that we have defined the kind of sliding window classifier system we want and stored
        // the details into the scanner object we are ready to use the structural_object_detection_trainer
        // to learn the weight vector and threshold needed to produce a complete object detector.
        structural_object_detection_trainer<image_scanner_type> trainer(scanner);
        trainer.set_num_threads(4); // Set this to the number of processing cores on your machine.

        // There are a variety of other useful parameters to the structural_object_detection_trainer.
        // Examples of the ones you are most likely to use follow (see dlib documentation for what they do):
        //trainer.set_match_eps(0.80);
        //trainer.set_c(1.0);
        //trainer.set_loss_per_missed_target(1);
        //trainer.set_loss_per_false_alarm(1);

        // Do the actual training and save the results into the detector object.
        object_detector<image_scanner_type> detector = trainer.train(images, object_locations);

        // We can easily test the new detector against our training data.  This print statement will indicate that it
        // has perfect precision and recall on this simple task.  It will also print the average precision (AP).
        cout << "Test detector (precision,recall,AP): " << test_object_detection_function(detector, images, object_locations) << endl;

        // The cross validation should also indicate perfect precision and recall.
        cout << "3-fold cross validation (precision,recall,AP): "
             << cross_validate_object_detection_trainer(trainer, images, object_locations, 3) << endl;

        // Let's display the output of the detector along with our training images.
        image_window win;
        for (unsigned long i = 0; i < images.size(); ++i)
        {
            // Run the detector on images[i]
            const std::vector<rectangle> rects = detector(images[i]);
            cout << "Number of detections: "<< rects.size() << endl;

            // Put the image and detections into the window.
            win.clear_overlay();
            win.set_image(images[i]);
            win.add_overlay(rects, rgb_pixel(255,0,0));

            cout << "Hit enter to see the next image.";
            cin.get();
        }

        // Finally, note that the detector can be serialized to disk just like other dlib objects.
        serialize("object_detector.dat") << detector;

        // Recall from disk.
        deserialize("object_detector.dat") >> detector;
    }
    catch (exception& e)
    {
        cout << "\nexception thrown!" << endl;
        cout << e.what() << endl;
    }
}

// ----------------------------------------------------------------------------------------


dlib C++ Library - object_detector_advanced_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example illustrating the process for defining custom
    bag-of-visual-word style feature extractors for use with the
    structural_object_detection_trainer.

    NOTICE: This example assumes you are familiar with the contents of the
    object_detector_ex.cpp example program.  Also, if the objects you want to
    detect are somewhat rigid in appearance (e.g.  faces, pedestrians, etc.)
    then you should try the methods shown in the fhog_object_detector_ex.cpp
    example program before trying to use the bag-of-visual-word tools shown in
    this example.
*/

#include <dlib/svm_threaded.h>
#include <dlib/gui_widgets.h>
#include <dlib/array.h>
#include <dlib/array2d.h>
#include <dlib/image_keypoint.h>
#include <dlib/image_processing.h>

#include <iostream>
#include <fstream>

using namespace std;
using namespace dlib;

// ----------------------------------------------------------------------------------------

template <
    typename image_array_type
    >
void make_simple_test_data (
    image_array_type& images,
    std::vector<std::vector<rectangle> >& object_locations
)
/*!
    ensures
        - #images.size() == 3
        - #object_locations.size() == 3
        - Creates some simple images to test the object detection routines.  In particular,
          this function creates images with white 70x70 squares in them.  It also stores
          the locations of these squares in object_locations.
        - for all valid i:
            - object_locations[i] == A list of all the white rectangles present in images[i].
!*/
{
    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);
}

// ----------------------------------------------------------------------------------------

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:

    template <
        typename image_type
        >
    inline void load (
        const image_type& 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 unsigned long 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& item){}

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;
};

// ----------------------------------------------------------------------------------------

int main()
{
    try
    {
        // Get some data
        dlib::array<array2d<unsigned char> > 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;
        // Instead of using setup_grid_detection_templates() like in object_detector_ex.cpp, let's manually
        // setup the sliding window box.  We use a window with the same shape as the white boxes we
        // are trying to detect.
        const rectangle object_box = compute_box_dimensions(1,    // width/height ratio
                                                            70*70 // box area
                                                            );
        scanner.add_detection_template(object_box, create_grid_detection_template(object_box,2,2));

        // Since our sliding window is already the right size to detect our objects we don't need
        // to use an image pyramid.  So setting this to 1 turns off the image pyramid.
        scanner.set_max_pyramid_levels(1);

        // While the very_simple_feature_extractor doesn't have any parameters, when you go solve
        // real problems you might define a feature extractor which has some non-trivial parameters
        // that need to be setup before it can be used.  So you need to be able to pass these parameters
        // to the scanner object somehow.  You can do this using the copy_configuration() function as
        // shown below.
        very_simple_feature_extractor fe;
        /*
            setup the parameters in the fe object.
            ...
        */
        // The scanner will use very_simple_feature_extractor::copy_configuration() to copy the state
        // of fe into its internal feature extractor.
        scanner.copy_configuration(fe);

        // Now that we have defined the kind of sliding window classifier system we want and stored
        // the details into the scanner object we are ready to use the structural_object_detection_trainer
        // to learn the weight vector and threshold needed to produce a complete object detector.
        structural_object_detection_trainer<image_scanner_type> trainer(scanner);
        trainer.set_num_threads(4); // Set this to the number of processing cores on your machine.

        // The trainer will try and find the detector which minimizes the number of detection mistakes.
        // This function controls how it decides if a detection output is a mistake or not.  The bigger
        // the input to this function the more strict it is in deciding if the detector is correctly
        // hitting the targets.  Try reducing the value to 0.001 and observing the results.  You should
        // see that the detections aren't exactly on top of the white squares anymore.  See the documentation
        // for the structural_object_detection_trainer and structural_svm_object_detection_problem objects
        // for a more detailed discussion of this parameter.
        trainer.set_match_eps(0.95);

        object_detector<image_scanner_type> detector = trainer.train(images, object_locations);

        // We can easily test the new detector against our training data.  This print
        // statement will indicate that it has perfect precision and recall on this simple
        // task.  It will also print the average precision (AP).
        cout << "Test detector (precision,recall,AP): " << test_object_detection_function(detector, images, object_locations) << endl;

        // The cross validation should also indicate perfect precision and recall.
        cout << "3-fold cross validation (precision,recall,AP): "
             << cross_validate_object_detection_trainer(trainer, images, object_locations, 3) << endl;

        /*
            It is also worth pointing out that you don't have to use dlib::array2d objects to
            represent your images.  In fact, you can use any object, even something like a struct
            of many images and other things as the "image".  The only requirements on an image
            are that it should be possible to pass it to scanner.load().  So if you can say
            scanner.load(images[0]), for example, then you are good to go.  See the documentation
            for scan_image_pyramid::load() for more details.
        */

        // Let's display the output of the detector along with our training images.
        image_window win;
        for (unsigned long i = 0; i < images.size(); ++i)
        {
            // Run the detector on images[i]
            const std::vector<rectangle> rects = detector(images[i]);
            cout << "Number of detections: "<< rects.size() << endl;

            // Put the image and detections into the window.
            win.clear_overlay();
            win.set_image(images[i]);
            win.add_overlay(rects, rgb_pixel(255,0,0));

            cout << "Hit enter to see the next image.";
            cin.get();
        }

    }
    catch (exception& e)
    {
        cout << "\nexception thrown!" << endl;
        cout << e.what() << endl;
    }
}

// ----------------------------------------------------------------------------------------


dlib C++ Library - one_class_classifiers_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*
    This is an example illustrating the use of the tools in dlib for doing distribution
    estimation or detecting anomalies using one-class support vector machines.

    Unlike regular classifiers, these tools take unlabeled points and try to learn what
    parts of the feature space normally contain data samples and which do not.  Typically
    you use these tools when you are interested in finding outliers or otherwise
    identifying "unusual" data samples.

    In this example, we will sample points from the sinc() function to generate our set of
    "typical looking" points.  Then we will train some one-class classifiers and use them
    to predict if new points are unusual or not.  In this case, unusual means a point is
    not from the sinc() curve.
*/

#include <iostream>
#include <vector>
#include <dlib/svm.h>
#include <dlib/gui_widgets.h>
#include <dlib/array2d.h>
#include <dlib/image_transforms.h>

using namespace std;
using namespace dlib;

// Here is the sinc function we will be trying to learn with the one-class SVMs
double sinc(double x)
{
    if (x == 0)
        return 2;
    return 2*sin(x)/x;
}

int main()
{
    // We will use column vectors to store our points.  Here we make a convenient typedef
    // for the kind of vector we will use.
    typedef matrix<double,0,1> sample_type;

    // Then we select the kernel we want to use.  For our present problem the radial basis
    // kernel is quite effective.
    typedef radial_basis_kernel<sample_type> kernel_type;

    // Now make the object responsible for training one-class SVMs.
    svm_one_class_trainer<kernel_type> trainer;
    // Here we set the width of the radial basis kernel to 4.0.  Larger values make the
    // width smaller and give the radial basis kernel more resolution.  If you play with
    // the value and observe the program output you will get a more intuitive feel for what
    // that means.
    trainer.set_kernel(kernel_type(4.0));

    // Now sample some 2D points.  The points will be located on the curve defined by the
    // sinc() function.
    std::vector<sample_type> samples;
    sample_type m(2);
    for (double x = -15; x <= 8; x += 0.3)
    {
        m(0) = x;
        m(1) = sinc(x);
        samples.push_back(m);
    }

    // Now train a one-class SVM.  The result is a function, df(), that outputs large
    // values for points from the sinc() curve and smaller values for points that are
    // anomalous (i.e. not on the sinc() curve in our case).
    decision_function<kernel_type> df = trainer.train(samples);

    // So for example, let's look at the output from some points on the sinc() curve.
    cout << "Points that are on the sinc function:\n";
    m(0) = -1.5; m(1) = sinc(m(0)); cout << "   " << df(m) << endl;
    m(0) = -1.5; m(1) = sinc(m(0)); cout << "   " << df(m) << endl;
    m(0) = -0;   m(1) = sinc(m(0)); cout << "   " << df(m) << endl;
    m(0) = -0.5; m(1) = sinc(m(0)); cout << "   " << df(m) << endl;
    m(0) = -4.1; m(1) = sinc(m(0)); cout << "   " << df(m) << endl;
    m(0) = -1.5; m(1) = sinc(m(0)); cout << "   " << df(m) << endl;
    m(0) = -0.5; m(1) = sinc(m(0)); cout << "   " << df(m) << endl;

    cout << endl;
    // Now look at some outputs for points not on the sinc() curve.  You will see that
    // these values are all notably smaller.
    cout << "Points that are NOT on the sinc function:\n";
    m(0) = -1.5; m(1) = sinc(m(0))+4;   cout << "   " << df(m) << endl;
    m(0) = -1.5; m(1) = sinc(m(0))+3;   cout << "   " << df(m) << endl;
    m(0) = -0;   m(1) = -sinc(m(0));    cout << "   " << df(m) << endl;
    m(0) = -0.5; m(1) = -sinc(m(0));    cout << "   " << df(m) << endl;
    m(0) = -4.1; m(1) = sinc(m(0))+2;   cout << "   " << df(m) << endl;
    m(0) = -1.5; m(1) = sinc(m(0))+0.9; cout << "   " << df(m) << endl;
    m(0) = -0.5; m(1) = sinc(m(0))+1;   cout << "   " << df(m) << endl;

    // The output is as follows:
    /*
    Points that are on the sinc function:
        0.000389691
        0.000389691
        -0.000239037
        -0.000179978
        -0.000178491
        0.000389691
        -0.000179978

    Points that are NOT on the sinc function:
        -0.269389
        -0.269389
        -0.269389
        -0.269389
        -0.269389
        -0.239954
        -0.264318
    */

    // So we can see that in this example the one-class SVM correctly indicates that
    // the non-sinc points are definitely not points from the sinc() curve.

    // It should be noted that the svm_one_class_trainer becomes very slow when you have
    // more than 10 or 20 thousand training points.  However, dlib comes with very fast SVM
    // tools which you can use instead at the cost of a little more setup.  In particular,
    // it is possible to use one of dlib's very fast linear SVM solvers to train a one
    // class SVM.  This is what we do below.  We will train on 115,000 points and it only
    // takes a few seconds with this tool!
    //
    // The first step is constructing a feature space that is appropriate for use with a
    // linear SVM.  In general, this is quite problem dependent.  However, if you have
    // under about a hundred dimensions in your vectors then it can often be quite
    // effective to use the empirical_kernel_map as we do below (see the
    // empirical_kernel_map documentation and example program for an extended discussion of
    // what it does).
    //
    // But putting the empirical_kernel_map aside, the most important step in turning a
    // linear SVM into a one-class SVM is the following.  We append a -1 value onto the end
    // of each feature vector and then tell the trainer to force the weight for this
    // feature to 1.  This means that if the linear SVM assigned all other weights a value
    // of 0 then the output from a learned decision function would always be -1.  The
    // second step is that we ask the SVM to label each training sample with +1.  This
    // causes the SVM to set the other feature weights such that the training samples have
    // positive outputs from the learned decision function.  But the starting bias for all
    // the points in the whole feature space is -1.  The result is that points outside our
    // training set will not be affected, so their outputs from the decision function will
    // remain close to -1.

    empirical_kernel_map<kernel_type> ekm;
    ekm.load(trainer.get_kernel(),samples);

    samples.clear();
    std::vector<double> labels;
    // make a vector with just 1 element in it equal to -1.
    sample_type bias(1);
    bias = -1;
    sample_type augmented;
    // This time sample 115,000 points from the sinc() function.
    for (double x = -15; x <= 8; x += 0.0002)
    {
        m(0) = x;
        m(1) = sinc(x);
        // Apply the empirical_kernel_map transformation and then append the -1 value
        augmented = join_cols(ekm.project(m), bias);
        samples.push_back(augmented);
        labels.push_back(+1);
    }
    cout << "samples.size(): "<< samples.size() << endl;

    // The svm_c_linear_dcd_trainer is a very fast SVM solver which only works with the
    // linear_kernel.  It has the nice feature of supporting this "force_last_weight_to_1"
    // mode we discussed above.
    svm_c_linear_dcd_trainer<linear_kernel<sample_type> > linear_trainer;
    linear_trainer.force_last_weight_to_1(true);

    // Train the SVM
    decision_function<linear_kernel<sample_type> > df2 = linear_trainer.train(samples, labels);

    // Here we test it as before, again we note that points from the sinc() curve have
    // large outputs from the decision function.  Note also that we must remember to
    // transform the points in exactly the same manner used to construct the training set
    // before giving them to df2() or the code will not work.
    cout << "Points that are on the sinc function:\n";
    m(0) = -1.5; m(1) = sinc(m(0)); cout << "   " << df2(join_cols(ekm.project(m),bias)) << endl;
    m(0) = -1.5; m(1) = sinc(m(0)); cout << "   " << df2(join_cols(ekm.project(m),bias)) << endl;
    m(0) = -0;   m(1) = sinc(m(0)); cout << "   " << df2(join_cols(ekm.project(m),bias)) << endl;
    m(0) = -0.5; m(1) = sinc(m(0)); cout << "   " << df2(join_cols(ekm.project(m),bias)) << endl;
    m(0) = -4.1; m(1) = sinc(m(0)); cout << "   " << df2(join_cols(ekm.project(m),bias)) << endl;
    m(0) = -1.5; m(1) = sinc(m(0)); cout << "   " << df2(join_cols(ekm.project(m),bias)) << endl;
    m(0) = -0.5; m(1) = sinc(m(0)); cout << "   " << df2(join_cols(ekm.project(m),bias)) << endl;

    cout << endl;
    // Again, we see here that points not on the sinc() function have small values.
    cout << "Points that are NOT on the sinc function:\n";
    m(0) = -1.5; m(1) = sinc(m(0))+4;   cout << "   " << df2(join_cols(ekm.project(m),bias)) << endl;
    m(0) = -1.5; m(1) = sinc(m(0))+3;   cout << "   " << df2(join_cols(ekm.project(m),bias)) << endl;
    m(0) = -0;   m(1) = -sinc(m(0));    cout << "   " << df2(join_cols(ekm.project(m),bias)) << endl;
    m(0) = -0.5; m(1) = -sinc(m(0));    cout << "   " << df2(join_cols(ekm.project(m),bias)) << endl;
    m(0) = -4.1; m(1) = sinc(m(0))+2;   cout << "   " << df2(join_cols(ekm.project(m),bias)) << endl;
    m(0) = -1.5; m(1) = sinc(m(0))+0.9; cout << "   " << df2(join_cols(ekm.project(m),bias)) << endl;
    m(0) = -0.5; m(1) = sinc(m(0))+1;   cout << "   " << df2(join_cols(ekm.project(m),bias)) << endl;

    // The output is as follows:
    /*
    Points that are on the sinc function:
        1.00454
        1.00454
        1.00022
        1.00007
        1.00371
        1.00454
        1.00007

    Points that are NOT on the sinc function:
        -1
        -1
        -1
        -1
        -0.999998
        -0.781231
        -0.96242
    */

    // Finally, to help you visualize what is happening here we are going to plot the
    // response of the one-class classifiers on the screen.  The code below creates two
    // heatmap images which show the response.  In these images you can clearly see where
    // the algorithms have identified the sinc() curve.  The hotter the pixel looks, the
    // larger the value coming out of the decision function and therefore the more "normal"
    // it is according to the classifier.
    const long size = 500;
    array2d<double> img1(size,size);
    array2d<double> img2(size,size);
    for (long r = 0; r < img1.nr(); ++r)
    {
        for (long c = 0; c < img1.nc(); ++c)
        {
            double x = 30.0*c/size - 19;
            double y = 8.0*r/size - 4;
            m(0) = x;
            m(1) = y;
            img1[r][c] = df(m);
            img2[r][c] = df2(join_cols(ekm.project(m),bias));
        }
    }
    image_window win1(heatmap(img1), "svm_one_class_trainer");
    image_window win2(heatmap(img2), "svm_c_linear_dcd_trainer");
    win1.wait_until_closed();


dlib C++ Library - svm_pegasos_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example illustrating the use of the dlib C++ library's
    implementation of the pegasos algorithm for online training of support
    vector machines.

    This example creates a simple binary classification problem and shows
    you how to train a support vector machine on that data.

    The data used in this example will be 2 dimensional data and will
    come from a distribution where points with a distance less than 10
    from the origin are labeled +1 and all other points are labeled
    as -1.

*/

#include <iostream>
#include <ctime>
#include <vector>
#include <dlib/svm.h>

using namespace std;
using namespace dlib;

int main()
{
    // The svm functions use column vectors to contain a lot of the data on which they
    // operate. So the first thing we do here is declare a convenient typedef.

    // This typedef declares a matrix with 2 rows and 1 column.  It will be the
    // object that contains each of our 2 dimensional samples.   (Note that if you wanted
    // more than 2 features in this vector you can simply change the 2 to something else.
    // Or if you don't know how many features you want until runtime then you can put a 0
    // here and use the matrix.set_size() member function)
    typedef matrix<double, 2, 1> sample_type;

    // This is a typedef for the type of kernel we are going to use in this example.
    // In this case I have selected the radial basis kernel that can operate on our
    // 2D sample_type objects
    typedef radial_basis_kernel<sample_type> kernel_type;

    // Here we create an instance of the pegasos svm trainer object we will be using.
    svm_pegasos<kernel_type> trainer;
    // Here we setup the parameters to this object.  See the dlib documentation for a
    // description of what these parameters are.
    trainer.set_lambda(0.00001);
    trainer.set_kernel(kernel_type(0.005));

    // Set the maximum number of support vectors we want the trainer object to use
    // in representing the decision function it is going to learn.  In general,
    // supplying a bigger number here will only ever give you a more accurate
    // answer.  However, giving a smaller number will make the algorithm run
    // faster and decision rules that involve fewer support vectors also take
    // less time to evaluate.
    trainer.set_max_num_sv(10);

    std::vector<sample_type> samples;
    std::vector<double> labels;

    // make an instance of a sample matrix so we can use it below
    sample_type sample, center;

    center = 20, 20;

    // Now let's go into a loop and randomly generate 1000 samples.
    srand(time(0));
    for (int i = 0; i < 10000; ++i)
    {
        // Make a random sample vector.
        sample = randm(2,1)*40 - center;

        // Now if that random vector is less than 10 units from the origin then it is in
        // the +1 class.
        if (length(sample) <= 10)
        {
            // let the svm_pegasos learn about this sample
            trainer.train(sample,+1);

            // save this sample so we can use it with the batch training examples below
            samples.push_back(sample);
            labels.push_back(+1);
        }
        else
        {
            // let the svm_pegasos learn about this sample
            trainer.train(sample,-1);

            // save this sample so we can use it with the batch training examples below
            samples.push_back(sample);
            labels.push_back(-1);
        }
    }

    // Now we have trained our SVM.  Let's see how well it did.
    // Each of these statements prints out the output of the SVM given a particular sample.
    // The SVM outputs a number > 0 if a sample is predicted to be in the +1 class and < 0
    // if a sample is predicted to be in the -1 class.

    sample(0) = 3.123;
    sample(1) = 4;
    cout << "This is a +1 example, its SVM output is: " << trainer(sample) << endl;

    sample(0) = 13.123;
    sample(1) = 9.3545;
    cout << "This is a -1 example, its SVM output is: " << trainer(sample) << endl;

    sample(0) = 13.123;
    sample(1) = 0;
    cout << "This is a -1 example, its SVM output is: " << trainer(sample) << endl;

    // The previous part of this example program showed you how to perform online training
    // with the pegasos algorithm.  But it is often the case that you have a dataset and you
    // just want to perform batch learning on that dataset and get the resulting decision
    // function.  To support this the dlib library provides functions for converting an online
    // training object like svm_pegasos into a batch training object.

    // First let's clear out anything in the trainer object.
    trainer.clear();

    // Now to begin with, you might want to compute the cross validation score of a trainer object
    // on your data.  To do this you should use the batch_cached() function to convert the svm_pegasos object
    // into a batch training object.  Note that the second argument to batch_cached() is the minimum
    // learning rate the trainer object must report for the batch_cached() function to consider training
    // complete.  So smaller values of this parameter cause training to take longer but may result
    // in a more accurate solution.
    // Here we perform 4-fold cross validation and print the results
    cout << "cross validation: " << cross_validate_trainer(batch_cached(trainer,0.1), samples, labels, 4);

    // Here is an example of creating a decision function.  Note that we have used the verbose_batch_cached()
    // function instead of batch_cached() as above.  They do the same things except verbose_batch_cached() will
    // print status messages to standard output while training is under way.
    decision_function<kernel_type> df = verbose_batch_cached(trainer,0.1).train(samples, labels);

    // At this point we have obtained a decision function from the above batch mode training.
    // Now we can use it on some test samples exactly as we did above.

    sample(0) = 3.123;
    sample(1) = 4;
    cout << "This is a +1 example, its SVM output is: " << df(sample) << endl;

    sample(0) = 13.123;
    sample(1) = 9.3545;
    cout << "This is a -1 example, its SVM output is: " << df(sample) << endl;

    sample(0) = 13.123;
    sample(1) = 0;
    cout << "This is a -1 example, its SVM output is: " << df(sample) << endl;


dlib C++ Library - optimization_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example illustrating the use the general purpose non-linear
    optimization routines from the dlib C++ Library.

    The library provides implementations of the conjugate gradient,  BFGS,
    L-BFGS, and BOBYQA optimization algorithms.  These algorithms allow you to
    find the minimum of a function of many input variables.  This example walks
    though a few of the ways you might put these routines to use.

*/

#include <dlib/optimization.h>
#include <iostream>

using namespace std;
using namespace dlib;

// ----------------------------------------------------------------------------------------

// In dlib, the general purpose solvers optimize functions that take a column
// vector as input and return a double.  So here we make a typedef for a
// variable length column vector of doubles.  This is the type we will use to
// represent the input to our objective functions which we will be minimizing.
typedef matrix<double,0,1> column_vector;

// ----------------------------------------------------------------------------------------
// Below we create a few functions.  When you get down into main() you will see that
// we can use the optimization algorithms to find the minimums of these functions.
// ----------------------------------------------------------------------------------------

double rosen (const column_vector& m)
/*
    This function computes what is known as Rosenbrock's function.  It is
    a function of two input variables and has a global minimum at (1,1).
    So when we use this function to test out the optimization algorithms
    we will see that the minimum found is indeed at the point (1,1).
*/
{
    const double x = m(0);
    const double y = m(1);

    // compute Rosenbrock's function and return the result
    return 100.0*pow(y - x*x,2) + pow(1 - x,2);
}

// This is a helper function used while optimizing the rosen() function.
const column_vector rosen_derivative (const column_vector& m)
/*!
    ensures
        - returns the gradient vector for the rosen function
!*/
{
    const double x = m(0);
    const double y = m(1);

    // make us a column vector of length 2
    column_vector 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;
}

// This function computes the Hessian matrix for the rosen() fuction.  This is
// the matrix of second derivatives.
matrix<double> rosen_hessian (const column_vector& m)
{
    const double x = m(0);
    const double y = m(1);

    matrix<double> res(2,2);

    // now compute the second derivatives
    res(0,0) = 1200*x*x - 400*y + 2; // second derivative with respect to x
    res(1,0) = res(0,1) = -400*x;   // derivative with respect to x and y
    res(1,1) = 200;                 // second derivative with respect to y
    return res;
}

// ----------------------------------------------------------------------------------------

class test_function
{
    /*
        This object is an example of what is known as a "function object" in C++.
        It is simply an object with an overloaded operator().  This means it can
        be used in a way that is similar to a normal C function.  The interesting
        thing about this sort of function is that it can have state.

        In this example, our test_function object contains a column_vector
        as its state and it computes the mean squared error between this
        stored column_vector and the arguments to its operator() function.

        This is a very simple function, however, in general you could compute
        any function you wanted here.  An example of a typical use would be
        to find the parameters of some regression function that minimized
        the mean squared error on a set of data.  In this case the arguments
        to the operator() function would be the parameters of your regression
        function.  You would loop over all your data samples and compute the output
        of the regression function for each data sample given the parameters and
        return a measure of the total error.   The dlib optimization functions
        could then be used to find the parameters that minimized the error.
    */
public:

    test_function (
        const column_vector& input
    )
    {
        target = input;
    }

    double operator() ( const column_vector& arg) const
    {
        // return the mean squared error between the target vector and the input vector
        return mean(squared(target-arg));
    }

private:
    column_vector target;
};

// ----------------------------------------------------------------------------------------

class rosen_model
{
    /*!
        This object is a "function model" which can be used with the
        find_min_trust_region() routine.
    !*/

public:
    typedef ::column_vector column_vector;
    typedef matrix<double> general_matrix;

    double operator() (
        const column_vector& x
    ) const { return rosen(x); }

    void get_derivative_and_hessian (
        const column_vector& x,
        column_vector& der,
        general_matrix& hess
    ) const
    {
        der = rosen_derivative(x);
        hess = rosen_hessian(x);
    }
};

// ----------------------------------------------------------------------------------------

int main()
{
    try
    {
        // make a column vector of length 2
        column_vector starting_point(2);

        // Set the starting point to (4,8).  This is the point the optimization algorithm
        // will start out from and it will move it closer and closer to the function's
        // minimum point.   So generally you want to try and compute a good guess that is
        // somewhat near the actual optimum value.
        starting_point = 4, 8;

        // The first example below finds the minimum of the rosen() function and uses the
        // analytical derivative computed by rosen_derivative().  Since it is very easy to
        // make a mistake while coding a function like rosen_derivative() it is a good idea
        // to compare your derivative function against a numerical approximation and see if
        // the results are similar.  If they are very different then you probably made a
        // mistake.  So the first thing we do is compare the results at a test point:
        cout << "Difference between analytic derivative and numerical approximation of derivative: "
              << length(derivative(rosen)(starting_point) - rosen_derivative(starting_point)) << endl;

        cout << "Find the minimum of the rosen function()" << endl;
        // Now we use the find_min() function to find the minimum point.  The first argument
        // to this routine is the search strategy we want to use.  The second argument is the
        // stopping strategy.  Below I'm using the objective_delta_stop_strategy which just
        // says that the search should stop when the change in the function being optimized
        // is small enough.

        // The other arguments to find_min() are the function to be minimized, its derivative,
        // then the starting point, and the last is an acceptable minimum value of the rosen()
        // function.  That is, if the algorithm finds any inputs to rosen() that gives an output
        // value <= -1 then it will stop immediately.  Usually you supply a number smaller than
        // the actual global minimum.  So since the smallest output of the rosen function is 0
        // we just put -1 here which effectively causes this last argument to be disregarded.

        find_min(bfgs_search_strategy(),  // Use BFGS search algorithm
                 objective_delta_stop_strategy(1e-7), // Stop when the change in rosen() is less than 1e-7
                 rosen, rosen_derivative, starting_point, -1);
        // Once the function ends the starting_point vector will contain the optimum point
        // of (1,1).
        cout << "rosen solution:\n" << starting_point << endl;

        // Now let's try doing it again with a different starting point and the version
        // of find_min() that doesn't require you to supply a derivative function.
        // This version will compute a numerical approximation of the derivative since
        // we didn't supply one to it.
        starting_point = -94, 5.2;
        find_min_using_approximate_derivatives(bfgs_search_strategy(),
                                               objective_delta_stop_strategy(1e-7),
                                               rosen, starting_point, -1);
        // Again the correct minimum point is found and stored in starting_point
        cout << "rosen solution:\n" << starting_point << endl;

        // Here we repeat the same thing as above but this time using the L-BFGS
        // algorithm.  L-BFGS is very similar to the BFGS algorithm, however, BFGS
        // uses O(N^2) memory where N is the size of the starting_point vector.
        // The L-BFGS algorithm however uses only O(N) memory.  So if you have a
        // function of a huge number of variables the L-BFGS algorithm is probably
        // a better choice.
        starting_point = 0.8, 1.3;
        find_min(lbfgs_search_strategy(10),  // The 10 here is basically a measure of how much memory L-BFGS will use.
                 objective_delta_stop_strategy(1e-7).be_verbose(),  // Adding be_verbose() causes a message to be
                                                                    // printed for each iteration of optimization.
                 rosen, rosen_derivative, starting_point, -1);

        cout << endl << "rosen solution: \n" << starting_point << endl;

        starting_point = -94, 5.2;
        find_min_using_approximate_derivatives(lbfgs_search_strategy(10),
                                               objective_delta_stop_strategy(1e-7),
                                               rosen, starting_point, -1);
        cout << "rosen solution: \n"<< starting_point << endl;

        // dlib also supports solving functions subject to bounds constraints on
        // the variables.  So for example, if you wanted to find the minimizer
        // of the rosen function where both input variables were in the range
        // 0.1 to 0.8 you would do it like this:
        starting_point = 0.1, 0.1; // Start with a valid point inside the constraint box.
        find_min_box_constrained(lbfgs_search_strategy(10),
                                 objective_delta_stop_strategy(1e-9),
                                 rosen, rosen_derivative, starting_point, 0.1, 0.8);
        // Here we put the same [0.1 0.8] range constraint on each variable, however, you
        // can put different bounds on each variable by passing in column vectors of
        // constraints for the last two arguments rather than scalars.

        cout << endl << "constrained rosen solution: \n" << starting_point << endl;

        // You can also use an approximate derivative like so:
        starting_point = 0.1, 0.1;
        find_min_box_constrained(bfgs_search_strategy(),
                                 objective_delta_stop_strategy(1e-9),
                                 rosen, derivative(rosen), starting_point, 0.1, 0.8);
        cout << endl << "constrained rosen solution: \n" << starting_point << endl;

        // In many cases, it is useful if we also provide second derivative information
        // to the optimizers.  Two examples of how we can do that are shown below.
        starting_point = 0.8, 1.3;
        find_min(newton_search_strategy(rosen_hessian),
                 objective_delta_stop_strategy(1e-7),
                 rosen,
                 rosen_derivative,
                 starting_point,
                 -1);
        cout << "rosen solution: \n"<< starting_point << endl;

        // We can also use find_min_trust_region(), which is also a method which uses
        // second derivatives.  For some kinds of non-convex function it may be more
        // reliable than using a newton_search_strategy with find_min().
        starting_point = 0.8, 1.3;
        find_min_trust_region(objective_delta_stop_strategy(1e-7),
            rosen_model(),
            starting_point,
            10 // initial trust region radius
        );
        cout << "rosen solution: \n"<< starting_point << endl;

        // Now let's look at using the test_function object with the optimization
        // functions.
        cout << "\nFind the minimum of the test_function" << endl;

        column_vector target(4);
        starting_point.set_size(4);

        // This variable will be used as the target of the test_function.   So,
        // our simple test_function object will have a global minimum at the
        // point given by the target.  We will then use the optimization
        // routines to find this minimum value.
        target = 3, 5, 1, 7;

        // set the starting point far from the global minimum
        starting_point = 1,2,3,4;
        find_min_using_approximate_derivatives(bfgs_search_strategy(),
                                               objective_delta_stop_strategy(1e-7),
                                               test_function(target), starting_point, -1);
        // At this point the correct value of (3,5,1,7) should be found and stored in starting_point
        cout << "test_function solution:\n" << starting_point << endl;

        // Now let's try it again with the conjugate gradient algorithm.
        starting_point = -4,5,99,3;
        find_min_using_approximate_derivatives(cg_search_strategy(),
                                               objective_delta_stop_strategy(1e-7),
                                               test_function(target), starting_point, -1);
        cout << "test_function solution:\n" << starting_point << endl;

        // Finally, let's try the BOBYQA algorithm.  This is a technique specially
        // designed to minimize a function in the absence of derivative information.
        // Generally speaking, it is the method of choice if derivatives are not available.
        starting_point = -4,5,99,3;
        find_min_bobyqa(test_function(target),
                        starting_point,
                        9,    // number of interpolation points
                        uniform_matrix<double>(4,1, -1e100),  // lower bound constraint
                        uniform_matrix<double>(4,1, 1e100),   // upper bound constraint
                        10,    // initial trust region radius
                        1e-6,  // stopping trust region radius
                        100    // max number of objective function evaluations
        );
        cout << "test_function solution:\n" << starting_point << endl;

    }
    catch (std::exception& e)
    {
        cout << e.what() << endl;


dlib C++ Library - parallel_for_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example illustrating the use of the parallel for loop tools from the dlib
    C++ Library.

    Normally, a for loop executes the body of the loop in a serial manner.  This means
    that, for example, if it takes 1 second to execute the body of the loop and the body
    needs to execute 10 times then it will take 10 seconds to execute the entire loop.
    However, on modern multi-core computers we have the opportunity to speed this up by
    executing multiple steps of a for loop in parallel.  This example program will walk you
    though a few examples showing how to do just that.
*/

#include <dlib/threads.h>
#include <dlib/misc_api.h>  // for dlib::sleep
#include <vector>
#include <iostream>

using namespace dlib;
using namespace std;

// ----------------------------------------------------------------------------------------

void print(const std::vector<int>& vect)
{
    for (unsigned long i = 0; i < vect.size(); ++i)
    {
        cout << vect[i] << endl;
    }
    cout << "\n**************************************\n";
}

// ----------------------------------------------------------------------------------------

void example_using_regular_non_parallel_loops();
void example_using_lambda_functions();
void example_without_using_lambda_functions();

// ----------------------------------------------------------------------------------------

int main()
{
    // We have 3 examples, each contained in a separate function.  Each example performs
    // exactly the same computation, however, the second two examples do so using parallel
    // for loops.  So the first example is here to show you what we are doing in terms of
    // classical non-parallel for loops.  Then the next two examples will illustrate two
    // ways to parallelize for loops in C++.  The first, and simplest way, uses C++11
    // lambda functions.  However, since lambda functions are a relatively recent addition
    // to C++ we also show how to write parallel for loops without using lambda functions.
    // This way, users who don't yet have access to a current C++ compiler can learn to
    // write parallel for loops as well.

    example_using_regular_non_parallel_loops();
    example_using_lambda_functions();
    example_without_using_lambda_functions();
}

// ----------------------------------------------------------------------------------------

void example_using_regular_non_parallel_loops()
{
    cout << "\nExample using regular non-parallel for loops\n" << endl;

    std::vector<int> vect;

    // put 10 elements into vect which are all equal to -1
    vect.assign(10, -1);

    // Now set each element equal to its index value.  We put a sleep call in here so that
    // when we run the same thing with a parallel for loop later on you will be able to
    // observe the speedup.
    for (unsigned long i = 0; i < vect.size(); ++i)
    {
        vect[i] = i;
        dlib::sleep(1000); // sleep for 1 second
    }
    print(vect);

    // Assign only part of the elements in vect.
    vect.assign(10, -1);
    for (unsigned long i = 1; i < 5; ++i)
    {
        vect[i] = i;
        dlib::sleep(1000);
    }
    print(vect);

    // Sum all element sin vect.
    int sum = 0;
    vect.assign(10, 2);
    for (unsigned long i = 0; i < vect.size(); ++i)
    {
        dlib::sleep(1000);
        sum += vect[i];
    }

    cout << "sum: "<< sum << endl;
}

// ----------------------------------------------------------------------------------------

void example_using_lambda_functions()
{
// Change the next line to #if 1 if your compiler supports the new C++11 lambda functions.
#if 0
    cout << "\nExample using parallel for loops\n" << endl;

    // This variable should be set to the number of processing cores on your computer since
    // it determines the amount of parallelism in the for loop.
    const unsigned long num_threads = 10;

    std::vector<int> vect;

    vect.assign(10, -1);
    parallel_for(num_threads, 0, vect.size(), [&](long i){
        // The i variable is the loop counter as in a normal for loop.  So we simply need
        // to place the body of the for loop right here and we get the same behavior.  The
        // range for the for loop is determined by the 2nd and 3rd arguments to
        // parallel_for().
        vect[i] = i;
        dlib::sleep(1000);
    });
    print(vect);

    // Assign only part of the elements in vect.
    vect.assign(10, -1);
    parallel_for(num_threads, 1, 5, [&](long i){
        vect[i] = i;
        dlib::sleep(1000);
    });
    print(vect);

    // Note that things become a little more complex if the loop bodies are not totally
    // independent.  In the first two cases each iteration of the loop touched different
    // memory locations, so we didn't need to use any kind of thread synchronization.
    // However, in the summing loop we need to add some synchronization to protect the sum
    // variable.  This is easily accomplished by creating a mutex and locking it before
    // adding to sum.  More generally, you must ensure that the bodies of your parallel for
    // loops are thread safe using whatever means is appropriate for your code.  Since a
    // parallel for loop is implemented using threads, all the usual techniques for
    // ensuring thread safety can be used.
    int sum = 0;
    dlib::mutex m;
    vect.assign(10, 2);
    parallel_for(num_threads, 0, vect.size(), [&](long i){
        // The sleep statements still execute in parallel.
        dlib::sleep(1000);

        // Lock the m mutex.  The auto_mutex will automatically unlock at the closing }.
        // This will ensure only one thread can execute the sum += vect[i] statement at
        // a time.
        auto_mutex lock(m);
        sum += vect[i];
    });

    cout << "sum: "<< sum << endl;

#endif
}

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//    The rest of this example program shows how to create parallel for loops without
//    using lambda functions.  So the first thing we do is explicitly create function
//    objects equivalent to the lambda functions we used.  Then we call parallel_for()
//    as done above.
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

struct function_object
{
    function_object( std::vector<int>& vect_ ) : vect(vect_) {}

    std::vector<int>& vect;

    void operator() (long i) const
    {
        vect[i] = i;
        dlib::sleep(1000);
    }
};

struct function_object_sum
{
    function_object_sum( const std::vector<int>& vect_, int& sum_ ) : vect(vect_), sum(sum_) {}

    const std::vector<int>& vect;
    int& sum;
    dlib::mutex m;

    void operator() (long i) const
    {
        dlib::sleep(1000);
        auto_mutex lock(m);
        sum += vect[i];
    }
};

void example_without_using_lambda_functions()
{
    // Again, note that this function does exactly the same thing as
    // example_using_regular_non_parallel_loops() and example_using_lambda_functions().

    cout << "\nExample using parallel for loops and no lambda functions\n" << endl;

    const unsigned long num_threads = 10;
    std::vector<int> vect;

    vect.assign(10, -1);
    parallel_for(num_threads, 0, vect.size(), function_object(vect));
    print(vect);

    vect.assign(10, -1);
    parallel_for(num_threads, 1, 5, function_object(vect));
    print(vect);

    int sum = 0;
    vect.assign(10, 2);
    function_object_sum funct(vect, sum);
    parallel_for(num_threads, 0, vect.size(), funct);
    cout << "sum: " << sum << endl;
}

// ----------------------------------------------------------------------------------------


dlib C++ Library - pipe_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt

/*
    This is an example illustrating the use of the threading API and pipe object
    from the dlib C++ Library.

    In this example we will create three threads that will read "jobs" off the end of
    a pipe object and process them.  It shows you how you can use the pipe object
    to communicate between threads.

    Example program output:
    0 INFO  [0] pipe_example: Add job 0 to pipe
    0 INFO  [0] pipe_example: Add job 1 to pipe
    0 INFO  [0] pipe_example: Add job 2 to pipe
    0 INFO  [0] pipe_example: Add job 3 to pipe
    0 INFO  [0] pipe_example: Add job 4 to pipe
    0 INFO  [0] pipe_example: Add job 5 to pipe
    0 INFO  [1] pipe_example: got job 0
    0 INFO  [0] pipe_example: Add job 6 to pipe
    0 INFO  [2] pipe_example: got job 1
    0 INFO  [0] pipe_example: Add job 7 to pipe
    0 INFO  [3] pipe_example: got job 2
  103 INFO  [0] pipe_example: Add job 8 to pipe
  103 INFO  [1] pipe_example: got job 3
  103 INFO  [0] pipe_example: Add job 9 to pipe
  103 INFO  [2] pipe_example: got job 4
  103 INFO  [0] pipe_example: Add job 10 to pipe
  103 INFO  [3] pipe_example: got job 5
  207 INFO  [0] pipe_example: Add job 11 to pipe
  207 INFO  [1] pipe_example: got job 6
  207 INFO  [0] pipe_example: Add job 12 to pipe
  207 INFO  [2] pipe_example: got job 7
  207 INFO  [0] pipe_example: Add job 13 to pipe
  207 INFO  [3] pipe_example: got job 8
  311 INFO  [1] pipe_example: got job 9
  311 INFO  [2] pipe_example: got job 10
  311 INFO  [3] pipe_example: got job 11
  311 INFO  [0] pipe_example: Add job 14 to pipe
  311 INFO  [0] pipe_example: main ending
  311 INFO  [0] pipe_example: destructing pipe object: wait for job_pipe to be empty
  415 INFO  [1] pipe_example: got job 12
  415 INFO  [2] pipe_example: got job 13
  415 INFO  [3] pipe_example: got job 14
  415 INFO  [0] pipe_example: destructing pipe object: job_pipe is empty
  519 INFO  [1] pipe_example: thread ending
  519 INFO  [2] pipe_example: thread ending
  519 INFO  [3] pipe_example: thread ending
  519 INFO  [0] pipe_example: destructing pipe object: all threads have ended

  The first column is the number of milliseconds since program start, the second
  column is the logging level, the third column is the thread id, and the rest
  is the log message.
*/

#include <dlib/threads.h>
#include <dlib/misc_api.h>  // for dlib::sleep
#include <dlib/pipe.h>
#include <dlib/logger.h>

using namespace dlib;

struct job
{
    /*
        This object represents the jobs we are going to send out to our threads.
    */
    int id;
};

dlib::logger dlog("pipe_example");

// ----------------------------------------------------------------------------------------

class pipe_example : private multithreaded_object
{
public:
    pipe_example(
    ) :
        job_pipe(4) // This 4 here is the size of our job_pipe.  The significance is that
                    // if you try to enqueue more than 4 jobs onto the pipe then enqueue() will
                    // block until there is room.
    {
        // register 3 threads
        register_thread(*this,&pipe_example::thread);
        register_thread(*this,&pipe_example::thread);
        register_thread(*this,&pipe_example::thread);

        // start the 3 threads we registered above
        start();
    }

    ~pipe_example (
    )
    {
        dlog << LINFO << "destructing pipe object: wait for job_pipe to be empty";
        // wait for all the jobs to be processed
        job_pipe.wait_until_empty();

        dlog << LINFO << "destructing pipe object: job_pipe is empty";

        // now disable the job_pipe.  doing this will cause all calls to
        // job_pipe.dequeue() to return false so our threads will terminate
        job_pipe.disable();

        // now block until all the threads have terminated
        wait();
        dlog << LINFO << "destructing pipe object: all threads have ended";
    }

    // Here we declare our pipe object.  It will contain our job objects.
    // There are only two requirements on the type of objects you can use in a
    // pipe, first they must have a default constructor and second they must
    // be swappable by a global swap().
    dlib::pipe<job> job_pipe;

private:
    void thread ()
    {
        job j;
        // Here we loop on jobs from the job_pipe.
        while (job_pipe.dequeue(j))
        {
            // process our job j in some way.
            dlog << LINFO << "got job " << j.id;

            // sleep for 0.1 seconds
            dlib::sleep(100);
        }
        dlog << LINFO << "thread ending";
    }

};

// ----------------------------------------------------------------------------------------

int main()
{
    // Set the dlog object so that it logs everything.
    dlog.set_level(LALL);

    pipe_example pe;

    for (int i = 0; i < 15; ++i)
    {
        dlog << LINFO << "Add job " << i << " to pipe";
        job j;
        j.id = i;

        // Add this job to the pipe.  One of our three threads will get it and process it.
        // It should also be pointed out that the enqueue() function uses the global
        // swap function to move jobs into the pipe.  This means that it modifies the
        // jobs we are passing in to it.  This allows you to implement a fast swap
        // operator for your jobs.  For example, std::vector objects have a global
        // swap and it can execute in constant time by just swapping pointers inside
        // std::vector.  This means that the dlib::pipe is effectively a zero-copy
        // message passing system if you setup global swap for your jobs.
        pe.job_pipe.enqueue(j);
    }

    dlog << LINFO << "main ending";

    // the main function won't really terminate here.  It will call the destructor for pe
    // which will block until all the jobs have been processed.
}

// ----------------------------------------------------------------------------------------


dlib C++ Library - pipe_ex_2.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt

/*
    This is an example showing how to use the type_safe_union and pipe object from
    from the dlib C++ Library to send messages between threads.

    In this example we will create a class with a single thread in it.  This thread
    will receive messages from a pipe object and simply print them to the screen.
    The interesting thing about this example is that it shows how to use a pipe and
    type_safe_union to create a message channel between threads that can send many
    different types of objects in a type safe manner.

    Program output:
        got a float: 4.567
        got a string: string message
        got an int: 7
        got a string: yet another string message
*/

#include <dlib/threads.h>
#include <dlib/pipe.h>
#include <dlib/type_safe_union.h>
#include <iostream>

using namespace dlib;
using namespace std;

// ----------------------------------------------------------------------------------------

typedef type_safe_union<int, float, std::string> tsu_type;
/*  This is a typedef for the type_safe_union we will be using in this example.
    This type_safe_union object is a type-safe analogue of a union declared as follows:
        union our_union_type
        {
            int a;
            float b;
            std::string c;
        };

    Note that the above union isn't actually valid C++ code because it contains a
    non-POD type.  That is, you can't put a std::string or any non-trivial
    C++ class in a union.   The type_safe_union, however, enables you to store non-POD
    types such as the std::string.

*/

// ----------------------------------------------------------------------------------------

class pipe_example : private threaded_object
{
public:
    pipe_example(
    ) :
        message_pipe(4) // This 4 here is the size of our message_pipe.  The significance is that
                    // if you try to enqueue more than 4 messages onto the pipe then enqueue() will
                    // block until there is room.
    {
        // start the thread
        start();
    }

    ~pipe_example (
    )
    {
        // wait for all the messages to be processed
        message_pipe.wait_until_empty();

        // Now disable the message_pipe.  Doing this will cause all calls to
        // message_pipe.dequeue() to return false so our thread will terminate
        message_pipe.disable();

        // now block until our thread has terminated
        wait();
    }

    // Here we declare our pipe object.  It will contain our messages.
    dlib::pipe<tsu_type> message_pipe;

private:

    // When we call apply_to_contents() below these are the
    // functions which get called.
    void operator() (int val)
    {
        cout << "got an int: " << val << endl;
    }

    void operator() (float val)
    {
        cout << "got a float: " << val << endl;
    }

    void operator() (std::string val)
    {
        cout << "got a string: " << val << endl;
    }

    void thread ()
    {
        tsu_type msg;

        // Here we loop on messages from the message_pipe.
        while (message_pipe.dequeue(msg))
        {
            // Here we call the apply_to_contents() function on our type_safe_union.
            // It takes a function object and applies that function object
            // to the contents of the union.  In our case we have setup
            // the pipe_example class as our function object and so below we
            // tell the msg object to take whatever it contains and
            // call (*this)(contained_object);   So what happens here is
            // one of the three above functions gets called with the message
            // we just got.
            msg.apply_to_contents(*this);
        }
    }

    // Finally, note that since we declared the operator() member functions
    // private we need to declare the type_safe_union as a friend of this
    // class so that it will be able to call them.
    friend class type_safe_union<int, float, std::string>;

};

// ----------------------------------------------------------------------------------------

int main()
{
    pipe_example pe;

    // Make one of our type_safe_union objects
    tsu_type msg;

    // Treat our msg as a float and assign it 4.567
    msg.get<float>() = 4.567f;
    // Now put the message into the pipe
    pe.message_pipe.enqueue(msg);

    // Put a string into the pipe
    msg.get<std::string>() = "string message";
    pe.message_pipe.enqueue(msg);

    // And now an int
    msg.get<int>() = 7;
    pe.message_pipe.enqueue(msg);

    // And another string
    msg.get<std::string>() = "yet another string message";
    pe.message_pipe.enqueue(msg);

    // the main function won't really terminate here.  It will call the destructor for pe
    // which will block until all the messages have been processed.
}

// ----------------------------------------------------------------------------------------


dlib C++ Library - quantum_computing_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*
    This is an example illustrating the use of the quantum computing
    simulation classes from the dlib C++ Library.

    This example assumes you are familiar with quantum computing and
    Grover's search algorithm and Shor's 9 bit error correcting code
    in particular.   The example shows how to simulate both of these
    algorithms.

    The code to simulate Grover's algorithm is primarily here to show
    you how to make custom quantum gate objects.  The Shor ECC example
    is simpler and uses just the default gates that come with the
    library.

*/

#include <iostream>
#include <complex>
#include <ctime>
#include <dlib/quantum_computing.h>
#include <dlib/string.h>

using namespace std;
using namespace dlib;

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

// This declares a random number generator that we will be using below
dlib::rand rnd;

// ----------------------------------------------------------------------------------------

void shor_encode (
    quantum_register& reg
)
/*!
    requires
        - reg.num_bits() == 1
    ensures
        - #reg.num_bits() == 9
        - #reg == the Shor error coding of the input register
!*/
{
    DLIB_CASSERT(reg.num_bits() == 1,"");

    quantum_register zeros;
    zeros.set_num_bits(8);
    reg.append(zeros);

    using namespace dlib::quantum_gates;
    const gate<1> h = hadamard();
    const gate<1> i = noop();

    // Note that the expression (h,i) represents the tensor product of the 1 qubit
    // h gate with the 1 qubit i gate and larger versions of this expression
    // represent even bigger tensor products.  So as you see below, we make gates
    // big enough to apply to our quantum register by listing out all the gates we
    // want to go into the tensor product and then we just apply the resulting gate
    // to the quantum register.

    // Now apply the gates that constitute Shor's encoding to the input register.
    (cnot<3,0>(),i,i,i,i,i).apply_gate_to(reg);
    (cnot<6,0>(),i,i).apply_gate_to(reg);
    (h,i,i,h,i,i,h,i,i).apply_gate_to(reg);
    (cnot<1,0>(),i,cnot<1,0>(),i,cnot<1,0>(),i).apply_gate_to(reg);
    (cnot<2,0>(),cnot<2,0>(),cnot<2,0>()).apply_gate_to(reg);
}

// ----------------------------------------------------------------------------------------

void shor_decode (
    quantum_register& reg
)
/*!
    requires
        - reg.num_bits() == 9
    ensures
        - #reg.num_bits() == 1
        - #reg == the decoded qubit that was in the given input register
!*/
{
    DLIB_CASSERT(reg.num_bits() == 9,"");

    using namespace dlib::quantum_gates;
    const gate<1> h = hadamard();
    const gate<1> i = noop();

    // Now apply the gates that constitute Shor's decoding to the input register

    (cnot<2,0>(),cnot<2,0>(),cnot<2,0>()).apply_gate_to(reg);
    (cnot<1,0>(),i,cnot<1,0>(),i,cnot<1,0>(),i).apply_gate_to(reg);

    (toffoli<0,1,2>(),toffoli<0,1,2>(),toffoli<0,1,2>()).apply_gate_to(reg);

    (h,i,i,h,i,i,h,i,i).apply_gate_to(reg);

    (cnot<6,0>(),i,i).apply_gate_to(reg);
    (cnot<3,0>(),i,i,i,i,i).apply_gate_to(reg);
    (toffoli<0,3,6>(),i,i).apply_gate_to(reg);

    // Now that we have decoded the value we don't need the extra 8 bits any more so
    // remove them from the register.
    for (int i = 0; i < 8; ++i)
        reg.measure_and_remove_bit(0,rnd);
}

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

// This is the function we will use in Grover's search algorithm.  In this
// case the value we are searching for is 257.
bool is_key (unsigned long n)
{
    return n == 257;
}

// ----------------------------------------------------------------------------------------

template <int bits>
class uf_gate;

namespace dlib {
template <int bits>
struct gate_traits<uf_gate<bits> >
{
    static const long num_bits = bits;
    static const long dims = dlib::qc_helpers::exp_2_n<num_bits>::value;
};}

template <int bits>
class uf_gate : public gate_exp<uf_gate<bits> >
{
    /*!
        This gate represents the black box function in Grover's search algorithm.
        That is, it is the gate defined as follows:
            Uf|x>|y> = |x>|y XOR is_key(x)>

        See the documentation for the gate_exp object for the details regarding
        the compute_state_element() and operator() functions defined below.
    !*/
public:
    uf_gate() : gate_exp<uf_gate>(*this) {}

    static const long num_bits = gate_traits<uf_gate>::num_bits;
    static const long dims = gate_traits<uf_gate>::dims;

    const qc_scalar_type operator() (long r, long c) const
    {
        unsigned long output = c;
        // if the input control bit is set
        if (is_key(output>>1))
        {
            output = output^0x1;
        }

        if ((unsigned long)r == output)
            return 1;
        else
            return 0;
    }

    template <typename exp>
    qc_scalar_type compute_state_element (
        const matrix_exp<exp>& reg,
        long row_idx
    ) const
    {
        unsigned long output = row_idx;
        // if the input control bit is set
        if (is_key(output>>1))
        {
            output = output^0x1;
        }

        return reg(output);
    }
};

// ----------------------------------------------------------------------------------------

template <int bits>
class w_gate;

namespace dlib {
template <int bits>
struct gate_traits<w_gate<bits> >
{
    static const long num_bits = bits;
    static const long dims = dlib::qc_helpers::exp_2_n<num_bits>::value;
}; }

template <int bits>
class w_gate : public gate_exp<w_gate<bits> >
{
    /*!
        This is the W gate from the Grover algorithm
    !*/
public:

    w_gate() : gate_exp<w_gate>(*this) {}

    static const long num_bits = gate_traits<w_gate>::num_bits;
    static const long dims = gate_traits<w_gate>::dims;

    const qc_scalar_type operator() (long r, long c) const
    {
        qc_scalar_type res = 2.0/dims;
        if (r != c)
            return res;
        else
            return res - 1.0;
    }

    template <typename exp>
    qc_scalar_type compute_state_element (
        const matrix_exp<exp>& reg,
        long row_idx
    ) const
    {
        qc_scalar_type temp = sum(reg)*2.0/dims;
        // compute this value: temp = temp - reg(row_idx)*2.0/dims + reg(row_idx)*(2.0/dims - 1.0)
        temp = temp - reg(row_idx);

        return temp;
    }
};

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

int main()
{
    // seed the random number generator
    rnd.set_seed(cast_to_string(time(0)));

    // Pick out some of the gates we will be using below
    using namespace dlib::quantum_gates;
    const gate<1> h = quantum_gates::hadamard();
    const gate<1> z = quantum_gates::z();
    const gate<1> x = quantum_gates::x();
    const gate<1> i = quantum_gates::noop();

    quantum_register reg;

    // We will be doing the 12 qubit version of Grover's search algorithm.
    const int bits=12;
    reg.set_num_bits(bits);

    // set the quantum register to its initial state
    (i,i, i,i,i,i,i, i,i,i,i,x).apply_gate_to(reg);

    // Print out the starting bits
    cout << "starting bits: ";
    for (int i = reg.num_bits()-1; i >= 0; --i)
        cout << reg.probability_of_bit(i);
    cout << endl;

    // Now apply the Hadamard gate to all the input bits
    (h,h, h,h,h,h,h, h,h,h,h,h).apply_gate_to(reg);

    // Here we do the grover iteration
    for (int j = 0; j < 35; ++j)
    {
        (uf_gate<bits>()).apply_gate_to(reg);
        (w_gate<bits-1>(),i).apply_gate_to(reg);

        cout << j << " probability: bit 1 = " << reg.probability_of_bit(1) << ", bit 9 = " << reg.probability_of_bit(9) << endl;
    }

    cout << endl;

    // Print out the final probability of measuring a 1 for each of the bits
    for (int i = reg.num_bits()-1; i >= 1; --i)
        cout << "probability for bit " << i << " = " << reg.probability_of_bit(i) << endl;
    cout << endl;

    cout << "The value we want grover's search to find is 257 which means we should measure a bit pattern of 00100000001" << endl;
    cout << "Measured bits: ";
    // finally, measure all the bits and print out what they are.
    for (int i = reg.num_bits()-1; i >= 1; --i)
        cout << reg.measure_bit(i,rnd);
    cout << endl;

    // Now let's test out the Shor 9 bit encoding
    cout << "\n\n\n\nNow let's try playing around with Shor's 9bit error correcting code" << endl;

    // Reset the quantum register to contain a single bit
    reg.set_num_bits(1);
    // Set the state of this single qubit to some random mixture of the two computational bases
    reg.state_vector()(0) = qc_scalar_type(rnd.get_random_double(),rnd.get_random_double());
    reg.state_vector()(1) = qc_scalar_type(rnd.get_random_double(),rnd.get_random_double());
    // Make sure the state of the quantum register is a unit vector
    reg.state_vector() /= sqrt(sum(norm(reg.state_vector())));

    cout << "state: " << trans(reg.state_vector());

    shor_encode(reg);
    cout << "x bit corruption on bit 8" << endl;
    (x,i,i,i,i,i,i,i,i).apply_gate_to(reg); // mess up the high order bit
    shor_decode(reg); // try to decode the register

    cout << "state: " << trans(reg.state_vector());

    shor_encode(reg);
    cout << "x bit corruption on bit 1" << endl;
    (i,i,i,i,i,i,i,x,i).apply_gate_to(reg);
    shor_decode(reg);

    cout << "state: " << trans(reg.state_vector());

    shor_encode(reg);
    cout << "z bit corruption on bit 8" << endl;
    (z,i,i,i,i,i,i,i,i).apply_gate_to(reg);
    shor_decode(reg);

    cout << "state: " << trans(reg.state_vector());

    cout << "\nThe state of the input qubit survived all the corruptions in tact so the code works." << endl;


dlib C++ Library - queue_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example illustrating the use of the queue component (and
    to some degree the general idea behind most of the other container
    classes) from the dlib C++ Library.

    It loads a queue with 20 random numbers.  Then it uses the enumerable
    interface to print them all to the screen.  Then it sorts the numbers and
    prints them to the screen.
*/

#include <dlib/queue.h>
#include <iostream>
#include <iomanip>
#include <ctime>
#include <cstdlib>

// I'm picking the version of the queue that is kernel_2a extended by
// the queue sorting extension.   This is just a normal queue but with the
// added member function sort() which sorts the queue.
typedef dlib::queue<int>::sort_1b_c queue_of_int;

using namespace std;
using namespace dlib;

int main()
{
    queue_of_int q;

    // initialize rand()
    srand(time(0));

    for (int i = 0; i < 20; ++i)
    {
        int a = rand()&0xFF;

        // note that adding a to the queue "consumes" the value of a because
        // all container classes move values around by swapping them rather
        // than copying them.   So a is swapped into the queue which results
        // in a having an initial value for its type (for int types that value
        // is just some undefined value. )
        q.enqueue(a);

    }

    cout << "The contents of the queue are:\n";
    while (q.move_next())
        cout << q.element() << " ";

    cout << "\n\nNow we sort the queue and its contents are:\n";
    q.sort();  // note that we don't have to call q.reset() to put the enumerator
               // back at the start of the queue because calling sort() does
               // that automatically for us.  (In general, modifying a container
               // will reset the enumerator).
    while (q.move_next())
        cout << q.element() << " ";

    cout << "\n\nNow we remove the numbers from the queue:\n";
    while (q.size() > 0)
    {
        int a;
        q.dequeue(a);
        cout << a << " ";
    }

    cout << endl;


dlib C++ Library - rank_features_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example illustrating the use of the rank_features() function
    from the dlib C++ Library.

    This example creates a simple set of data and then shows
    you how to use the rank_features() function to find a good
    set of features (where "good" means the feature set will probably
    work well with a classification algorithm).

    The data used in this example will be 4 dimensional data and will
    come from a distribution where points with a distance less than 10
    from the origin are labeled +1 and all other points are labeled
    as -1.  Note that this data is conceptually 2 dimensional but we
    will add two extra features for the purpose of showing what
    the rank_features() function does.
*/

#include <iostream>
#include <dlib/svm.h>
#include <dlib/rand.h>
#include <vector>

using namespace std;
using namespace dlib;

int main()
{

    // This first typedef declares a matrix with 4 rows and 1 column.  It will be the
    // object that contains each of our 4 dimensional samples.
    typedef matrix<double, 4, 1> sample_type;

    // Now let's make some vector objects that can hold our samples
    std::vector<sample_type> samples;
    std::vector<double> labels;

    dlib::rand rnd;

    for (int x = -30; x <= 30; ++x)
    {
        for (int y = -30; y <= 30; ++y)
        {
            sample_type samp;

            // the first two features are just the (x,y) position of our points and so
            // we expect them to be good features since our two classes here are points
            // close to the origin and points far away from the origin.
            samp(0) = x;
            samp(1) = y;

            // This is a worthless feature since it is just random noise.  It should
            // be indicated as worthless by the rank_features() function below.
            samp(2) = rnd.get_random_double();

            // This is a version of the y feature that is corrupted by random noise.  It
            // should be ranked as less useful than features 0, and 1, but more useful
            // than the above feature.
            samp(3) = y*0.2 + (rnd.get_random_double()-0.5)*10;

            // add this sample into our vector of samples.
            samples.push_back(samp);

            // if this point is less than 15 from the origin then label it as a +1 class point.
            // otherwise it is a -1 class point
            if (sqrt((double)x*x + y*y) <= 15)
                labels.push_back(+1);
            else
                labels.push_back(-1);
        }
    }

    // Here we normalize all the samples by subtracting their mean and dividing by their standard deviation.
    // This is generally a good idea since it often heads off numerical stability problems and also
    // prevents one large feature from smothering others.
    const sample_type m(mean(mat(samples)));  // compute a mean vector
    const sample_type sd(reciprocal(stddev(mat(samples)))); // compute a standard deviation vector
    // now normalize each sample
    for (unsigned long i = 0; i < samples.size(); ++i)
        samples[i] = pointwise_multiply(samples[i] - m, sd);

    // This is another thing that is often good to do from a numerical stability point of view.
    // However, in our case it doesn't really matter.   It's just here to show you how to do it.
    randomize_samples(samples,labels);

    // This is a typedef for the type of kernel we are going to use in this example.
    // In this case I have selected the radial basis kernel that can operate on our
    // 4D sample_type objects.  In general, I would suggest using the same kernel for
    // classification and feature ranking.
    typedef radial_basis_kernel<sample_type> kernel_type;

    // The radial_basis_kernel has a parameter called gamma that we need to set.  Generally,
    // you should try the same gamma that you are using for training.  But if you don't
    // have a particular gamma in mind then you can use the following function to
    // find a reasonable default gamma for your data.  Another reasonable way to pick a gamma
    // is often to use 1.0/compute_mean_squared_distance(randomly_subsample(samples, 2000)).
    // It computes the mean squared distance between 2000 randomly selected samples and often
    // works quite well.
    const double gamma = verbose_find_gamma_with_big_centroid_gap(samples, labels);

    // Next we declare an instance of the kcentroid object.  It is used by rank_features()
    // two represent the centroids of the two classes.  The kcentroid has 3 parameters
    // you need to set.  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 ranking algorithm.  Generally, smaller values
    // give better results but cause the algorithm to attempt to use more dictionary vectors
    // (and thus run slower and use more memory).  The third argument, however, is the
    // maximum number of dictionary vectors a kcentroid is allowed to use.  So you can use
    // it to put an upper limit on the runtime complexity.
    kcentroid<kernel_type> kc(kernel_type(gamma), 0.001, 25);

    // And finally we get to the feature ranking. Here we call rank_features() with the kcentroid we just made,
    // the samples and labels we made above, and the number of features we want it to rank.
    cout << rank_features(kc, samples, labels) << endl;

    // The output is:
    /*
        0 0.749265
        1        1
        3 0.933378
        2 0.825179
    */

    // The first column is a list of the features in order of decreasing goodness.  So the rank_features() function
    // is telling us that the samples[i](0) and samples[i](1) (i.e. the x and y) features are the best two.  Then
    // after that the next best feature is the samples[i](3) (i.e. the y corrupted by noise) and finally the worst
    // feature is the one that is just random noise.  So in this case rank_features did exactly what we would
    // intuitively expect.

    // The second column of the matrix is a number that indicates how much the features up to that point
    // contribute to the separation of the two classes.  So bigger numbers are better since they
    // indicate a larger separation.  The max value is always 1.  In the case below we see that the bad
    // features actually make the class separation go down.

    // So to break it down a little more.
    //    0 0.749265   <-- class separation of feature 0 all by itself
    //    1        1   <-- class separation of feature 0 and 1
    //    3 0.933378   <-- class separation of feature 0, 1, and 3
    //    2 0.825179   <-- class separation of feature 0, 1, 3, and 2


dlib C++ Library - rvm_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example illustrating the use of the relevance vector machine
    utilities from the dlib C++ Library.

    This example creates a simple set of data to train on and then shows
    you how to use the cross validation and rvm training functions
    to find a good decision function that can classify examples in our
    data set.

    The data used in this example will be 2 dimensional data and will
    come from a distribution where points with a distance less than 10
    from the origin are labeled +1 and all other points are labeled
    as -1.

*/

#include <iostream>
#include <dlib/svm.h>

using namespace std;
using namespace dlib;

int main()
{
    // The rvm functions use column vectors to contain a lot of the data on which they
    // operate. So the first thing we do here is declare a convenient typedef.

    // This typedef declares a matrix with 2 rows and 1 column.  It will be the
    // object that contains each of our 2 dimensional samples.   (Note that if you wanted
    // more than 2 features in this vector you can simply change the 2 to something else.
    // Or if you don't know how many features you want until runtime then you can put a 0
    // here and use the matrix.set_size() member function)
    typedef matrix<double, 2, 1> sample_type;

    // This is a typedef for the type of kernel we are going to use in this example.
    // In this case I have selected the radial basis kernel that can operate on our
    // 2D sample_type objects
    typedef radial_basis_kernel<sample_type> kernel_type;

    // Now we make objects to contain our samples and their respective labels.
    std::vector<sample_type> samples;
    std::vector<double> labels;

    // Now let's put some data into our samples and labels objects.  We do this
    // by looping over a bunch of points and labeling them according to their
    // distance from the origin.
    for (int r = -20; r <= 20; ++r)
    {
        for (int c = -20; c <= 20; ++c)
        {
            sample_type samp;
            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) <= 10)
                labels.push_back(+1);
            else
                labels.push_back(-1);

        }
    }

    // Here we normalize all the samples by subtracting their mean and dividing by their standard deviation.
    // This is generally a good idea since it often heads off numerical stability problems and also
    // prevents one large feature from smothering others.  Doing this doesn't matter much in this example
    // so I'm just doing this here so you can see an easy way to accomplish this with
    // the library.
    vector_normalizer<sample_type> normalizer;
    // let the normalizer learn the mean and standard deviation of the samples
    normalizer.train(samples);
    // now normalize each sample
    for (unsigned long i = 0; i < samples.size(); ++i)
        samples[i] = normalizer(samples[i]);

    // Now that we have some data we want to train on it.  However, there is a parameter to the
    // training.  This is the gamma parameter of the RBF kernel.  Our choice for this parameter will
    // influence how good the resulting decision function is.  To test how good a particular choice of
    // kernel parameters is we can use the cross_validate_trainer() function to perform n-fold cross
    // validation on our training data.  However, there is a problem with the way we have sampled
    // our distribution.  The problem is that there is a definite ordering to the samples.
    // That is, the first half of the samples look like they are from a different distribution
    // than the second half.  This would screw up the cross validation process but we can
    // fix it by randomizing the order of the samples with the following function call.
    randomize_samples(samples, labels);

    // here we make an instance of the rvm_trainer object that uses our kernel type.
    rvm_trainer<kernel_type> trainer;

    // One thing you can do to reduce the RVM training time is to make its
    // stopping epsilon bigger.  However, this might make the outputs less
    // reliable.  But sometimes it works out well.  0.001 is the default.
    trainer.set_epsilon(0.001);
    // You can also set an explicit limit on the number of iterations used by the numeric
    // solver.  The default is 2000.
    trainer.set_max_iterations(2000);

    // Now we loop over some different gamma values to see how good they are.  Note
    // that this is a very simple way to try out a few possible parameter choices.  You
    // should look at the model_selection_ex.cpp program for examples of more sophisticated
    // strategies for determining good parameter choices.
    cout << "doing cross validation" << endl;
    for (double gamma = 0.000001; gamma <= 1; gamma *= 5)
    {
        // tell the trainer the parameters we want to use
        trainer.set_kernel(kernel_type(gamma));

        cout << "gamma: " << gamma;
        // Print out the cross validation accuracy for 3-fold cross validation using the current gamma.
        // cross_validate_trainer() returns a row vector.  The first element of the vector is the fraction
        // of +1 training examples correctly classified and the second number is the fraction of -1 training
        // examples correctly classified.
        cout << "     cross validation accuracy: " << cross_validate_trainer(trainer, samples, labels, 3);
    }

    // From looking at the output of the above loop it turns out that a good value for
    // gamma for this problem is 0.08.  So that is what we will use.

    // Now we train on the full set of data and obtain the resulting decision function.  We use the
    // value of 0.08 for gamma.  The decision function will return values >= 0 for samples it predicts
    // are in the +1 class and numbers < 0 for samples it predicts to be in the -1 class.
    trainer.set_kernel(kernel_type(0.08));
    typedef decision_function<kernel_type> dec_funct_type;
    typedef normalized_function<dec_funct_type> funct_type;

    // Here we are making an instance of the normalized_function object.  This object provides a convenient
    // way to store the vector normalization information along with the decision function we are
    // going to learn.
    funct_type learned_function;
    learned_function.normalizer = normalizer;  // save normalization information
    learned_function.function = trainer.train(samples, labels); // perform the actual RVM training and save the results

    // Print out the number of relevance vectors in the resulting decision function.
    cout << "\nnumber of relevance vectors in our learned_function is "
         << learned_function.function.basis_vectors.size() << endl;

    // Now let's try this decision_function on some samples we haven't seen before
    sample_type sample;

    sample(0) = 3.123;
    sample(1) = 2;
    cout << "This is a +1 class example, the classifier output is " << learned_function(sample) << endl;

    sample(0) = 3.123;
    sample(1) = 9.3545;
    cout << "This is a +1 class example, the classifier output is " << learned_function(sample) << endl;

    sample(0) = 13.123;
    sample(1) = 9.3545;
    cout << "This is a -1 class example, the classifier output is " << learned_function(sample) << endl;

    sample(0) = 13.123;
    sample(1) = 0;
    cout << "This is a -1 class example, the classifier output is " << learned_function(sample) << endl;

    // We can also train a decision function that reports a well conditioned probability
    // instead of just a number > 0 for the +1 class and < 0 for the -1 class.  An example
    // of doing that follows:
    typedef probabilistic_decision_function<kernel_type> probabilistic_funct_type;
    typedef normalized_function<probabilistic_funct_type> pfunct_type;

    pfunct_type learned_pfunct;
    learned_pfunct.normalizer = normalizer;
    learned_pfunct.function = train_probabilistic_decision_function(trainer, samples, labels, 3);
    // Now we have a function that returns the probability that a given sample is of the +1 class.

    // print out the number of relevance vectors in the resulting decision function.
    // (it should be the same as in the one above)
    cout << "\nnumber of relevance vectors in our learned_pfunct is "
         << learned_pfunct.function.decision_funct.basis_vectors.size() << endl;

    sample(0) = 3.123;
    sample(1) = 2;
    cout << "This +1 class example should have high probability.  Its probability is: "
         << learned_pfunct(sample) << endl;

    sample(0) = 3.123;
    sample(1) = 9.3545;
    cout << "This +1 class example should have high probability.  Its probability is: "
         << learned_pfunct(sample) << endl;

    sample(0) = 13.123;
    sample(1) = 9.3545;
    cout << "This -1 class example should have low probability.  Its probability is: "
         << learned_pfunct(sample) << endl;

    sample(0) = 13.123;
    sample(1) = 0;
    cout << "This -1 class example should have low probability.  Its probability is: "
         << learned_pfunct(sample) << endl;

    // Another thing that is worth knowing is that just about everything in dlib is serializable.
    // So for example, you can save the learned_pfunct object to disk and recall it later like so:
    serialize("saved_function.dat") << learned_pfunct;

    // Now let's open that file back up and load the function object it contains.
    deserialize("saved_function.dat") >> learned_pfunct;


dlib C++ Library - rvm_regression_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*
    This is an example illustrating the use of the RVM regression object
    from the dlib C++ Library.

    This example will train on data from the sinc function.

*/

#include <iostream>
#include <vector>

#include <dlib/svm.h>

using namespace std;
using namespace dlib;

// Here is the sinc function we will be trying to learn with rvm regression
double sinc(double x)
{
    if (x == 0)
        return 1;
    return sin(x)/x;
}

int main()
{
    // Here we declare that our samples will be 1 dimensional column vectors.
    typedef matrix<double,1,1> sample_type;

    // Now sample some points from the sinc() function
    sample_type m;
    std::vector<sample_type> samples;
    std::vector<double> labels;
    for (double x = -10; x <= 4; x += 1)
    {
        m(0) = x;
        samples.push_back(m);
        labels.push_back(sinc(x));
    }

    // 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 rvm_regression_trainer object.  This is the
    // object that we will later use to do the training.
    rvm_regression_trainer<kernel_type> trainer;

    // Here we set the kernel we want to use for training.   The radial_basis_kernel
    // has a parameter called gamma that we need to determine.  As a rule of thumb, a good
    // gamma to try is 1.0/(mean squared distance between your sample points).  So
    // below we are using a similar value.   Note also that using an inappropriately large
    // gamma will cause the RVM training algorithm to run extremely slowly.  What
    // "large" means is relative to how spread out your data is.  So it is important
    // to use a rule like this as a starting point for determining the gamma value
    // if you want to use the RVM.  It is also probably a good idea to normalize your
    // samples as shown in the rvm_ex.cpp example program.
    const double gamma = 2.0/compute_mean_squared_distance(samples);
    cout << "using gamma of " << gamma << endl;
    trainer.set_kernel(kernel_type(gamma));

    // One thing you can do to reduce the RVM training time is to make its
    // stopping epsilon bigger.  However, this might make the outputs less
    // reliable.  But sometimes it works out well.  0.001 is the default.
    trainer.set_epsilon(0.001);

    // now train a function based on our sample points
    decision_function<kernel_type> test = trainer.train(samples, labels);

    // now we output the value of the sinc function for a few test points as well as the
    // value predicted by our regression.
    m(0) = 2.5; cout << sinc(m(0)) << "   " << test(m) << endl;
    m(0) = 0.1; cout << sinc(m(0)) << "   " << test(m) << endl;
    m(0) = -4;  cout << sinc(m(0)) << "   " << test(m) << endl;
    m(0) = 5.0; cout << sinc(m(0)) << "   " << test(m) << endl;

    // The output is as follows:
    //using gamma of 0.05
    //0.239389   0.240989
    //0.998334   0.999538
    //-0.189201   -0.188453
    //-0.191785   -0.226516

    // The first column is the true value of the sinc function and the second
    // column is the output from the rvm estimate.

    // Another thing that is worth knowing is that just about everything in dlib is serializable.
    // So for example, you can save the test object to disk and recall it later like so:
    serialize("saved_function.dat") << test;

    // Now let's open that file back up and load the function object it contains.
    deserialize("saved_function.dat") >> test;


dlib C++ Library - running_stats_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*
    This is an example illustrating the use of the running_stats object from the dlib C++
    Library.  It is a simple tool for computing basic statistics on a stream of numbers.
    In this example, we sample 100 points from the sinc function and then then compute the
    unbiased sample mean, variance, skewness, and excess kurtosis.

*/
#include <iostream>
#include <vector>
#include <dlib/statistics.h>

using namespace std;
using namespace dlib;

// Here we define the sinc function so that we may generate sample data. We compute the mean,
// variance, skewness, and excess kurtosis of this sample data.

double sinc(double x)
{
    if (x == 0)
        return 1;
    return sin(x)/x;
}

int main()
{
    running_stats<double> rs;

    double tp1 = 0;
    double tp2 = 0;

    // We first generate the data and add it sequentially to our running_stats object.  We
    // then print every fifth data point.
    for (int x = 1; x <= 100; x++)
    {
        tp1 = x/100.0;
        tp2 = sinc(pi*x/100.0);
        rs.add(tp2);

        if(x % 5 == 0)
        {
            cout << " x = " << tp1 << " sinc(x) = " << tp2 << endl;
        }
    }

    // Finally, we compute and print the mean, variance, skewness, and excess kurtosis of
    // our data.

    cout << endl;
    cout << "Mean:           " << rs.mean() << endl;
    cout << "Variance:       " << rs.variance() << endl;
    cout << "Skewness:       " << rs.skewness() << endl;
    cout << "Excess Kurtosis " << rs.ex_kurtosis() << endl;

    return 0;


dlib C++ Library - sequence_labeler_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example illustrating the use of the machine learning
    tools for sequence labeling in the dlib C++ Library.

    The general problem addressed by these tools is the following.
    Suppose you have a set of sequences of some kind and you want to
    learn to predict a label for each element of a sequence.  So for
    example, you might have a set of English sentences where each
    word is labeled with its part of speech and you want to learn a
    model which can predict the part of speech for each word in a new
    sentence.

    Central to these tools is the sequence_labeler object.  It is the
    object which represents the label prediction model. In particular,
    the model used by this object is the following.  Given an input
    sequence x, predict an output label sequence y such that:
        y == argmax_y dot(weight_vector, PSI(x,y))
    where PSI() is supplied by the user and defines the form of the
    model.  In this example program we will define it such that we
    obtain a simple Hidden Markov Model.  However, it's possible to
    define much more sophisticated models.  You should take a look
    at the following papers for a few examples:
        - Hidden Markov Support Vector Machines by
          Y. Altun, I. Tsochantaridis, T. Hofmann
        - Shallow Parsing with Conditional Random Fields by
          Fei Sha and Fernando Pereira

    In the remainder of this example program we will show how to
    define your own PSI(), as well as how to learn the "weight_vector"
    parameter.  Once you have these two items you will be able to
    use the sequence_labeler to predict the labels of new sequences.
*/

#include <iostream>
#include <dlib/svm_threaded.h>
#include <dlib/rand.h>

using namespace std;
using namespace dlib;

/*
    In this example we will be working with a Hidden Markov Model where
    the hidden nodes and observation nodes both take on 3 different states.
    The task will be to take a sequence of observations and predict the state
    of the corresponding hidden nodes.
*/

const unsigned long num_label_states = 3;
const unsigned long num_sample_states = 3;

// ----------------------------------------------------------------------------------------

class feature_extractor
{
    /*
        This object is where you define your PSI().  To ensure that the argmax_y
        remains a tractable problem, the PSI(x,y) vector is actually a sum of vectors,
        each derived from the entire input sequence x but only part of the label
        sequence y.  This allows the argmax_y to be efficiently solved using the
        well known Viterbi algorithm.
    */

public:
    // This defines the type used to represent the observed sequence.  You can use
    // any type here so long as it has a .size() which returns the number of things
    // in the sequence.
    typedef std::vector<unsigned long> sequence_type;

    unsigned long num_features() const
    /*!
        ensures
            - returns the dimensionality of the PSI() feature vector.
    !*/
    {
        // Recall that we are defining a HMM.  So in this case the PSI() vector
        // should have the same dimensionality as the number of parameters in the HMM.
        return num_label_states*num_label_states + num_label_states*num_sample_states;
    }

    unsigned long order() const
    /*!
        ensures
            - This object represents a Markov model on the output labels.
              This parameter defines the order of the model.  That is, this
              value controls how many previous label values get to be taken
              into consideration when performing feature extraction for a
              particular element of the input sequence.  Note that the runtime
              of the algorithm is exponential in the order.  So don't make order
              very large.
    !*/
    {
        // In this case we are using a HMM model that only looks at the
        // previous label.
        return 1;
    }

    unsigned long num_labels() const
    /*!
        ensures
            - returns the number of possible output labels.
    !*/
    {
        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
    /*!
        requires
            - EXP::type == unsigned long
              (i.e. y contains unsigned longs)
            - position < x.size()
            - y.size() == min(position, order) + 1
            - is_vector(y) == true
            - max(y) < num_labels()
            - set_feature is a function object which allows expressions of the form:
                - set_features((unsigned long)feature_index, (double)feature_value);
                - set_features((unsigned long)feature_index);
        ensures
            - for all valid i:
                - interprets y(i) as the label corresponding to x[position-i]
            - This function computes the part of PSI() corresponding to the x[position]
              element of the input sequence.  Moreover, this part of PSI() is returned as
              a sparse vector by invoking set_feature().  For example, to set the feature
              with an index of 55 to the value of 1 this method would call:
                set_feature(55);
              Or equivalently:
                set_feature(55,1);
              Therefore, the first argument to set_feature is the index of the feature
              to be set while the second argument is the value the feature should take.
              Additionally, note that calling set_feature() multiple times with the same
              feature index does NOT overwrite the old value, it adds to the previous
              value.  For example, if you call set_feature(55) 3 times then it will
              result in feature 55 having a value of 3.
            - This function only calls set_feature() with feature_index values < num_features()
    !*/
    {
        // Again, the features below only define a simple HMM.  But in general, you can
        // use a wide variety of sophisticated feature extraction methods here.

        // Pull out an indicator feature for the type of transition between the
        // previous label and the current label.
        if (y.size() > 1)
            set_feature(y(1)*num_label_states + y(0));

        // Pull out an indicator feature for the type of observed node given
        // the current label.
        set_feature(num_label_states*num_label_states +
                    y(0)*num_sample_states + x[position]);
    }
};

// We need to define serialize() and deserialize() for our feature extractor if we want
// to be able to serialize and deserialize our learned models.  In this case the
// implementation is empty since our feature_extractor doesn't have any state.  But you
// might define more complex feature extractors which have state that needs to be saved.
void serialize(const feature_extractor&, std::ostream&) {}
void deserialize(feature_extractor&, std::istream&) {}

// ----------------------------------------------------------------------------------------

void make_dataset (
    const matrix<double>& transition_probabilities,
    const matrix<double>& emission_probabilities,
    std::vector<std::vector<unsigned long> >& 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.
!*/

// ----------------------------------------------------------------------------------------

int main()
{
    // We need a dataset to test the machine learning algorithms.  So we are going to
    // define a HMM based on the following two matrices and then randomly sample a
    // set of data from it.  Then we will see if the machine learning method can
    // recover the HMM model from the training data.

    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;

    std::vector<std::vector<unsigned long> > samples;
    std::vector<std::vector<unsigned long> > labels;
    // sample 1000 labeled sequences from the HMM.
    make_dataset(transition_probabilities,emission_probabilities,
                 samples, labels, 1000);

    // print out some of the randomly sampled sequences
    for (int i = 0; i < 10; ++i)
    {
        cout << "hidden states:   " << trans(mat(labels[i]));
        cout << "observed states: " << trans(mat(samples[i]));
        cout << "******************************" << endl;
    }

    // Next we use the structural_sequence_labeling_trainer to learn our
    // prediction model based on just the samples and labels.
    structural_sequence_labeling_trainer<feature_extractor> trainer;
    // This is the common SVM C parameter.  Larger values encourage the
    // trainer to attempt to fit the data exactly but might overfit.
    // In general, you determine this parameter by cross-validation.
    trainer.set_c(4);
    // This trainer can use multiple CPU cores to speed up the training.
    // So set this to the number of available CPU cores.
    trainer.set_num_threads(4);

    // Learn to do sequence labeling from the dataset
    sequence_labeler<feature_extractor> labeler = trainer.train(samples, labels);

    // Test the learned labeler on one of the training samples.  In this
    // case it will give the correct sequence of labels.
    std::vector<unsigned long> predicted_labels = labeler(samples[0]);
    cout << "true hidden states:      "<< trans(mat(labels[0]));
    cout << "predicted hidden states: "<< trans(mat(predicted_labels));

    // We can also do cross-validation.  The confusion_matrix is defined as:
    //  - confusion_matrix(T,P) == the number of times a sequence element with label T
    //    was predicted to have a label of P.
    // So if all predictions are perfect then only diagonal elements of this matrix will
    // be non-zero.
    matrix<double> confusion_matrix;
    confusion_matrix = cross_validate_sequence_labeler(trainer, samples, labels, 4);
    cout << "\ncross-validation: " << endl;
    cout << confusion_matrix;
    cout << "label accuracy: "<< sum(diag(confusion_matrix))/sum(confusion_matrix) << endl;

    // In this case, the label accuracy is about 88%.  At this point, we want to know if
    // the machine learning method was able to recover the HMM model from the data.  So
    // to test this, we can load the true HMM model into another sequence_labeler and
    // test it out on the data and compare the results.

    matrix<double,0,1> true_hmm_model_weights = log(join_cols(reshape_to_column_vector(transition_probabilities),
                                                              reshape_to_column_vector(emission_probabilities)));
    // With this model, labeler_true will predict the most probable set of labels
    // given an input sequence.  That is, it will predict using the equation:
    //    y == argmax_y dot(true_hmm_model_weights, PSI(x,y))
    sequence_labeler<feature_extractor> labeler_true(true_hmm_model_weights);

    confusion_matrix = test_sequence_labeler(labeler_true, samples, labels);
    cout << "\nTrue HMM model: " << endl;
    cout << confusion_matrix;
    cout << "label accuracy: "<< sum(diag(confusion_matrix))/sum(confusion_matrix) << endl;

    // Happily, we observe that the true model also obtains a label accuracy of 88%.

    // Finally, the labeler can be serialized to disk just like most dlib objects.
    serialize("labeler.dat") << labeler;

    // recall from disk
    deserialize("labeler.dat") >> labeler;
}

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//              Code for creating a bunch of random samples from our HMM.
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

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<std::vector<unsigned long> >& samples,
    std::vector<std::vector<unsigned long> >& labels,
    unsigned long dataset_size
)
{
    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(sample);
        labels.push_back(label);
    }
}

// ----------------------------------------------------------------------------------------


dlib C++ Library - sequence_segmenter_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This example shows how to use dlib to learn to do sequence segmentation.  In a sequence
    segmentation task we are given a sequence of objects (e.g. words in a sentence) and we
    are supposed to detect certain subsequences (e.g. the names of people).  Therefore, in
    the code below we create some very simple training sequences and use them to learn a
    sequence segmentation model.  In particular, our sequences will be sentences
    represented as arrays of words and our task will be to learn to identify person names.
    Once we have our segmentation model we can use it to find names in new sentences, as we
    will show.

*/

#include <iostream>
#include <cctype>
#include <dlib/svm_threaded.h>
#include <dlib/string.h>

using namespace std;
using namespace dlib;

// ----------------------------------------------------------------------------------------

class feature_extractor
{
    /*
        The sequence segmentation models we work with in this example are chain structured
        conditional random field style models.  Therefore, central to a sequence
        segmentation model is a feature extractor object.  This object defines all the
        properties of the model such as how many features it will use, and more importantly,
        how they are calculated.
    */

public:
    // This should be the type used to represent an input sequence.  It can be
    // anything so long as it has a .size() which returns the length of the sequence.
    typedef std::vector<std::string> sequence_type;

    // The next four lines define high-level properties of the feature extraction model.
    // See the documentation for the sequence_labeler object for an extended discussion of
    // how they are used (note that the main body of the documentation is at the top of the
    // file documenting the sequence_labeler).
    const static bool use_BIO_model           = true;
    const static bool use_high_order_features = true;
    const static bool allow_negative_weights  = true;
    unsigned long window_size()  const { return 3; }

    // This function defines the dimensionality of the vectors output by the get_features()
    // function defined below.
    unsigned long num_features() const { return 1; }

    template <typename feature_setter>
    void get_features (
        feature_setter& set_feature,
        const sequence_type& sentence,
        unsigned long position
    ) const
    /*!
        requires
            - position < sentence.size()
            - set_feature is a function object which allows expressions of the form:
                - set_features((unsigned long)feature_index, (double)feature_value);
                - set_features((unsigned long)feature_index);
        ensures
            - This function computes a feature vector which should capture the properties
              of sentence[position] that are informative relative to the sequence
              segmentation task you are trying to perform.
            - The output feature vector is returned as a sparse vector by invoking set_feature().
              For example, to set the feature with an index of 55 to the value of 1
              this method would call:
                set_feature(55);
              Or equivalently:
                set_feature(55,1);
              Therefore, the first argument to set_feature is the index of the feature
              to be set while the second argument is the value the feature should take.
              Additionally, note that calling set_feature() multiple times with the
              same feature index does NOT overwrite the old value, it adds to the
              previous value.  For example, if you call set_feature(55) 3 times then it
              will result in feature 55 having a value of 3.
            - This function only calls set_feature() with feature_index values < num_features()
    !*/
    {
        // The model in this example program is very simple.  Our features only look at the
        // capitalization pattern of the words.  So we have a single feature which checks
        // if the first letter is capitalized or not.
        if (isupper(sentence[position][0]))
            set_feature(0);
    }
};

// We need to define serialize() and deserialize() for our feature extractor if we want
// to be able to serialize and deserialize our learned models.  In this case the
// implementation is empty since our feature_extractor doesn't have any state.  But you
// might define more complex feature extractors which have state that needs to be saved.
void serialize(const feature_extractor&, std::ostream&) {}
void deserialize(feature_extractor&, std::istream&) {}

// ----------------------------------------------------------------------------------------

void make_training_examples (
    std::vector<std::vector<std::string> >& samples,
    std::vector<std::vector<std::pair<unsigned long, unsigned long> > >& segments
)
/*!
    ensures
        - This function fills samples with example sentences and segments with the
          locations of person names that should be segmented out.
        - #samples.size() == #segments.size()
!*/
{
    std::vector<std::pair<unsigned long, unsigned long> > names;

    // Here we make our first training example.  split() turns the string into an array of
    // 10 words and then we store that into samples.
    samples.push_back(split("The other day I saw a man named Jim Smith"));
    // We want to detect person names.  So we note that the name is located within the
    // range [8, 10).  Note that we use half open ranges to identify segments.  So in this
    // case, the segment identifies the string "Jim Smith".
    names.push_back(make_pair(8, 10));
    segments.push_back(names); names.clear();

    // Now we add a few more example sentences

    samples.push_back(split("Davis King is the main author of the dlib Library"));
    names.push_back(make_pair(0, 2));
    segments.push_back(names); names.clear();

    samples.push_back(split("Bob Jones is a name and so is George Clinton"));
    names.push_back(make_pair(0, 2));
    names.push_back(make_pair(8, 10));
    segments.push_back(names); names.clear();

    samples.push_back(split("My dog is named Bob Barker"));
    names.push_back(make_pair(4, 6));
    segments.push_back(names); names.clear();

    samples.push_back(split("ABC is an acronym but John James Smith is a name"));
    names.push_back(make_pair(5, 8));
    segments.push_back(names); names.clear();

    samples.push_back(split("No names in this sentence at all"));
    segments.push_back(names); names.clear();
}

// ----------------------------------------------------------------------------------------

void print_segment (
    const std::vector<std::string>& sentence,
    const std::pair<unsigned long,unsigned long>& segment
)
{
    // Recall that a segment is a half open range starting with .first and ending just
    // before .second.
    for (unsigned long i = segment.first; i < segment.second; ++i)
        cout << sentence[i] << " ";
    cout << endl;
}

// ----------------------------------------------------------------------------------------

int main()
{
    // Finally we make it into the main program body.  So the first thing we do is get our
    // training data.
    std::vector<std::vector<std::string> > samples;
    std::vector<std::vector<std::pair<unsigned long, unsigned long> > > segments;
    make_training_examples(samples, segments);

    // Next we use the structural_sequence_segmentation_trainer to learn our segmentation
    // model based on just the samples and segments.  But first we setup some of its
    // parameters.
    structural_sequence_segmentation_trainer<feature_extractor> trainer;
    // This is the common SVM C parameter.  Larger values encourage the trainer to attempt
    // to fit the data exactly but might overfit.  In general, you determine this parameter
    // by cross-validation.
    trainer.set_c(10);
    // This trainer can use multiple CPU cores to speed up the training.  So set this to
    // the number of available CPU cores.
    trainer.set_num_threads(4);

    // Learn to do sequence segmentation from the dataset
    sequence_segmenter<feature_extractor> segmenter = trainer.train(samples, segments);

    // Let's print out all the segments our segmenter detects.
    for (unsigned long i = 0; i < samples.size(); ++i)
    {
        // get all the detected segments in samples[i]
        std::vector<std::pair<unsigned long,unsigned long> > seg = segmenter(samples[i]);
        // Print each of them
        for (unsigned long j = 0; j < seg.size(); ++j)
        {
            print_segment(samples[i], seg[j]);
        }
    }

    // Now let's test it on a new sentence and see what it detects.
    std::vector<std::string> sentence(split("There once was a man from Nantucket whose name rhymed with Bob Bucket"));
    std::vector<std::pair<unsigned long,unsigned long> > seg = segmenter(sentence);
    for (unsigned long j = 0; j < seg.size(); ++j)
    {
        print_segment(sentence, seg[j]);
    }

    // We can also test the accuracy of the segmenter on a dataset.  This statement simply
    // tests on the training data.  In this case we will see that it predicts everything
    // correctly.
    cout << "\nprecision, recall, f1-score: " << test_sequence_segmenter(segmenter, samples, segments);
    // Similarly, we can do 5-fold cross-validation and print the results.  Just as before,
    // we see everything is predicted correctly.
    cout << "precision, recall, f1-score: " << cross_validate_sequence_segmenter(trainer, samples, segments, 5);

    // Finally, the segmenter can be serialized to disk just like most dlib objects.
    serialize("segmenter.dat") << segmenter;

    // recall from disk
    deserialize("segmenter.dat") >> segmenter;
}

// ----------------------------------------------------------------------------------------


dlib C++ Library - sockets_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example illustrating the use of the sockets and
    server components from the dlib C++ Library.

    This is a simple echo server.  It listens on port 1234 for incoming
    connections and just echos back any data it receives.

*/

#include <dlib/sockets.h>
#include <dlib/server.h>
#include <iostream>

using namespace dlib;
using namespace std;

class serv : public server
{
    void on_connect  (
        connection& con
    )
    {
        char ch;
        while (con.read(&ch,1) > 0)
        {
            // we are just reading one char at a time and writing it back
            // to the connection.  If there is some problem writing the char
            // then we quit the loop.
            if (con.write(&ch,1) != 1)
                break;
        }
    }

};

int main()
{
    try
    {
        serv our_server;

        // set up the server object we have made
        our_server.set_listening_port(1234);
        // Tell the server to begin accepting connections.
        our_server.start_async();

        cout << "Press enter to end this program" << endl;
        cin.get();
    }
    catch (exception& e)
    {
        cout << e.what() << endl;


dlib C++ Library - sockstreambuf_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example illustrating the use of the sockets and sockstreambuf
    components from the dlib C++ Library.  Note that there is also an
    iosockstream object in dlib that is often simpler to use, see
    iosockstream_ex.cpp for an example of its use.

    This program simply connects to www.google.com at port 80 and requests the
    main Google web page.  It then prints what it gets back from Google to the
    screen.

    For those of you curious about HTTP check out the excellent introduction at
    http://www.jmarshall.com/easy/http/
*/

#include <dlib/sockets.h>
#include <dlib/sockstreambuf.h>
#include <iostream>

using namespace std;
using namespace dlib;

int main()
{
    try
    {
        // Connect to Google's web server which listens on port 80.  If this
        // fails it will throw a dlib::socket_error exception.  Note that we
        // are using a smart pointer here to contain the connection pointer
        // returned from connect.  Doing this ensures that the connection
        // is deleted even if someone throws an exception somewhere in your code.
        scoped_ptr<connection> con(connect("www.google.com",80));

        {
            // Create a stream buffer for our connection
            sockstreambuf buf(con);
            // Now stick that stream buffer into an iostream object
            iostream stream(&buf);
            // This command causes the iostream to flush its output buffers
            // whenever someone makes a read request.
            buf.flush_output_on_read();

            // Now we make the HTTP GET request for the main Google page.
            stream << "GET / HTTP/1.0\r\n\r\n";

            // Here we print each character we get back one at a time.
            int ch = stream.get();
            while (ch != EOF)
            {
                cout << (char)ch;
                ch = stream.get();
            }

            // At the end of this scope buf will be destructed and flush
            // anything it still contains to the connection.  Thus putting
            // this } here makes it safe to destroy the connection later on.
            // If we just destroyed the connection before buf was destructed
            // then buf might try to flush its data to a closed connection
            // which would be an error.
        }

        // Here we call close_gracefully().  It takes a connection and performs
        // a proper TCP shutdown by sending a FIN packet to the other end of the
        // connection and waiting half a second for the other end to close the
        // connection as well.  If half a second goes by without the other end
        // responding then the connection is forcefully shutdown and deleted.
        //
        // You usually want to perform a graceful shutdown of your TCP connections
        // because there might be some data you tried to send that is still buffered
        // in the operating system's output buffers.  If you just killed the
        // connection it might not be sent to the other side (although maybe
        // you don't care, and in the case of this example it doesn't really matter.
        // But I'm only putting this here for the purpose of illustration :-).
        // In any case, this function is provided to allow you to perform a graceful
        // close if you so choose.
        //
        // Also note that the timeout can be changed by suppling an optional argument
        // to this function.
        close_gracefully(con);
    }
    catch (exception& e)
    {
        cout << e.what() << endl;


dlib C++ Library - svm_sparse_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example showing how to use sparse feature vectors with
    the dlib C++ library's machine learning tools.

    This example creates a simple binary classification problem and shows
    you how to train a support vector machine on that data.

    The data used in this example will be 100 dimensional data and will
    come from a simple linearly separable distribution.
*/

#include <iostream>
#include <ctime>
#include <vector>
#include <dlib/svm.h>

using namespace std;
using namespace dlib;

int main()
{
    // In this example program we will be dealing with feature vectors that are sparse (i.e. most
    // of the values in each vector are zero).  So rather than using a dlib::matrix we can use
    // one of the containers from the STL to represent our sample vectors.  In particular, we
    // can use the std::map to represent sparse vectors.  (Note that you don't have to use std::map.
    // Any STL container of std::pair objects that is sorted can be used.  So for example, you could
    // use a std::vector<std::pair<unsigned long,double> > here so long as you took care to sort every vector)
    typedef std::map<unsigned long,double> sample_type;

    // This is a typedef for the type of kernel we are going to use in this example.
    // Since our data is linearly separable I picked the linear kernel.  Note that if you
    // are using a sparse vector representation like std::map then you have to use a kernel
    // meant to be used with that kind of data type.
    typedef sparse_linear_kernel<sample_type> kernel_type;

    // Here we create an instance of the pegasos svm trainer object we will be using.
    svm_pegasos<kernel_type> trainer;
    // Here we setup a parameter to this object.  See the dlib documentation for a
    // description of what this parameter does.
    trainer.set_lambda(0.00001);

    // Let's also use the svm trainer specially optimized for the linear_kernel and
    // sparse_linear_kernel.
    svm_c_linear_trainer<kernel_type> linear_trainer;
    // This trainer solves the "C" formulation of the SVM.  See the documentation for
    // details.
    linear_trainer.set_c(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;

    // Now let's go into a loop and randomly generate 10000 samples.
    srand(time(0));
    double label = +1;
    for (int i = 0; i < 10000; ++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;
        }

        // let the svm_pegasos learn about this sample.
        trainer.train(sample,label);

        // 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);
    }

    // In addition to the rule we learned with the pegasos trainer, let's also use our
    // linear_trainer to learn a decision rule.
    decision_function<kernel_type> df = linear_trainer.train(samples, labels);

    // Now we have trained our SVMs.  Let's test them out a bit.
    // Each of these statements prints the output of the SVMs given a particular sample.
    // Each SVM outputs a number > 0 if a sample is predicted to be in the +1 class and < 0
    // if a sample is predicted to be in the -1 class.

    sample.clear();
    sample[4] = 0.3;
    sample[10] = 0.9;
    cout << "This is a +1 example, its SVM output is: " << trainer(sample) << endl;
    cout << "df: " << df(sample) << endl;

    sample.clear();
    sample[83] = -0.3;
    sample[26] = -0.9;
    sample[58] = -0.7;
    cout << "This is a -1 example, its SVM output is: " << trainer(sample) << endl;
    cout << "df: " << df(sample) << endl;

    sample.clear();
    sample[0] = -0.2;
    sample[9] = -0.8;
    cout << "This is a -1 example, its SVM output is: " << trainer(sample) << endl;
    cout << "df: " << df(sample) << endl;


dlib C++ Library - sqlite_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt

/*
    This example gives a quick overview of dlib's C++ API for the popular SQLite library.
*/

#include <iostream>
#include <dlib/sqlite.h>
#include <dlib/matrix.h>

using namespace dlib;
using namespace std;

// ----------------------------------------------------------------------------------------

bool table_exists (
    database& db,
    const std::string& tablename
)
{
    // Sometimes you want to just run a query that returns one thing.  In this case, we
    // want to see how many tables are in our database with the given tablename.  The only
    // possible outcomes are 1 or 0 and we can do this by looking in the special
    // sqlite_master table that records such database metadata.  For these kinds of "one
    // result" queries we can use the query_int() method which executes a SQL statement
    // against a database and returns the result as an int.
    return query_int(db, "select count(*) from sqlite_master where name = '"+tablename+"'")==1;
}

// ----------------------------------------------------------------------------------------

int main() try
{
    // Open the SQLite database in the stuff.db file (or create an empty database in
    // stuff.db if it doesn't exist).
    database db("stuff.db");

    // Create a people table that records a person's name, age, and their "data".
    if (!table_exists(db,"people"))
        db.exec("create table people (name, age, data)");

    // Now let's add some data to this table.  We can do this by making a statement object
    // as shown.  Here we use the special ? character to indicate bindable arguments and
    // below we will use st.bind() statements to populate those fields with values.
    statement st(db, "insert into people VALUES(?,?,?)");

    // The data for Davis
    string name = "Davis";
    int age = 32;
    matrix<double> m = randm(3,3); // some random "data" for Davis

    // You can bind any of the built in scalar types (e.g. int, float) or std::string and
    // they will go into the table as the appropriate SQL types (e.g. INT, TEXT).  If you
    // try to bind any other object it will be saved as a binary blob if the type has an
    // appropriate void serialize(const T&, std::ostream&) function defined for it.  The
    // matrix has such a serialize function (as do most dlib types) so the bind below saves
    // the matrix as a binary blob.
    st.bind(1, name);
    st.bind(2, age);
    st.bind(3, m);
    st.exec(); // execute the SQL statement.  This does the insert.

    // We can reuse the statement to add more data to the database.  In fact, if you have a
    // bunch of statements to execute it is fastest if you reuse them in this manner.
    name = "John";
    age = 82;
    m = randm(2,3);
    st.bind(1, name);
    st.bind(2, age);
    st.bind(3, m);
    st.exec();

    // Now lets print out all the rows in the people table.
    statement st2(db, "select * from people");
    st2.exec();
    // Loop over all the rows obtained by executing the statement with .exec().
    while(st2.move_next())
    {
        string name;
        int age;
        matrix<double> m;
        // Analogously to bind, we can grab the columns straight into C++ types.  Here the
        // matrix is automatically deserialized by calling its deserialize() routine.
        st2.get_column(0, name);
        st2.get_column(1, age);
        st2.get_column(2, m);
        cout << name << " " << age << "\n" << m << endl << endl;
    }

    // Finally, if you want to make a bunch of atomic changes to a database then you should
    // do so inside a transaction.  Here, either all the database modifications that occur
    // between the creation of my_trans and the invocation of my_trans.commit() will appear
    // in the database or none of them will.  This way, if an exception or other error
    // happens halfway though your transaction you won't be left with your database in an
    // inconsistent state.
    //
    // Additionally, if you are going to do a large amount of inserts or updates then it is
    // much faster to group them into a transaction.
    transaction my_trans(db);

    name = "Dude";
    age = 49;
    m = randm(4,2);
    st.bind(1, name);
    st.bind(2, age);
    st.bind(3, m);
    st.exec();

    name = "Bob";
    age = 29;
    m = randm(2,2);
    st.bind(1, name);
    st.bind(2, age);
    st.bind(3, m);
    st.exec();

    // If you comment out this line then you will see that these inserts do not take place.
    // Specifically, what happens is that when my_trans is destructed it rolls back the
    // entire transaction unless commit() has been called.
    my_trans.commit();

}
catch (std::exception& e)
{
    cout << e.what() << endl;
}

// ----------------------------------------------------------------------------------------


dlib C++ Library - std_allocator_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*
    This is an example illustrating the use of the dlib::std_allocator object.

    In this example we will create the necessary typedefs to give the
    dlib::std_allocator object to the standard string and vector objects
    in the STL.  Thus we will create versions of std::string and std::vector
    that perform all their memory allocations and deallocations via one of
    the dlib memory manager objects.
*/

// include everything we need for this example
#include <vector>
#include <iostream>
#include <string>
#include <dlib/std_allocator.h>
#include <dlib/memory_manager.h>
#include <dlib/memory_manager_stateless.h>

using namespace std;
using namespace dlib;

int main()
{
    // Make a typedef for an allocator that uses the thread safe memory_manager_stateless object with a
    // global memory pool.  This version of the memory_manager_stateless object keeps everything it allocates
    // in a global memory pool and doesn't release any memory until the program terminates.
    typedef std_allocator<char, memory_manager_stateless<char>::kernel_2_3a> alloc_char_with_global_memory_pool;

    // Now make a typedef for a C++ standard string that uses our new allocator type
    typedef std::basic_string<char, char_traits<char>, alloc_char_with_global_memory_pool > dstring;

    // typedef another allocator for dstring objects
    typedef std_allocator<dstring, memory_manager_stateless<char>::kernel_2_3a> alloc_dstring_with_global_memory_pool;

    // Now make a typedef for a C++ standard vector that uses our new allocator type and also contains the new dstring
    typedef std::vector<dstring, alloc_dstring_with_global_memory_pool > dvector;

    // Now we can use the string and vector we have as we normally would.  So for example, I can make a
    // dvector and add 4 strings into it like so:
    dvector v;
    v.push_back("one");
    v.push_back("two");
    v.push_back("three");
    v.push_back("four");

    // And now we print out the contents of our vector
    for (unsigned long i = 0; i < v.size(); ++i)
    {
        cout << v[i] << endl;


dlib C++ Library - svm_struct_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example illustrating the use of the structural SVM solver from the dlib C++
    Library.  Therefore, this example teaches you the central ideas needed to setup a
    structural SVM model for your machine learning problems.  To illustrate the process, we
    use dlib's structural SVM solver to learn the parameters of a simple multi-class
    classifier.  We first discuss the multi-class classifier model and then walk through
    using the structural SVM tools to find the parameters of this classification model.

*/

#include <iostream>
#include <dlib/svm_threaded.h>

using namespace std;
using namespace dlib;

// Before we start, we define three typedefs we will use throughout this program.  The
// first is used to represent the parameter vector the structural SVM is learning, the
// second is used to represent the "sample type".  In this example program it is just a
// vector but in general when using a structural SVM your sample type can be anything you
// want (e.g. a string or an image).  The last typedef is the type used to represent the
// PSI vector which is part of the structural SVM model which we will explain in detail
// later on.  But the important thing to note here is that you can use either a dense
// representation (i.e. a dlib::matrix object) or a sparse representation for the PSI
// vector.  See svm_sparse_ex.cpp for an introduction to sparse vectors in dlib.  Here we
// use the same type for each of these three things to keep the example program simple.
typedef matrix<double,0,1> column_vector;       // Must be a dlib::matrix type.
typedef matrix<double,0,1> sample_type;         // Can be anything you want.
typedef matrix<double,0,1> feature_vector_type; // Must be dlib::matrix or some kind of sparse vector.

// ----------------------------------------------------------------------------------------

int           predict_label                (const column_vector& weights, const sample_type& sample);
column_vector train_three_class_classifier (const std::vector<sample_type>& samples, const std::vector<int>& labels);

// ----------------------------------------------------------------------------------------

int main()
{
    // In this example, we have three types of samples: class 0, 1, or 2.  That is, each of
    // our sample vectors falls into one of three classes.  To keep this example very
    // simple, each sample vector is zero everywhere except at one place.  The non-zero
    // dimension of each vector determines the class of the vector.  So for example, the
    // first element of samples has a class of 1 because samples[0](1) is the only non-zero
    // element of samples[0].
    sample_type samp(3);
    std::vector<sample_type> samples;
    samp = 0,2,0; samples.push_back(samp);
    samp = 1,0,0; samples.push_back(samp);
    samp = 0,4,0; samples.push_back(samp);
    samp = 0,0,3; samples.push_back(samp);
    // Since we want to use a machine learning method to learn a 3-class classifier we need
    // to record the labels of our samples.  Here samples[i] has a class label of labels[i].
    std::vector<int> labels;
    labels.push_back(1);
    labels.push_back(0);
    labels.push_back(1);
    labels.push_back(2);

    // Now that we have some training data we can tell the structural SVM to learn the
    // parameters of our 3-class classifier model.  The details of this will be explained
    // later.  For now, just note that it finds the weights (i.e. a vector of real valued
    // parameters) such that predict_label(weights, sample) always returns the correct
    // label for a sample vector.
    column_vector weights = train_three_class_classifier(samples, labels);

    // Print the weights and then evaluate predict_label() on each of our training samples.
    // Note that the correct label is predicted for each sample.
    cout << weights << endl;
    for (unsigned long i = 0; i < samples.size(); ++i)
        cout << "predicted label for sample["<<i<<"]: " << predict_label(weights, samples[i]) << endl;
}

// ----------------------------------------------------------------------------------------

int predict_label (
    const column_vector& weights,
    const sample_type& sample
)
/*!
    requires
        - weights.size() == 9
        - sample.size() == 3
    ensures
        - Given the 9-dimensional weight vector which defines a 3 class classifier, this
          function predicts the class of the given 3-dimensional sample vector.
          Therefore, the output of this function is either 0, 1, or 2 (i.e. one of the
          three possible labels).
!*/
{
    // Our 3-class classifier model can be thought of as containing 3 separate linear
    // classifiers.  So to predict the class of a sample vector we evaluate each of these
    // three classifiers and then whatever classifier has the largest output "wins" and
    // predicts the label of the sample.  This is the popular one-vs-all multi-class
    // classifier model.
    //
    // Keeping this in mind, the code below simply pulls the three separate weight vectors
    // out of weights and then evaluates each against sample.  The individual classifier
    // scores are stored in scores and the highest scoring index is returned as the label.
    column_vector w0, w1, w2;
    w0 = rowm(weights, range(0,2));
    w1 = rowm(weights, range(3,5));
    w2 = rowm(weights, range(6,8));

    column_vector scores(3);
    scores = dot(w0, sample), dot(w1, sample), dot(w2, sample);

    return index_of_max(scores);
}

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

class three_class_classifier_problem : public structural_svm_problem_threaded<column_vector, feature_vector_type>
{
    /*!
        Now we arrive at the meat of this example program.  To use dlib's structural SVM
        solver you need to define an object which tells the structural SVM solver what to
        do for your problem.  In this example, this is done by defining the three_class_classifier_problem
        object which inherits from structural_svm_problem_threaded.  Before we get into the
        details, we first discuss some background information on structural SVMs.

        A structural SVM is a supervised machine learning method for learning to predict
        complex outputs.  This is contrasted with a binary classifier which makes only simple
        yes/no predictions.  A structural SVM, on the other hand, can learn to predict
        complex outputs such as entire parse trees or DNA sequence alignments.  To do this,
        it learns a function F(x,y) which measures how well a particular data sample x
        matches a label y, where a label is potentially a complex thing like a parse tree.
        However, to keep this example program simple we use only a 3 category label output.

        At test time, the best label for a new x is given by the y which maximizes F(x,y).
        To put this into the context of the current example, F(x,y) computes the score for
        a given sample and class label.  The predicted class label is therefore whatever
        value of y which makes F(x,y) the biggest.  This is exactly what predict_label()
        does.  That is, it computes F(x,0), F(x,1), and F(x,2) and then reports which label
        has the biggest value.

        At a high level, a structural SVM can be thought of as searching the parameter space
        of F(x,y) for the set of parameters that make the following inequality true as often
        as possible:
            F(x_i,y_i) > max{over all incorrect labels of x_i} F(x_i, y_incorrect)
        That is, it seeks to find the parameter vector such that F(x,y) always gives the
        highest score to the correct output.  To define the structural SVM optimization
        problem precisely, we first introduce some notation:
            - let PSI(x,y)    == the joint feature vector for input x and a label y.
            - let F(x,y|w)    == dot(w,PSI(x,y)).
              (we use the | notation to emphasize that F() has the parameter vector of
              weights called w)
            - let LOSS(idx,y) == the loss incurred for predicting that the idx-th training
              sample has a label of y.  Note that LOSS() should always be >= 0 and should
              become exactly 0 when y is the correct label for the idx-th sample.  Moreover,
              it should notionally indicate how bad it is to predict y for the idx'th sample.
            - let x_i == the i-th training sample.
            - let y_i == the correct label for the i-th training sample.
            - The number of data samples is N.

        Then the optimization problem solved by dlib's structural SVM solver is the following:
            Minimize: h(w) == 0.5*dot(w,w) + C*R(w)

            Where R(w) == sum from i=1 to N: 1/N * sample_risk(i,w)
            and sample_risk(i,w) == max over all Y: LOSS(i,Y) + F(x_i,Y|w) - F(x_i,y_i|w)
            and C > 0

        You can think of the sample_risk(i,w) as measuring the degree of error you would make
        when predicting the label of the i-th sample using parameters w.  That is, it is zero
        only when the correct label would be predicted and grows larger the more "wrong" the
        predicted output becomes.  Therefore, the objective function is minimizing a balance
        between making the weights small (typically this reduces overfitting) and fitting the
        training data.  The degree to which you try to fit the data is controlled by the C
        parameter.

        For a more detailed introduction to structured support vector machines you should
        consult the following paper:
            Predicting Structured Objects with Support Vector Machines by
            Thorsten Joachims, Thomas Hofmann, Yisong Yue, and Chun-nam Yu

    !*/

public:

    // Finally, we come back to the code.  To use dlib's structural SVM solver you need to
    // provide the things discussed above.  This is the number of training samples, the
    // dimensionality of PSI(), as well as methods for calculating the loss values and
    // PSI() vectors.  You will also need to write code that can compute: max over all Y:
    // LOSS(i,Y) + F(x_i,Y|w).  In particular, the three_class_classifier_problem class is
    // required to implement the following four virtual functions:
    //   - get_num_dimensions()
    //   - get_num_samples()
    //   - get_truth_joint_feature_vector()
    //   - separation_oracle()

    // But first, we declare a constructor so we can populate our three_class_classifier_problem
    // object with the data we need to define our machine learning problem.  All we do here
    // is take in the training samples and their labels as well as a number indicating how
    // many threads the structural SVM solver will use.  You can declare this constructor
    // any way you like since it is not used by any of the dlib tools.
    three_class_classifier_problem (
        const std::vector<sample_type>& samples_,
        const std::vector<int>& labels_,
        const unsigned long num_threads
    ) :
        structural_svm_problem_threaded<column_vector, feature_vector_type>(num_threads),
        samples(samples_),
        labels(labels_)
    {}

    feature_vector_type make_psi (
        const sample_type& x,
        const int label
    ) const
    /*!
        ensures
            - returns the vector PSI(x,label)
    !*/
    {
        // All we are doing here is taking x, which is a 3 dimensional sample vector in this
        // example program, and putting it into one of 3 places in a 9 dimensional PSI
        // vector, which we then return.  So this function returns PSI(x,label).  To see why
        // we setup PSI like this, recall how predict_label() works.  It takes in a 9
        // dimensional weight vector and breaks the vector into 3 pieces.  Each piece then
        // defines a different classifier and we use them in a one-vs-all manner to predict
        // the label.  So now that we are in the structural SVM code we have to define the
        // PSI vector to correspond to this usage.  That is, we need to setup PSI so that
        // argmax_y dot(weights,PSI(x,y)) == predict_label(weights,x).  This is how we tell
        // the structural SVM solver what kind of problem we are trying to solve.
        //
        // It's worth emphasizing that the single biggest step in using a structural SVM is
        // deciding how you want to represent PSI(x,label).  It is always a vector, but
        // deciding what to put into it to solve your problem is often not a trivial task.
        // Part of the difficulty is that you need an efficient method for finding the label
        // that makes dot(w,PSI(x,label)) the biggest.  Sometimes this is easy, but often
        // finding the max scoring label turns into a difficult combinatorial optimization
        // problem.  So you need to pick a PSI that doesn't make the label maximization step
        // intractable but also still well models your problem.
        //
        // Finally, note that make_psi() is a helper routine we define in this example.  In
        // general, you are not required to implement it.  That is, all you must implement
        // are the four virtual functions defined below.

        // So let's make an empty 9-dimensional PSI vector
        feature_vector_type psi(get_num_dimensions());
        psi = 0; // zero initialize it

        // Now put a copy of x into the right place in PSI according to its label.  So for
        // example, if label is 1 then psi would be:  [0 0 0 x(0) x(1) x(2) 0 0 0]
        if (label == 0)
            set_rowm(psi,range(0,2)) = x;
        else if (label == 1)
            set_rowm(psi,range(3,5)) = x;
        else // the label must be 2
            set_rowm(psi,range(6,8)) = x;

        return psi;
    }

    // We need to declare the dimensionality of the PSI vector (this is also the
    // dimensionality of the weight vector we are learning).  Similarly, we need to declare
    // the number of training samples.  We do this by defining the following virtual
    // functions.
    virtual long get_num_dimensions () const { return samples[0].size() * 3; }
    virtual long get_num_samples ()    const { return samples.size(); }

    // In get_truth_joint_feature_vector(), all you have to do is output the PSI() vector
    // for the idx-th training sample when it has its true label.  So here it outputs
    // PSI(samples[idx], labels[idx]).
    virtual void get_truth_joint_feature_vector (
        long idx,
        feature_vector_type& psi
    ) const
    {
        psi = make_psi(samples[idx], labels[idx]);
    }

    // separation_oracle() is more interesting.  dlib's structural SVM solver will call
    // separation_oracle() many times during the optimization.  Each time it will give it
    // the current value of the parameter weights and separation_oracle() is supposed to
    // find the label that most violates the structural SVM objective function for the
    // idx-th sample.  Then the separation oracle reports the corresponding PSI vector and
    // loss value.  To state this more precisely, the separation_oracle() member function
    // has the following contract:
    //   requires
    //       - 0 <= idx < get_num_samples()
    //       - current_solution.size() == get_num_dimensions()
    //   ensures
    //       - runs the separation oracle on the idx-th sample.  We define this as follows:
    //           - let X           == the idx-th training sample.
    //           - let PSI(X,y)    == the joint feature vector for input X and an arbitrary label y.
    //           - let F(X,y)      == dot(current_solution,PSI(X,y)).
    //           - let LOSS(idx,y) == the loss incurred for predicting that the idx-th sample
    //             has a label of y.  Note that LOSS() should always be >= 0 and should
    //             become exactly 0 when y is the correct label for the idx-th sample.
    //
    //               Then the separation oracle finds a Y such that:
    //                   Y = argmax over all y: LOSS(idx,y) + F(X,y)
    //                   (i.e. It finds the label which maximizes the above expression.)
    //
    //               Finally, we can define the outputs of this function as:
    //               - #loss == LOSS(idx,Y)
    //               - #psi == PSI(X,Y)
    virtual void separation_oracle (
        const long idx,
        const column_vector& current_solution,
        scalar_type& loss,
        feature_vector_type& psi
    ) const
    {
        // Note that the solver will use multiple threads to make concurrent calls to
        // separation_oracle(), therefore, you must implement it in a thread safe manner
        // (or disable threading by inheriting from structural_svm_problem instead of
        // structural_svm_problem_threaded).  However, if your separation oracle is not
        // very fast to execute you can get a very significant speed boost by using the
        // threaded solver.  In general, all you need to do to make your separation oracle
        // thread safe is to make sure it does not modify any global variables or members
        // of three_class_classifier_problem.  So it is usually easy to make thread safe.

        column_vector scores(3);

        // compute scores for each of the three classifiers
        scores = dot(rowm(current_solution, range(0,2)),  samples[idx]),
                 dot(rowm(current_solution, range(3,5)),  samples[idx]),
                 dot(rowm(current_solution, range(6,8)),  samples[idx]);

        // Add in the loss-augmentation.  Recall that we maximize LOSS(idx,y) + F(X,y) in
        // the separate oracle, not just F(X,y) as we normally would in predict_label().
        // Therefore, we must add in this extra amount to account for the loss-augmentation.
        // For our simple multi-class classifier, we incur a loss of 1 if we don't predict
        // the correct label and a loss of 0 if we get the right label.
        if (labels[idx] != 0)
            scores(0) += 1;
        if (labels[idx] != 1)
            scores(1) += 1;
        if (labels[idx] != 2)
            scores(2) += 1;

        // Now figure out which classifier has the largest loss-augmented score.
        const int max_scoring_label = index_of_max(scores);
        // And finally record the loss that was associated with that predicted label.
        // Again, the loss is 1 if the label is incorrect and 0 otherwise.
        if (max_scoring_label == labels[idx])
            loss = 0;
        else
            loss = 1;

        // Finally, compute the PSI vector corresponding to the label we just found and
        // store it into psi for output.
        psi = make_psi(samples[idx], max_scoring_label);
    }

private:

    // Here we hold onto the training data by reference.  You can hold it by value or by
    // any other method you like.
    const std::vector<sample_type>& samples;
    const std::vector<int>& labels;
};

// ----------------------------------------------------------------------------------------

// This function puts it all together.  In here we use the three_class_classifier_problem
// along with dlib's oca cutting plane solver to find the optimal weights given our
// training data.
column_vector train_three_class_classifier (
    const std::vector<sample_type>& samples,
    const std::vector<int>& labels
)
{
    const unsigned long num_threads = 4;
    three_class_classifier_problem problem(samples, labels, num_threads);

    // Before we run the solver we set up some general parameters.  First,
    // you can set the C parameter of the structural SVM by calling set_c().
    problem.set_c(1);

    // The epsilon parameter controls the stopping tolerance.  The optimizer will run until
    // R(w) is within epsilon of its optimal value. If you don't set this then it defaults
    // to 0.001.
    problem.set_epsilon(0.0001);

    // Uncomment this and the optimizer will print its progress to standard out.  You will
    // be able to see things like the current risk gap.  The optimizer continues until the
    // risk gap is below epsilon.
    //problem.be_verbose();

    // The optimizer uses an internal cache to avoid unnecessary calls to your
    // separation_oracle() routine.  This parameter controls the size of that cache.
    // Bigger values use more RAM and might make the optimizer run faster.  You can also
    // disable it by setting it to 0 which is good to do when your separation_oracle is
    // very fast.  If you don't call this function it defaults to a value of 5.
    //problem.set_max_cache_size(20);

    column_vector weights;
    // Finally, we create the solver and then run it.
    oca solver;
    solver(problem, weights);

    // Alternatively, if you wanted to require that the learned weights are all
    // non-negative then you can call the solver as follows and it will put a constraint on
    // the optimization problem which causes all elements of weights to be >= 0.
    //solver(problem, weights, problem.get_num_dimensions());

    return weights;
}

// ----------------------------------------------------------------------------------------


dlib C++ Library - svr_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*
    This is an example illustrating the use of the epsilon-insensitive support vector
    regression object from the dlib C++ Library.

    In this example we will draw some points from the sinc() function and do a
    non-linear regression on them.
*/

#include <iostream>
#include <vector>

#include <dlib/svm.h>

using namespace std;
using namespace dlib;

// Here is the sinc function we will be trying to learn with the svr_trainer
// object.
double sinc(double x)
{
    if (x == 0)
        return 1;
    return sin(x)/x;
}

int main()
{
    // Here we declare that our samples will be 1 dimensional column vectors.
    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;

    std::vector<sample_type> samples;
    std::vector<double> targets;

    // The first thing we do is pick a few training points from the sinc() function.
    sample_type m;
    for (double x = -10; x <= 4; x += 1)
    {
        m(0) = x;

        samples.push_back(m);
        targets.push_back(sinc(x));
    }

    // Now setup a SVR trainer object.  It has three parameters, the kernel and
    // two parameters specific to SVR.
    svr_trainer<kernel_type> trainer;
    trainer.set_kernel(kernel_type(0.1));

    // This parameter is the usual regularization parameter.  It determines the trade-off
    // between trying to reduce the training error or allowing more errors but hopefully
    // improving the generalization of the resulting function.  Larger values encourage exact
    // fitting while smaller values of C may encourage better generalization.
    trainer.set_c(10);

    // Epsilon-insensitive regression means we do regression but stop trying to fit a data
    // point once it is "close enough" to its target value.  This parameter is the value that
    // controls what we mean by "close enough".  In this case, I'm saying I'm happy if the
    // resulting regression function gets within 0.001 of the target value.
    trainer.set_epsilon_insensitivity(0.001);

    // Now do the training and save the results
    decision_function<kernel_type> df = trainer.train(samples, targets);

    // now we output the value of the sinc function for a few test points as well as the
    // value predicted by SVR.
    m(0) = 2.5; cout << sinc(m(0)) << "   " << df(m) << endl;
    m(0) = 0.1; cout << sinc(m(0)) << "   " << df(m) << endl;
    m(0) = -4;  cout << sinc(m(0)) << "   " << df(m) << endl;
    m(0) = 5.0; cout << sinc(m(0)) << "   " << df(m) << endl;

    // The output is as follows:
    //  0.239389   0.23905
    //  0.998334   0.997331
    // -0.189201   -0.187636
    // -0.191785   -0.218924

    // The first column is the true value of the sinc function and the second
    // column is the output from the SVR estimate.

    // We can also do 5-fold cross-validation and find the mean squared error and R-squared
    // values.  Note that we need to randomly shuffle the samples first.  See the svm_ex.cpp
    // for a discussion of why this is important.
    randomize_samples(samples, targets);
    cout << "MSE and R-Squared: "<< cross_validate_regression_trainer(trainer, samples, targets, 5) << endl;
    // The output is:
    // MSE and R-Squared: 1.65984e-05    0.999901


dlib C++ Library - surf_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is a simple example illustrating the use of the get_surf_points() function.  It
    pulls out SURF points from an input image and displays them on the screen as an overlay
    on the image.

    For a description of the SURF algorithm you should consult the following papers:
        This is the original paper which introduced the algorithm:
            SURF: Speeded Up Robust Features
            By Herbert Bay, Tinne Tuytelaars, and Luc Van Gool

        This paper provides a nice detailed overview of how the algorithm works:
            Notes on the OpenSURF Library by Christopher Evans

*/

#include <dlib/image_keypoint/draw_surf_points.h>
#include <dlib/image_io.h>
#include <dlib/image_keypoint.h>
#include <fstream>

using namespace std;
using namespace dlib;

//  ----------------------------------------------------------------------------

int main(int argc, char** argv)
{
    try
    {
        // make sure the user entered an argument to this program
        if (argc != 2)
        {
            cout << "error, you have to enter a BMP file as an argument to this program" << endl;
            return 1;
        }

        // Here we declare an image object that can store rgb_pixels.  Note that in dlib
        // there is no explicit image object, just a 2D array and various pixel types.
        array2d<rgb_pixel> img;

        // Now load the image file into our image.  If something is wrong then load_image()
        // will throw an exception.  Also, if you linked with libpng and libjpeg then
        // load_image() can load PNG and JPEG files in addition to BMP files.
        load_image(img, argv[1]);

        // Get SURF points from the image.  Note that get_surf_points() has some optional
        // arguments that allow you to control the number of points you get back.  Here we
        // simply take the default.
        std::vector<surf_point> sp = get_surf_points(img);
        cout << "number of SURF points found: "<< sp.size() << endl;

        if (sp.size() > 0)
        {
            // A surf_point object contains a lot of information describing each point.
            // The most important fields are shown below:
            cout << "center of first SURF point: "<< sp[0].p.center << endl;
            cout << "pyramid scale:     " << sp[0].p.scale << endl;
            cout << "SURF descriptor: \n" << sp[0].des << endl;
        }

        // Create a window to display the input image and the SURF points.  (Note that
        // you can zoom into the window by holding CTRL and scrolling the mouse wheel)
        image_window my_window(img);
        draw_surf_points(my_window, sp);

        // wait until the user closes the window before we let the program
        // terminate.
        my_window.wait_until_closed();
    }
    catch (exception& e)
    {
        cout << "exception thrown: " << e.what() << endl;
    }
}

//  ----------------------------------------------------------------------------


dlib C++ Library - svm_rank_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example illustrating the use of the SVM-Rank tool from the dlib
    C++ Library.  This is a tool useful for learning to rank objects.  For
    example, you might use it to learn to rank web pages in response to a
    user's query.  The idea being to rank the most relevant pages higher than
    non-relevant pages.

    In this example, we will create a simple test dataset and show how to learn
    a ranking function from it.  The purpose of the function will be to give
    "relevant" objects higher scores than "non-relevant" objects.  The idea is
    that you use this score to order the objects so that the most relevant
    objects come to the top of the ranked list.

    Note that we use dense vectors (i.e. dlib::matrix objects) in this example,
    however, the ranking tools can also use sparse vectors as well.  See
    svm_sparse_ex.cpp for an example.
*/

#include <dlib/svm.h>
#include <iostream>

using namespace std;
using namespace dlib;

int main()
{
    try
    {
        // Make a typedef for the kind of object we will be ranking.  In this
        // example, we are ranking 2-dimensional vectors.
        typedef matrix<double,2,1> sample_type;

        // Now let's make some testing data.  To make it really simple, let's
        // suppose that vectors with positive values in the first dimension
        // should rank higher than other vectors.  So what we do is make
        // examples of relevant (i.e. high ranking) and non-relevant (i.e. low
        // ranking) vectors and store them into a ranking_pair object like so:
        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);

        // Now that we have some data, we can use a machine learning method to
        // learn a function that will give high scores to the relevant vectors
        // and low scores to the non-relevant vectors.

        // The first thing we do is select the kernel we want to use.  For the
        // svm_rank_trainer there are only two options.  The linear_kernel and
        // sparse_linear_kernel.  The later is used if you want to use sparse
        // vectors to represent your objects.  Since we are using dense vectors
        // (i.e. dlib::matrix objects to represent the vectors) we use the
        // linear_kernel.
        typedef linear_kernel<sample_type> kernel_type;

        // Now make a trainer and tell it to learn a ranking function based on
        // our data.
        svm_rank_trainer<kernel_type> trainer;
        decision_function<kernel_type> rank = trainer.train(data);

        // Now if you call rank on a vector it will output a ranking score.  In
        // particular, the ranking score for relevant vectors should be larger
        // than the score for non-relevant vectors.
        cout << "ranking score for a relevant vector:     " << rank(data.relevant[0]) << endl;
        cout << "ranking score for a non-relevant vector: " << rank(data.nonrelevant[0]) << endl;
        // These output the following:
        /*
            ranking score for a relevant vector:     0.5
            ranking score for a non-relevant vector: -0.5
        */

        // If we want an overall measure of ranking accuracy we can compute the
        // ordering accuracy and mean average precision values by calling
        // test_ranking_function().  In this case, the ordering accuracy tells
        // us how often a non-relevant vector was ranked ahead of a relevant
        // vector.  This function will return a 1 by 2 matrix containing these
        // measures.  In this case, it returns 1 1 indicating that the rank
        // function outputs a perfect ranking.
        cout << "testing (ordering accuracy, mean average precision): " << test_ranking_function(rank, data) << endl;

        // We can also see the ranking weights:
        cout << "learned ranking weights: \n" << rank.basis_vectors(0) << endl;
        // In this case they are:
        //  0.5
        // -0.5

        // In the above example, our data contains just two sets of objects.
        // The relevant set and non-relevant set.  The trainer is attempting to
        // find a ranking function that gives every relevant vector a higher
        // score than every non-relevant vector.  Sometimes what you want to do
        // is a little more complex than this.
        //
        // For example, in the web page ranking example we have to rank pages
        // based on a user's query.  In this case, each query will have its own
        // set of relevant and non-relevant documents.  What might be relevant
        // to one query may well be non-relevant to another.  So in this case
        // we don't have a single global set of relevant web pages and another
        // set of non-relevant web pages.
        //
        // To handle cases like this, we can simply give multiple ranking_pair
        // instances to the trainer.  Therefore, each ranking_pair would
        // represent the relevant/non-relevant sets for a particular query.  An
        // example is shown below (for simplicity, we reuse our data from above
        // to make 4 identical "queries").

        std::vector<ranking_pair<sample_type> > queries;
        queries.push_back(data);
        queries.push_back(data);
        queries.push_back(data);
        queries.push_back(data);

        // We train just as before.
        rank = trainer.train(queries);

        // Now that we have multiple ranking_pair instances, we can also use
        // cross_validate_ranking_trainer().  This performs cross-validation by
        // splitting the queries up into folds.  That is, it lets the trainer
        // train on a subset of ranking_pair instances and tests on the rest.
        // It does this over 4 different splits and returns the overall ranking
        // accuracy based on the held out data.  Just like test_ranking_function(),
        // it reports both the ordering accuracy and mean average precision.
        cout << "cross-validation (ordering accuracy, mean average precision): "
             << cross_validate_ranking_trainer(trainer, queries, 4) << endl;

    }
    catch (std::exception& e)
    {
        cout << e.what() << endl;


dlib C++ Library - thread_function_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*
    This is a very simple example that illustrates the use of the
    thread_function object from the dlib C++ Library.

    The output of the programs should look like this:

        45.6
        9.999
        I have no args!
        val: 3
*/

#include <iostream>
#include <dlib/threads.h>
#include <dlib/ref.h>

using namespace dlib;
using namespace std;

void thread_1(double a)
{
    cout << a << endl;
}

void thread_2 ()
{
    cout << "I have no args!" << endl;
}

void thread_increment(double& a)
{
    a += 1;
}

int main()
{
    // create a thread that will call thread_1(45.6)
    thread_function t1(thread_1,45.6);
    // wait for the t1 thread to end
    t1.wait();

    // create a thread that will call thread_1(9.999)
    thread_function t2(thread_1,9.999);
    // wait for the t2 thread to end
    t2.wait();

    // create a thread that will call thread_2()
    thread_function t3(thread_2);

    // Note that we can also use the ref() function to pass a variable
    // to a thread by reference.  For example, the thread below adds
    // one to val.
    double val = 2;
    thread_function t4(thread_increment, dlib::ref(val));
    t4.wait(); // wait for t4 to finish before printing val.
    // Print val.  It will now have a value of 3.
    cout << "val: " << val << endl;

    // At this point we will automatically wait for t3 to end because
    // the destructor for thread_function objects always wait for their
    // thread to terminate.


dlib C++ Library - thread_pool_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example illustrating the use of the thread_pool
    object from the dlib C++ Library.

    This is a very simple example.  It creates a thread pool with 3
    threads and then sends a few simple tasks to the pool.
*/

#include <dlib/threads.h>
#include <dlib/misc_api.h>  // for dlib::sleep
#include <dlib/logger.h>
#include <vector>

using namespace dlib;

// We will be using the dlib logger object to print out messages in this example
// because its output is timestamped and labeled with the thread that the log
// message came from.  So this will make it easier to see what is going on in
// this example.  Here we make an instance of the logger.  See the logger
// documentation and examples for detailed information regarding its use.
logger dlog("main");

// Here we make an instance of the thread pool object
thread_pool tp(3);

// ----------------------------------------------------------------------------------------

class test
{
    /*
        The thread_pool accepts "tasks" from the user and schedules them for
        execution in one of its threads when one becomes available.  Each task
        is just a request to call a function.  So here we create a class called
        test with a few member functions which we will have the thread pool call
        as tasks.
    */
public:

    void task()
    {
        dlog << LINFO << "task start";

        future<int> var;

        var = 1;

        // Here we ask the thread pool to call this->subtask() and this->subtask2().
        // Note that calls to add_task() will return immediately if there is an
        // available thread to hand the task off to.  However, if there isn't a
        // thread ready then add_task() blocks until there is such a thread.
        // Also note that since task() is executed within the thread pool (see main() below)
        // calls to add_task() will execute the requested task within the calling thread
        // in cases where the thread pool is full.  This means it is always safe to
        // spawn subtasks from within another task, which is what we are doing here.
        tp.add_task(*this,&test::subtask,var); // schedule call to this->subtask(var)
        tp.add_task(*this,&test::subtask2);    // schedule call to this->subtask2()

        // Since var is a future, this line will wait for the test::subtask task to
        // finish before allowing us to access the contents of var.  Then var will
        // return the integer it contains.  In this case result will be assigned
        // the value 2 since var was incremented by subtask().
        int result = var;
        // print out the result
        dlog << LINFO << "var = " << result;

        // Wait for all the tasks we have started to finish.  Note that
        // wait_for_all_tasks() only waits for tasks which were started
        // by the calling thread.  So you don't have to worry about other
        // unrelated parts of your application interfering.  In this case
        // it just waits for subtask2() to finish.
        tp.wait_for_all_tasks();

        dlog << LINFO << "task end" ;
    }

    void subtask(int& a)
    {
        dlib::sleep(200);
        a = a + 1;
        dlog << LINFO << "subtask end ";
    }

    void subtask2()
    {
        dlib::sleep(300);
        dlog << LINFO << "subtask2 end ";
    }

};

// ----------------------------------------------------------------------------------------

class add_value
{
public:
    add_value(int value):val(value) { }

    void operator()( int& a )
    {
        a += val;
    }

private:
    int val;
};

// ----------------------------------------------------------------------------------------

int main()
{
    // tell the logger to print out everything
    dlog.set_level(LALL);

    dlog << LINFO << "schedule a few tasks";

    test mytask;
    // Schedule the thread pool to call mytask.task().  Note that all forms of add_task()
    // pass in the task object by reference.  This means you must make sure, in this case,
    // that mytask isn't destructed until after the task has finished executing.
    tp.add_task(mytask, &test::task);

    // You can also pass task objects to a thread pool by value.  So in this case we don't
    // have to worry about keeping our own instance of the task.  Here we construct a temporary
    // add_value object and pass it right in and everything works like it should.
    future<int> num = 3;
    tp.add_task_by_value(add_value(7), num);  // adds 7 to num
    int result = num.get();
    dlog << LINFO << "result = " << result;   // prints result = 10

// uncomment this line if your compiler supports the new C++0x lambda functions
//#define COMPILER_SUPPORTS_CPP0X_LAMBDA_FUNCTIONS
#ifdef COMPILER_SUPPORTS_CPP0X_LAMBDA_FUNCTIONS

    // In the above examples we had to explicitly create task objects which is
    // inconvenient.  If you have a compiler which supports C++0x lambda functions
    // then you can use the following simpler method.

    // make a task which will just log a message
    tp.add_task_by_value([](){
                         dlog << LINFO << "A message from a lambda function running in another thread.";
                         });

    // Here we make 10 different tasks, each assigns a different value into
    // the elements of the vector vect.
    std::vector<int> vect(10);
    for (unsigned long i = 0; i < vect.size(); ++i)
    {
        // Make a lambda function which takes vect by reference and i by value.  So what
        // will happen is each assignment statement will run in a thread in the thread_pool.
        tp.add_task_by_value([&vect,i](){
                             vect[i] = i;
                             });
    }
    // Wait for all tasks which were requested by the main thread to complete.
    tp.wait_for_all_tasks();
    for (unsigned long i = 0; i < vect.size(); ++i)
    {
        dlog << LINFO << "vect["<<i<<"]: " << vect[i];
    }
#endif

    /* A possible run of this program might produce the following output (the first column is
       the time the log message occurred and the value in [] is the thread id for the thread
       that generated the log message):

    1 INFO  [0] main: schedule a few tasks
    1 INFO  [1] main: task start
    1 INFO  [0] main: result = 10
  201 INFO  [2] main: subtask end
  201 INFO  [1] main: var = 2
  201 INFO  [2] main: A message from a lambda function running in another thread.
  301 INFO  [3] main: subtask2 end
  301 INFO  [1] main: task end
  301 INFO  [0] main: vect[0]: 0
  301 INFO  [0] main: vect[1]: 1
  301 INFO  [0] main: vect[2]: 2
  301 INFO  [0] main: vect[3]: 3
  301 INFO  [0] main: vect[4]: 4
  301 INFO  [0] main: vect[5]: 5
  301 INFO  [0] main: vect[6]: 6
  301 INFO  [0] main: vect[7]: 7
  301 INFO  [0] main: vect[8]: 8
  301 INFO  [0] main: vect[9]: 9
    */


dlib C++ Library - threaded_object_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example illustrating the use of the threaded_object
    from the dlib C++ Library.

    This is a very simple example.  It creates a single thread that
    just prints messages to the screen.
*/

#include <iostream>
#include <dlib/threads.h>
#include <dlib/misc_api.h>  // for dlib::sleep

using namespace std;
using namespace dlib;

class my_object : public threaded_object
{
public:
    my_object()
    {
        // Start our thread going in the thread() function
        start();
    }

    ~my_object()
    {
        // Tell the thread() function to stop.  This will cause should_stop() to
        // return true so the thread knows what to do.
        stop();

        // Wait for the thread to stop before letting this object destruct itself.
        // Also note, you are *required* to wait for the thread to end before
        // letting this object destruct itself.
        wait();
    }

private:

    void thread()
    {
        // This is our thread.  It will loop until it is told that it should terminate.
        while (should_stop() == false)
        {
            cout << "hurray threads!" << endl;
            dlib::sleep(500);
        }
    }
};

int main()
{
    // Create an instance of our threaded object.
    my_object t;

    dlib::sleep(4000);

    // Tell the threaded object to pause its thread.  This causes the
    // thread to block on its next call to should_stop().
    t.pause();

    dlib::sleep(3000);
    cout << "starting thread back up from paused state" << endl;

    // Tell the thread to unpause itself.  This causes should_stop() to unblock
    // and to let the thread continue.
    t.start();

    dlib::sleep(4000);

    // Let the program end.  When t is destructed it will gracefully terminate your
    // thread because we have set the destructor up to do so.


dlib C++ Library - threads_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt

/*

    This is an example illustrating the use of the threading api from the dlib
    C++ Library.

    This is a very simple example.  It makes some threads and just waits for
    them to terminate.  It should be noted that this example shows how to use
    the lowest level of the dlib threading API.  Often, other higher level tools
    are more appropriate.  For examples of higher level tools see the
    documentation on the pipe, thread_pool, thread_function, or
    threaded_object.
*/

#include <iostream>
#include <dlib/threads.h>
#include <dlib/misc_api.h>  // for dlib::sleep

using namespace std;
using namespace dlib;

int thread_count = 10;
dlib::mutex count_mutex; // This is a mutex we will use to guard the thread_count variable.  Note that the mutex doesn't know
                   // anything about the thread_count variable.  Only our usage of a mutex determines what it guards.
                   // In this case we are going to make sure this mutex is always locked before we touch the
                   // thread_count variable.

signaler count_signaler(count_mutex);  // This is a signaler we will use to signal when
                                       // the thread_count variable is changed.  Note that it is
                                       // associated with the count_mutex.  This means that
                                       // when you call count_signaler.wait() it will automatically
                                       // unlock count_mutex for you.

void thread (void*)
{
    // just sleep for a second
    dlib::sleep(1000);

    // Now signal that this thread is ending.  First we should get a lock on the
    // count_mutex so we can safely mess with thread_count.  A convenient way to do this
    // is to use an auto_mutex object.  Its constructor takes a mutex object and locks
    // it right away, it then unlocks the mutex when the auto_mutex object is destructed.
    // Note that this happens even if an exception is thrown.  So it ensures that you
    // don't somehow quit your function without unlocking your mutex.
    auto_mutex locker(count_mutex);
    --thread_count;
    // Now we signal this change.  This will cause one thread that is currently waiting
    // on a call to count_signaler.wait() to unblock.
    count_signaler.signal();

    // At the end of this function locker goes out of scope and gets destructed, thus
    // unlocking count_mutex for us.
}

int main()
{

    cout << "Create some threads" << endl;
    for (int i = 0; i < thread_count; ++i)
    {
        // Create some threads.  This 0 we are passing in here is the argument that gets
        // passed to the thread function (a void pointer) but we aren't using it in this
        // example program so i'm just using 0.
        create_new_thread(thread,0);
    }
    cout << "Done creating threads, now we wait for them to end" << endl;

    // Again we use an auto_mutex to get a lock.  We don't have to do it this way
    // but it is convenient.  Also note that we can name the auto_mutex object anything.
    auto_mutex some_random_unused_name(count_mutex);

    // Now we wait in a loop for thread_count to be 0.  Note that it is important to do this in a
    // loop because it is possible to get spurious wakeups from calls to wait() on some
    // platforms.  So this guards against that and it also makes the code easy to understand.
    while (thread_count > 0)
        count_signaler.wait(); // This puts this thread to sleep until we get a signal to look at the
                               // thread_count variable.  It also unlocks the count_mutex before it
                               // goes to sleep and then relocks it when it wakes back up.  Again,
                               // note that it is possible for wait() to return even if no one signals you.
                               // This is just weird junk you have to deal with on some platforms.  So
                               // don't try to be clever and write code that depends on the number of
                               // times wait() returns because it won't always work.

    cout << "All threads done, ending program" << endl;


dlib C++ Library - timer_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt

/*
    This is an example illustrating the use of the timer object from the dlib C++ Library.

    The timer is an object that calls some user specified member function at regular
    intervals from another thread.
*/

#include <dlib/timer.h>
#include <dlib/misc_api.h> // for dlib::sleep
#include <iostream>

using namespace dlib;
using namespace std;

// ----------------------------------------------------------------------------------------

class timer_example
{
public:
    void action_function()
    {
        // print out a message so we can see that this function is being triggered
        cout << "action_function() called" << endl;
    }
};

// ----------------------------------------------------------------------------------------

int main()
{
    timer_example e;

    // Here we construct our timer object.  It needs two things.  The second argument is
    // the member function it is going to call at regular intervals and the first argument
    // is the object instance it will call that member function on.
    timer<timer_example> t(e, &timer_example::action_function);

    // Set the timer object to trigger every second
    t.set_delay_time(1000);

    // Start the timer.  It will start calling the action function 1 second from this call
    // to start.
    t.start();

    // Sleep for 10 seconds before letting the program end.
    dlib::sleep(10000);

    // The timer will destruct itself properly and stop calling the action_function.
}

// ----------------------------------------------------------------------------------------


dlib C++ Library - train_object_detector.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example showing how you might use dlib to create a reasonably
    functional command line tool for object detection.  This example assumes
    you are familiar with the contents of at least the following example
    programs:
        - fhog_object_detector_ex.cpp
        - compress_stream_ex.cpp

    This program is a command line tool for learning to detect objects in images.
    Therefore, to create an object detector it requires a set of annotated training
    images.  To create this annotated data you will need to use the imglab tool
    included with dlib.  It is located in the tools/imglab folder and can be compiled
    using the following commands.
        cd tools/imglab
        mkdir build
        cd build
        cmake ..
        cmake --build . --config Release
    Note that you may need to install CMake (www.cmake.org) for this to work.

    Next, let's assume you have a folder of images called /tmp/images.  These images
    should contain examples of the objects you want to learn to detect.  You will
    use the imglab tool to label these objects.  Do this by typing the following
        ./imglab -c mydataset.xml /tmp/images
    This will create a file called mydataset.xml which simply lists the images in
    /tmp/images.  To annotate them run
        ./imglab mydataset.xml
    A window will appear showing all the images.  You can use the up and down arrow
    keys to cycle though the images and the mouse to label objects.  In particular,
    holding the shift key, left clicking, and dragging the mouse will allow you to
    draw boxes around the objects you wish to detect.  So next, label all the objects
    with boxes.  Note that it is important to label all the objects since any object
    not labeled is implicitly assumed to be not an object we should detect.  If there
    are objects you are not sure about you should draw a box around them, then double
    click the box and press i.  This will cross out the box and mark it as "ignore".
    The training code in dlib will then simply ignore detections matching that box.

    Once you finish labeling objects go to the file menu, click save, and then close
    the program. This will save the object boxes back to mydataset.xml.  You can verify
    this by opening the tool again with
        ./imglab mydataset.xml
    and observing that the boxes are present.

    Returning to the present example program, we can compile it using cmake just as we
    did with the imglab tool.  Once compiled, we can issue the command
        ./train_object_detector -tv mydataset.xml
    which will train an object detection model based on our labeled data.  The model
    will be saved to the file object_detector.svm.  Once this has finished we can use
    the object detector to locate objects in new images with a command like
        ./train_object_detector some_image.png
    This command will display some_image.png in a window and any detected objects will
    be indicated by a red box.

    Finally, to make running this example easy dlib includes some training data in the
    examples/faces folder.  Therefore, you can test this program out by running the
    following sequence of commands:
      ./train_object_detector -tv examples/faces/training.xml -u1 --flip
      ./train_object_detector --test examples/faces/testing.xml -u1
      ./train_object_detector examples/faces/*.jpg -u1
    That will make a face detector that performs perfectly on the test images listed in
    testing.xml and then it will show you the detections on all the images.
*/

#include <dlib/svm_threaded.h>
#include <dlib/string.h>
#include <dlib/gui_widgets.h>
#include <dlib/image_processing.h>
#include <dlib/data_io.h>
#include <dlib/cmd_line_parser.h>

#include <iostream>
#include <fstream>

using namespace std;
using namespace dlib;

// ----------------------------------------------------------------------------------------

void pick_best_window_size (
    const std::vector<std::vector<rectangle> >& boxes,
    unsigned long& width,
    unsigned long& height,
    const unsigned long target_size
)
/*!
    ensures
        - Finds the average aspect ratio of the elements of boxes and outputs a width
          and height such that the aspect ratio is equal to the average and also the
          area is equal to target_size.  That is, the following will be approximately true:
            - #width*#height == target_size
            - #width/#height == the average aspect ratio of the elements of boxes.
!*/
{
    // find the average width and height
    running_stats<double> avg_width, avg_height;
    for (unsigned long i = 0; i < boxes.size(); ++i)
    {
        for (unsigned long j = 0; j < boxes[i].size(); ++j)
        {
            avg_width.add(boxes[i][j].width());
            avg_height.add(boxes[i][j].height());
        }
    }

    // now adjust the box size so that it is about target_pixels pixels in size
    double size = avg_width.mean()*avg_height.mean();
    double scale = std::sqrt(target_size/size);

    width = (unsigned long)(avg_width.mean()*scale+0.5);
    height = (unsigned long)(avg_height.mean()*scale+0.5);
    // make sure the width and height never round to zero.
    if (width == 0)
        width = 1;
    if (height == 0)
        height = 1;
}

// ----------------------------------------------------------------------------------------

bool contains_any_boxes (
    const std::vector<std::vector<rectangle> >& boxes
)
{
    for (unsigned long i = 0; i < boxes.size(); ++i)
    {
        if (boxes[i].size() != 0)
            return true;
    }
    return false;
}

// ----------------------------------------------------------------------------------------

void throw_invalid_box_error_message (
    const std::string& dataset_filename,
    const std::vector<std::vector<rectangle> >& removed,
    const unsigned long target_size
)
{
    image_dataset_metadata::dataset data;
    load_image_dataset_metadata(data, dataset_filename);

    std::ostringstream sout;
    sout << "Error!  An impossible set of object boxes was given for training. ";
    sout << "All the boxes need to have a similar aspect ratio and also not be ";
    sout << "smaller than about " << target_size << " pixels in area. ";
    sout << "The following images contain invalid boxes:\n";
    std::ostringstream sout2;
    for (unsigned long i = 0; i < removed.size(); ++i)
    {
        if (removed[i].size() != 0)
        {
            const std::string imgname = data.images[i].filename;
            sout2 << "  " << imgname << "\n";
        }
    }
    throw error("\n"+wrap_string(sout.str()) + "\n" + sout2.str());
}

// ----------------------------------------------------------------------------------------

int main(int argc, char** argv)
{
    try
    {
        command_line_parser parser;
        parser.add_option("h","Display this help message.");
        parser.add_option("t","Train an object detector and save the detector to disk.");
        parser.add_option("cross-validate",
                          "Perform cross-validation on an image dataset and print the results.");
        parser.add_option("test", "Test a trained detector on an image dataset and print the results.");
        parser.add_option("u", "Upsample each input image <arg> times. Each upsampling quadruples the number of pixels in the image (default: 0).", 1);

        parser.set_group_name("training/cross-validation sub-options");
        parser.add_option("v","Be verbose.");
        parser.add_option("folds","When doing cross-validation, do <arg> folds (default: 3).",1);
        parser.add_option("c","Set the SVM C parameter to <arg> (default: 1.0).",1);
        parser.add_option("threads", "Use <arg> threads for training (default: 4).",1);
        parser.add_option("eps", "Set training epsilon to <arg> (default: 0.01).", 1);
        parser.add_option("target-size", "Set size of the sliding window to about <arg> pixels in area (default: 80*80).", 1);
        parser.add_option("flip", "Add left/right flipped copies of the images into the training dataset.  Useful when the objects "
            "you want to detect are left/right symmetric.");

        parser.parse(argc, argv);

        // Now we do a little command line validation.  Each of the following functions
        // checks something and throws an exception if the test fails.
        const char* one_time_opts[] = {"h", "v", "t", "cross-validate", "c", "threads", "target-size",
                                        "folds", "test", "eps", "u", "flip"};
        parser.check_one_time_options(one_time_opts); // Can't give an option more than once
        // Make sure the arguments to these options are within valid ranges if they are supplied by the user.
        parser.check_option_arg_range("c", 1e-12, 1e12);
        parser.check_option_arg_range("eps", 1e-5, 1e4);
        parser.check_option_arg_range("threads", 1, 1000);
        parser.check_option_arg_range("folds", 2, 100);
        parser.check_option_arg_range("u", 0, 8);
        parser.check_option_arg_range("target-size", 4*4, 10000*10000);
        const char* incompatible[] = {"t", "cross-validate", "test"};
        parser.check_incompatible_options(incompatible);
        // You are only allowed to give these training_sub_ops if you also give either -t or --cross-validate.
        const char* training_ops[] = {"t", "cross-validate"};
        const char* training_sub_ops[] = {"v", "c", "threads", "target-size", "eps", "flip"};
        parser.check_sub_options(training_ops, training_sub_ops);
        parser.check_sub_option("cross-validate", "folds");

        if (parser.option("h"))
        {
            cout << "Usage: train_object_detector [options] <image dataset file|image file>\n";
            parser.print_options();

            return EXIT_SUCCESS;
        }

        typedef scan_fhog_pyramid<pyramid_down<6> > image_scanner_type;
        // Get the upsample option from the user but use 0 if it wasn't given.
        const unsigned long upsample_amount = get_option(parser, "u", 0);

        if (parser.option("t") || parser.option("cross-validate"))
        {
            if (parser.number_of_arguments() != 1)
            {
                cout << "You must give an image dataset metadata XML file produced by the imglab tool." << endl;
                cout << "\nTry the -h option for more information." << endl;
                return EXIT_FAILURE;
            }

            dlib::array<array2d<unsigned char> > images;
            std::vector<std::vector<rectangle> > object_locations, ignore;

            cout << "Loading image dataset from metadata file " << parser[0] << endl;
            ignore = load_image_dataset(images, object_locations, parser[0]);
            cout << "Number of images loaded: " << images.size() << endl;

            // Get the options from the user, but use default values if they are not
            // supplied.
            const int threads = get_option(parser, "threads", 4);
            const double C   = get_option(parser, "c", 1.0);
            const double eps = get_option(parser, "eps", 0.01);
            unsigned int num_folds = get_option(parser, "folds", 3);
            const unsigned long target_size = get_option(parser, "target-size", 80*80);
            // You can't do more folds than there are images.
            if (num_folds > images.size())
                num_folds = images.size();

            // Upsample images if the user asked us to do that.
            for (unsigned long i = 0; i < upsample_amount; ++i)
                upsample_image_dataset<pyramid_down<2> >(images, object_locations, ignore);

            image_scanner_type scanner;
            unsigned long width, height;
            pick_best_window_size(object_locations, width, height, target_size);
            scanner.set_detection_window_size(width, height);

            structural_object_detection_trainer<image_scanner_type> trainer(scanner);
            trainer.set_num_threads(threads);
            if (parser.option("v"))
                trainer.be_verbose();
            trainer.set_c(C);
            trainer.set_epsilon(eps);

            // Now make sure all the boxes are obtainable by the scanner.
            std::vector<std::vector<rectangle> > removed;
            removed = remove_unobtainable_rectangles(trainer, images, object_locations);
            // if we weren't able to get all the boxes to match then throw an error
            if (contains_any_boxes(removed))
            {
                unsigned long scale = upsample_amount+1;
                scale = scale*scale;
                throw_invalid_box_error_message(parser[0], removed, target_size/scale);
            }

            if (parser.option("flip"))
                add_image_left_right_flips(images, object_locations, ignore);

            if (parser.option("t"))
            {
                // Do the actual training and save the results into the detector object.
                object_detector<image_scanner_type> detector = trainer.train(images, object_locations, ignore);

                cout << "Saving trained detector to object_detector.svm" << endl;
                serialize("object_detector.svm") << detector;

                cout << "Testing detector on training data..." << endl;
                cout << "Test detector (precision,recall,AP): " << test_object_detection_function(detector, images, object_locations) << endl;
            }
            else
            {
                // shuffle the order of the training images
                randomize_samples(images, object_locations);

                cout << num_folds << "-fold cross validation (precision,recall,AP): "
                     << cross_validate_object_detection_trainer(trainer, images, object_locations, ignore, num_folds) << endl;
            }

            cout << "Parameters used: " << endl;
            cout << "  threads:                 "<< threads << endl;
            cout << "  C:                       "<< C << endl;
            cout << "  eps:                     "<< eps << endl;
            cout << "  target-size:             "<< target_size << endl;
            cout << "  detection window width:  "<< width << endl;
            cout << "  detection window height: "<< height << endl;
            cout << "  upsample this many times : "<< upsample_amount << endl;
            if (parser.option("flip"))
                cout << "  trained using left/right flips." << endl;
            if (parser.option("cross-validate"))
                cout << "  num_folds: "<< num_folds << endl;
            cout << endl;

            return EXIT_SUCCESS;
        }

        // The rest of the code is devoted to testing an already trained object detector.

        if (parser.number_of_arguments() == 0)
        {
            cout << "You must give an image or an image dataset metadata XML file produced by the imglab tool." << endl;
            cout << "\nTry the -h option for more information." << endl;
            return EXIT_FAILURE;
        }

        // load a previously trained object detector and try it out on some data
        ifstream fin("object_detector.svm", ios::binary);
        if (!fin)
        {
            cout << "Can't find a trained object detector file object_detector.svm. " << endl;
            cout << "You need to train one using the -t option." << endl;
            cout << "\nTry the -h option for more information." << endl;
            return EXIT_FAILURE;

        }
        object_detector<image_scanner_type> detector;
        deserialize(detector, fin);

        dlib::array<array2d<unsigned char> > images;
        // Check if the command line argument is an XML file
        if (tolower(right_substr(parser[0],".")) == "xml")
        {
            std::vector<std::vector<rectangle> > object_locations, ignore;
            cout << "Loading image dataset from metadata file " << parser[0] << endl;
            ignore = load_image_dataset(images, object_locations, parser[0]);
            cout << "Number of images loaded: " << images.size() << endl;

            // Upsample images if the user asked us to do that.
            for (unsigned long i = 0; i < upsample_amount; ++i)
                upsample_image_dataset<pyramid_down<2> >(images, object_locations, ignore);

            if (parser.option("test"))
            {
                cout << "Testing detector on data..." << endl;
                cout << "Results (precision,recall,AP): " << test_object_detection_function(detector, images, object_locations, ignore) << endl;
                return EXIT_SUCCESS;
            }
        }
        else
        {
            // In this case, the user should have given some image files.  So just
            // load them.
            images.resize(parser.number_of_arguments());
            for (unsigned long i = 0; i < images.size(); ++i)
                load_image(images[i], parser[i]);

            // Upsample images if the user asked us to do that.
            for (unsigned long i = 0; i < upsample_amount; ++i)
            {
                for (unsigned long j = 0; j < images.size(); ++j)
                    pyramid_up(images[j]);
            }
        }

        // Test the detector on the images we loaded and display the results
        // in a window.
        image_window win;
        for (unsigned long i = 0; i < images.size(); ++i)
        {
            // Run the detector on images[i]
            const std::vector<rectangle> rects = detector(images[i]);
            cout << "Number of detections: "<< rects.size() << endl;

            // Put the image and detections into the window.
            win.clear_overlay();
            win.set_image(images[i]);
            win.add_overlay(rects, rgb_pixel(255,0,0));

            cout << "Hit enter to see the next image.";
            cin.get();
        }

    }
    catch (exception& e)
    {
        cout << "\nexception thrown!" << endl;
        cout << e.what() << endl;
        cout << "\nTry the -h option for more information." << endl;
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

// ----------------------------------------------------------------------------------------


dlib C++ Library - train_shape_predictor_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This example program shows how to use dlib's implementation of the paper:
        One Millisecond Face Alignment with an Ensemble of Regression Trees by
        Vahid Kazemi and Josephine Sullivan, CVPR 2014

    In particular, we will train a face landmarking model based on a small dataset
    and then evaluate it.  If you want to visualize the output of the trained
    model on some images then you can run the face_landmark_detection_ex.cpp
    example program with sp.dat as the input model.

    It should also be noted that this kind of model, while often used for face
    landmarking, is quite general and can be used for a variety of shape
    prediction tasks.  But here we demonstrate it only on a simple face
    landmarking task.
*/

#include <dlib/image_processing.h>
#include <dlib/data_io.h>
#include <iostream>

using namespace dlib;
using namespace std;

// ----------------------------------------------------------------------------------------

std::vector<std::vector<double> > get_interocular_distances (
    const std::vector<std::vector<full_object_detection> >& objects
);
/*!
    ensures
        - returns an object D such that:
            - D[i][j] == the distance, in pixels, between the eyes for the face represented
              by objects[i][j].
!*/

// ----------------------------------------------------------------------------------------

int main(int argc, char** argv)
{
    try
    {
        // In this example we are going to train a shape_predictor based on the
        // small faces dataset in the examples/faces directory.  So the first
        // thing we do is load that dataset.  This means you need to supply the
        // path to this faces folder as a command line argument so we will know
        // where it is.
        if (argc != 2)
        {
            cout << "Give the path to the examples/faces directory as the argument to this" << endl;
            cout << "program.  For example, if you are in the examples folder then execute " << endl;
            cout << "this program by running: " << endl;
            cout << "   ./train_shape_predictor_ex faces" << endl;
            cout << endl;
            return 0;
        }
        const std::string faces_directory = argv[1];
        // The faces directory contains a training dataset and a separate
        // testing dataset.  The training data consists of 4 images, each
        // annotated with rectangles that bound each human face along with 68
        // face landmarks on each face.  The idea is to use this training data
        // to learn to identify the position of landmarks on human faces in new
        // images.
        //
        // Once you have trained a shape_predictor it is always important to
        // test it on data it wasn't trained on.  Therefore, we will also load
        // a separate testing set of 5 images.  Once we have a shape_predictor
        // created from the training data we will see how well it works by
        // running it on the testing images.
        //
        // So here we create the variables that will hold our dataset.
        // images_train will hold the 4 training images and faces_train holds
        // the locations and poses of each face in the training images.  So for
        // example, the image images_train[0] has the faces given by the
        // full_object_detections in faces_train[0].
        dlib::array<array2d<unsigned char> > images_train, images_test;
        std::vector<std::vector<full_object_detection> > faces_train, faces_test;

        // Now we load the data.  These XML files list the images in each
        // dataset and also contain the positions of the face boxes and
        // landmarks (called parts in the XML file).  Obviously you can use any
        // kind of input format you like so long as you store the data into
        // images_train and faces_train.  But for convenience dlib comes with
        // tools for creating and loading XML image dataset files.  Here you see
        // how to load the data.  To create the XML files you can use the imglab
        // tool which can be found in the tools/imglab folder.  It is a simple
        // graphical tool for labeling objects in images.  To see how to use it
        // read the tools/imglab/README.txt file.
        load_image_dataset(images_train, faces_train, faces_directory+"/training_with_face_landmarks.xml");
        load_image_dataset(images_test, faces_test, faces_directory+"/testing_with_face_landmarks.xml");

        // Now make the object responsible for training the model.
        shape_predictor_trainer trainer;
        // This algorithm has a bunch of parameters you can mess with.  The
        // documentation for the shape_predictor_trainer explains all of them.
        // You should also read Kazemi's paper which explains all the parameters
        // in great detail.  However, here I'm just setting three of them
        // differently than their default values.  I'm doing this because we
        // have a very small dataset.  In particular, setting the oversampling
        // to a high amount (300) effectively boosts the training set size, so
        // that helps this example.
        trainer.set_oversampling_amount(300);
        // I'm also reducing the capacity of the model by explicitly increasing
        // the regularization (making nu smaller) and by using trees with
        // smaller depths.
        trainer.set_nu(0.05);
        trainer.set_tree_depth(2);

        // Tell the trainer to print status messages to the console so we can
        // see how long the training will take.
        trainer.be_verbose();

        // Now finally generate the shape model
        shape_predictor sp = trainer.train(images_train, faces_train);

        // Now that we have a model we can test it.  This function measures the
        // average distance between a face landmark output by the
        // shape_predictor and where it should be according to the truth data.
        // Note that there is an optional 4th argument that lets us rescale the
        // distances.  Here we are causing the output to scale each face's
        // distances by the interocular distance, as is customary when
        // evaluating face landmarking systems.
        cout << "mean training error: "<<
            test_shape_predictor(sp, images_train, faces_train, get_interocular_distances(faces_train)) << endl;

        // The real test is to see how well it does on data it wasn't trained
        // on.  We trained it on a very small dataset so the accuracy is not
        // extremely high, but it's still doing quite good.  Moreover, if you
        // train it on one of the large face landmarking datasets you will
        // obtain state-of-the-art results, as shown in the Kazemi paper.
        cout << "mean testing error:  "<<
            test_shape_predictor(sp, images_test, faces_test, get_interocular_distances(faces_test)) << endl;

        // Finally, we save the model to disk so we can use it later.
        serialize("sp.dat") << sp;
    }
    catch (exception& e)
    {
        cout << "\nexception thrown!" << endl;
        cout << e.what() << endl;
    }
}

// ----------------------------------------------------------------------------------------

double interocular_distance (
    const full_object_detection& det
)
{
    dlib::vector<double,2> l, r;
    double cnt = 0;
    // Find the center of the left eye by averaging the points around
    // the eye.
    for (unsigned long i = 36; i <= 41; ++i)
    {
        l += det.part(i);
        ++cnt;
    }
    l /= cnt;

    // Find the center of the right eye by averaging the points around
    // the eye.
    cnt = 0;
    for (unsigned long i = 42; i <= 47; ++i)
    {
        r += det.part(i);
        ++cnt;
    }
    r /= cnt;

    // Now return the distance between the centers of the eyes
    return length(l-r);
}

std::vector<std::vector<double> > get_interocular_distances (
    const std::vector<std::vector<full_object_detection> >& objects
)
{
    std::vector<std::vector<double> > temp(objects.size());
    for (unsigned long i = 0; i < objects.size(); ++i)
    {
        for (unsigned long j = 0; j < objects[i].size(); ++j)
        {
            temp[i].push_back(interocular_distance(objects[i][j]));
        }
    }
    return temp;
}

// ----------------------------------------------------------------------------------------


dlib C++ Library - using_custom_kernels_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example showing how to define custom kernel functions for use with
    the machine learning tools in the dlib C++ Library.

    This example assumes you are somewhat familiar with the machine learning
    tools in dlib.  In particular, you should be familiar with the krr_trainer
    and the matrix object.  So you may want to read the krr_classification_ex.cpp
    and matrix_ex.cpp example programs if you haven't already.
*/

#include <iostream>
#include <dlib/svm.h>

using namespace std;
using namespace dlib;

// ----------------------------------------------------------------------------------------

/*
    Here we define our new kernel.  It is the UKF kernel from
        Facilitating the applications of support vector machine by using a new kernel
        by Rui Zhang and Wenjian Wang.

    In the context of the dlib library a kernel function object is an object with
    an interface with the following properties:
        - a public typedef named sample_type
        - a public typedef named scalar_type which should be a float, double, or
          long double type.
        - an overloaded operator() that operates on two items of sample_type
          and returns a scalar_type.
        - a public typedef named mem_manager_type that is an implementation of
          dlib/memory_manager/memory_manager_kernel_abstract.h or
          dlib/memory_manager_global/memory_manager_global_kernel_abstract.h or
          dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h
        - an overloaded == operator that tells you if two kernels are
          identical or not.

    Below we define such a beast for the UKF kernel.  In this case we are expecting the
    sample type (i.e. the T type) to be a dlib::matrix.  However, note that you can design
    kernels which operate on any type you like so long as you meet the above requirements.
*/

template < typename T >
struct ukf_kernel
{
    typedef typename T::type             scalar_type;
    typedef          T                   sample_type;
    // If your sample type, the T, doesn't have a memory manager then
    // you can use dlib::default_memory_manager here.
    typedef typename T::mem_manager_type mem_manager_type;

    ukf_kernel(const scalar_type g) : sigma(g) {}
    ukf_kernel() : sigma(0.1) {}

    scalar_type sigma;

    scalar_type operator() (
        const sample_type& a,
        const sample_type& b
    ) const
    {
        // This is the formula for the UKF kernel from the above referenced paper.
        return 1/(length_squared(a-b) + sigma);
    }

    bool operator== (
        const ukf_kernel& k
    ) const
    {
        return sigma == k.sigma;
    }
};

// ----------------------------------------------------------------------------------------

/*
    Here we define serialize() and deserialize() functions for our new kernel.  Defining
    these functions is optional.  However, if you don't define them you won't be able
    to save your learned decision_function objects to disk.
*/

template < typename T >
void serialize ( const ukf_kernel<T>& item, std::ostream& out)
{
    // save the state of the kernel to the output stream
    serialize(item.sigma, out);
}

template < typename T >
void deserialize ( ukf_kernel<T>& item, std::istream& in )
{
    deserialize(item.sigma, in);
}

// ----------------------------------------------------------------------------------------

/*
    This next thing, the kernel_derivative specialization is optional.  You only need
    to define it if you want to use the dlib::reduced2() or dlib::approximate_distance_function()
    routines.  If so, then you need to supply code for computing the derivative of your kernel as
    shown below.  Note also that you can only do this if your kernel operates on dlib::matrix
    objects which represent column vectors.
*/

namespace dlib
{
    template < typename T >
    struct kernel_derivative<ukf_kernel<T> >
    {
        typedef typename T::type             scalar_type;
        typedef          T                   sample_type;
        typedef typename T::mem_manager_type mem_manager_type;

        kernel_derivative(const ukf_kernel<T>& k_) : k(k_){}

        sample_type operator() (const sample_type& x, const sample_type& y) const
        {
            // return the derivative of the ukf kernel with respect to the second argument (i.e. y)
            return 2*(x-y)*std::pow(k(x,y),2);
        }

        const ukf_kernel<T>& k;
    };
}

// ----------------------------------------------------------------------------------------

int main()
{
    // We are going to be working with 2 dimensional samples and trying to perform
    // binary classification on them using our new ukf_kernel.
    typedef matrix<double, 2, 1> sample_type;

    typedef ukf_kernel<sample_type> kernel_type;

    // Now let's generate some training data
    std::vector<sample_type> samples;
    std::vector<double> labels;
    for (double r = -20; r <= 20; r += 0.9)
    {
        for (double c = -20; c <= 20; c += 0.9)
        {
            sample_type samp;
            samp(0) = r;
            samp(1) = c;
            samples.push_back(samp);

            // if this point is less than 13 from the origin
            if (sqrt(r*r + c*c) <= 13)
                labels.push_back(+1);
            else
                labels.push_back(-1);

        }
    }
    cout << "samples generated: " << samples.size() << endl;
    cout << "  number of +1 samples: " << sum(mat(labels) > 0) << endl;
    cout << "  number of -1 samples: " << sum(mat(labels) < 0) << endl;

    // A valid kernel must always give rise to kernel matrices which are symmetric
    // and positive semidefinite (i.e. have nonnegative eigenvalues).  This next
    // bit of code makes a kernel matrix and checks if it has these properties.
    const matrix<double> K = kernel_matrix(kernel_type(0.1), randomly_subsample(samples, 500));
    cout << "\nIs it symmetric? (this value should be 0): "<< min(abs(K - trans(K))) << endl;
    cout << "Smallest eigenvalue (should be >= 0):      "  << min(real_eigenvalues(K)) << endl;

    // here we make an instance of the krr_trainer object that uses our new kernel.
    krr_trainer<kernel_type> trainer;
    trainer.use_classification_loss_for_loo_cv();

    // Finally, let's test how good our new kernel is by doing some leave-one-out cross-validation.
    cout << "\ndoing leave-one-out cross-validation" << endl;
    for (double sigma = 0.01; sigma <= 100; sigma *= 3)
    {
        // tell the trainer the parameters we want to use
        trainer.set_kernel(kernel_type(sigma));

        std::vector<double> loo_values;
        trainer.train(samples, labels, loo_values);

        // Print sigma and the fraction of samples correctly classified during LOO cross-validation.
        const double classification_accuracy = mean_sign_agreement(labels, loo_values);
        cout << "sigma: " << sigma << "     LOO accuracy: " << classification_accuracy << endl;
    }

    const kernel_type kern(10);
    // Since it is very easy to make a mistake while coding a derivative it is a good idea
    // to compare your derivative function against a numerical approximation and see if
    // the results are similar.  If they are very different then you probably made a
    // mistake.  So here we compare the results at a test point.
    cout << "\nThese vectors should match, if they don't then we coded the kernel_derivative wrong!" << endl;
    cout << "approximate derivative: \n" <<               derivative(kern)(samples[0],samples[100]) << endl;
    cout << "exact derivative: \n" << kernel_derivative<kernel_type>(kern)(samples[0],samples[100]) << endl;


dlib C++ Library - video_tracking_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This example shows how to use the correlation_tracker from the dlib C++ library.  This
    object lets you track the position of an object as it moves from frame to frame in a
    video sequence.  To use it, you give the correlation_tracker the bounding box of the
    object you want to track in the current video frame.  Then it will identify the
    location of the object in subsequent frames.

    In this particular example, we are going to run on the video sequence that comes with
    dlib, which can be found in the examples/video_frames folder.  This video shows a juice
    box sitting on a table and someone is waving the camera around.  The task is to track the
    position of the juice box as the camera moves around.
*/

#include <dlib/image_processing.h>
#include <dlib/gui_widgets.h>
#include <dlib/image_io.h>
#include <dlib/dir_nav.h>

using namespace dlib;
using namespace std;

int main(int argc, char** argv) try
{
    if (argc != 2)
    {
        cout << "Call this program like this: " << endl;
        cout << "./video_tracking_ex ../video_frames" << endl;
        return 1;
    }

    // Get the list of video frames.
    std::vector<file> files = get_files_in_directory_tree(argv[1], match_ending(".jpg"));
    std::sort(files.begin(), files.end());
    if (files.size() == 0)
    {
        cout << "No images found in " << argv[1] << endl;
        return 1;
    }

    // Load the first frame.
    array2d<unsigned char> img;
    load_image(img, files[0]);
    // Now create a tracker and start a track on the juice box.  If you look at the first
    // frame you will see that the juice box is centered at pixel point(92,110) and 38
    // pixels wide and 86 pixels tall.
    correlation_tracker tracker;
    tracker.start_track(img, centered_rect(point(93,110), 38, 86));

    // Now run the tracker.  All we have to do is call tracker.update() and it will keep
    // track of the juice box!
    image_window win;
    for (unsigned long i = 1; i < files.size(); ++i)
    {
        load_image(img, files[i]);
        tracker.update(img);

        win.set_image(img);
        win.clear_overlay();
        win.add_overlay(tracker.get_position());

        cout << "hit enter to process next frame" << endl;
        cin.get();
    }
}
catch (std::exception& e)
{
    cout << e.what() << endl;


dlib C++ Library - webcam_face_pose_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This example program shows how to find frontal human faces in an image and
    estimate their pose.  The pose takes the form of 68 landmarks.  These are
    points on the face such as the corners of the mouth, along the eyebrows, on
    the eyes, and so forth.

    This example is essentially just a version of the face_landmark_detection_ex.cpp
    example modified to use OpenCV's VideoCapture object to read from a camera instead
    of files.

    Finally, note that the face detector is fastest when compiled with at least
    SSE2 instructions enabled.  So if you are using a PC with an Intel or AMD
    chip then you should enable at least SSE2 instructions.  If you are using
    cmake to compile this program you can enable them by using one of the
    following commands when you create the build project:
        cmake path_to_dlib_root/examples -DUSE_SSE2_INSTRUCTIONS=ON
        cmake path_to_dlib_root/examples -DUSE_SSE4_INSTRUCTIONS=ON
        cmake path_to_dlib_root/examples -DUSE_AVX_INSTRUCTIONS=ON
    This will set the appropriate compiler options for GCC, clang, Visual
    Studio, or the Intel compiler.  If you are using another compiler then you
    need to consult your compiler's manual to determine how to enable these
    instructions.  Note that AVX is the fastest but requires a CPU from at least
    2011.  SSE4 is the next fastest and is supported by most current machines.
*/

#include <dlib/opencv.h>
#include <opencv2/highgui/highgui.hpp>
#include <dlib/image_processing/frontal_face_detector.h>
#include <dlib/image_processing/render_face_detections.h>
#include <dlib/image_processing.h>
#include <dlib/gui_widgets.h>

using namespace dlib;
using namespace std;

int main()
{
    try
    {
        cv::VideoCapture cap(0);
        image_window win;

        // Load face detection and pose estimation models.
        frontal_face_detector detector = get_frontal_face_detector();
        shape_predictor pose_model;
        deserialize("shape_predictor_68_face_landmarks.dat") >> pose_model;

        // Grab and process frames until the main window is closed by the user.
        while(!win.is_closed())
        {
            // Grab a frame
            cv::Mat temp;
            cap >> temp;
            // Turn OpenCV's Mat into something dlib can deal with.  Note that this just
            // wraps the Mat object, it doesn't copy anything.  So cimg is only valid as
            // long as temp is valid.  Also don't do anything to temp that would cause it
            // to reallocate the memory which stores the image as that will make cimg
            // contain dangling pointers.  This basically means you shouldn't modify temp
            // while using cimg.
            cv_image<bgr_pixel> cimg(temp);

            // Detect faces
            std::vector<rectangle> faces = detector(cimg);
            // Find the pose of each face.
            std::vector<full_object_detection> shapes;
            for (unsigned long i = 0; i < faces.size(); ++i)
                shapes.push_back(pose_model(cimg, faces[i]));

            // Display it all on the screen
            win.clear_overlay();
            win.set_image(cimg);
            win.add_overlay(render_face_detections(shapes));
        }
    }
    catch(serialization_error& e)
    {
        cout << "You need dlib's default face landmarking model file to run this example." << endl;
        cout << "You can get it from the following URL: " << endl;
        cout << "   http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2" << endl;
        cout << endl << e.what() << endl;
    }
    catch(exception& e)
    {
        cout << e.what() << endl;


dlib C++ Library - xml_parser_ex.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

    This is an example illustrating the use of the xml_parser component in
    the dlib C++ Library.

    This example simply reads in an xml file and prints the parsing events
    to the screen.
*/

#include <dlib/xml_parser.h>
#include <iostream>
#include <fstream>

using namespace std;
using namespace dlib;

// ----------------------------------------------------------------------------------------

class doc_handler : public document_handler
{
    /*
        As the parser runs it generates events when it encounters tags and
        data in an XML file.  To be able to receive these events all you have to
        do is make a class that inherits from dlib::document_handler and
        implements its virtual methods.   Then you simply associate an
        instance of your class with the xml_parser.

        So this class is a simple example document handler that just prints
        all the events to the screen.
    */
public:

    virtual void start_document (
    )
    {
        cout << "parsing begins" << endl;
    }

    virtual void end_document (
    )
    {
        cout << "Parsing done" << endl;
    }

    virtual void start_element (
        const unsigned long line_number,
        const std::string& name,
        const dlib::attribute_list& atts
    )
    {
        cout << "on line " << line_number << " we hit the <" << name << "> tag" << endl;

        // print all the tag's attributes
        atts.reset();
        while (atts.move_next())
        {
            cout << "\tattribute: " << atts.element().key() << " = " << atts.element().value() << endl;
        }
    }

    virtual void end_element (
        const unsigned long line_number,
        const std::string& name
    )
    {
        cout << "on line " << line_number << " we hit the closing tag </" << name << ">" << endl;
    }

    virtual void characters (
        const std::string& data
    )
    {
        cout << "Got some data between tags and it is:\n" << data << endl;
    }

    virtual void processing_instruction (
        const unsigned long line_number,
        const std::string& target,
        const std::string& data
    )
    {
        cout << "on line " << line_number << " we hit a processing instruction with a target of '"
            << target << "' and data '" << data << "'" << endl;
    }
};

// ----------------------------------------------------------------------------------------

int main(int argc, char** argv)
{
    try
    {
        // Check if the user entered an argument to this application.
        if (argc != 2)
        {
            cout << "Please enter an xml file to parse on the command line" << endl;
            return 1;
        }

        doc_handler dh;
        // Now run the parser and tell it to call our doc_handler for each of the parsing
        // events.
        parse_xml(argv[1], dh);
    }
    catch (std::exception& e)
    {
        cout << e.what() << endl;


#!/usr/bin/python
# The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
#
#   This example program shows how to find frontal human faces in an image.  In
#   particular, it shows how you can take a list of images from the command
#   line and display each on the screen with red boxes overlaid on each human
#   face.
#
#   The examples/faces folder contains some jpg images of people.  You can run
#   this program on them and see the detections by executing the
#   following command:
#       ./face_detector.py ../examples/faces/*.jpg
#
#   This face detector is made using the now classic Histogram of Oriented
#   Gradients (HOG) feature combined with a linear classifier, an image
#   pyramid, and sliding window detection scheme.  This type of object detector
#   is fairly general and capable of detecting many types of semi-rigid objects
#   in addition to human faces.  Therefore, if you are interested in making
#   your own object detectors then read the train_object_detector.py example
#   program.
#
#
# COMPILING/INSTALLING THE DLIB PYTHON INTERFACE
#   You can install dlib using the command:
#       pip install dlib
#
#   Alternatively, if you want to compile dlib yourself then go into the dlib
#   root folder and run:
#       python setup.py install
#   or
#       python setup.py install --yes USE_AVX_INSTRUCTIONS
#   if you have a CPU that supports AVX instructions, since this makes some
#   things run faster.
#
#   Compiling dlib should work on any operating system so long as you have
#   CMake and boost-python installed.  On Ubuntu, this can be done easily by
#   running the command:
#       sudo apt-get install libboost-python-dev cmake
#
#   Also note that this example requires scikit-image which can be installed
#   via the command:
#       pip install scikit-image
#   Or downloaded from http://scikit-image.org/download.html.

import sys

import dlib
from skimage import io

detector = dlib.get_frontal_face_detector()
win = dlib.image_window()

for f in sys.argv[1:]:
    print("Processing file: {}".format(f))
    img = io.imread(f)
    # The 1 in the second argument indicates that we should upsample the image
    # 1 time.  This will make everything bigger and allow us to detect more
    # faces.
    dets = detector(img, 1)
    print("Number of faces detected: {}".format(len(dets)))
    for i, d in enumerate(dets):
        print("Detection {}: Left: {} Top: {} Right: {} Bottom: {}".format(
            i, d.left(), d.top(), d.right(), d.bottom()))

    win.clear_overlay()
    win.set_image(img)
    win.add_overlay(dets)
    dlib.hit_enter_to_continue()

# Finally, if you really want to you can ask the detector to tell you the score
# for each detection.  The score is bigger for more confident detections.
# Also, the idx tells you which of the face sub-detectors matched.  This can be
# used to broadly identify faces in different orientations.
if (len(sys.argv[1:]) > 0):
    img = io.imread(sys.argv[1])
    dets, scores, idx = detector.run(img, 1)
    for i, d in enumerate(dets):
        print("Detection {}, score: {}, face_type:{}".format(
            d, scores[i], idx[i]))


#!/usr/bin/python
# The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
#
#   This example program shows how to find frontal human faces in an image and
#   estimate their pose.  The pose takes the form of 68 landmarks.  These are
#   points on the face such as the corners of the mouth, along the eyebrows, on
#   the eyes, and so forth.
#
#   This face detector is made using the classic Histogram of Oriented
#   Gradients (HOG) feature combined with a linear classifier, an image pyramid,
#   and sliding window detection scheme.  The pose estimator was created by
#   using dlib's implementation of the paper:
#      One Millisecond Face Alignment with an Ensemble of Regression Trees by
#      Vahid Kazemi and Josephine Sullivan, CVPR 2014
#   and was trained on the iBUG 300-W face landmark dataset.
#
#   Also, note that you can train your own models using dlib's machine learning
#   tools. See train_shape_predictor.py to see an example.
#
#   You can get the shape_predictor_68_face_landmarks.dat file from:
#   http://sourceforge.net/projects/dclib/files/dlib/v18.10/shape_predictor_68_face_landmarks.dat.bz2
#
# COMPILING/INSTALLING THE DLIB PYTHON INTERFACE
#   You can install dlib using the command:
#       pip install dlib
#
#   Alternatively, if you want to compile dlib yourself then go into the dlib
#   root folder and run:
#       python setup.py install
#   or
#       python setup.py install --yes USE_AVX_INSTRUCTIONS
#   if you have a CPU that supports AVX instructions, since this makes some
#   things run faster.
#
#   Compiling dlib should work on any operating system so long as you have
#   CMake and boost-python installed.  On Ubuntu, this can be done easily by
#   running the command:
#       sudo apt-get install libboost-python-dev cmake
#
#   Also note that this example requires scikit-image which can be installed
#   via the command:
#       pip install scikit-image
#   Or downloaded from http://scikit-image.org/download.html.

import sys
import os
import dlib
import glob
from skimage import io

if len(sys.argv) != 3:
    print(
        "Give the path to the trained shape predictor model as the first "
        "argument and then the directory containing the facial images.\n"
        "For example, if you are in the python_examples folder then "
        "execute this program by running:\n"
        "    ./face_landmark_detection.py shape_predictor_68_face_landmarks.dat ../examples/faces\n"
        "You can download a trained facial shape predictor from:\n"
        "    http://sourceforge.net/projects/dclib/files/dlib/v18.10/shape_predictor_68_face_landmarks.dat.bz2")
    exit()

predictor_path = sys.argv[1]
faces_folder_path = sys.argv[2]

detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor(predictor_path)
win = dlib.image_window()

for f in glob.glob(os.path.join(faces_folder_path, "*.jpg")):
    print("Processing file: {}".format(f))
    img = io.imread(f)

    win.clear_overlay()
    win.set_image(img)

    # Ask the detector to find the bounding boxes of each face. The 1 in the
    # second argument indicates that we should upsample the image 1 time. This
    # will make everything bigger and allow us to detect more faces.
    dets = detector(img, 1)
    print("Number of faces detected: {}".format(len(dets)))
    for k, d in enumerate(dets):
        print("Detection {}: Left: {} Top: {} Right: {} Bottom: {}".format(
            k, d.left(), d.top(), d.right(), d.bottom()))
        # Get the landmarks/parts for the face in box d.
        shape = predictor(img, d)
        print("Part 0: {}, Part 1: {} ...".format(shape.part(0),
                                                  shape.part(1)))
        # Draw the face landmarks on the screen.
        win.add_overlay(shape)

    win.add_overlay(dets)
    dlib.hit_enter_to_continue()


#!/usr/bin/python
#
# This example shows how to use find_candidate_object_locations().  The
# function takes an input image and generates a set of candidate rectangles
# which are expected to bound any objects in the image.
# It is based on the paper:
#    Segmentation as Selective Search for Object Recognition by Koen E. A. van de Sande, et al.
#
# Typically, you would use this as part of an object detection pipeline.
# find_candidate_object_locations() nominates boxes that might contain an
# object and you then run some expensive classifier on each one and throw away
# the false alarms.  Since find_candidate_object_locations() will only generate
# a few thousand rectangles it is much faster than scanning all possible
# rectangles inside an image.
#
#
# COMPILING/INSTALLING THE DLIB PYTHON INTERFACE
#   You can install dlib using the command:
#       pip install dlib
#
#   Alternatively, if you want to compile dlib yourself then go into the dlib
#   root folder and run:
#       python setup.py install
#   or
#       python setup.py install --yes USE_AVX_INSTRUCTIONS
#   if you have a CPU that supports AVX instructions, since this makes some
#   things run faster.
#
#   Compiling dlib should work on any operating system so long as you have
#   CMake and boost-python installed.  On Ubuntu, this can be done easily by
#   running the command:
#       sudo apt-get install libboost-python-dev cmake
#
#   Also note that this example requires scikit-image which can be installed
#   via the command:
#       pip install scikit-image
#   Or downloaded from http://scikit-image.org/download.html.

import dlib
from skimage import io

image_file = '../examples/faces/2009_004587.jpg'
img = io.imread(image_file)

# Locations of candidate objects will be saved into rects
rects = []
dlib.find_candidate_object_locations(img, rects, min_size=500)

print("number of rectangles found {}".format(len(rects)))
for k, d in enumerate(rects):
    print("Detection {}: Left: {} Top: {} Right: {} Bottom: {}".format(
        k, d.left(), d.top(), d.right(), d.bottom()))


#!/usr/bin/python
# The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
#
# This simple example shows how to call dlib's optimal linear assignment
# problem solver.  It is an implementation of the famous Hungarian algorithm
# and is quite fast, operating in O(N^3) time.
#
# COMPILING/INSTALLING THE DLIB PYTHON INTERFACE
#   You can install dlib using the command:
#       pip install dlib
#
#   Alternatively, if you want to compile dlib yourself then go into the dlib
#   root folder and run:
#       python setup.py install
#   or
#       python setup.py install --yes USE_AVX_INSTRUCTIONS
#   if you have a CPU that supports AVX instructions, since this makes some
#   things run faster.
#
#   Compiling dlib should work on any operating system so long as you have
#   CMake and boost-python installed.  On Ubuntu, this can be done easily by
#   running the command:
#       sudo apt-get install libboost-python-dev cmake
#

import dlib

# Let's imagine you need to assign N people to N jobs.  Additionally, each
# person will make your company a certain amount of money at each job, but each
# person has different skills so they are better at some jobs and worse at
# others.  You would like to find the best way to assign people to these jobs.
# In particular, you would like to maximize the amount of money the group makes
# as a whole.  This is an example of an assignment problem and is what is solved
# by the dlib.max_cost_assignment() routine.

# So in this example, let's imagine we have 3 people and 3 jobs. We represent
# the amount of money each person will produce at each job with a cost matrix.
# Each row corresponds to a person and each column corresponds to a job. So for
# example, below we are saying that person 0 will make $1 at job 0, $2 at job 1,
# and $6 at job 2.
cost = dlib.matrix([[1, 2, 6],
                    [5, 3, 6],
                    [4, 5, 0]])

# To find out the best assignment of people to jobs we just need to call this
# function.
assignment = dlib.max_cost_assignment(cost)

# This prints optimal assignments:  [2, 0, 1]
# which indicates that we should assign the person from the first row of the
# cost matrix to job 2, the middle row person to job 0, and the bottom row
# person to job 1.
print("Optimal assignments: {}".format(assignment))

# This prints optimal cost:  16.0
# which is correct since our optimal assignment is 6+5+5.
print("Optimal cost: {}".format(dlib.assignment_cost(cost, assignment)))


#!/usr/bin/python
# The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
#
# This example shows how to use dlib to learn to do sequence segmentation.  In
# a sequence segmentation task we are given a sequence of objects (e.g. words in
# a sentence) and we are supposed to detect certain subsequences (e.g. the names
# of people).  Therefore, in the code below we create some very simple training
# sequences and use them to learn a sequence segmentation model.  In particular,
# our sequences will be sentences represented as arrays of words and our task
# will be to learn to identify person names.  Once we have our segmentation
# model we can use it to find names in new sentences, as we will show.
#
# COMPILING/INSTALLING THE DLIB PYTHON INTERFACE
#   You can install dlib using the command:
#       pip install dlib
#
#   Alternatively, if you want to compile dlib yourself then go into the dlib
#   root folder and run:
#       python setup.py install
#   or
#       python setup.py install --yes USE_AVX_INSTRUCTIONS
#   if you have a CPU that supports AVX instructions, since this makes some
#   things run faster.
#
#   Compiling dlib should work on any operating system so long as you have
#   CMake and boost-python installed.  On Ubuntu, this can be done easily by
#   running the command:
#       sudo apt-get install libboost-python-dev cmake
#
import sys
import dlib

# The sequence segmentation models we work with in this example are chain
# structured conditional random field style models.  Therefore, central to a
# sequence segmentation model is some method for converting the elements of a
# sequence into feature vectors. That is, while you might start out representing
# your sequence as an array of strings, the dlib interface works in terms of
# arrays of feature vectors.  Each feature vector should capture important
# information about its corresponding element in the original raw sequence.  So
# in this example, since we work with sequences of words and want to identify
# names, we will create feature vectors that tell us if the word is capitalized
# or not.  In our simple data, this will be enough to identify names.
# Therefore, we define sentence_to_vectors() which takes a sentence represented
# as a string and converts it into an array of words and then associates a
# feature vector with each word.
def sentence_to_vectors(sentence):
    # Create an empty array of vectors
    vects = dlib.vectors()
    for word in sentence.split():
        # Our vectors are very simple 1-dimensional vectors.  The value of the
        # single feature is 1 if the first letter of the word is capitalized and
        # 0 otherwise.
        if word[0].isupper():
            vects.append(dlib.vector([1]))
        else:
            vects.append(dlib.vector([0]))
    return vects

# Dlib also supports the use of a sparse vector representation.  This is more
# efficient than the above form when you have very high dimensional vectors that
# are mostly full of zeros.  In dlib, each sparse vector is represented as an
# array of pair objects.  Each pair contains an index and value.  Any index not
# listed in the vector is implicitly associated with a value of zero.
# Additionally, when using sparse vectors with dlib.train_sequence_segmenter()
# you can use "unsorted" sparse vectors.  This means you can add the index/value
# pairs into your sparse vectors in any order you want and don't need to worry
# about them being in sorted order.
def sentence_to_sparse_vectors(sentence):
    vects = dlib.sparse_vectors()
    has_cap = dlib.sparse_vector()
    no_cap = dlib.sparse_vector()
    # make has_cap equivalent to dlib.vector([1])
    has_cap.append(dlib.pair(0, 1))

    # Since we didn't add anything to no_cap it is equivalent to
    # dlib.vector([0])
    for word in sentence.split():
        if word[0].isupper():
            vects.append(has_cap)
        else:
            vects.append(no_cap)
    return vects

def print_segment(sentence, names):
    words = sentence.split()
    for name in names:
        for i in name:
            sys.stdout.write(words[i] + " ")
        sys.stdout.write("\n")

# Now let's make some training data.  Each example is a sentence as well as a
# set of ranges which indicate the locations of any names.
names = dlib.ranges()     # make an array of dlib.range objects.
segments = dlib.rangess() # make an array of arrays of dlib.range objects.
sentences = []

sentences.append("The other day I saw a man named Jim Smith")
# We want to detect person names.  So we note that the name is located within
# the range [8, 10).  Note that we use half open ranges to identify segments.
# So in this case, the segment identifies the string "Jim Smith".
names.append(dlib.range(8, 10))
segments.append(names)
names.clear() # make names empty for use again below

sentences.append("Davis King is the main author of the dlib Library")
names.append(dlib.range(0, 2))
segments.append(names)
names.clear()

sentences.append("Bob Jones is a name and so is George Clinton")
names.append(dlib.range(0, 2))
names.append(dlib.range(8, 10))
segments.append(names)
names.clear()

sentences.append("My dog is named Bob Barker")
names.append(dlib.range(4, 6))
segments.append(names)
names.clear()

sentences.append("ABC is an acronym but John James Smith is a name")
names.append(dlib.range(5, 8))
segments.append(names)
names.clear()

sentences.append("No names in this sentence at all")
segments.append(names)
names.clear()

# Now before we can pass these training sentences to the dlib tools we need to
# convert them into arrays of vectors as discussed above.  We can use either a
# sparse or dense representation depending on our needs.  In this example, we
# show how to do it both ways.
use_sparse_vects = False
if use_sparse_vects:
    # Make an array of arrays of dlib.sparse_vector objects.
    training_sequences = dlib.sparse_vectorss()
    for s in sentences:
        training_sequences.append(sentence_to_sparse_vectors(s))
else:
    # Make an array of arrays of dlib.vector objects.
    training_sequences = dlib.vectorss()
    for s in sentences:
        training_sequences.append(sentence_to_vectors(s))

# Now that we have a simple training set we can train a sequence segmenter.
# However, the sequence segmentation trainer has some optional parameters we can
# set.  These parameters determine properties of the segmentation model we will
# learn.  See the dlib documentation for the sequence_segmenter object for a
# full discussion of their meanings.
params = dlib.segmenter_params()
params.window_size = 3
params.use_high_order_features = True
params.use_BIO_model = True
# This is the common SVM C parameter.  Larger values encourage the trainer to
# attempt to fit the data exactly but might overfit.  In general, you determine
# this parameter by cross-validation.
params.C = 10

# Train a model.  The model object is responsible for predicting the locations
# of names in new sentences.
model = dlib.train_sequence_segmenter(training_sequences, segments, params)

# Let's print out the things the model thinks are names.  The output is a set
# of ranges which are predicted to contain names.  If you run this example
# program you will see that it gets them all correct.
for i, s in enumerate(sentences):
    print_segment(s, model(training_sequences[i]))

# Let's also try segmenting a new sentence.  This will print out "Bob Bucket".
# Note that we need to remember to use the same vector representation as we used
# during training.
test_sentence = "There once was a man from Nantucket " \
                "whose name rhymed with Bob Bucket"
if use_sparse_vects:
    print_segment(test_sentence,
                  model(sentence_to_sparse_vectors(test_sentence)))
else:
    print_segment(test_sentence, model(sentence_to_vectors(test_sentence)))

# We can also measure the accuracy of a model relative to some labeled data.
# This statement prints the precision, recall, and F1-score of the model
# relative to the data in training_sequences/segments.
print("Test on training data: {}".format(
      dlib.test_sequence_segmenter(model, training_sequences, segments)))

# We can also do 5-fold cross-validation and print the resulting precision,
# recall, and F1-score.
print("Cross validation: {}".format(
      dlib.cross_validate_sequence_segmenter(training_sequences, segments, 5,
                                             params)))


#!/usr/bin/python
# The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
#
# This is an example illustrating the use of the structural SVM solver from
# the dlib C++ Library.  Therefore, this example teaches you the central ideas
# needed to setup a structural SVM model for your machine learning problems.  To
# illustrate the process, we use dlib's structural SVM solver to learn the
# parameters of a simple multi-class classifier.  We first discuss the
# multi-class classifier model and then walk through using the structural SVM
# tools to find the parameters of this classification model.     As an aside,
# dlib's C++ interface to the structural SVM solver is threaded.  So on a
# multi-core computer it is significantly faster than using the python
# interface.  So consider using the C++ interface instead if you find that
# running it in python is slow.
#
#
# COMPILING/INSTALLING THE DLIB PYTHON INTERFACE
#   You can install dlib using the command:
#       pip install dlib
#
#   Alternatively, if you want to compile dlib yourself then go into the dlib
#   root folder and run:
#       python setup.py install
#   or
#       python setup.py install --yes USE_AVX_INSTRUCTIONS
#   if you have a CPU that supports AVX instructions, since this makes some
#   things run faster.
#
#   Compiling dlib should work on any operating system so long as you have
#   CMake and boost-python installed.  On Ubuntu, this can be done easily by
#   running the command:
#       sudo apt-get install libboost-python-dev cmake
#

import dlib

def main():
    # In this example, we have three types of samples: class 0, 1, or 2.  That
    # is, each of our sample vectors falls into one of three classes.  To keep
    # this example very simple, each sample vector is zero everywhere except at
    # one place.  The non-zero dimension of each vector determines the class of
    # the vector.  So for example, the first element of samples has a class of 1
    # because samples[0][1] is the only non-zero element of samples[0].
    samples = [[0, 2, 0], [1, 0, 0], [0, 4, 0], [0, 0, 3]]
    # Since we want to use a machine learning method to learn a 3-class
    # classifier we need to record the labels of our samples.  Here samples[i]
    # has a class label of labels[i].
    labels = [1, 0, 1, 2]

    # Now that we have some training data we can tell the structural SVM to
    # learn the parameters of our 3-class classifier model.  The details of this
    # will be explained later.  For now, just note that it finds the weights
    # (i.e. a vector of real valued parameters) such that predict_label(weights,
    # sample) always returns the correct label for a sample vector.
    problem = ThreeClassClassifierProblem(samples, labels)
    weights = dlib.solve_structural_svm_problem(problem)

    # Print the weights and then evaluate predict_label() on each of our
    # training samples. Note that the correct label is predicted for each
    # sample.
    print(weights)
    for k, s in enumerate(samples):
        print("Predicted label for sample[{0}]: {1}".format(
            k, predict_label(weights, s)))

def predict_label(weights, sample):
    """Given the 9-dimensional weight vector which defines a 3 class classifier,
    predict the class of the given 3-dimensional sample vector.   Therefore, the
    output of this function is either 0, 1, or 2 (i.e. one of the three possible
    labels)."""

    # Our 3-class classifier model can be thought of as containing 3 separate
    # linear classifiers.  So to predict the class of a sample vector we
    # evaluate each of these three classifiers and then whatever classifier has
    # the largest output "wins" and predicts the label of the sample.  This is
    # the popular one-vs-all multi-class classifier model.
    # Keeping this in mind, the code below simply pulls the three separate
    # weight vectors out of weights and then evaluates each against sample.  The
    # individual classifier scores are stored in scores and the highest scoring
    # index is returned as the label.
    w0 = weights[0:3]
    w1 = weights[3:6]
    w2 = weights[6:9]
    scores = [dot(w0, sample), dot(w1, sample), dot(w2, sample)]
    max_scoring_label = scores.index(max(scores))
    return max_scoring_label

def dot(a, b):
    """Compute the dot product between the two vectors a and b."""
    return sum(i * j for i, j in zip(a, b))

################################################################################

class ThreeClassClassifierProblem:
    # Now we arrive at the meat of this example program.  To use the
    # dlib.solve_structural_svm_problem() routine you need to define an object
    # which tells the structural SVM solver what to do for your problem.  In
    # this example, this is done by defining the ThreeClassClassifierProblem
    # object.  Before we get into the details, we first discuss some background
    # information on structural SVMs.
    #
    # A structural SVM is a supervised machine learning method for learning to
    # predict complex outputs.  This is contrasted with a binary classifier
    # which makes only simple yes/no predictions.  A structural SVM, on the
    # other hand, can learn to predict complex outputs such as entire parse
    # trees or DNA sequence alignments.  To do this, it learns a function F(x,y)
    # which measures how well a particular data sample x matches a label y,
    # where a label is potentially a complex thing like a parse tree. However,
    # to keep this example program simple we use only a 3 category label output.
    #
    # At test time, the best label for a new x is given by the y which
    # maximizes F(x,y). To put this into the context of the current example,
    # F(x,y) computes the score for a given sample and class label.  The
    # predicted class label is therefore whatever value of y which makes F(x,y)
    # the biggest.  This is exactly what predict_label() does. That is, it
    # computes F(x,0), F(x,1), and F(x,2) and then reports which label has the
    # biggest value.
    #
    # At a high level, a structural SVM can be thought of as searching the
    # parameter space of F(x,y) for the set of parameters that make the
    # following inequality true as often as possible:
    #     F(x_i,y_i) > max{over all incorrect labels of x_i} F(x_i, y_incorrect)
    # That is, it seeks to find the parameter vector such that F(x,y) always
    # gives the highest score to the correct output.  To define the structural
    # SVM optimization problem precisely, we first introduce some notation:
    #    - let PSI(x,y)    == the joint feature vector for input x and a label y
    #    - let F(x,y|w)    == dot(w,PSI(x,y)).
    #      (we use the | notation to emphasize that F() has the parameter vector
    #       of weights called w)
    #    - let LOSS(idx,y) == the loss incurred for predicting that the
    #      idx-th training  sample has a label of y.  Note that LOSS()
    #      should always be >= 0 and should become exactly 0 when y is the
    #      correct label for the idx-th sample.  Moreover, it should notionally
    #      indicate how bad it is to predict y for the idx'th sample.
    #    - let x_i == the i-th training sample.
    #    - let y_i == the correct label for the i-th training sample.
    #    - The number of data samples is N.
    #
    # Then the optimization problem solved by a structural SVM using
    # dlib.solve_structural_svm_problem() is the following:
    #     Minimize: h(w) == 0.5*dot(w,w) + C*R(w)
    #
    #     Where R(w) == sum from i=1 to N: 1/N * sample_risk(i,w) and
    #     sample_risk(i,w) == max over all
    #         Y: LOSS(i,Y) + F(x_i,Y|w) - F(x_i,y_i|w) and C > 0
    #
    # You can think of the sample_risk(i,w) as measuring the degree of error
    # you would make when predicting the label of the i-th sample using
    # parameters w.  That is, it is zero only when the correct label would be
    # predicted and grows larger the more "wrong" the predicted output becomes.
    # Therefore, the objective function is minimizing a balance between making
    # the weights small (typically this reduces overfitting) and fitting the
    # training data.  The degree to which you try to fit the data is controlled
    # by the C parameter.
    #
    # For a more detailed introduction to structured support vector machines
    # you should consult the following paper:
    #     Predicting Structured Objects with Support Vector Machines by
    #     Thorsten Joachims, Thomas Hofmann, Yisong Yue, and Chun-nam Yu
    #

    # Finally, we come back to the code.  To use
    # dlib.solve_structural_svm_problem() you need to provide the things
    # discussed above.  This is the value of C, the number of training samples,
    # the dimensionality of PSI(), as well as methods for calculating the loss
    # values and PSI() vectors.  You will also need to write code that can
    # compute:
    # max over all Y: LOSS(i,Y) + F(x_i,Y|w).  To summarize, the
    # ThreeClassClassifierProblem class is required to have the following
    # fields:
    #   - C
    #   - num_samples
    #   - num_dimensions
    #   - get_truth_joint_feature_vector()
    #   - separation_oracle()

    C = 1

    # There are also a number of optional arguments:
    # epsilon is the stopping tolerance.  The optimizer will run until R(w) is
    # within epsilon of its optimal value. If you don't set this then it
    # defaults to 0.001.
    # epsilon = 1e-13

    # Uncomment this and the optimizer will print its progress to standard
    # out.  You will be able to see things like the current risk gap.  The
    # optimizer continues until the
    # risk gap is below epsilon.
    # be_verbose = True

    # If you want to require that the learned weights are all non-negative
    # then set this field to True.
    # learns_nonnegative_weights = True

    # The optimizer uses an internal cache to avoid unnecessary calls to your
    # separation_oracle() routine.  This parameter controls the size of that
    # cache.  Bigger values use more RAM and might make the optimizer run
    # faster.  You can also disable it by setting it to 0 which is good to do
    # when your separation_oracle is very fast.  If If you don't call this
    # function it defaults to a value of 5.
    # max_cache_size = 20

    def __init__(self, samples, labels):
        # dlib.solve_structural_svm_problem() expects the class to have
        # num_samples and num_dimensions fields.  These fields should contain
        # the number of training samples and the dimensionality of the PSI
        # feature vector respectively.
        self.num_samples = len(samples)
        self.num_dimensions = len(samples[0])*3

        self.samples = samples
        self.labels = labels

    def make_psi(self, x, label):
        """Compute PSI(x,label)."""
        # All we are doing here is taking x, which is a 3 dimensional sample
        # vector in this example program, and putting it into one of 3 places in
        # a 9 dimensional PSI vector, which we then return.  So this function
        # returns PSI(x,label).  To see why we setup PSI like this, recall how
        # predict_label() works.  It takes in a 9 dimensional weight vector and
        # breaks the vector into 3 pieces.  Each piece then defines a different
        # classifier and we use them in a one-vs-all manner to predict the
        # label.  So now that we are in the structural SVM code we have to
        # define the PSI vector to correspond to this usage.  That is, we need
        # to setup PSI so that argmax_y dot(weights,PSI(x,y)) ==
        # predict_label(weights,x).  This is how we tell the structural SVM
        # solver what kind of problem we are trying to solve.
        #
        # It's worth emphasizing that the single biggest step in using a
        # structural SVM is deciding how you want to represent PSI(x,label).  It
        # is always a vector, but deciding what to put into it to solve your
        # problem is often not a trivial task. Part of the difficulty is that
        # you need an efficient method for finding the label that makes
        # dot(w,PSI(x,label)) the biggest.  Sometimes this is easy, but often
        # finding the max scoring label turns into a difficult combinatorial
        # optimization problem.  So you need to pick a PSI that doesn't make the
        # label maximization step intractable but also still well models your
        # problem.
        #
        # Create a dense vector object (note that you can also use unsorted
        # sparse vectors (i.e.  dlib.sparse_vector objects) to represent your
        # PSI vector.  This is useful if you have very high dimensional PSI
        # vectors that are mostly zeros.  In the context of this example, you
        # would simply return a dlib.sparse_vector at the end of make_psi() and
        # the rest of the example would still work properly. ).
        psi = dlib.vector()
        # Set it to have 9 dimensions.  Note that the elements of the vector
        # are 0 initialized.
        psi.resize(self.num_dimensions)
        dims = len(x)
        if label == 0:
            for i in range(0, dims):
                psi[i] = x[i]
        elif label == 1:
            for i in range(dims, 2 * dims):
                psi[i] = x[i - dims]
        else:  # the label must be 2
            for i in range(2 * dims, 3 * dims):
                psi[i] = x[i - 2 * dims]
        return psi

    # Now we get to the two member functions that are directly called by
    # dlib.solve_structural_svm_problem().
    #
    # In get_truth_joint_feature_vector(), all you have to do is return the
    # PSI() vector for the idx-th training sample when it has its true label.
    # So here it returns
    # PSI(self.samples[idx], self.labels[idx]).
    def get_truth_joint_feature_vector(self, idx):
        return self.make_psi(self.samples[idx], self.labels[idx])

    # separation_oracle() is more interesting.
    # dlib.solve_structural_svm_problem() will call separation_oracle() many
    # times during the optimization.  Each time it will give it the current
    # value of the parameter weights and the separation_oracle() is supposed to
    # find the label that most violates the structural SVM objective function
    # for the idx-th sample.  Then the separation oracle reports the
    # corresponding PSI vector and loss value.  To state this more precisely,
    # the separation_oracle() member function has the following contract:
    #   requires
    #      - 0 <= idx < self.num_samples
    #      - len(current_solution) == self.num_dimensions
    #   ensures
    #      - runs the separation oracle on the idx-th sample.
    #        We define this as follows:
    #         - let X           == the idx-th training sample.
    #         - let PSI(X,y)    == the joint feature vector for input X
    #                              and an arbitrary label y.
    #         - let F(X,y)      == dot(current_solution,PSI(X,y)).
    #         - let LOSS(idx,y) == the loss incurred for predicting that the
    #           idx-th sample has a label of y.  Note that LOSS()
    #           should always be >= 0 and should become exactly 0 when y is the
    #           correct label for the idx-th sample.
    #
    #            Then the separation oracle finds a Y such that:
    #               Y = argmax over all y: LOSS(idx,y) + F(X,y)
    #            (i.e. It finds the label which maximizes the above expression.)
    #
    #            Finally, separation_oracle() returns LOSS(idx,Y),PSI(X,Y)
    def separation_oracle(self, idx, current_solution):
        samp = self.samples[idx]
        dims = len(samp)
        scores = [0, 0, 0]
        # compute scores for each of the three classifiers
        scores[0] = dot(current_solution[0:dims], samp)
        scores[1] = dot(current_solution[dims:2*dims], samp)
        scores[2] = dot(current_solution[2*dims:3*dims], samp)

        # Add in the loss-augmentation.  Recall that we maximize
        # LOSS(idx,y) + F(X,y) in the separate oracle, not just F(X,y) as we
        # normally would in predict_label(). Therefore, we must add in this
        # extra amount to account for the loss-augmentation. For our simple
        # multi-class classifier, we incur a loss of 1 if we don't predict the
        # correct label and a loss of 0 if we get the right label.
        if self.labels[idx] != 0:
            scores[0] += 1
        if self.labels[idx] != 1:
            scores[1] += 1
        if self.labels[idx] != 2:
            scores[2] += 1

        # Now figure out which classifier has the largest loss-augmented score.
        max_scoring_label = scores.index(max(scores))
        # And finally record the loss that was associated with that predicted
        # label. Again, the loss is 1 if the label is incorrect and 0 otherwise.
        if max_scoring_label == self.labels[idx]:
            loss = 0
        else:
            loss = 1

        # Finally, return the loss and PSI vector corresponding to the label
        # we just found.
        psi = self.make_psi(samp, max_scoring_label)
        return loss, psi

if __name__ == "__main__":
    main()


#!/usr/bin/python
# The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
#
#
# This is an example illustrating the use of the SVM-Rank tool from the dlib C++
# Library.  This is a tool useful for learning to rank objects.  For example,
# you might use it to learn to rank web pages in response to a user's query.
# The idea being to rank the most relevant pages higher than non-relevant pages.
#
# In this example, we will create a simple test dataset and show how to learn a
# ranking function from it.  The purpose of the function will be to give
# "relevant" objects higher scores than "non-relevant" objects.  The idea is
# that you use this score to order the objects so that the most relevant objects
# come to the top of the ranked list.
#
#
# COMPILING/INSTALLING THE DLIB PYTHON INTERFACE
#   You can install dlib using the command:
#       pip install dlib
#
#   Alternatively, if you want to compile dlib yourself then go into the dlib
#   root folder and run:
#       python setup.py install
#   or
#       python setup.py install --yes USE_AVX_INSTRUCTIONS
#   if you have a CPU that supports AVX instructions, since this makes some
#   things run faster.
#
#   Compiling dlib should work on any operating system so long as you have
#   CMake and boost-python installed.  On Ubuntu, this can be done easily by
#   running the command:
#       sudo apt-get install libboost-python-dev cmake
#

import dlib

# Now let's make some testing data.  To make it really simple, let's suppose
# that we are ranking 2D vectors and that vectors with positive values in the
# first dimension should rank higher than other vectors.  So what we do is make
# examples of relevant (i.e. high ranking) and non-relevant (i.e. low ranking)
# vectors and store them into a ranking_pair object like so:
data = dlib.ranking_pair()
# Here we add two examples.  In real applications, you would want lots of
# examples of relevant and non-relevant vectors.
data.relevant.append(dlib.vector([1, 0]))
data.nonrelevant.append(dlib.vector([0, 1]))

# Now that we have some data, we can use a machine learning method to learn a
# function that will give high scores to the relevant vectors and low scores to
# the non-relevant vectors.
trainer = dlib.svm_rank_trainer()
# Note that the trainer object has some parameters that control how it behaves.
# For example, since this is the SVM-Rank algorithm it has a C parameter that
# controls the trade-off between trying to fit the training data exactly or
# selecting a "simpler" solution which might generalize better.
trainer.c = 10

# So let's do the training.
rank = trainer.train(data)

# Now if you call rank on a vector it will output a ranking score.  In
# particular, the ranking score for relevant vectors should be larger than the
# score for non-relevant vectors.
print("Ranking score for a relevant vector:     {}".format(
    rank(data.relevant[0])))
print("Ranking score for a non-relevant vector: {}".format(
    rank(data.nonrelevant[0])))
# The output is the following:
#    ranking score for a relevant vector:     0.5
#    ranking score for a non-relevant vector: -0.5

# If we want an overall measure of ranking accuracy we can compute the ordering
# accuracy and mean average precision values by calling test_ranking_function().
# In this case, the ordering accuracy tells us how often a non-relevant vector
# was ranked ahead of a relevant vector.  In this case, it returns 1 for both
# metrics, indicating that the rank function outputs a perfect ranking.
print(dlib.test_ranking_function(rank, data))

# The ranking scores are computed by taking the dot product between a learned
# weight vector and a data vector.  If you want to see the learned weight vector
# you can display it like so:
print("Weights: {}".format(rank.weights))
# In this case the weights are:
#  0.5
# -0.5

# In the above example, our data contains just two sets of objects.  The
# relevant set and non-relevant set.  The trainer is attempting to find a
# ranking function that gives every relevant vector a higher score than every
# non-relevant vector.  Sometimes what you want to do is a little more complex
# than this.
#
# For example, in the web page ranking example we have to rank pages based on a
# user's query.  In this case, each query will have its own set of relevant and
# non-relevant documents.  What might be relevant to one query may well be
# non-relevant to another.  So in this case we don't have a single global set of
# relevant web pages and another set of non-relevant web pages.
#
# To handle cases like this, we can simply give multiple ranking_pair instances
# to the trainer.  Therefore, each ranking_pair would represent the
# relevant/non-relevant sets for a particular query.  An example is shown below
# (for simplicity, we reuse our data from above to make 4 identical "queries").
queries = dlib.ranking_pairs()
queries.append(data)
queries.append(data)
queries.append(data)
queries.append(data)

# We can train just as before.
rank = trainer.train(queries)

# Now that we have multiple ranking_pair instances, we can also use
# cross_validate_ranking_trainer().  This performs cross-validation by splitting
# the queries up into folds.  That is, it lets the trainer train on a subset of
# ranking_pair instances and tests on the rest.  It does this over 4 different
# splits and returns the overall ranking accuracy based on the held out data.
# Just like test_ranking_function(), it reports both the ordering accuracy and
# mean average precision.
print("Cross validation results: {}".format(
    dlib.cross_validate_ranking_trainer(trainer, queries, 4)))

# Finally, note that the ranking tools also support the use of sparse vectors in
# addition to dense vectors (which we used above).  So if we wanted to do
# exactly what we did in the first part of the example program above but using
# sparse vectors we would do it like so:

data = dlib.sparse_ranking_pair()
samp = dlib.sparse_vector()

# Make samp represent the same vector as dlib.vector([1, 0]).  In dlib, a sparse
# vector is just an array of pair objects.  Each pair stores an index and a
# value.  Moreover, the svm-ranking tools require sparse vectors to be sorted
# and to have unique indices.  This means that the indices are listed in
# increasing order and no index value shows up more than once.  If necessary,
# you can use the dlib.make_sparse_vector() routine to make a sparse vector
# object properly sorted and contain unique indices.
samp.append(dlib.pair(0, 1))
data.relevant.append(samp)

# Now make samp represent the same vector as dlib.vector([0, 1])
samp.clear()
samp.append(dlib.pair(1, 1))
data.nonrelevant.append(samp)

trainer = dlib.svm_rank_trainer_sparse()
rank = trainer.train(data)
print("Ranking score for a relevant vector:     {}".format(
    rank(data.relevant[0])))
print("Ranking score for a non-relevant vector: {}".format(
    rank(data.nonrelevant[0])))
# Just as before, the output is the following:
#    ranking score for a relevant vector:     0.5
#    ranking score for a non-relevant vector: -0.5


#!/usr/bin/python
# The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
#
# This example program shows how you can use dlib to make an object
#   detector for things like faces, pedestrians, and any other semi-rigid
#   object.  In particular, we go though the steps to train the kind of sliding
#   window object detector first published by Dalal and Triggs in 2005 in the
#   paper Histograms of Oriented Gradients for Human Detection.
#
#
# COMPILING/INSTALLING THE DLIB PYTHON INTERFACE
#   You can install dlib using the command:
#       pip install dlib
#
#   Alternatively, if you want to compile dlib yourself then go into the dlib
#   root folder and run:
#       python setup.py install
#   or
#       python setup.py install --yes USE_AVX_INSTRUCTIONS
#   if you have a CPU that supports AVX instructions, since this makes some
#   things run faster.
#
#   Compiling dlib should work on any operating system so long as you have
#   CMake and boost-python installed.  On Ubuntu, this can be done easily by
#   running the command:
#       sudo apt-get install libboost-python-dev cmake
#
#   Also note that this example requires scikit-image which can be installed
#   via the command:
#       pip install scikit-image
#   Or downloaded from http://scikit-image.org/download.html.

import os
import sys
import glob

import dlib
from skimage import io

# In this example we are going to train a face detector based on the small
# faces dataset in the examples/faces directory.  This means you need to supply
# the path to this faces folder as a command line argument so we will know
# where it is.
if len(sys.argv) != 2:
    print(
        "Give the path to the examples/faces directory as the argument to this "
        "program. For example, if you are in the python_examples folder then "
        "execute this program by running:\n"
        "    ./train_object_detector.py ../examples/faces")
    exit()
faces_folder = sys.argv[1]

# Now let's do the training.  The train_simple_object_detector() function has a
# bunch of options, all of which come with reasonable default values.  The next
# few lines goes over some of these options.
options = dlib.simple_object_detector_training_options()
# Since faces are left/right symmetric we can tell the trainer to train a
# symmetric detector.  This helps it get the most value out of the training
# data.
options.add_left_right_image_flips = True
# The trainer is a kind of support vector machine and therefore has the usual
# SVM C parameter.  In general, a bigger C encourages it to fit the training
# data better but might lead to overfitting.  You must find the best C value
# empirically by checking how well the trained detector works on a test set of
# images you haven't trained on.  Don't just leave the value set at 5.  Try a
# few different C values and see what works best for your data.
options.C = 5
# Tell the code how many CPU cores your computer has for the fastest training.
options.num_threads = 4
options.be_verbose = True

training_xml_path = os.path.join(faces_folder, "training.xml")
testing_xml_path = os.path.join(faces_folder, "testing.xml")
# This function does the actual training.  It will save the final detector to
# detector.svm.  The input is an XML file that lists the images in the training
# dataset and also contains the positions of the face boxes.  To create your
# own XML files you can use the imglab tool which can be found in the
# tools/imglab folder.  It is a simple graphical tool for labeling objects in
# images with boxes.  To see how to use it read the tools/imglab/README.txt
# file.  But for this example, we just use the training.xml file included with
# dlib.
dlib.train_simple_object_detector(training_xml_path, "detector.svm", options)

# Now that we have a face detector we can test it.  The first statement tests
# it on the training data.  It will print(the precision, recall, and then)
# average precision.
print("")  # Print blank line to create gap from previous output
print("Training accuracy: {}".format(
    dlib.test_simple_object_detector(training_xml_path, "detector.svm")))
# However, to get an idea if it really worked without overfitting we need to
# run it on images it wasn't trained on.  The next line does this.  Happily, we
# see that the object detector works perfectly on the testing images.
print("Testing accuracy: {}".format(
    dlib.test_simple_object_detector(testing_xml_path, "detector.svm")))

# Now let's use the detector as you would in a normal application.  First we
# will load it from disk.
detector = dlib.simple_object_detector("detector.svm")

# We can look at the HOG filter we learned.  It should look like a face.  Neat!
win_det = dlib.image_window()
win_det.set_image(detector)

# Now let's run the detector over the images in the faces folder and display the
# results.
print("Showing detections on the images in the faces folder...")
win = dlib.image_window()
for f in glob.glob(os.path.join(faces_folder, "*.jpg")):
    print("Processing file: {}".format(f))
    img = io.imread(f)
    dets = detector(img)
    print("Number of faces detected: {}".format(len(dets)))
    for k, d in enumerate(dets):
        print("Detection {}: Left: {} Top: {} Right: {} Bottom: {}".format(
            k, d.left(), d.top(), d.right(), d.bottom()))

    win.clear_overlay()
    win.set_image(img)
    win.add_overlay(dets)
    dlib.hit_enter_to_continue()

# Finally, note that you don't have to use the XML based input to
# train_simple_object_detector().  If you have already loaded your training
# images and bounding boxes for the objects then you can call it as shown
# below.

# You just need to put your images into a list.
images = [io.imread(faces_folder + '/2008_002506.jpg'),
          io.imread(faces_folder + '/2009_004587.jpg')]
# Then for each image you make a list of rectangles which give the pixel
# locations of the edges of the boxes.
boxes_img1 = ([dlib.rectangle(left=329, top=78, right=437, bottom=186),
               dlib.rectangle(left=224, top=95, right=314, bottom=185),
               dlib.rectangle(left=125, top=65, right=214, bottom=155)])
boxes_img2 = ([dlib.rectangle(left=154, top=46, right=228, bottom=121),
               dlib.rectangle(left=266, top=280, right=328, bottom=342)])
# And then you aggregate those lists of boxes into one big list and then call
# train_simple_object_detector().
boxes = [boxes_img1, boxes_img2]

detector2 = dlib.train_simple_object_detector(images, boxes, options)
# We could save this detector to disk by uncommenting the following.
#detector2.save('detector2.svm')

# Now let's look at its HOG filter!
win_det.set_image(detector2)
dlib.hit_enter_to_continue()

# Note that you don't have to use the XML based input to
# test_simple_object_detector().  If you have already loaded your training
# images and bounding boxes for the objects then you can call it as shown
# below.
print("\nTraining accuracy: {}".format(
    dlib.test_simple_object_detector(images, boxes, detector2)))


#!/usr/bin/python
# The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
#
#   This example program shows how to use dlib's implementation of the paper:
#   One Millisecond Face Alignment with an Ensemble of Regression Trees by
#   Vahid Kazemi and Josephine Sullivan, CVPR 2014
#
#   In particular, we will train a face landmarking model based on a small
#   dataset and then evaluate it.  If you want to visualize the output of the
#   trained model on some images then you can run the
#   face_landmark_detection.py example program with predictor.dat as the input
#   model.
#
#   It should also be noted that this kind of model, while often used for face
#   landmarking, is quite general and can be used for a variety of shape
#   prediction tasks.  But here we demonstrate it only on a simple face
#   landmarking task.
#
# COMPILING/INSTALLING THE DLIB PYTHON INTERFACE
#   You can install dlib using the command:
#       pip install dlib
#
#   Alternatively, if you want to compile dlib yourself then go into the dlib
#   root folder and run:
#       python setup.py install
#   or
#       python setup.py install --yes USE_AVX_INSTRUCTIONS
#   if you have a CPU that supports AVX instructions, since this makes some
#   things run faster.
#
#   Compiling dlib should work on any operating system so long as you have
#   CMake and boost-python installed.  On Ubuntu, this can be done easily by
#   running the command:
#       sudo apt-get install libboost-python-dev cmake
#
#   Also note that this example requires scikit-image which can be installed
#   via the command:
#       pip install scikit-image
#   Or downloaded from http://scikit-image.org/download.html.

import os
import sys
import glob

import dlib
from skimage import io

# In this example we are going to train a face detector based on the small
# faces dataset in the examples/faces directory.  This means you need to supply
# the path to this faces folder as a command line argument so we will know
# where it is.
if len(sys.argv) != 2:
    print(
        "Give the path to the examples/faces directory as the argument to this "
        "program. For example, if you are in the python_examples folder then "
        "execute this program by running:\n"
        "    ./train_shape_predictor.py ../examples/faces")
    exit()
faces_folder = sys.argv[1]

options = dlib.shape_predictor_training_options()
# Now make the object responsible for training the model.
# This algorithm has a bunch of parameters you can mess with.  The
# documentation for the shape_predictor_trainer explains all of them.
# You should also read Kazemi's paper which explains all the parameters
# in great detail.  However, here I'm just setting three of them
# differently than their default values.  I'm doing this because we
# have a very small dataset.  In particular, setting the oversampling
# to a high amount (300) effectively boosts the training set size, so
# that helps this example.
options.oversampling_amount = 300
# I'm also reducing the capacity of the model by explicitly increasing
# the regularization (making nu smaller) and by using trees with
# smaller depths.
options.nu = 0.05
options.tree_depth = 2
options.be_verbose = True

# dlib.train_shape_predictor() does the actual training.  It will save the
# final predictor to predictor.dat.  The input is an XML file that lists the
# images in the training dataset and also contains the positions of the face
# parts.
training_xml_path = os.path.join(faces_folder, "training_with_face_landmarks.xml")
dlib.train_shape_predictor(training_xml_path, "predictor.dat", options)

# Now that we have a model we can test it.  dlib.test_shape_predictor()
# measures the average distance between a face landmark output by the
# shape_predictor and where it should be according to the truth data.
print("\nTraining accuracy: {}".format(
    dlib.test_shape_predictor(training_xml_path, "predictor.dat")))
# The real test is to see how well it does on data it wasn't trained on.  We
# trained it on a very small dataset so the accuracy is not extremely high, but
# it's still doing quite good.  Moreover, if you train it on one of the large
# face landmarking datasets you will obtain state-of-the-art results, as shown
# in the Kazemi paper.
testing_xml_path = os.path.join(faces_folder, "testing_with_face_landmarks.xml")
print("Testing accuracy: {}".format(
    dlib.test_shape_predictor(testing_xml_path, "predictor.dat")))

# Now let's use it as you would in a normal application.  First we will load it
# from disk. We also need to load a face detector to provide the initial
# estimate of the facial location.
predictor = dlib.shape_predictor("predictor.dat")
detector = dlib.get_frontal_face_detector()

# Now let's run the detector and shape_predictor over the images in the faces
# folder and display the results.
print("Showing detections and predictions on the images in the faces folder...")
win = dlib.image_window()
for f in glob.glob(os.path.join(faces_folder, "*.jpg")):
    print("Processing file: {}".format(f))
    img = io.imread(f)

    win.clear_overlay()
    win.set_image(img)

    # Ask the detector to find the bounding boxes of each face. The 1 in the
    # second argument indicates that we should upsample the image 1 time. This
    # will make everything bigger and allow us to detect more faces.
    dets = detector(img, 1)
    print("Number of faces detected: {}".format(len(dets)))
    for k, d in enumerate(dets):
        print("Detection {}: Left: {} Top: {} Right: {} Bottom: {}".format(
            k, d.left(), d.top(), d.right(), d.bottom()))
        # Get the landmarks/parts for the face in box d.
        shape = predictor(img, d)
        print("Part 0: {}, Part 1: {} ...".format(shape.part(0),
                                                  shape.part(1)))
        # Draw the face landmarks on the screen.
        win.add_overlay(shape)

    win.add_overlay(dets)
    dlib.hit_enter_to_continue()


#!/usr/bin/python
# The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
#
# This example shows how to use the correlation_tracker from the dlib Python
# library.  This object lets you track the position of an object as it moves
# from frame to frame in a video sequence.  To use it, you give the
# correlation_tracker the bounding box of the object you want to track in the
# current video frame.  Then it will identify the location of the object in
# subsequent frames.
#
# In this particular example, we are going to run on the
# video sequence that comes with dlib, which can be found in the
# examples/video_frames folder.  This video shows a juice box sitting on a table
# and someone is waving the camera around.  The task is to track the position of
# the juice box as the camera moves around.
#
#
# COMPILING/INSTALLING THE DLIB PYTHON INTERFACE
#   You can install dlib using the command:
#       pip install dlib
#
#   Alternatively, if you want to compile dlib yourself then go into the dlib
#   root folder and run:
#       python setup.py install
#   or
#       python setup.py install --yes USE_AVX_INSTRUCTIONS
#   if you have a CPU that supports AVX instructions, since this makes some
#   things run faster.
#
#   Compiling dlib should work on any operating system so long as you have
#   CMake and boost-python installed.  On Ubuntu, this can be done easily by
#   running the command:
#       sudo apt-get install libboost-python-dev cmake
#
#   Also note that this example requires scikit-image which can be installed
#   via the command:
#       pip install scikit-image
#   Or downloaded from http://scikit-image.org/download.html.

import os
import glob

import dlib
from skimage import io

# Path to the video frames
video_folder = os.path.join("..", "examples", "video_frames")

# Create the correlation tracker - the object needs to be initialized
# before it can be used
tracker = dlib.correlation_tracker()

win = dlib.image_window()
# We will track the frames as we load them off of disk
for k, f in enumerate(sorted(glob.glob(os.path.join(video_folder, "*.jpg")))):
    print("Processing Frame {}".format(k))
    img = io.imread(f)

    # We need to initialize the tracker on the first frame
    if k == 0:
        # Start a track on the juice box. If you look at the first frame you
        # will see that the juice box is contained within the bounding
        # box (74, 67, 112, 153).
        tracker.start_track(img, dlib.rectangle(74, 67, 112, 153))
    else:
        # Else we just attempt to track from the previous frame
        tracker.update(img)

    win.clear_overlay()
    win.set_image(img)
    win.add_overlay(tracker.get_position())
    dlib.hit_enter_to_continue()


dlib C++ Library - Frequently Asked Questions

The Library
  • Algorithms
  • API Wrappers
  • Bayesian Nets
  • Compression
  • Containers
  • Graph Tools
  • Image Processing
  • Linear Algebra
  • Machine Learning
  • Metaprogramming
  • Miscellaneous
  • Networking
  • Optimization
  • Parsing

Help/Info
  • Dlib Blog
  • Examples: C++
    • 3D Point Cloud
    • Assignment Learning
    • Base64 Encoder
    • Bayesian Network From Disk
    • Bayesian Network GUI
    • Bayesian Network
    • Bridge
    • BSP
    • C-Support Vector Machine
    • Cmd Line Parser
    • Compress Stream
    • Config File Reader
    • Custom Trainers
    • Directory Navigation
    • Empirical Kernel Map
    • Face Detection
    • Face Landmark Detection
    • FHOG Feature Extraction
    • FHOG Object Detection
    • Graph Labeling
    • GUI
    • Hough Transform
    • HTTP Server
    • Image
    • IO Socket Streams
    • IO Streams Server
    • Kernel Centroid
    • Kernel K-Means Clustering
    • Kernel Ridge Regression
    • Kernel RLS Filtering
    • Kernel RLS Regression
    • KRR Classification
    • Learning to Track
    • Linear Assignment Problems
    • Linear Manifold Regularizer
    • Linear Model Predictive Control
    • Logger Advanced
    • Logger Custom Output
    • Logger
    • Matrix Expressions
    • Matrix
    • Member Function Pointer
    • Model Selection
    • Multiclass Classification
    • Multithreaded Object
    • Neural Network
    • Non-Linear Least Squares
    • Nu-Support Vector Machine
    • Numerical Integration
    • Object Detector Advanced
    • Object Detector
    • One Class Classifiers
    • Online SVM
    • Optimization
    • Parallel For Loops
    • Pipe 2
    • Pipe
    • Quantum Computing
    • Queue
    • Rank Features
    • Relevance Vector Classification
    • Relevance Vector Regression
    • Running Stats
    • Sequence Labeling
    • Sequence Segmentation
    • Sockets
    • Sockstreambuf
    • Sparse Vectors
    • SQLite
    • Std C++ Allocator
    • Structural Support Vector Machines
    • Support Vector Regression
    • SURF
    • SVM-Rank
    • Thread Function
    • Thread Pool
    • Threaded Object
    • Threads
    • Timer
    • Train Object Detector
    • Train Shape Predictor
    • Using Custom Kernels
    • Video Object Tracking
    • Webcam Face Pose Estimation
    • XML Parser
  • Examples: Python
    • Face Detector
    • Face Landmark Detection
    • find candidate object locations
    • Linear Assignment Problems
    • Sequence Segmenter
    • Structural Support Vector Machines
    • SVM-Rank
    • Train Object Detector
    • Train Shape Predictor
    • Video Object Tracking
  • FAQ
  • Forums
  • Home
  • How to compile
  • How to contribute
  • Index
  • Introduction
  • License
  • Python API
  • Suggested Books
  • Who uses dlib?

Current Release
  • Change Log
  • Release Notes
  • Version: 18.18

Last Modified:
Jan 31, 2015
Frequently Asked Questions

General

  • How can I cite dlib?
  • How can I use dlib in Visual Studio?
  • How do I set the size of a matrix at runtime?
  • How does dlib interface with other libraries/tools?
  • Where is the documentation for <object/function>?
  • Why is dlib slow?
  • Why isn't serialization working?

Machine Learning

  • Can you give advice on feature generation/kernel selection?
  • How can I define a custom kernel?
  • Why does my decision_function always give the same output?
  • Why is cross_validate_trainer_threaded() crashing?
  • Why is RVM training is really slow?
[top]

How can I cite dlib?

If you use dlib in your research then please use the following citation:

Davis E. King. Dlib-ml: A Machine Learning Toolkit. Journal of Machine Learning Research 10, pp. 1755-1758, 2009

@Article{dlib09,
  author = {Davis E. King},
  title = {Dlib-ml: A Machine Learning Toolkit},
  journal = {Journal of Machine Learning Research},
  year = {2009},
  volume = {10},
  pages = {1755-1758},
}
[top]

How can I use dlib in Visual Studio?

There are instructions on the How to Compile page. If you do not understand the instructions in the "Compiling on Windows Using Visual Studio" section or are getting errors then follow the instructions in the "Compiling on Any Operating System Using CMake" section. In particular, install CMake and then type these exact commands from within the root of the dlib distribution:
cd examples
mkdir build
cd build
del /F /S /Q *
cmake ..
cmake --build . --config Release
That should compile the dlib examples in visual studio. The output executables will appear in the Release folder. The del /F /S /Q * command is to make sure you clear out any extraneous files you might have placed in the build folder and is not necessary if build begins empty.
[top]

How do I set the size of a matrix at runtime?

Long answer, read the matrix example program.

Short answer, here are some examples:
matrix<double> mat;
mat.set_size(4,5);

matrix<double,0,1> column_vect;
column_vect.set_size(6);

matrix<double,0,1> column_vect2(6);  // give size to constructor

matrix<double,1> row_vect;
row_vect.set_size(5);
[top]

How does dlib interface with other libraries/tools?

There should never be anything in dlib that prevents you from using or interacting with other libraries. Moreover, there are some additional tools in dlib to make some interactions easier:
  • BLAS and LAPACK libraries are used by the matrix automatically if you #define DLIB_USE_BLAS and/or DLIB_USE_LAPACK and link against the appropriate library files. Note that the CMakeLists.txt file that comes with dlib will do this for you automatically in many instances.

  • Armadillo and Eigen libraries have matrix objects which can be converted into dlib matrix objects by calling dlib::mat() on them.

  • OpenCV image objects can be converted into a form usable by dlib routines by using cv_image. You can also convert from a dlib matrix or image to an OpenCV Mat using dlib::toMat().

  • Google Protocol Buffers can be serialized by the dlib serialization routines. This means that, for example, you can pass protocol buffer objects through a bridge.

  • libpng and libjpeg are used by load_image whenever DLIB_PNG_SUPPORT and DLIB_JPEG_SUPPORT are defined respectively. You must also tell your compiler to link against these libraries to use them. However, CMake will try to link against them automatically if they are installed.

  • SQLite is used by the database object. In fact, it is just a wrapper around SQLite's C interface which simplifies its use (e.g. makes resource management use RAII).
[top]

Where is the documentation for <object/function>?

If you can't find something then check the index.

Also, the bulk of the documentation can be found by following the Detailed Documentation links.
[top]

Why is dlib slow?

Dlib isn't slow. I get this question many times a week and 95% of the time it's from someone using Visual Studio who has compiled their program in Debug mode rather than the optimized Release mode. So if you are using Visual Studio then realize that Visual Studio has these two modes. The default is Debug. The mode is selectable via a drop down:

Debug mode disables compiler optimizations. So the program will be very slow if you run it in Debug mode. So click the drop down,

and select Release.

Then when you compile the program it will appear in a folder named Release rather than in a folder named Debug.

Finally, you can enable either SSE4 or AVX instruction use. These will make certain operations much faster (e.g. face detection). You do this using CMake's cmake-gui tool. For example, if you execute these commands you will get the cmake-gui screen:
cd examples
mkdir build
cd build
cmake ..
cmake-gui .
Which looks like this:

Where you can select SSE4 or AVX instruction use. Then you click configure and then generate. After that when you build your visual studio project some things will be faster. Finally, note that AVX is a little bit faster than SSE4 but if your computer is fairly old it might not support it. In that case, either buy a new computer or use SSE4 instructions.
[top]

Why isn't serialization working?

Here are the possibilities:
  • You are using a file stream and forgot to put it into binary mode. You need to do something like this:
    std::ifstream fin("myfile", std::ios::binary);
    or
    std::ofstream fout("myfile", std::ios::binary);
    If you don't give std::ios::binary then the iostream will mess with the binary data and cause serialization to not work right.

  • The iostream is in a bad state. You can check the state by calling mystream.good(). If it returns false then the stream is in an error state such as end-of-file or maybe it failed to do the I/O. Also note that if you close a file stream and reopen it you might have to call mystream.clear() to clear out the error flags.
[top]

Can you give advice on feature generation/kernel selection?

Picking the right kernel all comes down to understanding your data, and obviously this is highly dependent on your problem.

One thing that's sometimes useful is to plot each feature against the target value. You can get an idea of what your overall feature space looks like and maybe tell if a linear kernel is the right solution. But this still hides important information from you. For example, imagine you have two diagonal lines which are very close together and are both the same length. Suppose one line is of the +1 class and the other is the -1 class. Each feature (the x or y coordinate values) by itself tells you almost nothing about which class a point belongs to but together they tell you everything you need to know.

On the other hand, if you know something about the data you are working with then you can also try and generate your own features. So for example, if your data is a bunch of images and you know that one of your classes contains a lot of lines then you can make a feature that attempts to measure the number of lines in an image using a hough transform or sobel edge filter or whatever. Generally, try and think up features which should be highly correlated with your target value. A good way to do this is to try and actually hand code N solutions to the problem using whatever you know about your data or domain. If you do a good job then you will have N really great features and a linear or rbf kernel will probably do very well when using them.

Or you can just try a whole bunch of kernels, kernel parameters, and training algorithm options while using cross validation. I.e. when in doubt, use brute force :) There is an example of that kind of thing in the model selection example program.

[top]

How can I define a custom kernel?

See the Using Custom Kernels example program.
[top]

Why does my decision_function always give the same output?

This happens when you use the radial_basis_kernel and you set the gamma value to something highly inappropriate. To understand what's happening lets imagine your data has just one feature and its value ranges from 0 to 7. Then what you want is a gamma value that gives nice Gaussian bumps like the one in this graph:

However, if you make gamma really huge you will get this (it's zero everywhere except for one place):

Or if you make gamma really small then it will be 1.0 everywhere:

So you need to pick the gamma value so that it is scaled reasonably to your data. A good rule of thumb (i.e. not the optimal gamma, just a heuristic guess) is the following:

const double gamma = 1.0/compute_mean_squared_distance(randomly_subsample(samples, 2000));
[top]

Why is cross_validate_trainer_threaded() crashing?

This function makes a copy of your training data for each thread. So you are probably running out of memory. To avoid this, use the randomly_subsample function to reduce the amount of data you are using or use fewer threads.

For example, you could reduce the amount of data by saying this:

// reduce to only 1000 samples
cross_validate_trainer_threaded(trainer,
                                randomly_subsample(samples, 1000),
                                randomly_subsample(labels,  1000),
                                4,   // num folds
                                4);  // num threads

[top]

Why is RVM training is really slow?

The optimization algorithm is somewhat unpredictable. Sometimes it is fast and sometimes it is slow. What usually makes it really slow is if you use a radial basis kernel and you set the gamma parameter to something too large. This causes the algorithm to start using a whole lot of relevance vectors (i.e. basis vectors) which then makes it slow. The algorithm is only fast as long as the number of relevance vectors remains small but it is hard to know beforehand if that will be the case.

You should try kernel ridge regression instead since it also doesn't take any parameters but is always very fast.


dlib C++ Library

The Library
  • Algorithms
  • API Wrappers
  • Bayesian Nets
  • Compression
  • Containers
  • Graph Tools
  • Image Processing
  • Linear Algebra
  • Machine Learning
  • Metaprogramming
  • Miscellaneous
  • Networking
  • Optimization
  • Parsing

Help/Info
  • Dlib Blog
  • Examples: C++
    • 3D Point Cloud
    • Assignment Learning
    • Base64 Encoder
    • Bayesian Network From Disk
    • Bayesian Network GUI
    • Bayesian Network
    • Bridge
    • BSP
    • C-Support Vector Machine
    • Cmd Line Parser
    • Compress Stream
    • Config File Reader
    • Custom Trainers
    • Directory Navigation
    • Empirical Kernel Map
    • Face Detection
    • Face Landmark Detection
    • FHOG Feature Extraction
    • FHOG Object Detection
    • Graph Labeling
    • GUI
    • Hough Transform
    • HTTP Server
    • Image
    • IO Socket Streams
    • IO Streams Server
    • Kernel Centroid
    • Kernel K-Means Clustering
    • Kernel Ridge Regression
    • Kernel RLS Filtering
    • Kernel RLS Regression
    • KRR Classification
    • Learning to Track
    • Linear Assignment Problems
    • Linear Manifold Regularizer
    • Linear Model Predictive Control
    • Logger Advanced
    • Logger Custom Output
    • Logger
    • Matrix Expressions
    • Matrix
    • Member Function Pointer
    • Model Selection
    • Multiclass Classification
    • Multithreaded Object
    • Neural Network
    • Non-Linear Least Squares
    • Nu-Support Vector Machine
    • Numerical Integration
    • Object Detector Advanced
    • Object Detector
    • One Class Classifiers
    • Online SVM
    • Optimization
    • Parallel For Loops
    • Pipe 2
    • Pipe
    • Quantum Computing
    • Queue
    • Rank Features
    • Relevance Vector Classification
    • Relevance Vector Regression
    • Running Stats
    • Sequence Labeling
    • Sequence Segmentation
    • Sockets
    • Sockstreambuf
    • Sparse Vectors
    • SQLite
    • Std C++ Allocator
    • Structural Support Vector Machines
    • Support Vector Regression
    • SURF
    • SVM-Rank
    • Thread Function
    • Thread Pool
    • Threaded Object
    • Threads
    • Timer
    • Train Object Detector
    • Train Shape Predictor
    • Using Custom Kernels
    • Video Object Tracking
    • Webcam Face Pose Estimation
    • XML Parser
  • Examples: Python
    • Face Detector
    • Face Landmark Detection
    • find candidate object locations
    • Linear Assignment Problems
    • Sequence Segmenter
    • Structural Support Vector Machines
    • SVM-Rank
    • Train Object Detector
    • Train Shape Predictor
    • Video Object Tracking
  • FAQ
  • Forums
  • Home
  • How to compile
  • How to contribute
  • Index
  • Introduction
  • License
  • Python API
  • Suggested Books
  • Who uses dlib?

Current Release
  • Change Log
  • Release Notes
  • Version: 18.18

Last Modified:
Oct 28, 2015

Dlib is a modern C++ toolkit containing machine learning algorithms and tools for creating complex software in C++ to solve real world problems. It is open source software and licensed under the Boost Software License. The introduction contains everything you need to know to get started using the library. However, if after consulting the documentation, you have any questions, comments, or complaints feel free to post in the forums.

For updates to this project see dlib.net.

Major Features

  • Documentation
    • Unlike a lot of open source projects, this one provides complete and precise documentation for every class and function. There are also debugging modes that check the documented preconditions for functions. When this is enabled it will catch the vast majority of bugs caused by calling functions incorrectly or using objects in an incorrect manner.
    • Lots of example programs are provided
    • I consider the documentation to be the most important part of the library. So if you find anything that isn't documented, isn't clear, or has out of date documentation, tell me and I will fix it.
  • High Quality Portable Code
    • Good unit test coverage. The ratio of unit test lines of code to library lines of code is about 1 to 4.
    • The library is tested regularly on MS Windows, Linux, and Mac OS X systems. However, it should work on any POSIX system and has been used on Solaris, HPUX, and the BSDs.
    • No other packages are required to use the library. Only APIs that are provided by an out of the box OS are needed.
    • There is no installation or configure step needed before you can use the library. See the How to compile page for details.
    • All operating system specific code is isolated inside the OS abstraction layers which are kept as small as possible. The rest of the library is either layered on top of the OS abstraction layers or is pure ISO standard C++.
  • Machine Learning Algorithms
    • Conventional SMO based Support Vector Machines for classification and regression
    • Reduced-rank methods for large-scale classification and regression
    • Relevance vector machines for classification and regression
    • General purpose multiclass classification tools
    • A Multiclass SVM
    • A tool for solving the optimization problem associated with structural support vector machines.
    • Structural SVM tools for sequence labeling
    • Structural SVM tools for solving assignment problems
    • Structural SVM tools for object detection in images
    • Structural SVM tools for labeling nodes in graphs
    • A large-scale SVM-Rank implementation
    • An online kernel RLS regression algorithm
    • An online SVM classification algorithm
    • Semidefinite Metric Learning
    • An online kernelized centroid estimator/novelty detector and offline support vector one-class classification
    • Clustering algorithms: linear or kernel k-means, Chinese Whispers, and Newman clustering.
    • Radial Basis Function Networks
    • Multi layer perceptrons
  • Numerical Algorithms
    • A fast matrix object implemented using the expression templates technique and capable of using BLAS and LAPACK libraries when available.
    • Numerous linear algebra and mathematical operations are defined for the matrix object such as the singular value decomposition, transpose, trig functions, etc.
    • General purpose unconstrained non-linear optimization algorithms using the conjugate gradient, BFGS, and L-BFGS techniques
    • Levenberg-Marquardt for solving non-linear least squares problems
    • Box-constrained derivative-free optimization via the BOBYQA algorithm
    • An implementation of the Optimized Cutting Plane Algorithm
    • Several quadratic program solvers
    • Combinatorial optimization tools for solving optimal assignment and min cut/max flow problems as well as the CKY algorithm for finding the most probable parse tree
    • A big integer object
    • A random number object
  • Graphical Model Inference Algorithms
    • Join tree algorithm for exact inference in a Bayesian network.
    • Gibbs sampler markov chain monte carlo algorithm for approximate inference in a Bayesian network.
    • Routines for performing MAP inference in chain-structured, Potts, or general factor graphs.
  • Image Processing
    • Routines for reading and writing common image formats.
    • Automatic color space conversion between various pixel types
    • Common image operations such as edge finding and morphological operations
    • Implementations of the SURF, HOG, and FHOG feature extraction algorithms.
    • Tools for detecting objects in images including frontal face detection and object pose estimation.
  • Threading
    • The library provides a portable and simple threading API
    • A message passing pipe for inter-thread and inter-process communication
    • A timer object capable of generating events that are regularly spaced in time
    • Threaded objects
    • Threaded functions
    • Parallel for loops
    • A thread_pool with support for futures
  • Networking
    • The library provides a portable and simple TCP sockets API
    • An object to help you make TCP based servers
    • iostream and streambuf objects that enables TCP sockets to interoperate with the C++ iostreams library
    • A simple HTTP server object you can use to embed a web server into your applications
    • A message passing pipe for inter-thread and inter-process communication
    • A tool used to implement algorithms using the Bulk Synchronous Parallel (BSP) computing model
  • Graphical User Interfaces
    • The library provides a portable and simple core GUI API
    • Implemented on top of the core GUI API are numerous widgets
    • Unlike many other GUI toolkits, the entire dlib GUI toolkit is threadsafe
  • Data Compression and Integrity Algorithms
    • A CRC 32 object
    • MD5 functions
    • Various abstracted objects representing parts of data compression algorithms. Many forms of the PPM algorithm are included.
  • Testing
    • A thread safe logger object styled after the popular Java logger log4j
    • A modular unit testing framework
    • Various assert macros useful for testing preconditions
  • General Utilities
    • A type-safe object to convert between big and little endian byte orderings
    • A command line parser with the ability to parse and validate command lines with various types of arguments and options
    • An XML parser
    • An object that can perform base64 conversions
    • Many container classes
    • Serialization support
    • Many memory manager objects that implement different memory pooling strategies
    • A tool that lets you easily call C++ from MATLAB


dlib C++ Library - How to compile

The Library
  • Algorithms
  • API Wrappers
  • Bayesian Nets
  • Compression
  • Containers
  • Graph Tools
  • Image Processing
  • Linear Algebra
  • Machine Learning
  • Metaprogramming
  • Miscellaneous
  • Networking
  • Optimization
  • Parsing

Help/Info
  • Dlib Blog
  • Examples: C++
    • 3D Point Cloud
    • Assignment Learning
    • Base64 Encoder
    • Bayesian Network From Disk
    • Bayesian Network GUI
    • Bayesian Network
    • Bridge
    • BSP
    • C-Support Vector Machine
    • Cmd Line Parser
    • Compress Stream
    • Config File Reader
    • Custom Trainers
    • Directory Navigation
    • Empirical Kernel Map
    • Face Detection
    • Face Landmark Detection
    • FHOG Feature Extraction
    • FHOG Object Detection
    • Graph Labeling
    • GUI
    • Hough Transform
    • HTTP Server
    • Image
    • IO Socket Streams
    • IO Streams Server
    • Kernel Centroid
    • Kernel K-Means Clustering
    • Kernel Ridge Regression
    • Kernel RLS Filtering
    • Kernel RLS Regression
    • KRR Classification
    • Learning to Track
    • Linear Assignment Problems
    • Linear Manifold Regularizer
    • Linear Model Predictive Control
    • Logger Advanced
    • Logger Custom Output
    • Logger
    • Matrix Expressions
    • Matrix
    • Member Function Pointer
    • Model Selection
    • Multiclass Classification
    • Multithreaded Object
    • Neural Network
    • Non-Linear Least Squares
    • Nu-Support Vector Machine
    • Numerical Integration
    • Object Detector Advanced
    • Object Detector
    • One Class Classifiers
    • Online SVM
    • Optimization
    • Parallel For Loops
    • Pipe 2
    • Pipe
    • Quantum Computing
    • Queue
    • Rank Features
    • Relevance Vector Classification
    • Relevance Vector Regression
    • Running Stats
    • Sequence Labeling
    • Sequence Segmentation
    • Sockets
    • Sockstreambuf
    • Sparse Vectors
    • SQLite
    • Std C++ Allocator
    • Structural Support Vector Machines
    • Support Vector Regression
    • SURF
    • SVM-Rank
    • Thread Function
    • Thread Pool
    • Threaded Object
    • Threads
    • Timer
    • Train Object Detector
    • Train Shape Predictor
    • Using Custom Kernels
    • Video Object Tracking
    • Webcam Face Pose Estimation
    • XML Parser
  • Examples: Python
    • Face Detector
    • Face Landmark Detection
    • find candidate object locations
    • Linear Assignment Problems
    • Sequence Segmenter
    • Structural Support Vector Machines
    • SVM-Rank
    • Train Object Detector
    • Train Shape Predictor
    • Video Object Tracking
  • FAQ
  • Forums
  • Home
  • How to compile
  • How to contribute
  • Index
  • Introduction
  • License
  • Python API
  • Suggested Books
  • Who uses dlib?

Current Release
  • Change Log
  • Release Notes
  • Version: 18.18

Last Modified:
Oct 27, 2015
How to compile

Compiling C++ Example Programs on Any Operating System Using CMake

The best way to compile a program that uses dlib is to use CMake. For example, the following commands will compile the example programs on any operating system:
cd examples
mkdir build
cd build
cmake ..
cmake --build . --config Release
Note that you also need to have a C++ compiler installed on your system. There are free C++ compilers for most operating systems. For example, Visual Studio Express is free on Windows and GCC is free and works well on Mac OS X and Linux systems. If you have multiple compilers/IDEs installed then you can tell CMake which one you want it to use via the -G option.

The examples/CMakeLists.txt file tells CMake how to build the examples. You can create your own projects by starting with this file and editing it however you like. You can also perform additional configuration of a cmake project using the cmake-gui or ccmake tool. For example, if you are using dlib's face detector then you should turn on either SSE4 or AVX instructions since this makes it run much faster (also see this FAQ).

Finally, note that when using Visual Studio, CMake will by default generate a 32bit executable. This means the programs you compile will only be able to use 2GB of RAM. To avoid this, you need to tell CMake to generate a 64bit executable. You do this by using a command like

cmake -G "Visual Studio 10 2010 Win64" ..
instead of
cmake ..
You can see the list of valid arguments to -G by running cmake with no options.

Compiling Dlib's Python Interface

Go to the base folder of the dlib repository and run python setup.py install. That should compile and install the dlib python API on your system.

Alternatively, if you want to add more python bindings to dlib's python interface then you probably want to avoid the setup.py file and work directly using CMake. In particular, dlib's python API is built by the CMake project in the tools/python folder. You build this project using the usual CMake commands and when compiled it outputs the dlib shared library that defines the python API for dlib.

Compiling C++ Examples Without CMake

In most cases, to use this library all you have to do is extract it somewhere, make sure the folder containing the dlib folder is in your include path, and finally add dlib/all/source.cpp to your project. It is worth noting that most of dlib is "header-only" which means that, in many cases, you don't actually have to build dlib/all/source.cpp into your application. So if you don't get linker errors when you exclude dlib/all/source.cpp from your project then you don't need it.

An example makefile that uses this library can be found here: dlib/test/makefile. It is the makefile used to build the regression test suite for this library.

Again, note that you should not add the dlib folder itself to your compiler's include path. Doing so will cause the build to fail because of name collisions (e.g. dlib/string.h with string.h from the standard library). Instead you should add the folder that contains the dlib folder to your include search path and then use include statements of the form #include <dlib/queue.h>. This will ensure that everything builds correctly.

Note also that if you want to work with jpeg/png files using dlib then you will need to link your program with libjpeg and/or libpng. You also need to tell dlib about this by defining the DLIB_JPEG_SUPPORT and DLIB_PNG_SUPPORT preprocessor directives. How you "link to libjpeg/libpng" varies from platform to platform. On UNIX machines you usually just add a -ljpeg or -lpng switch to your compiler (after installing the libraries). On windows it's less well defined. So dlib comes with a copy of these libraries in the dlib/external folder so that you can statically compile them into your application if no system wide version is available on your machine. If all this talk about linking is confusing to you then just use CMake. It will set this all up for you.

Dlib is also capable of using any optimized BLAS or LAPACK libraries that are installed on your system. Linking to these libraries will make many things run faster. To do this you define the DLIB_USE_BLAS and/or DLIB_USE_LAPACK preprocessor directives and then link your program with whatever BLAS or LAPACK libraries you have. If you use CMake it will set this up automatically.

Compiling on Linux From Command Line

From within the examples folder, you can compile nearly all of the examples with a single command like so:
g++ -O3 -I.. ../dlib/all/source.cpp -lpthread -lX11 example_program_name.cpp
Note that not all examples require this much work. For example, the svm_ex.cpp example can be compiled with just:
g++ -O3 -I.. svm_ex.cpp
On non-Linux systems like Solaris, you might have to link to other libraries. For example, I have seen systems where it was also necessary to supply -lnsl or -lsocket options to g++. Additionally, the X11 development library isn't installed on Ubuntu by default. So if you require it and are using Ubuntu you can install it by typing:
sudo apt-get install libx11-dev

Compiling on Windows Using GCC

The commands for gcc on windows are the same as above but you may also have to link (via the -l option) to the following libraries: gdi32, comctl32, user32, winmm, ws2_32, or imm32. However, it's worth pointing out that Visual Studio Express is free and a much better choice for windows development than gcc.

Compiling on Windows Using Visual Studio

All you need to do is create an empty console project. Then add dlib/all/source.cpp to it and add the folder containing the dlib folder to the #include search path. Then you can compile any example program by adding it to your project.

Again, note that dlib will only be able to work with jpeg and png files if you link in libjpeg and libpng. In Visual Studio, the easiest way to do this is to add all the source files in the dlib/external folder into your project and also define the DLIB_PNG_SUPPORT and DLIB_JPEG_SUPPORT preprocessor directives. If you don't know how to configure Visual Studio then you should use CMake as shown above since it will take care of everything automatically.

Miscellaneous Preprocessor Directives

In addition to the preprocessor directives mentioned above, there are a few more you can supply during the build process to cause the library to build in various optional ways. By default, the library will always do something reasonable, but they are listed here in the event that you need to use them.

#define ENABLE_ASSERTS

Defining this directive causes all the DLIB_ASSERT macros to be active. If you are using Visual Studio or CMake then ENABLE_ASSERTS will be automatically enabled for you when you compile in debug mode. However, if you are using a different build system then you might have to manually enable it if you want to turn the asserts on.

#define DLIB_ISO_CPP_ONLY

This is a #define directive that you can set to cause the library to exclude all non ISO C++ code (The things in the API wrappers section and any objects that depend on those wrappers). This is useful if you are trying to build on a system that isn't fully supported by the library or if you just decide you don't want any of that stuff compiled into your program for your own reasons.

#define DLIB_NO_GUI_SUPPORT

This is just like the DLIB_ISO_CPP_ONLY option except that it excludes only the GUI part of the library. An example of when you might want to use this would be if you don't need GUI support and you are building on a UNIX platform that doesn't have the X11 headers installed.

#define NO_MAKEFILE

This preprocessor directive causes the dlib headers to pull in all the code that would normally be built in dlib/all/source.cpp. Thus if you #define NO_MAKEFILE you won't have to add dlib/all/source.cpp to your project. The only time this is useful is when your project consists of a single translation unit (i.e. a single cpp file). In this instance NO_MAKEFILE allows you to easily build your project on the command line by saying something like g++ -DNO_MAKEFILE project.cpp. But again, this is only for single cpp file projects. If you use NO_MAKEFILE with projects that contain more than one cpp file you will get linker errors about multiply defined symbols.

Also note that if you use this macro then the stack trace functionality in the library will be disabled.

#define DLIB_THREAD_POOL_TIMEOUT <time-in-milliseconds>

If you use dlib to create your threads then you receive the benefit of the dlib dynamic thread pool (Note that the dlib::thread_pool object is something else unrelated to this so don't confuse the two). This pool enables dlib to spawn new threads very rapidly since it draws threads back out of its thread pool when the pool isn't empty.

Thus, when a thread that was created by dlib ends it actually goes back into the dlib thread pool and waits DLIB_THREAD_POOL_TIMEOUT milliseconds before totally terminating and releasing its resources back to the operating system. The default timeout used by this library is 30,000 milliseconds (30 seconds). You may however change this to whatever you like by defining DLIB_THREAD_POOL_TIMEOUT to some new value.


dlib C++ Library - How to Contribute

The Library
  • Algorithms
  • API Wrappers
  • Bayesian Nets
  • Compression
  • Containers
  • Graph Tools
  • Image Processing
  • Linear Algebra
  • Machine Learning
  • Metaprogramming
  • Miscellaneous
  • Networking
  • Optimization
  • Parsing

Help/Info
  • Dlib Blog
  • Examples: C++
    • 3D Point Cloud
    • Assignment Learning
    • Base64 Encoder
    • Bayesian Network From Disk
    • Bayesian Network GUI
    • Bayesian Network
    • Bridge
    • BSP
    • C-Support Vector Machine
    • Cmd Line Parser
    • Compress Stream
    • Config File Reader
    • Custom Trainers
    • Directory Navigation
    • Empirical Kernel Map
    • Face Detection
    • Face Landmark Detection
    • FHOG Feature Extraction
    • FHOG Object Detection
    • Graph Labeling
    • GUI
    • Hough Transform
    • HTTP Server
    • Image
    • IO Socket Streams
    • IO Streams Server
    • Kernel Centroid
    • Kernel K-Means Clustering
    • Kernel Ridge Regression
    • Kernel RLS Filtering
    • Kernel RLS Regression
    • KRR Classification
    • Learning to Track
    • Linear Assignment Problems
    • Linear Manifold Regularizer
    • Linear Model Predictive Control
    • Logger Advanced
    • Logger Custom Output
    • Logger
    • Matrix Expressions
    • Matrix
    • Member Function Pointer
    • Model Selection
    • Multiclass Classification
    • Multithreaded Object
    • Neural Network
    • Non-Linear Least Squares
    • Nu-Support Vector Machine
    • Numerical Integration
    • Object Detector Advanced
    • Object Detector
    • One Class Classifiers
    • Online SVM
    • Optimization
    • Parallel For Loops
    • Pipe 2
    • Pipe
    • Quantum Computing
    • Queue
    • Rank Features
    • Relevance Vector Classification
    • Relevance Vector Regression
    • Running Stats
    • Sequence Labeling
    • Sequence Segmentation
    • Sockets
    • Sockstreambuf
    • Sparse Vectors
    • SQLite
    • Std C++ Allocator
    • Structural Support Vector Machines
    • Support Vector Regression
    • SURF
    • SVM-Rank
    • Thread Function
    • Thread Pool
    • Threaded Object
    • Threads
    • Timer
    • Train Object Detector
    • Train Shape Predictor
    • Using Custom Kernels
    • Video Object Tracking
    • Webcam Face Pose Estimation
    • XML Parser
  • Examples: Python
    • Face Detector
    • Face Landmark Detection
    • find candidate object locations
    • Linear Assignment Problems
    • Sequence Segmenter
    • Structural Support Vector Machines
    • SVM-Rank
    • Train Object Detector
    • Train Shape Predictor
    • Video Object Tracking
  • FAQ
  • Forums
  • Home
  • How to compile
  • How to contribute
  • Index
  • Introduction
  • License
  • Python API
  • Suggested Books
  • Who uses dlib?

Current Release
  • Change Log
  • Release Notes
  • Version: 18.18

Last Modified:
Sep 27, 2015
How to Contribute
There are some simple ways to contribute to dlib:
  • Find confusing or incorrect documentation
  • Help make the web page prettier
  • Link to dlib from your web page
  • Add yourself or your project to the list of dlib users
  • Try to run the dlib regression test suite on any platforms you have access to

Contributing Code

Code contributions are welcome and can be done by submitting a pull request to dlib's github page.

If you want to make a big change or feature addition, it's probably a good idea to talk to me about it first. Additionally, you should read over the coding guidelines below and try to follow them. It is also probably a good idea to read the books Effective C++ and More Effective C++ by Scott Myers.

Coding Guidelines

1. Use Design by Contract
2. Use spaces instead of tabs.
3. Use the standard C++ naming convention
4. Use RAII
5. Don't use pointers
6. Don't use #define for constants.
7. Don't use stack based arrays.
8. Use exceptions, but don't abuse them
9. Write portable code
10. Setup regression tests
11. Use the Boost Software License

  • Apply Design by Contract to Your Code

      The most important part of a software library isn't the code, it is the set of interfaces the library exposes to the user. These interfaces need to be easy to use right, and hard to use wrong. The only way this happens is if the interfaces are documented in a simple, consistent, and precise way.

      The name for the way I design and document these interfaces is known as Design by Contract. There is a lot that can be said about Design by Contract, in fact, whole books have been written about it, and programming languages exist which use Design by Contract as a central element. Here I will just go over some of the basic ways it is used in dlib as well as some of the reasons why it is a Good Thing.

    • Functions should have documented preconditions which are programmatically verifiable

        Many functions have a set of requirements or preconditions that need to be satisfied if they are to be used. If these requirements are not satisfied when a function is called then the function will not do what it is supposed to do. Moreover, any piece of software that calls a function but doesn't make sure all preconditions are satisfied contains a bug, by definition.

        This means all functions must precisely document their preconditions if they are to be usable. In fact, all preconditions should be programmatically verifiable. Doing this has a number of benefits. First, it means they are unambiguous. English can be confusing and vague, but saying "some_predicate == true" uses a formal language, C++, that we all should understand quite well. Second, it means you can put checks into the code that will catch all usage errors.

        These checks should always be implemented using DLIB_ASSERT or DLIB_CASSERT and they should always cover all preconditions. These macros take a boolean argument and if it is false they throw dlib::fatal_error. So you can use them to check that all your preconditions are true. Also, don't forget that a violated function precondition indicates a bug in a program. That is, when dlib::fatal_error is thrown it means a bug has been found and the only thing an application can do at that point is print an error message and terminate. In fact, dlib::fatal_error has checks in it to make sure someone doesn't catch the exception and ignore it. These checks will abruptly terminate any program that attempts to ignore fatal errors.

        The above considerations bring me to my next bit of advice. Developers new to Design by Contract often confuse input validation requirements with function preconditions. When I tell them to consider any violation of a function's preconditions a bug and terminate their application with an error message they complain that this is not at all what an application should do when it receives invalid user inputs. They are right, that would be a bad thing and you should not write software that behaves that way. The way out of this problem is, of course, to not consider invalid input as a bug. Instead, you should perform explicit input validation on any data coming into your program before it gets to any functions that have preconditions which demand the validated inputs. Moreover, if you make your preconditions programmatically verifiable then it should be easy to validate any inputs by simply using whatever it is you use to check your preconditions.

        Consider the function cross_validate_trainer as an example. One of its requirements is that the input forms a valid binary classification problem. This is documented in the list of preconditions as "is_binary_classification_problem(x,y) == true". This precondition is just saying that when you call the is_binary_classification_problem function on the x and y inputs it had better return true if you want to use those inputs with the cross_validate_trainer function. Given this information it is trivial to perform input validation. All you have to do is call is_binary_classification_problem on your input data and you are done.

        Using the above technique you have validated your inputs, documented your preconditions, and are buffered by DLIB_ASSERT statements that will catch you if you accidentally forget to validate any inputs.

        The thing to understand here is that a violation of a function's preconditions means you have a bug on your hands. Or in other words, you should never intentionally violate any function preconditions. But of course it will happen from time to time because bugs are unavoidable. But at least with this approach you will get a detailed error message early in development rather than a mysterious segmentation fault days or weeks later.

    • Functions should have documented postconditions

        I don't have nearly as much to say about postconditions as I did about function requirements. You should strive to write programmatically verifiable postconditions because that makes your postconditions more precise. However, it is sometimes the case that this isn't practical and that is fine. But whatever you do write needs to clearly communicate to the user what it is your function does.

      • Now you may be wondering why this is called Design by Contract and not Documentation by Contract. The reason is that the process of writing down all these detailed descriptions of what your code does becomes part of how you design software. For example, often you will find that when you go to write down the requirements for calling a function you are unable to do so. This may be because the requirements are so complex you can't think of a way to describe them, or you may realize that you don't even know what they are. Alternatively, you may know what they are but discover there isn't any way to verify them programmatically. All these things are symptoms of a bad design and the reason you became aware of this design problem was by attempting to apply Design by Contract.

      After you get enough practice with this way of writing software you begin to think a lot more about questions like "how can I design this class such that every member function has a very simple set of requirements and postconditions?" Once you start doing this you are well on your way to creating software components that are easy to use right, and hard to use wrong.

      The notation dlib uses to document preconditions and postconditions is described in the introduction. All code that goes into dlib must document itself using this notation. You should also separate the implementation and specification of a component into two separate files as described in the introduction. This way users aren't confused or distracted by implementation details when they look at the documentation.

  • Use spaces instead of tabs.

      This is just generally good advice but it is especially important in dlib since everything is viewable as pretty-printed HTML. Tabs show up as 8 characters in most browsers and this results in the HTML version being difficult to read. So don't use tabs. Additionally, please use 4 spaces for each tab level.

  • Don't use capitol letters in the names of variables, functions, or classes. Use the _ character to separate words.

      The reason dlib uses this style is because it is the style used by the C++ standard library. But more importantly, dlib currently provides an interface to users that has a consistent look and feel and it is important to continue to do so.

      As for constants, they should usually contain all upper case letters but all lowercase is ok sometimes.

  • Don't use manual resource management. Use RAII instead.

      You should not be calling new and delete in your own code. You should instead be using objects like the std::vector, scoped_ptr, or any number of other objects that manage resources such as memory for you. If you want an array use std::vector (or the checked std_vector_c). If you want to make a lookup table use a map. If you want a two dimensional array use matrix or array2d.

      These container objects are examples of what is called RAII (Resource Acquisition Is Initialization) in C++. It is essentially a name for the fact that, in C++, you can have totally automated and deterministic resource management by always associating resource acquisition with the construction of an object and resource release with the destruction of an object. I say resource management here rather than memory management because, unlike Java, RAII can be used for more than memory management. For example, when you use a mutex you first lock it, do something, and then you need to remember to unlock it. The RAII way of doing this is to use the auto_mutex which will lock a mutex and automatically unlock it for you. Or suppose you have made a TCP connection to another machine and you want to be certain the resources associated with that connection are always released. You can easily accomplish this with RAII by using the scoped_ptr as shown in this example program.

      RAII is a trivial technique to use. All you have to do is not call new and delete and you will never have another memory leak. Just use the appropriate container instead. Finally, if you don't use RAII then your code is almost certainly not exception safe.

  • Don't use pointers

      There are a number of reasons to not use pointers. First, if you are using pointers then you are probably not using RAII. Second, pointers are ambiguous. When I see a pointer I don't know if it is a pointer to a single item, a pointer to nothing, or a pointer to an array of who knows how many things. On the other hand, when I see a std::vector I know with certainty that I'm dealing with a kind of array. Or if I see a reference to something then I know I'm dealing with exactly one instance of some object.

      Most importantly, it is impossible to validate the state of a pointer. Consider two functions:

      double compute_sum_of_array_elements(const double* array, int array_size);
double compute_sum_of_array_elements(const std::vector<double>& array);
      The first function is inherently unsafe. If the user accidentally passes in an invalid pointer or sets the size argument incorrectly then their program may crash and this will turn into a potentially hard to find bug. This is because there is absolutely nothing you can do inside the first function to tell the difference between a valid pointer and size pair and an invalid pointer and size pair. Nothing. The second function has none of these difficulties.

      If you absolutely need pointer semantics then you can usually use a smart pointer like scoped_ptr or shared_ptr. If that still isn't good enough for you and you really need to use a normal C style pointer then isolate your pointers inside a class or function so that they are contained in a small area of the code. However, in practice the container classes in dlib and the STL are more than sufficient in nearly every case where pointers would otherwise be used.

  • Don't use #define for constants.

      dlib is meant to be integrated into other people's projects. Because of this everything in dlib is contained inside the dlib namespace to avoid naming conflicts with user's code. #defines don't respect namespaces at all. For example, if you #define a constant called SIZE then it will cause a conflict with any piece of code anywhere that contains the identifier SIZE. This means that #define based constants must be avoided and constants should be created using the const keyword instead.

  • Don't use stack based arrays.

      A stack based array, or C style array, is an array declared like this:

      int array[200];
      Most of my criticisms of pointers also apply to stack based arrays. In particular, if you are passing a stack based array to a function then that means you are probably using functions similar to the unsafe compute_sum_of_array_elements() example above.

      The only time it is OK to use this kind of array is when you use it for simple tasks and you don't start passing pointers to the array to other parts of your code. You should also use a constant to store the array size and use that constant in your loops rather than hard coding the size in numerous places.

      But even still, you should use a container class instead and preferably one with the ability to do range checking such as the std_vector_c.

      Consider the following two bits of code:

      for (int i = 0; i < array_size; ++i)
   my_c_array[i] = 4;

for (int i = 0; i < my_std_vector.size(); ++i)
   my_std_vector[i] = 4;
      The second loop clearly doesn't overflow the bounds of the my_std_vector. On the other hand, just by looking at the code in the first loop, we can not tell if it overflows my_c_array. We have to assume that array_size is the appropriate constant but we could be wrong.

      Buffer overflows are probably the most common kind of bug in C and C++ code. These bugs also lead to serious exploitable security holes in software. So please try to avoid stack based arrays.

  • Use exceptions, but don't abuse them.

      Exceptions are one of the great features of modern programming languages. Some people, however, consider that to be a contentious statement. But if you accept the notion that a software library should be hard to use wrong then it becomes difficult to reject exceptions.

      Most of the complaints I hear about exceptions are actually complaints about their misuse rather than objections to the basic idea. So before I begin to defend the above paragraph I would like to lay out more clearly when it is appropriate to use exceptions and when it is not.

      There are two basic questions you should ask yourself when deciding whether to throw an exception in response to some event. The first is (1) "should this event occur in the normal use of my library component?" The second question is (2) "if this event were to occur, is it likely that the user will want to place the code for dealing with the event near the invocations of my library component?"

      If your answers to the above two questions are "no" then you should probably throw an exception in response to the event. On the other hand, if you answer "yes" to either of these questions then you should probably not throw an exception.

      A good example of an event worth throwing exceptions for is running out of memory. (1) It doesn't happen very often, and (2) when it does happen it is hardly ever the case that you want to deal with the out of memory event right next to the place where you are attempting to allocate memory.

      Alternatively, an example of an event that shouldn't throw an exception comes to us from the C++ I/O streams. This part of the standard library allows you to read the contents of a file from disk. When you hit the end of file they do not throw an exception. This is appropriate because (1) you usually want to read a file in its entirety. So hitting EOF happens all the time. Additionally, (2) when you hit EOF you usually want to break out of the loop you are in and continue immediately into the next block of code.

      Usually when someone tells me they don't like exceptions they give reasons like "they make me put try/catch blocks all over the place and it makes the code hard to read." Or "it makes it hard to understand the flow of a program with exceptions in it." Invariably they have been working with bodies of software that disregard the above rules regarding questions 1 and 2. Indeed, when exceptions are used for flow control the results are horrifying. Using exceptions for events that occur in the normal use of a software component, especially when the events need to be dealt with near where they happen result in a spaghetti-like mess of throw statements and try/catch blocks. Clearly, exceptions should be used judiciously. So please, take my advice regarding questions 1 and 2 to heart.

      Now let's go back to my claim that exceptions are an important part of making a library that is hard to use wrong. But first let's be honest about one thing, many developers don't think very hard about error handling and they similarly aren't very careful about checking function return codes. Moreover, even the most studious of us can easily forget to add these checks. It is also easy to forget to add appropriate exception catch blocks.

      So what is so great about exceptions then? Well, let's imagine some error just occurred and it caused an exception to be thrown. If you forgot to setup catch blocks to deal with the error then your program will be aborted. Not exactly a great thing. But you will, however, be able to easily find out what exception was thrown. Additionally, exceptions typically contain a message telling you all about the error. Moreover, any debugger worth its salt will be able to show you a stack trace that lets you see exactly where the exception came from. The exception forces you, the user, to be aware of this potential error and to add a catch block to deal with it. This is where the "hard to use wrong" comes from.

      Now let's imagine that we are using return codes to communicate errors to the user and the same error occurs. If you forgot to do all your return code checking then you will simply be unaware of the error. Maybe your program will crash right away. But more likely, it will continue to run for a while before crashing at some random place far away from the source of the error. You and your debugger now get to spend a few hours of quality time together trying to figure out what went wrong.

      The above considerations are why I maintain that exceptions, when used properly, contribute to the "hard to use wrong" factor of a library. There are also other reasons to use exceptions. They free the user from needing to clutter up code with lots of return code checking. This makes code easier to read and let's you focus more on the algorithm you are trying to implement and less on the bookkeeping.

      Finally, it is important to note that there is a place for return codes. When you answer "no" to questions 1 and 2, I suggest using exceptions. However, if you answer "yes" to even one of them then I would recommend pretty much anything other than throwing an exception. In this case error codes are often an excellent idea.

      As an aside, it is also important that your exception classes inherit from dlib::error to maintain consistency with the rest of the library.

  • Write portable code

    • Don't complicate the build process

        One of dlib's design goals is to not require any installation process before it can be used. A user should be able to copy the dlib folder into their project and have it just work.

        In particular, using dlib in a project should not make it difficult to compile the project from the command line. For example, all the example programs provided with dlib can be compiled using a single statement on the command line.

        Similarly, the user should be able to check the dlib folder into whatever version control system they use without running into any difficulties. The user should then be able to check out copies of the code on any of the dlib supported platforms and have their project build without needing to mess with anything.

    • Don't make assumptions about how objects are laid out in memory.

        If you have been following the prohibition against messing around with pointers then this won't even be an issue for you. Moreover, just about the only time this should even come up is when you are casting blocks of memory into other types or dumping the contents of memory to an I/O channel. All of these things are highly non-portable so don't do them.

        If you want a portable way to write the state of an object to an I/O channel then I recommend you use the serialization capability in dlib. If that doesn't suit your needs then do something else, but whatever you do don't just dump the contents of memory. Convert your data into some portable format and then output that.

        As an example of something else you might do: suppose you have a bunch of integers you want to write to disk. Assuming all your integers are positive numbers representable using 32 or fewer bits you could store all your numbers in dlib::uint32 variables and then convert them into either big or little endian byte order and then write them to an output stream. You could do this using code similar to the following:

        dlib::byte_orderer bo;
...
bo.host_to_big(my_uint);
my_out_stream.write((char*)&my_uint, sizeof(my_uint));
...

        There are three important things to understand about this process. First, you need to pick variables that always have the same size on all platforms. This means you can't use any of the built in C++ types like int, float, double, long, etc. All of these types have different sizes depending on your platform and even compiler settings. So you need to use something like dlib::uint32 to obtain a type of a known size.

        Second, you need to convert each thing you write out into either big or little endian byte order. The reason for this is, again, portability. If you don't explicitly convert to one of these byte orders then you end up writing data out using whatever byte order is used by your current machine. If you do this then only machines that have the same byte order as yours will be able to read in your data. If you use the dlib::byte_orderer object this is easy. It is very type safe. In fact, you should have a hard time even getting it to compile if you use it wrong.

        The third thing you should understand is that you need to write out each of your variables one at a time. You can't write out an entire struct in a single ostream.write() statement because the compiler is allowed to put any kind of padding it feels like between the fields in a struct.

        You may be aware that compilers usually provide #pragma directives that allow you to explicitly control this padding. However, if you want to submit code to dlib you will not use this feature. Not all compilers support it in the same way and, more importantly, not all CPU architectures are even capable of running code that has had the padding messed with. This is because it can result in the CPU attempting to perform what is called an "unaligned load" which many CPUs (like the SPARC) are incapable of doing.

        So in summary, convert your data into a known type with a fixed size, then convert into a specific byte order (like big endian), then write out each variable individually. Or you could just use serialize and not worry about all this horrible stuff. :)

    • All code that calls functions that aren't in dlib or the C++ standard library must be isolated inside the API wrappers.

        If you want to contribute code to dlib which needs to use something that isn't in the C++ standard then we need to introduce a new library component in the API wrappers section. The new component would provide whatever functionality you need. This new component would have to provide at least POSIX and win32 implementations.

        It is also worth pointing out that simple wrappers around operating system specific calls are usually a bad solution. This is because there are invariably subtle, if not huge, differences between what is available on different operating systems. So being truly portable takes a lot of work. It involves reading everything you can find about all the APIs needed to implement the feature on each target platform. In many cases there will be important details that are undocumented and you will only be able to find out about them by searching the internet for other developers complaining about bugs in API functions X, Y, and Z. All this stuff needs to be abstracted away to put a portable and simple interface in front of it. So this is a task that shouldn't be taken lightly.

  • Library components should have regression tests

      dlib has a regression test suite located in the dlib/test folder. Whenever possible, library components should have tests associated with them. GUI components get a pass since it isn't very easy to setup automatic tests for them but pretty much everything else should have some sort of test.

  • You must use the Boost Software License

      Having the library use more than one open source license is confusing so I ask that any code contributions be licensed under the Boost Software License.


dlib C++ Library - Index

The Library
  • Algorithms
  • API Wrappers
  • Bayesian Nets
  • Compression
  • Containers
  • Graph Tools
  • Image Processing
  • Linear Algebra
  • Machine Learning
  • Metaprogramming
  • Miscellaneous
  • Networking
  • Optimization
  • Parsing

Help/Info
  • Dlib Blog
  • Examples: C++
    • 3D Point Cloud
    • Assignment Learning
    • Base64 Encoder
    • Bayesian Network From Disk
    • Bayesian Network GUI
    • Bayesian Network
    • Bridge
    • BSP
    • C-Support Vector Machine
    • Cmd Line Parser
    • Compress Stream
    • Config File Reader
    • Custom Trainers
    • Directory Navigation
    • Empirical Kernel Map
    • Face Detection
    • Face Landmark Detection
    • FHOG Feature Extraction
    • FHOG Object Detection
    • Graph Labeling
    • GUI
    • Hough Transform
    • HTTP Server
    • Image
    • IO Socket Streams
    • IO Streams Server
    • Kernel Centroid
    • Kernel K-Means Clustering
    • Kernel Ridge Regression
    • Kernel RLS Filtering
    • Kernel RLS Regression
    • KRR Classification
    • Learning to Track
    • Linear Assignment Problems
    • Linear Manifold Regularizer
    • Linear Model Predictive Control
    • Logger Advanced
    • Logger Custom Output
    • Logger
    • Matrix Expressions
    • Matrix
    • Member Function Pointer
    • Model Selection
    • Multiclass Classification
    • Multithreaded Object
    • Neural Network
    • Non-Linear Least Squares
    • Nu-Support Vector Machine
    • Numerical Integration
    • Object Detector Advanced
    • Object Detector
    • One Class Classifiers
    • Online SVM
    • Optimization
    • Parallel For Loops
    • Pipe 2
    • Pipe
    • Quantum Computing
    • Queue
    • Rank Features
    • Relevance Vector Classification
    • Relevance Vector Regression
    • Running Stats
    • Sequence Labeling
    • Sequence Segmentation
    • Sockets
    • Sockstreambuf
    • Sparse Vectors
    • SQLite
    • Std C++ Allocator
    • Structural Support Vector Machines
    • Support Vector Regression
    • SURF
    • SVM-Rank
    • Thread Function
    • Thread Pool
    • Threaded Object
    • Threads
    • Timer
    • Train Object Detector
    • Train Shape Predictor
    • Using Custom Kernels
    • Video Object Tracking
    • Webcam Face Pose Estimation
    • XML Parser
  • Examples: Python
    • Face Detector
    • Face Landmark Detection
    • find candidate object locations
    • Linear Assignment Problems
    • Sequence Segmenter
    • Structural Support Vector Machines
    • SVM-Rank
    • Train Object Detector
    • Train Shape Predictor
    • Video Object Tracking
  • FAQ
  • Forums
  • Home
  • How to compile
  • How to contribute
  • Index
  • Introduction
  • License
  • Python API
  • Suggested Books
  • Who uses dlib?

Current Release
  • Change Log
  • Release Notes
  • Version: 18.18

Last Modified:
Oct 22, 2015
Index
[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [Y] [Z]

A

abs
#include <dlib/matrix.h>
abstract
acos
#include <dlib/matrix.h>
add
#include <dlib/sparse_vector.h>
add_image_left_right_flips
#include <dlib/image_transforms.h>
add_image_rotations
#include <dlib/image_transforms.h>
add_to
#include <dlib/sparse_vector.h>
allocator
all_images_same_size
#include <dlib/image_processing.h>
all_parts_in_rect
#include <dlib/image_processing.h>
all_values_are_nonnegative
#include <dlib/svm_threaded.h>
alpha
any
#include <dlib/any.h>
any_decision_function
#include <dlib/any.h>
any_function
#include <dlib/any.h>
any_trainer
#include <dlib/any.h>
apery
#include <dlib/numeric_constants.h>
approximate_distance_function
#include <dlib/svm.h>
area
#include <dlib/geometry.h>
array
#include <dlib/array.h>
array2d
#include <dlib/array2d.h>
asin
#include <dlib/matrix.h>
ASSERT_ARE_NOT_SAME_TYPE
#include <dlib/assert.h>
ASSERT_ARE_SAME_TYPE
#include <dlib/assert.h>
assign
#include <dlib/sparse_vector.h>
assignment
#include <dlib/bayes_utils.h>
assignment_cost
#include <dlib/optimization.h>
assignment_function
#include <dlib/svm.h>
assign_all_pixels
#include <dlib/image_transforms.h>
assign_border_pixels
#include <dlib/image_transforms.h>
assign_image
#include <dlib/image_transforms.h>
assign_image_scaled
#include <dlib/image_transforms.h>
assign_pixel
#include <dlib/pixel.h>
assign_pixel_intensity
#include <dlib/pixel.h>
assign_zero_if_built_in_scalar_type
#include <dlib/algs.h>
atan
#include <dlib/matrix.h>
attribute_list
#include <dlib/xml_parser.h>
auto_mutex
#include <dlib/threads.h>
auto_mutex_readonly
#include <dlib/threads.h>
auto_threshold_image
#include <dlib/image_transforms.h>
auto_unlock
#include <dlib/threads.h>
auto_unlock_readonly
#include <dlib/threads.h>
average_precision
#include <dlib/statistics.h>

B

backtracking_line_search
#include <dlib/optimization.h>
bad_type_safe_union_cast
#include <dlib/type_safe_union.h>
base64
#include <dlib/base64.h>
base_window
#include <dlib/gui_core.h>
basic_type
#include <dlib/algs.h>
basic_utf8_ifstream
#include <dlib/unicode.h>
basic_utf8_ifstream
#include <dlib/unicode.h>
basic_utf8_ifstream
#include <dlib/unicode.h>
batch
#include <dlib/svm.h>
batch_cached
#include <dlib/svm.h>
batch_trainer
#include <dlib/svm.h>
bayesian_network_gibbs_sampler
#include <dlib/bayes_utils.h>
bayesian_network_join_tree
#include <dlib/bayes_utils.h>
bayes_node
#include <dlib/bayes_utils.h>
bdf_font
#include <dlib/gui_widgets.h>
bfgs_search_strategy
#include <dlib/optimization.h>
bgr_pixel
#include <dlib/pixel.h>
bigint
#include <dlib/bigint.h>
big_to_host
#include <dlib/byte_orderer.h>
binary_close
#include <dlib/image_transforms.h>
binary_complement
#include <dlib/image_transforms.h>
binary_difference
#include <dlib/image_transforms.h>
binary_dilation
#include <dlib/image_transforms.h>
binary_erosion
#include <dlib/image_transforms.h>
binary_intersection
#include <dlib/image_transforms.h>
binary_open
#include <dlib/image_transforms.h>
binary_search_tree
#include <dlib/binary_search_tree.h>
binary_union
#include <dlib/image_transforms.h>
binned_vector_feature_image
#include <dlib/image_keypoint.h>
bit_stream
#include <dlib/bit_stream.h>
black_background
#include <dlib/image_transforms.h>
BOBYQA
#include <dlib/optimization.h>
bobyqa_failure
#include <dlib/optimization.h>
border_enumerator
#include <dlib/geometry.h>
bottom
in drawable object
#include <dlib/gui_widgets.h>
in rectangle object
#include <dlib/geometry.h>
bottom_up_cluster
#include <dlib/clustering.h>
bound_function_pointer
#include <dlib/bound_function_pointer.h>
box
#include <dlib/data_io.h>
bridge
#include <dlib/bridge.h>
bridge_status
#include <dlib/bridge.h>
bsp_connect
#include <dlib/bsp.h>
bsp_context
#include <dlib/bsp.h>
bsp_listen
#include <dlib/bsp.h>
bsp_listen_dynamic_port
#include <dlib/bsp.h>
button
#include <dlib/gui_widgets.h>
button_action
#include <dlib/gui_widgets.h>
button_style
#include <dlib/gui_widgets.h>
button_style_arrow
#include <dlib/gui_widgets.h>
button_style_default
#include <dlib/gui_widgets.h>
button_style_toolbar1
#include <dlib/gui_widgets.h>
button_style_toolbar_icon1
#include <dlib/gui_widgets.h>
byte_orderer
#include <dlib/byte_orderer.h>

C

camera_transform
#include <dlib/geometry.h>
canvas
#include <dlib/gui_core.h>
cartesian_product
#include <dlib/matrix.h>
cast_to_string
#include <dlib/string.h>
catalan
#include <dlib/numeric_constants.h>
cca
#include <dlib/statistics.h>
ceil
#include <dlib/matrix.h>
center
#include <dlib/geometry.h>
centered_rect
#include <dlib/geometry.h>
central_differences
#include <dlib/optimization.h>
cg_search_strategy
#include <dlib/optimization.h>
check_box
#include <dlib/gui_widgets.h>
chinese_whispers
#include <dlib/clustering.h>
chip_details
#include <dlib/image_transforms.h>
chip_dims
#include <dlib/image_transforms.h>
chol
#include <dlib/matrix.h>
cholesky_decomposition
#include <dlib/matrix.h>
circular_buffer
#include <dlib/sliding_buffer.h>
clamp
#include <dlib/matrix.h>
clamp_function
#include <dlib/optimization.h>
clip_line_to_rectangle
#include <dlib/geometry.h>
close_gracefully
#include <dlib/sockets.h>
close_window
#include <dlib/gui_core.h>
cmd_line_parser
#include <dlib/cmd_line_parser.h>
cmd_line_parser_option
#include <dlib/cmd_line_parser.h>
cnot
#include <dlib/quantum_computing.h>
colm
#include <dlib/matrix.h>
colm_exp
#include <dlib/matrix.h>
colormap_heat
#include <dlib/image_transforms.h>
colormap_jet
#include <dlib/image_transforms.h>
column_major_layout
#include <dlib/matrix.h>
command line parsing
command_line_parser
#include <dlib/cmd_line_parser.h>
COMPILE_TIME_ASSERT
#include <dlib/assert.h>
complex_matrix
#include <dlib/matrix.h>
composite_gate
#include <dlib/quantum_computing.h>
compress_stream
#include <dlib/compress_stream.h>
compute_box_dimensions
#include <dlib/image_processing.h>
compute_dominant_angle
#include <dlib/image_keypoint.h>
compute_lda_transform
#include <dlib/statistics.h>
compute_mean_squared_distance
#include <dlib/svm.h>
compute_surf_descriptor
#include <dlib/image_keypoint.h>
conditional_probability_table
#include <dlib/bayes_utils.h>
conditioning_class
#include <dlib/conditioning_class.h>
config file parser
configure_loggers_from_file
#include <dlib/logger.h>
config_reader
#include <dlib/config_reader.h>
config_reader_thread_safe
#include <dlib/config_reader.h>
conj
#include <dlib/matrix.h>
connect
#include <dlib/sockets.h>
connected_if_both_not_zero
#include <dlib/image_transforms.h>
connected_if_equal
#include <dlib/image_transforms.h>
connection
#include <dlib/sockets.h>
connect_to
#include <dlib/bridge.h>
connect_to_ip_and_port
#include <dlib/bridge.h>
console_progress_indicator
#include <dlib/console_progress_indicator.h>
constituent
#include <dlib/optimization.h>
const_image_view
#include <dlib/image_processing.h>
const_temp_matrix
#include <dlib/matrix.h>
contains_duplicate_pairs
#include <dlib/graph_utils.h>
contains_invalid_labeling
#include <dlib/svm.h>
conv
#include <dlib/matrix.h>
CONVENTION
convert_to_decision_function
#include <dlib/svm.h>
convert_unordered_to_ordered
#include <dlib/graph_utils.h>
convert_utf8_to_utf32
#include <dlib/unicode.h>
conv_same
#include <dlib/matrix.h>
conv_valid
#include <dlib/matrix.h>
copy_functor
#include <dlib/algs.h>
copy_graph
#include <dlib/graph_utils.h>
copy_graph_structure
#include <dlib/graph_utils.h>
correlation
#include <dlib/statistics.h>
correlation_tracker
#include <dlib/image_processing.h>
cos
#include <dlib/matrix.h>
cosh
#include <dlib/matrix.h>
cosine_distance
#include <dlib/graph_utils.h>
count_bits
#include <dlib/hash.h>
count_ranking_inversions
#include <dlib/svm.h>
covariance
#include <dlib/statistics.h>
covariance
#include <dlib/matrix.h>
cpp_pretty_printer
#include <dlib/cpp_pretty_printer.h>
cpp_tokenizer
#include <dlib/cpp_tokenizer.h>
crc32
#include <dlib/crc32.h>
create_connection
#include <dlib/sockets.h>
create_directory
#include <dlib/misc_api.h>
create_gaussian_filter
#include <dlib/image_transforms.h>
create_grid_detection_template
#include <dlib/image_processing.h>
create_join_tree
#include <dlib/graph_utils.h>
create_listener
#include <dlib/sockets.h>
create_max_margin_projection_hash
#include <dlib/lsh.h>
create_moral_graph
#include <dlib/graph_utils.h>
create_new_thread
#include <dlib/threads.h>
create_new_thread extension
#include <dlib/threads.h>
create_overlapped_2x2_detection_template
#include <dlib/image_processing.h>
create_random_projection_hash
#include <dlib/lsh.h>
create_single_box_detection_template
#include <dlib/image_processing.h>
cref
#include <dlib/ref.h>
cross_validate_assignment_trainer
#include <dlib/svm.h>
cross_validate_graph_labeling_trainer
#include <dlib/svm_threaded.h>
cross_validate_multiclass_trainer
#include <dlib/svm.h>
cross_validate_object_detection_trainer
#include <dlib/svm.h>
cross_validate_ranking_trainer
#include <dlib/svm.h>
cross_validate_regression_trainer
#include <dlib/svm.h>
cross_validate_sequence_labeler
#include <dlib/svm.h>
cross_validate_sequence_segmenter
#include <dlib/svm.h>
cross_validate_track_association_trainer
#include <dlib/svm_threaded.h>
cross_validate_trainer
#include <dlib/svm.h>
cross_validate_trainer_threaded
#include <dlib/svm_threaded.h>
cross_validation_error
#include <dlib/svm.h>
csv
#include <dlib/matrix.h>
cubed
#include <dlib/matrix.h>
cubed
#include <dlib/matrix.h>
cv_image
#include <dlib/opencv.h>

D

database
#include <dlib/sqlite.h>
dataset
#include <dlib/data_io.h>
dcenter
#include <dlib/geometry.h>
debugging modes: enable/disable
decision_function
#include <dlib/svm.h>
default_box_generator
#include <dlib/image_processing.h>
default_fhog_feature_extractor
#include <dlib/image_processing.h>
default_font
#include <dlib/gui_widgets.h>
default_memory_manager
#include <dlib/algs.h>
derivative
#include <dlib/optimization.h>
deserialize
#include <dlib/serialize.h>
det
#include <dlib/matrix.h>
determine_object_boxes
#include <dlib/image_processing.h>
diag
#include <dlib/matrix.h>
diagm
#include <dlib/matrix.h>
diag_exp
#include <dlib/matrix.h>
directed_graph
#include <dlib/directed_graph.h>
directed_graph_drawer
#include <dlib/gui_widgets.h>
directory
#include <dlib/dir_nav.h>
dir_create_error
#include <dlib/misc_api.h>
dir_nav
dir_not_found
#include <dlib/dir_nav.h>
disable
#include <dlib/gui_widgets.h>
disable_events
#include <dlib/gui_widgets.h>
disable_if
#include <dlib/enable_if.h>
discriminant_pca
#include <dlib/statistics.h>
discriminant_pca_error
#include <dlib/statistics.h>
disjoint_subsets
#include <dlib/disjoint_subsets.h>
distance
#include <dlib/sparse_vector.h>
distance_function
#include <dlib/svm.h>
distance_squared
#include <dlib/sparse_vector.h>
distance_to_line
#include <dlib/geometry.h>
distance_to_rect_edge
#include <dlib/geometry.h>
DLIB_ASSERT
#include <dlib/assert.h>
dlib_assert_breakpoint
DLIB_ASSERT_HAS_STANDARD_LAYOUT
#include <dlib/assert.h>
DLIB_CASSERT
#include <dlib/assert.h>
DLIB_ENABLE_STACK_TRACE
DLIB_ISO_CPP_ONLY
DLIB_MAJOR_VERSION
#include <dlib/revision.h>
DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST
#include <dlib/algs.h>
DLIB_MINOR_VERSION
#include <dlib/revision.h>
DLIB_NO_GUI_SUPPORT
DLIB_STACK_TRACE
#include <dlib/assert.h>
DLIB_STACK_TRACE_NAMED
#include <dlib/assert.h>
DLIB_THREAD_POOL_TIMEOUT
document_handler
#include <dlib/xml_parser.h>
dot
for matrix objects
#include <dlib/matrix.h>
for sparse vectors
#include <dlib/sparse_vector.h>
dpoint
#include <dlib/geometry.h>
draggable
#include <dlib/gui_widgets.h>
draw
#include <dlib/gui_widgets.h>
drawable
#include <dlib/gui_widgets.h>
drawable_window
#include <dlib/gui_widgets.h>
draw_button_down
#include <dlib/gui_widgets.h>
draw_button_up
#include <dlib/gui_widgets.h>
draw_checkered
#include <dlib/gui_widgets.h>
draw_circle
#include <dlib/gui_widgets.h>
draw_fhog
#include <dlib/image_transforms.h>
draw_image
#include <dlib/gui_widgets.h>
draw_line
for image/array2d objects
#include <dlib/image_transforms.h>
for the GUI canvas object
#include <dlib/gui_widgets.h>
draw_pixel
#include <dlib/gui_widgets.h>
draw_rectangle
for image/array2d objects
#include <dlib/image_transforms.h>
for the GUI canvas object
#include <dlib/gui_widgets.h>
draw_rounded_rectangle
#include <dlib/gui_widgets.h>
draw_solid_circle
for image/array2d objects
#include <dlib/image_transforms.h>
for the GUI canvas object
#include <dlib/gui_widgets.h>
draw_solid_convex_polygon
#include <dlib/gui_widgets.h>
draw_sunken_rectangle
#include <dlib/gui_widgets.h>
draw_surf_points
#include <dlib/image_keypoint/draw_surf_points.h>
drectangle
#include <dlib/geometry.h>

E

e
#include <dlib/numeric_constants.h>
edge
#include <dlib/graph_utils.h>
edge_orientation
#include <dlib/image_transforms.h>
eigenvalue_decomposition
#include <dlib/matrix.h>
empirical_kernel_map
#include <dlib/svm.h>
empirical_kernel_map_error
#include <dlib/svm.h>
enable
#include <dlib/gui_widgets.h>
enabled
#include <dlib/gui_widgets.h>
ENABLE_ASSERTS
enable_events
#include <dlib/gui_widgets.h>
enable_if
#include <dlib/enable_if.h>
END_OF_TREE
#include <dlib/optimization.h>
ensures
entropy_decoder
#include <dlib/entropy_decoder.h>
entropy_decoder_model
#include <dlib/entropy_decoder_model.h>
entropy_encoder
#include <dlib/entropy_encoder.h>
entropy_encoder_model
#include <dlib/entropy_encoder_model.h>
enumerable
#include <dlib/interfaces/enumerable.h>
equal
#include <dlib/matrix.h>
equalize_histogram
#include <dlib/image_transforms.h>
equal_error_rate
#include <dlib/statistics.h>
error
#include <dlib/error.h>
error_handler
#include <dlib/xml_parser.h>
euler_gamma
#include <dlib/numeric_constants.h>
evaluate_detectors
#include <dlib/image_processing.h>
events_are_enabled
#include <dlib/gui_widgets.h>
exp
#include <dlib/matrix.h>
extension
extract_fhog_features
#include <dlib/image_transforms.h>
extract_highdim_face_lbp_descriptors
#include <dlib/image_transforms.h>
extract_histogram_descriptors
#include <dlib/image_transforms.h>
extract_image_chip
#include <dlib/image_transforms.h>
extract_image_chips
#include <dlib/image_transforms.h>
extract_uniform_lbp_descriptors
#include <dlib/image_transforms.h>

F

feature_extractor_track_association
#include <dlib/svm.h>
fft
#include <dlib/matrix.h>
fhog_to_image
#include <dlib/image_transforms.h>
file
#include <dlib/dir_nav.h>
file_exists
#include <dlib/dir_nav.h>
file_not_found
#include <dlib/dir_nav.h>
fill_gradient_rounded
#include <dlib/gui_widgets.h>
fill_lisf
#include <dlib/svm.h>
fill_rect
for GUI canvas objects
#include <dlib/gui_widgets.h>
for image/array2d objects
#include <dlib/image_transforms.h>
fill_rect_with_vertical_gradient
#include <dlib/gui_widgets.h>
find_affine_transform
#include <dlib/geometry.h>
find_approximate_k_nearest_neighbors
#include <dlib/graph_utils.h>
find_candidate_object_locations
#include <dlib/image_transforms.h>
find_clusters_using_angular_kmeans
#include <dlib/clustering.h>
find_clusters_using_kmeans
#include <dlib/clustering.h>
find_connected_nodes
#include <dlib/graph_utils.h>
find_gamma_with_big_centroid_gap
#include <dlib/svm.h>
find_k_nearest_neighbors
#include <dlib/graph_utils.h>
find_k_nearest_neighbors_lsh
#include <dlib/graph_utils_threaded.h>
find_max
#include <dlib/optimization.h>
find_max_bobyqa
#include <dlib/optimization.h>
find_max_box_constrained
#include <dlib/optimization.h>
find_max_factor_graph_nmplp
#include <dlib/optimization.h>
find_max_factor_graph_potts
#include <dlib/graph_cuts.h>
find_max_factor_graph_viterbi
#include <dlib/optimization.h>
find_max_parse_cky
#include <dlib/optimization.h>
find_max_single_variable
#include <dlib/optimization.h>
find_max_trust_region
#include <dlib/optimization.h>
find_max_using_approximate_derivatives
#include <dlib/optimization.h>
find_min
#include <dlib/optimization.h>
find_min_and_max
#include <dlib/matrix.h>
find_min_bobyqa
#include <dlib/optimization.h>
find_min_box_constrained
#include <dlib/optimization.h>
find_min_single_variable
#include <dlib/optimization.h>
find_min_trust_region
#include <dlib/optimization.h>
find_min_using_approximate_derivatives
#include <dlib/optimization.h>
find_missing_pairs
#include <dlib/svm.h>
find_neighbor_ranges
#include <dlib/graph_utils.h>
find_percent_shortest_edges_randomly
#include <dlib/graph_utils.h>
find_points_above_thresh
#include <dlib/image_processing.h>
find_projective_transform
#include <dlib/geometry.h>
find_similarity_transform
#include <dlib/geometry.h>
find_tight_overlap_tester
#include <dlib/image_processing.h>
find_trees_not_rooted_with_tag
#include <dlib/optimization.h>
fine_hog_image
#include <dlib/image_keypoint.h>
fix_nonzero_indexing
#include <dlib/data_io.h>
flip
#include <dlib/matrix.h>
fliplr
#include <dlib/matrix.h>
flipud
#include <dlib/matrix.h>
flip_image_dataset_left_right
#include <dlib/image_transforms.h>
flip_image_left_right
#include <dlib/image_transforms.h>
flip_image_up_down
#include <dlib/image_transforms.h>
float_details
#include <dlib/float_details.h>
float_spatially_filter_image_separable
#include <dlib/image_transforms.h>
floor
#include <dlib/matrix.h>
font
#include <dlib/gui_widgets.h>
FREE_NODE
#include <dlib/graph_cuts.h>
frobmetric_training_sample
#include <dlib/statistics.h>
full_detection
#include <dlib/image_processing.h>
full_object_detection
#include <dlib/image_processing.h>
futures
#include <dlib/threads.h>

G

gate
#include <dlib/quantum_computing.h>
gate_exp
#include <dlib/quantum_computing.h>
gaussian
1D Gaussian
#include <dlib/image_transforms.h>
2D Gaussian
#include <dlib/image_keypoint.h>
gaussian_blur
#include <dlib/image_transforms.h>
gaussian_randm
#include <dlib/matrix.h>
gaussian_random_hash
#include <dlib/hash.h>
general_hash
#include <dlib/general_hash/general_hash.h>
Generic image interface
get_current_dir
#include <dlib/misc_api.h>
get_display_size
#include <dlib/gui_core.h>
get_face_chip_details
#include <dlib/image_transforms.h>
get_filesystem_roots
#include <dlib/dir_nav.h>
get_files_in_directory_tree
#include <dlib/dir_nav.h>
get_from_clipboard
#include <dlib/gui_core.h>
get_frontal_face_detector
#include <dlib/image_processing/frontal_face_detector.h>
get_histogram
#include <dlib/image_transforms.h>
get_interest_points
#include <dlib/image_keypoint.h>
get_local_hostname
#include <dlib/sockets.h>
get_mapping_to_chip
#include <dlib/image_transforms.h>
get_native_font
#include <dlib/gui_widgets.h>
get_next_double_click
#include <dlib/gui_widgets.h>
get_option
#include <dlib/cmd_line_parser.h>
get_parent_directory
#include <dlib/dir_nav.h>
get_pixel_intensity
#include <dlib/pixel.h>
get_pos
#include <dlib/gui_core.h>
get_rect
for general matrix like objects
#include <dlib/matrix.h>
in drawable object
#include <dlib/gui_widgets.h>
get_size
#include <dlib/gui_core.h>
get_stack_trace
#include <dlib/assert.h>
get_surf_points
#include <dlib/image_keypoint.h>
get_thread_id
#include <dlib/threads.h>
get_timestamp
#include <dlib/misc_api.h>
glaisher
#include <dlib/numeric_constants.h>
golden_ratio
#include <dlib/numeric_constants.h>
gradient_norm_stop_strategy
#include <dlib/optimization.h>
graph
#include <dlib/graph.h>
graph_contains_directed_cycle
#include <dlib/graph_utils.h>
graph_contains_length_one_cycle
#include <dlib/graph_utils.h>
graph_contains_undirected_cycle
#include <dlib/graph_utils.h>
graph_cut_score
#include <dlib/graph_cuts.h>
graph_has_symmetric_edges
#include <dlib/graph_utils.h>
graph_is_connected
#include <dlib/graph_utils.h>
graph_labeler
#include <dlib/graph_cuts.h>
grow_rect
#include <dlib/geometry.h>
gui
gui_core
gui_widgets

H

haar_x
#include <dlib/image_transforms.h>
haar_y
#include <dlib/image_transforms.h>
hamming_distance
#include <dlib/hash.h>
hash
#include <dlib/hash.h>
hashed_feature_image
#include <dlib/image_keypoint.h>
hash_map
#include <dlib/hash_map.h>
hash_samples
#include <dlib/graph_utils_threaded.h>
hash_set
#include <dlib/hash_set.h>
hash_similar_angles_128
#include <dlib/lsh.h>
hash_similar_angles_256
#include <dlib/lsh.h>
hash_similar_angles_512
#include <dlib/lsh.h>
hash_similar_angles_64
#include <dlib/lsh.h>
hash_table
#include <dlib/hash_table.h>
has_unsigned_keys
#include <dlib/sparse_vector.h>
heatmap
#include <dlib/image_transforms.h>
hessian_pyramid
#include <dlib/image_keypoint.h>
hidden
#include <dlib/gui_widgets.h>
hide
in base_window object
#include <dlib/gui_core.h>
in drawable object
#include <dlib/gui_widgets.h>
histogram_intersection_kernel
#include <dlib/svm.h>
hog_image
#include <dlib/image_keypoint.h>
hostname_to_ip
#include <dlib/sockets.h>
host_is_big_endian
#include <dlib/byte_orderer.h>
host_is_little_endian
#include <dlib/byte_orderer.h>
host_to_big
#include <dlib/byte_orderer.h>
host_to_little
#include <dlib/byte_orderer.h>
host_to_network
#include <dlib/byte_orderer.h>
hough_transform
#include <dlib/image_transforms.h>
HPUX
#include <dlib/platform.h>
hsi_pixel
#include <dlib/pixel.h>
hsort_array
#include <dlib/sort.h>
HTTP server
Hungarian Algorithm
#include <dlib/optimization.h>
hysteresis_threshold
#include <dlib/image_transforms.h>

I

identity_matrix
#include <dlib/matrix.h>
ifft
#include <dlib/matrix.h>
imag
#include <dlib/matrix.h>
image
#include <dlib/data_io.h>
image_data
#include <dlib/image_processing.h>
image_dataset_file
#include <dlib/data_io.h>
image_dataset_metadata
#include <dlib/data_io.h>
image_display
#include <dlib/gui_widgets.h>
image_hash_construction_failure
#include <dlib/image_processing.h>
image_size
#include <dlib/image_processing.h>
image_to_fhog
#include <dlib/image_transforms.h>
image_traits
#include <dlib/image_processing.h>
image_view
#include <dlib/image_processing.h>
image_widget
#include <dlib/gui_widgets.h>
image_window
#include <dlib/gui_widgets.h>
index_of_max
#include <dlib/matrix.h>
index_of_min
#include <dlib/matrix.h>
int16
#include <dlib/uintn.h>
int32
#include <dlib/uintn.h>
int64
#include <dlib/uintn.h>
int8
#include <dlib/uintn.h>
integral_image
#include <dlib/image_transforms.h>
integral_image_generic
#include <dlib/image_transforms.h>
integrate_function_adapt_simp
#include <dlib/numerical_integration.h>
interest_point
#include <dlib/image_keypoint.h>
interpolate_bilinear
#include <dlib/image_transforms.h>
interpolate_nearest_neighbor
#include <dlib/image_transforms.h>
interpolate_quadratic
#include <dlib/image_transforms.h>
intersect
#include <dlib/geometry.h>
inv
#include <dlib/matrix.h>
invalidate_rectangle
#include <dlib/gui_core.h>
invalid_nu_error
#include <dlib/optimization.h>
invalid_utf8_error
#include <dlib/unicode.h>
inv_lower_triangular
#include <dlib/matrix.h>
inv_upper_triangular
#include <dlib/matrix.h>
iosockstream
#include <dlib/iosockstream.h>
ip_to_hostname
#include <dlib/sockets.h>
isort_array
#include <dlib/sort.h>
is_array
#include <dlib/is_kind.h>
is_array2d
#include <dlib/is_kind.h>
is_assignment_problem
#include <dlib/svm.h>
is_binary_classification_problem
#include <dlib/svm.h>
is_built_in_scalar_type
#include <dlib/algs.h>
is_clique
#include <dlib/graph_utils.h>
is_closed
#include <dlib/gui_core.h>
is_col_vector
#include <dlib/matrix.h>
is_combining_char
#include <dlib/unicode.h>
is_complex
#include <dlib/matrix.h>
is_config_reader
#include <dlib/is_kind.h>
is_const_type
#include <dlib/algs.h>
is_convertible
#include <dlib/algs.h>
is_directed_graph
#include <dlib/is_kind.h>
is_dlib_thread
#include <dlib/threads.h>
is_enabled
#include <dlib/gui_widgets.h>
is_finite
for matrix objects
#include <dlib/matrix.h>
for scalar values
#include <dlib/algs.h>
is_float_type
#include <dlib/algs.h>
is_forced_assignment_problem
#include <dlib/svm.h>
is_function
#include <dlib/algs.h>
is_graph
#include <dlib/is_kind.h>
is_graph_labeling_problem
#include <dlib/svm_threaded.h>
is_hidden
#include <dlib/gui_widgets.h>
is_ip_address
#include <dlib/sockets.h>
is_join_tree
#include <dlib/graph_utils.h>
is_learning_problem
#include <dlib/svm.h>
is_matrix
#include <dlib/is_kind.h>
is_maximal_clique
#include <dlib/graph_utils.h>
is_ordered_by_index
#include <dlib/graph_utils.h>
is_pair
#include <dlib/is_kind.h>
is_pointer_type
#include <dlib/algs.h>
is_power_of_two
#include <dlib/matrix.h>
is_rand
#include <dlib/is_kind.h>
is_ranking_problem
#include <dlib/svm.h>
is_reference_type
#include <dlib/algs.h>
is_row_vector
#include <dlib/matrix.h>
is_same_object
#include <dlib/algs.h>
is_same_type
#include <dlib/algs.h>
is_sequence_labeling_problem
#include <dlib/svm.h>
is_sequence_segmentation_problem
#include <dlib/svm.h>
is_signed_type
#include <dlib/algs.h>
is_std_vector
#include <dlib/is_kind.h>
is_track_association_problem
#include <dlib/svm.h>
is_unsigned_type
#include <dlib/algs.h>
is_vector
#include <dlib/matrix.h>

J

jet
#include <dlib/image_transforms.h>
joint_probability_table
#include <dlib/bayes_utils.h>
join_cols
#include <dlib/matrix.h>
join_rows
#include <dlib/matrix.h>
jpeg_loader
#include <dlib/image_io.h>

K

kalman_filter
#include <dlib/filtering.h>
kcentroid
#include <dlib/svm.h>
kernel
in notation overview
regarding creating objects
Kernel Function Objects
kernel ridge regression
#include <dlib/svm.h>
kernel_derivative
#include <dlib/svm.h>
kernel_matrix
#include <dlib/svm.h>
khinchin
#include <dlib/numeric_constants.h>
kkmeans
#include <dlib/clustering.h>
krls
#include <dlib/svm.h>
krr_trainer
#include <dlib/svm.h>

L

label
#include <dlib/gui_widgets.h>
labeled_detection
#include <dlib/svm.h>
label_connected_blobs
#include <dlib/image_transforms.h>
lagrange_poly_min_extrap
#include <dlib/optimization.h>
LALL
#include <dlib/logger.h>
lastx
#include <dlib/gui_widgets.h>
lasty
#include <dlib/gui_widgets.h>
lbfgs_search_strategy
#include <dlib/optimization.h>
LDEBUG
#include <dlib/logger.h>
learn_platt_scaling
#include <dlib/svm.h>
least squares SVM
#include <dlib/svm.h>
left
in drawable object
#include <dlib/gui_widgets.h>
in rectangle object
#include <dlib/geometry.h>
left_substr
#include <dlib/string.h>
length
for matrix objects
#include <dlib/matrix.h>
for sparse vectors
#include <dlib/sparse_vector.h>
length_squared
for matrix objects
#include <dlib/matrix.h>
for sparse vectors
#include <dlib/sparse_vector.h>
LERROR
#include <dlib/logger.h>
letter
#include <dlib/gui_widgets.h>
LFATAL
#include <dlib/logger.h>
light_spd
#include <dlib/numeric_constants.h>
linearly_independent_subset_finder
#include <dlib/svm.h>
linear_kernel
#include <dlib/svm.h>
linear_manifold_regularizer
#include <dlib/manifold_regularization.h>
line_search
#include <dlib/optimization.h>
line_search_funct
#include <dlib/optimization.h>
LINFO
#include <dlib/logger.h>
linker
#include <dlib/linker.h>
linpiece
#include <dlib/matrix.h>
linspace
#include <dlib/matrix.h>
listener
#include <dlib/sockets.h>
listen_on_port
#include <dlib/bridge.h>
listing_error
#include <dlib/dir_nav.h>
list_box
#include <dlib/gui_widgets.h>
list_box_style
#include <dlib/gui_widgets.h>
list_box_style_default
#include <dlib/gui_widgets.h>
little_to_host
#include <dlib/byte_orderer.h>
LNONE
#include <dlib/logger.h>
load_bmp
#include <dlib/image_io.h>
load_dng
#include <dlib/image_io.h>
load_image
#include <dlib/image_io.h>
load_image_dataset
#include <dlib/data_io.h>
load_image_dataset_metadata
#include <dlib/data_io.h>
load_jpeg
#include <dlib/image_io.h>
load_libsvm_formatted_data
#include <dlib/data_io.h>
load_png
#include <dlib/image_io.h>
locally_change_current_dir
#include <dlib/misc_api.h>
log
#include <dlib/matrix.h>
log10
#include <dlib/matrix.h>
log10_2
#include <dlib/numeric_constants.h>
logger
#include <dlib/logger.h>
logspace
#include <dlib/matrix.h>
log_level
#include <dlib/logger.h>
lowerbound
#include <dlib/matrix.h>
lowerm
#include <dlib/matrix.h>
lpad
#include <dlib/string.h>
lspi
#include <dlib/control.h>
LTRACE
#include <dlib/logger.h>
ltrim
#include <dlib/string.h>
lu_decomposition
#include <dlib/matrix.h>
LWARN
#include <dlib/logger.h>
lz77_buffer
#include <dlib/lz77_buffer.h>
lzp_buffer
#include <dlib/lzp_buffer.h>

M

m
#include <dlib/gui_widgets.h>
MACOSX
#include <dlib/platform.h>
main_font
#include <dlib/gui_widgets.h>
make_image_view
#include <dlib/image_processing.h>
make_line_search_function
#include <dlib/optimization.h>
make_mfp
#include <dlib/member_function_pointer.h>
make_potts_grid_problem
#include <dlib/graph_cuts.h>
make_sparse_vector
#include <dlib/sparse_vector.h>
make_sparse_vector_inplace
#include <dlib/sparse_vector.h>
make_symmetric
#include <dlib/matrix.h>
make_uniform_lbp_image
#include <dlib/image_transforms.h>
map
#include <dlib/map.h>
map_det_to_chip
#include <dlib/image_transforms.h>
map_pair
#include <dlib/interfaces/map_pair.h>
mat
#include <dlib/matrix.h>
match_all
#include <dlib/dir_nav.h>
match_ending
#include <dlib/dir_nav.h>
match_endings
#include <dlib/dir_nav.h>
MATLAB
matrix
#include <dlib/matrix.h>
matrix_cast
#include <dlib/matrix.h>
matrix_exp
#include <dlib/matrix.h>
max
for matrix objects
#include <dlib/matrix.h>
for sparse vectors
#include <dlib/sparse_vector.h>
maximum_nu
#include <dlib/optimization.h>
max_cost_assignment
#include <dlib/optimization.h>
max_filter
#include <dlib/image_transforms.h>
max_index_plus_one
for graphs
#include <dlib/graph_utils.h>
for ranking_pairs
#include <dlib/svm.h>
for sparse vectors
#include <dlib/sparse_vector.h>
max_point
#include <dlib/matrix.h>
max_point_interpolated
#include <dlib/matrix.h>
max_sum_submatrix
#include <dlib/optimization.h>
md5
#include <dlib/md5.h>
mean
#include <dlib/matrix.h>
mean_sign_agreement
#include <dlib/statistics.h>
mean_squared_error
#include <dlib/statistics.h>
median
#include <dlib/algs.h>
member_function_pointer
#include <dlib/member_function_pointer.h>
memory_manager
#include <dlib/memory_manager.h>
memory_manager_global
#include <dlib/memory_manager_global.h>
memory_manager_stateless
#include <dlib/memory_manager_stateless.h>
menu_bar
#include <dlib/gui_widgets.h>
menu_item
#include <dlib/gui_widgets.h>
menu_item_separator
#include <dlib/gui_widgets.h>
menu_item_submenu
#include <dlib/gui_widgets.h>
menu_item_text
#include <dlib/gui_widgets.h>
Mersenne Twister
#include <dlib/rand.h>
message_box
#include <dlib/gui_widgets.h>
message_box_blocking
#include <dlib/gui_widgets.h>
min
for matrix objects
#include <dlib/matrix.h>
for sparse vectors
#include <dlib/sparse_vector.h>
min_cut
#include <dlib/graph_cuts.h>
min_point
#include <dlib/matrix.h>
misc_api
mlp
#include <dlib/mlp.h>
modularity
#include <dlib/clustering.h>
mouse_over_event
#include <dlib/gui_widgets.h>
mouse_tracker
#include <dlib/gui_widgets.h>
move_rect
#include <dlib/geometry.h>
mpc
#include <dlib/control.h>
multi-layer perceptron
#include <dlib/mlp.h>
Multiclass SVM
#include <dlib/svm_threaded.h>
multiclass_linear_decision_function
#include <dlib/svm.h>
multithreaded_object
#include <dlib/threads.h>
murmur_hash3
#include <dlib/hash.h>
murmur_hash3_128bit
#include <dlib/hash.h>
mutex
#include <dlib/threads.h>

N

named_rectangle
#include <dlib/gui_widgets.h>
narrow
#include <dlib/string.h>
nearest_center
#include <dlib/clustering.h>
nearest_neighbor_feature_image
#include <dlib/image_keypoint.h>
nearest_point
#include <dlib/geometry.h>
negate_function
#include <dlib/optimization.h>
negative_dot_product_distance
#include <dlib/graph_utils.h>
neighbors_4
#include <dlib/image_transforms.h>
neighbors_8
#include <dlib/image_transforms.h>
network_address
#include <dlib/sockets.h>
network_to_host
#include <dlib/byte_orderer.h>
neural network
#include <dlib/mlp.h>
newman_cluster
#include <dlib/clustering.h>
newton_G
#include <dlib/numeric_constants.h>
newton_search_strategy
#include <dlib/optimization.h>
newton_search_strategy_obj
#include <dlib/optimization.h>
node_cpt_filled_out
#include <dlib/bayes_utils.h>
node_first_parent_assignment
#include <dlib/bayes_utils.h>
node_is_evidence
#include <dlib/bayes_utils.h>
node_label
#include <dlib/graph_cuts.h>
node_next_parent_assignment
#include <dlib/bayes_utils.h>
node_num_values
#include <dlib/bayes_utils.h>
node_probability
#include <dlib/bayes_utils.h>
node_value
#include <dlib/bayes_utils.h>
noncopyable
#include <dlib/noncopyable.h>
noop
#include <dlib/quantum_computing.h>
norm
#include <dlib/matrix.h>
normalize
#include <dlib/matrix.h>
normalized_function
#include <dlib/svm.h>
nothing_is_background
#include <dlib/image_transforms.h>
no_background
#include <dlib/image_transforms.h>
NO_MAKEFILE
null_trainer
#include <dlib/svm.h>
null_trainer_type
#include <dlib/svm.h>
numeric_constants
#include <dlib/numeric_constants.h>
num_columns
#include <dlib/image_processing.h>
num_rows
#include <dlib/image_processing.h>
num_separable_filters
#include <dlib/image_processing.h>

O

objective_delta_stop_strategy
#include <dlib/optimization.h>
object_detector
#include <dlib/image_processing.h>
oca
#include <dlib/optimization.h>
oca_problem
#include <dlib/optimization.h>
offset_kernel
#include <dlib/svm.h>
off_pixel
#include <dlib/image_transforms.h>
ones_matrix
#include <dlib/matrix.h>
one_vs_all_decision_function
#include <dlib/svm.h>
one_vs_all_trainer
#include <dlib/svm_threaded.h>
one_vs_one_decision_function
#include <dlib/svm.h>
one_vs_one_trainer
#include <dlib/svm_threaded.h>
on_focus_gained
in base_window object
#include <dlib/gui_core.h>
in drawable object
#include <dlib/gui_widgets.h>
on_focus_lost
in base_window object
#include <dlib/gui_core.h>
in drawable object
#include <dlib/gui_widgets.h>
on_keydown
in base_window object
#include <dlib/gui_core.h>
in drawable object
#include <dlib/gui_widgets.h>
on_mouse_down
in base_window object
#include <dlib/gui_core.h>
in drawable object
#include <dlib/gui_widgets.h>
on_mouse_enter
in base_window object
#include <dlib/gui_core.h>
in drawable object
#include <dlib/gui_widgets.h>
on_mouse_leave
in base_window object
#include <dlib/gui_core.h>
in drawable object
#include <dlib/gui_widgets.h>
on_mouse_move
in base_window object
#include <dlib/gui_core.h>
in drawable object
#include <dlib/gui_widgets.h>
on_mouse_up
in base_window object
#include <dlib/gui_core.h>
in drawable object
#include <dlib/gui_widgets.h>
on_pixel
#include <dlib/image_transforms.h>
on_string_put
in base_window object
#include <dlib/gui_core.h>
in drawable object
#include <dlib/gui_widgets.h>
on_user_event
in base_window object
#include <dlib/gui_core.h>
in drawable object
#include <dlib/gui_widgets.h>
on_wheel_down
in base_window object
#include <dlib/gui_core.h>
in drawable object
#include <dlib/gui_widgets.h>
on_wheel_up
in base_window object
#include <dlib/gui_core.h>
in drawable object
#include <dlib/gui_widgets.h>
on_window_close
#include <dlib/gui_core.h>
on_window_moved
in base_window object
#include <dlib/gui_core.h>
in drawable object
#include <dlib/gui_widgets.h>
on_window_resized
in base_window object
#include <dlib/gui_core.h>
in drawable object
#include <dlib/gui_widgets.h>
OpenCV Image
open_existing_file_box
#include <dlib/gui_widgets.h>
open_file_box
#include <dlib/gui_widgets.h>
optimize_single_variable_failure
#include <dlib/optimization.h>
option_parse_error
#include <dlib/cmd_line_parser.h>
ordered_sample_pair
#include <dlib/graph_utils.h>
order_by_descending_distance
#include <dlib/graph_utils.h>
order_by_distance
#include <dlib/graph_utils.h>
order_by_distance_and_index
#include <dlib/graph_utils.h>
order_by_index
#include <dlib/graph_utils.h>
orthogonalize
#include <dlib/matrix.h>
OTHER_ERROR
#include <dlib/algs.h>
overlaps_any_box
#include <dlib/image_processing.h>
overlay_line
#include <dlib/gui_widgets.h>
overlay_rect
#include <dlib/gui_widgets.h>

P

pad
#include <dlib/string.h>
pad_int_with_zeros
#include <dlib/string.h>
paint
#include <dlib/gui_core.h>
parallel_for
#include <dlib/threads.h>
parallel_for_blocked
#include <dlib/threads.h>
parallel_for_verbose
#include <dlib/threads.h>
parent
#include <dlib/gui_widgets.h>
parent_window
#include <dlib/gui_widgets.h>
parse_trees_to_string
#include <dlib/optimization.h>
parse_trees_to_string_tagged
#include <dlib/optimization.h>
parse_tree_element
#include <dlib/optimization.h>
parse_tree_to_string
#include <dlib/optimization.h>
parse_tree_to_string_error
#include <dlib/optimization.h>
parse_tree_to_string_tagged
#include <dlib/optimization.h>
parse_xml
#include <dlib/xml_parser.h>
perspective_display
#include <dlib/gui_widgets.h>
perspective_window
#include <dlib/gui_widgets.h>
pi
#include <dlib/numeric_constants.h>
pick_initial_centers
#include <dlib/clustering.h>
pinv
#include <dlib/matrix.h>
pipe
#include <dlib/pipe.h>
pixel_to_vector
#include <dlib/matrix.h>
pixel_traits
#include <dlib/pixel.h>
planck_cst
#include <dlib/numeric_constants.h>
platt_scale
#include <dlib/svm.h>
png_loader
#include <dlib/image_io.h>
point
#include <dlib/geometry.h>
pointwise_multiply
#include <dlib/matrix.h>
point_rotator
#include <dlib/geometry.h>
point_transform
#include <dlib/geometry.h>
point_transform_affine
#include <dlib/geometry.h>
point_transform_affine3d
#include <dlib/geometry.h>
point_transform_projective
#include <dlib/geometry.h>
policy
#include <dlib/control.h>
polynomial_kernel
#include <dlib/svm.h>
poly_image
#include <dlib/image_keypoint.h>
poly_min_extrap
#include <dlib/optimization.h>
popup_menu
#include <dlib/gui_widgets.h>
popup_menu_region
#include <dlib/gui_widgets.h>
portability macros
PORTINUSE
#include <dlib/algs.h>
POSIX
#include <dlib/platform.h>
potts_model_score
#include <dlib/graph_cuts.h>
pow
#include <dlib/matrix.h>
print
#include <dlib/timing.h>
print_datetime_logger_header
#include <dlib/logger.h>
print_default_logger_header
#include <dlib/logger.h>
probabilistic
#include <dlib/svm.h>
probabilistic_decision_function
#include <dlib/svm.h>
probabilistic_function
#include <dlib/svm.h>
process_sample
#include <dlib/control.h>
prod
#include <dlib/matrix.h>
projection_function
#include <dlib/svm.h>
projection_hash
#include <dlib/lsh.h>
promote
#include <dlib/algs.h>
put_in_range
#include <dlib/algs.h>
put_on_clipboard
#include <dlib/gui_core.h>
pyramid_disable
#include <dlib/image_transforms.h>
pyramid_down
#include <dlib/image_transforms.h>
pyramid_up
#include <dlib/image_transforms.h>

Q

qr_decomposition
#include <dlib/matrix.h>
qsort_array
#include <dlib/sort.h>
quantum_register
#include <dlib/quantum_computing.h>
query_blob
#include <dlib/sqlite.h>
query_double
#include <dlib/sqlite.h>
query_int
#include <dlib/sqlite.h>
query_int64
#include <dlib/sqlite.h>
query_object
#include <dlib/sqlite.h>
query_text
#include <dlib/sqlite.h>
queue
#include <dlib/queue.h>

R

radial_basis_kernel
#include <dlib/svm.h>
radio_button
#include <dlib/gui_widgets.h>
rand
#include <dlib/rand.h>
randm
#include <dlib/matrix.h>
randomize_samples
#include <dlib/svm.h>
randomly_color_image
#include <dlib/image_transforms.h>
randomly_sample_image_features
#include <dlib/statistics.h>
randomly_subsample
#include <dlib/statistics.h>
random_subset_selector
#include <dlib/statistics.h>
range
#include <dlib/matrix.h>
ranking_pair
#include <dlib/svm.h>
rank_features
#include <dlib/svm.h>
rank_unlabeled_training_samples
#include <dlib/svm.h>
rbf_network_trainer
#include <dlib/svm.h>
read_write_mutex
#include <dlib/threads.h>
real
#include <dlib/matrix.h>
real_eigenvalues
#include <dlib/matrix.h>
receive
#include <dlib/bridge.h>
reciprocal
#include <dlib/matrix.h>
reciprocal_max
#include <dlib/matrix.h>
rect
#include <dlib/gui_widgets.h>
rectangle
#include <dlib/geometry.h>
rect_detection
#include <dlib/image_processing.h>
reduced
#include <dlib/svm.h>
reduced2
#include <dlib/svm.h>
reduced_decision_function_trainer
#include <dlib/svm.h>
reduced_decision_function_trainer2
#include <dlib/svm.h>
ref
#include <dlib/ref.h>
reference_counter
#include <dlib/reference_counter.h>
reference_wrapper
#include <dlib/ref.h>
register_thread_end_handler
#include <dlib/threads.h>
regularized least squares
#include <dlib/svm.h>
relevance vector machine
#include <dlib/svm.h>
remover
#include <dlib/interfaces/remover.h>
removerc
#include <dlib/matrix.h>
remove_col
#include <dlib/matrix.h>
remove_duplicates
#include <dlib/image_transforms.h>
remove_duplicate_edges
#include <dlib/graph_utils.h>
remove_long_edges
#include <dlib/graph_utils.h>
remove_percent_longest_edges
#include <dlib/graph_utils.h>
remove_percent_shortest_edges
#include <dlib/graph_utils.h>
remove_row
#include <dlib/matrix.h>
remove_short_edges
#include <dlib/graph_utils.h>
remove_unobtainable_rectangles
#include <dlib/image_processing.h>
render_face_detections
#include <dlib/image_processing/render_face_detections.h>
replicate_settings
#include <dlib/svm.h>
requires
reshape
#include <dlib/matrix.h>
reshape_to_column_vector
#include <dlib/matrix.h>
resize_image
#include <dlib/image_transforms.h>
resize_rect
#include <dlib/geometry.h>
resize_rect_height
#include <dlib/geometry.h>
resize_rect_width
#include <dlib/geometry.h>
rgb_alpha_pixel
#include <dlib/pixel.h>
rgb_pixel
#include <dlib/pixel.h>
ridge regression
#include <dlib/svm.h>
right
in drawable object
#include <dlib/gui_widgets.h>
in rectangle object
#include <dlib/geometry.h>
right_substr
#include <dlib/string.h>
rls
#include <dlib/svm.h>
rls_filter
#include <dlib/filtering.h>
rmutex
#include <dlib/threads.h>
roc_c1_trainer
#include <dlib/svm.h>
roc_c2_trainer
#include <dlib/svm.h>
roc_trainer_type
#include <dlib/svm.h>
rotate
#include <dlib/matrix.h>
rotate_around_x
#include <dlib/geometry.h>
rotate_around_y
#include <dlib/geometry.h>
rotate_around_z
#include <dlib/geometry.h>
rotate_image
#include <dlib/image_transforms.h>
rotate_image_dataset
#include <dlib/image_transforms.h>
rotate_point
#include <dlib/geometry.h>
rotation_matrix
#include <dlib/geometry.h>
round
#include <dlib/matrix.h>
round_zeros
#include <dlib/matrix.h>
rowm
#include <dlib/matrix.h>
rowm_exp
#include <dlib/matrix.h>
row_major_layout
#include <dlib/matrix.h>
rpad
#include <dlib/string.h>
rr_trainer
#include <dlib/svm.h>
rsignaler
#include <dlib/threads.h>
rsort_columns
#include <dlib/matrix.h>
rtrim
#include <dlib/string.h>
running_covariance
#include <dlib/statistics.h>
running_cross_covariance
#include <dlib/statistics.h>
running_scalar_covariance
#include <dlib/statistics.h>
running_stats
#include <dlib/statistics.h>
rvm_regression_trainer
#include <dlib/svm.h>
rvm_trainer
#include <dlib/svm.h>
r_squared
#include <dlib/statistics.h>

S

sa
#include <dlib/string.h>
sammon_projection
#include <dlib/statistics.h>
sample_pair
#include <dlib/graph_utils.h>
save_bmp
#include <dlib/image_io.h>
save_dng
#include <dlib/image_io.h>
save_file_box
#include <dlib/gui_widgets.h>
save_image_dataset_metadata
#include <dlib/data_io.h>
save_jpeg
#include <dlib/image_io.h>
save_libsvm_formatted_data
#include <dlib/data_io.h>
save_png
#include <dlib/image_io.h>
scale_by
#include <dlib/sparse_vector.h>
scale_columns
#include <dlib/matrix.h>
scale_rows
#include <dlib/matrix.h>
scan_fhog_pyramid
#include <dlib/image_processing.h>
scan_image
#include <dlib/image_processing.h>
scan_image_boxes
#include <dlib/image_processing.h>
scan_image_custom
#include <dlib/image_processing.h>
scan_image_movable_parts
#include <dlib/image_processing.h>
scan_image_pyramid
#include <dlib/image_processing.h>
scoped_ptr
#include <dlib/smart_pointers.h>
scrollable_region
#include <dlib/gui_widgets.h>
scrollable_region_style
#include <dlib/gui_widgets.h>
scrollable_region_style_default
#include <dlib/gui_widgets.h>
scroll_bar
#include <dlib/gui_widgets.h>
scroll_bar_style
#include <dlib/gui_widgets.h>
scroll_bar_style_default
#include <dlib/gui_widgets.h>
segment_image
#include <dlib/image_transforms.h>
select_all_distinct_labels
#include <dlib/svm.h>
separable_3x3_filter_block_grayscale
#include <dlib/image_transforms.h>
separable_3x3_filter_block_rgb
#include <dlib/image_transforms.h>
sequence
#include <dlib/sequence.h>
sequence_labeler
#include <dlib/svm.h>
sequence_segmenter
#include <dlib/svm.h>
serialize
#include <dlib/serialize.h>
server
#include <dlib/server.h>
server_http
#include <dlib/server.h>
server_iostream
#include <dlib/server.h>
set
#include <dlib/set.h>
setup_grid_detection_templates
#include <dlib/image_processing.h>
setup_grid_detection_templates_verbose
#include <dlib/image_processing.h>
setup_hashed_features
#include <dlib/image_processing.h>
set_all_elements
#include <dlib/matrix.h>
set_all_logging_headers
#include <dlib/logger.h>
set_all_logging_levels
#include <dlib/logger.h>
set_all_logging_output_hooks
#include <dlib/logger.h>
set_all_logging_output_streams
#include <dlib/logger.h>
set_aspect_ratio
#include <dlib/geometry.h>
set_background_color
#include <dlib/gui_widgets.h>
set_colm
#include <dlib/matrix.h>
set_current_dir
#include <dlib/misc_api.h>
set_current_dir_error
#include <dlib/misc_api.h>
set_difference
#include <dlib/set_utils.h>
set_image_size
#include <dlib/image_processing.h>
set_intersection
#include <dlib/set_utils.h>
set_intersection_size
#include <dlib/set_utils.h>
set_main_font
#include <dlib/gui_widgets.h>
set_node_as_evidence
#include <dlib/bayes_utils.h>
set_node_as_nonevidence
#include <dlib/bayes_utils.h>
set_node_num_values
#include <dlib/bayes_utils.h>
set_node_probability
#include <dlib/bayes_utils.h>
set_node_value
#include <dlib/bayes_utils.h>
set_pos
in base_window object
#include <dlib/gui_core.h>
in drawable object
#include <dlib/gui_widgets.h>
set_ptrm
#include <dlib/matrix.h>
set_rowm
#include <dlib/matrix.h>
set_subm
#include <dlib/matrix.h>
set_title
#include <dlib/gui_core.h>
set_union
#include <dlib/set_utils.h>
set_z_order
#include <dlib/gui_widgets.h>
shape_predictor
#include <dlib/image_processing.h>
shape_predictor_trainer
#include <dlib/image_processing.h>
shared_ptr
#include <dlib/smart_pointers.h>
shared_ptr_thread_safe
#include <dlib/smart_pointers_thread_safe.h>
show
in base_window object
#include <dlib/gui_core.h>
in drawable object
#include <dlib/gui_widgets.h>
shrink_rect
#include <dlib/geometry.h>
SHUTDOWN
#include <dlib/algs.h>
sigmoid
#include <dlib/matrix.h>
sigmoid_kernel
#include <dlib/svm.h>
signaler
#include <dlib/threads.h>
simplify_linear_decision_function
#include <dlib/svm.h>
sin
#include <dlib/matrix.h>
singular value decomposition
#include <dlib/matrix.h>
sinh
#include <dlib/matrix.h>
SINK_CUT
#include <dlib/graph_cuts.h>
sizes_match
#include <dlib/svm_threaded.h>
skeleton
#include <dlib/image_transforms.h>
sleep
#include <dlib/misc_api.h>
sliding_buffer
#include <dlib/sliding_buffer.h>
sobel_edge_detector
#include <dlib/image_transforms.h>
sockets
sockstreambuf
#include <dlib/sockstreambuf.h>
solve_least_squares
#include <dlib/optimization.h>
solve_least_squares_lm
#include <dlib/optimization.h>
solve_qp2_using_smo
#include <dlib/optimization.h>
solve_qp3_using_smo
#include <dlib/optimization.h>
solve_qp4_using_smo
#include <dlib/optimization.h>
solve_qp_using_smo
#include <dlib/optimization.h>
solve_trust_region_subproblem
#include <dlib/optimization.h>
sort_basis_vectors
#include <dlib/svm.h>
sort_columns
#include <dlib/matrix.h>
SOURCE_CUT
#include <dlib/graph_cuts.h>
sparse vectors
sparse_histogram_intersection_kernel
#include <dlib/svm.h>
sparse_linear_kernel
#include <dlib/svm.h>
sparse_matrix_vector_multiply
#include <dlib/sparse_vector.h>
sparse_polynomial_kernel
#include <dlib/svm.h>
sparse_radial_basis_kernel
#include <dlib/svm.h>
sparse_sigmoid_kernel
#include <dlib/svm.h>
sparse_to_dense
#include <dlib/sparse_vector.h>
spatially_filter_image
#include <dlib/image_transforms.h>
spatially_filter_image_separable
#include <dlib/image_transforms.h>
spatially_filter_image_separable_down
#include <dlib/image_transforms.h>
spectral_cluster
#include <dlib/clustering.h>
split
#include <dlib/string.h>
split_array
#include <dlib/array.h>
split_on_first
#include <dlib/string.h>
split_on_last
#include <dlib/string.h>
SQLite
sqlite_error
#include <dlib/sqlite.h>
sqrt
#include <dlib/matrix.h>
sqrt_2
#include <dlib/numeric_constants.h>
sqrt_3
#include <dlib/numeric_constants.h>
squared
#include <dlib/matrix.h>
squared_euclidean_distance
#include <dlib/graph_utils.h>
square_root
#include <dlib/algs.h>
stack
#include <dlib/stack.h>
Stack Trace
stack_based_memory_block
#include <dlib/algs.h>
start
#include <dlib/timing.h>
statement
#include <dlib/sqlite.h>
static_map
#include <dlib/static_map.h>
static_set
#include <dlib/static_set.h>
static_switch
#include <dlib/algs.h>
stddev
#include <dlib/matrix.h>
std_allocator
#include <dlib/std_allocator.h>
std_vector_c
#include <dlib/stl_checked.h>
stop
#include <dlib/timing.h>
strings_equal_ignore_case
#include <dlib/string.h>
string_assign
#include <dlib/string.h>
string_cast
#include <dlib/string.h>
structural_assignment_trainer
#include <dlib/svm_threaded.h>
structural_graph_labeling_trainer
#include <dlib/svm_threaded.h>
structural_object_detection_trainer
#include <dlib/svm_threaded.h>
structural_sequence_labeling_trainer
#include <dlib/svm_threaded.h>
structural_sequence_segmentation_trainer
#include <dlib/svm_threaded.h>
structural_svm_assignment_problem
#include <dlib/svm_threaded.h>
structural_svm_graph_labeling_problem
#include <dlib/svm_threaded.h>
structural_svm_object_detection_problem
#include <dlib/svm_threaded.h>
structural_svm_problem
#include <dlib/svm.h>
structural_svm_problem_threaded
#include <dlib/svm_threaded.h>
structural_svm_sequence_labeling_problem
#include <dlib/svm_threaded.h>
structural_track_association_trainer
#include <dlib/svm_threaded.h>
subm
#include <dlib/matrix.h>
subtract
#include <dlib/sparse_vector.h>
subtract_from
#include <dlib/sparse_vector.h>
sub_image
#include <dlib/image_transforms.h>
sub_image_proxy
#include <dlib/image_transforms.h>
sum
#include <dlib/matrix.h>
sum_cols
#include <dlib/matrix.h>
sum_filter
#include <dlib/image_transforms.h>
sum_filter_assign
#include <dlib/image_transforms.h>
sum_of_rects_in_images
#include <dlib/image_processing.h>
sum_of_rects_in_images_movable_parts
#include <dlib/image_processing.h>
sum_rows
#include <dlib/matrix.h>
support vector machine
#include <dlib/svm.h>
support vector regression
#include <dlib/svm.h>
suppress_non_maximum_edges
#include <dlib/image_transforms.h>
surf_point
#include <dlib/image_keypoint.h>
svd
#include <dlib/matrix.h>
svd2
#include <dlib/matrix.h>
svd3
#include <dlib/matrix.h>
svd_fast
#include <dlib/matrix.h>
svm_c_ekm_trainer
#include <dlib/svm.h>
svm_c_linear_dcd_trainer
#include <dlib/svm.h>
svm_c_linear_trainer
#include <dlib/svm.h>
svm_c_trainer
#include <dlib/svm.h>
svm_multiclass_linear_trainer
#include <dlib/svm_threaded.h>
svm_nu_trainer
#include <dlib/svm.h>
svm_one_class_trainer
#include <dlib/svm.h>
svm_pegasos
#include <dlib/svm.h>
svm_rank_trainer
#include <dlib/svm.h>
svm_struct_controller_node
#include <dlib/svm_threaded.h>
svm_struct_processing_node
#include <dlib/svm_threaded.h>
svr_linear_trainer
#include <dlib/svm.h>
svr_trainer
#include <dlib/svm.h>
symmetric_matrix_cache
#include <dlib/matrix.h>
sync_extension
#include <dlib/sync_extension.h>

T

tabbed_display
#include <dlib/gui_widgets.h>
tabs
#include <dlib/algs.h>
tan
#include <dlib/matrix.h>
tanh
#include <dlib/matrix.h>
tensor_product
#include <dlib/matrix.h>
testing
test_assignment_function
#include <dlib/svm.h>
test_binary_decision_function
#include <dlib/svm.h>
test_box_overlap
#include <dlib/image_processing.h>
test_graph_labeling_function
#include <dlib/svm_threaded.h>
test_multiclass_decision_function
#include <dlib/svm.h>
test_object_detection_function
#include <dlib/svm.h>
test_ranking_function
#include <dlib/svm.h>
test_regression_function
#include <dlib/svm.h>
test_sequence_labeler
#include <dlib/svm.h>
test_sequence_segmenter
#include <dlib/svm.h>
test_shape_predictor
#include <dlib/image_processing.h>
test_track_association_function
#include <dlib/svm_threaded.h>
text_box
#include <dlib/gui_widgets.h>
text_box_style
#include <dlib/gui_widgets.h>
text_box_style_default
#include <dlib/gui_widgets.h>
text_field
#include <dlib/gui_widgets.h>
text_field_style
#include <dlib/gui_widgets.h>
text_field_style_default
#include <dlib/gui_widgets.h>
text_grid
#include <dlib/gui_widgets.h>
threaded_object
#include <dlib/threads.h>
threads
thread_function
#include <dlib/threads.h>
thread_pool
#include <dlib/threads.h>
thread_specific_data
#include <dlib/threads.h>
threshold_filter_singular_values
#include <dlib/image_processing.h>
threshold_image
#include <dlib/image_transforms.h>
throws
tile_images
#include <dlib/image_transforms.h>
timeout
#include <dlib/timeout.h>
TIMEOUT
#include <dlib/algs.h>
timer
#include <dlib/timer.h>
timestamper
#include <dlib/misc_api.h>
TIME_THIS
#include <dlib/time_this.h>
TIME_THIS_TO
#include <dlib/time_this.h>
timing code blocks
#include <dlib/timing.h>
tmax
#include <dlib/algs.h>
tmin
#include <dlib/algs.h>
tmp
#include <dlib/matrix.h>
toffoli
#include <dlib/quantum_computing.h>
toggle_button
#include <dlib/gui_widgets.h>
toggle_button_style
#include <dlib/gui_widgets.h>
toggle_button_style_check_box
#include <dlib/gui_widgets.h>
toggle_button_style_default
#include <dlib/gui_widgets.h>
toggle_button_style_radio_button
#include <dlib/gui_widgets.h>
tokenizer
#include <dlib/tokenizer.h>
tolower
#include <dlib/string.h>
toMat
#include <dlib/opencv.h>
tooltip
#include <dlib/gui_widgets.h>
top
in drawable object
#include <dlib/gui_widgets.h>
in rectangle object
#include <dlib/geometry.h>
total_feature_vector_size
#include <dlib/svm.h>
toupper
#include <dlib/string.h>
trace
#include <dlib/matrix.h>
track_association_function
#include <dlib/svm.h>
train_probabilistic_decision_function
#include <dlib/svm.h>
trans
#include <dlib/matrix.h>
transaction
#include <dlib/sqlite.h>
transform_image
#include <dlib/image_transforms.h>
translate_point
#include <dlib/geometry.h>
translate_rect
#include <dlib/geometry.h>
transmit
#include <dlib/bridge.h>
triangulate_graph_and_find_cliques
#include <dlib/graph_utils.h>
trigger_user_event
#include <dlib/gui_core.h>
trim
#include <dlib/string.h>
tuple
#include <dlib/tuple.h>
type_safe_union
#include <dlib/type_safe_union.h>

U

uint16
#include <dlib/uintn.h>
uint32
#include <dlib/uintn.h>
uint64
#include <dlib/uintn.h>
uint8
#include <dlib/uintn.h>
unichar
#include <dlib/unicode.h>
uniform_matrix
#include <dlib/matrix.h>
uniform_random_hash
#include <dlib/hash.h>
union-find
#include <dlib/disjoint_subsets.h>
unit testing
unordered_pair
#include <dlib/unordered_pair.h>
unregister_thread_end_handler
#include <dlib/threads.h>
unsigned_type
#include <dlib/uintn.h>
unsorted sparse vectors
upperbound
#include <dlib/matrix.h>
upperm
#include <dlib/matrix.h>
upsample_image_dataset
#include <dlib/image_transforms.h>
use_gaussian_weights
#include <dlib/graph_utils.h>
use_relative_feature_weights
#include <dlib/image_processing.h>
use_uniform_feature_weights
#include <dlib/image_processing.h>
use_weights_of_one
#include <dlib/graph_utils.h>
ustring
#include <dlib/unicode.h>

V

variance
#include <dlib/matrix.h>
vector
#include <dlib/geometry.h>
vectorstream
#include <dlib/vectorstream.h>
vector_normalizer
#include <dlib/statistics.h>
vector_normalizer_frobmetric
#include <dlib/statistics.h>
vector_normalizer_pca
#include <dlib/statistics.h>
vector_to_pixel
#include <dlib/matrix.h>
verbose_batch
#include <dlib/svm.h>
verbose_batch_cached
#include <dlib/svm.h>
verbose_find_gamma_with_big_centroid_gap
#include <dlib/svm.h>

W

wait_until_closed
#include <dlib/gui_core.h>
wcommand_line_parser
#include <dlib/cmd_line_parser.h>
weak_ptr
#include <dlib/smart_pointers.h>
white_background
#include <dlib/image_transforms.h>
widget_group
#include <dlib/gui_widgets.h>
width
in drawable object
#include <dlib/gui_widgets.h>
in rectangle object
#include <dlib/geometry.h>
width_step
#include <dlib/image_processing.h>
WIN32
#include <dlib/platform.h>
WOULDBLOCK
#include <dlib/algs.h>
wrap_function
#include <dlib/algs.h>
wrap_string
#include <dlib/string.h>

X

x
#include <dlib/quantum_computing.h>
xcorr
#include <dlib/matrix.h>
xcorr_same
#include <dlib/matrix.h>
xcorr_valid
#include <dlib/matrix.h>
xml_parser
#include <dlib/xml_parser.h>

Y

y
#include <dlib/quantum_computing.h>

Z

z
#include <dlib/quantum_computing.h>
zeros_matrix
#include <dlib/matrix.h>
zero_border_pixels
#include <dlib/image_transforms.h>
zero_extend_cast
#include <dlib/uintn.h>
zero_pixels_are_background
#include <dlib/image_transforms.h>
zoomable_region
#include <dlib/gui_widgets.h>
z_order
#include <dlib/gui_widgets.h>


dlib C++ Library - Introduction

The Library
  • Algorithms
  • API Wrappers
  • Bayesian Nets
  • Compression
  • Containers
  • Graph Tools
  • Image Processing
  • Linear Algebra
  • Machine Learning
  • Metaprogramming
  • Miscellaneous
  • Networking
  • Optimization
  • Parsing

Help/Info
  • Dlib Blog
  • Examples: C++
    • 3D Point Cloud
    • Assignment Learning
    • Base64 Encoder
    • Bayesian Network From Disk
    • Bayesian Network GUI
    • Bayesian Network
    • Bridge
    • BSP
    • C-Support Vector Machine
    • Cmd Line Parser
    • Compress Stream
    • Config File Reader
    • Custom Trainers
    • Directory Navigation
    • Empirical Kernel Map
    • Face Detection
    • Face Landmark Detection
    • FHOG Feature Extraction
    • FHOG Object Detection
    • Graph Labeling
    • GUI
    • Hough Transform
    • HTTP Server
    • Image
    • IO Socket Streams
    • IO Streams Server
    • Kernel Centroid
    • Kernel K-Means Clustering
    • Kernel Ridge Regression
    • Kernel RLS Filtering
    • Kernel RLS Regression
    • KRR Classification
    • Learning to Track
    • Linear Assignment Problems
    • Linear Manifold Regularizer
    • Linear Model Predictive Control
    • Logger Advanced
    • Logger Custom Output
    • Logger
    • Matrix Expressions
    • Matrix
    • Member Function Pointer
    • Model Selection
    • Multiclass Classification
    • Multithreaded Object
    • Neural Network
    • Non-Linear Least Squares
    • Nu-Support Vector Machine
    • Numerical Integration
    • Object Detector Advanced
    • Object Detector
    • One Class Classifiers
    • Online SVM
    • Optimization
    • Parallel For Loops
    • Pipe 2
    • Pipe
    • Quantum Computing
    • Queue
    • Rank Features
    • Relevance Vector Classification
    • Relevance Vector Regression
    • Running Stats
    • Sequence Labeling
    • Sequence Segmentation
    • Sockets
    • Sockstreambuf
    • Sparse Vectors
    • SQLite
    • Std C++ Allocator
    • Structural Support Vector Machines
    • Support Vector Regression
    • SURF
    • SVM-Rank
    • Thread Function
    • Thread Pool
    • Threaded Object
    • Threads
    • Timer
    • Train Object Detector
    • Train Shape Predictor
    • Using Custom Kernels
    • Video Object Tracking
    • Webcam Face Pose Estimation
    • XML Parser
  • Examples: Python
    • Face Detector
    • Face Landmark Detection
    • find candidate object locations
    • Linear Assignment Problems
    • Sequence Segmenter
    • Structural Support Vector Machines
    • SVM-Rank
    • Train Object Detector
    • Train Shape Predictor
    • Video Object Tracking
  • FAQ
  • Forums
  • Home
  • How to compile
  • How to contribute
  • Index
  • Introduction
  • License
  • Python API
  • Suggested Books
  • Who uses dlib?

Current Release
  • Change Log
  • Release Notes
  • Version: 18.18

Last Modified:
Oct 28, 2015
Introduction

Overview

Dlib is a general purpose cross-platform open source software library written in the C++ programming language. Its design is heavily influenced by ideas from design by contract and component-based software engineering. This means it is, first and foremost, a collection of independent software components, each accompanied by extensive documentation and thorough debugging modes.

Davis King has been the primary author of dlib since development began in 2002. In that time dlib has grown to include a wide variety of tools. In particular, it now contains software components for dealing with networking, threads, graphical interfaces, complex data structures, linear algebra, statistical machine learning, image processing, data mining, XML and text parsing, numerical optimization, Bayesian networks, and numerous other tasks. In recent years, much of the development has been focused on creating a broad set of statistical machine learning tools. However, dlib remains a general purpose library and welcomes contributions of high quality software components useful in any domain.

Core to the development philosophy of dlib is a dedication to portability and ease of use. Therefore, all code in dlib is designed to be as portable as possible and similarly to not require a user to configure or install anything. To help achieve this, all platform specific code is confined inside the API wrappers. Everything else is either layered on top of those wrappers or is written in pure ISO standard C++. Currently the library is known to work on OS X, MS Windows, Linux, Solaris, the BSDs, and HP-UX. It should work on any POSIX platform but I haven't had the opportunity to test it on any others (if you have access to other platforms and would like to help increase this list then let me know).

The rest of this page explains everything you need to know to get started using the library. It explains where to find the documentation for each object/function and how to interpret what you find there. For help compiling with dlib check out the how to compile page. Or if you are having trouble finding where a particular object's documentation is located you may be able to find it by consulting the index.

The library is also covered by the very liberal Boost Software License so feel free to use it any way you like. However, if you use dlib in your research then please cite its Journal of Machine Learning Research paper when publishing.

Finally, I must give some credit to the Reusable Software Research Group at Ohio State since they taught me much of the software engineering techniques used in the creation of this library.

Notation

For the most part I try to document my code in a way that any C++ programmer would understand, but for the sake of brevity I use some of the following uncommon notation.

  • kernel, extension, and abstract
      Each component of the library has a specification which defines its core behavior and interface. This specification defines what is called the component's kernel. Additionally, each component may have any number of extensions. An extension is essentially a specification for something that layers functionality on top of the kernel of a component.

      In the naming of files I use the word abstract to indicate that a file contains a specification of a kernel component or extension rather than an actual implementation.

  • /*! comments like this !*/
      This is just for "formal comments." Generally these appear after a function prototype and contain the requires/ensures stuff or at the top of a class and tell you general things about the class.

  • requires/ensures/throws
      These words appear in the formal comment following function prototypes and have the following meanings.

      requires: This defines a list of requirements for calling the function. These requirements MUST be met or a call to the function has undefined results. (note that when the checking/debugging modes are enabled on an object then it will throw the dlib::fatal_error exception with fatal_error::type == EBROKEN_ASSERT when the requires clause is broken rather than causing "undefined results")

      ensures: This defines what the function does. It is a list of conditions that will be true after the function finishes executing. Note that if an exception is thrown then nothing in the ensures clause is guaranteed to be true.

      throws: This defines what exceptions may be thrown by this function. It generally tells you why the exception might be thrown. It also tells you what the function does in this event: Does it have no effect at all? Does it corrupt any objects? etc.

      Sometimes these blocks do not appear in the formal comment. The meanings in these cases are as follows:
      missing requires: There are no requirements, you may put anything in the function arguments.
      missing ensures: This means that the effects of the function are unspecified. This is often used for call backs where the client programmer implements the actual function.
      missing throws: This doesn't mean anything. A function without a throws block might throw exceptions or it might not.

      So in summary, the requires clause must always be satisfied, the ensures clause tells you what the function does when it does not throw or return an error, and the throws clause tells you what happens when the function does throw.

  • meaning of # symbol
      I use this as a prefix on identifiers to make reference to the value of the identifier "after" some event has occurred.

      The most common place I use this notation is inside the formal comment following a function prototype. If the # symbol appears in a requires/ensures/throws block then it means the value of the identifier after the function has finished, otherwise all references to an identifier refer to its value before the function was called.

      An example will make it clear.
      int funct(
    int& something
);
/*!
    requires
        - something > 4
    ensures
        - #some_other_function() == 9
        - #something == something + 1
        - returns something
!*/
      This says that funct() requires that "something" be greater than 4, that funct() will increment "something" by 1, and funct() returns the original value of something. It also says that after the call to funct() ends a call to some_other_function() will return the value 9.

  • CONVENTION
      This is a section of the formal comment which appears at the top of classes which are actual implementations (as opposed to specifications). This section of the comment contains a list of invariants that tell you what the member variables are used for. It also relates the state of the member variables to the class interface.

      For example, you might see a line in this section that says "my_size == size()". This just means that the member variable my_size always contains the value returned by the size() function.

  • "initial value for its type"
      I frequently say that after a function executes some variable or argument will have an initial value for its type. This makes sense for objects with a user defined constructor, but for anything else not so much. Therefore the initial value of a type with no user defined constructor is undefined.

Organization

The library can be thought of as a collection of components. Each component always consists of at least two separate files, a specification file and an implementation file. The specification files are the ones that end with _abstract.h. Each of these specification files don't actually contain any code and they even have preprocessor directives that prevent any of their contents from being included. Their purpose is purely to document a component's interface in a file that isn't cluttered with implementation details the user shouldn't need to know about.

The next important concept in dlib organization is multi-implementation components. That is, some components provide more than one implementation of what is defined in their specification. When you use these components you have to identify them with names like dlib::component::kernel_1a. Often these components will have just a debugging and non-debugging implementation. However, many components provide a large number of alternate implementations. For example, the entropy_encoder_model has 32 different implementations you can choose from.

  • File organization for multi-implementation components
      Each component gets its own folder and one file in the root of the directory tree.

      I will use the queue object as a typical example and explain what each of its files contain. Below is the directory structure and all the files related to the queue component.

      • file tree
        • dlib/
          • queue.h
          • queue/
            • queue_kernel_abstract.h
            • queue_kernel_1.h
            • queue_kernel_2.h
            • queue_kernel_c.h
            • queue_sort_abstract.h
            • queue_sort_1.h

      • queue.h
          This file does not contain any executable code. All it does is define the typedefs such as kernel_1a, kernel_1a_c, etc. for the queue object. See the Creating Objects section to learn what these typedefs are for.
      • queue_kernel_abstract.h
          This file does not contain any code. It even has preprocessor directives that prevent any of its contents from being included.

          The purpose of this file is to define exactly what a queue object does and what its interface is.
      • queue_sort_abstract.h
          This file also doesn't contain any code. Its only purpose is to define the sort extension to queue objects.
      • queue_kernel_1.h
          This file contains an implementation of the queue kernel specification found in queue_kernel_abstract.h
      • queue_kernel_2.h
          This file contains another implementation of the queue kernel specification found in queue_kernel_abstract.h
      • queue_sort_1.h
          This file contains an implementation of the queue sort extension specification found in queue_sort_abstract.h
      • queue_kernel_c.h
          This file contains a templated class which wraps any implementation of the queue kernel specification. It is used during debugging to check that the requires clauses are never violated.

Creating Objects

To create many of the objects in this library you need to choose which kernel implementation you would like and if you want the checking version or any extensions.

To make this easy there are header files which define typedefs of all this stuff. For example, to create a queue of ints using queue kernel implementation 1 you would type dlib::queue<int>::kernel_1a my_queue;. Or to get the debugging/checking version you would type dlib::queue<int>::kernel_1a_c my_queue;.

There can be a lot of different typedefs for each component. You can find a list of them in the section for the component in question. For the queue component they can be found here.

None of the above applies to the single-implementation components, that is, anything that doesn't have an "implementations" section in its documentation. These tools are designed to have only one implementation and thus do not follow the above naming convention. For example, to create a logger object you would simply type dlib::logger mylog("name");. For the purposes of object creation the API components also appear to be single-implementation. That is, there is no need to specify which implementation you want since it is automatically determined by which platform you compile under. Note also that there are no explicit checking versions of these components. However, there are DLIB_ASSERT statements that perform checking and you can enable them by #defining DEBUG or ENABLE_ASSERTS.

Assumptions

There are some restrictions on the behavior of certain objects or functions. Rather than replicating these restrictions all over the place in my documentation they are listed here.
  • global swap()
      It is assumed that this operator does not throw. Undefined behavior results if it does. Note that std::swap() for all intrinsics and std::string does not throw.

  • operator<()
      It is assumed that this operator (or std::less or any similar functor supplied by you to the library) does not throw. Undefined behavior results if it does.

  • dlib::general_hash
      It is assumed that general_hash does not throw. Undefined behavior results if it does. This is actually noted in the general hash spec file but I'm listing it here also for good measure.

Thread Safety

In the library there are three kinds of objects with regards to threading:

  • Objects which are completely thread safe. This means that any pattern of access from multiple threads is safe.
  • Objects which are safe to use if no threads touch the same instance, but require access to a particular instance to be serialized via a mutex if it is shared among threads.
  • Objects which share some kind of global resource or are reference counted. This kind of object is extremely thread unfriendly and can only be used in a threaded program with great care.

How do you know which components/objects are thread safe and which aren't? The rule is that if the specification for the component doesn't mention threading or thread safety then it is ok to use as long as you serialize access to shared instances. If the component might have some global resources or be reference counted then the specifications will tell you this. Lastly if the component is completely thread safe then the specification will tell you this.

Also note that global functions in dlib are always thread safe.


dlib C++ Library - License

The Library
  • Algorithms
  • API Wrappers
  • Bayesian Nets
  • Compression
  • Containers
  • Graph Tools
  • Image Processing
  • Linear Algebra
  • Machine Learning
  • Metaprogramming
  • Miscellaneous
  • Networking
  • Optimization
  • Parsing

Help/Info
  • Dlib Blog
  • Examples: C++
    • 3D Point Cloud
    • Assignment Learning
    • Base64 Encoder
    • Bayesian Network From Disk
    • Bayesian Network GUI
    • Bayesian Network
    • Bridge
    • BSP
    • C-Support Vector Machine
    • Cmd Line Parser
    • Compress Stream
    • Config File Reader
    • Custom Trainers
    • Directory Navigation
    • Empirical Kernel Map
    • Face Detection
    • Face Landmark Detection
    • FHOG Feature Extraction
    • FHOG Object Detection
    • Graph Labeling
    • GUI
    • Hough Transform
    • HTTP Server
    • Image
    • IO Socket Streams
    • IO Streams Server
    • Kernel Centroid
    • Kernel K-Means Clustering
    • Kernel Ridge Regression
    • Kernel RLS Filtering
    • Kernel RLS Regression
    • KRR Classification
    • Learning to Track
    • Linear Assignment Problems
    • Linear Manifold Regularizer
    • Linear Model Predictive Control
    • Logger Advanced
    • Logger Custom Output
    • Logger
    • Matrix Expressions
    • Matrix
    • Member Function Pointer
    • Model Selection
    • Multiclass Classification
    • Multithreaded Object
    • Neural Network
    • Non-Linear Least Squares
    • Nu-Support Vector Machine
    • Numerical Integration
    • Object Detector Advanced
    • Object Detector
    • One Class Classifiers
    • Online SVM
    • Optimization
    • Parallel For Loops
    • Pipe 2
    • Pipe
    • Quantum Computing
    • Queue
    • Rank Features
    • Relevance Vector Classification
    • Relevance Vector Regression
    • Running Stats
    • Sequence Labeling
    • Sequence Segmentation
    • Sockets
    • Sockstreambuf
    • Sparse Vectors
    • SQLite
    • Std C++ Allocator
    • Structural Support Vector Machines
    • Support Vector Regression
    • SURF
    • SVM-Rank
    • Thread Function
    • Thread Pool
    • Threaded Object
    • Threads
    • Timer
    • Train Object Detector
    • Train Shape Predictor
    • Using Custom Kernels
    • Video Object Tracking
    • Webcam Face Pose Estimation
    • XML Parser
  • Examples: Python
    • Face Detector
    • Face Landmark Detection
    • find candidate object locations
    • Linear Assignment Problems
    • Sequence Segmenter
    • Structural Support Vector Machines
    • SVM-Rank
    • Train Object Detector
    • Train Shape Predictor
    • Video Object Tracking
  • FAQ
  • Forums
  • Home
  • How to compile
  • How to contribute
  • Index
  • Introduction
  • License
  • Python API
  • Suggested Books
  • Who uses dlib?

Current Release
  • Change Log
  • Release Notes
  • Version: 18.18

Last Modified:
Jun 22, 2008
License

Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.


Classes — dlib documentation

Navigation

  • index
  • modules |
  • dlib documentation »
Dlib C++ Library

Dlib is principally a C++ library, however, you can use a number of its tools from python applications. This page documents the python API for working with these dlib tools. If you haven’t done so already, you should probably look at the python example programs first before consulting this reference. These example programs are little mini-tutorials for using dlib from python. They are listed on the left of the main dlib web page.

Classes¶

  • dlib.array
  • dlib.cca_outputs
  • dlib.correlation_tracker
  • dlib.drectangle
  • dlib.fhog_object_detector
  • dlib.full_object_detection
  • dlib.image_window
  • dlib.matrix
  • dlib.pair
  • dlib.point
  • dlib.points
  • dlib.range
  • dlib.ranges
  • dlib.rangess
  • dlib.ranking_pair
  • dlib.ranking_pairs
  • dlib.rectangle
  • dlib.rectangles
  • dlib.rgb_pixel
  • dlib.segmenter_params
  • dlib.segmenter_test
  • dlib.segmenter_type
  • dlib.shape_predictor
  • dlib.shape_predictor_training_options
  • dlib.simple_object_detector
  • dlib.simple_object_detector_training_options
  • dlib.simple_test_results
  • dlib.sparse_ranking_pair
  • dlib.sparse_ranking_pairs
  • dlib.sparse_vector
  • dlib.sparse_vectors
  • dlib.sparse_vectorss
  • dlib.svm_c_trainer_histogram_intersection
  • dlib.svm_c_trainer_linear
  • dlib.svm_c_trainer_radial_basis
  • dlib.svm_c_trainer_sparse_histogram_intersection
  • dlib.svm_c_trainer_sparse_linear
  • dlib.svm_c_trainer_sparse_radial_basis
  • dlib.svm_rank_trainer
  • dlib.svm_rank_trainer_sparse
  • dlib.vector
  • dlib.vectors
  • dlib.vectorss

Functions¶

  • dlib.apply_cca_transform()
  • dlib.assignment_cost()
  • dlib.cca()
  • dlib.cross_validate_ranking_trainer()
  • dlib.cross_validate_sequence_segmenter()
  • dlib.cross_validate_trainer()
  • dlib.cross_validate_trainer_threaded()
  • dlib.dot()
  • dlib.find_candidate_object_locations()
  • dlib.get_frontal_face_detector()
  • dlib.hit_enter_to_continue()
  • dlib.load_libsvm_formatted_data()
  • dlib.make_sparse_vector()
  • dlib.max_cost_assignment()
  • dlib.max_index_plus_one()
  • dlib.save_libsvm_formatted_data()
  • dlib.solve_structural_svm_problem()
  • dlib.test_binary_decision_function()
  • dlib.test_ranking_function()
  • dlib.test_regression_function()
  • dlib.test_sequence_segmenter()
  • dlib.test_shape_predictor()
  • dlib.test_simple_object_detector()
  • dlib.train_sequence_segmenter()
  • dlib.train_shape_predictor()
  • dlib.train_simple_object_detector()

Detailed API Listing¶

dlib.apply_cca_transform((matrix)m, (sparse_vector)v) → vector :¶
requires
  • max_index_plus_one(v) <= m.nr()
ensures
  • returns trans(m)*v (i.e. multiply m by the vector v and return the result)
class dlib.array ¶

This object represents a 1D array of floating point numbers. Moreover, it binds directly to the C++ type std::vector<double>.

append((array)arg1, (object)arg2) → None¶
clear((array)arg1) → None¶
extend((array)arg1, (object)arg2) → None¶
resize((array)arg1, (int)arg2) → None¶
dlib.assignment_cost((matrix)cost, (list)assignment) → float :¶
requires

  • cost.nr() == cost.nc() (i.e. the input must be a square matrix)

  • for all valid i:
    • 0 <= assignment[i] < cost.nr()
ensures

  • Interprets cost as a cost assignment matrix. That is, cost[i][j] represents the cost of assigning i to j.

  • Interprets assignment as a particular set of assignments. That is, i is assigned to assignment[i].

  • returns the cost of the given assignment. That is, returns a number which is:

    sum over i: cost[i][assignment[i]]

dlib.cca((sparse_vectors)L, (sparse_vectors)R, (int)num_correlations[, (int)extra_rank=5[, (int)q=2[, (float)regularization=0]]]) → cca_outputs :¶
requires
  • num_correlations > 0
  • len(L) > 0
  • len(R) > 0
  • len(L) == len(R)
  • regularization >= 0
  • L and R must be properly sorted sparse vectors. This means they must list their elements in ascending index order and not contain duplicate index values. You can use make_sparse_vector() to ensure this is true.
ensures

  • This function performs a canonical correlation analysis between the vectors in L and R. That is, it finds two transformation matrices, Ltrans and Rtrans, such that row vectors in the transformed matrices L*Ltrans and R*Rtrans are as correlated as possible (note that in this notation we interpret L as a matrix with the input vectors in its rows). Note also that this function tries to find transformations which produce num_correlations dimensional output vectors.

  • Note that you can easily apply the transformation to a vector using apply_cca_transform(). So for example, like this:

    • apply_cca_transform(Ltrans, some_sparse_vector)

  • returns a structure containing the Ltrans and Rtrans transformation matrices as well as the estimated correlations between elements of the transformed vectors.

  • This function assumes the data vectors in L and R have already been centered (i.e. we assume the vectors have zero means). However, in many cases it is fine to use uncentered data with cca(). But if it is important for your problem then you should center your data before passing it to cca().

  • This function works with reduced rank approximations of the L and R matrices. This makes it fast when working with large matrices. In particular, we use the dlib::svd_fast() routine to find reduced rank representations of the input matrices by calling it as follows: svd_fast(L, U,D,V, num_correlations+extra_rank, q) and similarly for R. This means that you can use the extra_rank and q arguments to cca() to influence the accuracy of the reduced rank approximation. However, the default values should work fine for most problems.

  • The dimensions of the output vectors produced by L*#Ltrans or R*#Rtrans are ordered such that the dimensions with the highest correlations come first. That is, after applying the transforms produced by cca() to a set of vectors you will find that dimension 0 has the highest correlation, then dimension 1 has the next highest, and so on. This also means that the list of estimated correlations returned from cca() will always be listed in decreasing order.

  • This function performs the ridge regression version of Canonical Correlation Analysis when regularization is set to a value > 0. In particular, larger values indicate the solution should be more heavily regularized. This can be useful when the dimensionality of the data is larger than the number of samples.

  • A good discussion of CCA can be found in the paper “Canonical Correlation Analysis” by David Weenink. In particular, this function is implemented using equations 29 and 30 from his paper. We also use the idea of doing CCA on a reduced rank approximation of L and R as suggested by Paramveer S. Dhillon in his paper “Two Step CCA: A new spectral method for estimating vector models of words”.

class dlib.cca_outputs ¶
Ltrans ¶
Rtrans ¶
correlations ¶
class dlib.correlation_tracker ¶

This is a tool for tracking moving objects in a video stream. You give it the bounding box of an object in the first frame and it attempts to track the object in the box from frame to frame. This tool is an implementation of the method described in the following paper:

Danelljan, Martin, et al. ‘Accurate scale estimation for robust visual tracking.’ Proceedings of the British Machine Vision Conference BMVC. 2014.
get_position((correlation_tracker)arg1) → drectangle :¶

returns the predicted position of the object under track.

start_track((correlation_tracker)arg1, (object)image, (drectangle)bounding_box) → None :¶
requires
  • image is a numpy ndarray containing either an 8bit grayscale or RGB image.
  • bounding_box.is_empty() == false
ensures
  • This object will start tracking the thing inside the bounding box in the given image. That is, if you call update() with subsequent video frames then it will try to keep track of the position of the object inside bounding_box.
  • #get_position() == bounding_box
start_track( (correlation_tracker)arg1, (object)image, (rectangle)bounding_box) -> None :
requires
  • image is a numpy ndarray containing either an 8bit grayscale or RGB image.
  • bounding_box.is_empty() == false
ensures
  • This object will start tracking the thing inside the bounding box in the given image. That is, if you call update() with subsequent video frames then it will try to keep track of the position of the object inside bounding_box.
  • #get_position() == bounding_box
update((correlation_tracker)arg1, (object)image) → float :¶
requires
  • image is a numpy ndarray containing either an 8bit grayscale or RGB image.
  • get_position().is_empty() == false (i.e. you must have started tracking by calling start_track())
ensures
  • performs: return update(img, get_position())
update( (correlation_tracker)arg1, (object)image, (drectangle)guess) -> float :
requires
  • image is a numpy ndarray containing either an 8bit grayscale or RGB image.
  • get_position().is_empty() == false (i.e. you must have started tracking by calling start_track())
ensures
  • When searching for the object in img, we search in the area around the provided guess.
  • #get_position() == the new predicted location of the object in img. This location will be a copy of guess that has been translated and scaled appropriately based on the content of img so that it, hopefully, bounds the object in img.
  • Returns the peak to side-lobe ratio. This is a number that measures how confident the tracker is that the object is inside #get_position(). Larger values indicate higher confidence.
update( (correlation_tracker)arg1, (object)image, (rectangle)guess) -> float :
requires
  • image is a numpy ndarray containing either an 8bit grayscale or RGB image.
  • get_position().is_empty() == false (i.e. you must have started tracking by calling start_track())
ensures
  • When searching for the object in img, we search in the area around the provided guess.
  • #get_position() == the new predicted location of the object in img. This location will be a copy of guess that has been translated and scaled appropriately based on the content of img so that it, hopefully, bounds the object in img.
  • Returns the peak to side-lobe ratio. This is a number that measures how confident the tracker is that the object is inside #get_position(). Larger values indicate higher confidence.
dlib.cross_validate_ranking_trainer((svm_rank_trainer)trainer, (ranking_pairs)samples, (int)folds) → _ranking_test¶

cross_validate_ranking_trainer( (svm_rank_trainer_sparse)trainer, (sparse_ranking_pairs)samples, (int)folds) -> _ranking_test

dlib.cross_validate_sequence_segmenter((vectorss)samples, (rangess)segments, (int)folds[, (segmenter_params)params=<BIO, highFeats, signed, win=5, threads=4, eps=0.1, cache=40, non-verbose, C=100>]) → segmenter_test¶

cross_validate_sequence_segmenter( (sparse_vectorss)samples, (rangess)segments, (int)folds [, (segmenter_params)params=<BIO,highFeats,signed,win=5,threads=4,eps=0.1,cache=40,non-verbose,C=100>]) -> segmenter_test

dlib.cross_validate_trainer((svm_c_trainer_radial_basis)trainer, (vectors)x, (array)y, (int)folds) → _binary_test¶

cross_validate_trainer( (svm_c_trainer_sparse_radial_basis)trainer, (sparse_vectors)x, (array)y, (int)folds) -> _binary_test

cross_validate_trainer( (svm_c_trainer_histogram_intersection)trainer, (vectors)x, (array)y, (int)folds) -> _binary_test

cross_validate_trainer( (svm_c_trainer_sparse_histogram_intersection)trainer, (sparse_vectors)x, (array)y, (int)folds) -> _binary_test

cross_validate_trainer( (svm_c_trainer_linear)trainer, (vectors)x, (array)y, (int)folds) -> _binary_test

cross_validate_trainer( (svm_c_trainer_sparse_linear)trainer, (sparse_vectors)x, (array)y, (int)folds) -> _binary_test

dlib.cross_validate_trainer_threaded((svm_c_trainer_radial_basis)trainer, (vectors)x, (array)y, (int)folds, (int)num_threads) → _binary_test¶

cross_validate_trainer_threaded( (svm_c_trainer_sparse_radial_basis)trainer, (sparse_vectors)x, (array)y, (int)folds, (int)num_threads) -> _binary_test

cross_validate_trainer_threaded( (svm_c_trainer_histogram_intersection)trainer, (vectors)x, (array)y, (int)folds, (int)num_threads) -> _binary_test

cross_validate_trainer_threaded( (svm_c_trainer_sparse_histogram_intersection)trainer, (sparse_vectors)x, (array)y, (int)folds, (int)num_threads) -> _binary_test

cross_validate_trainer_threaded( (svm_c_trainer_linear)trainer, (vectors)x, (array)y, (int)folds, (int)num_threads) -> _binary_test

cross_validate_trainer_threaded( (svm_c_trainer_sparse_linear)trainer, (sparse_vectors)x, (array)y, (int)folds, (int)num_threads) -> _binary_test

dlib.dot((vector)arg1, (vector)arg2) → float :¶

Compute the dot product between two dense column vectors.

class dlib.drectangle ¶

This object represents a rectangular area of an image with floating point coordinates.

area((drectangle)arg1) → float¶
bottom((drectangle)arg1) → float¶
center((drectangle)arg1) → point¶
contains((drectangle)arg1, (point)point) → bool¶

contains( (drectangle)arg1, (int)x, (int)y) -> bool

contains( (drectangle)arg1, (drectangle)rectangle) -> bool

dcenter((drectangle)arg1) → point¶
height((drectangle)arg1) → float¶
intersect((drectangle)arg1, (drectangle)rectangle) → drectangle¶
is_empty((drectangle)arg1) → bool¶
left((drectangle)arg1) → float¶
right((drectangle)arg1) → float¶
top((drectangle)arg1) → float¶
width((drectangle)arg1) → float¶
class dlib.fhog_object_detector ¶

This object represents a sliding window histogram-of-oriented-gradients based object detector.

run((fhog_object_detector)arg1, (object)image[, (int)upsample_num_times=0]) → tuple :¶
requires
  • image is a numpy ndarray containing either an 8bit grayscale or RGB image.
  • upsample_num_times >= 0
ensures
  • This function runs the object detector on the input image and returns a tuple of (list of detections, list of scores, list of weight_indices).
  • Upsamples the image upsample_num_times before running the basic detector. If you don’t know how many times you want to upsample then don’t provide a value for upsample_num_times and an appropriate default will be used.
save((fhog_object_detector)arg1, (str)detector_output_filename) → None :¶

Save a simple_object_detector to the provided path.

dlib.find_candidate_object_locations((object)image, (list)rects[, (tuple)kvals=(50, 200, 3)[, (int)min_size=20[, (int)max_merging_iterations=50]]]) → None :¶

Returns found candidate objects requires

  • image == an image object which is a numpy ndarray
  • len(kvals) == 3
  • kvals should be a tuple that specifies the range of k values to use. In particular, it should take the form (start, end, num) where num > 0.
ensures

  • This function takes an input image and generates a set of candidate rectangles which are expected to bound any objects in the image. It does this by running a version of the segment_image() routine on the image and then reports rectangles containing each of the segments as well as rectangles containing unions of adjacent segments. The basic idea is described in the paper:

    Segmentation as Selective Search for Object Recognition by Koen E. A. van de Sande, et al.

    Note that this function deviates from what is described in the paper slightly. See the code for details.

  • The basic segmentation is performed kvals[2] times, each time with the k parameter (see segment_image() and the Felzenszwalb paper for details on k) set to a different value from the range of numbers linearly spaced between kvals[0] to kvals[1].

  • When doing the basic segmentations prior to any box merging, we discard all rectangles that have an area < min_size. Therefore, all outputs and subsequent merged rectangles are built out of rectangles that contain at least min_size pixels. Note that setting min_size to a smaller value than you might otherwise be interested in using can be useful since it allows a larger number of possible merged boxes to be created.

  • There are max_merging_iterations rounds of neighboring blob merging. Therefore, this parameter has some effect on the number of output rectangles you get, with larger values of the parameter giving more output rectangles.

  • This function appends the output rectangles into #rects. This means that any rectangles in rects before this function was called will still be in there after it terminates. Note further that #rects will not contain any duplicate rectangles. That is, for all valid i and j where i != j it will be true that:

    • #rects[i] != rects[j]
class dlib.full_object_detection ¶

This object represents the location of an object in an image along with the positions of each of its constituent parts.

num_parts ¶

The number of parts of the object.

part((full_object_detection)arg1, (int)idx) → point :¶

A single part of the object as a dlib point.

parts((full_object_detection)arg1) → points :¶

A vector of dlib points representing all of the parts.

rect ¶

The bounding box of the parts.

dlib.get_frontal_face_detector() → fhog_object_detector :¶

Returns the default face detector

dlib.hit_enter_to_continue() → None :¶

Asks the user to hit enter to continue and pauses until they do so.

class dlib.image_window ¶

This is a GUI window capable of showing images on the screen.

add_overlay((image_window)arg1, (rectangles)rectangles[, (rgb_pixel)color=rgb_pixel(ÿ, , )]) → None :¶
Add a list of rectangles to the image_window. They will be displayed as red boxes by default, but the color can be passed.
add_overlay( (image_window)arg1, (rectangle)rectangle [, (rgb_pixel)color=rgb_pixel(ÿ,,)]) -> None :
Add a rectangle to the image_window. It will be displayed as a red box by default, but the color can be passed.
add_overlay( (image_window)arg1, (drectangle)rectangle [, (rgb_pixel)color=rgb_pixel(ÿ,,)]) -> None :
Add a rectangle to the image_window. It will be displayed as a red box by default, but the color can be passed.
add_overlay( (image_window)arg1, (full_object_detection)detection [, (rgb_pixel)color=rgb_pixel(,,ÿ)]) -> None :
Add full_object_detection parts to the image window. They will be displayed as blue lines by default, but the color can be passed.
clear_overlay((image_window)arg1) → None :¶

Remove all overlays from the image_window.

set_image((image_window)arg1, (object)image) → None :¶
Make the image_window display the given image.
set_image( (image_window)arg1, (fhog_object_detector)detector) -> None :
Make the image_window display the given HOG detector’s filters.
set_image( (image_window)arg1, (simple_object_detector)detector) -> None :
Make the image_window display the given HOG detector’s filters.
set_title((image_window)arg1, (str)title) → None :¶

Set the title of the window to the given value.

wait_until_closed((image_window)arg1) → None :¶

This function blocks until the window is closed.

dlib.load_libsvm_formatted_data((str)file_name) → tuple :¶
ensures
  • Attempts to read a file of the given name that should contain libsvm formatted data. The data is returned as a tuple where the first tuple element is an array of sparse vectors and the second element is an array of labels.
dlib.make_sparse_vector((sparse_vector)arg1) → None :¶
This function modifies its argument so that it is a properly sorted sparse vector. This means that the elements of the sparse vector will be ordered so that pairs with smaller indices come first. Additionally, there won’t be any pairs with identical indices. If such pairs were present in the input sparse vector then their values will be added together and only one pair with their index will be present in the output.
make_sparse_vector( (sparse_vectors)arg1) -> None :
This function modifies a sparse_vectors object so that all elements it contains are properly sorted sparse vectors.
class dlib.matrix ¶

This object represents a dense 2D matrix of floating point numbers.Moreover, it binds directly to the C++ type dlib::matrix<double>.

nc((matrix)arg1) → int :¶

Return the number of columns in the matrix.

nr((matrix)arg1) → int :¶

Return the number of rows in the matrix.

set_size((matrix)arg1, (int)rows, (int)cols) → None :¶

Set the size of the matrix to the given number of rows and columns.

shape ¶
dlib.max_cost_assignment((matrix)cost) → list :¶
requires
  • cost.nr() == cost.nc() (i.e. the input must be a square matrix)
ensures

  • Finds and returns the solution to the following optimization problem:

    Maximize: f(A) == assignment_cost(cost, A) Subject to the following constraints:

    • The elements of A are unique. That is, there aren’t any elements of A which are equal.
    • len(A) == cost.nr()

  • Note that this function converts the input cost matrix into a 64bit fixed point representation. Therefore, you should make sure that the values in your cost matrix can be accurately represented by 64bit fixed point values. If this is not the case then the solution my become inaccurate due to rounding error. In general, this function will work properly when the ratio of the largest to the smallest value in cost is no more than about 1e16.

dlib.max_index_plus_one((sparse_vector)v) → int :¶
ensures
  • returns the dimensionality of the given sparse vector. That is, returns a number one larger than the maximum index value in the vector. If the vector is empty then returns 0.
class dlib.pair ¶

This object is used to represent the elements of a sparse_vector.

first ¶

This field represents the index/dimension number.

second ¶

This field contains the value in a vector at dimension specified by the first field.

class dlib.point ¶

This object represents a single point of integer coordinates that maps directly to a dlib::point.

x ¶

The x-coordinate of the point.

y ¶

The y-coordinate of the point.

class dlib.points ¶

An array of point objects.

append((points)arg1, (object)arg2) → None¶
clear((points)arg1) → None¶
extend((points)arg1, (object)arg2) → None¶
resize((points)arg1, (int)arg2) → None¶
class dlib.range ¶

This object is used to represent a range of elements in an array.

begin ¶

The index of the first element in the range. This is represented using an unsigned integer.

end ¶

One past the index of the last element in the range. This is represented using an unsigned integer.

class dlib.ranges ¶

This object is an array of range objects.

append((ranges)arg1, (object)arg2) → None¶
clear((ranges)arg1) → None¶
extend((ranges)arg1, (object)arg2) → None¶
resize((ranges)arg1, (int)arg2) → None¶
class dlib.rangess ¶

This object is an array of arrays of range objects.

append((rangess)arg1, (object)arg2) → None¶
clear((rangess)arg1) → None¶
extend((rangess)arg1, (object)arg2) → None¶
resize((rangess)arg1, (int)arg2) → None¶
class dlib.ranking_pair ¶
nonrelevant ¶
relevant ¶
class dlib.ranking_pairs ¶
append((ranking_pairs)arg1, (object)arg2) → None¶
clear((ranking_pairs)arg1) → None¶
extend((ranking_pairs)arg1, (object)arg2) → None¶
resize((ranking_pairs)arg1, (int)arg2) → None¶
class dlib.rectangle ¶

This object represents a rectangular area of an image.

area((rectangle)arg1) → int¶
bottom((rectangle)arg1) → int¶
center((rectangle)arg1) → point¶
contains((rectangle)arg1, (point)point) → bool¶

contains( (rectangle)arg1, (int)x, (int)y) -> bool

contains( (rectangle)arg1, (rectangle)rectangle) -> bool

dcenter((rectangle)arg1) → point¶
height((rectangle)arg1) → int¶
intersect((rectangle)arg1, (rectangle)rectangle) → rectangle¶
is_empty((rectangle)arg1) → bool¶
left((rectangle)arg1) → int¶
right((rectangle)arg1) → int¶
top((rectangle)arg1) → int¶
width((rectangle)arg1) → int¶
class dlib.rectangles ¶

An array of rectangle objects.

append((rectangles)arg1, (object)arg2) → None¶
clear((rectangles)arg1) → None¶
extend((rectangles)arg1, (object)arg2) → None¶
resize((rectangles)arg1, (int)arg2) → None¶
class dlib.rgb_pixel ¶
blue ¶
green ¶
red ¶
dlib.save_libsvm_formatted_data((str)file_name, (sparse_vectors)samples, (array)labels) → None :¶
requires
  • len(samples) == len(labels)
ensures
  • saves the data to the given file in libsvm format
class dlib.segmenter_params ¶

This class is used to define all the optional parameters to the train_sequence_segmenter() and cross_validate_sequence_segmenter() routines.

C ¶

SVM C parameter

allow_negative_weights ¶
be_verbose ¶
epsilon ¶
max_cache_size ¶
num_threads ¶
use_BIO_model ¶
use_high_order_features ¶
window_size ¶
class dlib.segmenter_test ¶

This object is the output of the dlib.test_sequence_segmenter() and dlib.cross_validate_sequence_segmenter() routines.

f1 ¶
precision ¶
recall ¶
class dlib.segmenter_type ¶

This object represents a sequence segmenter and is the type of object returned by the dlib.train_sequence_segmenter() routine.

weights ¶
class dlib.shape_predictor ¶

This object is a tool that takes in an image region containing some object and outputs a set of point locations that define the pose of the object. The classic example of this is human face pose prediction, where you take an image of a human face as input and are expected to identify the locations of important facial landmarks such as the corners of the mouth and eyes, tip of the nose, and so forth.

save((shape_predictor)arg1, (str)predictor_output_filename) → None :¶

Save a shape_predictor to the provided path.

class dlib.shape_predictor_training_options ¶

This object is a container for the options to the train_shape_predictor() routine.

be_verbose ¶

If true, train_shape_predictor() will print out a lot of information to stdout while training.

cascade_depth ¶

The number of cascades created to train the model with.

feature_pool_region_padding ¶

Size of region within which to sample features for the feature pool, e.g a padding of 0.5 would cause the algorithm to sample pixels from a box that was 2x2 pixels

feature_pool_size ¶

Number of pixels used to generate features for the random trees.

lambda_param ¶

Controls how tight the feature sampling should be. Lower values enforce closer features.

nu ¶

The regularization parameter. Larger values of this parameter will cause the algorithm to fit the training data better but may also cause overfitting. The value must be in the range (0, 1].

num_test_splits ¶

Number of split features at each node to sample. The one that gives the best split is chosen.

num_trees_per_cascade_level ¶

The number of trees created for each cascade.

oversampling_amount ¶

The number of randomly selected initial starting points sampled for each training example

random_seed ¶

The random seed used by the internal random number generator

tree_depth ¶

The depth of the trees used in each cascade. There are pow(2, get_tree_depth()) leaves in each tree

class dlib.simple_object_detector ¶

This object represents a sliding window histogram-of-oriented-gradients based object detector.

save((simple_object_detector)arg1, (str)detector_output_filename) → None :¶

Save a simple_object_detector to the provided path.

class dlib.simple_object_detector_training_options ¶

This object is a container for the options to the train_simple_object_detector() routine.

C ¶

C is the usual SVM C regularization parameter. So it is passed to structural_object_detection_trainer::set_c(). Larger values of C will encourage the trainer to fit the data better but might lead to overfitting. Therefore, you must determine the proper setting of this parameter experimentally.

add_left_right_image_flips ¶

if true, train_simple_object_detector() will assume the objects are left/right symmetric and add in left right flips of the training images. This doubles the size of the training dataset.

be_verbose ¶

If true, train_simple_object_detector() will print out a lot of information to the screen while training.

detection_window_size ¶

The sliding window used will have about this many pixels inside it.

epsilon ¶

epsilon is the stopping epsilon. Smaller values make the trainer’s solver more accurate but might take longer to train.

num_threads ¶

train_simple_object_detector() will use this many threads of execution. Set this to the number of CPU cores on your machine to obtain the fastest training speed.

class dlib.simple_test_results ¶
average_precision ¶
precision ¶
recall ¶
dlib.solve_structural_svm_problem((object)problem) → vector :¶

This function solves a structural SVM problem and returns the weight vector that defines the solution. See the example program python_examples/svm_struct.py for documentation about how to create a proper problem object.

class dlib.sparse_ranking_pair ¶
nonrelevant ¶
relevant ¶
class dlib.sparse_ranking_pairs ¶
append((sparse_ranking_pairs)arg1, (object)arg2) → None¶
clear((sparse_ranking_pairs)arg1) → None¶
extend((sparse_ranking_pairs)arg1, (object)arg2) → None¶
resize((sparse_ranking_pairs)arg1, (int)arg2) → None¶
class dlib.sparse_vector ¶

This object represents the mathematical idea of a sparse column vector. It is simply an array of dlib.pair objects, each representing an index/value pair in the vector. Any elements of the vector which are missing are implicitly set to zero.

Unless otherwise noted, any routines taking a sparse_vector assume the sparse vector is sorted and has unique elements. That is, the index values of the pairs in a sparse_vector should be listed in increasing order and there should not be duplicates. However, some functions work with “unsorted” sparse vectors. These are dlib.sparse_vector objects that have either duplicate entries or non-sorted index values. Note further that you can convert an “unsorted” sparse_vector into a properly sorted sparse vector by calling dlib.make_sparse_vector() on it.

append((sparse_vector)arg1, (object)arg2) → None¶
clear((sparse_vector)arg1) → None¶
extend((sparse_vector)arg1, (object)arg2) → None¶
resize((sparse_vector)arg1, (int)arg2) → None¶
class dlib.sparse_vectors ¶

This object is an array of sparse_vector objects.

append((sparse_vectors)arg1, (object)arg2) → None¶
clear((sparse_vectors)arg1) → None¶
extend((sparse_vectors)arg1, (object)arg2) → None¶
resize((sparse_vectors)arg1, (int)arg2) → None¶
class dlib.sparse_vectorss ¶

This object is an array of arrays of sparse_vector objects.

append((sparse_vectorss)arg1, (object)arg2) → None¶
clear((sparse_vectorss)arg1) → None¶
extend((sparse_vectorss)arg1, (object)arg2) → None¶
resize((sparse_vectorss)arg1, (int)arg2) → None¶
class dlib.svm_c_trainer_histogram_intersection ¶
c_class1 ¶
c_class2 ¶
cache_size ¶
epsilon ¶
set_c((svm_c_trainer_histogram_intersection)arg1, (float)arg2) → None¶
train((svm_c_trainer_histogram_intersection)arg1, (vectors)arg2, (array)arg3) → _decision_function_histogram_intersection¶
class dlib.svm_c_trainer_linear ¶
be_quiet((svm_c_trainer_linear)arg1) → None¶
be_verbose((svm_c_trainer_linear)arg1) → None¶
c_class1 ¶
c_class2 ¶
epsilon ¶
force_last_weight_to_1 ¶
has_prior ¶
learns_nonnegative_weights ¶
max_iterations ¶
set_c((svm_c_trainer_linear)arg1, (float)arg2) → None¶
set_prior((svm_c_trainer_linear)arg1, (_decision_function_linear)arg2) → None¶
train((svm_c_trainer_linear)arg1, (vectors)arg2, (array)arg3) → _decision_function_linear¶
class dlib.svm_c_trainer_radial_basis ¶
c_class1 ¶
c_class2 ¶
cache_size ¶
epsilon ¶
gamma ¶
set_c((svm_c_trainer_radial_basis)arg1, (float)arg2) → None¶
train((svm_c_trainer_radial_basis)arg1, (vectors)arg2, (array)arg3) → _decision_function_radial_basis¶
class dlib.svm_c_trainer_sparse_histogram_intersection ¶
c_class1 ¶
c_class2 ¶
cache_size ¶
epsilon ¶
set_c((svm_c_trainer_sparse_histogram_intersection)arg1, (float)arg2) → None¶
train((svm_c_trainer_sparse_histogram_intersection)arg1, (sparse_vectors)arg2, (array)arg3) → _decision_function_sparse_histogram_intersection¶
class dlib.svm_c_trainer_sparse_linear ¶
be_quiet((svm_c_trainer_sparse_linear)arg1) → None¶
be_verbose((svm_c_trainer_sparse_linear)arg1) → None¶
c_class1 ¶
c_class2 ¶
epsilon ¶
force_last_weight_to_1 ¶
has_prior ¶
learns_nonnegative_weights ¶
max_iterations ¶
set_c((svm_c_trainer_sparse_linear)arg1, (float)arg2) → None¶
set_prior((svm_c_trainer_sparse_linear)arg1, (_decision_function_sparse_linear)arg2) → None¶
train((svm_c_trainer_sparse_linear)arg1, (sparse_vectors)arg2, (array)arg3) → _decision_function_sparse_linear¶
class dlib.svm_c_trainer_sparse_radial_basis ¶
c_class1 ¶
c_class2 ¶
cache_size ¶
epsilon ¶
gamma ¶
set_c((svm_c_trainer_sparse_radial_basis)arg1, (float)arg2) → None¶
train((svm_c_trainer_sparse_radial_basis)arg1, (sparse_vectors)arg2, (array)arg3) → _decision_function_sparse_radial_basis¶
class dlib.svm_rank_trainer ¶
be_quiet((svm_rank_trainer)arg1) → None¶
be_verbose((svm_rank_trainer)arg1) → None¶
c ¶
epsilon ¶
force_last_weight_to_1 ¶
has_prior ¶
learns_nonnegative_weights ¶
max_iterations ¶
set_prior((svm_rank_trainer)arg1, (_decision_function_linear)arg2) → None¶
train((svm_rank_trainer)arg1, (ranking_pair)arg2) → _decision_function_linear¶

train( (svm_rank_trainer)arg1, (ranking_pairs)arg2) -> _decision_function_linear

class dlib.svm_rank_trainer_sparse ¶
be_quiet((svm_rank_trainer_sparse)arg1) → None¶
be_verbose((svm_rank_trainer_sparse)arg1) → None¶
c ¶
epsilon ¶
force_last_weight_to_1 ¶
has_prior ¶
learns_nonnegative_weights ¶
max_iterations ¶
set_prior((svm_rank_trainer_sparse)arg1, (_decision_function_sparse_linear)arg2) → None¶
train((svm_rank_trainer_sparse)arg1, (sparse_ranking_pair)arg2) → _decision_function_sparse_linear¶

train( (svm_rank_trainer_sparse)arg1, (sparse_ranking_pairs)arg2) -> _decision_function_sparse_linear

dlib.test_binary_decision_function((_decision_function_linear)function, (vectors)samples, (array)labels) → _binary_test¶

test_binary_decision_function( (_decision_function_sparse_linear)function, (sparse_vectors)samples, (array)labels) -> _binary_test

test_binary_decision_function( (_decision_function_radial_basis)function, (vectors)samples, (array)labels) -> _binary_test

test_binary_decision_function( (_decision_function_sparse_radial_basis)function, (sparse_vectors)samples, (array)labels) -> _binary_test

test_binary_decision_function( (_decision_function_polynomial)function, (vectors)samples, (array)labels) -> _binary_test

test_binary_decision_function( (_decision_function_sparse_polynomial)function, (sparse_vectors)samples, (array)labels) -> _binary_test

test_binary_decision_function( (_decision_function_histogram_intersection)function, (vectors)samples, (array)labels) -> _binary_test

test_binary_decision_function( (_decision_function_sparse_histogram_intersection)function, (sparse_vectors)samples, (array)labels) -> _binary_test

test_binary_decision_function( (_decision_function_sigmoid)function, (vectors)samples, (array)labels) -> _binary_test

test_binary_decision_function( (_decision_function_sparse_sigmoid)function, (sparse_vectors)samples, (array)labels) -> _binary_test

dlib.test_ranking_function((_decision_function_linear)function, (ranking_pairs)samples) → _ranking_test¶

test_ranking_function( (_decision_function_sparse_linear)function, (sparse_ranking_pairs)samples) -> _ranking_test

test_ranking_function( (_decision_function_linear)function, (ranking_pair)sample) -> _ranking_test

test_ranking_function( (_decision_function_sparse_linear)function, (sparse_ranking_pair)sample) -> _ranking_test

dlib.test_regression_function((_decision_function_linear)function, (vectors)samples, (array)targets) → _regression_test¶

test_regression_function( (_decision_function_sparse_linear)function, (sparse_vectors)samples, (array)targets) -> _regression_test

test_regression_function( (_decision_function_radial_basis)function, (vectors)samples, (array)targets) -> _regression_test

test_regression_function( (_decision_function_sparse_radial_basis)function, (sparse_vectors)samples, (array)targets) -> _regression_test

test_regression_function( (_decision_function_histogram_intersection)function, (vectors)samples, (array)targets) -> _regression_test

test_regression_function( (_decision_function_sparse_histogram_intersection)function, (sparse_vectors)samples, (array)targets) -> _regression_test

test_regression_function( (_decision_function_sigmoid)function, (vectors)samples, (array)targets) -> _regression_test

test_regression_function( (_decision_function_sparse_sigmoid)function, (sparse_vectors)samples, (array)targets) -> _regression_test

test_regression_function( (_decision_function_polynomial)function, (vectors)samples, (array)targets) -> _regression_test

test_regression_function( (_decision_function_sparse_polynomial)function, (sparse_vectors)samples, (array)targets) -> _regression_test

dlib.test_sequence_segmenter((segmenter_type)arg1, (vectorss)arg2, (rangess)arg3) → segmenter_test¶

test_sequence_segmenter( (segmenter_type)arg1, (sparse_vectorss)arg2, (rangess)arg3) -> segmenter_test

dlib.test_shape_predictor((str)dataset_filename, (str)predictor_filename) → float :¶
ensures
  • Loads an image dataset from dataset_filename. We assume dataset_filename is a file using the XML format written by save_image_dataset_metadata().
  • Loads a shape_predictor from the file predictor_filename. This means predictor_filename should be a file produced by the train_shape_predictor() routine.
  • This function tests the predictor against the dataset and returns the mean average error of the detector. In fact, The return value of this function is identical to that of dlib’s shape_predictor_trainer() routine. Therefore, see the documentation for shape_predictor_trainer() for a detailed definition of the mean average error.
test_shape_predictor( (list)images, (list)detections, (shape_predictor)shape_predictor) -> float :
requires
  • len(images) == len(object_detections)
  • images should be a list of numpy matrices that represent images, either RGB or grayscale.
  • object_detections should be a list of lists of dlib.full_object_detection objects. Each dlib.full_object_detection contains the bounding box and the lists of points that make up the object parts.
ensures
  • shape_predictor should be a file produced by the train_shape_predictor() routine.
  • This function tests the predictor against the dataset and returns the mean average error of the detector. In fact, The return value of this function is identical to that of dlib’s shape_predictor_trainer() routine. Therefore, see the documentation for shape_predictor_trainer() for a detailed definition of the mean average error.
test_shape_predictor( (list)images, (list)detections, (list)scales, (shape_predictor)shape_predictor) -> float :
requires
  • len(images) == len(object_detections)
  • len(object_detections) == len(scales)
  • for every sublist in object_detections: len(object_detections[i]) == len(scales[i])
  • scales is a list of floating point scales that each predicted part location should be divided by. Useful for normalization.
  • images should be a list of numpy matrices that represent images, either RGB or grayscale.
  • object_detections should be a list of lists of dlib.full_object_detection objects. Each dlib.full_object_detection contains the bounding box and the lists of points that make up the object parts.
ensures
  • shape_predictor should be a file produced by the train_shape_predictor() routine.
  • This function tests the predictor against the dataset and returns the mean average error of the detector. In fact, The return value of this function is identical to that of dlib’s shape_predictor_trainer() routine. Therefore, see the documentation for shape_predictor_trainer() for a detailed definition of the mean average error.
dlib.test_simple_object_detector((str)dataset_filename, (str)detector_filename[, (int)upsampling_amount=-1]) → simple_test_results :¶
requires
  • Optionally, take the number of times to upsample the testing images (upsampling_amount >= 0).
ensures
  • Loads an image dataset from dataset_filename. We assume dataset_filename is a file using the XML format written by save_image_dataset_metadata().
  • Loads a simple_object_detector from the file detector_filename. This means detector_filename should be a file produced by the train_simple_object_detector() routine.
  • This function tests the detector against the dataset and returns the precision, recall, and average precision of the detector. In fact, The return value of this function is identical to that of dlib’s test_object_detection_function() routine. Therefore, see the documentation for test_object_detection_function() for a detailed definition of these metrics.
test_simple_object_detector( (list)images, (list)boxes, (fhog_object_detector)detector [, (int)upsampling_amount=0]) -> simple_test_results :
requires
  • len(images) == len(boxes)
  • images should be a list of numpy matrices that represent images, either RGB or grayscale.
  • boxes should be a list of lists of dlib.rectangle object.
  • Optionally, take the number of times to upsample the testing images (upsampling_amount >= 0).
ensures
  • Loads a simple_object_detector from the file detector_filename. This means detector_filename should be a file produced by the train_simple_object_detector() routine.
  • This function tests the detector against the dataset and returns the precision, recall, and average precision of the detector. In fact, The return value of this function is identical to that of dlib’s test_object_detection_function() routine. Therefore, see the documentation for test_object_detection_function() for a detailed definition of these metrics.
test_simple_object_detector( (list)images, (list)boxes, (simple_object_detector)detector [, (int)upsampling_amount=-1]) -> simple_test_results :
requires
  • len(images) == len(boxes)
  • images should be a list of numpy matrices that represent images, either RGB or grayscale.
  • boxes should be a list of lists of dlib.rectangle object.
ensures
  • Loads a simple_object_detector from the file detector_filename. This means detector_filename should be a file produced by the train_simple_object_detector() routine.
  • This function tests the detector against the dataset and returns the precision, recall, and average precision of the detector. In fact, The return value of this function is identical to that of dlib’s test_object_detection_function() routine. Therefore, see the documentation for test_object_detection_function() for a detailed definition of these metrics.
dlib.train_sequence_segmenter((vectorss)samples, (rangess)segments[, (segmenter_params)params=<BIO, highFeats, signed, win=5, threads=4, eps=0.1, cache=40, non-verbose, C=100>]) → segmenter_type¶

train_sequence_segmenter( (sparse_vectorss)samples, (rangess)segments [, (segmenter_params)params=<BIO,highFeats,signed,win=5,threads=4,eps=0.1,cache=40,non-verbose,C=100>]) -> segmenter_type

dlib.train_shape_predictor((list)images, (list)object_detections, (shape_predictor_training_options)options) → shape_predictor :¶
requires
  • options.lambda_param > 0
  • 0 < options.nu <= 1
  • options.feature_pool_region_padding >= 0
  • len(images) == len(object_detections)
  • images should be a list of numpy matrices that represent images, either RGB or grayscale.
  • object_detections should be a list of lists of dlib.full_object_detection objects. Each dlib.full_object_detection contains the bounding box and the lists of points that make up the object parts.
ensures
  • Uses dlib’s shape_predictor_trainer object to train a shape_predictor based on the provided labeled images, full_object_detections, and options.
  • The trained shape_predictor is returned
train_shape_predictor( (str)dataset_filename, (str)predictor_output_filename, (shape_predictor_training_options)options) -> None :
requires
  • options.lambda_param > 0
  • 0 < options.nu <= 1
  • options.feature_pool_region_padding >= 0
ensures
  • Uses dlib’s shape_predictor_trainer to train a shape_predictor based on the labeled images in the XML file dataset_filename and the provided options. This function assumes the file dataset_filename is in the XML format produced by dlib’s save_image_dataset_metadata() routine.
  • The trained shape predictor is serialized to the file predictor_output_filename.
dlib.train_simple_object_detector((str)dataset_filename, (str)detector_output_filename, (simple_object_detector_training_options)options) → None :¶
requires
  • options.C > 0
ensures
  • Uses the structural_object_detection_trainer to train a simple_object_detector based on the labeled images in the XML file dataset_filename. This function assumes the file dataset_filename is in the XML format produced by dlib’s save_image_dataset_metadata() routine.
  • This function will apply a reasonable set of default parameters and preprocessing techniques to the training procedure for simple_object_detector objects. So the point of this function is to provide you with a very easy way to train a basic object detector.
  • The trained object detector is serialized to the file detector_output_filename.
train_simple_object_detector( (list)images, (list)boxes, (simple_object_detector_training_options)options) -> simple_object_detector :
requires
  • options.C > 0
  • len(images) == len(boxes)
  • images should be a list of numpy matrices that represent images, either RGB or grayscale.
  • boxes should be a list of lists of dlib.rectangle object.
ensures
  • Uses the structural_object_detection_trainer to train a simple_object_detector based on the labeled images and bounding boxes.
  • This function will apply a reasonable set of default parameters and preprocessing techniques to the training procedure for simple_object_detector objects. So the point of this function is to provide you with a very easy way to train a basic object detector.
  • The trained object detector is returned.
class dlib.vector ¶

This object represents the mathematical idea of a column vector.

resize((vector)arg1, (int)arg2) → None¶
set_size((vector)arg1, (int)arg2) → None¶
shape ¶
class dlib.vectors ¶

This object is an array of vector objects.

append((vectors)arg1, (object)arg2) → None¶
clear((vectors)arg1) → None¶
extend((vectors)arg1, (object)arg2) → None¶
resize((vectors)arg1, (int)arg2) → None¶
class dlib.vectorss ¶

This object is an array of arrays of vector objects.

append((vectorss)arg1, (object)arg2) → None¶
clear((vectorss)arg1) → None¶
extend((vectorss)arg1, (object)arg2) → None¶
resize((vectorss)arg1, (int)arg2) → None¶

Table Of Contents

  • Classes
  • Functions
  • Detailed API Listing

This Page

  • Show Source

Quick search

Enter search terms or a module, class or function name.

Navigation

  • index
  • modules |
  • dlib documentation »
© Copyright 2013, Davis E. King. Created using Sphinx 1.1.3.


dlib C++ Library - Suggested Books

The Library
  • Algorithms
  • API Wrappers
  • Bayesian Nets
  • Compression
  • Containers
  • Graph Tools
  • Image Processing
  • Linear Algebra
  • Machine Learning
  • Metaprogramming
  • Miscellaneous
  • Networking
  • Optimization
  • Parsing

Help/Info
  • Dlib Blog
  • Examples: C++
    • 3D Point Cloud
    • Assignment Learning
    • Base64 Encoder
    • Bayesian Network From Disk
    • Bayesian Network GUI
    • Bayesian Network
    • Bridge
    • BSP
    • C-Support Vector Machine
    • Cmd Line Parser
    • Compress Stream
    • Config File Reader
    • Custom Trainers
    • Directory Navigation
    • Empirical Kernel Map
    • Face Detection
    • Face Landmark Detection
    • FHOG Feature Extraction
    • FHOG Object Detection
    • Graph Labeling
    • GUI
    • Hough Transform
    • HTTP Server
    • Image
    • IO Socket Streams
    • IO Streams Server
    • Kernel Centroid
    • Kernel K-Means Clustering
    • Kernel Ridge Regression
    • Kernel RLS Filtering
    • Kernel RLS Regression
    • KRR Classification
    • Learning to Track
    • Linear Assignment Problems
    • Linear Manifold Regularizer
    • Linear Model Predictive Control
    • Logger Advanced
    • Logger Custom Output
    • Logger
    • Matrix Expressions
    • Matrix
    • Member Function Pointer
    • Model Selection
    • Multiclass Classification
    • Multithreaded Object
    • Neural Network
    • Non-Linear Least Squares
    • Nu-Support Vector Machine
    • Numerical Integration
    • Object Detector Advanced
    • Object Detector
    • One Class Classifiers
    • Online SVM
    • Optimization
    • Parallel For Loops
    • Pipe 2
    • Pipe
    • Quantum Computing
    • Queue
    • Rank Features
    • Relevance Vector Classification
    • Relevance Vector Regression
    • Running Stats
    • Sequence Labeling
    • Sequence Segmentation
    • Sockets
    • Sockstreambuf
    • Sparse Vectors
    • SQLite
    • Std C++ Allocator
    • Structural Support Vector Machines
    • Support Vector Regression
    • SURF
    • SVM-Rank
    • Thread Function
    • Thread Pool
    • Threaded Object
    • Threads
    • Timer
    • Train Object Detector
    • Train Shape Predictor
    • Using Custom Kernels
    • Video Object Tracking
    • Webcam Face Pose Estimation
    • XML Parser
  • Examples: Python
    • Face Detector
    • Face Landmark Detection
    • find candidate object locations
    • Linear Assignment Problems
    • Sequence Segmenter
    • Structural Support Vector Machines
    • SVM-Rank
    • Train Object Detector
    • Train Shape Predictor
    • Video Object Tracking
  • FAQ
  • Forums
  • Home
  • How to compile
  • How to contribute
  • Index
  • Introduction
  • License
  • Python API
  • Suggested Books
  • Who uses dlib?

Current Release
  • Change Log
  • Release Notes
  • Version: 18.18

Last Modified:
Sep 13, 2015
Suggested Books

One of the major goals of dlib is to have documentation that enables someone to easily make use of its various components. Ideally, you would read a short description of something, understand it immediately, and begin using it in your application without any difficulty. Obviously, this depends partly on the background of the user. For example, if you have never written C++ software before then it probably isn't going to be this easy.

This page is meant to complement the main library documentation by providing references to books, along with my commentary, which explain most of the background material needed to understand the various parts of the library. In most cases these are the books I learned from during the process of creating dlib. As always, if you disagree with anything or think I have left out an important text then shoot me an email.

General Programming

    C++

    • Programming: Principles and Practice Using C++ by Bjarne Stroustrup
        This is the sort of book you would use in a freshman introduction-to-programming class. So if you are just beginning to study programming and are interested in C++ then I think it is probably safe to say this is one of the best books you could read.

    • Accelerated C++: Practical Programming by Example by Andrew Koenig and Barbara E. Moo
        If you are new to C++ but already know how to program then this is a great book. It's also about one fourth the size of the Stroustrup book.

    • Effective C++: 55 Specific Ways to Improve Your Programs and Designs (3rd Edition) by Scott Meyers
        This is a great intermediate level C++ book. Most people have heard the jokes about how easy it is to shoot yourself in the foot with C++. This book explains many things you need to know about the language to avoid doing so on a regular basis. So if you are writing C++ software then this is a must-read. I would even claim that you are a danger to the C++ software you touch unless you know what is in this book. I'm not kidding. Finally, the book isn't just about the quirks of C++. It also discusses many general software engineering ideas which have wide applicability. So in this respect it is a great book for any software developer to read.

    • More Effective C++: 35 New Ways to Improve Your Programs and Designs by Scott Meyers
        Consider this an expansion to Effective C++. If you are going to read the above book then you would almost certainly benefit from reading this one as well.

    • The C++ Standard Library: A Tutorial and Reference by Nicolai M. Josuttis
        If you are going to buy a reference book on the C++ standard library then this is the one to get. I think you will find it is better than any of the available online references. So if you find yourself frustrated with the online resources, then this is the book for you.

    • Online C++ Standard Library Reference
        What I said aside, this is a good online reference. I often find myself referring to it when I do not have the Josuttis book on hand.

    Multithreading

    • Programming with POSIX Threads by David R. Butenhof
        When I was an undergrad, this book was my main resource for learning about multithreading. It was enjoyable to read, as are all the books on this list, and covered everything in great depth without becoming overbearing. Also, despite what the title may suggest, this book is useful for understanding multithreading broadly, not just multithreading on POSIX systems.

    Network Programming

    • Unix Network Programming, Volume 1: The Sockets Networking API (3rd Edition) by W. Richard Stevens
        A lot of people call this book the network programming Bible and this praise is well deserved. If you want a deep understanding of how computer networks function, including the Internet, then this is the book to read. As with the Butenhof book above, this is an excellent choice even for people who do not intend to write software for Unix systems.

    WIN32 Programming

    It has been a long time since I needed to refer to these two books. However, they contained information I couldn't find elsewhere no matter how hard I looked. So I recommend them in case you need to create or understand some low level win32 code.

    • Win32 Programming by Brent E. Rector and Joseph M. Newcomer
    • Programming Windows by Charles Petzold
    • MSDN Library
        This is Microsoft's online reference documentation. It is very large and sometimes confusing. But at the end of the day you should be able to find the documentation for just about every function in the entire Windows API.

Computer Science: Algorithms and Data Structures

  • Introduction to Algorithms by Cormen, Leiserson, Rivest and Stein
      You should get this book if you are looking for a good discussion of the classic computer science algorithms and data structures (e.g. most of the components on the containers page).

  • Algorithms in C++, Parts 1-4: Fundamentals, Data Structure, Sorting, Searching (3rd Edition) by Robert Sedgewick
      This is another good algorithms book. If you are going to get only one book on this subject then get the one above. However, when I was learning about these topics I used both these books and on many occasions I found it helpful to read the description of an algorithm or data structure in both. Where one description was a little vague or confusing the other generally filled in the gaps.

Lossless Data Compression

  • Text Compression by Bell, Cleary, and Witten
      When I was studying data compression this was my most useful resource. If you are looking to understand how lossless data compression algorithms work then this is the book you want. It is completely self-contained and an absolute joy to read. Note that contrary to one of the reviews on amazon.com, the book Managing Gigabytes is not the second edition of this book; if this topic interests you then be sure you get the 318 page book published in 1990.

General Math

  • Linear Algebra Done Right by Sheldon Jay Axler
      If a matrix seems like an arbitrary grid of numbers or you find that you are confused by vectors, matrices, and the various things that get done with them then this book will change your whole view of this subject. It doesn't teach you any algorithms. Instead, it will give you a general framework in which to think about all this stuff. Once you have that down everything else will start to make a lot more sense. If all goes well you will even start to agree with the following: linear algebra is beautiful. :)

  • Numerical Linear Algebra by Trefethen and Bau
      While Linear Algebra Done Right is fairly abstract, this book by Trefethen and Bau will explain some of the actual algorithms that are often used. This is a great second book if you find that you want to know more about the SVD, LU decomposition, or various other algorithms involving linear algebra.

  • Calculus: Single and Multivariable by Hughes-Hallett, Gleason, and McCallum
      Some of the books below will require and understanding of basic calculus. So I'm recommending this book. It was the book I used as an undergrad and I remember it being alright. That isn't exactly a glowing review so if you are really considering buying a calculus book you may want to check out other reviews before picking this one.

  • Introduction to Real Analysis (third edition) by Bartle and Sherbert
      At some level real analysis is like a really rigorous repeat of calculus. So if you already have an undergraduate education in calculus and you are reading things that seem reminiscent of calculus but involve stuff you haven't seen before (e.g. sup, inf, "sets of numbers", sequences of points) then you may be in need of a real analysis book. This one is quite good and should be accessible to someone with the usual undergraduate computer science math background.

Optimization

The subject of linear algebra is fundamental to optimization. So you must be familiar with the contents of a book like Linear Algebra Done Right if you are going to study this area. You will also need to know how to find the derivative of a function and understand what a derivative is all about. So you will need to know a little bit of calculus. Finally, once in a while you will need to know a little bit about real analysis. Ultimately, what you need all depends on how deep you want to go.
  • Practical Methods of Optimization (second edition) by R. Fletcher 1987
      I love this book. When I got it I literally spent my weekends sitting around reading it for hours. It is a fascinating and well written introduction to the subject of optimization. This has been my most valuable resource for learning the fundamentals of optimization and I cannot recommend it highly enough.

  • Numerical Optimization by Jorge Nocedal and Stephen Wright 2006
      This is a more recent text on optimization that is also very good. It covers many algorithms not covered by the above book.

  • Introduction to Derivative-Free Optimization by Conn, Scheinberg, and Vicente
      If you want to understand algorithms like BOBYQA then this is a good recent book on the subject. Note that a book like Practical Methods of Optimization is almost certainly a prerequisite for reading this book. As an aside, BOBYQA is not discussed in this book but its predecessor, NEWUOA is.

Machine Learning

  • Artificial Intelligence: A Modern Approach (3rd Edition) by Stuart Russell and Peter Norvig
      This book is about the much broader field of AI but it contains an excellent introduction to machine learning and it also covers other useful topics like bayesian networks. Moreover, it is very well written and self-contained. So you don't need any particular background to be able to learn from it apart from a typical undergraduate background in computer science.

  • Learning with Kernels: Support Vector Machines, Regularization, Optimization, and Beyond by Bernhard Schlkopf and Alexander J. Smola
      Most of the machine learning tools in dlib are implementations of various kernel methods. So if you want a book that covers this topic in great depth as well as breadth then this is probably the book for you. The most important prerequisite for this book is linear algebra. Virtually everything in this book depends on linear algebra in a fundamental way.

      The second important subject is optimization. Whenever you see the text mention the KKT conditions, duality, "primal variables", or quadratic programming it is talking about ideas from optimization. A good book which will explain all this to you is Practical Methods of Optimization. Note that this book calls the KKT conditions just the "KT" conditions. It is talking about the same thing. Also, duality is something that comes up a lot in optimization but in the context of machine learning usually people are talking about a particular form known as the Wolfe Dual.

      It would also be good (but maybe not critical depending on which parts you want to read) to be familiar with real analysis.

  • Kernel Methods for Pattern Analysis by John Shawe-Taylor and Nello Cristianini
      This is another good book about kernel methods. If you have to choose between this book and Learning with Kernels I would go with Learning with Kernels. However, it is good to have both since reading different presentations of difficult subjects usually makes learning them easier.

  • Structured Prediction and Learning in Computer Vision by Sebastian Nowozin and Christoph H. Lampert 2011
      If you are looking for a book discussing the background material necessary for understanding things like the Structural SVM tools in dlib then this is a good book. It is also available online in PDF form.

Image Processing

  • Digital Image Processing by Rafael C. Gonzalez and Richard E. Woods
      This is a terrific introduction to digital image processing. By and large this book doesn't require any special prerequisites. Sometimes calculus shows up, but not too much.


dlib C++ Library - Change Log

The Library
  • Algorithms
  • API Wrappers
  • Bayesian Nets
  • Compression
  • Containers
  • Graph Tools
  • Image Processing
  • Linear Algebra
  • Machine Learning
  • Metaprogramming
  • Miscellaneous
  • Networking
  • Optimization
  • Parsing

Help/Info
  • Dlib Blog
  • Examples: C++
    • 3D Point Cloud
    • Assignment Learning
    • Base64 Encoder
    • Bayesian Network From Disk
    • Bayesian Network GUI
    • Bayesian Network
    • Bridge
    • BSP
    • C-Support Vector Machine
    • Cmd Line Parser
    • Compress Stream
    • Config File Reader
    • Custom Trainers
    • Directory Navigation
    • Empirical Kernel Map
    • Face Detection
    • Face Landmark Detection
    • FHOG Feature Extraction
    • FHOG Object Detection
    • Graph Labeling
    • GUI
    • Hough Transform
    • HTTP Server
    • Image
    • IO Socket Streams
    • IO Streams Server
    • Kernel Centroid
    • Kernel K-Means Clustering
    • Kernel Ridge Regression
    • Kernel RLS Filtering
    • Kernel RLS Regression
    • KRR Classification
    • Learning to Track
    • Linear Assignment Problems
    • Linear Manifold Regularizer
    • Linear Model Predictive Control
    • Logger Advanced
    • Logger Custom Output
    • Logger
    • Matrix Expressions
    • Matrix
    • Member Function Pointer
    • Model Selection
    • Multiclass Classification
    • Multithreaded Object
    • Neural Network
    • Non-Linear Least Squares
    • Nu-Support Vector Machine
    • Numerical Integration
    • Object Detector Advanced
    • Object Detector
    • One Class Classifiers
    • Online SVM
    • Optimization
    • Parallel For Loops
    • Pipe 2
    • Pipe
    • Quantum Computing
    • Queue
    • Rank Features
    • Relevance Vector Classification
    • Relevance Vector Regression
    • Running Stats
    • Sequence Labeling
    • Sequence Segmentation
    • Sockets
    • Sockstreambuf
    • Sparse Vectors
    • SQLite
    • Std C++ Allocator
    • Structural Support Vector Machines
    • Support Vector Regression
    • SURF
    • SVM-Rank
    • Thread Function
    • Thread Pool
    • Threaded Object
    • Threads
    • Timer
    • Train Object Detector
    • Train Shape Predictor
    • Using Custom Kernels
    • Video Object Tracking
    • Webcam Face Pose Estimation
    • XML Parser
  • Examples: Python
    • Face Detector
    • Face Landmark Detection
    • find candidate object locations
    • Linear Assignment Problems
    • Sequence Segmenter
    • Structural Support Vector Machines
    • SVM-Rank
    • Train Object Detector
    • Train Shape Predictor
    • Video Object Tracking
  • FAQ
  • Forums
  • Home
  • How to compile
  • How to contribute
  • Index
  • Introduction
  • License
  • Python API
  • Suggested Books
  • Who uses dlib?

Current Release
  • Change Log
  • Release Notes
  • Version: 18.18

Last Modified:
Oct 28, 2015
Change Log
Revision: 7ae1775f61a44b7f
Author: Davis King
Date: Oct 28, 2015 (16:25:59 UTC)

Created release v18.18

Modified
dlib/CMakeLists.txt
Revision: 99b8177f34cf4091
Author: Davis King
Date: Oct 27, 2015 (14:15:47 UTC)

Removed readme since the top level one is a better place to put this information.

Deleted
dlib/README.txt
Revision: 8c7e494972a09a8d
Author: Davis King
Date: Oct 27, 2015 (13:49:40 UTC)

Suppressed warnings about unused testing code.

Modified
dlib/test/cca.cpp
Revision: e2bdd06d97346b06
Author: Davis King
Date: Oct 27, 2015 (13:38:35 UTC)

Added throw() spec to a throwing destructor.

Modified
dlib/test/multithreaded_object.cpp
Revision: c95fb0a896fbb215
Author: Davis King
Date: Oct 27, 2015 (04:50:44 UTC)

Cleaned up install instructions slightly.

Modified
python_examples/correlation_tracker.py
python_examples/face_detector.py
python_examples/face_landmark_detection.py
python_examples/find_candidate_object_locations.py
python_examples/train_object_detector.py
python_examples/train_shape_predictor.py
Revision: 06c54b1ce9117006
Author: Davis King
Date: Oct 27, 2015 (04:25:43 UTC)

Updated compile/install instructions for python bindings.

Modified
python_examples/correlation_tracker.py
python_examples/face_detector.py
python_examples/face_landmark_detection.py
python_examples/find_candidate_object_locations.py
python_examples/max_cost_assignment.py
python_examples/sequence_segmenter.py
python_examples/svm_rank.py
python_examples/svm_struct.py
python_examples/train_object_detector.py
python_examples/train_shape_predictor.py
Deleted
python_examples/compile_dlib_python_module.bat
Revision: 20e78ffeed0893a5
Author: Davis King
Date: Oct 22, 2015 (04:44:03 UTC)

fixed formatting

Modified
dlib/matrix/matrix_abstract.h
Revision: af2b147ca39b5669
Author: Davis King
Date: Oct 22, 2015 (04:40:31 UTC)

Added spec for the csv matrix output method.

Modified
dlib/matrix/matrix_abstract.h
Revision: 8d897382215d72d1
Author: Davis King
Date: Oct 22, 2015 (04:10:41 UTC)

Cleaned up the float_details code and made it more standards conforming.

Modified
dlib/float_details.h
Revision: d6b92e3d8eb5a995
Author: Davis King
Date: Oct 22, 2015 (03:59:38 UTC)

Make the Fortran bindings work in Borland compilers

Modified
dlib/matrix/lapack/fortran_id.h
Revision: 4c9aaaa0af608424
Author: Davis King
Date: Oct 02, 2015 (03:50:13 UTC)

fixed spelling error in comment

Modified
dlib/control/approximate_linear_models_abstract.h
Revision: 3f39e1040620b396
Author: Davis King
Date: Oct 12, 2015 (16:07:16 UTC)

Fixed potential compile time error.

Modified
dlib/hash_map/hash_map_kernel_c.h
Revision: c8313e63f743071e
Author: Davis King
Date: Sep 28, 2015 (17:47:44 UTC)

Made the python modules use SSE4 instructions by default.

Modified
tools/python/CMakeLists.txt
Revision: a234f2ef691e7c16
Author: Davis King
Date: Sep 28, 2015 (17:47:22 UTC)

Added message statements to print if simd instructions are being enabled.

Modified
dlib/cmake
Revision: 89e79920fbb95e3a
Author: Davis King
Date: Sep 28, 2015 (02:09:19 UTC)

More python build script improvements for windows.

Modified
dlib/add_python_module
Revision: 1effca45589d5d4f
Author: Davis King
Date: Sep 27, 2015 (16:29:07 UTC)

Made the search for pyhton3 libraries more robust.

Modified
dlib/add_python_module
Revision: 20218b525bcdf6fb
Author: Davis King
Date: Sep 27, 2015 (16:27:51 UTC)

Added missing file

Added
dlib/tell_visual_studio_to_use_static_runtime.cmake
Revision: 54d82d277a5893c8
Author: Davis King
Date: Sep 27, 2015 (16:00:51 UTC)

Improved error message when boost isn't found.

Modified
dlib/add_python_module
Revision: 62f344d334702370
Author: Davis King
Date: Sep 27, 2015 (14:10:53 UTC)

Incremented patch number.

Modified
dlib/CMakeLists.txt
Revision: 2295a3661c483949
Author: Davis King
Date: Sep 27, 2015 (14:09:44 UTC)

Made python extensions use static linking when compiled with visual studio to avoid dll hell.

Modified
dlib/add_python_module
Revision: 5ed6d16ca3728cb2
Author: Davis King
Date: Sep 27, 2015 (07:07:16 UTC)

Made the add_python_module cmake script include the visual studio runtime dlls in its output. This way they will get included by the python setup.py script.

Modified
dlib/add_python_module
Revision: ba011e10aae323f0
Author: Davis King
Date: Sep 27, 2015 (06:52:38 UTC)

On Windows, made the cmake check for an installed copy of the Intel MKL see if it works with the currently selected compiler and only uses it if the version is appropraite.

Modified
dlib/cmake_find_blas.txt
Revision: a96c1143348bd180
Author: Davis King
Date: Sep 24, 2015 (18:44:47 UTC)

Fixed a bunch of warnings in visual studio 2015.

Modified
dlib/algs.h
dlib/general_hash/random_hashing.h
dlib/gui_widgets/drawable.cpp
dlib/matrix/matrix.h
dlib/threads/multithreaded_object_extension.cpp
dlib/threads/threaded_object_extension.cpp
Revision: 3bb2eec9f4623cf9
Author: Davis King
Date: Sep 22, 2015 (16:35:03 UTC)

merged

Modified
dlib/CMakeLists.txt
dlib/matrix/matrix.h
Revision: fac7c5fb5a4c08a2
Author: Davis King
Date: Sep 22, 2015 (16:33:44 UTC)

Fixed a bug that caused cmake to not provide the correct preprocessor definitions until cmake was run twice. This was causing some projects to not build properly.

Modified
dlib/cmake
Revision: a9642b7f5f393cda
Author: Davis King
Date: Sep 22, 2015 (16:32:58 UTC)

Moved the add_global_define() macro into its own file so it can be easily used in multiple cmake files.

Modified
dlib/CMakeLists.txt
Added
dlib/add_global_compiler_switch.cmake
Revision: ac77f8b432ca894f
Author: Davis King
Date: Sep 20, 2015 (03:33:09 UTC)

Minor change to avoid warning in visual studio.

Modified
dlib/matrix/matrix.h
Revision: 18125d23b74c356c
Author: Davis King
Date: Sep 20, 2015 (03:28:30 UTC)

Changed to avoid cmake warning on cygwin.

Modified
dlib/CMakeLists.txt
Revision: c6b2b5299adb1b42
Author: Séverin Lemaignan
Date: Sep 19, 2015 (20:59:36 UTC)

'Hide' dlibConfig.cmake to prevent Windows' CMake to wrongly consider the build directory as dlib install prefix

Modified
dlib/CMakeLists.txt
Revision: a361f032ca02eae0
Author: Séverin Lemaignan
Date: Sep 13, 2015 (14:42:33 UTC)

Always generate an install target, except for 'in project' builds On Windows, though, only install the static library as dlib does not generate any useful shared library on Windows.

Modified
dlib/CMakeLists.txt
Revision: 68e9703c2cd8d6a3
Author: Séverin Lemaignan
Date: Sep 12, 2015 (24:56:42 UTC)

Set the default configuration to Release

Modified
dlib/CMakeLists.txt
Revision: b84dd35b44632145
Author: Séverin Lemaignan
Date: Sep 12, 2015 (22:41:46 UTC)

Prevent compilation (and installation) of shared lib when dlib included via dlib/cmake

Modified
dlib/CMakeLists.txt
dlib/cmake
Revision: a78e2a8cb0726b2e
Author: Séverin Lemaignan
Date: Sep 11, 2015 (18:31:12 UTC)

Create and install dlibConfig.cmake and dlibConfigVersion.cmake This allows external project to include dlib by simply using find_package(dlib REQUIRED) and: include_directories() / target_link_libraries(your_target )

Modified
dlib/CMakeLists.txt
Added
dlib/dlibConfig.cmake.in
Revision: 44919cc03b21a191
Author: Séverin Lemaignan
Date: Sep 11, 2015 (16:48:27 UTC)

Always compile a static library (even in release mode) to ease deployment of examples Install the static library along the shared one.

Modified
dlib/CMakeLists.txt
Revision: a163ed66f278dd60
Author: Séverin Lemaignan
Date: Sep 11, 2015 (15:47:32 UTC)

Added (and configure in CMake) a revision.h.in containing the version number

Modified
dlib/CMakeLists.txt
Added
dlib/revision.h.in
Revision: b7ee66fcc9fb589e
Author: Séverin Lemaignan
Date: Sep 11, 2015 (15:40:56 UTC)

In release mode on unixes, configure and install config.h according to the compilation options The name of some CMake variables has been changed to follow the naming in config.h (and thus get the special #cmakedefine directives to work as expected in config.h.in)

Modified
dlib/CMakeLists.txt
Added
dlib/config.h.in
Revision: 86bb15be9bdc2b82
Author: Séverin Lemaignan
Date: Sep 10, 2015 (18:10:00 UTC)

Added an install target for dlib Implementing the design discussed in issue #34 (ie, installation only in Release mode, for unix platforms).

Modified
dlib/CMakeLists.txt
Revision: cd4feb3d07b63ae2
Author: Séverin Lemaignan
Date: Sep 10, 2015 (17:36:27 UTC)

Set the lib version in CMakeLists

Modified
dlib/CMakeLists.txt
Revision: b12c69fdbf885e8d
Author: Davis King
Date: Sep 04, 2015 (04:48:50 UTC)

Added a check that you don't mix matrix types (float vs. double) when using set_ptrm().

Modified
dlib/matrix/matrix_subexp.h
Revision: 4438f083d627d7b0
Author: Davis King
Date: Sep 03, 2015 (18:57:29 UTC)

Added set_ptrm() along with all the aliasing detection updates necessary to allow assignment statements with mixed dlib::matrix and mat(T*) expressions that might alias each other. Also updated BLAS bindings to bind to set_ptrm() assignments.

Modified
dlib/matrix/matrix.h
dlib/matrix/matrix_assign.h
dlib/matrix/matrix_blas_bindings.h
dlib/matrix/matrix_mat.h
dlib/matrix/matrix_subexp.h
dlib/matrix/matrix_subexp_abstract.h
dlib/test/blas_bindings/blas_bindings_gemm.cpp
dlib/test/blas_bindings/blas_bindings_scal_axpy.cpp
dlib/test/matrix.cpp
Revision: 88c985aad1be53d2
Author: Davis King
Date: Sep 03, 2015 (18:20:51 UTC)

updated makefile to avoid warnings from cmake

Modified
dlib/test/blas_bindings/CMakeLists.txt
Revision: 7310e2c4d368bc2c
Author: Ehsan Azarnasab
Date: Aug 20, 2015 (02:42:44 UTC)

move setup.py 2 levels up to avoid the need to git submodules to link to source

Added
MANIFEST.in
setup.py
Deleted
tools/python/MANIFEST.in
tools/python/setup.py
Revision: 9b7de6f4bfe22574
Author: Ehsan Azarnasab
Date: Aug 20, 2015 (02:38:57 UTC)

clean up options

Modified
tools/python/setup.py
Revision: b5648c28aa2b9689
Author: Ehsan Azarnasab
Date: Aug 19, 2015 (10:43:15 UTC)

clean up module license

Modified
tools/python/setup.py
Revision: 83e3889cbba3af6e
Author: Ehsan Azarnasab
Date: Aug 19, 2015 (10:43:01 UTC)

initial manifest file to include distribution

Added
tools/python/MANIFEST.in
Revision: 19ccdb6b12b38cee
Author: Ehsan Azarnasab
Date: Aug 19, 2015 (09:59:28 UTC)

read version infor from docs

Modified
tools/python/setup.py
Revision: 4e53059f22e823bf
Author: Ehsan Azarnasab
Date: Aug 19, 2015 (09:49:45 UTC)

remove used options from argv

Modified
tools/python/setup.py
Revision: e97b2726ff25f664
Author: Ehsan Azarnasab
Date: Aug 19, 2015 (09:43:42 UTC)

initial setup.py commit. Will build and create distribution directory.

Added
tools/python/setup.py
Revision: 3caa544f487d4471
Author: Davis King
Date: Aug 26, 2015 (16:28:19 UTC)

Improved finding of X11 on mac os

Modified
dlib/CMakeLists.txt

Old Change Logs


dlib C++ Library - Release notes

The Library
  • Algorithms
  • API Wrappers
  • Bayesian Nets
  • Compression
  • Containers
  • Graph Tools
  • Image Processing
  • Linear Algebra
  • Machine Learning
  • Metaprogramming
  • Miscellaneous
  • Networking
  • Optimization
  • Parsing

Help/Info
  • Dlib Blog
  • Examples: C++
    • 3D Point Cloud
    • Assignment Learning
    • Base64 Encoder
    • Bayesian Network From Disk
    • Bayesian Network GUI
    • Bayesian Network
    • Bridge
    • BSP
    • C-Support Vector Machine
    • Cmd Line Parser
    • Compress Stream
    • Config File Reader
    • Custom Trainers
    • Directory Navigation
    • Empirical Kernel Map
    • Face Detection
    • Face Landmark Detection
    • FHOG Feature Extraction
    • FHOG Object Detection
    • Graph Labeling
    • GUI
    • Hough Transform
    • HTTP Server
    • Image
    • IO Socket Streams
    • IO Streams Server
    • Kernel Centroid
    • Kernel K-Means Clustering
    • Kernel Ridge Regression
    • Kernel RLS Filtering
    • Kernel RLS Regression
    • KRR Classification
    • Learning to Track
    • Linear Assignment Problems
    • Linear Manifold Regularizer
    • Linear Model Predictive Control
    • Logger Advanced
    • Logger Custom Output
    • Logger
    • Matrix Expressions
    • Matrix
    • Member Function Pointer
    • Model Selection
    • Multiclass Classification
    • Multithreaded Object
    • Neural Network
    • Non-Linear Least Squares
    • Nu-Support Vector Machine
    • Numerical Integration
    • Object Detector Advanced
    • Object Detector
    • One Class Classifiers
    • Online SVM
    • Optimization
    • Parallel For Loops
    • Pipe 2
    • Pipe
    • Quantum Computing
    • Queue
    • Rank Features
    • Relevance Vector Classification
    • Relevance Vector Regression
    • Running Stats
    • Sequence Labeling
    • Sequence Segmentation
    • Sockets
    • Sockstreambuf
    • Sparse Vectors
    • SQLite
    • Std C++ Allocator
    • Structural Support Vector Machines
    • Support Vector Regression
    • SURF
    • SVM-Rank
    • Thread Function
    • Thread Pool
    • Threaded Object
    • Threads
    • Timer
    • Train Object Detector
    • Train Shape Predictor
    • Using Custom Kernels
    • Video Object Tracking
    • Webcam Face Pose Estimation
    • XML Parser
  • Examples: Python
    • Face Detector
    • Face Landmark Detection
    • find candidate object locations
    • Linear Assignment Problems
    • Sequence Segmenter
    • Structural Support Vector Machines
    • SVM-Rank
    • Train Object Detector
    • Train Shape Predictor
    • Video Object Tracking
  • FAQ
  • Forums
  • Home
  • How to compile
  • How to contribute
  • Index
  • Introduction
  • License
  • Python API
  • Suggested Books
  • Who uses dlib?

Current Release
  • Change Log
  • Release Notes
  • Version: 18.18

Last Modified:
Oct 28, 2015
Release notes

Release 18.18

Release date: Oct 28, 2015
Major Changes in this Release:
New Features:
   - Added the set_ptrm() routine for assigning dlib::matrix objects to arbitrary
     memory blocks.

Non-Backwards Compatible Changes:

Bug fixes:
   - Fixed a bug that caused cmake to not provide the correct preprocessor
     definitions until cmake was run twice. This was causing some projects to
     not build properly.

Other:
   - Improvements to build system:
      - Ehsan Azarnasab contributed a setup.py so the dlib Python API can be
        installed via the usual 'python setup.py install' command.
      - Séverin Lemaignan upgraded dlib's CMake scripts so they include an
        install target.  Now dlib can be installed system wide by executing
        'cmake PATH_TO_DLIB; make install'.  This also includes installing the
        appropriate scripts for CMake's find_package(dlib) to work.

Release 18.17

Release date: Aug 15, 2015
Major Changes in this Release:
New Features:
   - More clustering tools:
      - Added bottom_up_cluster() and find_clusters_using_angular_kmeans()
        routines.
      - Added a --cluster option to the imglab tool.  This lets you cluster
        objects into groups of similar appearance/pose.
   - Improved the shape_predictor.  In particular, it can now be learned from
     datasets where some landmarks are missing.  The shape_predictor also now
     outputs a sparse feature vector that encodes which leafs are used on each
     tree to make a prediction.

Non-Backwards Compatible Changes:
   - extract_highdim_face_lbp_descriptors() produces slightly different output.

Bug fixes:
   - Fixed a minor bug in extract_highdim_face_lbp_descriptors() which was
     pointed out by Yan Xu. One of the face locations was mistakenly used twice
     while another was skipped. This change breaks backwards compatibility with
     the previous feature extraction output but should slightly improve
     accuracy of classifiers trained using these features.
   - Fixed jet() and heatmap() so they work on empty images.
   - The SQLite transaction object did not function correctly when compiled
     in a C++11 program.  Since its destructor can throw, an exception
     specification needed to be added indicating that this was possible since
     destructors are now noexcept by default in C++11.
   - Fixed a bug pointed out by Ernesto Tapia that could cause matrix
     expressions that involve sub matrix views (e.g. colm) to produce the wrong
     results when the BLAS bindings were enabled.
   - Added an if to avoid a possible division by zero inside spectral_cluster().
   - Fixed a bug in parse_xml(). It failed to check if the given input stream
     was valid before trying to parse it.

Other:

Release 18.16

Release date: Jun 3, 2015
Major Changes in this Release:
New Features:
   - Added a linear model predictive control solver.  See the mpc_ex.cpp example
     program for details.
   - Thanks to Patrick Snape, the correlation_tracker can now be used from Python.

Non-Backwards Compatible Changes:
   - The camera_transform's second operator() method now takes 3 arguments
     instead of 2.  This is to allow it to output the z distance in addition to
     scale.

Bug fixes:
   - Fixed a bug in the eigenvalue_decomposition which could occur when a
     symmetric matrix was used along with the LAPACK bindings.
   - Fixed a bug where the last column of data in a file wasn't loaded on some
     OS X machines when load_libsvm_formatted_data() was called.

Other:
   - Added a hard iteration limit to a number of the SVM solvers.
   - Adrian Rosebrock graciously setup an OS X machine for dlib testing, which
     resulted in improved CMake python scripts on OS X machines.
   - Improved the way overlapping points are rendered by the perspective_window.

Release 18.15

Release date: Apr 29, 2015
Major Changes in this Release:
New Features:
   - Added a number of tools for working with 3D data:
      - Added the perspective_window which is a tool for displaying 3D point clouds.
      - Added camera_transform.  It performs the 3D to 2D mapping needed to visualize 3D
        data.
      - Added point_transform_affine3d as well as functions for creating such transforms:
        rotate_around_x(), rotate_around_y(), rotate_around_z(), and translate_point().
   - Added draw_solid_circle() for drawing on images.
   - Added get_best_hough_point() to the hough_transform.
   - Thanks to Jack Culpepper, the python API for object detection now outputs detection
     confidences.
   - Added lspi, an implementation of the least-squares policy iteration algorithm.

Non-Backwards Compatible Changes:
   - The shape_predictor and shape_predictor_trainer had a non-optimal behavior when used
     with objects that have non-square bounding boxes. This has been fixed but will cause
     models that were trained with the previous version of dlib to not work as accurately if
     they used non-square boxes. So you might have to retrain your models when updating dlib.

Bug fixes:
   - Fixed a bug which prevented add_image_rotations() from compiling.

Other:
   - The imglab tool now allows the user to click and drag annotations around by holding
     shift and right clicking.

Release 18.14

Release date: Mar 01, 2015
Major Changes in this Release:
New Features:
   - Added spectral_cluster()
   - Added sub_image() and sub_image_proxy
   - Added set_all_logging_headers()

Non-Backwards Compatible Changes:

Bug fixes:
   - Fixed a bug that caused the correlation_tracker to erroneously trigger an assert when
     run in debug mode.

Other:
   - Improved the usability of the new drectanle object.
   - Optimized extract_fhog_features() for the case where cell_size==1. This makes it about
     4x faster in that case.
   - Made it so you can compose point transform objects via operator *.

Release 18.13

Release date: Feb 03, 2015
Major Changes in this Release:
New Features:
   - Added the correlation_tracker object
   - Added the option to force the last weight to 1 to structural_assignment_trainer.
   - Added max_point_interpolated()
   - Added the drectangle object
   - New Python Tools:
      - Patrick Snape contributed a Python binding for the face landmarking tool and
        the general purpose shape prediction/training tools.
      - Vinh Khuc contributed a Python binding for find_candidate_object_locations(),
        dlib's implementation of the selective search object location proposal method.

Non-Backwards Compatible Changes:

Bug fixes:
   - Fixed a bug in extract_image_chips() and get_mapping_to_chip() that caused
     incorrect outputs when the requested chip stretched the image unevenly
     vertically or horizontally.
   - Made CMake check that libpng and libjpeg actually contain the link symbols
     they are supposed to since, on some systems, these libraries aren't
     installed correctly and will cause linker errors if used.
   - Fixed assign_border_pixels(img, rect) so that it correctly zeros an image
     when an empty rectangle is supplied. Previously, it did nothing to the
     image in this case.
   - Fixed compute_lda_transform() so it works properly when the class
     covariance matrices are singular even after performing PCA.
   - Fixed a bug in find_similarity_transform(). When given just two points as
     inputs it would sometimes produce a reflection rather than a similarity
     transform.
   - Disabled all bindings to FFTW because FFTW isn't threadsafe.

Other:
   - Added an example program for dlib's SQLite API and made a few minor
     usability improvements to the API as well.

Release 18.12

Release date: Dec 20, 2014
Major Changes in this Release:
New Features:
   - Upgraded fft() and ifft() to support 2D matrices.
   - Added hough_transform
   - Added skeleton() for finding the skeletonization of a binary image.
   - Added distance_to_line(), clip_line_to_rectangle(), min_point(), and max_point().
   - Added a simple API for calling C++ from MATLAB.

Non-Backwards Compatible Changes:

Bug fixes:
   - Fixed a compile time error that could happen when calling fft() for
     certain input types.
   - Fixed a compile time error that prevented auto_threshold_image() from
     being used.
   - Fixed name clashes with new version of Boost.
   - Changed Python pickling code so it works with Python 3.
   - Fixed CMake compile time error related to finding fftw.

Other:
   - Made extract_image_chips() much faster when extracting unscaled image chips.

Release 18.11

Release date: Nov 13, 2014
Major Changes in this Release:
New Features:
   - Added save_jpeg()
   - Added the option to use an identity matrix prior to vector_normalizer_frobmetric.
   - Made the extract_image_chips() routine more flexible, in particular: Added
     get_mapping_to_chip(), get_face_chip_details(), map_det_to_chip(), and also
     upgraded chip_details so you can specify a chip extraction by a bunch of
     point correspondences between the chip and the original image.
   - Added a set of local-binary-pattern based feature extractors:
     make_uniform_lbp_image(), extract_histogram_descriptors(),
     extract_uniform_lbp_descriptors(), and extract_highdim_face_lbp_descriptors()
   - Added compute_lda_transform()
   - Added equal_error_rate()
   - Added cast_to() to the type_safe_union. This allows you to get the
     contents of a const type_safe_union.

Non-Backwards Compatible Changes:

Bug fixes:
   - Changed noncopyable.h to avoid a name clash with boost 1.56
   - On some platforms hostname_to_ip() would erroneously return 0.0.0.0. This
     has been fixed.

Other:

Release 18.10

Release date: Aug 28, 2014
Major Changes in this Release:
New Features:
   - Added find_similarity_transform()
   - Added the ability to upgrade a auto_mutex_readonly from a readonly lock to a write
     lock.
   - Added an implementation of the paper "One Millisecond Face Alignment with an Ensemble
     of Regression Trees" by Vahid Kazemi and Josephine Sullivan which appeared in this
     year's CVPR conference.  Therefore, dlib now includes tools for learning shape models
     and also comes with a state-of-the-art face landmark locator.  See the
     face_landmark_detection_ex.cpp and train_shape_predictor_ex.cpp example programs for
     an introduction.

Non-Backwards Compatible Changes:
   - Made the interface to all the image processing routines more generic.  In particular,
     it is now easier to use arbitrary image types with dlib.  The new generic image
     interface is defined in dlib/image_processing/generic_image.h and simply consists of
     seven user defined global functions and a traits template.  Any user code that was
     using array2d objects to represent images will still work.  However, if you had been
     using your own custom image object you will need to provide implementations of the
     seven functions.  Instructions for how to do this are in
     dlib/image_processing/generic_image.h.

Bug fixes:
   - Changed the murmur hash implementation to avoid any possibility of strict aliasing
     violations in user code, even when things get inlined in unfavorable ways.
   - Fixed a color space handling bug in resize_image() that caused bad looking outputs in
     some cases.
   - If "cmake" was a substring of the full path to your source code folder then the cmake
     scripts would fail. This has been fixed.
   - Fixed a compile time error that could occur when using find_max_single_variable().

Other:
   - load_image() now uses the internal file header information to detect the
     image format rather than looking at the file extension.
   - Renamed unit test program to dtest avoid warnings from CMake.
   - cross_validate_trainer() and cross_validate_trainer_threaded() no loner make copies
     of the training data.  This significantly reduces their RAM usage for large datasets.
   - Changed the serialization code for C-strings so that they don't save the null
     terminator byte. This makes their serialization format the same as the format for
     std::string.  The code should still be able to read all previously serialized data
     correctly, so the change is backwards compatible with previous versions of dlib.
   - Changed the evaluate_detectors() routine so that it applies non-max suppression to
     each detector individually. This way one detector doesn't stomp on the output of
     another detector.
   - Made the version of draw_line() that draws onto a regular image use alpha blending
     for drawing diagonal lines.

Release 18.9

Release date: Jun 16, 2014
Major Changes in this Release:
New Features:

Non-Backwards Compatible Changes:

Bug fixes:
   - The new simplified serialization API that works like serialize("filename")<<object
     was not opening files in binary mode and therefore didn't work properly on Windows.
     This has been fixed.

Other:

Old Release Notes


enable_if

Copyright 2003 Jaakko Järvi, Jeremiah Willcock, Andrew Lumsdaine.

1 Introduction

The enable_if family of templates is a set of tools to allow a function template or a class template specialization to include or exclude itself from a set of matching functions or specializations based on properties of its template arguments. For example, one can define function templates that are only enabled for, and thus only match, an arbitrary set of types defined by a traits class. The enable_if templates can also be applied to enable class template specializations. Applications of enable_if are discussed in length in [1] and [2].

1.1 Synopsis

namespace boost {
  template <class Cond, class T = void> struct enable_if;
  template <class Cond, class T = void> struct disable_if;
  template <class Cond, class T> struct lazy_enable_if;
  template <class Cond, class T> struct lazy_disable_if;

  template <bool B, class T = void> struct enable_if_c;
  template <bool B, class T = void> struct disable_if_c;
  template <bool B, class T> struct lazy_enable_if_c;
  template <bool B, class T> struct lazy_disable_if_c;
}

1.2 Background

Sensible operation of template function overloading in C++ relies on the SFINAE (substitution-failure-is-not-an-error) principle [3]: if an invalid argument or return type is formed during the instantiation of a function template, the instantiation is removed from the overload resolution set instead of causing a compilation error. The following example, taken from [1], demonstrates why this is important:
int negate(int i) { return -i; }

template <class F>
typename F::result_type negate(const F& f) { return -f(); }
Suppose the compiler encounters the call negate(1). The first definition is obviously a better match, but the compiler must nevertheless consider (and instantiate the prototypes) of both definitions to find this out. Instantiating the latter definition with F as int would result in:
int::result_type negate(const int&);
where the return type is invalid. If this was an error, adding an unrelated function template (that was never called) could break otherwise valid code. Due to the SFINAE principle the above example is not, however, erroneous. The latter definition of negate is simply removed from the overload resolution set.

The enable_if templates are tools for controlled creation of the SFINAE conditions.

2 The enable_if templates

The names of the enable_if templates have three parts: an optional lazy_ tag, either enable_if or disable_if, and an optional _c tag. All eight combinations of these parts are supported. The meaning of the lazy_ tag is described in Section 3.3. The second part of the name indicates whether a true condition argument should enable or disable the current overload. The third part of the name indicates whether the condition argument is a bool value (_c suffix), or a type containing a static bool constant named value (no suffix). The latter version interoperates with Boost.MPL.

The definitions of enable_if_c and enable_if are as follows (we use enable_if templates unqualified but they are in the boost namespace).
template <bool B, class T = void>
struct enable_if_c {
  typedef T type;
};

template <class T>
struct enable_if_c<false, T> {};

template <class Cond, class T = void>
struct enable_if : public enable_if_c<Cond::value, T> {};
An instantiation of the enable_if_c template with the parameter B as true contains a member type type, defined to be T. If B is false, no such member is defined. Thus enable_if_c<B, T>::type is either a valid or an invalid type expression, depending on the value of B. When valid, enable_if_c<B, T>::type equals T. The enable_if_c template can thus be used for controlling when functions are considered for overload resolution and when they are not. For example, the following function is defined for all arithmetic types (according to the classification of the Boost type_traits library):
template <class T>
typename enable_if_c<boost::is_arithmetic<T>::value, T>::type
foo(T t) { return t; }
The disable_if_c template is provided as well, and has the same functionality as enable_if_c except for the negated condition. The following function is enabled for all non-arithmetic types.
template <class T>
typename disable_if_c<boost::is_arithmetic<T>::value, T>::type
bar(T t) { return t; }
For easier syntax in some cases and interoperation with Boost.MPL we provide versions of the enable_if templates taking any type with a bool member constant named value as the condition argument. The MPL bool_, and_, or_, and not_ templates are likely to be useful for creating such types. Also, the traits classes in the Boost.Type_traits library follow this convention. For example, the above example function foo can be alternatively written as:
template <class T>
typename enable_if<boost::is_arithmetic<T>, T>::type
foo(T t) { return t; }

3 Using enable_if

The enable_if templates are defined in boost/utility/enable_if.hpp, which is included by boost/utility.hpp.

The enable_if template can be used either as the return type, or as an extra argument. For example, the foo function in the previous section could also be written as:
template <class T>
T foo(T t, typename enable_if<boost::is_arithmetic<T> >::type* dummy = 0);
Hence, an extra parameter of type void* is added, but it is given a default value to keep the parameter hidden from client code. Note that the second template argument was not given to enable_if, as the default void gives the desired behavior.

Whether to write the enabler as an argument or within the return type is largely a matter of taste, but for certain functions, only one alternative is possible:
  • Operators have a fixed number of arguments, thus enable_if must be used in the return type.
  • Constructors and destructors do not have a return type; an extra argument is the only option.
  • There does not seem to be a way to specify an enabler for a conversion operator. Converting constructors, however, can have enablers as extra default arguments.

3.1 Enabling template class specializations

Class template specializations can be enabled or disabled with enable_if. One extra template parameter needs to be added for the enabler expressions. This parameter has the default value void. For example:
template <class T, class Enable = void>
class A { ... };

template <class T>
class A<T, typename enable_if<is_integral<T> >::type> { ... };

template <class T>
class A<T, typename enable_if<is_float<T> >::type> { ... };
Instantiating A with any integral type matches the first specialization, whereas any floating point type matches the second one. All other types match the primary template. The condition can be any compile-time boolean expression that depends on the template arguments of the class. Note that again, the second argument to enable_if is not needed; the default (void) is the correct value.

3.2 Overlapping enabler conditions

Once the compiler has examined the enabling conditions and included the function into the overload resolution set, normal C++ overload resolution rules are used to select the best matching function. In particular, there is no ordering between enabling conditions. Function templates with enabling conditions that are not mutually exclusive can lead to ambiguities. For example:
template <class T>
typename enable_if<boost::is_integral<T>, void>::type
foo(T t) {}

template <class T>
typename enable_if<boost::is_arithmetic<T>, void>::type
foo(T t) {}
All integral types are also arithmetic. Therefore, say, for the call foo(1), both conditions are true and both functions are thus in the overload resolution set. They are both equally good matches and thus ambiguous. Of course, more than one enabling condition can be simultaneously true as long as other arguments disambiguate the functions.

The above discussion applies to using enable_if in class template partial specializations as well.

3.3 Lazy enable_if

In some cases it is necessary to avoid instantiating part of a function signature unless an enabling condition is true. For example:
template <class T, class U> class mult_traits;

template <class T, class U>
typename enable_if<is_multipliable<T, U>, typename mult_traits<T, U>::type>::type
operator*(const T& t, const U& u) { ... }
Assume the class template mult_traits is a traits class defining the resulting type of a multiplication operator. The is_multipliable traits class specifies for which types to enable the operator. Whenever is_multipliable<A, B>::value is true for some types A and B, then mult_traits<A, B>::type is defined.

Now, trying to invoke (some other overload) of operator* with, say, operand types C and D for which is_multipliable<C, D>::value is false and mult_traits<C, D>::type is not defined is an error on some compilers. The SFINAE principle is not applied because the invalid type occurs as an argument to another template. The lazy_enable_if and lazy_disable_if templates (and their _c versions) can be used in such situations:
template<class T, class U>
typename lazy_enable_if<is_multipliable<T, U>, mult_traits<T, U> >::type
operator*(const T& t, const U& u) { ... }
The second argument of lazy_enable_if must be a class type that defines a nested type named type whenever the first parameter (the condition) is true.

Note
Referring to one member type or static constant in a traits class causes all of the members (type and static constant) of that specialization to be instantiated. Therefore, if your traits classes can sometimes contain invalid types, you should use two distinct templates for describing the conditions and the type mappings. In the above example, is_multipliable<T, U>::value defines when mult_traits<T, U>::type is valid.

3.4 Compiler workarounds

Some compilers flag functions as ambiguous if the only distinguishing factor is a different condition in an enabler (even though the functions could never be ambiguous). For example, some compilers (e.g. GCC 3.2) diagnose the following two functions as ambiguous:
template <class T>
typename enable_if<boost::is_arithmetic<T>, T>::type
foo(T t);

template <class T>
typename disable_if<boost::is_arithmetic<T>, T>::type
foo(T t);
Two workarounds can be applied:
  • Use an extra dummy parameter which disambiguates the functions. Use a default value for it to hide the parameter from the caller. For example:
    template <int> struct dummy { dummy(int) {} };

template <class T>
typename enable_if<boost::is_arithmetic<T>, T>::type
foo(T t, dummy<0> = 0);

template <class T>
typename disable_if<boost::is_arithmetic<T>, T>::type
foo(T t, dummy<1> = 0);

  • Define the functions in different namespaces and bring them into a common namespace with using declarations:
    namespace A {
  template <class T>
  typename enable_if<boost::is_arithmetic<T>, T>::type
  foo(T t);
}

namespace B {
  template <class T>
  typename disable_if<boost::is_arithmetic<T>, T>::type
  foo(T t);
}

using A::foo;
using B::foo;
    Note that the second workaround above cannot be used for member templates. On the other hand, operators do not accept extra arguments, which makes the first workaround unusable. As the net effect, neither of the workarounds are of assistance for templated operators that need to be defined as member functions (assignment and subscript operators).

4 Acknowledgements

We are grateful to Howard Hinnant, Jason Shirk, Paul Mensonides, and Richard Smith whose findings have influenced the library.

References

[1]
Jaakko Järvi, Jeremiah Willcock, Howard Hinnant, and Andrew Lumsdaine. Function overloading based on arbitrary properties of types. C/C++ Users Journal, 21(6):25--32, June 2003.

[2]
Jaakko Järvi, Jeremiah Willcock, and Andrew Lumsdaine. Concept-controlled polymorphism. In Frank Pfennig and Yannis Smaragdakis, editors, Generative Programming and Component Engineering, volume 2830 of LNCS, pages 228--244. Springer Verlag, September 2003.

[3]
David Vandevoorde and Nicolai M. Josuttis. C++ Templates: The Complete Guide. Addison-Wesley, 2002.
Contributed by:
Jaakko Järvi, Jeremiah Willcock and Andrew Lumsdaine
{jajarvi|jewillco|lums}@osl.iu.edu
Indiana University
Open Systems Lab
This document was translated from LATEX by HEVEA .


dlib C++ Library - Old Change Logs

The Library
  • Algorithms
  • API Wrappers
  • Bayesian Nets
  • Compression
  • Containers
  • Graph Tools
  • Image Processing
  • Linear Algebra
  • Machine Learning
  • Metaprogramming
  • Miscellaneous
  • Networking
  • Optimization
  • Parsing

Help/Info
  • Dlib Blog
  • Examples: C++
    • 3D Point Cloud
    • Assignment Learning
    • Base64 Encoder
    • Bayesian Network From Disk
    • Bayesian Network GUI
    • Bayesian Network
    • Bridge
    • BSP
    • C-Support Vector Machine
    • Cmd Line Parser
    • Compress Stream
    • Config File Reader
    • Custom Trainers
    • Directory Navigation
    • Empirical Kernel Map
    • Face Detection
    • Face Landmark Detection
    • FHOG Feature Extraction
    • FHOG Object Detection
    • Graph Labeling
    • GUI
    • Hough Transform
    • HTTP Server
    • Image
    • IO Socket Streams
    • IO Streams Server
    • Kernel Centroid
    • Kernel K-Means Clustering
    • Kernel Ridge Regression
    • Kernel RLS Filtering
    • Kernel RLS Regression
    • KRR Classification
    • Learning to Track
    • Linear Assignment Problems
    • Linear Manifold Regularizer
    • Linear Model Predictive Control
    • Logger Advanced
    • Logger Custom Output
    • Logger
    • Matrix Expressions
    • Matrix
    • Member Function Pointer
    • Model Selection
    • Multiclass Classification
    • Multithreaded Object
    • Neural Network
    • Non-Linear Least Squares
    • Nu-Support Vector Machine
    • Numerical Integration
    • Object Detector Advanced
    • Object Detector
    • One Class Classifiers
    • Online SVM
    • Optimization
    • Parallel For Loops
    • Pipe 2
    • Pipe
    • Quantum Computing
    • Queue
    • Rank Features
    • Relevance Vector Classification
    • Relevance Vector Regression
    • Running Stats
    • Sequence Labeling
    • Sequence Segmentation
    • Sockets
    • Sockstreambuf
    • Sparse Vectors
    • SQLite
    • Std C++ Allocator
    • Structural Support Vector Machines
    • Support Vector Regression
    • SURF
    • SVM-Rank
    • Thread Function
    • Thread Pool
    • Threaded Object
    • Threads
    • Timer
    • Train Object Detector
    • Train Shape Predictor
    • Using Custom Kernels
    • Video Object Tracking
    • Webcam Face Pose Estimation
    • XML Parser
  • Examples: Python
    • Face Detector
    • Face Landmark Detection
    • find candidate object locations
    • Linear Assignment Problems
    • Sequence Segmenter
    • Structural Support Vector Machines
    • SVM-Rank
    • Train Object Detector
    • Train Shape Predictor
    • Video Object Tracking
  • FAQ
  • Forums
  • Home
  • How to compile
  • How to contribute
  • Index
  • Introduction
  • License
  • Python API
  • Suggested Books
  • Who uses dlib?

Current Release
  • Change Log
  • Release Notes
  • Version: 18.18

Last Modified:
Oct 28, 2015
Old Change Logs
Revision: 840e939d29579133
Author: Davis King
Date: Aug 15, 2015 (17:37:19 UTC)

fixed incorrect tests

Modified
dlib/test/matrix3.cpp
Revision: ce79c2f10418c4b0
Author: Davis King
Date: Aug 15, 2015 (08:13:41 UTC)

Improved grammar in boost compilation message.

Modified
dlib/add_python_module
Revision: c91dc2b306b6a620
Author: Davis King
Date: Aug 15, 2015 (07:01:47 UTC)

Fixed a bug in parse_xml(). It failed to check if the given input stream was valid before trying to parse it.

Modified
dlib/xml_parser/xml_parser_kernel_1.h
dlib/xml_parser/xml_parser_kernel_abstract.h
Revision: 46613bd0943216ac
Author: Davis King
Date: Aug 12, 2015 (16:15:18 UTC)

Fixed build error due to messed up includes.

Modified
dlib/image_processing/scan_image_boxes.h
dlib/image_processing/scan_image_pyramid.h
tools/python/src/simple_object_detector.h
Revision: a05e0cb11e25e772
Author: Davis King
Date: Aug 11, 2015 (02:51:35 UTC)

added missing #include

Modified
examples/webcam_face_pose_ex.cpp
Revision: 5eb8a31bfc198c84
Author: Davis King
Date: Aug 11, 2015 (02:49:14 UTC)

Removed unnecessary #included code.

Modified
dlib/image_processing/frontal_face_detector.h
Revision: 24bda73b32b46353
Author: TzuTa Lin
Date: Aug 06, 2015 (21:31:53 UTC)

Remove redundant include

Modified
dlib/serialize.h
Revision: 4124252490836ba2
Author: Davis King
Date: Aug 05, 2015 (16:44:10 UTC)

Added sponsorship statement

Modified
dlib/README.txt
Revision: 1ba8d41bfd8abc5c
Author: Davis King
Date: Jul 13, 2015 (16:45:56 UTC)

Made the shape_predictor output a sparse feature vector that encodes which leafs are used on each tree to make a prediction.

Modified
dlib/image_processing/shape_predictor.h
dlib/image_processing/shape_predictor_abstract.h
Revision: 573a2020698b0e79
Author: Davis King
Date: Jul 03, 2015 (10:31:43 UTC)

merged

Modified
dlib/geometry/drectangle.h
dlib/geometry/drectangle_abstract.h
dlib/misc_api/misc_api_kernel_abstract.h
dlib/misc_api/misc_api_shared.h
dlib/svm/kkmeans.h
dlib/svm/kkmeans_abstract.h
dlib/test/kmeans.cpp
docs/docs/ml.xml
docs/docs/term_index.xml
tools/imglab/CMakeLists.txt
tools/imglab/src/main.cpp
Added
tools/imglab/src/cluster.cpp
tools/imglab/src/cluster.h
Revision: a636ba03c2b48da2
Author: Davis King
Date: Jun 21, 2015 (05:12:11 UTC)

Turned some DLIB_ASSERT() statements into DLIB_CASSERT() since it gives better error reporting and is not a speed bottleneck.

Modified
dlib/image_processing/object_detector.h
Revision: 316d9d8c0b46b47e
Author: Davis King
Date: Jun 13, 2015 (17:20:06 UTC)

Added an if to avoid a possible division by zero inside spectral_cluster().

Modified
dlib/clustering/spectral_cluster.h
Revision: 2196f5b0a2478cca
Author: Davis King
Date: Jun 13, 2015 (17:19:39 UTC)

Made pick_initial_centers() slightly more robust.

Modified
dlib/svm/kkmeans.h
Revision: 992ee20aace3abd9
Author: Davis King
Date: Jun 12, 2015 (05:00:21 UTC)

Gave the shape_predictor_trainer the ability to learn from datasets where some landmarks are missing.

Modified
dlib/image_processing/shape_predictor.h
dlib/image_processing/shape_predictor_abstract.h
Revision: 07b4ea0a61a45af7
Author: Davis King
Date: Aug 01, 2015 (08:51:05 UTC)

Fixed a bug pointed out by Ernesto Tapia that could cause matrix expressions that involve sub matrix views (e.g. colm) to produce the wrong results when the BLAS bindings were enabled.

Modified
dlib/matrix/matrix_blas_bindings.h
dlib/test/matrix3.cpp
Revision: 32ac355ab4e99ec2
Author: Davis King
Date: Aug 01, 2015 (08:49:03 UTC)

Clarified spec

Modified
dlib/optimization/optimization_trust_region_abstract.h
Revision: baa4cb792c58698b
Author: Davis King
Date: Jul 24, 2015 (04:15:40 UTC)

Switched more URLs to dlib.net rather than sourceforge.net.

Modified
examples/face_landmark_detection_ex.cpp
examples/webcam_face_pose_ex.cpp
Revision: 5432208e28ff8a86
Author: Davis King
Date: Jul 22, 2015 (10:46:26 UTC)

Added an exception specification saying that transaction's destructor can throw since C++11 sets all destructors to noexcept unless otherwise specified.

Modified
dlib/sqlite/sqlite_tools.h
Revision: 52e9debcbf05f7b7
Author: Davis King
Date: Jul 14, 2015 (04:13:46 UTC)

Fixed jet() and heatmap() so they work on empty images.

Modified
dlib/image_transforms/colormaps.h
Revision: 3d54275b600da1bf
Author: Davis King
Date: Jul 17, 2015 (15:41:33 UTC)

Fixed the image_display so that when you try to click on boxes that happen to have object parts labeled with OBJECT_PART_NOT_PRESENT it doesn't accidentally move that non-present part rather than what you are clicking on.

Modified
dlib/gui_widgets/widgets.cpp
Revision: 33e977b838e1e45a
Author: Aziz Baibabaev
Date: Jul 13, 2015 (19:30:14 UTC)

Replace add_definitions with CMAKE_CXX_FLAGS in cmake file When using add_definitions erroneous flags are passed to dll resource compiler under MinGW. This breaks the build for anything linked to dlib, using a dll rc and MinGW. The proper way is to append to CMAKE_CXX_FLAGS. For CMake 2.8.12 and higher the proper way is add_compile_options(-Wreturn-type) OR target_compile_options(dlib PRIVATE -Wreturn-type)

Modified
dlib/cmake
Revision: 5392623eba437591
Author: Davis King
Date: Jul 12, 2015 (09:50:40 UTC)

Gave imglab the ability to jump to a specific image via a keyboard command.

Modified
tools/imglab/src/metadata_editor.cpp
tools/imglab/src/metadata_editor.h
Revision: f790c32310d50dd6
Author: Davis King
Date: Jul 12, 2015 (09:48:12 UTC)

Added has_input_focus() to the field_field.

Modified
dlib/gui_widgets/widgets.cpp
dlib/gui_widgets/widgets.h
dlib/gui_widgets/widgets_abstract.h
Revision: ca2f6a00a7c6ca80
Author: Davis King
Date: Jul 05, 2015 (10:36:39 UTC)

Added --rmdupes.

Modified
tools/imglab/src/main.cpp
Revision: 7a24d77092489beb
Author: Davis King
Date: Jul 04, 2015 (16:45:07 UTC)

Added --rmtrunc, made --rmdiff mark a box as ignored rather than totally removing it, and also made --stats print the number of non-ignored boxes.

Modified
tools/imglab/src/main.cpp
Revision: 66673cb72111b14d
Author: Davis King
Date: Jul 04, 2015 (16:28:52 UTC)

Fixed a bug that crashed imglab when trying to cluster datasets with empty or really small boxes.

Modified
tools/imglab/src/cluster.cpp
Revision: 0006634a9f6b9406
Author: Davis King
Date: Jul 04, 2015 (05:41:34 UTC)

fixed bad input validation

Modified
tools/imglab/src/main.cpp
Revision: fae92a16c74271db
Author: Davis King
Date: Jul 04, 2015 (05:37:02 UTC)

Added the --rotate option to imglab.

Modified
tools/imglab/src/main.cpp
Revision: ce805eb57997fbcd
Author: Davis King
Date: Jul 04, 2015 (05:15:02 UTC)

Removed conditional compilation regarding jpeg and png support. It's just always going to be required for imglab.

Modified
tools/imglab/src/main.cpp
Revision: e6143f94fa6b8ff4
Author: Davis King
Date: Jul 03, 2015 (07:58:59 UTC)

Added the --cluster option to imglab.

Modified
tools/imglab/CMakeLists.txt
tools/imglab/src/main.cpp
Added
tools/imglab/src/cluster.cpp
tools/imglab/src/cluster.h
Revision: 746e57a1aab88c61
Author: Davis King
Date: Jul 03, 2015 (07:54:56 UTC)

Added a version of set_aspect_ratio() that works for drectangle.

Modified
dlib/geometry/drectangle.h
dlib/geometry/drectangle_abstract.h
Revision: db2cdc11fb1d6635
Author: Davis King
Date: Jul 02, 2015 (04:27:51 UTC)

A minor optimization

Modified
tools/imglab/src/main.cpp
Revision: c5788e40ad3bb7b6
Author: Davis King
Date: Jul 02, 2015 (04:24:41 UTC)

Added the --tile option to imglab.

Modified
tools/imglab/src/main.cpp
Revision: af99f424e6faf52c
Author: Davis King
Date: Jul 02, 2015 (04:20:27 UTC)

Added a .revert() to the locally_change_current_dir object.

Modified
dlib/misc_api/misc_api_kernel_abstract.h
dlib/misc_api/misc_api_shared.h
Revision: 3e503e2572dceac3
Author: Davis King
Date: Jul 01, 2015 (13:26:05 UTC)

Added find_clusters_using_angular_kmeans()

Modified
dlib/svm/kkmeans.h
dlib/svm/kkmeans_abstract.h
dlib/test/kmeans.cpp
Revision: 89508b4b6af765d3
Author: Davis King
Date: Jun 23, 2015 (04:24:48 UTC)

Added bottom_up_cluster()

Modified
dlib/clustering.h
dlib/test/clustering.cpp
Added
dlib/clustering/bottom_up_cluster.h
dlib/clustering/bottom_up_cluster_abstract.h
Revision: b692e7298c0b372a
Author: Davis King
Date: Jun 18, 2015 (13:42:43 UTC)

Made max_cost_assignment() give an error if you incorrectly give it a non-square matrix.

Modified
tools/python/src/other.cpp
Revision: d9a39d0edd32a31e
Author: Davis King
Date: Jun 08, 2015 (14:26:56 UTC)

Fixed a minor bug in extract_highdim_face_lbp_descriptors() which was pointed out by Yan Xu. One of the face locations was mistakenly used twice while another was skipped. This change breaks backwards compatibility with the previous feature extraction output but should slightly improve accuracy of classifiers trained using these features.

Modified
dlib/image_transforms/lbp.h
Revision: 23126937a8fcf180
Author: Davis King
Date: Jun 03, 2015 (13:33:55 UTC)

A minor change to avoid a compiler warning

Modified
dlib/gui_widgets/widgets.cpp
Revision: 7d7177e01aedbc4d
Author: Davis King
Date: Jun 03, 2015 (03:53:43 UTC)

Improved the depth testing for the perspective_display.

Modified
dlib/gui_widgets/widgets.cpp
dlib/gui_widgets/widgets.h
Revision: 28abe009aa5d735e
Author: Davis King
Date: Jun 02, 2015 (14:06:29 UTC)

Made the camera_transform output the point's distance.

Modified
dlib/geometry/point_transforms.h
dlib/geometry/point_transforms_abstract.h
Revision: ebb86f164b019b01
Author: Davis King
Date: Jun 02, 2015 (13:47:46 UTC)

fleshed out this example with comments

Modified
examples/mpc_ex.cpp
Revision: 8ccb4f0960025452
Author: Davis King
Date: Jun 02, 2015 (04:12:28 UTC)

Made the solver use an SMO type iteration in the beginning before switching to projected gradient steps.

Modified
dlib/control/mpc.h
Revision: c3dc175bb53d89ab
Author: Fabio Perez
Date: May 30, 2015 (19:00:36 UTC)

Revise help message

Modified
examples/train_object_detector.cpp
Revision: 3235c08650b3b29e
Author: Davis King
Date: May 30, 2015 (15:04:50 UTC)

Added initial version of model predictive control example program.

Modified
examples/CMakeLists.txt
Added
examples/mpc_ex.cpp
Revision: 48f7630ad62694f8
Author: Davis King
Date: May 30, 2015 (15:03:06 UTC)

Fixed compile time bug and also made it so you can set all the targets at once.

Modified
dlib/control/mpc.h
dlib/control/mpc_abstract.h
Revision: 8689a8d7332eb19f
Author: Davis King
Date: May 30, 2015 (03:05:11 UTC)

Made cmake check which version of python is currently in the user's path and try to link against that one rather than whatever might be installed system wide.

Modified
dlib/add_python_module
Revision: 90665d94d4161f65
Author: Davis King
Date: May 29, 2015 (14:00:42 UTC)

Cleaned up this code, filled out spec, added asserts.

Modified
dlib/control/mpc.h
dlib/control/mpc_abstract.h
Revision: ce6f655678a8c3a1
Author: Davis King
Date: May 27, 2015 (14:04:04 UTC)

more cleanup of the spec

Modified
dlib/control/mpc.h
dlib/control/mpc_abstract.h
Revision: 7ae267ba9c239473
Author: Davis King
Date: May 27, 2015 (13:38:39 UTC)

Added tests for the MPC tool

Modified
dlib/control/mpc.h
dlib/test/CMakeLists.txt
dlib/test/makefile
Added
dlib/test/mpc.cpp
Revision: f1b5644487908634
Author: Davis King
Date: May 27, 2015 (04:10:29 UTC)

Added initial version of linear mpc

Modified
dlib/control.h
Added
dlib/control/mpc.h
dlib/control/mpc_abstract.h
Revision: f7d8ab94f249d249
Author: Davis King
Date: May 25, 2015 (10:43:04 UTC)

Added messages saying how to install Boost on UNIX systems if it isn't installed already.

Modified
dlib/add_python_module
Revision: c8611bf0f879f809
Author: Davis King
Date: May 25, 2015 (10:32:37 UTC)

minor change to avoid compiler warning

Modified
tools/python/src/shape_predictor.cpp
Revision: 7d215ec3a772e652
Author: Davis King
Date: May 25, 2015 (09:39:53 UTC)

Fixed a bug where the last column of data in a file wasn't loaded on some OS X machines when load_libsvm_formatted_data() was called.

Modified
dlib/data_io/libsvm_io.h
Revision: 47aa9d3725c19df1
Author: Patrick Snape
Date: May 20, 2015 (13:25:28 UTC)

Add example of python correlation tracker This replicates the c++ example.

Added
python_examples/correlation_tracker.py
Revision: c582796a37c8b302
Author: Patrick Snape
Date: May 20, 2015 (13:24:42 UTC)

Add overlay overload for drectangle This is useful for visualizing the tracking results.

Modified
tools/python/src/gui.cpp
Revision: 1e01940b9d1b090d
Author: Patrick Snape
Date: May 20, 2015 (12:52:29 UTC)

Update docs on corr tracker, return side lobe Added the missing documentation for the correlation tracker. Didn't realise that the tracker returned the side lobe ratio, so fixed the API to return it properly.

Modified
tools/python/src/correlation_tracker.cpp
Revision: 608620bacb43072a
Author: Patrick Snape
Date: May 20, 2015 (12:29:14 UTC)

Add an API for the correlation tracker This aids an API for the correlation based tracker that Davis recently added to Dlib. I've made sure to allow overrides for passing normal rectangles rather than drectangles (which isn't currently supported in the Dlib C++ API). This is mostly because I imagine people might initialize the tracking using something like a bounding box from a detector (e.g. load_frontal_face_detector).

Modified
tools/python/CMakeLists.txt
tools/python/src/dlib.cpp
Added
tools/python/src/correlation_tracker.cpp
Revision: 31cc62914027fc76
Author: Patrick Snape
Date: May 20, 2015 (11:46:01 UTC)

Preparing for correlation tracker - add drectangle The correlation tracker deals with the drectangle (double rectangle) class which currently isn't wrapped. Therefore, I add the drectangle class and refactor rectangles into their own file. I also added a load of methods on rectangle that might be useful such as intersection/contains/area etc.

Modified
tools/python/CMakeLists.txt
tools/python/src/dlib.cpp
tools/python/src/object_detection.cpp
Added
tools/python/src/rectangles.cpp
Revision: d637958fc4e177aa
Author: Patrick Snape
Date: May 20, 2015 (10:37:33 UTC)

Incorrect IFDEF name for shape predictor The word detector didn't make much sense!

Modified
tools/python/src/shape_predictor.h
Revision: baa8393d923f263f
Author: Davis King
Date: May 05, 2015 (14:01:52 UTC)

Added a max iterations option to the sequence labeling and segmentation learning tools.

Modified
dlib/svm/structural_sequence_labeling_trainer.h
dlib/svm/structural_sequence_labeling_trainer_abstract.h
dlib/svm/structural_sequence_segmentation_trainer.h
dlib/svm/structural_sequence_segmentation_trainer_abstract.h
Revision: cd3a20837ae2ea18
Author: Davis King
Date: May 05, 2015 (13:54:04 UTC)

Added a max iterations option to the svm_multiclass_linear_trainer.

Modified
dlib/svm/svm_multiclass_linear_trainer.h
dlib/svm/svm_multiclass_linear_trainer_abstract.h
Revision: c7b9646c27fd7922
Author: Davis King
Date: May 05, 2015 (13:46:56 UTC)

Added an optional hard limit on the number of iterations in the structural SVM solver.

Modified
dlib/svm/structural_svm_distributed.h
dlib/svm/structural_svm_distributed_abstract.h
dlib/svm/structural_svm_problem.h
dlib/svm/structural_svm_problem_abstract.h
Revision: 29fc1bf2291b0cfd
Author: Davis King
Date: May 05, 2015 (04:15:12 UTC)

fixed typo in assert message

Modified
dlib/optimization/optimization_solve_qp_using_smo.h
Revision: 381955c89c121b5d
Author: Davis King
Date: May 03, 2015 (10:30:18 UTC)

Added checks to avoid redefining #defines that already exist.

Modified
dlib/simd/simd_check.h
Revision: 019711d780a4e9c8
Author: Davis King
Date: Apr 30, 2015 (04:25:08 UTC)

Fixed a bug in the eigenvalue_decomposition which could occur when a symmetric matrix was used along with the LAPACK bindings.

Modified
dlib/matrix/matrix_eigenvalue.h
dlib/test/matrix_eig.cpp
Revision: c8eea577dc04bd32
Author: Davis King
Date: Apr 28, 2015 (14:31:05 UTC)

Filled out spec for the reinforcement learning stuff.

Modified
dlib/control/approximate_linear_models.h
dlib/control/approximate_linear_models_abstract.h
dlib/control/lspi.h
dlib/control/lspi_abstract.h
Revision: fbee9c63212360f0
Author: Davis King
Date: Apr 22, 2015 (04:01:39 UTC)

Made the perspective display resort the points with the proper z order whenever you release the mouse button or add more points.

Modified
dlib/gui_widgets/widgets.cpp
dlib/gui_widgets/widgets.h
Revision: bc7f2219b8bdca09
Author: Davis King
Date: Apr 22, 2015 (03:40:06 UTC)

Added a convenient overload of translate_point.

Modified
dlib/geometry/point_transforms.h
dlib/geometry/point_transforms_abstract.h
Revision: 552e61547c7a0630
Author: Davis King
Date: Apr 20, 2015 (03:58:35 UTC)

Added an implementation of the least-squares policy iteration algorithm.

Modified
dlib/test/CMakeLists.txt
dlib/test/makefile
Added
dlib/control.h
dlib/control/approximate_linear_models.h
dlib/control/approximate_linear_models_abstract.h
dlib/control/lspi.h
dlib/control/lspi_abstract.h
dlib/test/lspi.cpp
Revision: 5ba4d41d793aa3a3
Author: Davis King
Date: Apr 13, 2015 (-01:52:45 UTC)

Improved assert error message in cv_image's constructor.

Modified
dlib/opencv/cv_image.h
Revision: 83159841f7a629a7
Author: Aziz Baibabaev
Date: Apr 09, 2015 (17:17:13 UTC)

Fix dlib tests for c++11

c++11 std::mutex clashes with dlib::mutex when:

using namespace std;
using namespace dlib;

Modified
dlib/test/pipe.cpp
dlib/test/read_write_mutex.cpp
dlib/test/timer.cpp
Revision: aa556db473d3c422
Author: Davis King
Date: Apr 08, 2015 (00:14:44 UTC)

Added missing scope qualifiers to assert statement code so that calls to these macros compile when invoked outside dlib namespace.

Modified
dlib/assert.h
Revision: a266528d481e5917
Author: Davis King
Date: Apr 06, 2015 (13:47:18 UTC)

Merged changes and modified them slightly. In particular, the class already has a timeout parameter, so the connect() call should use that rather than adding another.

Modified
dlib/http_client/http_client.cpp
dlib/http_client/http_client.h
Revision: 13ec362aecc71e4f
Author: Suresh Namla
Date: Apr 06, 2015 (20:35:07 UTC)

Dlib::http_client - Changes for configured Socket Connection Initialization Timeout

Modified
dlib/http_client/http_client.cpp
dlib/http_client/http_client.h
Revision: 716de365a36a6d86
Author: Davis King
Date: Apr 04, 2015 (09:45:09 UTC)

Made the perspective widgets draw lines first.

Modified
dlib/gui_widgets/widgets.cpp
Revision: e87852042fdd4540
Author: Davis King
Date: Apr 04, 2015 (09:41:44 UTC)

Added another add_overlay() overload to perspective_window and also fixed a rendering problem in perspective_display that appeared when drawing lines on displays that weren't positioned at the upper left corner of the entire window.

Modified
dlib/gui_widgets/widgets.cpp
dlib/gui_widgets/widgets.h
dlib/gui_widgets/widgets_abstract.h
Revision: 2c31b968267cd882
Author: Davis King
Date: Apr 03, 2015 (09:20:09 UTC)

The shape_predictor and shape_predictor_trainer had a non-optimal behavior when used with objects that have non-square bounding boxes. This has been fixed but will cause models that were trained with the previous version of dlib to not work as accurately if they used non-square boxes. So you might have to retrain your models when updating dlib.

Modified
dlib/image_processing/shape_predictor.h
Revision: 12ca999d69b27468
Author: Davis King
Date: Mar 29, 2015 (12:49:00 UTC)

updated README

Modified
tools/imglab/README.txt
Revision: b98432b6dc6b2a14
Author: Davis King
Date: Mar 29, 2015 (12:47:37 UTC)

added comments about using imglab

Modified
examples/train_shape_predictor_ex.cpp
Revision: 60eafa957cbff58a
Author: Davis King
Date: Mar 29, 2015 (12:44:31 UTC)

updated version number and about docs

Modified
tools/imglab/src/main.cpp
tools/imglab/src/metadata_editor.cpp
Revision: b633df7b8f79fd5f
Author: Davis King
Date: Mar 29, 2015 (12:41:25 UTC)

Now you can move overlay rectangles and their parts around on the image_display by holding shift and right clicking and dragging.

Modified
dlib/gui_widgets/widgets.cpp
dlib/gui_widgets/widgets.h
dlib/gui_widgets/widgets_abstract.h
Revision: a6516a86112c8efe
Author: Davis King
Date: Mar 29, 2015 (12:35:23 UTC)

clarified documentation

Modified
tools/imglab/src/main.cpp
Revision: ce1221e6417e5619
Author: Davis King
Date: Mar 28, 2015 (19:16:54 UTC)

Added default upsampling amount to detector.run(). Also moved the new example code into face_detector.py and added some comments.

Modified
python_examples/face_detector.py
tools/python/src/object_detection.cpp
Deleted
python_examples/face_detector_scores_idx.py
Revision: 700bc3cccb68ba85
Author: Jack Culpepper
Date: Mar 12, 2015 (-06:17:40 UTC)

simplify

Modified
tools/python/src/simple_object_detector_py.h
Revision: fc2389fe5b4efc79
Author: Jack Culpepper
Date: Mar 12, 2015 (08:10:56 UTC)

repair old interface

Modified
tools/python/src/object_detection.cpp
tools/python/src/simple_object_detector_py.h
Revision: 48e7d168583239b2
Author: Jack Culpepper
Date: Mar 12, 2015 (07:48:21 UTC)

run on telling example

Added
python_examples/face_detector_scores_idx.py
Revision: 3d26e92fa1c4b4a5
Author: Jack Culpepper
Date: Mar 12, 2015 (07:39:42 UTC)

re-arrange, use vector<double> to facilitate pass back to python

Modified
tools/python/src/object_detection.cpp
tools/python/src/simple_object_detector_py.h
Revision: baf7130795b73f77
Author: Jack Culpepper
Date: Mar 11, 2015 (16:23:19 UTC)

add ability to return detection confidences and weight index to python

Modified
tools/python/src/object_detection.cpp
tools/python/src/simple_object_detector_py.h
Revision: ccae0e78a834af94
Author: Davis King
Date: Mar 25, 2015 (14:00:40 UTC)

Fixed the get_best_hough_point() function so that it works on generic images.

Modified
dlib/image_transforms/hough_transform.h
Revision: a112c64db55a0ee2
Author: Davis King
Date: Mar 25, 2015 (13:45:12 UTC)

Renamed the lambda variable since it clashes with a python keyword.

Modified
tools/python/src/shape_predictor.cpp
tools/python/src/shape_predictor.h
Revision: 61f97f083b2c1c83
Author: Davis King
Date: Mar 24, 2015 (13:36:07 UTC)

Fixed some bug in the point rotation code and added more unit tests.

Modified
dlib/geometry/point_transforms.h
dlib/test/geometry.cpp
Revision: d22008e6c8621fc8
Author: Davis King
Date: Mar 24, 2015 (13:28:07 UTC)

Minor change to avoid compiler warning

Modified
dlib/gui_widgets/widgets.cpp
Revision: 45e75796cde9d974
Author: Davis King
Date: Mar 24, 2015 (03:40:50 UTC)

Added the apt-get statement to install libx11-dev

Modified
dlib/CMakeLists.txt
Revision: 21a603e9baeb1349
Author: Davis King
Date: Mar 23, 2015 (12:30:24 UTC)

Changed how we #include and compile our own copy of libjpeg. This is to make the build more robust against name conflicts from other libraries that also statically compile libjpeg or stick incompatible versions of libjpeg's header files into folders in the include search path.

Modified
dlib/CMakeLists.txt
dlib/external/libjpeg/jmorecfg.h
dlib/image_loader/jpeg_loader.cpp
dlib/image_saver/save_jpeg.cpp
Revision: fdb49393d88b348f
Author: Davis King
Date: Mar 23, 2015 (02:38:29 UTC)

Added an optional scale output to the camera_transform.

Modified
dlib/geometry/point_transforms.h
dlib/geometry/point_transforms_abstract.h
Revision: 692528915020cf73
Author: Davis King
Date: Mar 22, 2015 (15:33:17 UTC)

cleaned up examples

Modified
examples/3d_point_cloud_ex.cpp
Revision: 3e3cd44c63363ae1
Author: Davis King
Date: Mar 22, 2015 (15:22:07 UTC)

Added an example program for the new perspective_window object.

Modified
examples/CMakeLists.txt
Added
examples/3d_point_cloud_ex.cpp
Revision: 5ce030707417759e
Author: Davis King
Date: Mar 22, 2015 (14:45:08 UTC)

Replaced the raw_input() calls with a call into dlib since raw_input() isn't available in python3.

Modified
python_examples/face_detector.py
python_examples/face_landmark_detection.py
python_examples/train_object_detector.py
python_examples/train_shape_predictor.py
tools/python/src/other.cpp
Revision: c201be2569e43188
Author: Davis King
Date: Mar 22, 2015 (14:30:41 UTC)

Forgot to make the default constructor for perspective_window make the window show itself.

Modified
dlib/gui_widgets/widgets.h
Revision: c9724176a7a2c6ac
Author: Davis King
Date: Mar 22, 2015 (14:24:07 UTC)

Made the jet and heat colormaps more accessible to other routines.

Modified
dlib/image_transforms/colormaps.h
dlib/image_transforms/colormaps_abstract.h
Revision: 8c0660060a599d6a
Author: Davis King
Date: Mar 22, 2015 (12:43:42 UTC)

Added the perspective_display and perspective_window GUI tools.

Modified
dlib/gui_widgets/widgets.cpp
dlib/gui_widgets/widgets.h
dlib/gui_widgets/widgets_abstract.h
Revision: a000e05ea8e925ed
Author: Davis King
Date: Mar 22, 2015 (12:42:29 UTC)

fixed typo in comment

Modified
dlib/gui_widgets/base_widgets_abstract.h
Revision: b41b78336fc6d51f
Author: Davis King
Date: Mar 21, 2015 (13:55:08 UTC)

Fixed fov parameter range for camera_transform.

Modified
dlib/geometry/point_transforms.h
dlib/geometry/point_transforms_abstract.h
Revision: 1d4a3dc5b0c786fc
Author: Davis King
Date: Mar 21, 2015 (13:24:14 UTC)

Made camera_transform default constructable.

Modified
dlib/geometry/point_transforms.h
dlib/geometry/point_transforms_abstract.h
Revision: 8fdc45286ab6b539
Author: Davis King
Date: Mar 21, 2015 (13:23:35 UTC)

fixed typo in comment

Modified
dlib/gui_widgets/drawable.h
Revision: 6e731f5f4a901c73
Author: Davis King
Date: Mar 21, 2015 (11:23:24 UTC)

Added the camera_transform object.

Modified
dlib/geometry/point_transforms.h
dlib/geometry/point_transforms_abstract.h
Revision: a178bfe650d144c6
Author: Davis King
Date: Mar 21, 2015 (04:45:17 UTC)

Added get_best_hough_point() to the hough_transform object.

Modified
dlib/image_transforms/hough_transform.h
dlib/image_transforms/hough_transform_abstract.h
Revision: d83295406545ded1
Author: Davis King
Date: Mar 21, 2015 (03:59:41 UTC)

Made it so you can multiply 2d and 3d point transforms together.

Modified
dlib/geometry/point_transforms.h
dlib/geometry/point_transforms_abstract.h
dlib/test/geometry.cpp
Revision: 37999c2b39e1f75c
Author: Davis King
Date: Mar 20, 2015 (15:53:57 UTC)

Added draw_solid_circle()

Modified
dlib/image_transforms/draw.h
dlib/image_transforms/draw_abstract.h
Revision: 1ec014deedce8576
Author: Davis King
Date: Mar 09, 2015 (04:01:13 UTC)

Added a 3d version of point_transform_affine and also some functions for making 3d rotations.

Modified
dlib/geometry/point_transforms.h
dlib/geometry/point_transforms_abstract.h
dlib/test/geometry.cpp
Revision: f9e3203128163ddf
Author: Davis King
Date: Mar 07, 2015 (09:14:47 UTC)

Added notes about installing skimage.

Modified
python_examples/face_detector.py
python_examples/face_landmark_detection.py
python_examples/find_candidate_object_locations.py
python_examples/train_object_detector.py
python_examples/train_shape_predictor.py
Revision: edac7bff8b92b323
Author: Davis King
Date: Mar 07, 2015 (09:05:42 UTC)

Added instructions for compiling boost-python on windows.

Modified
dlib/add_python_module
Revision: 31627ee88c3c588e
Author: Davis King
Date: Mar 07, 2015 (08:29:23 UTC)

Made the PYTHON3 cmake switch a proper cmake option.

Modified
dlib/add_python_module
tools/python/CMakeLists.txt
Revision: c799f5ee41e99e38
Author: Davis King
Date: Mar 07, 2015 (08:12:39 UTC)

Made the search for boost-python a little more robust

Modified
dlib/add_python_module
Revision: 039ec4bbbfa57f4c
Author: Davis King
Date: Mar 03, 2015 (11:54:53 UTC)

Fixed a bug which prevented add_image_rotations() from compiling.

Modified
dlib/image_transforms/interpolation.h
Revision: ebececc00c39b5fd
Author: Davis King
Date: Mar 02, 2015 (12:49:50 UTC)

A minor change to avoid errors from some compilers.

Modified
dlib/svm/kkmeans.h
Revision: 4d5f3df18274d9fc
Author: Davis King
Date: Feb 28, 2015 (09:34:50 UTC)

Updated spec to reference the paper describing this solver.

Modified
dlib/svm/structural_svm_object_detection_problem_abstract.h
Revision: 4c24879b61023fc4
Author: Davis King
Date: Feb 28, 2015 (09:21:16 UTC)

Added unit tests for extract_image_chips()

Modified
dlib/test/image.cpp
Revision: 2eac09505b20abb3
Author: Davis King
Date: Feb 28, 2015 (08:46:58 UTC)

Changed extract_image_chips() so that it doesn't build image pyramids larger than necessary when pulling out chips.

Modified
dlib/image_transforms/interpolation.h
Revision: 8846c8bb77350e44
Author: Davis King
Date: Feb 28, 2015 (07:52:33 UTC)

Added a typedef for vector<double,2> called dpoint.

Modified
dlib/geometry/vector.h
dlib/geometry/vector_abstract.h
Revision: 704e4491c421cd7a
Author: nate.crosswhite
Date: Feb 26, 2015 (08:56:07 UTC)

Locate ATLAS on RHEL/CentOS 7

Modified
dlib/cmake_find_blas.txt
Revision: 819b72adec82b802
Author: Davis King
Date: Feb 27, 2015 (13:08:04 UTC)

Made it so you can compose point transform objects via operator *.

Modified
dlib/geometry/point_transforms.h
dlib/geometry/point_transforms_abstract.h
dlib/test/geometry.cpp
Revision: 5475b4a2d2b1bd8b
Author: Davis King
Date: Feb 26, 2015 (16:16:00 UTC)

Fixed uninitialized variable in the code I just committed

Modified
dlib/image_transforms/fhog.h
Revision: 6e666d21facf06ff
Author: Davis King
Date: Feb 26, 2015 (13:32:25 UTC)

Optimized extract_fhog_features() for the case where cell_size==1. This makes it about 4x faster in that case.

Modified
dlib/image_transforms/fhog.h
Revision: 1b3d7ee19ff947a6
Author: Davis King
Date: Feb 25, 2015 (02:59:58 UTC)

clarified thread safety

Modified
dlib/sockstreambuf/sockstreambuf_abstract.h
Revision: c6452495d7fb0065
Author: Davis King
Date: Feb 25, 2015 (02:52:35 UTC)

Added set_all_logging_headers()

Modified
dlib/logger/logger_kernel_1.cpp
dlib/logger/logger_kernel_1.h
dlib/logger/logger_kernel_abstract.h
Revision: 107b5bad79f2c89e
Author: Davis King
Date: Feb 21, 2015 (14:25:12 UTC)

Made the point up/down mapping for pyramid_down<2> and pyramid_down<3> a little bit more accurate.

Modified
dlib/image_transforms/image_pyramid.h
dlib/test/pyramid_down.cpp
Revision: 08372181e08c0727
Author: Davis King
Date: Feb 18, 2015 (02:55:53 UTC)

Made sub_image() a little more robust with regards to object lifetime and const correctness.

Modified
dlib/image_transforms/interpolation.h
dlib/image_transforms/interpolation_abstract.h
Revision: 9183fbd6812e9966
Author: Davis King
Date: Feb 16, 2015 (12:16:39 UTC)

Refined the definition of the drectangle a little. In particular, now it behaves more like the rectangle in terms of how it measures width and height.

Modified
dlib/geometry/drectangle.h
dlib/geometry/drectangle_abstract.h
Revision: 4b81ac375c136885
Author: Davis King
Date: Feb 16, 2015 (12:14:34 UTC)

Made cmake script work a little better in projects that involve a lot of subdirectories and create a lot of executables.

Modified
dlib/cmake
Revision: cc65a655109d0377
Author: Davis King
Date: Feb 15, 2015 (16:56:44 UTC)

Fixed typo in spec

Modified
dlib/image_transforms/interpolation_abstract.h
Revision: 05e8957a74d1bed6
Author: Davis King
Date: Feb 15, 2015 (16:46:49 UTC)

Added another test

Modified
dlib/test/geometry.cpp
Revision: b0fecc9097206968
Author: Davis King
Date: Feb 15, 2015 (03:02:04 UTC)

Minor change to avoid triggering an assert.

Modified
dlib/image_processing/correlation_tracker.h
Revision: c37d9becb489c5db
Author: Davis King
Date: Feb 14, 2015 (14:11:09 UTC)

Refined drectangle a little.

Modified
dlib/geometry/drectangle.h
dlib/geometry/drectangle_abstract.h
dlib/test/geometry.cpp
Revision: 5a51a860aa7294c3
Author: Davis King
Date: Feb 14, 2015 (13:12:50 UTC)

Fixed warning in gcc

Modified
dlib/logger/logger_config_file.cpp
Revision: 94407a69a2f1ae59
Author: Davis King
Date: Feb 14, 2015 (13:03:44 UTC)

Made the mapping from rectangle -> drectangle -> rectangle invertible.

Modified
dlib/geometry/drectangle.h
dlib/geometry/drectangle_abstract.h
Revision: e2b7a71700451724
Author: Davis King
Date: Feb 12, 2015 (02:30:28 UTC)

Made rectangle implicitly convertible to a chip_details.

Modified
dlib/image_transforms/interpolation.h
dlib/image_transforms/interpolation_abstract.h
Revision: 011d68915e512b70
Author: Davis King
Date: Feb 11, 2015 (13:42:53 UTC)

Fixed sub_image() so it works properly with nested sub-images.

Modified
dlib/image_transforms/interpolation.h
Revision: ecbf85e1acae83d4
Author: Davis King
Date: Feb 11, 2015 (13:34:14 UTC)

Added sub_image() and sub_image_proxy.

Modified
dlib/image_transforms/interpolation.h
dlib/image_transforms/interpolation_abstract.h
Revision: 5788b63006f1e430
Author: Davis King
Date: Feb 11, 2015 (02:55:42 UTC)

Added spectral_cluster() example

Modified
examples/kkmeans_ex.cpp
Revision: 31b1af7efde6eb22
Author: Davis King
Date: Feb 11, 2015 (02:50:27 UTC)

Added spectral_cluster()

Modified
dlib/clustering.h
Added
dlib/clustering/spectral_cluster.h
dlib/clustering/spectral_cluster_abstract.h
Revision: f2dded2d03bc87a2
Author: Davis King
Date: Feb 14, 2015 (03:07:32 UTC)

Added an overload of configure_loggers_from_file() that can read directly from a config_reader.

Modified
dlib/logger/logger_config_file.cpp
dlib/logger/logger_config_file.h
Revision: 7f39c7e6405d8ec2
Author: Davis King
Date: Feb 14, 2015 (02:52:53 UTC)

Added compile time assert checks on the type given to the kernels.

Modified
dlib/svm/kernel.h
Revision: 40bc46728501eda9
Author: Davis King
Date: Feb 07, 2015 (04:33:19 UTC)

Changed the cmake code for finding libjpeg and libpng slightly to avoid a cmake error on some platforms when one of these libraries can't be found.

Modified
dlib/CMakeLists.txt
Revision: 9ae9621b8e097055
Author: Davis King
Date: Feb 03, 2015 (12:58:22 UTC)

Made libjpeg always use C linking so there are not incompatibilities with other libjpeg header files.

Modified
dlib/external/libjpeg/jmorecfg.h
Revision: 202bb57831145dcd
Author: Davis King
Date: Feb 03, 2015 (10:33:11 UTC)

Added comments

Modified
examples/video_tracking_ex.cpp
Revision: fdbc041e0d49481d
Author: Davis King
Date: Feb 03, 2015 (09:26:16 UTC)

Fixed compiler warnings

Modified
dlib/image_processing/correlation_tracker.h
Revision: 58a2ad7823e7c6c0
Author: Davis King
Date: Feb 03, 2015 (09:01:37 UTC)

Added an example for the correlation_tracker

Modified
examples/CMakeLists.txt
Added
examples/video_frames/frame_000100.jpg
examples/video_frames/frame_000101.jpg
examples/video_frames/frame_000102.jpg
examples/video_frames/frame_000103.jpg
examples/video_frames/frame_000104.jpg
examples/video_frames/frame_000105.jpg
examples/video_frames/frame_000106.jpg
examples/video_frames/frame_000107.jpg
examples/video_frames/frame_000108.jpg
examples/video_frames/frame_000109.jpg
examples/video_frames/frame_000110.jpg
examples/video_frames/frame_000111.jpg
examples/video_frames/frame_000112.jpg
examples/video_frames/frame_000113.jpg
examples/video_frames/frame_000114.jpg
examples/video_frames/frame_000115.jpg
examples/video_frames/frame_000116.jpg
examples/video_frames/frame_000117.jpg
examples/video_frames/frame_000118.jpg
examples/video_frames/frame_000119.jpg
examples/video_frames/frame_000120.jpg
examples/video_frames/frame_000121.jpg
examples/video_frames/frame_000122.jpg
examples/video_frames/frame_000123.jpg
examples/video_frames/frame_000124.jpg
examples/video_frames/frame_000125.jpg
examples/video_frames/frame_000126.jpg
examples/video_frames/frame_000127.jpg
examples/video_frames/frame_000128.jpg
examples/video_frames/frame_000129.jpg
examples/video_frames/frame_000130.jpg
examples/video_frames/frame_000131.jpg
examples/video_frames/frame_000132.jpg
examples/video_frames/frame_000133.jpg
examples/video_frames/frame_000134.jpg
examples/video_frames/frame_000135.jpg
examples/video_frames/frame_000136.jpg
examples/video_frames/frame_000137.jpg
examples/video_frames/frame_000138.jpg
examples/video_frames/frame_000139.jpg
examples/video_frames/frame_000140.jpg
examples/video_frames/frame_000141.jpg
examples/video_frames/frame_000142.jpg
examples/video_frames/frame_000143.jpg
examples/video_frames/frame_000144.jpg
examples/video_frames/frame_000145.jpg
examples/video_frames/frame_000146.jpg
examples/video_frames/frame_000147.jpg
examples/video_frames/frame_000148.jpg
examples/video_frames/frame_000149.jpg
examples/video_frames/frame_000150.jpg
examples/video_frames/frame_000151.jpg
examples/video_frames/frame_000152.jpg
examples/video_frames/frame_000153.jpg
examples/video_frames/frame_000154.jpg
examples/video_frames/frame_000155.jpg
examples/video_frames/frame_000156.jpg
examples/video_frames/frame_000157.jpg
examples/video_frames/frame_000158.jpg
examples/video_frames/frame_000159.jpg
examples/video_frames/frame_000160.jpg
examples/video_frames/frame_000161.jpg
examples/video_frames/frame_000162.jpg
examples/video_frames/frame_000163.jpg
examples/video_frames/frame_000164.jpg
examples/video_frames/frame_000165.jpg
examples/video_frames/frame_000166.jpg
examples/video_frames/frame_000167.jpg
examples/video_frames/frame_000168.jpg
examples/video_frames/frame_000169.jpg
examples/video_frames/frame_000170.jpg
examples/video_frames/frame_000171.jpg
examples/video_frames/frame_000172.jpg
examples/video_frames/frame_000173.jpg
examples/video_frames/frame_000174.jpg
examples/video_frames/frame_000175.jpg
examples/video_frames/frame_000176.jpg
examples/video_frames/frame_000177.jpg
examples/video_frames/frame_000178.jpg
examples/video_frames/frame_000179.jpg
examples/video_frames/frame_000180.jpg
examples/video_frames/frame_000181.jpg
examples/video_frames/frame_000182.jpg
examples/video_frames/frame_000183.jpg
examples/video_frames/frame_000184.jpg
examples/video_frames/frame_000185.jpg
examples/video_frames/frame_000186.jpg
examples/video_frames/frame_000187.jpg
examples/video_frames/frame_000188.jpg
examples/video_frames/frame_000189.jpg
examples/video_frames/frame_000190.jpg
examples/video_frames/frame_000191.jpg
examples/video_frames/frame_000192.jpg
examples/video_frames/frame_000193.jpg
examples/video_frames/frame_000194.jpg
examples/video_frames/frame_000195.jpg
examples/video_frames/frame_000196.jpg
examples/video_frames/frame_000197.jpg
examples/video_frames/frame_000198.jpg
examples/video_frames/frame_000199.jpg
examples/video_frames/frame_000200.jpg
examples/video_frames/frame_000201.jpg
examples/video_frames/frame_000202.jpg
examples/video_frames/frame_000203.jpg
examples/video_frames/frame_000204.jpg
examples/video_frames/frame_000205.jpg
examples/video_frames/frame_000206.jpg
examples/video_frames/frame_000207.jpg
examples/video_frames/frame_000208.jpg
examples/video_frames/frame_000209.jpg
examples/video_frames/frame_000210.jpg
examples/video_frames/frame_000211.jpg
examples/video_frames/frame_000212.jpg
examples/video_frames/frame_000213.jpg
examples/video_frames/frame_000214.jpg
examples/video_frames/frame_000215.jpg
examples/video_frames/frame_000216.jpg
examples/video_frames/frame_000217.jpg
examples/video_frames/frame_000218.jpg
examples/video_frames/frame_000219.jpg
examples/video_frames/frame_000220.jpg
examples/video_frames/frame_000221.jpg
examples/video_frames/frame_000222.jpg
examples/video_frames/frame_000223.jpg
examples/video_frames/frame_000224.jpg
examples/video_frames/frame_000225.jpg
examples/video_frames/frame_000226.jpg
examples/video_frames/frame_000227.jpg
examples/video_frames/frame_000228.jpg
examples/video_frames/frame_000229.jpg
examples/video_frames/frame_000230.jpg
examples/video_frames/frame_000231.jpg
examples/video_frames/frame_000232.jpg
examples/video_frames/frame_000233.jpg
examples/video_frames/frame_000234.jpg
examples/video_frames/frame_000235.jpg
examples/video_frames/frame_000236.jpg
examples/video_frames/frame_000237.jpg
examples/video_frames/frame_000238.jpg
examples/video_frames/frame_000239.jpg
examples/video_frames/frame_000240.jpg
examples/video_frames/frame_000241.jpg
examples/video_frames/frame_000242.jpg
examples/video_frames/frame_000243.jpg
examples/video_frames/frame_000244.jpg
examples/video_frames/frame_000245.jpg
examples/video_frames/frame_000246.jpg
examples/video_frames/frame_000247.jpg
examples/video_frames/frame_000248.jpg
examples/video_frames/frame_000249.jpg
examples/video_frames/frame_000250.jpg
examples/video_frames/license.txt
examples/video_tracking_ex.cpp
Revision: 10bdf4cd8e53fc81
Author: Davis King
Date: Feb 03, 2015 (09:01:10 UTC)

Added another overload of add_overlay(), this one doesn't require a pixel type and just makes the overlay red.

Modified
dlib/gui_widgets/widgets.h
dlib/gui_widgets/widgets_abstract.h
Revision: bff6848eee838c2a
Author: Davis King
Date: Feb 03, 2015 (08:38:35 UTC)

Added the correlation_tracker.

Modified
dlib/image_processing.h
Added
dlib/image_processing/correlation_tracker.h
dlib/image_processing/correlation_tracker_abstract.h
Revision: 24b43b0ba00322c2
Author: Davis King
Date: Feb 02, 2015 (16:24:01 UTC)

Added shrink_rect() and grow_rect() for drectangle objects.

Modified
dlib/geometry/drectangle.h
dlib/geometry/drectangle_abstract.h
Revision: fadea8b493aae968
Author: Davis King
Date: Feb 01, 2015 (15:12:20 UTC)

cleaned up code

Modified
dlib/matrix/matrix_la.h
Revision: b9f28dd8d1823618
Author: Davis King
Date: Feb 01, 2015 (14:59:19 UTC)

Added Gaussian windowing to max_point_interpolated().

Modified
dlib/matrix/matrix_la.h
Revision: 463c5176a76b767e
Author: Davis King
Date: Jan 31, 2015 (10:02:22 UTC)

Disabled all bindings to FFTW because FFTW isn't threadsafe.

Modified
dlib/CMakeLists.txt
dlib/matrix/matrix_fft.h
dlib/matrix/matrix_fft_abstract.h
Revision: 8129346a0b5595aa
Author: Davis King
Date: Jan 31, 2015 (09:35:30 UTC)

Made dlib's built in fft faster by tweaking a few things and adding a twiddle cache.

Modified
dlib/matrix/matrix_fft.h
Revision: 33bcefc93d074184
Author: Davis King
Date: Jan 31, 2015 (07:02:32 UTC)

Made bind() and get_column() correctly handle large unsigned 32bit integer values.

Modified
dlib/sqlite/sqlite.h
Revision: 8e1ac6b2a9ca4b7a
Author: Davis King
Date: Jan 31, 2015 (06:25:16 UTC)

Added an implicit conversion to unsigned long for extracting the checksum of crc32 objects.

Modified
dlib/crc32/crc32_kernel_1.h
dlib/crc32/crc32_kernel_abstract.h
dlib/test/crc32.cpp
Revision: 2fda21d9d4195309
Author: Davis King
Date: Jan 31, 2015 (06:20:58 UTC)

Hard coded the crc table into the crc32 object so it doesn't need to spend time in its constructor computing it.

Modified
dlib/crc32/crc32_kernel_1.h
Revision: 8e5864c5936105ad
Author: Davis King
Date: Jan 31, 2015 (05:16:27 UTC)

Added batch ingest functions for std::vector<char>

Modified
dlib/crc32/crc32_kernel_1.h
dlib/crc32/crc32_kernel_abstract.h
dlib/test/crc32.cpp
Revision: 7ca3893287049473
Author: Davis King
Date: Jan 31, 2015 (04:43:57 UTC)

Made example's CMakeLists.txt file a little more tutorial like.

Modified
examples/CMakeLists.txt
Revision: a383c3cb57053252
Author: Davis King
Date: Jan 29, 2015 (15:53:01 UTC)

added a SQLite example program

Modified
examples/sqlite_ex.cpp
Revision: 94ce5daa93735b5f
Author: Davis King
Date: Jan 29, 2015 (12:54:57 UTC)

Fixed missing const on statement::bind()

Modified
dlib/sqlite/sqlite.h
dlib/sqlite/sqlite_abstract.h
Revision: 73e2829ff8495e57
Author: Davis King
Date: Jan 29, 2015 (12:51:18 UTC)

Made the timestamper use timeGetTime() instead of GetTickCount() on windows since timeGetTime() is more accurate.

Modified
dlib/CMakeLists.txt
dlib/misc_api/misc_api_kernel_1.cpp
Revision: 8bfed4694355cf33
Author: Davis King
Date: Jan 28, 2015 (15:18:13 UTC)

Added a shutdown() method to iosockstream.

Modified
dlib/iosockstream/iosockstream.h
dlib/iosockstream/iosockstream_abstract.h
Revision: 52b82ea03be30d0d
Author: Davis King
Date: Jan 28, 2015 (15:17:03 UTC)

fixed spelling error in spec

Modified
dlib/sockets/sockets_kernel_abstract.h
Revision: 0af130d76d9d32f4
Author: Davis King
Date: Jan 28, 2015 (09:43:29 UTC)

Made logger constructor take a std::string instead of char*

Modified
dlib/logger/logger_kernel_1.cpp
dlib/logger/logger_kernel_1.h
dlib/logger/logger_kernel_abstract.h
Revision: 32dcd2a62c5cbd4c
Author: Davis King
Date: Jan 28, 2015 (09:40:00 UTC)

Fixed spelling error in comment

Modified
dlib/assert.h
Revision: 36563f1697bf03e3
Author: Davis King
Date: Jan 27, 2015 (18:40:53 UTC)

Added sqlite example. Needs comments

Modified
examples/CMakeLists.txt
Added
examples/sqlite_ex.cpp
Revision: 2d78e5637253ec7f
Author: Davis King
Date: Jan 26, 2015 (16:14:49 UTC)

Added templated versions of get_column() and bind() that inter what type to get/bind based on the type of variable passed in.

Modified
dlib/sqlite/sqlite.h
dlib/sqlite/sqlite_abstract.h
Revision: 331506f73c6acf45
Author: Davis King
Date: Jan 26, 2015 (13:02:24 UTC)

clarified spec

Modified
dlib/image_transforms/thresholding_abstract.h
Revision: d26788fdae9419a5
Author: Davis King
Date: Jan 26, 2015 (12:59:35 UTC)

Fixed spelling error

Modified
dlib/base64/base64_kernel_abstract.h
Revision: e8cd26d517a12128
Author: Davis King
Date: Jan 26, 2015 (12:58:35 UTC)

fixed spelling error in comment

Modified
examples/face_landmark_detection_ex.cpp
Revision: d117d72e9c8ac56b
Author: Davis King
Date: Jan 26, 2015 (12:51:59 UTC)

Added the drectangle object and switched a few interpolation related APIs over to use it.

Modified
dlib/geometry.h
dlib/image_transforms/image_pyramid.h
dlib/image_transforms/image_pyramid_abstract.h
dlib/image_transforms/interpolation.h
dlib/image_transforms/interpolation_abstract.h
Added
dlib/geometry/drectangle.h
dlib/geometry/drectangle_abstract.h
Revision: eaa5d163601d4b24
Author: Davis King
Date: Jan 26, 2015 (02:30:18 UTC)

Made the timing print() display which timing block number is being printed in addition to the text name.

Modified
dlib/timing.h
Revision: b81150f0368bc4ed
Author: Davis King
Date: Jan 21, 2015 (12:43:25 UTC)

Made max_point_interpolated() do interpolation for row and column vectors and also generally cleaned up the code a bit.

Modified
dlib/matrix/matrix_la.h
Revision: 99f9ffe78e1cc2c4
Author: Davis King
Date: Jan 20, 2015 (17:46:18 UTC)

fixed typo in spec

Modified
dlib/matrix/matrix_utilities_abstract.h
Revision: 504d6c5eb4579487
Author: Davis King
Date: Jan 20, 2015 (17:42:38 UTC)

Added max_point_interpolated()

Modified
dlib/matrix/matrix_la.h
dlib/matrix/matrix_utilities_abstract.h
Revision: 54a619c35f51a88f
Author: Davis King
Date: Jan 19, 2015 (16:21:37 UTC)

minor change to avoid compiler warnings

Modified
dlib/svm/structural_svm_problem.h
Revision: a482ad69a97609c6
Author: Davis King
Date: Jan 15, 2015 (16:28:14 UTC)

Added another folder to the openblas search path

Modified
dlib/cmake_find_blas.txt
Revision: 1066ca04c91f5cb5
Author: Davis King
Date: Jan 14, 2015 (15:39:05 UTC)

Fixed a bug in find_similarity_transform(). When given just two points as inputs it would sometimes produce a reflection rather than a similarity transform.

Modified
dlib/geometry/point_transforms.h
Revision: 6efc0b134d35bd56
Author: Davis King
Date: Jan 10, 2015 (07:15:19 UTC)

Added a test for compute_lda_transform()

Modified
dlib/test/statistics.cpp
Revision: 3c508b2ac1eec9d2
Author: Davis King
Date: Jan 10, 2015 (06:53:29 UTC)

Fixed compute_lda_transform() so it works properly when the class covariance matrices are singular even after performing PCA.

Modified
dlib/statistics/lda.h
Revision: 4d64e75061a966ec
Author: Davis King
Date: Jan 06, 2015 (12:54:27 UTC)

Added another reference on homography estimation

Modified
dlib/geometry/point_transforms.h
Revision: 9ec2581149a55faf
Author: Davis King
Date: Jan 05, 2015 (15:11:14 UTC)

Added some checks that the user produces PSI vectors that are the proper dimension.

Modified
dlib/svm/structural_svm_problem.h
Revision: 93fa17d9402bd500
Author: Davis King
Date: Jan 05, 2015 (12:39:37 UTC)

Fixed some grammar and added a note about the bias term.

Modified
examples/assignment_learning_ex.cpp
Revision: 37d5e039c8c6deb3
Author: Davis King
Date: Jan 05, 2015 (03:20:27 UTC)

Added the option to force the last weight to 1 to the assignment learning tools.

Modified
dlib/svm/structural_assignment_trainer.h
dlib/svm/structural_assignment_trainer_abstract.h
Revision: 61ce7bbcf296fb9b
Author: Davis King
Date: Jan 04, 2015 (04:11:34 UTC)

Fixed assign_border_pixels(img, rect) so that it correctly zeros an image when an empty rectangle is supplied. Previously, it just did nothing to the image in this case.

Modified
dlib/image_transforms/assign_image.h
Revision: e880abc08a60cfab
Author: Davis King
Date: Jan 03, 2015 (18:39:38 UTC)

A minor change to allow a wider variety of output image types to be used. In particular, this change allows complex valued images to be the output of extract_image_chips().

Modified
dlib/image_transforms/interpolation.h
Revision: db4a4d1131896f04
Author: Davis King
Date: Jan 03, 2015 (18:33:46 UTC)

clarified example

Modified
python_examples/find_candidate_object_locations.py
Revision: 858413a0f59da443
Author: Davis King
Date: Jan 03, 2015 (18:26:28 UTC)

Fixed the python doc string so that it's correct relative to the python API. Also made find_candidate_object_locations() correctly include any input boxes in the call to the C++ version of the function.

Modified
tools/python/src/object_detection.cpp
Revision: 4a9047965f6a4809
Author: Davis King
Date: Jan 03, 2015 (18:26:02 UTC)

Made this file executable

Modified
python_examples/find_candidate_object_locations.py
Revision: 23bdfdd08646c254
Author: Vinh Khuc
Date: Jan 03, 2015 (09:58:10 UTC)

Explained the difference between pykvals in the Python API and kvals in C++ code

Modified
tools/python/src/object_detection.cpp
Revision: 1090a1d94e31912e
Author: Vinh Khuc
Date: Jan 03, 2015 (-04:19:35 UTC)

Added a Python example for find_candidate_object_locations

Added
python_examples/find_candidate_object_locations.py
Revision: cb97ad1703a195ad
Author: Vinh Khuc
Date: Jan 03, 2015 (-04:11:52 UTC)

Added Python-binding for find_candidate_object_locations

Modified
tools/python/src/object_detection.cpp
Revision: 3822b7b245480f91
Author: Davis King
Date: Jan 01, 2015 (14:08:06 UTC)

Made cmake not use the installed libjpeg on apple systems because it's broken on some newer OS X installs.

Modified
dlib/CMakeLists.txt
Revision: 4df734390109d584
Author: Davis King
Date: Dec 29, 2014 (14:50:05 UTC)

Made cmake check that libpng and libjpeg actually contain the link symbols they are supposed to since, on some systems, these libraries aren't installed correctly and will cause linker errors if used.

Modified
dlib/CMakeLists.txt
Revision: bf5b1f597a923255
Author: Davis King
Date: Dec 29, 2014 (12:55:40 UTC)

Fixed a bug in extract_image_chips() and get_mapping_to_chip() that caused incorrect outputs when the requested chip stretched the image unevenly vertically or horizontally. This is because we used the best similarity transform rather than affine transform between the image and the output chip.

Modified
dlib/image_transforms/interpolation.h
Revision: 94b92234f7c58d32
Author: Davis King
Date: Dec 29, 2014 (12:26:14 UTC)

Added image_traits specializations for const types because it makes certain compiler errors you get when accidentally trying to mutate a const image a little easier to understand.

Modified
dlib/array2d/array2d_generic_image.h
dlib/matrix/matrix_generic_image.h
Revision: 213ddab795c4f58e
Author: Davis King
Date: Dec 28, 2014 (02:31:28 UTC)

cleaned up cmake file a little

Modified
dlib/CMakeLists.txt
Revision: f6b54ff326020cce
Author: Davis King
Date: Dec 27, 2014 (13:15:07 UTC)

Fixed grammar

Modified
python_examples/train_shape_predictor.py
Revision: d13e1d626c0d517b
Author: Davis King
Date: Dec 27, 2014 (10:32:29 UTC)

Merge github.com:davisking/dlib

Modified
.hgtags
dlib/CMakeLists.txt
dlib/add_python_module
dlib/cmake
dlib/image_processing/shape_predictor.h
dlib/image_processing/shape_predictor_abstract.h
dlib/image_transforms/interpolation.h
dlib/image_transforms/morphological_operations.h
dlib/image_transforms/morphological_operations_abstract.h
dlib/image_transforms/spatial_filtering.h
dlib/image_transforms/spatial_filtering_abstract.h
dlib/matlab/CMakeLists.txt
dlib/matlab/README.txt
dlib/matlab/call_matlab.h
dlib/matlab/cmake_mex_wrapper
dlib/matlab/example_mex_callback.cpp
dlib/matlab/example_mex_function.cpp
dlib/matlab/mex_wrapper.cpp
dlib/test/image.cpp
docs/.current_minor_release_number
docs/.logger_revnum
docs/docs/imaging.xml
docs/docs/index.xml
docs/docs/other.xml
docs/docs/release_notes.xml
docs/docs/term_index.xml
Revision: dbf94690e4ef2793
Author: Davis King
Date: Dec 27, 2014 (10:30:56 UTC)

Clarified a few comments and simplified the serialization code a bit. Also just cleaned up a few minor details.

Modified
python_examples/face_landmark_detection.py
python_examples/max_cost_assignment.py
python_examples/sequence_segmenter.py
python_examples/train_object_detector.py
python_examples/train_shape_predictor.py
tools/python/src/gui.cpp
tools/python/src/object_detection.cpp
tools/python/src/serialize_object_detector.h
tools/python/src/shape_predictor.cpp
tools/python/src/shape_predictor.h
tools/python/src/simple_object_detector.h
Revision: 541be4a3736e78cc
Author: Davis King
Date: Dec 27, 2014 (10:05:25 UTC)

Fixed grammar

Modified
examples/train_shape_predictor_ex.cpp
Revision: 65cee219ce80c4d6
Author: Davis King
Date: Dec 27, 2014 (09:56:22 UTC)

Fixed typo in assert I introduced a moment ago.

Modified
dlib/image_processing/shape_predictor.h
Revision: f4685974fe9a1f1a
Author: Davis King
Date: Dec 27, 2014 (09:10:59 UTC)

The nu parameter of the shape_predictor must be in the range (0,1]. I changed the spec to reflect this.

Modified
dlib/image_processing/shape_predictor.h
dlib/image_processing/shape_predictor_abstract.h
Revision: 6e05d0ec6f131bc5
Author: Patrick Snape
Date: Dec 12, 2014 (16:22:57 UTC)

Re-add the cached object detector A little bit hacky, but should be fine. Supports both fhog detectors and the "cached" simple_object_detector. Also, maintains the upscale parameter for testing

Modified
python_examples/train_object_detector.py
tools/python/src/gui.cpp
tools/python/src/object_detection.cpp
tools/python/src/simple_object_detector.h
Added
tools/python/src/serialize_object_detector.h
tools/python/src/simple_object_detector_py.h
Deleted
tools/python/src/simple_object_detector_abstract.h
Revision: ee8cb26641057469
Author: Patrick Snape
Date: Dec 11, 2014 (15:01:08 UTC)

Add facial landmark prediction examples for Python

Modified
python_examples/train_object_detector.py
Added
python_examples/face_landmark_detection.py
python_examples/train_shape_predictor.py
Revision: 33df6ab13b8b7acd
Author: Patrick Snape
Date: Dec 11, 2014 (15:00:39 UTC)

Change logic for upsampling printing

Modified
tools/python/src/simple_object_detector.h
Revision: 05b57aa0d2ebb982
Author: Patrick Snape
Date: Dec 11, 2014 (14:06:05 UTC)

Update the interface to be more Pythonic This is the biggest change so far. Now, there are two different classes of interface. One where you pass ONLY file paths, and one where you pass ONLY Python objects. The file paths are maintained to keep a matching interface with the C++ examples of dlib. So shape predicition and object detection can be trained using the dlib XML file paths and then serialize the detectors to disk. Shape prediction and object detection can also be trained using numpy arrays and in-memory objects. In this case, the predictor and detector objects are returned from the training functions. To facilitate serializing these objects, they now have a 'save' method. Tetsing follows a similar pattern, in that it can take either XML files are or in-memory objects. I also added back the concept of upsampling during testing to make amends for removing the simple_object_detector_py struct.

Modified
tools/python/src/object_detection.cpp
tools/python/src/shape_predictor.cpp
tools/python/src/shape_predictor.h
tools/python/src/simple_object_detector.h
Revision: 57bfbfec9fecb008
Author: Patrick Snape
Date: Dec 11, 2014 (12:34:20 UTC)

Add a save method to detectors and predictors Also, removed the saving of the upsample which I missed from before (since I'm not using the struct now). I understand why the upsample was being saved, but I don't necessarily agree it is particularly useful as you should really be upsampling on a case by case basis at test time.

Modified
tools/python/src/object_detection.cpp
tools/python/src/shape_predictor.cpp
tools/python/src/simple_object_detector.h
Revision: 0cdba7860659dcf8
Author: Patrick Snape
Date: Dec 11, 2014 (12:05:10 UTC)

Properly handle turning the GUI off

Modified
tools/python/CMakeLists.txt
tools/python/src/dlib.cpp
Revision: 93b1e7fb97fec59b
Author: Patrick Snape
Date: Dec 11, 2014 (11:46:01 UTC)

Refactor the GUI code out I also cleaned up a bunch of code. I'm not sure why the simple_object_detector was keeping track of the upsample amount, since it can't even be passed as an argument to the constructor. Therefore, I removed the simple_object_detector_py and the second declaration of the hog object detector. I also changed the view code to optionally take keyword args of color and added a single view of a rectangle. Finally, I added viewing of the shape parts.

Modified
tools/python/CMakeLists.txt
tools/python/src/dlib.cpp
tools/python/src/object_detection.cpp
Added
tools/python/src/gui.cpp
Revision: 64a52919a7a183fa
Author: Patrick Snape
Date: Dec 11, 2014 (10:28:14 UTC)

Add rendering of faces (lines) Can either be a list of full_object_detections or a single full_object_detection. I couldn't get the vector type to work for full_object_detection due to a template error.

Modified
tools/python/src/indexing.h
tools/python/src/object_detection.cpp
tools/python/src/vector.cpp
Revision: f5c3babf06d1e971
Author: Patrick Snape
Date: Dec 11, 2014 (09:44:50 UTC)

Sort out PEP8 issues in the examples

Modified
python_examples/LICENSE_FOR_EXAMPLE_PROGRAMS.txt
python_examples/face_detector.py
python_examples/max_cost_assignment.py
python_examples/sequence_segmenter.py
python_examples/svm_rank.py
python_examples/svm_struct.py
python_examples/train_object_detector.py
Revision: e68146c76319af32
Author: Patrick Snape
Date: Dec 10, 2014 (18:07:38 UTC)

Make shape predictor pickleable Fix typo as well

Modified
tools/python/src/shape_predictor.cpp
Revision: 2ce729aaf11290dd
Author: Patrick Snape
Date: Dec 10, 2014 (17:42:05 UTC)

Add example of testing detector using existing data

Modified
python_examples/train_object_detector.py
Revision: 45a062f903f030e0
Author: Patrick Snape
Date: Dec 10, 2014 (17:32:32 UTC)

Python3 friendly printing in examples

Modified
python_examples/face_detector.py
python_examples/max_cost_assignment.py
python_examples/sequence_segmenter.py
python_examples/svm_rank.py
python_examples/svm_struct.py
python_examples/train_object_detector.py
Revision: 079f3861760d7c2b
Author: Patrick Snape
Date: Dec 10, 2014 (17:25:20 UTC)

Add wrappers for the shape predictors This includes the full_object_detection, a new struct in the same vein as the simple_object_detector_training_options and of course, the shape predictor classes themselves. All of training, fitting and testing are wrapped.

Modified
tools/python/CMakeLists.txt
tools/python/src/dlib.cpp
Added
tools/python/src/shape_predictor.cpp
tools/python/src/shape_predictor.h
Revision: d280d310609c8a5a
Author: Patrick Snape
Date: Dec 10, 2014 (17:24:30 UTC)

Add a new conversion header This deals with converting python objects to dlib objects

Modified
tools/python/src/object_detection.cpp
Added
tools/python/src/conversion.h
Revision: 6d2c9f94e50d114a
Author: Patrick Snape
Date: Dec 10, 2014 (12:14:53 UTC)

Refactor rgb_pixel out of object detection Also, move the vectorize template into its own header to stop having to declare it again in vector.

Modified
tools/python/CMakeLists.txt
tools/python/src/dlib.cpp
tools/python/src/object_detection.cpp
tools/python/src/vector.cpp
Added
tools/python/src/image.cpp
tools/python/src/indexing.h
Revision: d8d2e2493b694a28
Author: Patrick Snape
Date: Dec 10, 2014 (10:07:14 UTC)

Add a list of points Also, change point x and y to be properties

Modified
tools/python/src/vector.cpp
Revision: 402f840b7920d63b
Author: Patrick Snape
Date: Dec 09, 2014 (20:07:21 UTC)

Wrap the dlib point for Python

Modified
tools/python/src/vector.cpp
Revision: 02cd627bd08b47ae
Author: Patrick Snape
Date: Dec 09, 2014 (18:23:09 UTC)

First attempt at adding to the boost API Exposes the test method, but takes in images and bounding boxes. Seems fairly simply to extend the API

Modified
tools/python/src/object_detection.cpp
tools/python/src/simple_object_detector.h
Revision: 4e3941b13ca859f7
Author: Davis King
Date: Dec 20, 2014 (11:21:54 UTC)

Fixed policy setting so it works on old cmakes

Modified
dlib/CMakeLists.txt
dlib/cmake
Revision: dc9225e103718e3a
Author: Davis King
Date: Dec 20, 2014 (11:01:02 UTC)

Minor change to avoid warnings from newer cmake

Modified
dlib/CMakeLists.txt
dlib/cmake
Revision: 8cf0cedb2d73bedd
Author: Davis King
Date: Dec 20, 2014 (10:44:35 UTC)

Removed quoting from path strings

Modified
dlib/add_python_module
Revision: 28dfa22b686eb936
Author: Davis King
Date: Dec 20, 2014 (04:25:49 UTC)

Fixed finding of boost python

Modified
dlib/add_python_module
Revision: 892c2e12bac54bd0
Author: Davis King
Date: Dec 19, 2014 (16:47:47 UTC)

Added license statements and also converted line endings to unix format

Modified
dlib/matlab/CMakeLists.txt
dlib/matlab/README.txt
dlib/matlab/call_matlab.h
dlib/matlab/cmake_mex_wrapper
dlib/matlab/example_mex_callback.cpp
dlib/matlab/example_mex_function.cpp
dlib/matlab/mex_wrapper.cpp
Revision: 33e9788863df7b05
Author: Davis King
Date: Dec 19, 2014 (15:18:55 UTC)

added skeleton unit test

Modified
dlib/test/image.cpp
Revision: c55b2e21bd8ce4c4
Author: Davis King
Date: Dec 19, 2014 (12:58:42 UTC)

Slightly improved skeleton output

Modified
dlib/image_transforms/morphological_operations.h
Revision: 493c28a09a654b34
Author: Davis King
Date: Dec 19, 2014 (03:02:31 UTC)

Added skeleton()

Modified
dlib/image_transforms/morphological_operations.h
dlib/image_transforms/morphological_operations_abstract.h
Revision: b91dba05a6a2fb92
Author: Davis King
Date: Dec 15, 2014 (11:13:53 UTC)

Changed extract_image_chips() slightly so that it can take non-resizable images like cv_image as input.

Modified
dlib/image_transforms/interpolation.h
Revision: 8a0b4d48155fa719
Author: Davis King
Date: Dec 11, 2014 (03:00:00 UTC)

Made gaussian_blur return a rectangle that defines which part of the image has valid outputs.

Modified
dlib/image_transforms/spatial_filtering.h
dlib/image_transforms/spatial_filtering_abstract.h
Revision: 5844dbd16459fff7
Author: Davis King
Date: Dec 14, 2014 (07:01:08 UTC)

minor cleanup

Modified
dlib/image_processing/shape_predictor.h
Revision: 382b1512a9807df4
Author: Davis King
Date: Dec 10, 2014 (12:41:59 UTC)

Fixed error in spec

Modified
dlib/image_processing/shape_predictor_abstract.h
Revision: 4bc90e1da9d9252e
Author: Davis King
Date: Dec 09, 2014 (14:53:20 UTC)

Changed code to avoid a warning

Modified
dlib/simd/simd_check.h
Revision: 1575a41686493925
Author: Davis King
Date: Dec 09, 2014 (13:13:45 UTC)

Added an example for svm_c_trainer.

Modified
examples/CMakeLists.txt
Added
examples/svm_c_ex.cpp
Revision: 28e68064cf1ddf92
Author: Davis King
Date: Dec 09, 2014 (12:40:19 UTC)

Added an example program for the new hough_transform object.

Modified
examples/CMakeLists.txt
Added
examples/hough_transform_ex.cpp
Revision: b239b4b1d9f4ad26
Author: Davis King
Date: Dec 09, 2014 (03:08:02 UTC)

Added example of accessing individual pixels

Modified
examples/image_ex.cpp
Revision: 8e1ca4cc903f4598
Author: Davis King
Date: Dec 08, 2014 (15:07:11 UTC)

Added hough transform unit tests

Modified
dlib/test/image.cpp
Revision: 5be0bbe435fd54b3
Author: Davis King
Date: Dec 08, 2014 (14:58:54 UTC)

Added hough_transform

Modified
dlib/image_transforms.h
Added
dlib/image_transforms/hough_transform.h
dlib/image_transforms/hough_transform_abstract.h
Revision: 2aeb392a2f75ee3e
Author: Davis King
Date: Dec 08, 2014 (14:57:14 UTC)

Added distance_to_line() and clip_line_to_rectangle()

Modified
dlib/geometry/rectangle.h
dlib/geometry/rectangle_abstract.h
Revision: ff887bf78fdfdadd
Author: Davis King
Date: Dec 08, 2014 (14:56:31 UTC)

Added a length_squared() member to vector.

Modified
dlib/geometry/vector.h
dlib/geometry/vector_abstract.h
Revision: 01669c92a0442ecf
Author: Davis King
Date: Dec 08, 2014 (12:37:48 UTC)

Fixed spelling error in spec

Modified
dlib/statistics/lda_abstract.h
Revision: 1691ec73fe9a8fd1
Author: Davis King
Date: Dec 08, 2014 (03:26:43 UTC)

Clarified the error message a user gets when they try to load a jpeg or png file but didn't link to the approrpiate library.

Modified
dlib/image_loader/load_image.h
Revision: 5761c33e8bb6b66e
Author: Davis King
Date: Dec 08, 2014 (03:02:42 UTC)

clarified spec

Modified
dlib/image_transforms/lbp_abstract.h
Revision: 73c237639b702ef6
Author: Davis King
Date: Dec 07, 2014 (07:11:13 UTC)

Added max cost assignment example program

Modified
examples/CMakeLists.txt
Added
examples/max_cost_assignment_ex.cpp
Revision: fa9c033275a01d57
Author: Davis King
Date: Dec 07, 2014 (06:29:44 UTC)

Merged and also clarified requires clauses.

Modified
dlib/image_transforms/interpolation.h
dlib/image_transforms/interpolation_abstract.h
Revision: 50c491ae857bef01
Author: haja
Date: Nov 19, 2014 (19:22:18 UTC)

interpolation.h: changed dlib::array<image_type> to image_array_type

Modified
dlib/image_transforms/interpolation.h
dlib/image_transforms/interpolation_abstract.h
Revision: ac71155524008f61
Author: Davis King
Date: Dec 07, 2014 (06:16:29 UTC)

Added some unit tests

Modified
dlib/test/matrix2.cpp
Revision: 2b9506e3858367b6
Author: Davis King
Date: Dec 07, 2014 (06:16:17 UTC)

Added min_point()

Modified
dlib/matrix/matrix_utilities.h
dlib/matrix/matrix_utilities_abstract.h
Revision: 2a01204e984150c6
Author: Davis King
Date: Dec 07, 2014 (06:00:11 UTC)

Added max_point()

Modified
dlib/matrix/matrix_utilities.h
dlib/matrix/matrix_utilities_abstract.h
Revision: 1c1115585cfbe059
Author: Davis King
Date: Dec 07, 2014 (05:57:12 UTC)

Added pixel_traits definitions that allow you to copy images into complex valued images using any dlib functions.

Modified
dlib/pixel.h
Revision: abaa9974e468d0c6
Author: Davis King
Date: Dec 06, 2014 (03:38:04 UTC)

more cmake changes to avoid cmake warnings

Modified
tools/htmlify/CMakeLists.txt
tools/imglab/CMakeLists.txt
tools/mltool/CMakeLists.txt
tools/python/CMakeLists.txt
Revision: 779960a188b3fad4
Author: Davis King
Date: Dec 06, 2014 (03:34:19 UTC)

Another minor cmake change to avoid warnings

Modified
examples/CMakeLists.txt
Revision: cf44f6e40ad3e20a
Author: Davis King
Date: Dec 06, 2014 (03:30:36 UTC)

Minor changes to cmake scripts to avoid warnings in new version of cmake.

Modified
dlib/CMakeLists.txt
dlib/cmake
dlib/test/CMakeLists.txt
Revision: 37a0624a2782b15f
Author: Davis King
Date: Dec 06, 2014 (03:27:12 UTC)

Made cmake better at finding OpenBLAS installs, in particular, it will now find them if you install straight from the OpenBLAS source.

Modified
dlib/cmake_find_blas.txt
Revision: 2352482f934c0ec4
Author: nate crosswhite
Date: Dec 04, 2014 (06:33:01 UTC)

Set correct include directory for fftw

Modified
dlib/CMakeLists.txt
Revision: 8e822bb63e1aabeb
Author: Davis King
Date: Nov 27, 2014 (02:27:11 UTC)

Made the compile time assert macros use static_assert if it's available.

Modified
dlib/assert.h
Revision: 4078ac7be1685a0f
Author: Davis King
Date: Nov 26, 2014 (11:28:52 UTC)

Changed python cmake scrips to have an option to compile Python 3 libraries.

Modified
dlib/add_python_module
tools/python/CMakeLists.txt
Revision: 8a2a975a67a5346d
Author: Davis King
Date: Nov 26, 2014 (11:04:51 UTC)

Changed python pickling code so it works with Python 3

Modified
dlib/python/serialize_pickle.h
Revision: 55e4467012ba630b
Author: Davis King
Date: Nov 24, 2014 (13:57:16 UTC)

Removed boost namespace to avoid name clashes with newer versions of boost.

Modified
dlib/enable_if.h
Revision: a21aea60b2d158af
Author: Davis King
Date: Nov 26, 2014 (06:18:32 UTC)

Merged in code changes from MITIE project

Modified
dlib/cmake
Added
dlib/matlab/CMakeLists.txt
dlib/matlab/README.txt
dlib/matlab/call_matlab.h
dlib/matlab/cmake_mex_wrapper
dlib/matlab/example.m
dlib/matlab/example_mex_callback.cpp
dlib/matlab/example_mex_function.cpp
dlib/matlab/mex_wrapper.cpp
Revision: 6a4ca93990528be4
Author: Davis King
Date: Nov 16, 2014 (06:28:56 UTC)

Made extract_image_chips() much faster when extracting an unscaled and unrotated chip. Also added another constructor to chip_details that takes just a rectangle.

Modified
dlib/image_transforms/interpolation.h
dlib/image_transforms/interpolation_abstract.h
Revision: 6cc9a0cb49bf73c3
Author: Davis King
Date: Nov 15, 2014 (07:10:31 UTC)

Increased min required cmake version to avoid warnings from OpenCV cmake scripts.

Modified
examples/CMakeLists.txt
Revision: be573285a078e210
Author: Davis King
Date: Nov 15, 2014 (06:39:26 UTC)

Added an example showing how to use OpenCV's frame grabber for face pose estimation.

Modified
examples/CMakeLists.txt
Added
examples/webcam_face_pose_ex.cpp
Revision: 3709f1c0f79880e3
Author: Davis King
Date: Nov 15, 2014 (04:28:48 UTC)

Merged in Patrick Snape's patch that allows the python bindings to be built without GUI support.

Modified
tools/python/src/object_detection.cpp
Revision: c766bd60efb8835f
Author: Davis King
Date: Nov 15, 2014 (04:15:36 UTC)

Fixed a compile time error that prevented auto_threshold_image() from being used.

Modified
dlib/image_transforms/thresholding.h
Revision: 9d4daeae81aada37
Author: Davis King
Date: Nov 09, 2014 (14:00:42 UTC)

Upgraded fft() and ifft() to support 2D matrices.

Modified
dlib/matrix/matrix_fft.h
dlib/matrix/matrix_fft_abstract.h
dlib/test/fft.cpp
Revision: 9ea98f4ab87b2598
Author: Davis King
Date: Nov 06, 2014 (08:49:43 UTC)

Fixed a compile time error that could happen when calling fft() for certain input types.

Modified
dlib/matrix/matrix_fft.h
Revision: dd8e950033d50263
Author: Davis King
Date: Oct 14, 2014 (01:10:50 UTC)

cleaned up cmake code slightly

Modified
dlib/add_python_module
Revision: e8dc9a5d5861d5b1
Author: Davis King
Date: Oct 14, 2014 (01:08:50 UTC)

Slightly changed cmake file to make sure the python binding is always compiled with -fPIC.

Modified
dlib/add_python_module
Revision: b4b4f4d7679ed8de
Author: Davis King
Date: May 24, 2014 (-02:06:27 UTC)

Minor change to avoid a compiler error in gcc 4.1.2.

Modified
dlib/statistics/lda.h
Revision: 1511d53c769632e2
Author: Davis King
Date: Oct 13, 2014 (12:00:47 UTC)

Defined the jpeg quality measure.

Modified
dlib/image_saver/save_jpeg.cpp
dlib/image_saver/save_jpeg_abstract.h
Revision: 8977b42671be0685
Author: Davis King
Date: Oct 12, 2014 (18:39:31 UTC)

Added cast_to() to the type_safe_union. This allows you to get the contents of a const type_safe_union.

Modified
dlib/test/type_safe_union.cpp
dlib/type_safe_union/type_safe_union_kernel.h
dlib/type_safe_union/type_safe_union_kernel_abstract.h
Revision: 6a3466ca1eba6eb3
Author: Davis King
Date: Oct 12, 2014 (11:55:33 UTC)

Renamed some variables to avoid clash with #defines in Visual Studio.

Modified
dlib/test/statistics.cpp
Revision: ea17aea5e49a65cf
Author: Davis King
Date: Oct 12, 2014 (11:08:58 UTC)

Made the OpenCV tools #include the right OpenCV headers so the user doesn't need to.

Modified
dlib/opencv/cv_image.h
dlib/opencv/cv_image_abstract.h
dlib/opencv/to_open_cv.h
dlib/opencv/to_open_cv_abstract.h
Revision: fc36e799ff2c964f
Author: Davis King
Date: Oct 12, 2014 (07:24:46 UTC)

Added a thread safety note to the shape_predictor.

Modified
dlib/image_processing/shape_predictor_abstract.h
Revision: df421944e6992649
Author: Davis King
Date: Oct 12, 2014 (06:56:11 UTC)

Made cmake's "can't find X11" error message on OS X provide a link to download XQuartz.

Modified
dlib/CMakeLists.txt
Revision: 4b0eecebc6b7bf39
Author: Davis King
Date: Oct 12, 2014 (06:49:08 UTC)

Made the optimization functions throw an error when non-finite values are supplied by the user.

Modified
dlib/optimization/optimization.h
Revision: 1bb9ec9824246356
Author: Davis King
Date: Oct 11, 2014 (06:54:01 UTC)

Fixed typo in spec

Modified
dlib/image_processing/remove_unobtainable_rectangles_abstract.h
Revision: ed6fe2f491600767
Author: Davis King
Date: Oct 10, 2014 (16:15:26 UTC)

clarified spec

Modified
dlib/image_processing/scan_fhog_pyramid_abstract.h
Revision: b1f74426d9da8940
Author: Davis King
Date: Sep 30, 2014 (18:07:32 UTC)

Minor changes to suppress compiler warnings in gcc

Modified
dlib/external/libjpeg/jccoefct.cpp
dlib/external/libjpeg/jccolor.cpp
dlib/external/libjpeg/jcmarker.cpp
dlib/external/libjpeg/jcsample.cpp
Revision: b10df52295f353d0
Author: Davis King
Date: Sep 30, 2014 (17:59:08 UTC)

Minor changes to avoid errors and warnings in visual studio.

Modified
dlib/external/libjpeg/jchuff.cpp
dlib/external/libjpeg/jcphuff.cpp
Revision: 6aa6fa274b68b7ed
Author: Davis King
Date: Sep 30, 2014 (17:52:53 UTC)

Added missing asserts

Modified
dlib/image_saver/save_jpeg.cpp
Revision: 62a48c858baed231
Author: Davis King
Date: Sep 30, 2014 (17:34:38 UTC)

Added save_jpeg()

Modified
dlib/CMakeLists.txt
dlib/all/source.cpp
dlib/image_io.h
Added
dlib/external/libjpeg/jcapimin.cpp
dlib/external/libjpeg/jcapistd.cpp
dlib/external/libjpeg/jccoefct.cpp
dlib/external/libjpeg/jccolor.cpp
dlib/external/libjpeg/jcdctmgr.cpp
dlib/external/libjpeg/jchuff.cpp
dlib/external/libjpeg/jchuff.h
dlib/external/libjpeg/jcinit.cpp
dlib/external/libjpeg/jcmainct.cpp
dlib/external/libjpeg/jcmarker.cpp
dlib/external/libjpeg/jcmaster.cpp
dlib/external/libjpeg/jcparam.cpp
dlib/external/libjpeg/jcphuff.cpp
dlib/external/libjpeg/jcprepct.cpp
dlib/external/libjpeg/jcsample.cpp
dlib/external/libjpeg/jdatadst.cpp
dlib/external/libjpeg/jfdctflt.cpp
dlib/external/libjpeg/jfdctfst.cpp
dlib/external/libjpeg/jfdctint.cpp
dlib/image_saver/save_jpeg.cpp
dlib/image_saver/save_jpeg.h
dlib/image_saver/save_jpeg_abstract.h
Revision: 3df580a9d45e177d
Author: Davis King
Date: Sep 30, 2014 (15:22:24 UTC)

Changed hostname_to_ip() to filter out 0.0.0.0 from the result set since sometimes getaddrinfo() returns that which is bad.

Modified
dlib/sockets/sockets_kernel_2.cpp
Revision: cf1fa82f08c1adc1
Author: Davis King
Date: Sep 30, 2014 (15:21:38 UTC)

Changed example to avoid tying a stream to itself since some iostream libraries have a bug that causes them to crash when you do this.

Modified
examples/sockstreambuf_ex.cpp
Revision: 7dc91f3f69c80aeb
Author: Davis King
Date: Sep 27, 2014 (05:57:28 UTC)

Added scope qualifiers to some mutex objects to avoid a name collision in newer versions of clang.

Modified
examples/parallel_for_ex.cpp
examples/threads_ex.cpp
Revision: b89ecb218999459a
Author: Davis King
Date: Sep 26, 2014 (07:57:21 UTC)

Changed CMakeLists.txt so that the find libjpeg step doesn't output confusing messages to the console.

Modified
dlib/CMakeLists.txt
Revision: 081183aba847a8d6
Author: Davis King
Date: Sep 17, 2014 (16:50:14 UTC)

Fixed spelling errors in comments.

Modified
dlib/sqlite/sqlite_abstract.h
Revision: 5788b953de234e7a
Author: Davis King
Date: Sep 17, 2014 (16:47:11 UTC)

Made DLIB_ASSERT turn into an empty {} when disabled instead of turning into nothing. This way if you have a DLIB_ASSERT inside an if statement it doesn't change anything about the code if it's disabled.

Modified
dlib/assert.h
Revision: 9d7fa4321bfcfb32
Author: Davis King
Date: Sep 17, 2014 (16:42:55 UTC)

Changed python cmake files so they always set fPIC even if the compiler isn't GCC.

Modified
dlib/add_python_module
Revision: e34d545c4042db8f
Author: Davis King
Date: Sep 17, 2014 (16:37:26 UTC)

Updated style sheet so face parts aren't all smashed together when viewed in a browser.

Modified
examples/faces/image_metadata_stylesheet.xsl
Revision: 2f3d393739ab19be
Author: Davis King
Date: Sep 17, 2014 (16:37:00 UTC)

Changed the XSLT stylesheet that is saved with an image dataset metadata file display the parts using smaller circles. It was too cluttered prior to this.

Modified
dlib/data_io/image_dataset_metadata.cpp
Revision: aff32e0b039c4221
Author: Davis King
Date: Sep 17, 2014 (15:46:23 UTC)

Minor changes to avoid compiler warnings.

Modified
dlib/image_processing/shape_predictor.h
dlib/image_transforms/draw.h
Revision: 593cf8b881dfe965
Author: Davis King
Date: Sep 14, 2014 (16:49:33 UTC)

fixed grammar

Modified
dlib/image_transforms/lbp_abstract.h
Revision: 20b25b58c985f0cd
Author: Davis King
Date: Sep 14, 2014 (16:34:45 UTC)

Renamed compute_equal_error_rate() to equal_error_rate()

Modified
dlib/statistics/lda.h
dlib/statistics/lda_abstract.h
Revision: e373ff9159756004
Author: Davis King
Date: Sep 14, 2014 (16:29:29 UTC)

fixed spelling

Modified
dlib/statistics/lda_abstract.h
Revision: b2f4b16429e8c71a
Author: Davis King
Date: Sep 14, 2014 (16:18:37 UTC)

Added the following functions:
    make_uniform_lbp_image()
    extract_histogram_descriptors()
    extract_uniform_lbp_descriptors()
    extract_highdim_face_lbp_descriptors()
    compute_lda_transform()
    compute_equal_error_rate()

Modified
dlib/image_transforms.h
dlib/statistics.h
Added
dlib/image_transforms/lbp.h
dlib/image_transforms/lbp_abstract.h
dlib/statistics/lda.h
dlib/statistics/lda_abstract.h
Revision: e163cd2aa350ce34
Author: Davis King
Date: Sep 14, 2014 (16:16:46 UTC)

Added map_det_to_chip()

Modified
dlib/image_transforms/interpolation.h
dlib/image_transforms/interpolation_abstract.h
Revision: c486886c1e4872d7
Author: Davis King
Date: Sep 14, 2014 (15:55:30 UTC)

fixed spelling error

Modified
dlib/image_transforms/interpolation_abstract.h
Revision: abf72bff127d44ab
Author: Davis King
Date: Sep 14, 2014 (07:27:36 UTC)

Added the option to use an identity matrix prior to the vector_normalizer_frobmetric object.

Modified
dlib/statistics/vector_normalizer_frobmetric.h
dlib/statistics/vector_normalizer_frobmetric_abstract.h
dlib/test/statistics.cpp
Revision: 7f0a2bd3ebbca6b7
Author: Davis King
Date: Sep 07, 2014 (11:19:42 UTC)

Increased default face chip size from get_face_chip_details()

Modified
dlib/image_transforms/interpolation.h
dlib/image_transforms/interpolation_abstract.h
Revision: de86facf50b8c798
Author: Davis King
Date: Sep 07, 2014 (11:19:18 UTC)

clarified spec

Modified
dlib/matrix/matrix_la_abstract.h
Revision: 4718f85fb7d61cb2
Author: Davis King
Date: Sep 06, 2014 (12:01:42 UTC)

Changed get_face_chip_details() so it ignores the eyebrows and lower lip since those are really mobile parts of the face.

Modified
dlib/image_transforms/interpolation.h
Revision: 26e3d23ceb6c2500
Author: Davis King
Date: Sep 06, 2014 (11:44:09 UTC)

Added code to show how to chip out the faces.

Modified
examples/face_landmark_detection_ex.cpp
Revision: 39ca4b557c6f273c
Author: Davis King
Date: Sep 06, 2014 (11:43:54 UTC)

Added an overload of get_face_chip_details() that works on arrays of detections.

Modified
dlib/image_transforms/interpolation.h
dlib/image_transforms/interpolation_abstract.h
Revision: d3a711fff202e116
Author: Davis King
Date: Sep 06, 2014 (11:31:13 UTC)

added get_face_chip_details()

Modified
dlib/image_transforms/interpolation.h
dlib/image_transforms/interpolation_abstract.h
Revision: 4538a837d9c0822d
Author: Davis King
Date: Sep 06, 2014 (10:04:34 UTC)

Upgraded chip_details so you can specify a chip extraction by a bunch of point correspondences between the chip and the original image.

Modified
dlib/image_transforms/interpolation.h
dlib/image_transforms/interpolation_abstract.h
Revision: 4d9127609fe18abb
Author: Davis King
Date: Sep 05, 2014 (14:42:35 UTC)

Added missing assert

Modified
dlib/image_processing/shape_predictor.h
Revision: fa945098714c8b01
Author: Davis King
Date: Sep 05, 2014 (14:26:37 UTC)

Changed noncopyable.h to avoid a name clash with boost 1.56

Modified
dlib/noncopyable.h
Revision: d7820be2003786b4
Author: Davis King
Date: Sep 02, 2014 (16:55:44 UTC)

Fixed bug in the render_face_detections() overload I just added.

Modified
dlib/image_processing/render_face_detections.h
Revision: ac61317b10796bfe
Author: Davis King
Date: Sep 02, 2014 (16:47:33 UTC)

Added get_mapping_to_chip()

Modified
dlib/image_transforms/interpolation.h
dlib/image_transforms/interpolation_abstract.h
Revision: d4c80059df33d5cb
Author: Davis King
Date: Sep 02, 2014 (16:15:11 UTC)

Added an overload of render_face_detections() that takes just a single full_object_detection.

Modified
dlib/image_processing/render_face_detections.h
dlib/image_processing/render_face_detections_abstract.h
Revision: e1be0f9926c28193
Author: Davis King
Date: Sep 02, 2014 (16:14:22 UTC)

Added methods to allow in-place modification of a full_object_detection.

Modified
dlib/image_processing/full_object_detection.h
dlib/image_processing/full_object_detection_abstract.h
Revision: 0e9c4c49cd5bcad6
Author: Davis King
Date: Aug 24, 2014 (15:34:39 UTC)

Fixed a minor bug.

Modified
dlib/image_processing/shape_predictor.h
Revision: 35eb23706c9af7f8
Author: Davis King
Date: Aug 24, 2014 (15:20:42 UTC)

Fixed spelling error in comment

Modified
dlib/image_processing/generic_image.h
Revision: b96cdbbff14390f0
Author: Davis King
Date: Aug 24, 2014 (09:21:09 UTC)

changed cmake files a little to avoid warnings from the example programs.

Modified
dlib/test/CMakeLists.txt
Added
dlib/test/examples/CMakeLists.txt
Revision: 6e3e3c25b574de14
Author: Davis King
Date: Aug 24, 2014 (08:43:51 UTC)

added missing asserts

Modified
dlib/image_processing/render_face_detections.h
dlib/image_processing/shape_predictor.h
dlib/image_processing/shape_predictor_abstract.h
Revision: 2136e574285873c8
Author: Davis King
Date: Aug 24, 2014 (08:15:52 UTC)

Added unit tests for the face processing code

Modified
dlib/test/CMakeLists.txt
dlib/test/makefile
Added
dlib/test/face.cpp
Revision: 9689e3594f886eb6
Author: Davis King
Date: Aug 24, 2014 (06:37:19 UTC)

improved examples

Modified
examples/face_landmark_detection_ex.cpp
examples/train_shape_predictor_ex.cpp
Revision: 7f7a59257d104b70
Author: Davis King
Date: Aug 24, 2014 (05:01:31 UTC)

fleshed out the spec

Modified
dlib/image_processing/shape_predictor.h
dlib/image_processing/shape_predictor_abstract.h
Revision: 870cde8bee8501b0
Author: Davis King
Date: Aug 23, 2014 (17:00:33 UTC)

Cleaned up the code a bit. Still more cleaning to do.

Modified
dlib/image_processing/shape_predictor.h
dlib/image_processing/shape_predictor_abstract.h
Revision: bc8ce4cfb09ec198
Author: Davis King
Date: Aug 21, 2014 (18:42:48 UTC)

Added initial version of shape training example

Modified
examples/CMakeLists.txt
Added
examples/faces/testing_with_face_landmarks.xml
examples/faces/training_with_face_landmarks.xml
examples/train_shape_predictor_ex.cpp
Revision: 31f4d49e4c5edb58
Author: Davis King
Date: Aug 21, 2014 (18:11:55 UTC)

Added a face landmarking example program

Modified
examples/CMakeLists.txt
Added
examples/face_landmark_detection_ex.cpp
Revision: 076512736401faf6
Author: Davis King
Date: Aug 21, 2014 (17:27:51 UTC)

upped the imglab version number

Modified
tools/imglab/src/main.cpp
Revision: 114db23eb14cfd91
Author: Davis King
Date: Aug 21, 2014 (17:07:45 UTC)

Made the way the image_display draws parts not so awful. Now the parts will have a reasonable size based on the current zoom level.

Modified
dlib/gui_widgets/widgets.cpp
Revision: 674a1093a3d97717
Author: Davis King
Date: Aug 21, 2014 (16:42:16 UTC)

Added image shape prediction code. It works well, just need to fill out the spec and add asserts.

Modified
dlib/image_processing.h
Added
dlib/image_processing/render_face_detections.h
dlib/image_processing/render_face_detections_abstract.h
dlib/image_processing/shape_predictor.h
dlib/image_processing/shape_predictor_abstract.h
Revision: 9cd8010e16a07dd2
Author: Davis King
Date: Aug 21, 2014 (15:29:27 UTC)

A minor change to avoid a compiler warning from gcc with -Wall is on.

Modified
dlib/image_loader/load_image.h
Revision: 46ad48395ae4ba14
Author: Davis King
Date: Aug 21, 2014 (15:16:49 UTC)

Made code work in C++03 and fixed a linker error

Modified
dlib/image_loader/load_image.h
Revision: 24fa4305e1d983de
Author: Davis King
Date: Aug 21, 2014 (15:07:16 UTC)

Incorporated Changjiang Yang's patch that makes load_image() use the file headers to decide how to load images instead of using their file extensions. This makes load_image() work even when the files have the incorrect file extensions.

Modified
dlib/image_loader/load_image.h
dlib/image_loader/load_image_abstract.h
Revision: b89452ca58960dfb
Author: Davis King
Date: Aug 19, 2014 (17:00:26 UTC)

Made the image views do range checking when asserts are enabled.

Modified
dlib/image_processing/generic_image.h
Revision: 209d611d9920097e
Author: Davis King
Date: Aug 18, 2014 (16:18:06 UTC)

Fixed the cmake files to avoid getting an error if the word cmake or various other words appear in the file path to the source code.

Modified
dlib/add_python_module
dlib/cmake
Revision: 214ea3eca7b016cd
Author: Davis King
Date: Aug 17, 2014 (15:30:15 UTC)

minor code cleanup

Modified
dlib/image_transforms/segment_image.h
Revision: 7d9c5afc8385acc5
Author: Davis King
Date: Aug 17, 2014 (13:26:44 UTC)

Made the version of draw_line() that draws onto a regular image use alpha blending for drawing diagonal lines.

Modified
dlib/image_transforms/draw.h
Revision: 925daeeda48b60b3
Author: Davis King
Date: Aug 16, 2014 (08:47:07 UTC)

Added find_similarity_transform()

Modified
dlib/geometry/point_transforms.h
dlib/geometry/point_transforms_abstract.h
dlib/test/geometry.cpp
Revision: 1a97255cfb935338
Author: Davis King
Date: Aug 15, 2014 (16:16:21 UTC)

Renamed a variable to avoid a name conflict on windows which was pointed out by Ahti Leppänen.

Modified
dlib/numerical_integration/integrate_function_adapt_simpson.h
Revision: 1a0001cf0a41448d
Author: Davis King
Date: Aug 14, 2014 (16:40:42 UTC)

fixed typo in spec

Modified
dlib/image_processing/box_overlap_testing_abstract.h
Revision: d29c9f63300f04d2
Author: Davis King
Date: Aug 13, 2014 (15:06:26 UTC)

Changed the evaluate_detectors() routine so that it applies non-max suppression to each detector individually. This way one detector doesn't stomp on the output of another detector.

Modified
dlib/image_processing/scan_fhog_pyramid.h
dlib/image_processing/scan_fhog_pyramid_abstract.h
dlib/test/object_detector.cpp
Revision: cd08347b1cba5ad0
Author: Davis King
Date: Aug 12, 2014 (15:47:41 UTC)

Updated the Python API, train_simple_object_detector() so you can call it directly on already loaded data rather than needing to use an XML file as input.

Modified
python_examples/train_object_detector.py
tools/python/src/object_detection.cpp
tools/python/src/simple_object_detector.h
Revision: 6118734e0a97a1f4
Author: Davis King
Date: Aug 11, 2014 (15:51:05 UTC)

Made svd3 faster when working on small matrices.

Modified
dlib/matrix/matrix_la.h
Revision: 27a35b6ad71d8da3
Author: Davis King
Date: Aug 02, 2014 (14:56:01 UTC)

Made inv() handle singular matrices in a more reasonable way. Now it will make some effort to detect them and output an identity matrix in that case.

Modified
dlib/matrix/matrix_la.h
dlib/test/matrix2.cpp
Revision: 3e2ed39bf1da006b
Author: Davis King
Date: Jul 24, 2014 (17:38:26 UTC)

Added assignment operator for scalar float assignments.

Modified
dlib/simd/simd4f.h
Revision: b317be29dbe3608f
Author: Davis King
Date: Jul 20, 2014 (15:18:40 UTC)

clarified spec

Modified
dlib/image_processing/generic_image.h
Revision: a35b8481e05256ea
Author: Davis King
Date: Jul 20, 2014 (13:18:34 UTC)

Added links to the generic image definition in all the relevant abstract files.

Modified
dlib/image_keypoint/poly_image_abstract.h
dlib/image_keypoint/surf_abstract.h
dlib/image_loader/image_loader_abstract.h
dlib/image_loader/jpeg_loader_abstract.h
dlib/image_loader/load_image_abstract.h
dlib/image_loader/png_loader_abstract.h
dlib/image_processing/scan_image_abstract.h
dlib/image_saver/image_saver_abstract.h
dlib/image_saver/save_png_abstract.h
dlib/image_transforms/assign_image_abstract.h
dlib/image_transforms/colormaps_abstract.h
dlib/image_transforms/draw_abstract.h
dlib/image_transforms/edge_detector_abstract.h
dlib/image_transforms/equalize_histogram_abstract.h
dlib/image_transforms/fhog_abstract.h
dlib/image_transforms/image_pyramid_abstract.h
dlib/image_transforms/integral_image_abstract.h
dlib/image_transforms/interpolation_abstract.h
dlib/image_transforms/label_connected_blobs_abstract.h
dlib/image_transforms/morphological_operations_abstract.h
dlib/image_transforms/segment_image_abstract.h
dlib/image_transforms/spatial_filtering_abstract.h
Revision: e4eeea8d39353d72
Author: Davis King
Date: Jul 20, 2014 (10:47:05 UTC)

Fixed a bug where the imglab tool would sometimes start out with an annoyingly small window when the first image was bigger than the screen.

Modified
tools/imglab/src/main.cpp
tools/imglab/src/metadata_editor.cpp
Revision: 55ebdb8c9e53f30d
Author: Davis King
Date: Jul 20, 2014 (04:07:59 UTC)

Made the disabled version of pyramid_down support the new image interface. Also added an overload of operator() for pyramid_down that takes just a single image and downsamples it.

Modified
dlib/image_transforms/image_pyramid.h
dlib/image_transforms/image_pyramid_abstract.h
Revision: 3c5d428f63dd1722
Author: Davis King
Date: Jul 19, 2014 (08:09:55 UTC)

Clarified the exact size of the HOG feature maps produced by extract_fhog_features(). Also fixed a minor bug where empty planar HOG feature maps had 0 planes in them rather than 31 empty planes as the spec says they should.

Modified
dlib/image_transforms/fhog.h
dlib/image_transforms/fhog_abstract.h
dlib/test/fhog.cpp
Revision: 57abaa70725b9447
Author: Davis King
Date: Jul 18, 2014 (18:44:11 UTC)

Fixed a color space handling bug in resize_image()

Modified
dlib/image_transforms/interpolation.h
Revision: 6107a2b5aa188ebd
Author: Davis King
Date: Jul 18, 2014 (18:22:31 UTC)

Added a typedef to the object_detector that allows you to find out what scanner type it is using.

Modified
dlib/image_processing/object_detector.h
dlib/image_processing/object_detector_abstract.h
Revision: ae3e60490e740557
Author: Davis King
Date: Jul 18, 2014 (18:05:06 UTC)

removed more double __

Modified
dlib/array2d/array2d_kernel.h
dlib/assert.h
dlib/gui_core/gui_core_kernel_1.h
dlib/gui_core/gui_core_kernel_2.h
dlib/matrix/lapack/ormqr.h
dlib/matrix/lapack/syevr.h
dlib/matrix/matrix_eigenvalue.h
dlib/matrix/matrix_subexp.h
dlib/stack_trace.h
dlib/test/tester.cpp
dlib/test/tester.h
Revision: 02acb9951d5e4a89
Author: Davis King
Date: Jul 18, 2014 (17:46:24 UTC)

Just removed double __ from the inclusion guard names.

Modified
dlib/any/any_decision_function.h
dlib/any/any_function.h
dlib/array2d/array2d_generic_image.h
dlib/array2d/serialize_pixel_overloads.h
dlib/bridge/bridge.h
dlib/bsp.h
dlib/bsp/bsp.cpp
dlib/bsp/bsp.h
dlib/bsp/bsp_abstract.h
dlib/clustering/chinese_whispers.h
dlib/clustering/chinese_whispers_abstract.h
dlib/clustering/modularity_clustering_abstract.h
dlib/cmd_line_parser/get_option.h
dlib/cmd_line_parser/get_option_abstract.h
dlib/console_progress_indicator.h
dlib/data_io/image_dataset_metadata.cpp
dlib/data_io/image_dataset_metadata.h
dlib/data_io/libsvm_io.h
dlib/data_io/libsvm_io_abstract.h
dlib/data_io/load_image_dataset.h
dlib/data_io/load_image_dataset_abstract.h
dlib/disjoint_subsets/disjoint_subsets.h
dlib/disjoint_subsets/disjoint_subsets_abstract.h
dlib/filtering/kalman_filter.h
dlib/filtering/kalman_filter_abstract.h
dlib/filtering/rls_filter.h
dlib/filtering/rls_filter_abstract.h
dlib/float_details.h
dlib/general_hash/count_bits.h
dlib/general_hash/count_bits_abstract.h
dlib/general_hash/hash.h
dlib/general_hash/hash_abstract.h
dlib/general_hash/murmur_hash3.h
dlib/general_hash/murmur_hash3_abstract.h
dlib/general_hash/random_hashing.h
dlib/general_hash/random_hashing_abstract.h
dlib/geometry/point_transforms_abstract.h
dlib/graph_cuts/find_max_factor_graph_potts.h
dlib/graph_cuts/find_max_factor_graph_potts_abstract.h
dlib/graph_cuts/general_flow_graph.h
dlib/graph_cuts/general_potts_problem.h
dlib/graph_cuts/graph_labeler.h
dlib/graph_cuts/graph_labeler_abstract.h
dlib/graph_cuts/min_cut.h
dlib/graph_cuts/min_cut_abstract.h
dlib/graph_utils/edge_list_graphs.h
dlib/graph_utils/edge_list_graphs_abstract.h
dlib/graph_utils/find_k_nearest_neighbors_lsh.h
dlib/graph_utils/find_k_nearest_neighbors_lsh_abstract.h
dlib/graph_utils/function_objects.h
dlib/graph_utils/function_objects_abstract.h
dlib/graph_utils/ordered_sample_pair.h
dlib/graph_utils/ordered_sample_pair_abstract.h
dlib/graph_utils/sample_pair.h
dlib/graph_utils/sample_pair_abstract.h
dlib/http_client/http_client.h
dlib/http_client/http_client_abstract.h
dlib/image_keypoint/binned_vector_feature_image.h
dlib/image_keypoint/binned_vector_feature_image_abstract.h
dlib/image_keypoint/build_separable_poly_filters.h
dlib/image_keypoint/fine_hog_image.h
dlib/image_keypoint/fine_hog_image_abstract.h
dlib/image_keypoint/hashed_feature_image.h
dlib/image_keypoint/hashed_feature_image_abstract.h
dlib/image_keypoint/hessian_pyramid.h
dlib/image_keypoint/hessian_pyramid_abstract.h
dlib/image_keypoint/hog.h
dlib/image_keypoint/hog_abstract.h
dlib/image_keypoint/nearest_neighbor_feature_image.h
dlib/image_keypoint/nearest_neighbor_feature_image_abstract.h
dlib/image_keypoint/poly_image.h
dlib/image_keypoint/poly_image_abstract.h
dlib/image_loader/load_image.h
dlib/image_processing.h
dlib/image_processing/box_overlap_testing.h
dlib/image_processing/box_overlap_testing_abstract.h
dlib/image_processing/detection_template_tools.h
dlib/image_processing/detection_template_tools_abstract.h
dlib/image_processing/frontal_face_detector.h
dlib/image_processing/frontal_face_detector_abstract.h
dlib/image_processing/full_object_detection.h
dlib/image_processing/full_object_detection_abstract.h
dlib/image_processing/generic_image.h
dlib/image_processing/object_detector.h
dlib/image_processing/object_detector_abstract.h
dlib/image_processing/remove_unobtainable_rectangles.h
dlib/image_processing/remove_unobtainable_rectangles_abstract.h
dlib/image_processing/scan_fhog_pyramid.h
dlib/image_processing/scan_fhog_pyramid_abstract.h
dlib/image_processing/scan_image.h
dlib/image_processing/scan_image_abstract.h
dlib/image_processing/scan_image_boxes.h
dlib/image_processing/scan_image_boxes_abstract.h
dlib/image_processing/scan_image_custom.h
dlib/image_processing/scan_image_custom_abstract.h
dlib/image_processing/scan_image_pyramid.h
dlib/image_processing/scan_image_pyramid_abstract.h
dlib/image_processing/scan_image_pyramid_tools.h
dlib/image_processing/scan_image_pyramid_tools_abstract.h
dlib/image_processing/setup_hashed_features.h
dlib/image_processing/setup_hashed_features_abstract.h
dlib/image_saver/save_png.cpp
dlib/image_saver/save_png.h
dlib/image_transforms/colormaps.h
dlib/image_transforms/colormaps_abstract.h
dlib/image_transforms/fhog.h
dlib/image_transforms/fhog_abstract.h
dlib/image_transforms/image_pyramid.h
dlib/image_transforms/image_pyramid_abstract.h
dlib/image_transforms/interpolation.h
dlib/image_transforms/segment_image.h
dlib/image_transforms/segment_image_abstract.h
dlib/iosockstream.h
dlib/iosockstream/iosockstream.h
dlib/iosockstream/iosockstream_abstract.h
dlib/lsh/create_random_projection_hash.h
dlib/lsh/create_random_projection_hash_abstract.h
dlib/lsh/hashes.h
dlib/lsh/hashes_abstract.h
dlib/lsh/projection_hash.h
dlib/lsh/projection_hash_abstract.h
dlib/manifold_regularization/linear_manifold_regularizer.h
dlib/manifold_regularization/linear_manifold_regularizer_abstract.h
dlib/matrix/cblas_constants.h
dlib/matrix/lapack/gees.h
dlib/matrix/lapack/geev.h
dlib/matrix/lapack/geqrf.h
dlib/matrix/lapack/gesdd.h
dlib/matrix/lapack/gesvd.h
dlib/matrix/lapack/getrf.h
dlib/matrix/lapack/ormqr.h
dlib/matrix/lapack/potrf.h
dlib/matrix/lapack/syev.h
dlib/matrix/lapack/syevr.h
dlib/matrix/matrix_conv.h
dlib/matrix/matrix_conv_abstract.h
dlib/matrix/matrix_fft.h
dlib/matrix/matrix_fft_abstract.h
dlib/matrix/matrix_generic_image.h
dlib/matrix/matrix_mat.h
dlib/matrix/matrix_mat_abstract.h
dlib/matrix/matrix_read_from_istream.h
dlib/matrix/matrix_trsm.h
dlib/matrix/symmetric_matrix_cache.h
dlib/matrix/symmetric_matrix_cache_abstract.h
dlib/misc_api/misc_api_shared.h
dlib/numerical_integration/integrate_function_adapt_simpson.h
dlib/numerical_integration/integrate_function_adapt_simpson_abstract.h
dlib/opencv/to_open_cv.h
dlib/opencv/to_open_cv_abstract.h
dlib/optimization/find_max_factor_graph_nmplp.h
dlib/optimization/find_max_factor_graph_nmplp_abstract.h
dlib/optimization/find_max_factor_graph_viterbi.h
dlib/optimization/find_max_factor_graph_viterbi_abstract.h
dlib/optimization/find_max_parse_cky.h
dlib/optimization/find_max_parse_cky_abstract.h
dlib/optimization/max_cost_assignment.h
dlib/optimization/max_cost_assignment_abstract.h
dlib/optimization/max_sum_submatrix.h
dlib/optimization/max_sum_submatrix_abstract.h
dlib/optimization/optimization_bobyqa.h
dlib/optimization/optimization_bobyqa_abstract.h
dlib/optimization/optimization_least_squares.h
dlib/optimization/optimization_oca.h
dlib/optimization/optimization_oca_abstract.h
dlib/optimization/optimization_solve_qp2_using_smo.h
dlib/optimization/optimization_solve_qp3_using_smo.h
dlib/optimization/optimization_solve_qp_using_smo.h
dlib/optimization/optimization_solve_qp_using_smo_abstract.h
dlib/optimization/optimization_trust_region.h
dlib/optimization/optimization_trust_region_abstract.h
dlib/python/boost_python_utils.h
dlib/python/numpy.h
dlib/python/numpy_image.h
dlib/python/pyassert.h
dlib/python/serialize_pickle.h
dlib/simd.h
dlib/simd/simd4f.h
dlib/simd/simd4i.h
dlib/simd/simd8f.h
dlib/simd/simd8i.h
dlib/simd/simd_check.h
dlib/sliding_buffer/circular_buffer.h
dlib/sliding_buffer/circular_buffer_abstract.h
dlib/sockstreambuf.h
dlib/sockstreambuf/sockstreambuf.h
dlib/sockstreambuf/sockstreambuf_unbuffered.h
dlib/sparse_vector.h
dlib/statistics/average_precision.h
dlib/statistics/average_precision_abstract.h
dlib/statistics/cca.h
dlib/statistics/cca_abstract.h
dlib/statistics/image_feature_sampling.h
dlib/statistics/image_feature_sampling_abstract.h
dlib/statistics/sammon.h
dlib/statistics/sammon_abstract.h
dlib/statistics/vector_normalizer_frobmetric.h
dlib/statistics/vector_normalizer_frobmetric_abstract.h
dlib/svm/active_learning.h
dlib/svm/active_learning_abstract.h
dlib/svm/assignment_function.h
dlib/svm/assignment_function_abstract.h
dlib/svm/cross_validate_assignment_trainer.h
dlib/svm/cross_validate_assignment_trainer_abstract.h
dlib/svm/cross_validate_graph_labeling_trainer.h
dlib/svm/cross_validate_graph_labeling_trainer_abstract.h
dlib/svm/cross_validate_multiclass_trainer.h
dlib/svm/cross_validate_multiclass_trainer_abstract.h
dlib/svm/cross_validate_object_detection_trainer.h
dlib/svm/cross_validate_object_detection_trainer_abstract.h
dlib/svm/cross_validate_regression_trainer.h
dlib/svm/cross_validate_regression_trainer_abstract.h
dlib/svm/cross_validate_sequence_labeler.h
dlib/svm/cross_validate_sequence_labeler_abstract.h
dlib/svm/cross_validate_sequence_segmenter.h
dlib/svm/cross_validate_sequence_segmenter_abstract.h
dlib/svm/cross_validate_track_association_trainer.h
dlib/svm/cross_validate_track_association_trainer_abstract.h
dlib/svm/krr_trainer.h
dlib/svm/krr_trainer_abstract.h
dlib/svm/linearly_independent_subset_finder.h
dlib/svm/multiclass_tools.h
dlib/svm/multiclass_tools_abstract.h
dlib/svm/null_df.h
dlib/svm/num_nonnegative_weights.h
dlib/svm/one_vs_all_decision_function.h
dlib/svm/one_vs_all_decision_function_abstract.h
dlib/svm/one_vs_all_trainer.h
dlib/svm/one_vs_all_trainer_abstract.h
dlib/svm/one_vs_one_decision_function.h
dlib/svm/one_vs_one_decision_function_abstract.h
dlib/svm/one_vs_one_trainer.h
dlib/svm/one_vs_one_trainer_abstract.h
dlib/svm/ranking_tools.h
dlib/svm/ranking_tools_abstract.h
dlib/svm/rls.h
dlib/svm/rls_abstract.h
dlib/svm/rr_trainer.h
dlib/svm/rr_trainer_abstract.h
dlib/svm/sequence_labeler.h
dlib/svm/sequence_labeler_abstract.h
dlib/svm/sequence_segmenter.h
dlib/svm/sequence_segmenter_abstract.h
dlib/svm/simplify_linear_decision_function.h
dlib/svm/simplify_linear_decision_function_abstract.h
dlib/svm/sort_basis_vectors.h
dlib/svm/sort_basis_vectors_abstract.h
dlib/svm/structural_assignment_trainer.h
dlib/svm/structural_assignment_trainer_abstract.h
dlib/svm/structural_graph_labeling_trainer.h
dlib/svm/structural_graph_labeling_trainer_abstract.h
dlib/svm/structural_object_detection_trainer.h
dlib/svm/structural_object_detection_trainer_abstract.h
dlib/svm/structural_sequence_labeling_trainer.h
dlib/svm/structural_sequence_labeling_trainer_abstract.h
dlib/svm/structural_sequence_segmentation_trainer.h
dlib/svm/structural_sequence_segmentation_trainer_abstract.h
dlib/svm/structural_svm_assignment_problem.h
dlib/svm/structural_svm_assignment_problem_abstract.h
dlib/svm/structural_svm_distributed.h
dlib/svm/structural_svm_distributed_abstract.h
dlib/svm/structural_svm_graph_labeling_problem.h
dlib/svm/structural_svm_graph_labeling_problem_abstract.h
dlib/svm/structural_svm_object_detection_problem.h
dlib/svm/structural_svm_object_detection_problem_abstract.h
dlib/svm/structural_svm_problem.h
dlib/svm/structural_svm_problem_abstract.h
dlib/svm/structural_svm_problem_threaded.h
dlib/svm/structural_svm_problem_threaded_abstract.h
dlib/svm/structural_svm_sequence_labeling_problem.h
dlib/svm/structural_svm_sequence_labeling_problem_abstract.h
dlib/svm/structural_track_association_trainer.h
dlib/svm/structural_track_association_trainer_abstract.h
dlib/svm/svm_c_ekm_trainer.h
dlib/svm/svm_c_ekm_trainer_abstract.h
dlib/svm/svm_c_linear_dcd_trainer.h
dlib/svm/svm_c_linear_dcd_trainer_abstract.h
dlib/svm/svm_c_linear_trainer.h
dlib/svm/svm_c_linear_trainer_abstract.h
dlib/svm/svm_c_trainer.h
dlib/svm/svm_multiclass_linear_trainer.h
dlib/svm/svm_multiclass_linear_trainer_abstract.h
dlib/svm/svm_nu_trainer.h
dlib/svm/svm_one_class_trainer.h
dlib/svm/svm_rank_trainer.h
dlib/svm/svm_rank_trainer_abstract.h
dlib/svm/svr_linear_trainer.h
dlib/svm/svr_linear_trainer_abstract.h
dlib/svm/svr_trainer.h
dlib/svm/track_association_function.h
dlib/svm/track_association_function_abstract.h
dlib/test/create_iris_datafile.h
dlib/test/optimization_test_functions.h
dlib/threads/parallel_for_extension.h
dlib/threads/parallel_for_extension_abstract.h
dlib/threads/thread_pool_extension.cpp
dlib/threads/thread_pool_extension.h
dlib/threads/thread_pool_extension_abstract.h
dlib/timer/timer.cpp
dlib/timer/timer.h
dlib/timing.h
dlib/tuple.h
dlib/unordered_pair.h
dlib/vectorstream.h
dlib/vectorstream/vectorstream.h
dlib/vectorstream/vectorstream_abstract.h
Revision: 44445ca8c3a3af4c
Author: Davis King
Date: Jul 18, 2014 (17:31:55 UTC)

Just fixed some funny typos in some comments.

Modified
dlib/image_keypoint/hessian_pyramid.h
dlib/numerical_integration/integrate_function_adapt_simpson.h
dlib/numerical_integration/integrate_function_adapt_simpson_abstract.h
dlib/optimization/find_max_factor_graph_nmplp_abstract.h
dlib/statistics/average_precision_abstract.h
dlib/svm/null_df.h
dlib/svm/svm_c_linear_trainer.h
Revision: dda46909ccc5693d
Author: Davis King
Date: Jul 17, 2014 (18:29:06 UTC)

Fixed a few things so they work with the new image generic interface.

Modified
dlib/image_processing/scan_fhog_pyramid.h
dlib/image_transforms/interpolation.h
dlib/python/numpy_image.h
Revision: c62c1d104a8f4ecc
Author: Davis King
Date: Jul 17, 2014 (15:23:43 UTC)

Added a file that defines a new generic image interface for images in dlib. This is the dlib/image_processing/generic_image.h file. Then I changed all the image processing functions so that they use this interface. All the changes are very minor, but there are just a lot of them. Any user code that was using array2d objects to represent images will still work. However, this change makes it so that users can use their own custom image objects with dlib by simply implementing a few global functions for their image object.

Modified
dlib/array2d.h
dlib/geometry/rectangle.h
dlib/geometry/rectangle_abstract.h
dlib/gui_widgets/widgets.h
dlib/image_keypoint/fine_hog_image.h
dlib/image_keypoint/fine_hog_image_abstract.h
dlib/image_keypoint/hashed_feature_image.h
dlib/image_keypoint/hog.h
dlib/image_keypoint/hog_abstract.h
dlib/image_keypoint/poly_image.h
dlib/image_keypoint/poly_image_abstract.h
dlib/image_keypoint/surf.h
dlib/image_keypoint/surf_abstract.h
dlib/image_loader/image_loader.h
dlib/image_loader/image_loader_abstract.h
dlib/image_loader/jpeg_loader.h
dlib/image_loader/jpeg_loader_abstract.h
dlib/image_loader/load_image_abstract.h
dlib/image_loader/png_loader.h
dlib/image_loader/png_loader_abstract.h
dlib/image_processing/scan_fhog_pyramid.h
dlib/image_processing/scan_image.h
dlib/image_processing/scan_image_abstract.h
dlib/image_processing/scan_image_pyramid.h
dlib/image_processing/scan_image_pyramid_abstract.h
dlib/image_saver/image_saver.h
dlib/image_saver/image_saver_abstract.h
dlib/image_saver/save_png.h
dlib/image_saver/save_png_abstract.h
dlib/image_transforms/assign_image.h
dlib/image_transforms/assign_image_abstract.h
dlib/image_transforms/colormaps.h
dlib/image_transforms/colormaps_abstract.h
dlib/image_transforms/draw.h
dlib/image_transforms/draw_abstract.h
dlib/image_transforms/edge_detector.h
dlib/image_transforms/edge_detector_abstract.h
dlib/image_transforms/equalize_histogram.h
dlib/image_transforms/equalize_histogram_abstract.h
dlib/image_transforms/fhog.h
dlib/image_transforms/fhog_abstract.h
dlib/image_transforms/image_pyramid.h
dlib/image_transforms/image_pyramid_abstract.h
dlib/image_transforms/integral_image.h
dlib/image_transforms/integral_image_abstract.h
dlib/image_transforms/interpolation.h
dlib/image_transforms/interpolation_abstract.h
dlib/image_transforms/label_connected_blobs.h
dlib/image_transforms/label_connected_blobs_abstract.h
dlib/image_transforms/morphological_operations.h
dlib/image_transforms/morphological_operations_abstract.h
dlib/image_transforms/segment_image.h
dlib/image_transforms/segment_image_abstract.h
dlib/image_transforms/spatial_filtering.h
dlib/image_transforms/spatial_filtering_abstract.h
dlib/image_transforms/thresholding.h
dlib/image_transforms/thresholding_abstract.h
dlib/matrix.h
dlib/matrix/matrix_mat.h
dlib/matrix/matrix_mat_abstract.h
dlib/opencv/cv_image.h
dlib/opencv/to_open_cv.h
dlib/opencv/to_open_cv_abstract.h
Added
dlib/array2d/array2d_generic_image.h
dlib/image_processing/generic_image.h
dlib/matrix/matrix_generic_image.h
Revision: ce8f80013d26608e
Author: Davis King
Date: Jul 12, 2014 (10:47:52 UTC)

Harmonized the array2d::set_size and matrix::set_size methods. In particular, array2d::set_size() now simply allows any row and column sizes so long as they are non-negative.

Modified
dlib/array2d/array2d_kernel.h
dlib/array2d/array2d_kernel_abstract.h
Revision: 9cecbdb353542ad1
Author: Michael Yee
Date: Jul 09, 2014 (03:06:30 UTC)

Removed another unused typedef to avoid a compiler warning in gcc 4.8.1.

Modified
dlib/svm/svm.h
Revision: 0cc8c2589d51fe95
Author: Davis E. King
Date: Jul 09, 2014 (08:47:28 UTC)

Removed unused typedef to avoid compiler warnings.

Modified
dlib/svm/svm.h
Revision: e12396b3f2fec101
Author: Davis King
Date: Jul 08, 2014 (17:50:50 UTC)

Changed the serialization code for C-strings so that they don't save the null terminator byte. This makes their serialization format the same as the format for std::string. I had to revert the previous mod for this because it didn't work in visual studio. This change fixes that. The code should still be able to read all previously serialized data correctly. Moreover, any char arrays that aren't null terminated will still be read and written in their entirety.

Modified
dlib/serialize.h
dlib/test/serialize.cpp
Revision: e990549e22be38ed
Author: Davis E. King
Date: Jul 07, 2014 (11:22:36 UTC)

Changed the code so that literal strings "i.e. stuff like this" are serialized using the same format as std::string. Previously, the trailing 0 was also saved so if you deserialized them into a std::string you ended up with a trailing 0 in the std::string which isn't what you want.

Modified
dlib/serialize.h
dlib/test/serialize.cpp
Revision: 9b27c096944c06cc
Author: Davis E. King
Date: Jul 02, 2014 (12:16:41 UTC)

Fixed a bug in find_min_single_variable() I introduced a few hours ago.

Modified
dlib/optimization/optimization_line_search.h
Revision: 98f90bed0940639d
Author: Davis E. King
Date: Jul 02, 2014 (08:41:31 UTC)

Made find_min_single_variable() a little more efficient.

Modified
dlib/optimization/optimization_line_search.h
Revision: be24b14482331244
Author: Davis E. King
Date: Jul 02, 2014 (06:31:55 UTC)

Fixed a bug, the initial step size wasn't being used in part of the code. Also made the initial bracketing step a little more efficient.

Modified
dlib/optimization/optimization_line_search.h
Revision: c3acb32f27442ff3
Author: Davis King
Date: Jul 01, 2014 (17:23:55 UTC)

Added a parameter to control the search radius to the find_min_single_variable() and find_max_single_variable() routines. Also made these functions a little more robust to unusual objective functions.

Modified
dlib/optimization/optimization_line_search.h
dlib/optimization/optimization_line_search_abstract.h
Revision: 2fcd4491b0252cde
Author: Davis King
Date: Jul 01, 2014 (16:26:10 UTC)

Moved negate_function() to a different file to avoid an #include ordering bug that happened when using find_max_single_variable().

Modified
dlib/optimization/optimization.h
dlib/optimization/optimization_abstract.h
dlib/optimization/optimization_line_search.h
dlib/optimization/optimization_line_search_abstract.h
Revision: 8bc59ace44c42306
Author: Davis King
Date: Jun 24, 2014 (15:46:05 UTC)

Renamed assert link check variable to be a little more informative.

Modified
dlib/threads/threads_kernel_shared.cpp
dlib/threads/threads_kernel_shared.h
Revision: b8866e308db58746
Author: Davis King
Date: Jun 23, 2014 (12:11:21 UTC)

Clarified the thread safety of evaluate_detectors().

Modified
dlib/image_processing/scan_fhog_pyramid_abstract.h
Revision: ade44c495d3cadde
Author: Davis King
Date: Jun 23, 2014 (12:06:23 UTC)

Changed the example to recommend using something like the f1-score when using BOBYQA for model selection.

Modified
examples/model_selection_ex.cpp
Revision: ec51007b4868d1f5
Author: Davis King
Date: Jun 23, 2014 (11:20:16 UTC)

Added more member functions to the auto_mutex_readonly object that allows you to convert between a readonly and write lock but still use RAII.

Modified
dlib/test/read_write_mutex.cpp
dlib/threads/auto_mutex_extension.h
dlib/threads/auto_mutex_extension_abstract.h
Revision: de24b9e6602468a9
Author: Davis King
Date: Jun 22, 2014 (06:02:03 UTC)

Made cross_validate_trainer() and cross_validate_trainer_threaded() not make duplicate copies of the training data since doing so uses a lot of RAM for large datasets.

Modified
dlib/svm/svm.h
dlib/svm/svm_threaded.h
dlib/svm/svm_threaded_abstract.h
Revision: 95b5eeb9481f7033
Author: Davis King
Date: Jun 17, 2014 (16:24:19 UTC)

Changed the murmur hash implementation to avoid any possibility of strict aliasing violations in user code, even when things get inlined in unfavorable ways.

Modified
dlib/general_hash/murmur_hash3.h
dlib/test/hash.cpp
Revision: 1cf3020c076fbfa8
Author: Davis King
Date: Jun 17, 2014 (16:03:19 UTC)

Renamed unit test program to avoid warnings from cmake

Modified
dlib/test/CMakeLists.txt
dlib/test/makefile
Revision: cc8c2ebc9959b259
Author: Davis King
Date: Jun 13, 2014 (16:13:18 UTC)

Fixed spelling errors in comments

Modified
dlib/threads/threads_kernel_shared.cpp
Revision: 597d3586c556114b
Author: Davis King
Date: Jun 08, 2014 (11:35:12 UTC)

The new serialization API that works like serialize("filename") << object; wasn't opening files in binary mode. Oops. This is now fixed.

Modified
dlib/serialize.h
Revision: 492860bbb86e2782
Author: Davis King
Date: May 31, 2014 (08:19:10 UTC)

Fixed a minor interface usability flaw in the scan_fhog_pyramid. It wasn't documented that you couldn't change the padding, cell size, or window size parameters between calls to load() and detect().

Modified
dlib/image_processing/scan_fhog_pyramid.h
dlib/image_processing/scan_fhog_pyramid_abstract.h
Revision: e64b062797ece754
Author: Davis King
Date: May 31, 2014 (08:04:00 UTC)

Fixed a warning about signed/unsigned comparisons.

Modified
dlib/image_processing/scan_fhog_pyramid.h
Revision: 14f7beeeac9f8f8f
Author: Davis King
Date: May 26, 2014 (15:25:46 UTC)

Added missing requires clauses

Modified
dlib/image_processing/scan_fhog_pyramid_abstract.h
Revision: 612653f5dbcf1e22
Author: Davis King
Date: May 26, 2014 (14:56:01 UTC)

Fixed bug in evaluate_detectors() and added unit tests.

Modified
dlib/image_processing/scan_fhog_pyramid.h
dlib/test/object_detector.cpp
Revision: d816f279aaf19f73
Author: Davis King
Date: May 26, 2014 (14:46:35 UTC)

Updated example to use evaluate_detectors()

Modified
examples/fhog_object_detector_ex.cpp
Revision: 6cdb057c61c50b1f
Author: Davis King
Date: May 26, 2014 (14:46:13 UTC)

Added evaluate_detectors() to make it easy to run a bunch of HOG detectors efficiently, even when their window sizes differ.

Modified
dlib/image_processing/scan_fhog_pyramid.h
dlib/image_processing/scan_fhog_pyramid_abstract.h
Revision: f8d9a56a3deb6fa9
Author: Davis King
Date: May 26, 2014 (14:22:55 UTC)

Refactored a bit of the object_detector interface. Also fixed a bug in the non-max suppression code that I introduced a few commits ago.

Modified
dlib/image_processing/object_detector.h
dlib/image_processing/object_detector_abstract.h
Revision: 390a6d2230adf8bf
Author: Davis King
Date: May 24, 2014 (08:27:20 UTC)

Improved non-max-suppression for detectors with multiple sub-detectors packed into them.

Modified
dlib/image_processing/object_detector.h
Revision: d2783b65366561d7
Author: Davis King
Date: May 24, 2014 (06:18:31 UTC)

Added set_prior() to the python interfaces of the relevant trainer objects.

Modified
tools/python/src/svm_c_trainer.cpp
tools/python/src/svm_rank_trainer.cpp
Revision: 7bf28d5225404480
Author: Davis King
Date: May 23, 2014 (18:03:55 UTC)

Made set_prior() work with sparse vectors.

Modified
dlib/svm/svm_c_linear_trainer.h
dlib/test/oca.cpp
dlib/test/svm_c_linear.cpp
Revision: 61a6ece07460ff1d
Author: Davis King
Date: May 23, 2014 (17:53:51 UTC)

Fixed a bug in the prior support related to sparse vector usage.

Modified
dlib/svm/svm_multiclass_linear_trainer.h
Revision: 0dad7eaf84bce19d
Author: Davis King
Date: May 23, 2014 (17:52:01 UTC)

Relaxed some excessively restrictive requires clauses.

Modified
dlib/matrix/matrix_utilities.h
dlib/matrix/matrix_utilities_abstract.h
Revision: 42758e94aefa8096
Author: Davis King
Date: May 23, 2014 (15:07:32 UTC)

Fixed set_prior() so it works with sparse vectors in addition to dense vectors.

Modified
dlib/svm/svm_rank_trainer.h
dlib/test/ranking.cpp
Revision: fde18d33b0c142a4
Author: Davis King
Date: May 23, 2014 (14:35:49 UTC)

Added unit tests for the svm_multiclass_linear with sparse priors

Modified
dlib/test/svm_multiclass_linear.cpp
Revision: ceeb863b3b2e617e
Author: Davis King
Date: May 22, 2014 (17:34:35 UTC)

Fixed compile time bug

Modified
dlib/svm/svm_multiclass_linear_trainer.h
Revision: 5061fdd1b431b4fe
Author: Davis King
Date: May 22, 2014 (16:19:02 UTC)

Added another test

Modified
dlib/test/matrix.cpp
Revision: a72e4ac8c26939d8
Author: Davis King
Date: May 22, 2014 (16:17:21 UTC)

Made it so you can write statements like mymat = m = 0; That is, chain the = operator when using a literal assignment on matrix objects.

Modified
dlib/matrix/matrix.h
dlib/test/matrix.cpp
Revision: 30b951b666a2a9bb
Author: Davis King
Date: May 21, 2014 (17:56:04 UTC)

Added unit test for the new dot() overloads.

Modified
dlib/test/sparse_vector.cpp
Revision: 6327c26242e3b516
Author: Davis King
Date: May 21, 2014 (17:48:04 UTC)

Added unit tests for new serialization syntax.

Modified
dlib/test/serialize.cpp
Revision: 66ebdb63b96c8300
Author: Davis King
Date: May 21, 2014 (16:52:57 UTC)

Made the requires checking for array::set_size() always stay on since it is not going to be performance critical and is a common user error.

Modified
dlib/array/array_kernel.h
Revision: e85dcb870c7b7fe4
Author: Davis King
Date: May 21, 2014 (16:51:11 UTC)

Fixed incorrect requires clause on the cross_validate_trainer() and cross_validate_trainer_threaded() routines.

Modified
dlib/svm/svm.h
dlib/svm/svm_abstract.h
dlib/svm/svm_threaded.h
dlib/svm/svm_threaded_abstract.h
Revision: b6a4c87914fdf8bf
Author: Davis King
Date: May 21, 2014 (-02:19:57 UTC)

Changed code so that the proper error code is always returned even in the event that closesocket() fails.

Modified
dlib/sockets/sockets_kernel_1.cpp
Revision: d862afecf86457c5
Author: Davis King
Date: May 20, 2014 (17:12:34 UTC)

Fixed spelling error in comment.

Modified
dlib/sockets/sockets_kernel_2.cpp
Revision: e3f06fb6e064b842
Author: Davis King
Date: May 18, 2014 (10:37:04 UTC)

Changed the assign() function so that it no longer removes zeros from dense vectors when assigning them to sparse vectors. Also updated dot() so that it is much faster when working with "sparse vectors" that are the product of assigning a dense vector to a sparse vector.

Modified
dlib/svm/sparse_vector.h
Revision: ecbd1ac86cafb2b3
Author: Davis King
Date: May 16, 2014 (15:36:01 UTC)

Fixed a potential divide by zero in draw_fhog()

Modified
dlib/image_transforms/fhog.h
Revision: 6096ac2e2324100f
Author: Davis King
Date: May 08, 2014 (17:07:56 UTC)

Made the examples use the new simplified file serialization API.

Modified
examples/assignment_learning_ex.cpp
examples/custom_trainer_ex.cpp
examples/fhog_object_detector_ex.cpp
examples/krls_ex.cpp
examples/krr_classification_ex.cpp
examples/krr_regression_ex.cpp
examples/learning_to_track_ex.cpp
examples/multiclass_classification_ex.cpp
examples/object_detector_ex.cpp
examples/rvm_ex.cpp
examples/rvm_regression_ex.cpp
examples/sequence_labeler_ex.cpp
examples/sequence_segmenter_ex.cpp
examples/svm_ex.cpp
examples/train_object_detector.cpp
Revision: dd0288c699d682b7
Author: Davis King
Date: May 08, 2014 (16:40:22 UTC)

Added a simplified operator << and >> syntax for serializing to and from files.

Modified
dlib/serialize.h
Revision: b00a471b53bfde67
Author: Davis King
Date: May 04, 2014 (18:09:59 UTC)

Added the option to set a prior to svm_rank_trainer.

Modified
dlib/svm/svm_rank_trainer.h
dlib/svm/svm_rank_trainer_abstract.h
dlib/test/ranking.cpp
Revision: e65a49a1b9ab753a
Author: Davis King
Date: May 04, 2014 (17:32:50 UTC)

Added missing assert

Modified
dlib/svm/svm_c_linear_trainer.h
Revision: 2badb5f6899e93cc
Author: Davis King
Date: May 04, 2014 (17:32:38 UTC)

Fixed grammar

Modified
dlib/svm/svm_c_linear_trainer_abstract.h
Revision: c5dd0ebceb841784
Author: Davis King
Date: May 04, 2014 (16:53:48 UTC)

Fixed compiler errors in unit tests

Modified
dlib/test/svm_struct.cpp
Revision: 65695ed6be50c7c1
Author: Davis King
Date: May 04, 2014 (16:08:44 UTC)

Fixed compile time error I just introduced.

Modified
dlib/svm/svm_c_linear_trainer.h
Revision: d0a366cfe4dd89f8
Author: Davis King
Date: May 04, 2014 (16:01:20 UTC)

Added the ability to set a prior to the svm_c_linear_trainer.

Modified
dlib/svm/svm_c_linear_trainer.h
dlib/svm/svm_c_linear_trainer_abstract.h
dlib/test/svm_c_linear.cpp
Revision: 7172005a4937851f
Author: Davis King
Date: May 04, 2014 (15:45:57 UTC)

Added overloads of mat() that convert a single scalar into a matrix.

Modified
dlib/matrix/matrix_mat.h
dlib/matrix/matrix_mat_abstract.h
Revision: 148793c1763dbad9
Author: Davis King
Date: May 04, 2014 (15:21:58 UTC)

clarified spec

Modified
dlib/svm/svm_multiclass_linear_trainer_abstract.h
Revision: 4c2b50d19f0cefe1
Author: Davis King
Date: May 04, 2014 (15:14:38 UTC)

Clarified spec and also slightly improved usability

Modified
dlib/svm/svm_multiclass_linear_trainer.h
dlib/svm/svm_multiclass_linear_trainer_abstract.h
Revision: 1db294f4e69272a4
Author: Davis King
Date: May 01, 2014 (16:47:07 UTC)

Added the ability to set a previously trained function as a prior to the svm_multiclass_linear_trainer.

Modified
dlib/svm/svm_multiclass_linear_trainer.h
dlib/svm/svm_multiclass_linear_trainer_abstract.h
dlib/test/svm_multiclass_linear.cpp
Revision: 9bb42de59762e16b
Author: Davis King
Date: Apr 26, 2014 (15:56:18 UTC)

Fixed minor typos

Modified
examples/logger_ex_2.cpp
Revision: fb60ed2c25e61025
Author: Davis King
Date: Apr 26, 2014 (13:32:06 UTC)

Added an example program showing how to setup a logger hook

Modified
examples/CMakeLists.txt
Added
examples/logger_custom_output_ex.cpp
Revision: 0eb450520e893091
Author: Davis King
Date: Apr 26, 2014 (13:17:22 UTC)

Just a few minor overloads and usability tweaks to the logger interface.

Modified
dlib/logger/logger_kernel_1.h
dlib/logger/logger_kernel_abstract.h
Revision: 410e9eb9e5ebcc43
Author: Davis King
Date: Apr 26, 2014 (11:35:45 UTC)

Added locally_change_current_dir

Modified
dlib/misc_api.h
dlib/misc_api/misc_api_kernel_abstract.h
Added
dlib/misc_api/misc_api_shared.h
Revision: c121ed7e04dd6b22
Author: Davis King
Date: Apr 26, 2014 (09:10:09 UTC)

Made the ODR rule violation error diagnostic clearer.

Modified
dlib/threads/threads_kernel_shared.cpp
dlib/threads/threads_kernel_shared.h
Revision: 9b49cd55cfe898ab
Author: Davis King
Date: Apr 26, 2014 (08:57:42 UTC)

Added user settable loss to the structural_track_association_trainer.

Modified
dlib/svm/structural_track_association_trainer.h
dlib/svm/structural_track_association_trainer_abstract.h
Revision: 47071c701fea6abf
Author: Davis King
Date: Apr 23, 2014 (16:25:27 UTC)

Slightly simplified the code

Modified
dlib/svm/structural_svm_problem.h
Revision: e11ad0889a8cd1af
Author: Davis King
Date: Apr 23, 2014 (15:41:37 UTC)

Added operator+= to discriminant_pca.

Modified
dlib/statistics/dpca.h
dlib/statistics/dpca_abstract.h
dlib/test/discriminant_pca.cpp
Revision: a3f3d9b5e9b86ff7
Author: Davis King
Date: Apr 23, 2014 (15:19:49 UTC)

Improve error message generated when calling argument() incorrectly.

Modified
dlib/cmd_line_parser/cmd_line_parser_kernel_1.h
Revision: c72a3f001d37a958
Author: Davis King
Date: Apr 23, 2014 (15:09:24 UTC)

fixed spelling errors

Modified
dlib/interfaces/cmd_line_parser_option.h
Revision: 9e33b4c369c6d6d8
Author: Davis King
Date: Apr 22, 2014 (17:18:31 UTC)

Added user settable loss to the association trainer

Modified
dlib/svm/structural_assignment_trainer.h
dlib/svm/structural_assignment_trainer_abstract.h
dlib/svm/structural_svm_assignment_problem.h
dlib/svm/structural_svm_assignment_problem_abstract.h
Revision: 77f4321d7b5f88cc
Author: Davis King
Date: Apr 22, 2014 (16:18:58 UTC)

fixed typo in spec

Modified
dlib/svm/svm_rank_trainer_abstract.h
Revision: 3308807ea377af67
Author: Davis King
Date: Apr 22, 2014 (16:52:26 UTC)

Added a #define for _NO_W32_PSEUDO_MODIFIERS so that windows.h won't #define IN or OUT

Modified
dlib/windows_magic.h
Revision: 3c097f560513b809
Author: Davis King
Date: Apr 22, 2014 (16:13:47 UTC)

merged changes and updated abstract file.

Modified
dlib/svm/rvm.h
dlib/svm/rvm_abstract.h
examples/rvm_ex.cpp
Revision: b8e8de0dc71bdf90
Author: Csaba Kertesz
Date: Mar 16, 2014 (13:19:19 UTC)

Add maximal iterations option for relevance vector machine trainer

Modified
dlib/svm/rvm.h
examples/rvm_ex.cpp
Revision: 56d6aae8d8c25882
Author: Davis King
Date: Apr 21, 2014 (06:04:54 UTC)

fixed typo in spec

Modified
dlib/disjoint_subsets/disjoint_subsets_abstract.h
Revision: 50dccf05ad39bae4
Author: Davis King
Date: Apr 16, 2014 (17:27:11 UTC)

A minor change to avoid a compiler warning.

Modified
dlib/image_transforms/draw.h
Revision: 5073ec1b7c924c83
Author: Davis King
Date: Apr 16, 2014 (15:54:55 UTC)

Added split_on_first() and split_on_last().

Modified
dlib/string/string.h
dlib/string/string_abstract.h
dlib/test/string.cpp
Revision: 434de92b54f370e2
Author: Davis King
Date: Apr 13, 2014 (07:10:41 UTC)

clarified spec

Modified
dlib/logger/logger_kernel_abstract.h
Revision: 22446ff38555c1cf
Author: Davis King
Date: Apr 10, 2014 (15:43:08 UTC)

Made the point transformation objects default constructable and also serializable.

Modified
dlib/geometry/point_transforms.h
dlib/geometry/point_transforms_abstract.h
dlib/test/geometry.cpp
Revision: bdc9ee65b87360a6
Author: Davis King
Date: Apr 05, 2014 (14:56:50 UTC)

Made the loss calculation more explicit.

Modified
dlib/svm/structural_svm_assignment_problem.h
Revision: 710c2c08d6c9fe33
Author: Davis King
Date: Apr 05, 2014 (12:56:48 UTC)

Simplified example program.

Modified
examples/assignment_learning_ex.cpp
Revision: f558affe6d7c7af8
Author: Davis King
Date: Apr 02, 2014 (15:49:24 UTC)

fixed a typo in the spec

Modified
dlib/statistics/vector_normalizer_frobmetric_abstract.h
Revision: 4cd480e714851553
Author: Davis King
Date: Mar 27, 2014 (16:32:26 UTC)

Changed oca code so the prior vector can be the same object as the w vector.

Modified
dlib/optimization/optimization_oca.h
Revision: be293a7c2f0d7cb0
Author: Davis King
Date: Mar 18, 2014 (15:18:04 UTC)

A minor change to avoid a compiler error from clang 3.4 on Mac OS X 10.9. Thanks to Martin Fergie for reporting this problem.

Modified
dlib/sockets/sockets_kernel_1.h
dlib/sockets/sockets_kernel_2.h
Revision: 61c6f9f510aae090
Author: Davis King
Date: Mar 17, 2014 (14:24:41 UTC)

Fixed a bug in the backtracking_line_search() function pointed out by Ping-Chang Shih. The function ignored the max_iter parameter.

Modified
dlib/optimization/optimization_line_search.h
Revision: d26119e550debf5b
Author: Davis King
Date: Mar 17, 2014 (14:17:26 UTC)

Fixed a bug pointed out by Daniel Girardeau-Montaut. The covariance() function didn't work on non-double valued matrices.

Modified
dlib/matrix/matrix_utilities.h
Revision: 64a8e64d050b1c77
Author: Davis King
Date: Mar 17, 2014 (14:01:59 UTC)

Made frobmetric_training_sample serializable.

Modified
dlib/statistics/vector_normalizer_frobmetric.h
dlib/statistics/vector_normalizer_frobmetric_abstract.h
Revision: b19967f2c81868a8
Author: Davis King
Date: Mar 17, 2014 (14:00:44 UTC)

Improved speed of reshape_to_column_vector()

Modified
dlib/matrix/matrix_utilities.h
dlib/test/matrix3.cpp
Revision: 5a3fb1f810419789
Author: Davis King
Date: Mar 09, 2014 (09:37:30 UTC)

changed python example so that running it without commands doesn't trigger a testing failure in the makedocs script

Modified
python_examples/train_object_detector.py
Revision: ae9fd0072d2dadf0
Author: Davis King
Date: Mar 09, 2014 (08:10:15 UTC)

Added epsilon to the python object detection training API.

Modified
tools/python/src/object_detection.cpp
tools/python/src/simple_object_detector.h
tools/python/src/simple_object_detector_abstract.h
Revision: e7b86f7c65a670dd
Author: Davis King
Date: Mar 08, 2014 (16:41:21 UTC)

A minor change to avoid a warning from visual studio.

Modified
dlib/test/learning_to_track.cpp
Revision: b9714ef6bab36c7e
Author: Davis King
Date: Mar 08, 2014 (16:41:04 UTC)

Renamed a variable to avoid a name clash with a #define in Cygwin

Modified
dlib/svm/svm_c_linear_trainer.h
Revision: e08c124ecd9643bb
Author: Davis King
Date: Mar 08, 2014 (16:40:20 UTC)

Updated cmake file so the compiled python API file has the correct extension.

Modified
dlib/add_python_module
Revision: 51ec3c890c196aca
Author: Davis King
Date: Mar 08, 2014 (09:58:57 UTC)

fixed typo in spec

Modified
dlib/image_processing/scan_fhog_pyramid_abstract.h
Revision: 0a8e2682c28edf54
Author: Davis King
Date: Mar 08, 2014 (08:12:48 UTC)

Updated this example to use the scan_fhog_pyramid version of the object detector since it is much more user friendly.

Modified
examples/train_object_detector.cpp
Revision: 52d2a7794f01b30d
Author: Davis King
Date: Mar 08, 2014 (07:14:24 UTC)

removed cruft

Modified
tools/python/src/simple_object_detector.h
Revision: fc9814672e5ea79c
Author: Davis King
Date: Mar 08, 2014 (06:32:12 UTC)

grammar

Modified
python_examples/face_detector.py
Revision: cee0435f8f01d9cd
Author: Davis King
Date: Apr 22, 2013 (04:44:22 UTC)

Minor changes to avoid compiler warnings.

Modified
dlib/image_processing/scan_fhog_pyramid.h
dlib/image_processing/scan_fhog_pyramid_abstract.h
dlib/svm/cross_validate_track_association_trainer.h
dlib/test/learning_to_track.cpp
Revision: f9e56dbd2e1db64c
Author: Davis King
Date: Apr 22, 2013 (04:23:24 UTC)

A minor change to avoid compiler warnings.

Modified
examples/learning_to_track_ex.cpp
examples/one_class_classifiers_ex.cpp
Revision: 19bf692ded62013b
Author: Davis King
Date: Mar 07, 2014 (15:23:40 UTC)

Changed code slightly so that calling identity_matrix<double>(a_matrix) results in a compile time error rather than a confusing runtime error.

Modified
dlib/matrix/matrix_utilities.h
Revision: 5911507e40cf0dc9
Author: Davis King
Date: Mar 07, 2014 (14:45:18 UTC)

Added more comments about how to pack multiple detectors into a single object_detector.

Modified
examples/fhog_object_detector_ex.cpp
Revision: 7a2396f7acbdb81c
Author: Davis King
Date: Mar 06, 2014 (17:14:44 UTC)

Gave scan_fhog_pyramid an optional template argument that lets you define a custom version of HOG feature extraction.

Modified
dlib/image_processing/scan_fhog_pyramid.h
dlib/image_processing/scan_fhog_pyramid_abstract.h
Revision: f964581c815e1889
Author: Davis King
Date: Mar 06, 2014 (17:11:56 UTC)

clarified spec

Modified
dlib/image_transforms/fhog_abstract.h
Revision: d9ff015825c7a454
Author: Davis King
Date: Mar 05, 2014 (16:29:02 UTC)

Slightly tweaked some parameters to avoid accidentally triggering the "PSI isn't being computed correctly" debugging check inside the structural SVM solver.

Modified
dlib/image_processing/scan_fhog_pyramid.h
dlib/svm/structural_svm_object_detection_problem.h
Revision: 2adbfbc70f13dc50
Author: Davis King
Date: Mar 03, 2014 (17:36:26 UTC)

Added more pyramid point transform unit tests

Modified
dlib/test/pyramid_down.cpp
Revision: 6e9149a346a2e81f
Author: Davis King
Date: Mar 03, 2014 (13:43:33 UTC)

Made mat() correctly convert std::vector<bool> objects to matrices. Previously, the elements of the vector were returned by reference which is problematic for std::vector<bool>

Modified
dlib/matrix/matrix_mat.h
Revision: 790b6354c7599f79
Author: Davis King
Date: Mar 03, 2014 (13:29:00 UTC)

Clarified spec

Modified
dlib/lsh/projection_hash_abstract.h
Revision: 6743be629199edd6
Author: Davis King
Date: Mar 02, 2014 (06:59:31 UTC)

Fixed incorrect comment.

Modified
python_examples/train_object_detector.py
Revision: eaac72590759d8af
Author: Davis King
Date: Mar 02, 2014 (06:19:06 UTC)

Made the python object detection tools process color images in color instead of always converting to grayscale.

Modified
python_examples/train_object_detector.py
tools/python/src/object_detection.cpp
tools/python/src/simple_object_detector.h
Revision: fd9efb90a4dcbc09
Author: Davis King
Date: Mar 02, 2014 (06:08:20 UTC)

Improved error message.

Modified
tools/python/src/simple_object_detector.h
Revision: eeed7f146943000f
Author: Davis King
Date: Mar 01, 2014 (16:42:01 UTC)

Fixed name conflicts that prevented the python bindings from compiling in visual sudio 2013.

Modified
tools/python/src/other.cpp
tools/python/src/vector.cpp
Revision: e021eccfc243abe7
Author: Davis King
Date: Mar 01, 2014 (16:39:10 UTC)

Made the add_python_module cmake file look in more folders for boost when compiled on windows.

Modified
dlib/add_python_module
Revision: 3b8ded33af68a9a2
Author: Davis King
Date: Mar 01, 2014 (16:38:47 UTC)

Fixed warning on visual studio.

Modified
examples/learning_to_track_ex.cpp
Revision: 35b579be057b285e
Author: Davis King
Date: Feb 26, 2014 (16:05:39 UTC)

Made labeled_detection serializable.

Modified
dlib/svm/svm.h
dlib/svm/svm_abstract.h
Revision: 4e9671d3291517fd
Author: Davis King
Date: Feb 24, 2014 (13:18:34 UTC)

Lowered default stopping epsilon

Modified
dlib/svm/structural_assignment_trainer.h
dlib/svm/structural_assignment_trainer_abstract.h
Revision: 6d6f851c09457f1f
Author: Davis King
Date: Feb 23, 2014 (13:16:15 UTC)

fixed grammar

Modified
python_examples/train_object_detector.py
Revision: bc9088a566745d04
Author: Davis King
Date: Feb 23, 2014 (11:56:14 UTC)

Added python object detection examples

Modified
python_examples/face_detector.py
Added
python_examples/train_object_detector.py
Revision: 8dc2881c54453cce
Author: Davis King
Date: Feb 23, 2014 (11:18:04 UTC)

improved python docs

Modified
tools/python/src/object_detection.cpp
Revision: 6e7b912b65daa237
Author: Davis King
Date: Feb 23, 2014 (11:02:52 UTC)

Cleaned up the new python object detection interface a little.

Modified
tools/python/src/object_detection.cpp
tools/python/src/simple_object_detector.h
tools/python/src/simple_object_detector_abstract.h
Revision: d32a392c60cbdb96
Author: Davis King
Date: Feb 23, 2014 (10:24:22 UTC)

Gave the image_window the ability to display fhog object detectors.

Modified
tools/python/src/object_detection.cpp
Revision: 03362e8d37827399
Author: Davis King
Date: Feb 23, 2014 (09:39:59 UTC)

Added a simple python interface for training fhog object detectors.

Modified
tools/python/src/object_detection.cpp
Added
tools/python/src/simple_object_detector.h
tools/python/src/simple_object_detector_abstract.h
Revision: 7490a66fdde31bda
Author: Davis King
Date: Feb 23, 2014 (09:25:43 UTC)

Added another python utility. This one deserializes objects.

Modified
dlib/python/boost_python_utils.h
Revision: 134a1c2ad2e21689
Author: Davis King
Date: Feb 23, 2014 (07:24:54 UTC)

Made wrap_string() a little simpler to use.

Modified
dlib/string/string.h
dlib/string/string_abstract.h
Revision: 538c52b421247d12
Author: Davis King
Date: Feb 23, 2014 (05:21:53 UTC)

Clarified spec

Modified
dlib/image_processing/remove_unobtainable_rectangles_abstract.h
Revision: 62df9fd85f87a8ec
Author: Davis King
Date: Feb 22, 2014 (17:03:49 UTC)

Minor CLI cleanup

Modified
tools/mltool/src/main.cpp
Revision: b4d1536ac9db782a
Author: Davis King
Date: Feb 22, 2014 (17:00:07 UTC)

fixed grammar in comment

Modified
tools/imglab/CMakeLists.txt
Revision: c18fe76b86d62a7e
Author: Davis King
Date: Feb 22, 2014 (12:49:33 UTC)

Added more comments

Modified
examples/fhog_object_detector_ex.cpp
Revision: 1058ad4639bf4f2d
Author: Davis King
Date: Feb 22, 2014 (12:35:48 UTC)

Clarified spec

Modified
dlib/svm/sequence_segmenter_abstract.h
Revision: 1a50ca1bcd26d876
Author: Davis King
Date: Feb 22, 2014 (12:32:14 UTC)

Added comments to config.h about what other #defines you should set when building dlib as a shared library.

Modified
dlib/config.h
Revision: 23a6757db3ceb3c1
Author: Davis King
Date: Feb 22, 2014 (12:31:53 UTC)

Fixed cmake file so that the "use fftw" option actually causes the build to use fftw.

Modified
dlib/CMakeLists.txt
Revision: 264d89a4e3e0f186
Author: Davis King
Date: Feb 22, 2014 (12:31:25 UTC)

Fixed compile time error that triggered when trying to link with fftw

Modified
dlib/matrix/matrix_fft.h
Revision: 118d28d0bd1fa29d
Author: Davis King
Date: Feb 22, 2014 (11:47:31 UTC)

Added unit tests for the new learning-to-track stuff.

Modified
dlib/test/CMakeLists.txt
dlib/test/makefile
Added
dlib/test/learning_to_track.cpp
Revision: bd69ec891bd65919
Author: Davis King
Date: Feb 22, 2014 (11:08:34 UTC)

fixed more grammar

Modified
python_examples/max_cost_assignment.py
python_examples/sequence_segmenter.py
python_examples/svm_rank.py
Revision: 91c8ca830dcf56b5
Author: Davis King
Date: Feb 22, 2014 (11:07:17 UTC)

Fixing grammar in comments.

Modified
examples/bayes_net_ex.cpp
examples/bayes_net_from_disk_ex.cpp
examples/bayes_net_gui_ex.cpp
examples/bridge_ex.cpp
examples/config_reader_ex.cpp
examples/custom_trainer_ex.cpp
examples/empirical_kernel_map_ex.cpp
examples/fhog_ex.cpp
examples/fhog_object_detector_ex.cpp
examples/graph_labeling_ex.cpp
examples/gui_api_ex.cpp
examples/image_ex.cpp
examples/iosockstream_ex.cpp
examples/kcentroid_ex.cpp
examples/krls_ex.cpp
examples/krls_filter_ex.cpp
examples/krr_classification_ex.cpp
examples/krr_regression_ex.cpp
examples/least_squares_ex.cpp
examples/linear_manifold_regularizer_ex.cpp
examples/matrix_ex.cpp
examples/matrix_expressions_ex.cpp
examples/mlp_ex.cpp
examples/model_selection_ex.cpp
examples/multiclass_classification_ex.cpp
examples/object_detector_advanced_ex.cpp
examples/object_detector_ex.cpp
examples/one_class_classifiers_ex.cpp
examples/optimization_ex.cpp
examples/quantum_computing_ex.cpp
examples/rank_features_ex.cpp
examples/rvm_ex.cpp
examples/rvm_regression_ex.cpp
examples/sequence_segmenter_ex.cpp
examples/svm_ex.cpp
examples/svm_pegasos_ex.cpp
examples/svm_rank_ex.cpp
examples/svm_sparse_ex.cpp
examples/svm_struct_ex.cpp
examples/train_object_detector.cpp
examples/using_custom_kernels_ex.cpp
Revision: e3a0775331f2b620
Author: Davis King
Date: Feb 22, 2014 (10:52:28 UTC)

Fleshed out example program.

Modified
examples/learning_to_track_ex.cpp
Revision: 0954bea7c07b80fc
Author: Davis King
Date: Feb 22, 2014 (08:37:58 UTC)

clarified spec

Modified
dlib/svm/track_association_function_abstract.h
Revision: 758cbe6a8f790e36
Author: Davis King
Date: Feb 22, 2014 (08:06:41 UTC)

Made the track association testing functions smarter about how they evaluate the quality of a track association function.

Modified
dlib/svm/cross_validate_track_association_trainer.h
Revision: 68af39e89cfe3612
Author: Davis King
Date: Feb 22, 2014 (08:04:44 UTC)

Fixed a bug in randomize_samples(). It forced each element of the input arrays to move to a new position but was random amongst all permutations with such moves. However, this isn't really fully random so this function has been fixed so it does exactly what the spec says it should.

Modified
dlib/svm/svm.h
Revision: 6007664ca587ba14
Author: Davis King
Date: Feb 22, 2014 (08:03:14 UTC)

Made test a little more numerically robust.

Modified
dlib/test/one_vs_one_trainer.cpp
Revision: 0fc6f780c1937ec8
Author: Davis King
Date: Feb 20, 2014 (17:45:46 UTC)

added more comments

Modified
examples/assignment_learning_ex.cpp
Revision: b2b64bd7d4f4292b
Author: Davis King
Date: Feb 20, 2014 (17:39:48 UTC)

Added initial version of the learning to track example program.

Modified
examples/CMakeLists.txt
Added
examples/learning_to_track_ex.cpp
Revision: 328e286ac0586b2b
Author: Davis King
Date: Feb 20, 2014 (17:39:32 UTC)

Fixed compile time error.

Modified
dlib/svm/cross_validate_track_association_trainer.h
Revision: 0a50c59986c6e4f4
Author: Davis King
Date: Feb 20, 2014 (17:22:44 UTC)

Lowered the default stopping epsilon.

Modified
dlib/svm/structural_track_association_trainer.h
dlib/svm/structural_track_association_trainer_abstract.h
Revision: 51f83800e528ba82
Author: Davis King
Date: Feb 20, 2014 (17:14:42 UTC)

Just renamed variables and simplified a few things. No real changes.

Modified
dlib/svm/cross_validate_track_association_trainer.h
dlib/svm/cross_validate_track_association_trainer_abstract.h
dlib/svm/structural_track_association_trainer.h
dlib/svm/structural_track_association_trainer_abstract.h
dlib/svm/svm.h
dlib/svm/svm_abstract.h
Revision: ec9d52dc9eeb6bf1
Author: Davis King
Date: Feb 20, 2014 (16:13:41 UTC)

Added a bias term to the assignment_function's model so the user doesn't need to remember, or even understand, that they should add it themselves. However, this change breaks backwards compatibility with the previous serialization format for assignment_function objects.

Modified
dlib/svm/assignment_function.h
dlib/svm/assignment_function_abstract.h
dlib/svm/structural_assignment_trainer.h
dlib/svm/structural_svm_assignment_problem.h
dlib/svm/structural_svm_assignment_problem_abstract.h
dlib/test/assignment_learning.cpp
Revision: f0624b8d7930e5da
Author: Davis King
Date: Feb 20, 2014 (14:59:34 UTC)

Added a few more BLAS binding tests

Modified
dlib/test/blas_bindings/blas_bindings_dot.cpp
Revision: f3368c091b949665
Author: Davis King
Date: Feb 20, 2014 (14:40:17 UTC)

Added a guarantee that tracks won't be asked for their feature vector until they are updated at least once with a detection.

Modified
dlib/svm/structural_track_association_trainer.h
dlib/svm/track_association_function_abstract.h
Revision: 1fdf61ce3a91e0f7
Author: Davis King
Date: Feb 20, 2014 (14:11:42 UTC)

Clarified spec again

Modified
dlib/svm/track_association_function_abstract.h
Revision: 24e30faf48090284
Author: Davis King
Date: Feb 20, 2014 (13:45:29 UTC)

clarified spec

Modified
dlib/svm/track_association_function_abstract.h
Revision: 7293ae1deafaed3c
Author: Davis King
Date: Feb 19, 2014 (17:27:34 UTC)

Fleshed out the spec for the new track association stuff.

Modified
dlib/svm/cross_validate_track_association_trainer.h
dlib/svm/cross_validate_track_association_trainer_abstract.h
dlib/svm/structural_track_association_trainer.h
dlib/svm/structural_track_association_trainer_abstract.h
dlib/svm/track_association_function_abstract.h
Revision: e7b95a37c4ca6ab5
Author: Davis King
Date: Feb 17, 2014 (17:23:11 UTC)

Added initial version of the learning-to-track interface to the association learning tools. So this adds the track_association_function and structural_track_association_trainer objects and also test_track_association_function() and cross_validate_track_association_trainer() routines.

Modified
dlib/svm.h
dlib/svm_threaded.h
Added
dlib/svm/cross_validate_track_association_trainer.h
dlib/svm/cross_validate_track_association_trainer_abstract.h
dlib/svm/structural_track_association_trainer.h
dlib/svm/structural_track_association_trainer_abstract.h
dlib/svm/track_association_function.h
dlib/svm/track_association_function_abstract.h
Revision: 749b86459b9f0dd7
Author: Davis King
Date: Feb 17, 2014 (04:56:51 UTC)

clarified spec

Modified
dlib/mlp/mlp_kernel_abstract.h
Revision: 4661204c689cfbe1
Author: Davis King
Date: Feb 15, 2014 (15:11:04 UTC)

Added is_track_association_problem()

Modified
dlib/svm/svm.h
dlib/svm/svm_abstract.h
Revision: 61bf2b2ed4577756
Author: Davis King
Date: Feb 15, 2014 (08:03:38 UTC)

Simplified sum_filter_assign() interface.

Modified
dlib/image_transforms/spatial_filtering.h
dlib/image_transforms/spatial_filtering_abstract.h
Revision: 5b9fb4226505ad08
Author: Davis King
Date: Feb 14, 2014 (18:57:24 UTC)

Slightly changed #includes to avoid compiler error.

Modified
dlib/svm.h
dlib/svm_threaded.h
Revision: dfd8fed2ec7a964e
Author: Davis King
Date: Feb 13, 2014 (14:02:33 UTC)

Disabled use of XIM for X11 windowing since it makes programs hang on some systems. This means the wide character input methods won't work on X11 systems.

Modified
dlib/gui_core/gui_core_kernel_2.cpp
Revision: 56505c10b9970fde
Author: Davis King
Date: Feb 11, 2014 (15:23:21 UTC)

updated about

Modified
tools/imglab/src/metadata_editor.cpp
Revision: 60a8307633e261e9
Author: Davis King
Date: Feb 11, 2014 (15:22:15 UTC)

Made imglab halt at a convenient place when you are using ctrl+key up/down to auto label boxes. It will also auto-skip empty images when you hold ctrl.

Modified
tools/imglab/src/metadata_editor.cpp
Revision: 7441a5d04a3e92ab
Author: Davis King
Date: Feb 11, 2014 (15:19:57 UTC)

Made --stats print out info on unlabeled boxes.

Modified
tools/imglab/src/main.cpp
Revision: 76d8449fcd027cf3
Author: Davis King
Date: Feb 11, 2014 (14:03:08 UTC)

Gave imglab the ability to propagate rectangle labels between images.

Modified
tools/imglab/src/metadata_editor.cpp
Revision: 95958e857ebf763f
Author: Davis King
Date: Feb 11, 2014 (12:58:57 UTC)

clarified spec

Modified
dlib/gui_widgets/widgets_abstract.h
Revision: 1bc75d84164c336b
Author: Davis King
Date: Feb 10, 2014 (15:49:15 UTC)

Fixed weird rectangle highlighting behavior from previous commit.

Modified
dlib/gui_widgets/widgets.h
Revision: 37556c2377562b2c
Author: Davis King
Date: Feb 10, 2014 (15:40:24 UTC)

Updated version number and about string to say that you can now ctrl+left click to change the label for a rectangle.

Modified
tools/imglab/src/main.cpp
tools/imglab/src/metadata_editor.cpp
Revision: 6a020b87ee4cd65e
Author: Davis King
Date: Feb 10, 2014 (15:39:53 UTC)

Now you can ctrl+left click on a rectangle in the image_display to change its label.

Modified
dlib/gui_widgets/widgets.cpp
dlib/gui_widgets/widgets.h
dlib/gui_widgets/widgets_abstract.h
Revision: 1cc259b408a9263e
Author: Davis King
Date: Feb 10, 2014 (15:28:52 UTC)

Fixed spelling errors in spec

Modified
dlib/timer/timer_abstract.h
Revision: 585c2a268b539612
Author: Davis King
Date: Feb 10, 2014 (14:24:15 UTC)

made test more robust

Modified
dlib/test/svm_multiclass_linear.cpp
Revision: e3545570e6e01182
Author: Davis King
Date: Feb 10, 2014 (13:31:52 UTC)

Added another #include to avoid a compile time error on Mac OS X 10.9.1 with gcc 4.8.

Modified
dlib/dir_nav/dir_nav_kernel_2.h
Revision: e4c102d2195635d5
Author: Lukas
Date: Feb 10, 2014 (15:19:46 UTC)

Prevent static assert for set_size on gradient in compute_nuclear_norm_parts()

Modified
dlib/svm/structural_svm_problem.h
Revision: 519fa9f7f776e591
Author: Davis King
Date: Feb 09, 2014 (16:26:42 UTC)

Added code to test the oca interface with a prior vector.

Modified
dlib/test/oca.cpp
Revision: 2cb71d1dbbf57f61
Author: Davis King
Date: Feb 09, 2014 (16:17:33 UTC)

The oca solver now supports taking a user supplied prior vector. That is, it lets you use a regularizer like ||w-prior||^2 instead of the usual ||w||^2 regularizer.

Modified
dlib/optimization/optimization_oca.h
dlib/optimization/optimization_oca_abstract.h
Revision: 041573d020004349
Author: Davis King
Date: Feb 09, 2014 (13:51:30 UTC)

Renamed one of the unit tests functions because it was often an auto-completion based on ctags, which is annoying.

Modified
dlib/test/svm.cpp
Revision: c8c2415f3fd8cd00
Author: Davis King
Date: Feb 09, 2014 (08:23:44 UTC)

Added face detection python example

Added
python_examples/face_detector.py
Revision: fd4a23c10b96951b
Author: Davis King
Date: Feb 09, 2014 (07:56:35 UTC)

Added a python interface to the fhog_object_detector and related tools.

Modified
tools/python/CMakeLists.txt
tools/python/src/dlib.cpp
Added
tools/python/src/object_detection.cpp
Revision: d99a47677ddea891
Author: Davis King
Date: Feb 09, 2014 (07:56:13 UTC)

Added tools for interfacing with python images.

Modified
dlib/python.h
Added
dlib/python/numpy_image.h
Revision: 1eb0b15b9d4c5a97
Author: Davis King
Date: Feb 09, 2014 (05:25:59 UTC)

A minor change to ensure the load() function can load objects like the cv_image.

Modified
dlib/image_processing/scan_fhog_pyramid.h
Revision: 4e6fb2fbfa351bd7
Author: Davis King
Date: Feb 08, 2014 (12:48:33 UTC)

Fixed compiler error in assert statement

Modified
dlib/geometry/rectangle.h
Revision: 2a8a350b79588531
Author: Davis King
Date: Feb 08, 2014 (12:46:35 UTC)

Clarified the spec for extract_image_chips() and also made it so the user can explicitly specify the dimensions of the extracted chips.

Modified
dlib/image_transforms/interpolation.h
dlib/image_transforms/interpolation_abstract.h
Revision: 9520bb111a7709f0
Author: Davis King
Date: Feb 08, 2014 (12:44:34 UTC)

Added tile_images()

Modified
dlib/image_transforms/draw.h
dlib/image_transforms/draw_abstract.h
Revision: 564c2ee863a5e29c
Author: Davis King
Date: Feb 08, 2014 (11:52:47 UTC)

Added set_aspect_ratio()

Modified
dlib/geometry/rectangle.h
dlib/geometry/rectangle_abstract.h
Revision: 0585aed1c27c4eee
Author: Davis King
Date: Feb 06, 2014 (18:03:35 UTC)

Added some functions for converting a numpy array into a pointer and its dimensions.

Added
dlib/python/numpy.h
Revision: 23ccf88244d576d9
Author: Davis King
Date: Feb 05, 2014 (13:16:11 UTC)

Fixed awkward wording

Modified
examples/fhog_object_detector_ex.cpp
Revision: 7d2f93198a744145
Author: Davis King
Date: Feb 03, 2014 (15:34:38 UTC)

Added code that will cause the user to get a linker error if they violate the one definition rule with inconsistent assert enabling.

Modified
dlib/threads/threads_kernel_shared.cpp
dlib/threads/threads_kernel_shared.h
Revision: 5ab454d77711d58c
Author: Davis King
Date: Feb 01, 2014 (11:19:11 UTC)

Gave pinv() an optional tolerance option.

Modified
dlib/matrix/matrix_la.h
dlib/matrix/matrix_la_abstract.h
dlib/test/matrix.cpp
Revision: 6abba8a446dde6a7
Author: Davis King
Date: Feb 01, 2014 (11:07:05 UTC)

Fixed typo in assert that prevented it from compiling

Modified
dlib/svm/kkmeans.h
Revision: 23712cb477b304be
Author: Davis King
Date: Feb 01, 2014 (11:06:37 UTC)

Fixed a compile time bug that happened with gcc when DEBUG was #defined but not ENABLE_ASSERTS.

Modified
dlib/image_transforms/interpolation.h
Revision: dc9456766f09cec8
Author: Davis King
Date: Jan 28, 2014 (16:27:21 UTC)

The stopping condition for the svr_linear_trainer was too tight when there were a lot of samples, causing it to take an excessive amount of time to converge in some cases. This fixes it.

Modified
dlib/svm/svr_linear_trainer.h
dlib/test/svr_linear_trainer.cpp
Revision: 34f5a02eb11a5d47
Author: Davis King
Date: Jan 27, 2014 (12:56:19 UTC)

Made the asserts that checks if the inputs to the optimization functions are column vectors always enabled since violating this is a common user error.

Modified
dlib/optimization/optimization.h
Revision: 124ec98152fc5f17
Author: Davis King
Date: Jan 26, 2014 (14:51:10 UTC)

Added another overload of extract_fhog_features(). This one returns the features as a column vector but by reference instead of by value.

Modified
dlib/image_transforms/fhog.h
dlib/image_transforms/fhog_abstract.h
Revision: 9da6ebf44f6e88b4
Author: Davis King
Date: Jan 26, 2014 (14:33:43 UTC)

Clarified spec

Modified
dlib/data_io/load_image_dataset_abstract.h
Revision: 756547958d1b74d2
Author: Davis King
Date: Jan 26, 2014 (14:24:39 UTC)

Added add_image_rotations() and also made add_image_left_right_flips() work with full_object_detection objects in addition to rectangles.

Modified
dlib/image_transforms/interpolation.h
dlib/image_transforms/interpolation_abstract.h
Revision: 91a44c594fc7d0bd
Author: Davis King
Date: Jan 26, 2014 (11:42:10 UTC)

Refactored the load_image_dataset() routines so they are easier to use and more flexible. This introduces a slight backwards incompatibility in that the version that loads full_object_detection objects now returns an ignore rectangle set instead of a parts name list. But other than that the changes are backwards compatible with previous version of dlib.

Modified
dlib/data_io/load_image_dataset.h
dlib/data_io/load_image_dataset_abstract.h
Revision: 62f2baa01d2fad29
Author: Davis King
Date: Jan 23, 2014 (17:17:09 UTC)

Added another constructor to object_detector that makes it easy to combine multiple detectors together.

Modified
dlib/image_processing/object_detector.h
dlib/image_processing/object_detector_abstract.h
Revision: e29e01120438f213
Author: Davis King
Date: Jan 19, 2014 (16:06:27 UTC)

Added a value_type typedef to the array object.

Modified
dlib/array/array_kernel.h
dlib/array/array_kernel_abstract.h
Revision: 6159d6e667d28bb2
Author: Davis King
Date: Jan 19, 2014 (10:45:05 UTC)

Minor code cleanup

Modified
dlib/data_io/load_image_dataset.h
Revision: b533669e21fc2004
Author: Davis King
Date: Jan 19, 2014 (07:40:54 UTC)

Added an overload of pick_initial_centers() that uses the linear kernel when no other kernel is specified by the user.

Modified
dlib/svm/kkmeans.h
dlib/svm/kkmeans_abstract.h
Revision: bdd5e8df2134f7a7
Author: Davis King
Date: Jan 19, 2014 (06:32:31 UTC)

Added nearest_center()

Modified
dlib/svm/kkmeans.h
dlib/svm/kkmeans_abstract.h
Revision: c648719ee557e1a3
Author: Davis King
Date: Jan 12, 2014 (09:15:19 UTC)

Clarified spec

Modified
dlib/image_transforms/interpolation_abstract.h
Revision: b8ab5b542788b04f
Author: Davis King
Date: Jan 12, 2014 (08:37:15 UTC)

Added an overload of extract_fhog_features() that returns a single column vector represented using a matrix.

Modified
dlib/image_transforms/fhog.h
dlib/image_transforms/fhog_abstract.h
Revision: 094cf692f8df3389
Author: Davis King
Date: Jan 12, 2014 (08:20:35 UTC)

Made dlib::array usable in C++11 range based for loops by adding begin() and end() methods.

Modified
dlib/array/array_kernel.h
dlib/array/array_kernel_abstract.h
Revision: 26acd113ed2c7896
Author: Davis King
Date: Jan 12, 2014 (05:15:46 UTC)

fixed grammar

Modified
examples/bsp_ex.cpp
Revision: fb385cd6a0168f86
Author: Davis King
Date: Jan 11, 2014 (17:40:43 UTC)

clarified examples

Modified
examples/face_detection_ex.cpp
examples/fhog_object_detector_ex.cpp
Revision: 52b9e4a41042242b
Author: Davis King
Date: Jan 11, 2014 (13:16:31 UTC)

Made the box overlap testing stuff a little more robust to differences in floating point behavior on different compilers. In particular, this change avoids having false "impossible truth box" exceptions being thrown when the object detection tools are used with the mingw gcc compiler.

Modified
dlib/image_processing/box_overlap_testing.h
Revision: e11233cc87df0fa3
Author: Davis King
Date: Jan 11, 2014 (12:46:00 UTC)

Fixed file load bug related to dealing with relative paths correctly. The bug prevented the load_image_dataset() routine from working on Windows systems in some cases.

Modified
dlib/data_io/load_image_dataset.h
Revision: 1aeace9f1948dace
Author: Davis King
Date: Jan 11, 2014 (12:14:15 UTC)

Changed cmake settings so it doesn't try to use the intel MKL when using mingw.

Modified
dlib/cmake_find_blas.txt
Revision: bb23a5b866f8b429
Author: Davis King
Date: Jan 11, 2014 (11:42:50 UTC)

Another minor change to avoid warnings from visual studio

Modified
dlib/test/graph_cuts.cpp
Revision: 8c5b3e283a30376b
Author: Davis King
Date: Jan 11, 2014 (10:58:24 UTC)

Added a cast to avoid a warning from visual studio 2013

Modified
dlib/graph_utils/edge_list_graphs.h
Revision: 0a101fb1782dd828
Author: Davis King
Date: Jan 11, 2014 (10:42:26 UTC)

normalized line endings so visual studio won't complain.

Modified
dlib/external/zlib/gzguts.h
Revision: c6a7ce6b04628bb9
Author: Davis King
Date: Jan 11, 2014 (09:52:28 UTC)

clarified example

Modified
examples/matrix_ex.cpp
Revision: 46402d1f8943bb9a
Author: Davis King
Date: Jan 11, 2014 (06:30:52 UTC)

clarified example

Modified
examples/fhog_object_detector_ex.cpp
Revision: 4690ca9c36444a19
Author: Davis King
Date: Jan 11, 2014 (05:40:39 UTC)

Clarified examples now that we have more object detectors in the library.

Modified
examples/object_detector_advanced_ex.cpp
examples/object_detector_ex.cpp
Revision: 522574cf87f8138b
Author: Davis King
Date: Jan 09, 2014 (18:23:04 UTC)

clarified example

Modified
examples/fhog_object_detector_ex.cpp
Revision: 131adf5f6cce6912
Author: Davis King
Date: Jan 09, 2014 (18:19:44 UTC)

improved example program documentation

Modified
examples/face_detection_ex.cpp
examples/fhog_object_detector_ex.cpp
Revision: a44f91155aac21b1
Author: Davis King
Date: Jan 09, 2014 (17:15:17 UTC)

Added a readme file to imglab that gives a little introduction

Added
tools/imglab/README.txt
Revision: 3f0e1523a682b84e
Author: Davis King
Date: Jan 06, 2014 (15:12:05 UTC)

Added a version of draw_rectangle() that can draw directly onto an array2d.

Modified
dlib/image_transforms/draw.h
dlib/image_transforms/draw_abstract.h
Revision: e288170ba90ad1db
Author: Davis King
Date: Jan 06, 2014 (14:38:47 UTC)

Fixed a typo

Modified
dlib/svm/structural_svm_problem.h
Revision: af64219c6a850af2
Author: Davis King
Date: Jan 05, 2014 (15:01:49 UTC)

Slightly improved example. Still needs a lot of work though.

Modified
examples/fhog_object_detector_ex.cpp
Revision: e3893db828598901
Author: Davis King
Date: Jan 05, 2014 (13:58:29 UTC)

Made the CMakeLists.txt file build dlib by compiling its individual .cpp files instead of compiling the all/source.cpp file since this results in smaller binaries in many cases and also sometimes improves compilation speed.

Modified
dlib/CMakeLists.txt
Revision: 6477bf8dec767f4c
Author: Davis King
Date: Jan 05, 2014 (13:45:08 UTC)

Fixed some #include problems so the library can be compiled by compiling its individual .cpp files instead of the single large all/source.cpp file.

Modified
dlib/sockets/sockets_extensions.cpp
dlib/threads/multithreaded_object_extension.cpp
dlib/threads/multithreaded_object_extension.h
dlib/threads/rsignaler_extension.h
dlib/threads/thread_pool_extension.h
dlib/tokenizer/tokenizer_kernel_1.cpp
Revision: 7e358ff614b1ba2d
Author: Davis King
Date: Jan 05, 2014 (12:57:39 UTC)

Made test a little more robust

Modified
dlib/test/optimization.cpp
Revision: 28d27038a07859db
Author: Davis King
Date: Jan 05, 2014 (12:11:56 UTC)

Made the stopping condition for the structural svm solver a little more robust.

Modified
dlib/svm/structural_svm_problem.h
Revision: 16ad689154ec11b6
Author: Davis King
Date: Jan 05, 2014 (08:53:21 UTC)

Added comments to this example program

Modified
examples/face_detection_ex.cpp
Revision: 51f8ea15b68ebca9
Author: Davis King
Date: Jan 05, 2014 (08:38:59 UTC)

Made the SIMD options work with the Intel compiler

Modified
dlib/cmake
Revision: cc63059d44e5cc7c
Author: Davis King
Date: Jan 04, 2014 (13:13:47 UTC)

Fixed a bug in the bigint object that caused division to sometimes produce incorrect results.

Modified
dlib/bigint/bigint_kernel_1.cpp
dlib/bigint/bigint_kernel_2.cpp
dlib/test/bigint.cpp
Revision: 56d881385b512f65
Author: Davis King
Date: Jan 04, 2014 (05:08:09 UTC)

suppressed more bogus warnings from gcc 4.8

Modified
dlib/matrix/matrix_assign_fwd.h
Revision: 17d50531cdca611d
Author: Davis King
Date: Jan 02, 2014 (16:14:48 UTC)

When using visual studio, made cmake only show the supported SSE options.

Modified
dlib/cmake
Revision: 3e23a6848980cb83
Author: Davis King
Date: Jan 02, 2014 (15:53:28 UTC)

Added face detection example program

Modified
examples/CMakeLists.txt
Added
examples/face_detection_ex.cpp
Revision: 8297d64a159d7168
Author: Davis King
Date: Jan 02, 2014 (14:57:59 UTC)

Suppressed some spurious warnings from gcc 4.8

Modified
dlib/matrix/matrix_data_layout.h
dlib/test/optimization_test_functions.h
Revision: 76e758554110ac0b
Author: Davis King
Date: Jan 02, 2014 (13:49:05 UTC)

Added comments about the source of the face images

Modified
examples/faces/testing.xml
examples/faces/training.xml
Revision: 3cbeb8ba0fa137b9
Author: Davis King
Date: Jan 02, 2014 (15:46:46 UTC)

Improved the automatic selction of different SIMD instructions sets in visual studio.

Modified
dlib/cmake
dlib/simd/simd_check.h
Revision: edf6b9e5b9c1e30f
Author: Davis King
Date: Jan 02, 2014 (13:40:19 UTC)

Added casts to avoid compiler warnings in visual studio 2013

Modified
dlib/external/libjpeg/jmemmgr.cpp
Revision: bce55e5f3283e026
Author: Davis King
Date: Jan 02, 2014 (07:28:45 UTC)

Made the cmake option for using SSE4 work with visual studio.

Modified
dlib/cmake
Revision: cd40276c677e2d08
Author: Davis King
Date: Jan 02, 2014 (07:10:00 UTC)

Made the default cmake settings enable SSE2 instructions when using Visual Studio.

Modified
dlib/cmake
Revision: 355f5dab11b8f8fd
Author: Davis King
Date: Jan 02, 2014 (07:01:03 UTC)

Added cmake options to easily turn SSE/AVX instructions on/off

Modified
dlib/cmake
Revision: 7d5b348b45f547cf
Author: Davis King
Date: Apr 22, 2013 (-01:47:10 UTC)

Relaxed tests slightly to avoid false alarms.

Modified
dlib/test/geometry.cpp
Revision: 0d729ef5d45ed288
Author: Davis King
Date: Jan 02, 2014 (04:41:53 UTC)

fixed grammar

Modified
dlib/svm/structural_object_detection_trainer_abstract.h
Revision: 790fb5e87d930bd6
Author: Davis King
Date: Jan 02, 2014 (04:32:39 UTC)

A minor change to avoid compiler warnings from gcc 4.1. It also makes the code slightly faster.

Modified
dlib/image_transforms/fhog.h
Revision: 6964496c6be9f368
Author: Davis King
Date: Jan 02, 2014 (04:22:10 UTC)

Changed SIMD #includes so they work on older versions of gcc

Modified
dlib/simd/simd_check.h
Revision: 376a21b80e0a0776
Author: Davis King
Date: Jan 01, 2014 (17:58:02 UTC)

updated specs

Modified
dlib/svm/structural_object_detection_trainer_abstract.h
dlib/svm/structural_svm_object_detection_problem_abstract.h
Revision: 18907b5101091d00
Author: Davis King
Date: Jan 01, 2014 (14:12:06 UTC)

Added skeleton of fhog object detection example.

Modified
examples/CMakeLists.txt
Added
examples/faces/2007_007763.jpg
examples/faces/2008_001009.jpg
examples/faces/2008_001322.jpg
examples/faces/2008_002079.jpg
examples/faces/2008_002470.jpg
examples/faces/2008_002506.jpg
examples/faces/2008_004176.jpg
examples/faces/2008_007676.jpg
examples/faces/2009_004587.jpg
examples/faces/image_metadata_stylesheet.xsl
examples/faces/testing.xml
examples/faces/training.xml
examples/fhog_object_detector_ex.cpp
Revision: 42ed57efdb6b4a42
Author: Davis King
Date: Jan 01, 2014 (10:45:34 UTC)

Changed the default stopping epsilon from 0.3 to 0.1.

Modified
dlib/svm/structural_object_detection_trainer.h
dlib/svm/structural_object_detection_trainer_abstract.h
Revision: 652a2e71a230e499
Author: Davis King
Date: Jan 01, 2014 (10:03:53 UTC)

Made the image_dataset_metadata::box constructable from a rectangle.

Modified
dlib/data_io/image_dataset_metadata.h
Revision: 53c33db106ab9ad2
Author: Davis King
Date: Jan 01, 2014 (09:14:53 UTC)

Made many of the mat() converters bind the resulting matrix expressions into the BLAS bindings.

Modified
dlib/matrix/matrix_assign.h
dlib/matrix/matrix_blas_bindings.h
dlib/test/blas_bindings/blas_bindings_dot.cpp
dlib/test/blas_bindings/blas_bindings_gemm.cpp
Revision: f0414b18588467d2
Author: Davis King
Date: Jan 01, 2014 (08:59:58 UTC)

Fixed compiler error due to missing )

Modified
dlib/image_transforms/interpolation.h
Revision: 7e0a326ee908cc72
Author: Davis King
Date: Jan 01, 2014 (07:11:43 UTC)

A minor change to avoid compiler errors when serializing mlp objects.

Modified
dlib/mlp/mlp_kernel_1.h
Revision: 22264a71556b9a59
Author: Davis King
Date: Dec 27, 2013 (12:29:40 UTC)

Made directory and file printable with operator <<

Modified
dlib/dir_nav/dir_nav_kernel_1.h
dlib/dir_nav/dir_nav_kernel_2.h
dlib/dir_nav/dir_nav_kernel_abstract.h
Revision: 642adc773d8be26d
Author: Davis King
Date: Dec 27, 2013 (09:05:39 UTC)

Added an angle field to image_dataset_metadata

Modified
dlib/data_io/image_dataset_metadata.cpp
dlib/data_io/image_dataset_metadata.h
Revision: 68ece4c13644f8bf
Author: Davis King
Date: Dec 27, 2013 (08:50:22 UTC)

Added extract_image_chips()

Modified
dlib/image_transforms/interpolation.h
dlib/image_transforms/interpolation_abstract.h
Revision: 057700fa78fa44ed
Author: Davis King
Date: Dec 27, 2013 (06:59:12 UTC)

Minor changes to avoid compiler warnings from gcc in some cases

Modified
dlib/assert.h
dlib/logger/logger_kernel_1.h
dlib/uintn.h
Revision: 9546792a96052e93
Author: Davis King
Date: Dec 27, 2013 (06:58:48 UTC)

Added std:: qualifiers to avoid compiler errors in some situations

Modified
dlib/bigint/bigint_kernel_2.cpp
Revision: b7a22dad21adb038
Author: Davis King
Date: Dec 25, 2013 (02:21:13 UTC)

A minor change to avoid compiler warnings from gcc

Modified
dlib/image_transforms/interpolation.h
Revision: dd0920ba0666bea8
Author: Davis King
Date: Dec 23, 2013 (11:25:46 UTC)

- Made flip_image_left_right() return a point_transform_affine object that describes the exact transformation used. - Fixed a bug in rotate_image(), it returned a point_transform_affine object that did the opposite of what the specification said it returns.

Modified
dlib/image_transforms/interpolation.h
dlib/image_transforms/interpolation_abstract.h
Revision: 44a9c6f12695f050
Author: Davis King
Date: Dec 11, 2013 (17:42:55 UTC)

Added an overload of overlaps_any_box() that uses a default test_box_overlap object.

Modified
dlib/image_processing/box_overlap_testing.h
dlib/image_processing/box_overlap_testing_abstract.h
Revision: d3b04fef18d755e4
Author: Davis King
Date: Dec 09, 2013 (16:11:09 UTC)

Added get_frontal_face_detector()

Added
dlib/image_processing/frontal_face_detector.h
dlib/image_processing/frontal_face_detector_abstract.h
Revision: c0981f323171b400
Author: Davis King
Date: Dec 08, 2013 (05:51:21 UTC)

Clarified spec

Modified
dlib/image_processing/scan_fhog_pyramid_abstract.h
Revision: b4f32d46f1f72789
Author: Davis King
Date: Dec 08, 2013 (05:50:13 UTC)

Changed requires clause slightly to increase usability.

Modified
dlib/image_processing/scan_fhog_pyramid.h
dlib/image_processing/scan_fhog_pyramid_abstract.h
Revision: 2acd4397daf7a69d
Author: Davis King
Date: Dec 08, 2013 (05:46:51 UTC)

Added threshold_filter_singular_values()

Modified
dlib/image_processing/scan_fhog_pyramid.h
dlib/image_processing/scan_fhog_pyramid_abstract.h
Revision: 7c66dc8bb487caa3
Author: Davis King
Date: Dec 07, 2013 (06:52:07 UTC)

Made the spatial filtering functions always center their filters over the output pixel exactly the same way as defined by centered_rect().

Modified
dlib/image_processing/scan_fhog_pyramid.h
dlib/image_transforms/spatial_filtering.h
dlib/image_transforms/spatial_filtering_abstract.h
dlib/test/image.cpp
Revision: abfdfa9bb75abcde
Author: Davis King
Date: Dec 06, 2013 (14:48:40 UTC)

fixed some typos

Modified
dlib/image_transforms/spatial_filtering_abstract.h
Revision: f307c7650a99c4a5
Author: Davis King
Date: Dec 05, 2013 (18:29:35 UTC)

Another minor thing to avoid warnings from visual studio.

Modified
dlib/external/zlib/gzguts.h
Revision: 4be08365aee0913f
Author: Davis King
Date: Dec 04, 2013 (16:07:18 UTC)

Added missing #include (needed only to avoid gcc warnings)

Modified
dlib/external/zlib/gzguts.h
Revision: de125919e39e6101
Author: Davis King
Date: Dec 04, 2013 (13:34:45 UTC)

Minor changes to avoid conflicts and warnings in visual studio.

Modified
dlib/external/libjpeg/jmorecfg.h
dlib/external/libpng/pngconf.h
Revision: cf090531e6f6ffaa
Author: Davis King
Date: Dec 04, 2013 (13:30:08 UTC)

Just removed some typedefs because they cause name conflicts in visual studio 2010. So I just replaced the uses of the typedef with the actual type.

Modified
dlib/external/libjpeg/jdapimin.cpp
dlib/external/libjpeg/jdapistd.cpp
dlib/external/libjpeg/jdatasrc.cpp
dlib/external/libjpeg/jdcoefct.cpp
dlib/external/libjpeg/jdcolor.cpp
dlib/external/libjpeg/jdct.h
dlib/external/libjpeg/jddctmgr.cpp
dlib/external/libjpeg/jdhuff.cpp
dlib/external/libjpeg/jdhuff.h
dlib/external/libjpeg/jdinput.cpp
dlib/external/libjpeg/jdmainct.cpp
dlib/external/libjpeg/jdmarker.cpp
dlib/external/libjpeg/jdmaster.cpp
dlib/external/libjpeg/jdmerge.cpp
dlib/external/libjpeg/jdphuff.cpp
dlib/external/libjpeg/jdpostct.cpp
dlib/external/libjpeg/jdsample.cpp
dlib/external/libjpeg/jerror.cpp
dlib/external/libjpeg/jidctflt.cpp
dlib/external/libjpeg/jidctfst.cpp
dlib/external/libjpeg/jidctint.cpp
dlib/external/libjpeg/jidctred.cpp
dlib/external/libjpeg/jmemmgr.cpp
dlib/external/libjpeg/jmorecfg.h
dlib/external/libjpeg/jpegint.h
dlib/external/libjpeg/jpeglib.h
dlib/external/libjpeg/jquant1.cpp
dlib/external/libjpeg/jquant2.cpp
Revision: 8a91f5e1038dd8e2
Author: Davis King
Date: Dec 03, 2013 (17:51:11 UTC)

Just removed unused variable names to avoid warnings from gcc.

Modified
dlib/external/libjpeg/jdatasrc.cpp
dlib/external/libjpeg/jdcoefct.cpp
dlib/external/libjpeg/jdcolor.cpp
dlib/external/libjpeg/jdmerge.cpp
dlib/external/libjpeg/jdpostct.cpp
dlib/external/libjpeg/jdsample.cpp
dlib/external/libjpeg/jmemnobs.cpp
dlib/external/libjpeg/jquant1.cpp
dlib/external/libjpeg/jquant2.cpp
Revision: 1bd04084d98c0c57
Author: Davis King
Date: Dec 03, 2013 (17:44:47 UTC)

Added a copy of libpng and zlib that will be statically compiled in if no dynamic version of these libraries are installed on the system.

Modified
dlib/CMakeLists.txt
Added
dlib/external/libpng/LICENSE
dlib/external/libpng/README
dlib/external/libpng/png.c
dlib/external/libpng/png.h
dlib/external/libpng/pngconf.h
dlib/external/libpng/pngdebug.h
dlib/external/libpng/pngerror.c
dlib/external/libpng/pngget.c
dlib/external/libpng/pnginfo.h
dlib/external/libpng/pnglibconf.h
dlib/external/libpng/pngmem.c
dlib/external/libpng/pngpread.c
dlib/external/libpng/pngpriv.h
dlib/external/libpng/pngread.c
dlib/external/libpng/pngrio.c
dlib/external/libpng/pngrtran.c
dlib/external/libpng/pngrutil.c
dlib/external/libpng/pngset.c
dlib/external/libpng/pngstruct.h
dlib/external/libpng/pngtrans.c
dlib/external/libpng/pngwio.c
dlib/external/libpng/pngwrite.c
dlib/external/libpng/pngwtran.c
dlib/external/libpng/pngwutil.c
dlib/external/zlib/README
dlib/external/zlib/adler32.c
dlib/external/zlib/compress.c
dlib/external/zlib/crc32.c
dlib/external/zlib/crc32.h
dlib/external/zlib/deflate.c
dlib/external/zlib/deflate.h
dlib/external/zlib/gzclose.c
dlib/external/zlib/gzguts.h
dlib/external/zlib/gzlib.c
dlib/external/zlib/gzread.c
dlib/external/zlib/gzwrite.c
dlib/external/zlib/infback.c
dlib/external/zlib/inffast.c
dlib/external/zlib/inffast.h
dlib/external/zlib/inffixed.h
dlib/external/zlib/inflate.c
dlib/external/zlib/inflate.h
dlib/external/zlib/inftrees.c
dlib/external/zlib/inftrees.h
dlib/external/zlib/trees.c
dlib/external/zlib/trees.h
dlib/external/zlib/uncompr.c
dlib/external/zlib/zconf.h
dlib/external/zlib/zlib.h
dlib/external/zlib/zutil.c
dlib/external/zlib/zutil.h
Revision: 802eac3ab3b982d6
Author: Davis King
Date: Dec 03, 2013 (17:24:14 UTC)

Added a copy of libjpeg so that it can be statically compiled in when cmake can't find a copy to dynamically link to. This is especially useful on windows where cmake never finds libjpeg.

Modified
dlib/CMakeLists.txt
Added
dlib/external/libjpeg/README
dlib/external/libjpeg/jcomapi.cpp
dlib/external/libjpeg/jconfig.h
dlib/external/libjpeg/jdapimin.cpp
dlib/external/libjpeg/jdapistd.cpp
dlib/external/libjpeg/jdatasrc.cpp
dlib/external/libjpeg/jdcoefct.cpp
dlib/external/libjpeg/jdcolor.cpp
dlib/external/libjpeg/jdct.h
dlib/external/libjpeg/jddctmgr.cpp
dlib/external/libjpeg/jdhuff.cpp
dlib/external/libjpeg/jdhuff.h
dlib/external/libjpeg/jdinput.cpp
dlib/external/libjpeg/jdmainct.cpp
dlib/external/libjpeg/jdmarker.cpp
dlib/external/libjpeg/jdmaster.cpp
dlib/external/libjpeg/jdmerge.cpp
dlib/external/libjpeg/jdphuff.cpp
dlib/external/libjpeg/jdpostct.cpp
dlib/external/libjpeg/jdsample.cpp
dlib/external/libjpeg/jerror.cpp
dlib/external/libjpeg/jerror.h
dlib/external/libjpeg/jidctflt.cpp
dlib/external/libjpeg/jidctfst.cpp
dlib/external/libjpeg/jidctint.cpp
dlib/external/libjpeg/jidctred.cpp
dlib/external/libjpeg/jinclude.h
dlib/external/libjpeg/jmemmgr.cpp
dlib/external/libjpeg/jmemnobs.cpp
dlib/external/libjpeg/jmemsys.h
dlib/external/libjpeg/jmorecfg.h
dlib/external/libjpeg/jpegint.h
dlib/external/libjpeg/jpeglib.h
dlib/external/libjpeg/jquant1.cpp
dlib/external/libjpeg/jquant2.cpp
dlib/external/libjpeg/jutils.cpp
dlib/external/libjpeg/jversion.h
Revision: cf6ab8b9d7ea23bf
Author: Davis King
Date: Dec 01, 2013 (12:17:50 UTC)

Made the SIMD code automatically pick which kind of instructions to use when compiled in visual studio based on the setting of the /arch compiler option.

Modified
dlib/simd/simd_check.h
Revision: e8d055fae5a42554
Author: Davis King
Date: Dec 01, 2013 (11:27:14 UTC)

Made all the simd functions explicitly inline because otherwise visual studio 2010 won't inline them.

Modified
dlib/simd/simd4f.h
dlib/simd/simd4i.h
dlib/simd/simd8f.h
dlib/simd/simd8i.h
Revision: d739b9efb795d6b8
Author: Davis King
Date: Dec 01, 2013 (10:55:48 UTC)

Added convenience overloads of pyramid_up() that work in place.

Modified
dlib/image_transforms/interpolation.h
dlib/image_transforms/interpolation_abstract.h
Revision: 39d2054775c8e50d
Author: Davis King
Date: Dec 01, 2013 (10:15:14 UTC)

Added flip_image_dataset_left_right(), upsample_image_dataset(), and rotate_image_dataset().

Modified
dlib/image_transforms/interpolation.h
dlib/image_transforms/interpolation_abstract.h
Revision: d952f60f061f0cd6
Author: davis
Date: Dec 01, 2013 (08:52:50 UTC)

Some minor changes to avoid compiler errors in cygwin.

Modified
dlib/float_details.h
dlib/statistics/vector_normalizer_frobmetric.h
Revision: c16fe5af00b43869
Author: Davis King
Date: Nov 29, 2013 (17:35:52 UTC)

Added --flip to imglab

Modified
tools/imglab/src/main.cpp
Revision: 5693377797e3a920
Author: Davis King
Date: Nov 29, 2013 (17:35:28 UTC)

Made directory implicitly convertible to string.

Modified
dlib/dir_nav/dir_nav_kernel_1.h
dlib/dir_nav/dir_nav_kernel_2.h
dlib/dir_nav/dir_nav_kernel_abstract.h
Revision: 34d504b3403f1101
Author: Davis King
Date: Nov 29, 2013 (13:21:52 UTC)

Made dlib::file implicitly convertible to std::string.

Modified
dlib/dir_nav/dir_nav_kernel_1.h
dlib/dir_nav/dir_nav_kernel_2.h
dlib/dir_nav/dir_nav_kernel_abstract.h
Revision: f4b522a41b7c9d46
Author: Davis King
Date: Nov 29, 2013 (12:05:38 UTC)

Updated find_max_factor_graph_nmplp() to use the version of the algorithm from the 2011 paper Introduction to dual decomposition for inference by David Sontag, Amir Globerson, and Tommi Jaakkola since the original 2008 paper had an error in the algorithm that negatively effected its convergence. Thanks to James Gunning for pointing this out.

Modified
dlib/optimization/find_max_factor_graph_nmplp.h
dlib/optimization/find_max_factor_graph_nmplp_abstract.h
dlib/test/find_max_factor_graph_nmplp.cpp
Revision: 753fba352b003cac
Author: Davis King
Date: Nov 28, 2013 (-03:51:00 UTC)

Minor changes to avoid compiler errors in visual studio 2013

Modified
dlib/binary_search_tree/binary_search_tree_kernel_c.h
dlib/hash_table/hash_table_kernel_c.h
dlib/map/map_kernel_c.h
dlib/test/geometry.cpp
dlib/test/matrix3.cpp
Revision: 3bcc64a88e3572a7
Author: Davis King
Date: Nov 23, 2013 (15:07:13 UTC)

Fixed a bug in the average precision calculation when ignore boxes were used.

Modified
dlib/svm/cross_validate_object_detection_trainer.h
Revision: e4e514dd2364aa39
Author: Davis King
Date: Nov 23, 2013 (14:55:44 UTC)

Simplified code slightly.

Modified
dlib/svm/structural_svm_object_detection_problem.h
Revision: 466758af9f28e0e1
Author: Davis King
Date: Nov 23, 2013 (14:34:04 UTC)

Made num_separable_filters() work with multi-filter object detectors.

Modified
dlib/image_processing/scan_fhog_pyramid.h
dlib/image_processing/scan_fhog_pyramid_abstract.h
Revision: 3374e51835de3312
Author: Davis King
Date: Nov 23, 2013 (10:48:02 UTC)

Slightly changed code to reduce the number of memory allocations made during object detection.

Modified
dlib/image_processing/scan_fhog_pyramid.h
Revision: 673411884e727e19
Author: Davis King
Date: Nov 23, 2013 (10:47:32 UTC)

Added float_spatially_filter_image_separable() to the public API.

Modified
dlib/image_transforms/spatial_filtering.h
dlib/image_transforms/spatial_filtering_abstract.h
Revision: eb788258b9e114c9
Author: Davis King
Date: Nov 23, 2013 (09:20:47 UTC)

Added support for ignore rectangles into the object detection testing functions. I also changed the interfaces to these functions slightly. Instead of taking a double that determines how we decide if boxes match, they now take a test_box_overlap object.

Modified
dlib/svm/cross_validate_object_detection_trainer.h
dlib/svm/cross_validate_object_detection_trainer_abstract.h
Revision: 37aee00946645335
Author: Davis King
Date: Nov 23, 2013 (06:49:45 UTC)

Set a default value for the second argument of test_box_overlap's constructor. Also added overlaps_any_box().

Modified
dlib/image_processing/box_overlap_testing.h
dlib/image_processing/box_overlap_testing_abstract.h
Revision: 047db3b92a03e8c4
Author: Davis King
Date: Nov 22, 2013 (15:07:12 UTC)

Changed the default parameters of the test_box_overlap object. Now it defaults to using exactly the PASCAL VOC match criterion.

Modified
dlib/image_processing/box_overlap_testing.h
dlib/image_processing/box_overlap_testing_abstract.h
Revision: b1bcc86f42106970
Author: Davis King
Date: Nov 22, 2013 (14:05:52 UTC)

A minor change to avoid compiler warnings.

Modified
dlib/image_processing/scan_fhog_pyramid.h
dlib/image_processing/scan_fhog_pyramid_abstract.h
Revision: 125a6942d97a25d5
Author: Davis King
Date: Nov 22, 2013 (13:45:06 UTC)

Updated about window text for imglab.

Modified
tools/imglab/src/metadata_editor.cpp
Revision: dfe4192fef912d82
Author: Davis King
Date: Nov 21, 2013 (18:20:23 UTC)

Added an overload of add_image_left_right_flips() that can take two sets of rectangles instead of just one.

Modified
dlib/image_transforms/interpolation.h
dlib/image_transforms/interpolation_abstract.h
Revision: ff3d22c6fbd67f7e
Author: Davis King
Date: Nov 21, 2013 (18:14:18 UTC)

Added the option to tell the optimizer there are "ignorable" rectangles in each image.

Modified
dlib/svm/structural_object_detection_trainer.h
dlib/svm/structural_object_detection_trainer_abstract.h
dlib/svm/structural_svm_object_detection_problem.h
dlib/svm/structural_svm_object_detection_problem_abstract.h
Revision: dce9ad48d6cf341b
Author: Davis King
Date: Nov 21, 2013 (17:15:36 UTC)

Upgraded load_image_dataset() so that it returns the list of ignored rectangles.

Modified
dlib/data_io/load_image_dataset.h
dlib/data_io/load_image_dataset_abstract.h
Revision: 80c7c5f55243174e
Author: Davis King
Date: Nov 21, 2013 (15:40:12 UTC)

Updated imglab so it loads and stores the new ignore option from the gui to/from the xml files.

Modified
tools/imglab/src/metadata_editor.cpp
Revision: 835fcc620b85cbc4
Author: Davis King
Date: Nov 21, 2013 (15:39:12 UTC)

Added an ignore option to the image dataset metadata file format.

Modified
dlib/data_io/image_dataset_metadata.cpp
dlib/data_io/image_dataset_metadata.h
Revision: 74510960ba9426b0
Author: Davis King
Date: Nov 21, 2013 (15:38:45 UTC)

Added the option to draw crossed out rectangles onto the image_display widget.

Modified
dlib/gui_widgets/widgets.cpp
dlib/gui_widgets/widgets.h
dlib/gui_widgets/widgets_abstract.h
Revision: c806d21d0d8a121c
Author: Davis King
Date: Nov 21, 2013 (14:45:17 UTC)

Made the multiclass SVM work with label types other than basic integers and floats.

Modified
dlib/svm/svm_multiclass_linear_trainer.h
Revision: fe3d1dd6e6f4370f
Author: Davis King
Date: Nov 20, 2013 (15:29:26 UTC)

Upgraded the object_detector. Now it can store multiple weight vectors and hence multiple object detectors.

Modified
dlib/image_processing/object_detector.h
dlib/image_processing/object_detector_abstract.h
dlib/image_processing/scan_fhog_pyramid.h
dlib/image_processing/scan_fhog_pyramid_abstract.h
Revision: f1ad98b50ace5c07
Author: Davis King
Date: Nov 19, 2013 (18:57:41 UTC)

Fixed off by one bug in resize_image()

Modified
dlib/image_transforms/interpolation.h
Revision: 854ac31108d2451c
Author: Davis King
Date: Nov 18, 2013 (16:39:58 UTC)

removed cruft

Modified
dlib/image_transforms/spatial_filtering.h
Revision: 3fee313bfd99746d
Author: Davis King
Date: Nov 18, 2013 (16:05:40 UTC)

Changed code a bit so that the scan_fhog_pyramid can avoid constructing the fhog_filterbank each time the detector executes.

Modified
dlib/image_processing/object_detector.h
dlib/image_processing/scan_fhog_pyramid.h
Revision: 46403b72c2ef7a4e
Author: Davis King
Date: Nov 17, 2013 (16:21:08 UTC)

Fixed #include

Modified
dlib/test/data_io.cpp
Revision: ea5f4599078d46a0
Author: Davis King
Date: Nov 17, 2013 (15:26:37 UTC)

fixed #include

Modified
examples/custom_trainer_ex.cpp
Revision: e422fcff21e6af11
Author: Davis King
Date: Nov 17, 2013 (14:29:10 UTC)

merged

Modified
dlib/image_processing/scan_fhog_pyramid.h
Revision: 20ed62023f34056d
Author: Davis King
Date: Nov 17, 2013 (09:45:52 UTC)

Made the test for using the separable vs. non-separable filters scale with the size of the filters being applied.

Modified
dlib/image_processing/scan_fhog_pyramid.h
Revision: 8ffdbf85faa3b7b7
Author: Davis King
Date: Nov 17, 2013 (14:18:52 UTC)

Fixed broken #include

Modified
examples/multiclass_classification_ex.cpp
Revision: 92d6e0f6416a385a
Author: Davis King
Date: Nov 17, 2013 (14:14:35 UTC)

Made the one_vs_one_trainer and one_vs_all_trainer objects multithreaded so they can run each binary trainer on a different core.

Modified
dlib/svm.h
dlib/svm/cross_validate_multiclass_trainer.h
dlib/svm/one_vs_all_trainer.h
dlib/svm/one_vs_all_trainer_abstract.h
dlib/svm/one_vs_one_trainer.h
dlib/svm/one_vs_one_trainer_abstract.h
dlib/svm_threaded.h
dlib/test/one_vs_all_trainer.cpp
dlib/test/one_vs_one_trainer.cpp
Revision: 3cafc38fce97d2ff
Author: Davis King
Date: Nov 17, 2013 (14:01:27 UTC)

Made the probabilistic trainer adapter not hold onto the input trainer by reference since this causes problems if the probabilistic adapter is saved for later use. Now it will simply hold the trainer by value.

Modified
dlib/svm/svm.h
Revision: 3dbbc74215801369
Author: Davis King
Date: Nov 17, 2013 (11:25:34 UTC)

Added the option to learn non-negative weights to the svm_multiclass_linear_trainer.

Modified
dlib/svm/svm_multiclass_linear_trainer.h
dlib/svm/svm_multiclass_linear_trainer_abstract.h
Revision: b082dbad9e9e420b
Author: Davis King
Date: Nov 17, 2013 (10:58:32 UTC)

Made the svm_multiclass_linear_trainer threaded. This also means you have to #include dlib/svm_threaded.h instead of dlib/svm.h to get it now.

Modified
dlib/svm.h
dlib/svm/svm_multiclass_linear_trainer.h
dlib/svm/svm_multiclass_linear_trainer_abstract.h
dlib/svm_threaded.h
dlib/test/svm_multiclass_linear.cpp
dlib/test/svm_struct.cpp
Revision: 37f52384215c65d8
Author: Davis King
Date: Nov 17, 2013 (10:05:41 UTC)

Made the matrix sub expression operators work with any kind of integer ranges rather than just long ranges.

Modified
dlib/matrix/matrix_subexp.h
dlib/matrix/matrix_subexp_abstract.h
Revision: 569326e944e34830
Author: Davis King
Date: Nov 17, 2013 (09:14:26 UTC)

Added missing asserts

Modified
dlib/image_processing/scan_fhog_pyramid.h
dlib/image_processing/scan_fhog_pyramid_abstract.h
Revision: 8ad4f3738002d5dd
Author: Davis King
Date: Nov 17, 2013 (09:01:47 UTC)

Added unit tests for new scan_fhog_pyramid object.

Modified
dlib/test/object_detector.cpp
Revision: e55497b70d0fbe0d
Author: Davis King
Date: Nov 17, 2013 (08:47:26 UTC)

Added code showing how to get the individual decision functions out of a multiclass decision function object.

Modified
examples/multiclass_classification_ex.cpp
Revision: a89499ffc36cfed5
Author: Davis King
Date: Nov 17, 2013 (08:29:52 UTC)

Added unit tests for new inv() functions for the point transformation objects.

Modified
dlib/test/geometry.cpp
Revision: a4becdefec1e9c7a
Author: Davis King
Date: Nov 17, 2013 (08:24:00 UTC)

Added sign() for matrix objects.

Modified
dlib/matrix/matrix_math_functions.h
dlib/matrix/matrix_math_functions_abstract.h
dlib/test/matrix3.cpp
Revision: 611278303346fa54
Author: Davis King
Date: Nov 17, 2013 (07:42:41 UTC)

Clarified matrix usage in the examples

Modified
examples/matrix_ex.cpp
examples/matrix_expressions_ex.cpp
Revision: 76b7d8966408e8d9
Author: Davis King
Date: Nov 16, 2013 (11:28:13 UTC)

Added the --add option to the imglab tool.

Modified
tools/imglab/src/main.cpp
Revision: 28866d35ba87eb59
Author: Davis King
Date: Nov 16, 2013 (04:15:52 UTC)

Fixed grammar/confusing sentence.

Modified
examples/multiclass_classification_ex.cpp
Revision: bb6fb7cb8a201866
Author: Davis King
Date: Nov 15, 2013 (15:18:10 UTC)

relaxed PSI consistency test again.

Modified
dlib/svm/structural_svm_object_detection_problem.h
Revision: 3c72f2eadd2ca537
Author: Davis King
Date: Nov 15, 2013 (15:17:57 UTC)

Slightly simplified the code

Modified
dlib/image_processing/scan_fhog_pyramid.h
Revision: 1f29be600a603277
Author: Davis King
Date: Nov 13, 2013 (14:52:40 UTC)

Made rotate_image() return a transformation object that defines the point mapping between the input and output images.

Modified
dlib/image_transforms/interpolation.h
dlib/image_transforms/interpolation_abstract.h
Revision: e47932abd62d25f1
Author: Davis King
Date: Nov 13, 2013 (14:50:15 UTC)

Added inv() that invert point transformation functions.

Modified
dlib/geometry/point_transforms.h
dlib/geometry/point_transforms_abstract.h
Revision: f413e75ae8f20989
Author: Davis King
Date: Nov 13, 2013 (13:50:47 UTC)

Fixed a compile time bug that could occur when wide character strings were serialized.

Modified
dlib/serialize.h
Revision: 3c8e75d87a7b2c68
Author: Davis King
Date: Nov 11, 2013 (16:20:09 UTC)

Increased the threshold for using separable filters.

Modified
dlib/image_processing/scan_fhog_pyramid.h
Revision: 8178aac7ba158515
Author: Davis King
Date: Nov 11, 2013 (14:08:28 UTC)

Made remove_unobtainable_rectangles() work on scan_fhog_pyramid.

Modified
dlib/image_processing/remove_unobtainable_rectangles.h
Revision: e6020d571a61663f
Author: Davis King
Date: Nov 11, 2013 (12:48:48 UTC)

Added missing requires clause to function.

Modified
dlib/image_processing/scan_fhog_pyramid_abstract.h
Revision: a12b352646c59050
Author: Davis King
Date: Nov 11, 2013 (12:46:50 UTC)

clarified spec

Modified
dlib/image_processing/scan_fhog_pyramid_abstract.h
Revision: ebd19ff9c9bcf98c
Author: Davis King
Date: Nov 11, 2013 (12:35:00 UTC)

Added scan_fhog_pyramid.

Modified
dlib/image_processing.h
Added
dlib/image_processing/scan_fhog_pyramid.h
dlib/image_processing/scan_fhog_pyramid_abstract.h
Revision: 0e88dd12611af98b
Author: Davis King
Date: Nov 11, 2013 (-05:36:26 UTC)

More stuff to avoid compiler errors in clang

Modified
dlib/simd/simd4f.h
dlib/simd/simd8f.h
Revision: 846e9a7dd79abb57
Author: Davis King
Date: Nov 11, 2013 (-05:30:25 UTC)

Minor change to avoid compiler error in clang

Modified
dlib/simd/simd4f.h
Revision: 48cf5d52a701a93e
Author: Davis King
Date: Nov 11, 2013 (-05:08:17 UTC)

A minor change to avoid a compiler error in visual studio 2005

Modified
dlib/simd/simd4f.h
Revision: ad5c53b02c45954f
Author: Davis King
Date: Nov 10, 2013 (18:49:42 UTC)

Sped up the image filtering functions by switching them to use AVX instructions when available.

Modified
dlib/image_transforms/spatial_filtering.h
Revision: 684578fa05efc01d
Author: Davis King
Date: Nov 10, 2013 (18:48:58 UTC)

Fleshed out the AVX SIMD support

Modified
dlib/simd.h
dlib/simd/simd8f.h
dlib/simd/simd_check.h
Added
dlib/simd/simd8i.h
Revision: b6ca9c0d7232d9ca
Author: Davis King
Date: Nov 10, 2013 (17:03:26 UTC)

Fixed bug in simd4i operator>>

Modified
dlib/simd/simd4i.h
Revision: 4a42dc0106f8fe75
Author: Davis King
Date: Nov 10, 2013 (16:21:57 UTC)

A minor change to avoid a compiler error when not using SSE instructions.

Modified
dlib/simd/simd4f.h
dlib/simd/simd4i.h
Revision: 464a8f77a4581063
Author: Davis King
Date: Nov 10, 2013 (15:52:26 UTC)

Made extract_fhog_features() and resize_image() a little faster.

Modified
dlib/image_transforms/fhog.h
dlib/image_transforms/interpolation.h
Revision: b1f618eb6a95fff6
Author: Davis King
Date: Nov 10, 2013 (15:47:32 UTC)

Fixed SSE detection macros to work properly with -msse3

Modified
dlib/simd/simd_check.h
Revision: 16424fc0167d7fab
Author: Davis King
Date: Nov 10, 2013 (09:00:35 UTC)

Made extract_fhog_features() a little faster by adding more SIMD instructions.

Modified
dlib/image_transforms/fhog.h
Revision: 12b7564fe17c62d7
Author: Davis King
Date: Nov 10, 2013 (08:24:27 UTC)

Made spatially_filter_image_separable() a little bit faster.

Modified
dlib/image_transforms/spatial_filtering.h
dlib/test/image.cpp
Revision: 5004671351d7f87f
Author: Davis King
Date: Nov 10, 2013 (07:29:02 UTC)

Made spatially_filter_image() use SIMD instructions when filtering float data.

Modified
dlib/image_transforms/spatial_filtering.h
dlib/image_transforms/spatial_filtering_abstract.h
Revision: d68a84401cd786d7
Author: Davis King
Date: Nov 10, 2013 (06:48:22 UTC)

Made spatially_filter_image_separable() use SIMD instructions when filtering float data.

Modified
dlib/image_transforms/spatial_filtering.h
dlib/image_transforms/spatial_filtering_abstract.h
Revision: 509f0a98b94a8135
Author: Davis King
Date: Nov 08, 2013 (17:46:41 UTC)

Increased the speed of resize_image() and the image pyramid functions by making them use SIMD instructions. Also changed the default interpolation method for pyramid_up to bilinear interpolation and removed the levels option.

Modified
dlib/image_transforms/interpolation.h
dlib/image_transforms/interpolation_abstract.h
Revision: d79fdd4342c2c315
Author: Davis King
Date: Nov 08, 2013 (17:17:45 UTC)

Added conversions from simd4f to simd4i.

Modified
dlib/simd/simd4f.h
Revision: a47df84716512726
Author: Davis King
Date: Nov 08, 2013 (13:08:34 UTC)

fixed incorrect #include

Modified
dlib/simd/simd4i.h
Revision: f9e752052829e3ff
Author: Davis King
Date: Nov 07, 2013 (16:42:23 UTC)

Fixed the distributed version of the structural svm solver to work with the recent changes to the core solver. Also added support for the nuclear norm regularization and cache refinement options.

Modified
dlib/svm/structural_svm_distributed.h
dlib/svm/structural_svm_distributed_abstract.h
dlib/svm/structural_svm_problem.h
Revision: 01736a96b2fc0b7b
Author: Davis King
Date: Nov 06, 2013 (18:03:49 UTC)

updated fhog unit tests

Modified
dlib/test/fhog.cpp
Revision: 32c3a77e65d34fb7
Author: Davis King
Date: Nov 06, 2013 (17:39:45 UTC)

Made extract_fhog_features() faster by using simd instructions. Also added an option to zero pad the borders of the output to it's easier to filter.

Modified
dlib/image_transforms/fhog.h
dlib/image_transforms/fhog_abstract.h
Revision: 4a0a85f0836cc5b6
Author: Davis King
Date: Nov 05, 2013 (17:42:25 UTC)

Fixed the new cache based epsilon feature so it actually prevents any calls to the separation oracle once the cache based refinement starts.

Modified
dlib/svm/structural_svm_problem.h
Revision: b999bdbbcea699dd
Author: Davis King
Date: Nov 05, 2013 (15:14:52 UTC)

Added initial version of simd objects.

Added
dlib/simd.h
dlib/simd/simd4f.h
dlib/simd/simd4i.h
dlib/simd/simd8f.h
dlib/simd/simd_check.h
Revision: 68d04a140d5976fd
Author: Davis King
Date: Nov 05, 2013 (14:53:55 UTC)

Added more filtering unit tests

Modified
dlib/test/image.cpp
Revision: 1a657b30b31b40ae
Author: Davis King
Date: Nov 05, 2013 (13:31:29 UTC)

Added missing #include to example

Modified
examples/one_class_classifiers_ex.cpp
Revision: 9d8d29301d711177
Author: Davis King
Date: Nov 05, 2013 (13:10:30 UTC)

Fixed a bug I just introduced which caused the filtering functions to not filter the entire image. Also added a bunch of unit tests to cover the new behavior of the filtering functions.

Modified
dlib/image_transforms/spatial_filtering.h
dlib/test/image.cpp
Revision: 65435f6765481140
Author: Davis King
Date: Nov 05, 2013 (12:41:58 UTC)

Upgraded spatial filtering routines to work with even sized filters.

Modified
dlib/image_transforms/spatial_filtering.h
dlib/image_transforms/spatial_filtering_abstract.h
Revision: 07d59e797a5869fc
Author: Davis King
Date: Nov 05, 2013 (12:37:23 UTC)

Added tests for new zero_border_pixels() overload.

Modified
dlib/test/image.cpp
Revision: 6eb7e0fa64543fe2
Author: Davis King
Date: Nov 05, 2013 (12:30:40 UTC)

Added an overload of zero_border_pixels() that lets you give a rectangle as input to define the non-border area.

Modified
dlib/image_transforms/assign_image.h
dlib/image_transforms/assign_image_abstract.h
Revision: 3659c1aa416b2cbc
Author: Davis King
Date: Nov 02, 2013 (14:44:10 UTC)

Added std:: to some functions to avoid potential ambiguity.

Modified
dlib/pixel.h
Revision: e5f7ebe329a7dd59
Author: Davis King
Date: Nov 02, 2013 (12:56:42 UTC)

Changed #includes to avoid unnecessary recompilation.

Modified
dlib/gui_widgets/base_widgets.h
dlib/gui_widgets/canvas_drawing.h
Revision: 743ac007f055c8d0
Author: Davis King
Date: Nov 01, 2013 (16:19:50 UTC)

Added utility function that can be overloaded by image scanners that want to use nuclear norm regularization in their parameter estimation.

Modified
dlib/svm/structural_object_detection_trainer.h
Revision: fcaae935b9f4d73f
Author: Davis King
Date: Nov 01, 2013 (16:14:51 UTC)

Added a nuclear norm regularization option to the structural svm solver.

Modified
dlib/svm/structural_svm_problem.h
dlib/svm/structural_svm_problem_abstract.h
Revision: 97d7c05f8bd84ecd
Author: Davis King
Date: Nov 01, 2013 (13:37:21 UTC)

Clarified spec

Modified
dlib/svm/structural_svm_problem_abstract.h
Revision: bb20613b9fa25eca
Author: Davis King
Date: Nov 01, 2013 (13:31:13 UTC)

Added another draw_fhog() overload.

Modified
dlib/image_transforms/fhog.h
dlib/image_transforms/fhog_abstract.h
Revision: 039207d5aa7c3a0c
Author: Davis King
Date: Oct 31, 2013 (19:28:44 UTC)

More tweaks to fhog feature extraction that makes it a bit faster.

Modified
dlib/image_transforms/fhog.h
Revision: b3c61d2a41f60a00
Author: Davis King
Date: Oct 31, 2013 (19:00:07 UTC)

Updated requires clause for the spatial filtering methods to note that you can't use the add_to or use_abs options with color images.

Modified
dlib/image_transforms/spatial_filtering.h
dlib/image_transforms/spatial_filtering_abstract.h
Revision: aa9d17cc9aa1d0d4
Author: Davis King
Date: Oct 31, 2013 (18:16:46 UTC)

Changed tests slightly to avoid a bug in gcc 4.8

Modified
dlib/test/queue.cpp
dlib/test/stack.cpp
Revision: 736497f873b4e339
Author: Davis King
Date: Oct 31, 2013 (18:46:50 UTC)

Made the fhog code a little bit faster.

Modified
dlib/image_transforms/fhog.h
Revision: e1aeb405daef4f33
Author: Davis King
Date: Oct 31, 2013 (17:36:44 UTC)

Just fixes compiler warnings in gcc 4.8 and clang 3.4.

Modified
dlib/assert.h
dlib/graph_cuts/min_cut.h
dlib/image_transforms/edge_detector.h
dlib/image_transforms/equalize_histogram.h
dlib/image_transforms/segment_image.h
dlib/matrix/matrix_assign.h
dlib/matrix/matrix_la.h
dlib/optimization/optimization_trust_region.h
dlib/svm.h
dlib/svm/cross_validate_multiclass_trainer.h
dlib/svm/cross_validate_regression_trainer.h
dlib/svm/feature_ranking.h
dlib/svm/krr_trainer.h
dlib/svm/pegasos.h
dlib/svm/rbf_network.h
dlib/svm/sort_basis_vectors.h
dlib/svm/svm.h
dlib/svm/svm_threaded.h
dlib/test/cmd_line_parser.h
dlib/test/matrix2.cpp
dlib/test/matrix3.cpp
dlib/test/matrix4.cpp
dlib/test/opt_qp_solver.cpp
dlib/test/pipe.cpp
dlib/test/scan_image.cpp
Revision: 324467515a9f12f4
Author: Davis King
Date: Oct 26, 2013 (05:23:33 UTC)

Added more () to avoid a compiler error in gcc 4.7.1 on SUSE Linux. Thanks to Volker Härtel for finding this.

Modified
dlib/optimization/find_max_parse_cky.h
Revision: 49105c58cdf37efd
Author: Davis King
Date: Oct 22, 2013 (17:07:23 UTC)

Refactored code slightly to avoid getting this warning from gcc when certain optimizations are enabled "warning: assuming signed overflow does not occur when assuming that (X + c) < X is always false"

Modified
dlib/matrix/matrix_subexp.h
Revision: 1c68f064db4083f5
Author: Davis King
Date: Oct 21, 2013 (14:33:56 UTC)

Tweaked the PSI validation test again

Modified
dlib/svm/structural_svm_object_detection_problem.h
Revision: d8d3d5ec44314d88
Author: Davis King
Date: Oct 20, 2013 (07:04:32 UTC)

Changed fhog coordinate transforms so that they are properly invertible.

Modified
dlib/image_transforms/fhog.h
dlib/image_transforms/fhog_abstract.h
dlib/test/fhog.cpp
Revision: 7cc91977cadbae6e
Author: Davis King
Date: Oct 19, 2013 (05:20:36 UTC)

Slightly tweaked PSI validation test again

Modified
dlib/svm/structural_svm_object_detection_problem.h
Revision: 9b9dd81e0c38890c
Author: Davis King
Date: Oct 18, 2013 (18:49:58 UTC)

Added overloads of fhog_to_image() and image_to_fhog() that work on rectangles.

Modified
dlib/image_transforms/fhog.h
dlib/image_transforms/fhog_abstract.h
Revision: 544eaa604f6e6b2b
Author: Davis King
Date: Oct 18, 2013 (18:46:25 UTC)

Relaxed PSI vector consistency test to avoid false alarms.

Modified
dlib/svm/structural_svm_object_detection_problem.h
Revision: 26c16180c1ab5608
Author: Davis King
Date: Oct 17, 2013 (16:24:11 UTC)

Made the spatial filtering functions filter each color channel independently rather than converting to HSI and filtering just the I channel. Also, the spatially_filter_image_separable_down() routine now only allows grayscale output images.

Modified
dlib/image_transforms/spatial_filtering.h
dlib/image_transforms/spatial_filtering_abstract.h
Revision: 22a58768ba95f3e8
Author: Davis King
Date: Oct 16, 2013 (15:15:26 UTC)

fixed grammar in comment

Modified
dlib/svm/structural_svm_object_detection_problem.h
Revision: 4c5c1add1a4f2f6b
Author: Davis King
Date: Oct 09, 2013 (15:59:29 UTC)

Changed test slightly to avoid a false alarm

Modified
dlib/test/filtering.cpp
Revision: 3f637fc5ac235fd9
Author: Davis King
Date: Oct 08, 2013 (03:20:53 UTC)

Added more paths to search when looking for the Intel MKL on windows.

Modified
dlib/cmake_find_blas.txt
Revision: bdba0d56813a90d1
Author: Davis King
Date: Oct 07, 2013 (17:01:25 UTC)

Reverted the changes from 4704356b676c.

Modified
dlib/matrix/lapack/fortran_id.h
dlib/matrix/matrix_blas_bindings.h
Revision: cdf1c40fbc1ff71f
Author: Davis King
Date: Oct 07, 2013 (16:59:22 UTC)

Fixed some issues with the cmake files for linking with 64bit intel mkl

Modified
dlib/cmake_find_blas.txt
Revision: 56db2e78b5208915
Author: Davis King
Date: Oct 07, 2013 (16:07:29 UTC)

Setup cmake files to find the Intel MKL on windows and try to link with it if present.

Modified
dlib/cmake_find_blas.txt
Revision: 4704356b676caf96
Author: Davis King
Date: Oct 07, 2013 (16:05:49 UTC)

Fixed the BLAS and LAPACK bindings so they work with the 64bit version of the Intel MKL when used on Windows.

Modified
dlib/matrix/lapack/fortran_id.h
dlib/matrix/matrix_blas_bindings.h
Revision: 72ec4bcd256d630c
Author: Davis King
Date: Oct 05, 2013 (06:29:48 UTC)

Made pyramid_down<1> equivalent to pyramid_disable.

Modified
dlib/image_transforms/image_pyramid.h
dlib/image_transforms/image_pyramid_abstract.h
Revision: e04a7c95a120d40d
Author: Davis King
Date: Oct 04, 2013 (19:07:44 UTC)

Added missing assert

Modified
dlib/svm/function.h
Revision: 64d89145601b61cd
Author: Davis King
Date: Oct 04, 2013 (18:50:10 UTC)

Added the ability to get the score in addition to the label out of the one_vs_all_decision_function.

Modified
dlib/svm/one_vs_all_decision_function.h
dlib/svm/one_vs_all_decision_function_abstract.h
Revision: c38263073971ced0
Author: Davis King
Date: Oct 04, 2013 (18:35:30 UTC)

Added the ability to get the score in addition to the label out of the multiclass_linear_decision_function.

Modified
dlib/svm/function.h
dlib/svm/function_abstract.h
Revision: 2f549185bf3ae6e4
Author: Davis King
Date: Oct 04, 2013 (18:14:33 UTC)

Added compile time checks that make it so the user gets a much more informative error message if they mistakenly use matrices that are not column vectors with the general purpose optimizers.

Modified
dlib/optimization/optimization.h
dlib/optimization/optimization_bobyqa.h
dlib/optimization/optimization_least_squares.h
Revision: e20442f739764833
Author: Davis King
Date: Oct 04, 2013 (18:13:03 UTC)

Clarified some things in the example and also added code showing how to use the new bounds constrained solver.

Modified
examples/optimization_ex.cpp
Revision: 66447c73cfc76022
Author: Davis King
Date: Oct 04, 2013 (17:37:22 UTC)

Added comments about python not being threaded for the structural SVM

Modified
python_examples/svm_struct.py
Revision: 71ce259fffd4c582
Author: Davis King
Date: Oct 03, 2013 (18:17:58 UTC)

Fixed a bug in extract_fhog_features() that happened when very small images were given.

Modified
dlib/image_transforms/fhog.h
dlib/test/fhog.cpp
Revision: b07924f03a577c37
Author: Davis King
Date: Oct 03, 2013 (17:36:51 UTC)

Refactored the image pyramid code. Now there is just one templated object, pyramid_down and you give it the downsampling amount as a template argument.

Modified
dlib/image_transforms/image_pyramid.h
dlib/image_transforms/image_pyramid_abstract.h
dlib/test/object_detector.cpp
dlib/test/pyramid_down.cpp
examples/object_detector_advanced_ex.cpp
examples/object_detector_ex.cpp
examples/train_object_detector.cpp
Revision: 7adbbfd675a94eb4
Author: Davis King
Date: Oct 03, 2013 (17:23:23 UTC)

Made resize_image() overload a little more robust.

Modified
dlib/image_transforms/interpolation.h
Revision: 26c7c7aabf9e2f14
Author: Davis King
Date: Oct 03, 2013 (16:58:43 UTC)

Added pyramid_down_generic

Modified
dlib/image_transforms/image_pyramid.h
dlib/image_transforms/image_pyramid_abstract.h
dlib/test/pyramid_down.cpp
Revision: cc2ff3fe5996e323
Author: Davis King
Date: Oct 03, 2013 (16:57:22 UTC)

Fixed some compile time errors in the new overload of resize_image().

Modified
dlib/image_transforms/interpolation.h
Revision: d929ec2347a18316
Author: Davis King
Date: Oct 02, 2013 (18:51:12 UTC)

Added missing assert

Modified
dlib/image_transforms/interpolation.h
Revision: f531f1b72c317ab0
Author: Davis King
Date: Oct 02, 2013 (18:47:34 UTC)

Made resize_image() use bilinear interpolation by default and also added a special version of it that is optimized for this case.

Modified
dlib/image_transforms/interpolation.h
dlib/image_transforms/interpolation_abstract.h
Revision: 745978eda9f642f9
Author: Davis King
Date: Oct 02, 2013 (17:48:00 UTC)

Made color version of interpolate_bilinear faster.

Modified
dlib/image_transforms/interpolation.h
Revision: 7615451fc2c8dd82
Author: Davis King
Date: Oct 02, 2013 (17:45:08 UTC)

Made interpolate_bilinear a little bit faster.

Modified
dlib/image_transforms/interpolation.h
Revision: 561077db61317bb0
Author: Davis King
Date: Oct 02, 2013 (17:24:51 UTC)

Slightly reduced the amount of blurring that happens in pyramid_down_5_4.

Modified
dlib/image_transforms/image_pyramid.h
Revision: 2f2af3bbcfea8470
Author: Davis King
Date: Oct 02, 2013 (15:08:13 UTC)

Added code to avoid another useless vistual studio warning.

Modified
dlib/algs.h
Revision: 56e1afa0a9b883e6
Author: Davis King
Date: Oct 02, 2013 (13:57:48 UTC)

Just renamed some variables to avoid a name conflict with a #define in vistual studio.

Modified
dlib/statistics/vector_normalizer_frobmetric.h
dlib/statistics/vector_normalizer_frobmetric_abstract.h
dlib/test/statistics.cpp
Revision: 48baafdca6db0b2f
Author: Davis King
Date: Oct 01, 2013 (19:05:46 UTC)

Fixed grammar and added minor clarifications

Modified
examples/fhog_ex.cpp
Revision: 519668b19fb3b4e2
Author: Davis King
Date: Oct 01, 2013 (18:58:56 UTC)

Added an example for the new HOG feature extractor.

Modified
examples/CMakeLists.txt
Added
examples/fhog_ex.cpp
Revision: 93465866e5482155
Author: Davis King
Date: Oct 01, 2013 (16:25:59 UTC)

Set a default value for the cell size on image_to_fhog() and fhog_to_image().

Modified
dlib/image_transforms/fhog.h
dlib/image_transforms/fhog_abstract.h
Revision: a4c29da6ea8b1950
Author: Davis King
Date: Oct 01, 2013 (15:46:34 UTC)

clarified spec

Modified
dlib/image_transforms/fhog_abstract.h
Revision: 1808ed42ff5669b3
Author: Davis King
Date: Oct 01, 2013 (15:38:50 UTC)

Filled out spec for the FHOG feature extraction routines.

Modified
dlib/image_transforms/fhog.h
dlib/image_transforms/fhog_abstract.h


dlib C++ Library - Old Release Notes

The Library
  • Algorithms
  • API Wrappers
  • Bayesian Nets
  • Compression
  • Containers
  • Graph Tools
  • Image Processing
  • Linear Algebra
  • Machine Learning
  • Metaprogramming
  • Miscellaneous
  • Networking
  • Optimization
  • Parsing

Help/Info
  • Dlib Blog
  • Examples: C++
    • 3D Point Cloud
    • Assignment Learning
    • Base64 Encoder
    • Bayesian Network From Disk
    • Bayesian Network GUI
    • Bayesian Network
    • Bridge
    • BSP
    • C-Support Vector Machine
    • Cmd Line Parser
    • Compress Stream
    • Config File Reader
    • Custom Trainers
    • Directory Navigation
    • Empirical Kernel Map
    • Face Detection
    • Face Landmark Detection
    • FHOG Feature Extraction
    • FHOG Object Detection
    • Graph Labeling
    • GUI
    • Hough Transform
    • HTTP Server
    • Image
    • IO Socket Streams
    • IO Streams Server
    • Kernel Centroid
    • Kernel K-Means Clustering
    • Kernel Ridge Regression
    • Kernel RLS Filtering
    • Kernel RLS Regression
    • KRR Classification
    • Learning to Track
    • Linear Assignment Problems
    • Linear Manifold Regularizer
    • Linear Model Predictive Control
    • Logger Advanced
    • Logger Custom Output
    • Logger
    • Matrix Expressions
    • Matrix
    • Member Function Pointer
    • Model Selection
    • Multiclass Classification
    • Multithreaded Object
    • Neural Network
    • Non-Linear Least Squares
    • Nu-Support Vector Machine
    • Numerical Integration
    • Object Detector Advanced
    • Object Detector
    • One Class Classifiers
    • Online SVM
    • Optimization
    • Parallel For Loops
    • Pipe 2
    • Pipe
    • Quantum Computing
    • Queue
    • Rank Features
    • Relevance Vector Classification
    • Relevance Vector Regression
    • Running Stats
    • Sequence Labeling
    • Sequence Segmentation
    • Sockets
    • Sockstreambuf
    • Sparse Vectors
    • SQLite
    • Std C++ Allocator
    • Structural Support Vector Machines
    • Support Vector Regression
    • SURF
    • SVM-Rank
    • Thread Function
    • Thread Pool
    • Threaded Object
    • Threads
    • Timer
    • Train Object Detector
    • Train Shape Predictor
    • Using Custom Kernels
    • Video Object Tracking
    • Webcam Face Pose Estimation
    • XML Parser
  • Examples: Python
    • Face Detector
    • Face Landmark Detection
    • find candidate object locations
    • Linear Assignment Problems
    • Sequence Segmenter
    • Structural Support Vector Machines
    • SVM-Rank
    • Train Object Detector
    • Train Shape Predictor
    • Video Object Tracking
  • FAQ
  • Forums
  • Home
  • How to compile
  • How to contribute
  • Index
  • Introduction
  • License
  • Python API
  • Suggested Books
  • Who uses dlib?

Current Release
  • Change Log
  • Release Notes
  • Version: 18.18

Last Modified:
Oct 28, 2015
Old Release Notes

Release 18.8

Release date: Jun 02, 2014
Major Changes in this Release:
New Features:
   - Added the ability to set a previously trained function as a prior to the
     svm_multiclass_linear_trainer, svm_c_linear_trainer, and svm_rank_trainer
     objects.
   - Added a user settable loss to the structural_assignment_trainer and
     structural_track_association_trainer objects.
   - Added evaluate_detectors(), a function for efficiently running multiple fHOG
     based object detectors.
   - Added the new split_on_first() and split_on_last() string manipulation functions.
   - Added locally_change_current_dir, a RAII tool for switching between directories.
   - You can now make a 1x1 matrix containing a single value by calling mat() on a single
     scalar value.
   - The point transform functions and frobmetric_training_sample are now serializable.
   - Added a simplified operator << and >> based syntax for serializing to and
     from files.  So now you can serialize to a file using a syntax of:
       serialize("myfile.dat") << myobject << another_object;
     and then load those objects from disk via:
       deserialize("myfile.dat") >> myobject >> another_object;
     An arbitrary number of objects can be serialized or deserialized by
     chaining the << and >> operators.

Non-Backwards Compatible Changes:

Bug fixes:
   - Fixed a bug pointed out by Daniel Girardeau-Montaut. The covariance()
     function didn't work on non-double valued matrices.
   - Fixed a bug in the backtracking_line_search() function pointed out by
     Ping-Chang Shih. The function ignored the max_iter parameter.
   - Fixed a compiler error encountered when using clang 3.4 on Mac OS X 10.9.
     Thanks to Martin Fergie for reporting this problem.
   - Fixed a potential divide by zero in draw_fhog()

Other:
   - Added an example program showing how to set a custom logger output hook.
   - Made linear decision_functions which use sparse vectors much faster.

Release 18.7

Release date: Apr 09, 2014
Major Changes in this Release:
New Features:
   - Added a Python API for working with fHOG based object detectors.  See the
     new python example programs train_object_detector.py and face_detector.py for
     more details.
   - Added the ability to use a user supplied fHOG style feature extractor with
     the scan_fhog_pyramid object.  So now you can define your own version of HOG
     for use with these tools.
   - The oca solver now supports taking a user supplied prior vector. That is,
     it lets you use a regularizer like ||w-prior||^2 instead of the usual
     ||w||^2 regularizer.
   - Added the structural_track_association_trainer object.  It is a structural
     SVM tool for creating multi-target tracking algorithms.  See the
     learning_to_track_ex.cpp example program for an introduction.
   - Added the following minor utility functions: nearest_center(),
     add_image_rotations(), set_aspect_ratio(), and tile_images().

Non-Backwards Compatible Changes:
   - Refactored the load_image_dataset() routines so they are easier to use and
     more flexible. This introduces a slight backwards incompatibility in that
     the version that loads full_object_detection objects now returns an ignore
     rectangle set instead of a parts name list.  Other than that the changes
     are backwards compatible with previous versions of dlib.
   - Added a bias term to the assignment_function's model so the user doesn't
     need to remember, or even understand, that they should add it themselves.
     However, this change breaks backwards compatibility with the previous
     serialization format for assignment_function objects.

Bug fixes:
   - Fixed a number of compile time errors that could occur in rare cases.
   - The stopping condition for the svr_linear_trainer was too tight, causing it
     to take an excessive amount of time to converge in some cases.
   - Disabled use of XIM for X11 windowing since it makes programs hang on some
     systems. However, this means the wide character input methods won't work on
     X11 systems anymore.
   - Fixed a bug in randomize_samples() which caused the outputs to be not as
     random as they should be.
   - Fixed dlib's CMakeLists.txt file so that the "use FFTW" option actually
     causes the build to use FFTW.
   - Fixed a compile time error that triggered when trying to link with FFTW.
   - mat() did not work correctly when used with std::vector<bool> objects.
     This has been fixed.

Other:

Release 18.6

Release date: Feb 03, 2014
Major Changes in this Release:
New Features:
   - Object Detection Tools:
      - Added scan_fhog_pyramid, a tool for creating Histogram of Oriented Gradient (HOG)
        based object detectors.
      - Added get_frontal_face_detector(), a HOG based face detector.
      - Added an option to include "ignore/don't care" truth boxes to the
        structural_object_detection_trainer.  This allows a user to tell the trainer that
        they don't care if certain objects are detected or not detected.
   - Image Processing Tools:
      - Added extract_image_chips()
      - Added a version of draw_rectangle() for drawing on images.
      - The spatial filtering routines now support even sized filters.
      - Added flip_image_dataset_left_right(), upsample_image_dataset(), and
        rotate_image_dataset().
   - Machine Learning Tools:
      - Added a nuclear norm regularization option to the structural SVM solver.
      - Added the option to learn only non-negative weights to the
        svm_multiclass_linear_trainer.
   - Speed Improvements:
      - The svm_multiclass_linear_trainer, one_vs_one_trainer, and one_vs_all_trainer
        objects are now multithreaded.  This also means you have to #include
        dlib/svm_threaded.h instead of dlib/svm.h to use these tools.
      - A number of image processing tools can now optionally use SSE and AVX instructions
        and are therefore considerably faster.  In particular, the following tools have been
        accelerated: extract_fhog_features, resize_image, pyramid_down, pyramid_up,
        spatially_filter_image_separable, and spatially_filter_image.
   - Added an inv() routine that inverts point transformation functions.
   - Added a sign() routine for matrix objects.

Non-Backwards Compatible Changes:
   - The spatial image filtering functions have the following changes:
      - They no longer zero the image borders when you set the add_to parameter to true.
      - The spatially_filter_image_separable_down() routine now only allows grayscale
        output images.
   - Changed the default parameters of the test_box_overlap object. Now it defaults to
     using exactly the PASCAL VOC match criterion.
   - To use the svm_multiclass_linear_trainer, one_vs_one_trainer, or one_vs_all_trainer
     objects you now have to #include dlib/svm_threaded.h instead of dlib/svm.h.
   - pyramid_up() no longer has a levels option.

Bug fixes:
   - Fixed a compile time bug that could occur when wide character strings were
     serialized.
   - Fixed a compile time bug occurring in gcc 4.7.1 on SUSE Linux.  Thanks to Volker
     Härtel for finding this.
   - Fixed compile time errors that occurred when using gcc on cygwin.
   - Fixed a compile time bug that could occur when serializing mlp objects.
   - Fixed a bug in the bigint object that caused division to sometimes produce incorrect
     results.
   - Fixed a bug which sometimes caused load_image_dataset() to erroneously report that
     the dataset file could not be found.
   - Fixed a bug in the structural_object_detection_trainer that caused it to erroneously
     throw a impossible_labeling_error exception in certain rare cases.
   - Updated find_max_factor_graph_nmplp() to use the improved version of the algorithm
     from the 2011 paper Introduction to dual decomposition for inference by David Sontag,
     Amir Globerson, and Tommi Jaakkola.  The original algorithm presented in their 2008
     paper had an error that negatively affected its convergence.  Thanks to James Gunning
     for pointing this out.

Other:
   - Fixed many compiler warnings in gcc 4.8.
   - Made many of the mat() converters bind the resulting matrix expressions into BLAS
     functions.
   - libpng and libjpeg are now included in the dlib/external folder to enable easy static
     linking to these libraries on platforms that typically don't have them (e.g. Windows).
     Moreover, dlib's cmake files will automatically perform this static linking when no
     copy of these libraries is found on the system.

Release 18.5

Release date: Oct 22, 2013
Major Changes in this Release:
New Features:
   - Added routines for performing BFGS and L-BFGS optimization with box constraints.
     See the new find_min_box_constrained() and find_max_box_constrained() routines.
   - Added vector_normalizer_frobmetric.  This is a tool for learning a
     Mahalanobis distance metric.
   - The user can now set different loss values for false alarming vs. getting a
     correct detection when using the structural_sequence_segmentation_trainer.
   - Added an overload of clamp() that lets you use matrix valued lower/upper bounds.
   - New image processing tools:
      - Added the scan_image_custom object, split_array(), and add_image_left_right_flips().
      - Added extract_fhog_features(), this is a function for computing
        Felzenszwalb's 31 channel HOG image representation.

Non-Backwards Compatible Changes:
   - Refactored the image pyramid code. Now there is just one templated object called
     pyramid_down and you give it the downsampling amount as a template argument.  To make
     old code work with this change use the following substitutions:
       change pyramid_down to pyramid_down<2>
       change pyramid_down_3_2 to pyramid_down<3>
       change pyramid_down_4_3 to pyramid_down<4>
       change pyramid_down_5_4 to pyramid_down<5>

Bug fixes:

Other:
   - Made the structural SVM solver slightly faster.
   - Moved the python C++ utility headers from tools/python/src into dlib/python.
   - The PNG loader is now able to load grayscale images with an alpha channel.
   - Removed checks that prevented users from using references to functions with the
     optimization code and forced the use of function pointers. This was to avoid
     triggering a bug in gcc 4.0.  Since that compiler is no longer officially supported
     by dlib I've removed these checks to increase usability.
   - Made resize_image() use bilinear interpolation by default and also added a special
     version of it that is optimized for this case.
   - Dlib's cmake files will now automatically link to the Intel MKL on MS Windows
     platforms if the MKL is installed.

Release 18.4

Release date: Aug 14, 2013
Major Changes in this Release:
New Features:
   - Added Python interfaces to dlib's structural support vector machine solver and
     Hungarian algorithm implementation.
   - Added running_cross_covariance
   - Added order_by_descending_distance()
   - Added is_finite()
   - Added the csv IO manipulator that lets you print a matrix in comma separated value
     format.

Non-Backwards Compatible Changes:
   - Changed the object detector testing functions to output average precision instead of
     mean average precision.
   - Added an option to weight the features from a hashed_feature_image relative to the
     number of times they occur in an image.  I also made it the default behavior to use
     this relative weighting and changed the serialization format to accommodate this.

Bug fixes:
   - Fixed typo in learn_platt_scaling(). The method wasn't using the exact prior
     suggested by Platt's paper.
   - Fixed a bug in running_scalar_covariance that caused the covariance() and
     correlation() methods to output the wrong answer if the covariance was negative.

Other:
   - Gave the image_window the ability to tie the mouse and keyboard events together such
     that it is possible for a user to listen for both simultaneously.
   - A number of changes were made to the structural_svm_problem's code which make it
     significantly faster in some cases.
   - Added Steven Van Ingelgem's patch to the HTTP server which makes operations on HTTP
     headers case-insensitive.

Release 18.3

Release date: June 21, 2013
Major Changes in this Release:
New Features:
   - Machine Learning:
      - Added the svr_linear_trainer, a tool for solving large scale support vector
        regression problems.
      - Added a tool for working with BIO and BILOU style sequence taggers/segmenters.
        This is the new sequence_segmenter object and its associated
        structural_sequence_segmentation_trainer object.
      - Added a python interface to some of the machine learning tools.  These
        include the svm_c_trainer, svm_c_linear_trainer, svm_rank_trainer, and
        structural_sequence_segmentation_trainer objects as well as the cca()
        routine.
   - Added point_transform_projective and find_projective_transform().
   - Added a function for numerically integrating arbitrary functions, this is the
     new integrate_function_adapt_simpson() routine which was contributed by
     Steve Taylor
   - Added jet(), a routine for coloring images with the jet color scheme.

Non-Backwards Compatible Changes:

Bug fixes:
   - Fixed a bug in hysteresis_threshold() that caused it to produce incorrect
     outputs in some cases.
   - Fixed a segmentation fault in the eigenvalue_decomposition object which
     could occur when NaN valued inputs were given.

Other:
   - Made image saving routines work on matrix objects in addition to array2d objects.
   - The machine learning page now contains a flow chart to help new users
     select a machine learning tool appropriate for their task.

Release 18.2

Release date: May 30, 2013
Major Changes in this Release:
New Features:
   - Object Detection Tools:
      - Added another image scanning tool similar to scan_image_pyramid.  This
        is the new scan_image_boxes object.  It allows a user to easily specify
        an arbitrary set of object boxes which should be checked by an object
        detector rather than scanning a fixed sized window over the image as is
        done by the scan_image_pyramid tool.  This allows more flexible scanning
        strategies.  For example, it is now possible to use the selective search
        method implemented by the new find_candidate_object_locations() routine.
      - Added the binned_vector_feature_image.
      - Upgraded the object_detector so that you can use the adjust_threshold
        argument for all versions of the operator() method.
      - Added remove_unobtainable_rectangles()
   - Hashing Tools:
      - Added a set of new locality sensitive hashing functions meant for use
        with larger vectors and higher bit sizes than the current LSH tools.
        These are the new hash_similar_angles_xxx objects.
      - Added find_k_nearest_neighbors_lsh() and hash_samples()
      - Added create_max_margin_projection_hash()
   - New Matrix Routines: linpiece(), fft(), and ifft()
   - Added numeric constants and additional statistics to the running_stats
     object.  This code was contributed by Steve Taylor.
   - Added the image_window::get_next_keypress() routine.  This tool allows a
     user to easily find out which keyboard key the user is pressing.

Non-Backwards Compatible Changes:
   - Changed the object_detector interface slightly.  In particular, it no
     longer adds the adjust_threshold argument to the output scores.
   - The object detector testing functions now output mean average precision in
     addition to precision and recall.
   - Changed how dlib does serialization in a number of ways:
      - The running_stats and scan_image_pyramid objects have had their
        serialization format changed in a way that breaks backwards
        compatibility.  This means serialized versions of these objects can't be
        loaded by the new version of dlib.
      - Changed the format dlib uses when it serializes floating point values.
        Previously, we used an ASCII based format.  Dlib now uses a much more
        efficient binary format. However, the deserialization routines have
        been made backwards compatible with the previous format. So dlib can
        still deserialize older data but older software won't be able to read
        the new format.
      - Changed the serialization formats for the matrix and array2d objects so
        that either object can be deserialized into the other. This was done in a
        way that is backwards compatible with previous versions of dlib. That is,
        we can still load data serialized by previous dlib versions. However,
        older versions of dlib can't load the new serialization format.

Bug fixes:
   - Fixed a bug in save_dng() that happened sometimes when saving images with
     unsigned char pixels.
   - The test_ranking_function() and cross_validate_ranking_trainer() routines
     computed incorrect MAP scores when the learned function output a constant
     value for all samples.  This has been fixed.

Other:
   - Gave load_image_dataset() the ability to skip images that don't have any
     ground truth boxes.
   - Changed average_precision() to use interpolated precision. So now it uses
     the same metric as the one used by the Pascal VOC challenge.
   - Upgraded the dng image format so it can natively store floating point
     pixel types without any information loss.

Release 18.1

Release date: Mar 25, 2013
Major Changes in this Release:
New Features:
   - Added svd_fast(), a routine for computing a singular value decomposition of very
     large matrices.
   - Added cca(), a routine for doing canonical correlation analysis on very large
     and high-dimensional datasets.
   - Added tools for creating parallel for loops, see parallel_for().
   - Added some features to the image display widgets to let the user easily
     get information about where the user is clicking.  This is the new
     get_next_double_click() routine.
   - Added an operator>> for matrix objects which allows you to read in ASCII
     matrices using the format used by operator<<.
   - Added serialization support for std::vector<bool>.
   - Added the following new minor objects and routines: average_precision(),
     make_sparse_vector_inplace(), orthogonalize(), count_bits(), draw_surf_points(),
     hamming_distance(), cosine_distance, and negative_dot_product_distance.

Non-Backwards Compatible Changes:
   - Changed ranking evaluation functions to return the mean average precision
     in addition to just raw ranking accuracy. This changes their return types
     from double to matrix<double,1,2>.
   - Generalized segment_image() so it works on any pixel type or array of
     vectors.  I also changed its interface slightly.  In particular, I removed
     the min_diff parameter and replaced it with an explicit min_size parameter.
   - Changed how the SURF descriptor is computed slightly to improve its
     accuracy.  The interface to the user has not been changed, however, the
     number and position of detected SURF points might be different than in
     previous dlib versions.

Bug fixes:
   - Fixed an endianness bug in the PNG I/O functions which occurred when 16bit
     grayscale PNGs were used.
   - Fixed a bug which could potentially occur when empty std::vector<char> or
     std::vector<unsigned char> were serialized.
   - There was a bug in the version of draw_line() that draws directly onto an
     array2d type image (not the one that draws onto a GUI canvas object). The
     bug triggered whenever a perfectly horizontal or vertical line that extended
     outside the image was drawn. This has been fixed.
   - Fixed a bug in the Windows implementation of the signaler object, which
     was found by Isaac Peterson. The bug caused the program to deadlock if
     signal() or broadcast() was called at exactly the same time a
     wait_or_timeout() function timed out.
   - Fixed a bug in the image_window and image_display GUI tools which caused
     them to not redraw overlay lines correctly in certain cases involving
     non-default zoom levels.
   - Switched randomly_color_image() to use the non-pointer based version of
     murmur_hash3() to avoid violation of the strict aliasing rule. In
     particular, the previous version didn't work correctly in gcc 4.7.2 when
     optimizations were enabled.
   - Visual Studio 2012's iostreams library has a bug which caused the
     iosockstream to crash on use.  This version of dlib has been changed to
     avoid triggering this bug.

Other:
   - Refactored the Platt scaling code a little. Now there is a function,
     learn_platt_scaling(), that allows you to directly call the Platt scaling
     code without supplying a trainer object.
   - Optimized the oca and structural SVM solvers.  They are now a little bit faster
     than in previous dlib releases.

Release 18.0

Release date: Feb 04, 2013
Major Changes in this Release:
New Features:
   - Machine Learning
      - Added svm_rank_trainer, an optimized implementation of the SVM-Rank algorithm.
      - Added rank_unlabeled_training_samples(), an implementation of the SVM Active
        Learning algorithm.
      - Added svm_c_linear_dcd_trainer, a warm-startable SVM solver using the dual
        coordinate descent algorithm used by liblinear.
      - Added the ability to force the last element of a weight vector to 1 to the
        following objects: svm_c_linear_trainer, svm_c_linear_dcd_trainer,
        svm_rank_trainer, and oca.
      - Added the ability to learn non-negative weight vectors to the
        structural_sequence_labeling_trainer object.
   - Networking
      - Added an iosockstream object.
      - Added a method to the server object that lets a user set the graceful close timeout
        time to something other than the default of 500ms.
   - Linear Algebra
      - Added the gaussian_randm() function.
      - Added the find_affine_transform() function.
      - Added the mat() function.  It combines the array_to_matrix(), vector_to_matrix(),
        pointer_to_column_vector(), and pointer_to_matrix() methods all into one convenient
        interface.   mat() also works for Armadillo and Eigen matrices.
      - Added STL style begin() and end() methods to matrix and matrix_exp.
      - Added an overload of sparse_matrix_vector_multiply() that multiplies a dense matrix
        with a sparse vector.
      - Made toMat() work with the matrix object in addition to array2d style images.
   - Graphical User Interface Tools
      - Added draw_solid_convex_polygon().
      - Added an overload of draw_image() that's useful for drawing images and doing
        interpolation at the same time.
      - Added the on_view_changed() callback to zoomable_region and scrollable_region widgets.
   - Added parse_trees_to_string() and parse_trees_to_string_tagged().
   - Added lambda function support to the timeout object.
   - Added the vectorstream object.
   - Added the parse_xml() routines.
   - Added a group name feature to the command line parser.  Now it is possible to make
     print_options() print related options in named groups.
   - Added the following new hashing functions: murmur_hash3_128bit_3(),
     murmur_hash3_2(), murmur_hash3_3(), uniform_random_hash(), gaussian_random_hash()
     as well as hash() overloads for uint32, uint64, and std::pair.

Non-Backwards Compatible Changes:
   - Made the svm_c_linear_trainer use the risk gap to decide when to stop.  This was done
     because it is how all the other OCA based SVM tools in dlib decide when to stop.
     However, it might cause the outputs to be slightly different in this version of dlib.
   - It is now illegal to call unlock() on a mutex when the mutex is not owned by the
     calling thread.  The most likely reason for doing this was to unlock early in an area
     locked by an auto_mutex.  Old code that does this can be fixed by calling auto_mutex's
     unlock() function instead.
   - Removed the structural_assignment_trainer::learns_nonnegative_weights() routine
     and moved its functionality into the feature extraction interface used by this object.

Bug fixes:
   - Fixed a bug in find_max_factor_graph_nmplp() which caused it to not work properly on
     some compilers.
   - Fixed a bug pointed out by Joel Nelson in the version of md5() that took an istream.
     The bug caused the function to crash on strings longer than 56 characters.

Other:
   - dlib now has an excellent new logo thanks to Yasser Asmi.
   - Added a new documentation page for the various linear algebra tools.
   - The following objects were turned into single implementation components:
     sockstreambuf, timeout, member_function_pointer, xml_parser, linker,
     bound_function_pointer, and timer.

Release 17.49

Release date: Dec 18, 2012
Major Changes in this Release:
New Features:
   - Machine Learning
      - Added the ability to learn non-negative weight vectors to the
        structural_assignment_trainer object.
      - Added two new graph clustering algorithms: Chinese Whispers and Newman's modularity
        clustering.
      - Added a number of new graph manipulation tools: sparse_matrix_vector_multiply(),
        is_ordered_by_index(), find_neighbor_ranges(), convert_unordered_to_ordered(),
        remove_duplicate_edges(), and the ordered_sample_pair object.
   - Networking
      - Added a set of tools for creating applications using the Bulk Synchronous Parallel
        computing model.  See the new bsp_ex.cpp example program for an introduction.
      - Added a routine that lets a user disable Nagle's algorithm on a TCP connection.
      - Added an asynchronous start routine to the server object.  This is the new
        start_async() method.
      - Added the network_address object.
      - Added connect_to() to the bridge interface.
   - Added find_max_parse_cky(), a method implementing the well known CKY algorithm for
     parsing probabilistic context free grammars.
   - Added the ability to label parts of objects with the mouse to the image_display
     widget.
   - Added the ability to put overlay circles and full_object_detections into the
     image_window widget.
   - Added a stddev() for matrix objects.
   - Added operator+() for running_stats and running_scalar_covariance.
   - Added an overload of murmur_hash3_128bit() that takes 4 integers instead of a block of
     memory.
   - Added rand::get_random_64bit_number().

Non-Backwards Compatible Changes:
   - Changed the image_dataset_metadata XML reading tools to use a map of strings to points
     to represent object parts. This change removes the old head point from a box since
     this information can now be represented in the parts map.
   - The syntax for passing order_by_distance and order_by_index to std::sort() is now
     slightly different since these functions are now templates.  However, this change
     allows them to work on any kind of sample_pair or ordered_sample_pair object.
   - The default distance value of a sample_pair is now initialized to 1 instead of
     infinity.

Bug fixes:
   - Added a patch, contributed by Martin Müllenhaupt, to fix a minor bug in the SQLite
     bindings.
   - Fixed a typo which would prevent code that called running_stats::max_n() from
     compiling.

Other:
   - Added a new documentation page for the various graph tools in dlib.
   - Added support for Visual Studio 2012.
   - Switched the sample_pair object to use double to store its distance value instead of
     float.
   - Added William Sobel's patch to the web server that improves its flexibility and
     security.
   - Changed the server object so you don't have to use the server::kernel_1a syntax to
     declare it anymore.  Now you just say server, server_iostream, or server_http
     depending on which one you want.
   - Changed the cmd_line_parser so you don't have to use the ::kernel_1a syntax anymore.
     Now it is declared like a normal single implementation object.
   - Set the default max number of connections a server will accept at a time to 1000
     rather than the previous default of infinity.

Release 17.48

Release date: Oct 18, 2012
Major Changes in this Release:
New Features:
  - Added more overloads of find_max_factor_graph_potts() to make applying it
    over a Markov random field of image pixels really simple.
  - Added overloads of serialize()/deserialize() so that they can serialize
    Google protocol buffer objects.
  - Image Processing:
      - Added find_points_above_thresh()
      - Added max_filter()
      - Added scan_image_movable_parts()
      - Added sum_filter_assign()
      - Added the full_object_detection object.
      - Added the ability to model objects with movable parts into the
        scan_image_pyramid object.  This update also includes all the needed tools
        to train movable part models using the structural_object_detection_trainer.
  - Machine Learning:
      - Added a per node loss option to the structural_svm_graph_labeling_problem's
        interface.
      - Added Emanuele Cesena's implementation of Sammon's nonlinear dimensionality
        reduction method.

Non-Backwards Compatible Changes:
  - To support movable part models, the serialization format of scan_image_pyramid
    objects was modified.  This breaks backwards compatibility with the previous
    format for scan_image_pyramid objects as well as object_detector instances
    that use the scan_image_pyramid.

Bug fixes:
  - Fixed a bug in auto_threshold_image() that caused it to give bad outputs
    when used with very large images.

Other:
  - Updated find_max_factor_graph_potts() to correctly say you can use infinite
    weights for the factor_value_disagreement() values since the code actually
    supports this.
  - Made integer serialization about 3 times faster.

Release 17.47

Release date: Jun 15, 2012
Major Changes in this Release:
New Features:
   - Improvements to linear algebra tools:
      - Added the lowerbound() and upperbound() routines for thresholding dense
        matrices.
      - Refined the tools for working with sparse vectors.  In particular,
        the following functions were added: min(), max(), make_sparse_vector(),
        add(), and subtract().  A number of existing routines were also updated
        to work with both sparse and dense vectors so that templated code which
        works on both vector types is simpler to write.
      - Added the += and -= operators to the set_subm(), set_rowm(), and set_colm()
        tools for operating on submatrices.
   - Optimization:
      - Added a new quadratic program solver, solve_qp4_using_smo().  This new
        solver is useful for solving quadratic programs corresponding to
        non-negative constrained primal quadratic programs.
      - Added an optional non-negativity constraint to the oca optimizer.
      - Added the min_cut object.  It provides a method to find the minimum weight
        cut on a graph.
      - Added tools for finding the maximum probability assignment in a Potts
        style Markov random field.  See the find_max_factor_graph_potts() routine
        for details.
   - Machine Learning:
      - Added structural SVM tools for learning the parameters of a Potts style
        Markov random field.  See the structural_graph_labeling_trainer and
        graph_labeler objects as well as their associated example program for
        details.
      - Added the ability to learn only non-negative weights to the
        svm_c_linear_trainer.
   - Improved Integration with OpenCV:
      - Updated the cv_image object so it works with cv::Mat as well as IplImage.
      - Added the toMat() routine for converting from a dlib style image to an
        OpenCV cv::Mat image.

Non-Backwards Compatible Changes:
   - Removed the dlib::sparse_vector namespace.  Everything from this namespace
     was moved into the normal dlib:: namespace so that code which works with
     both sparse and dense vectors is more cohesive.

Bug fixes:
   - Fixed a bug in find_max_factor_graph_viterbi() which sometimes occurred when
     the model order was larger than the number of variables.
   - Fixed a bug which caused a compiler error if you tried to call dot() on two
     1x1 matrices which were statically dimensioned.

Other:
   - Improved existing documentation: added pictures of the gui widgets,
     added documentation of the dlib::bridge protocol, and other minor
     usability improvements.

Release 17.46

Release date: Apr 11, 2012
Major Changes in this Release:
New Features:
   - Image Processing:
      - Added the option to make the features generated by poly_image rotationally
        invariant.
      - Added a set of routines for warping, scaling, and resizing images.
        See the new "Scaling and Rotating" section of the image processing
        documentation for details.
      - Added the heatmap() routine for converting an image into a heatmap.
   - Machine Learning
      - Updated the sequence labeling trainer to allow the user to set different
        loss values for different labels.
      - Added the rls object.  It is an implementation of the linear recursive
        least squares algorithm.
   - Added the get_option() routines which slightly simplify option parsing
     from the command line and config files.
   - Added the 128bit version of Murmur hash.
   - Added the kalman_filter and rls_filter objects.  These are tools for
     performing Kalman filtering and recursive least squares filtering.
   - Added the circular_buffer object.

Non-Backwards Compatible Changes:
   - The poly_image generates slightly different features in this new release.
     Therefore, classifiers trained using the previous version will need to be
     retrained if they are switched to the new version of poly_image.
   - Changed the xcorr() functions so they take the complex conjugate of the right
     hand arguments if they are complex numbers.  This way they do a proper
     cross-correlation and also mirror the behavior of MATLAB.  However, this
     breaks backwards compatibility with the previous behavior of xcorr().
   - Previously, dlib included two versions of dlib::array.  However, to
     simplify the user interface, dlib now includes only the contiguous
     memory implementation of dlib::array.  This change should only affect
     you if you wrote code which assumed dlib::array::set_max_size() only
     allocated a small amount of RAM.  The new behavior is similar to the
     std::vector::reserve() routine.  That is, dlib::array::set_max_size()
     will allocate the requested amount of memory immediately.

Bug fixes:
   - Fixed a bug which caused certain matrix expressions to not compile
     when the BLAS bindings were enabled.  In particular, expressions which
     involved a 1x1 matrix sometimes didn't compile.

Other:
   - Made the matrix routines min(), max(), sum() and mean() work with
     complex numbers.
   - Turned the array object into a single implementation object.  Now arrays
     can be created using the normal array<type> obj; syntax.  Additionally,
     all extensions were merged into the array object.
   - Added an example program which better documents how to create training
     data for the object detection tools as well as how this data can be used.
     See the train_object_detector.cpp example for details.

Release 17.45

Release date: Jan 29, 2012
Major Changes in this Release:
New Features:
   - Added tools for timing blocks of code
   - Machine Learning
      - Added a set of tools for learning to solve the assignment problem.
        See the structural_assignment_trainer and its associated example
        program for an introduction.
      - Added random projection based locality sensitive hashing tools.
      - Added tools to simplify the creation of scan_image_pyramid objects.
        See the object_detector_ex.cpp example program for details.
   - Image Processing
      - Added sum_filter() and spatially_filter_image_separable_down()
      - New feature extractors: poly_image, nearest_neighbor_feature_image, and
        fine_hog_image

Non-Backwards Compatible Changes:
   - Changed the serialization format for rand objects.
   - Changed the order of arguments for the sequence_labeler's constructor.
   - Object Detection Changes
      - Some parts of the object detection tools have been refactored.  In particular,
        the interfaces of the scan_image_pyramid and structural_object_detection_trainer
        have been changed slightly to improve usability.
      - Made the test_box_overlap a little more flexible.  This change breaks
        backwards compatibility with the previous version though.
      - The hashed_feature_image object has been made more general.  It now
        uses a user supplied hashing function rather than its own hashing
        implementation.
      - Removed constness from the operator() member functions of the
        object_detector.
   - Fixed improper normalization in the gaussian() functions.  The
     normalization constant was being computed incorrectly.
   - Sequence labeling feature extractors must now define a sequence_type
     typedef instead of sample_type.  This change allows the user to use any
     type of sequence, not just std::vector objects.

Bug fixes:
   - Changed the add_probability() method of joint_probability_table so
     it does a saturating add rather than a normal add.  This ensures the
     probability value stays exactly <= 1.  Previously, floating point
     rounding error could cause it to be slightly above 1 and would therefore
     cause some asserts to misfire during debugging mode.
   - The object_detector had code in it which limited the number of outputs
     to 100 rectangles.  This has been removed.
   - Fixed improper normalization in the gaussian() functions.  The
     normalization constant was being computed incorrectly.

Other:
   - dlib::rand can now generate Gaussian random numbers.
   - The structural_object_detection_trainer will now automatically setup
     appropriate non-max suppression parameters if the user doesn't supply them.
   - The structural_object_detection_trainer has been optimized and now runs
     significantly faster than in previous dlib releases.
   - The tools folder containing htmlify, imglab, and mltool is now included
     in the dlib release archive files.  Previously, these tools were only
     available directly from source control.

Release 17.44

Release date: Nov 21, 2011
Major Changes in this Release:
New Features:
   - Machine Learning
      - Added the histogram intersection kernel for sparse and dense vectors.
      - Added a set of tools to allow a user to easily learn to do sequence
        labeling using dlib's structural SVM implementation.  See the new
        sequence_labeler object and its associated example program for an
        introduction.
   - Image processing:
      - Added segment_image()
      - Added randomly_color_image()
      - Added the border_enumerator
   - Added the disjoint_subsets object, it is an implementation of the
     union-find algorithm/disjoint-set data structure.
   - Added new matrix routines: conv(), conv_same(), conv_valid(), xcorr(),
     xcorr_same(), xcorr_valid(), and flip().

Non-Backwards Compatible Changes:
   - Changed find_max_factor_graph_viterbi() so you can use run-time
     defined order and num_states parameters.

Bug fixes:
   - The last dlib release added a max_iterations parameter to the
     svm_c_linear_trainer and svm_c_ekm_trainer objects.  However,
     there was a bug which made them only do at most 16 iterations,
     which is too few to solve many problems.  This has been fixed.
   - Fixed a bug in is_const_type.  It didn't work for reference types.
   - Fixed a bug in the SQLite binding routine statement::get_column_as_text().
     It didn't work correctly if the column contained a NULL.
   - Fixed a bug in find_max_factor_graph_viterbi() which occurred when a
     zero order model had negative factor values.

Other:

Release 17.43

Release date: Oct 21, 2011
Major Changes in this Release:
New Features:
   - Two new routines for performing MAP inference in factor graphs:
      - For chain-structured graphs: find_max_factor_graph_viterbi()
      - For general graphs:          find_max_factor_graph_nmplp()
   - Image Processing
      - Added more tools for creating image pyramids.  See pyramid_down_5_4,
        pyramid_down_4_3, and pyramid_down_3_2.
      - Added more image filtering and morphology functions.
      - Added a set of tools for creating sliding window classifiers:
         - Added the scan_image() routine.  It is a tool for sliding a set of
           rectangles over an image space and finding the locations where the sum
           of pixels in the rectangles exceeds a threshold.  Also added
           scan_image_pyramid, which is a tool for running scan_image() over an
           image pyramid.
         - Added the structural_object_detection_trainer.  This is a tool which
           formulates the sliding window classifier learning problem as an
           instance of structural SVM learning.
         - Added a variety of supporting tools and two object detection example
           programs.
   - Added the following functions for computing statistics on vectors:
     mean_sign_agreement(), correlation(), covariance(), r_squared(),
     and mean_squared_error()
   - Added a C++ wrapper for SQLite (see the new database and statement objects)

Non-Backwards Compatible Changes:
   - Changed the interface to the ridge regression trainer objects so that they
     report the entire set of leave-one-out prediction values rather than a
     summary statistic like mean squared error.
   - Changed the serialization routine for bgr_pixels to store the pixels in BGR
     order rather than RGB.
   - Changed the interface for the spatially_filter_image() routine to take the
     filter as a matrix rather than C-array.  Also, now it won't force signed pixel
     values to 0 if they go negative.
   - Changed the test_regression_function() and cross_validate_regression_trainer()
     routines so they return both the MSE and R-squared values rather than just the
     MSE.
   - Changed suppress_non_maximum_edges() to use the L2 norm instead of L1 norm
     for measuring the strength of an edge since this produces a slightly better
     result.

Bug fixes:
   - The image_display didn't display overlay rectangles quite right.  If you zoomed
     in you could see that some of the pixels which are inside the rectangle were
     outside the overlay.  Specifically, the right column and bottom row was outside
     the overlay rectangle.  This has been fixed.  Now all pixels which are supposed
     to be part of a rectangle are drawn as being inside the overlay rectangle.
   - Fixed a bug pointed out by Martin Müllenhaupt which caused the windows socket
     code to not compile when used with the mingw-cross-env project.
   - Fixed a bug in the png_loader.  If you loaded an image with an alpha channel
     into something without an alpha channel there were uninitialized values being
     alpha blended into the image.
   - Fixed a bug in the cpp_tokenizer that only shows up on newer versions of gcc.
     It wasn't tokenizing double quoted strings right.
   - Fixed a bug in spatially_filter_image() which showed up when using non-square
     filters.  The bug would cause the edges of the output image to be incorrect.
   - Fixed a bug in the matrix class.  Expressions of the form mat *= mat(0) would
     evaluate incorrectly because the *= operator took the right hand side by reference
     and thus experienced an aliasing problem.  The other op= operators had similar
     problems and have also been fixed.
   - Fixed a bug pointed out by Justin Solomon which could cause the svr_trainer and
     svm_c_trainer to produce incorrect results in certain unusual cases.

Other:
   - Added a more complete set of methods for converting between image space and
     the downsampled hog grid used by hog_image.  Now you can convert from image
     to hog in addition to hog to image.
   - Made the integral_image more general by making it templated on the type of
     scalar used to store the sums.

Release 17.42

Release date: Jun 24, 2011
Major Changes in this Release:
New Features:
   - Added the check_sub_option() method to the command line parser check
     object.
   - Added match_endings to the dir_nav utils.
   - Added a set_current_dir() function.
   - Added the distance_to_rect_edge() routine.
   - Added support for user drawn rectangle overlays and selectable overlays
     to the image_display widget.

Non-Backwards Compatible Changes:

Bug fixes:
   - Fixed a bug in the image_display widget.  If you switched it between
     images of a different size while any kind of zoom was in effect
     it could cause a segmentation fault.

Other:

Release 17.41

Release date: Jun 12, 2011
Major Changes in this Release:
New Features:
   - You can now add tasks to a thread_pool by value, using the new
     add_task_by_value() method.

Non-Backwards Compatible Changes:

Bug fixes:
   - Fixed a bug which caused multiply defined symbol errors during linking
     if the PNG saving routine was #included.

Other:
   - Optimized the threaded and distributed structural svm solvers for the
     case where there are many data samples and the separation oracle is
     quick to evaluate.

Release 17.40

Release date: Jun 05, 2011
Major Changes in this Release:
New Features:
   - Added a function for saving to the PNG image format.
   - Added Austin Appleby's excellent MurmurHash3 hashing code and setup some
     additional convenience functions.  These functions are murmur_hash3() and
     various overloads of hash().

Non-Backwards Compatible Changes:
   - Made get_pixel_intensity() more efficient.  However, the value returned
     is slightly different than it used to be for RGB pixel types.

Bug fixes:
   - Setup proper error handling for libpng in the png_loader.  Now if the PNG
     file is corrupted in the middle it won't just print a message and abort
     the program.
   - Fixed a bug in assign_pixel_intensity() that happened when the target pixel
     was an RGB pixel with an alpha channel.

Other:
   - Added a Frequently Asked Questions page
   - Changed the array2d object so you don't have to say array2d<type>::kernel_1a
     anymore to declare it.  Now you just say array2d<type>.

Release 17.39

Release date: May 22, 2011
Major Changes in this Release:
New Features:
   - Added tools for distributing the work involved in solving a structured
     SVM problem over many computers and CPUs.
   - Added the bridge.  It allows a dlib::pipe to be used for networked
     communication.

Non-Backwards Compatible Changes:
   - Removed the DLIB_REVISION macro and replaced it with DLIB_MAJOR_VERSION and
     DLIB_MINOR_VERSION.

Bug fixes:

Other:
   - dlib's version control system has switched from Subversion to Mercurial.

Release 17.38

Release date: May 7, 2011
Major Changes in this Release:
New Features:
   - Added the max_sum_submatrix() function to the optimization tools.
   - Upgraded the pyramid_down function object so it can create color pyramids.
     Also, added some functions which define the coordinate transforms between
     different layers in an image pyramid.

Non-Backwards Compatible Changes:
   - Changed the oca_problem interface to the oca optimizer.  Now the
     optimization_status() function reports back the current risk and risk gap
     in addition to the overall objective value and objective gap.
   - Changed the stopping condition for the structured svm to the one suggested
     by the Joachims paper.  Now it stops when the risk gap is below a user
     supplied epsilon.

Bug fixes:

Other:
   - Various usability improvements.
   - Improved the feature vector caching in the structural_svm_problem object.
   - Some objects were setup as multi-implementation objects but only had one
     implementation.  I went through dlib and switched these to single implementation
     objects.  So for example, to use the dlib crc32 module you used to declare an
     object of type "crc32::kernel_1a" but now you can just say "crc32".  Note that
     I did this change in a way that maintains backwards compatibility with previous
     versions.  So crc32::kernel_1a is still allowed but that form is officially
     deprecated.  The modified objects are as follows:
      - base64
      - byte_orderer
      - config_reader
      - crc32
      - pipe
      - rand

Release 17.37

Release date: Mar 24, 2011
Major Changes in this Release:
New Features:
   - Added a multiclass support vector machine.
   - Added a tool for solving the optimization problem associated with
     structural support vector machines.
   - Added new functions for dealing with sparse vectors: add_to(),
     subtract_from(), max_index_plus_one(), fix_nonzero_indexing(), a
     more flexible dot(), and I renamed assign_dense_to_sparse() to assign()
     and made it more flexible.

Non-Backwards Compatible Changes:
   - Renamed max_index_value_plus_one() (a function for working with graphs) to
     max_index_plus_one() so that it uses the same name as the essentially
     identical function for working with sparse vectors.
   - I simplified the cross_validate_multiclass_trainer(), cross_validate_trainer(),
     test_binary_decision_function(), and test_multiclass_decision_function()
     routines.  They now always return double matrices regardless of any other
     consideration.  This only breaks previous code if you had been assigning
     the result into a float or long double matrix.
   - Renamed assign_dense_to_sparse() to assign()

Bug fixes:
   - Fixed a bug in load_libsvm_formatted_data().  I had forgotten to clear the
     contents of the labels output vector before adding the loaded label data.
   - Fixed a bug in the kernel_matrix() function.  It didn't compile when used
     with sparse samples which were of type std::vector<std::pair<> >.
     Moreover, some of the trainers have a dependency on kernel_matrix() so this
     fix makes those trainers also work with this kind of sparse sample.

Other:
   - Added a value_type typedef to matrix_exp so it's easier to write templates
     which operate on STL containers and matrix objects.

Release 17.36

Release date: Mar 2, 2011
Major Changes in this Release:
New Features:
   - Added an implementation of the Hungarian algorithm for solving the optimal
     assignment problem (in the new max_cost_assignment() routine).

Non-Backwards Compatible Changes:

Bug fixes:
   - Fixed a problem which prevented the any_function unit test from compiling
     in visual studio 2008.

Other:
   - Changed the oca optimizer so that it warm starts the QP subproblem
     rather than resolving it from scratch during each iteration. This
     improves the speed and stability of the algorithm.

Release 17.35

Release date: Feb 10, 2011
Major Changes in this Release:
New Features:
   - Added the rr_trainer.  It is a version of krr_trainer which is optimized
     for use with the linear_kernel.
   - Added the approximate_distance_function() routine.  It is the core optimizer
     behind the reduced2() trainer adapter.
   - Added an any_function which supports the same functionality as std::function
     from the upcoming C++0x standard.  I added this so dlib can be modified to
     easily support lambda functions while still being compilable with compilers
     which don't support the new std::function.
   - Added overloads of all the GUI event handlers so you can use general functions
     as callbacks (via any_function).  This way, if you have a C++0x compiler, you
     can use lambda functions with the event handlers.
   - Added the split() function for splitting up strings.

Non-Backwards Compatible Changes:
   - Improved the distance_function object by turning it into a properly
     encapsulated class rather than just a simple struct.  I also added
     overloaded +, -, *, and / operators for this object so you can do the
     kind of arithmetic you would expect on an object which represents a
     point in a vector space.  This breaks backwards compatibility with
     the previous interface though as the member variables are now private.

Bug fixes:
   - Fixed a compile-time error in the kernel_matrix().
   - Fixed a bug in an assert in the spatially_filter_image() function.
   - Applied a patch from Nils Labugt which fixes a runtime bug in the gui_core
     component.  The bug caused a crash when using X11 and Ubuntu 10.10 in
     certain cases.
   - Updated code so that it compiles with the clang compiler.

Other:
   - Updated the image_display widget so you can zoom in and out using the
     mouse wheel.

Release 17.34

Release date: Jan 03, 2011
Major Changes in this Release:
New Features:
   - General Stuff
      - Added the promote template
      - Added the basic_type template
      - Added the assign_image_scaled() function
      - Added the unordered_pair object.
      - Added the symmetric_matrix_cache() function
      - Added two new quadratic program solvers.  The solve_qp2_using_smo
        and solve_qp3_using_smo objects.

   - Machine Learning Stuff
      - Added the svm_c_trainer object.  It implements C-SVM classification and
        allows the user to set different C values for each class.
      - Added the svm_one_class_trainer object.
      - Added the svr_trainer object.  It implements epsilon-insensitive
        support vector regression.
      - Added two new any objects.  The any_decision_function for containing
        decision function style objects and the any_trainer for trainers.
      - Added cross_validate_regression_trainer()
      - Added test_regression_function()
      - Added the probabilistic() function.  It is a trainer adapter that
        simply calls train_probabilistic_decision_function().
      - Added tools for multiclass classification
         - Added one_vs_one_trainer
         - Added one_vs_all_trainer
         - Added cross_validate_multiclass_trainer()
         - Added test_multiclass_decision_function()

Non-Backwards Compatible Changes:
  - invalid_svm_nu_error has been renamed to invalid_nu_error.
  - Changed the pixel_traits so that signed grayscale pixel types are allowed.
    This involved adding a few new fields to pixel_traits.  I also changed the
    get_pixel_intensity() function so that its return value is of the same type
    as the basic pixel type rather than always being unsigned long.
  - Removed the kernel_type typedef from the normalized function since this
    meta-object should be capable of working with non-kernel decision functions.
  - train_probabilistic_decision_function() no longer accepts column vectors of
    samples and labels.  Now it only accepts std::vectors of samples and labels.

Bug fixes:
  - Fixed a bug in the deserialization code for the sparse kernels.  The bug
    prevented code which used the deserialize() routine from compiling.

Other:
  - Changed the image display GUI widgets to use the assign_image_scaled()
    function internally.  Now they will accept just about any image and
    do the right thing.
  - Modified the type_safe_union so that you can call apply_to_contents() on const
    type_safe_unions.
  - Added serialization support for std::pair objects.
  - Made the train_probabilistic_decision_function() more general by making it work
    with any kind of trainer object rather than only ones which produce
    dlib::decision_function objects.  I also made it work with trainers that only
    take std::vectors.
  - Added overloads to the config_reader's methods to allow it to load directly
    from a file name given as a string in addition to taking istream objects.

Release 17.33

Release date: Dec 05, 2010
Major Changes in this Release:
New Features:
  - Added the ability to add/subtract scalar values to/from all the elements
    of a matrix using the - and + operators.
  - Added a trust region optimizer.
  - Added Levenberg-Marquardt and LM/quasi-newton hybrid methods for solving
    non-linear least squares problems.
  - Added an any container object.

Non-Backwards Compatible Changes:

Bug fixes:
  - Fixed a compiler warning and also a runtime bug in sort_basis_vectors().
    The bug triggered when all the basis vectors were included in the final
    answer.

Other:
  - Added a bunch of overloads to catch operations on diagonal matrices
    and use more efficient code paths for them.  For example, inv(diagm(d))
    turns into diagm(reciprocal(d)).  Multiplication by a diagonal matrix
    is now also handled efficiently.

Release 17.32

Release date: Nov 13, 2010
Major Changes in this Release:
New Features:
  - Added a class for reading JPEG image files.
  - Added scale_rows(), flipud() and fliplr() matrix functions.
  - Added console_progress_indicator.  It is a tool for measuring how long a
    task will take.
  - Added sort_basis_vectors().  It is a function for performing supervised
    basis selection.

Non-Backwards Compatible Changes:
   - Renamed the linearly_independent_subset_finder's dictionary_size() member
     function to size().  This way, linearly_independent_subset_finder objects
     can be used in many templated functions which expect objects which look
     like arrays.

Bug fixes:
  - Changed the assert macros so that they don't use __PRETTY_FUNCTION__
    with gcc 4.4.5 since, on Ubuntu at least, this version of gcc segfaults
    when __PRETTY_FUNCTION__ is used within certain template constructs.
  - Improved the alias detection capability of kernel_matrix() expressions.
    Now statements of the form: sample = kernel_matrix(kern, *, sample) can
    be used since the aliasing of sample will be handled.

Other:
  - Generally tried to make things more usable.
  - Optimized matrix expressions such as mat*diagm(vect)
  - Made the code in chol() more robust to indefinite matrices.

Release 17.31

Release date: Sep 15, 2010
Major Changes in this Release:
New Features:
   - Added the running_scalar_covariance object.
   - All the matrix decomposition routines now use LAPACK when DLIB_USE_LAPACK
     is #defined.

Non-Backwards Compatible Changes:
   - Removed the dlib::EOTHER constant since it conflicts with visual
     studio 2010.
   - Changed the svd functions so you can't supply output matrices which use
     both column and row major layouts.  Now all the output matrices need to
     use the same memory layout.
   - Removed the qr_decomposition::get_householder() function.

Bug fixes:
   - Minor fixes so that dlib compiles in Visual Studio 2010

Other:
   - Added an overloaded matrix_assign() that handles symmetric kernel_matrix()
     expressions more efficiently by only evaluating the upper triangular part
     of the matrix.

Release 17.30

Release date: Jul 28, 2010
Major Changes in this Release:
New Features:

Non-Backwards Compatible Changes:

Bug fixes:
   - Fixed a compile-time bug in the matrix related to multiplication by
     subm() expressions when the BLAS bindings were enabled.
   - Fixed a bug in train_probabilistic_decision_function() which could
     cause it to go into an infinite loop when working with very large
     datasets.

Other:

Release 17.29

Release date: Jul 25, 2010
Major Changes in this Release:
New Features:
  - Added a reference_wrapper implementation and modified the thread_function
    slightly so it works with it.
  - Added an implementation of kernel ridge regression.
  - Added a simple newton search strategy for optimizing functions.

Non-Backwards Compatible Changes:
  - If you have created your own matrix expressions then its possible this
    new release will cause them to not compile.

Bug fixes:
  - Fixed a bug in scale_columns.  It said it didn't have any destructive aliasing
    when in fact it destructively aliased its second argument.
  - Fixed a bug in the random number generator where setting the seed back to ""
    didn't result in the object going back to its initial state.

Other:
  - Reorganized the matrix expression code.  It's now much simpler and the
    library includes a new example program which details the steps needed to
    create new matrix expressions.
  - Changed the train_probabilistic_decision_function() routine so that it uses
    a more numerically stable method to perform its maximum likelihood optimization.
  - Added missing get/set epsilon functions to the RVM training objects.
    I also changed the default epsilon from 0.0005 to 0.001.

Release 17.28

Release date: Jun 14, 2010
Major Changes in this Release:
New Features:
   - Added the simplify_linear_decision_function() routines.
   - Added the find_approximate_k_nearest_neighbors() function.
   - Added the fill_lisf() function.

Non-Backwards Compatible Changes:
   - Made the sample_pair have a default distance of infinity instead of
     the max floating point value.  I also reworked the graph creation functions
     to make them a little more versatile.  Now you can use infinite distances to
     indicate that certain nodes are not connected at all.
   - Changed the linear_manifold_regularizer to normalize the regularization
     parameter by the sum of edge weights instead of the sum of edges.

Bug fixes:
   - Fixed a bug in the timer_kernel_2 object.  In certain rare cases it would
     stop calling the action function and essentially shut down without being
     told to do so.

Other:
   - Made the reduced() and reduced2() functions more efficient.
   - Many small usability improvements here and there.

Release 17.27

Release date: May 16, 2010
Major Changes in this Release:
New Features:
   - Added the svm_c_ekm_trainer.  It is a kernelized version of the fast
     linear trainer svm_c_linear_trainer.
   - Added the linear_manifold_regularizer and some supporting tools.
   - Added the sum_rows(), sum_cols(), join_rows(), join_cols(), reshape(),
     and pointer_to_matrix() functions.
   - Added the randomly_subsample() function.

Non-Backwards Compatible Changes:

Bug fixes:
   - Fixed some minor compile time bugs on certain older compilers.

Other:
   - Updated the += and -= matrix operators to be a little more flexible.  Now
     if you try to apply them to a matrix of the wrong size it will automatically
     resize the target matrix and just do a normal assignment.
   - Removed the requirement that you load dng files into an image of the exact
     pixel type that created the file.  Now you can use any pixel type.  I also
     changed the code so that grayscale pixels with more than 16 bits get saved as
     16 bit grayscale images instead of 8 bit images.

Release 17.26

Release date: Mar 07, 2010
Major Changes in this Release:
New Features:
   - Added the solve_qp_using_smo() function to solve certain quadratic
     programs.
   - Added the oca object.  It is an implementation of the Optimized Cutting
     Plane Algorithm.
   - Added a linear SVM trainer that uses oca.
   - Added an implementation of the Histogram of Oriented Gradients algorithm
   - Added a simple tool for making image pyramids
   - Added the running_covariance object
   - Added a simple linear (i.e. non-kernelized) kmeans implementation
   - Added support for serializing dlib::int64
   - Added some functions to load and save LIBSVM formatted data files.

Non-Backwards Compatible Changes:
   - Changed the definition of dlib's sparse vector format to require
     unsigned integral keys.  Having this requirement is nice because it
     creates a simple correspondence between dense vector index values and
     sparse vector keys.  The previous sparse vector definition was
     excessively generic.
   - Renamed sparse_vector::dot_product() to sparse_vector::dot() so that
     both dense and sparse vectors have a global function with the same
     name (i.e. dot()).

Bug fixes:
   - Fixed a bug discovered by Mitchell Peabody.  In some instances trying to
     deserialize a std::vector would fail to compile.

Other:
   - Increased the number of template arguments of the type_safe_union from 10
     to 20.  Additionally, I made the get_id() function public and renamed it
     to get_type_id().  I also added a comment explaining the serialization
     format of type_safe_union objects.
   - Moved the optimization algorithms into their own page in the documentation.
   - Added a Suggested Books page to the documentation

Release 17.25

Release date: Feb 05, 2010
Major Changes in this Release:
New Features:
   - Added the ability to compute transformation matrices that map between
     the representations used by different empirical_kernel_maps.  Also added
     the ability to compute projection error.
   - Added the random_subset_selector object.
   - Added the compute_mean_squared_distance() function.

Non-Backwards Compatible Changes:
   - Modified the logger's hook implementation so that it uses a special stream
     buffer instead of an std::ostringstream.  This way logging doesn't cause
     memory allocations.  This breaks backwards compatibility with the previous
     hook function API but only slightly.  The new hook functions must take a
     const char* instead of std::string.
   - Added the const_ret_type typedef to the matrix_exp.  It is now required that
     all matrix expressions define this type.  This enables the expressions to
     return elements by constant reference when appropriate rather than always
     returning by value.

Bug fixes:
   - Fixed a bug in the matrix BLAS bindings that caused BLAS to return an invalid
     argument error.  The error occurred when general matrix multiply expressions
     were transposed and didn't result in a square matrix.  E.g. mat = trans(a*b)
     where mat isn't square.
   - Fixed potential compile time bugs in the comparison operators for futures.
   - Added a missing check for division by zero in the SURF feature extractor.
   - Modified the find_min_single_variable() function so that it is more
     robust when working with functions that are made up of a bunch of
     constant value strips.  Previously, these kinds of functions could
     cause the optimization to fail.

Other:
   - Changed the regression test suite so that when it sets the logging level
     it now sets it for all loggers.  Not just ones that start with "test."

Release 17.24

Release date: Jan 04, 2010
Major Changes in this Release:
New Features:
   - Added some MATLAB style thresholding relational operators to the matrix.
   - Added the kernel_matrix() functions.
   - Added the empirical_kernel_map object.
   - Added the discriminant_pca object.
   - Added the read_write_mutex object.

Non-Backwards Compatible Changes:
   - Renamed the support_vectors member of the decision_function and
     distance_function classes to basis_vectors.  This name more appropriately
     reflects how these two classes are used within the library.
   - Changed the matrix_exp interface slightly.  This could only impact users
     who created their own custom matrix expressions.  If you don't get a
     compiler error then you don't have to worry about it.

Bug fixes:
   - Fixed a minor error in the LBFGS code.
   - Added a missing check for division by zero to the kcentroid, krls,
     and linearly_independent_subset_finder classes.  If someone added
     the zero vector to them as the first training example a division by zero
     could result.
   - There were a few cases where the code wouldn't compile when using
     matrices of complex numbers.  There was also a runtime bug that triggered
     when a rank 1 update was performed where one of the vectors was conjugated
     and two or more transposes were used in certain positions.  This bug
     caused the wrong output to be computed if the BLAS bindings were used.
     Both of these bugs have been fixed.
   - Fixed a bug in the http server that affected cookies with certain kinds of
     data.  The result was invalid data being sent back to the web browser.

Other:
   - Generally improved the BLAS bindings for the matrix object.

Release 17.23

Release date: Oct 20, 2009
Major Changes in this Release:
New Features:
   - Added the pointer_to_column_vector function.
   - Added the BOBYQA algorithm for derivative-free optimization.
   - Added some functions to make it easy to do a line search on a function
     of a single variable when derivatives are not available.

Non-Backwards Compatible Changes:

Bug fixes:
   - Fixed a bug in the cpp pretty printer.  It wasn't parsing
     exponentiated numbers like 1e100 correctly.

Other:
   - Added a model selection example program using grid search
     and the new BOBYQA algorithm.

Release 17.22

Release date: Sep 10, 2009
Major Changes in this Release:
New Features:
   - Added an implementation of the L-BFGS algorithm for unconstrained non-linear
     optimization.

Non-Backwards Compatible Changes:
   - Refactored the optimization code.  It is now much more flexible but
     this resulted in changes to the API.  See the optimization example program
     for a discussion of the new API.

Bug fixes:
   - Fixed a bug in the get_filesystem_roots() roots function that
     prevented it from compiling.

Other:

Release 17.21

Release date: Aug 30, 2009
Major Changes in this Release:
New Features:
   - Added the ability to use a kernel cache to the batch_trainer object.
   - svm_pegasos can now be configured to use two different lambda arguments
     for use with unbalanced data.
   - Added the reciprocal_max() and dot() matrix functions.
   - Added the bgr_pixel and cv_image objects so that OpenCV images can
     be easily used with dlib routines.

Non-Backwards Compatible Changes:
   - I changed the batch trainers so that they always call clear() on the
     trainer being used before training begins.
   - Modified the svm_pegasos class so that the user can set independent lambda
     parameters for each class.  This breaks backwards compatibility with
     the previous interface slightly and changes the serialization format
     of this class.
   - Split the vector_normalizer into a normal normalizer and a pca normalizer
     version.
   - The zoomable_region widget now uses exponential rather than linear
     zoom scaling since this is much more pleasing to use.  There is now
     a new requirement on the zoom increment that it must be between 0
     and 1.

Bug fixes:
   - Fixed a bug in the cross_validate_trainer_threaded() function.  It could
     deadlock if more than about 10 folds were requested.
   - Fixed the serialization functions for the normalized_function object.
     They will now work with custom normalizer function objects.
   - Fixed a minor bug in the zoomable_region::set_min_zoom_scale() function.
     It didn't always end up zooming in a smooth sensible manner after this
     function was called.

Other:
   - Made the thread_function object more general.   It can now handle
     arbitrary functions of up to four arguments.

Release 17.20

Release date: Jul 11, 2009
Major Changes in this Release:
New Features:
   - Added the reshape_to_column_vector() function.
   - Added a hook to the logger object that lets you set a different kind of
     output logging destination (in addition to the std::ostream supported
     already).
   - Upgraded the scoped_ptr so that it can handle array pointers as well
     as customer deleter functions.
   - Added overloads of the kernel_derivative object for all the kernels
     in dlib.

Non-Backwards Compatible Changes:
   - Reworked the config_reader interface a little to make it easier to use.
     In particular, I removed the enumerator over blocks in favor of a simple
     get_blocks() function that just returns a std::vector of all the blocks.
     I also removed the requires clauses on the block and key accessor functions
     and instead made a request for a non-existent key/block result in a non-fatal
     exception.  This way users can let the config reader perform a more natural
     role in config file validation (by catching this exception and acting
     accordingly).
   - It is now illegal to multiply matrices of size zero together.

Bug fixes:
   - Fixed the gaussian() function used by the SURF code.  It wasn't computing
     a properly weighted Gaussian function.
   - Fixed a few things in various parts of the code to avoid compiler errors
     in certain use-cases.
   - Added a missing rethrow statement.  The xml parser would eat exceptions
     thrown by event handlers rather than letting them propagate out as
     documented in the specification.

Other:

Release 17.19

Release date: May 25, 2009
Major Changes in this Release:
New Features:
    - Added an implementation of the SURF algorithm which includes the
      following new objects and functions:  integral_image, hessian_pyramid,
      interest_point, surf_point, compute_dominant_angle(),
      compute_surf_descriptor(), haar_x(), haar_y(), get_interest_points(),
      and get_surf_points().
    - Added the zeros_matrix() and ones_matrix() functions.
    - Added serialization support to the type_safe_union object.
    - Added the grow_rect() and shrink_rect() functions.
    - Added the get_files_in_directory_tree() function.
    - Added the null_trainer_type object.
    - Added the roc_trainer_type object.

Non-Backwards Compatible Changes:
    - Removed some extraneous get_kernel() functions from some of the
      trainer adapter classes since they really aren't needed.

Bug fixes:
    - Changed the socket read/write code so that it can handle a large
      number ( > 2 billion) of bytes in I/O calls.
    - Added a missing type cast to the reciprocal() function to fix a compile
      time error you get when you use it with complex<float> type matrices.
    - Fixed a bug in the assign_border_pixels() and zero_border_pixels() functions.
      Their contracts said there was no upper limit on the size of the border that
      could be assigned/zeroed but the implementations failed to handle the case
      where the border was bigger than the image.

Other:
    - Generally cleaned up the code and documentation here and there.
    - Added in Steven Van Ingelgem's patches to improve the usability of the
      HTTP server object.
    - Updated the load_bmp() function so that it is capable of reading BMP
      files that have been compressed with the RLE compression sometimes
      used for 8bit BMP files.
    - Merged in Miguel Grinberg's patch to add a non-blocking read() function to the
      connection object.

Release 17.18

Release date: Apr 5, 2009
Major Changes in this Release:
New Features:
   - Added a set of kernels that can operate on sparse vectors.
   - Added the image_window and image_display objects.
   - Added the rotate_point() function and the point_rotator object.

Non-Backwards Compatible Changes:
   - Added Steven Van Ingelgem's patch to add the body of data posted
     back to the server into the incoming data object given to the
     server_http::on_request() handler.  This removes the content_length
     field and replaces it with a string that contains the body of content
     data.

Bug fixes:
   - Fixed a compile time bug in the offset_kernel.

Other:
   - Added optimized overloads of the kcentroid object for various
     linear kernels.
   - Changed all the tests in the dlib test suite to use a new DLIB_TEST
     macro instead of DLIB_CASSERT since the tests really aren't
     technically assertions

Release 17.17

Release date: Mar 16, 2009
Major Changes in this Release:
New Features:
   - Added the strings_equal_ignore_case() functions

Non-Backwards Compatible Changes:
   - Changed the on_request() function in the http server
   - Changed the serialization format of the kcentroid and svm_pegasos
     objects
   - By default, the kcentroid now keeps the most linearly independent
     dictionary vectors rather than the newest

Bug fixes:

Other:
   - Split the algorithms documentation page into three pages, algorithms,
     machine learning, and bayes nets.
   - Merged in Steven Van Ingelgem's patch to cleanup the HTTP server and
     add new functionality.  This breaks backwards compatibility with the
     previous on_request() interface but it is easy to update old code and
     it is now much cleaner and easier to use.
   - Changed the kcentroid so that you can tell it to keep the most linearly
     independent vectors rather than the newest vectors.  I then changed the
     svm_pegasos object so that it has a max number of support vector setting
     so that the user can supply an upper limit on the number of support
     vectors to use.

Release 17.16

Release date: Mar 08, 2009
Major Changes in this Release:
New Features:
   - Matrix related
      - Added the find_min_and_max(), index_of_min(), index_of_max(), trace(),
        randm(), linspace(), logspace(), and cartesian_product() functions.
   - Machine learning related
      - Added the offset_kernel
      - Added some functions to the kcentroid to allow the user to compute
        the inner_product of kcentroids as well as a few other useful things.
      - Added a kernelized version of the Pegasos SVM training algorithm.

Non-Backwards Compatible Changes:
   - Changed the range() function so that it returns row vectors
     instead of column vectors.

Bug fixes:
   - Changed threading code to avoid a potential race condition during
     program termination.
   - Fixed a few incorrect DLIB_ASSERT statements
   - Fixed a bug in the way Content-type was handled in HTTP posts.
   - Fixed a bug in subm() that showed up when statically dimensioned row
     vectors were used to select a sub matrix.

Other:
   - Added some functions to the rectangle to make it easy
     to get the corner points.
   - The cross validation functions no longer allow invalid_svm_nu_error
     exceptions to escape.  Instead, they are assigned low CV scores.
   - Made std_vector_c able to copy directly from std::vector objects.
   - Added a get_socket_descriptor() function to the connection class.

Release 17.15

Release date: Feb 03, 2009
Major Changes in this Release:
New Features:
   - Matrix related
      - Added QR, LU, Cholesky, and eigenvalue decomposition class objects
      - Added overloads for rowm() and colm() that allow you to pick out
        less than an entire vector
      - Added the lowerm() and upperm() functions
      - Added the const_temp_matrix class

Non-Backwards Compatible Changes:
   - Renamed the cholesky_decomposition() function to chol()

Bug fixes:
   - Fixed some errors in the requirements for calling the new rowm() and
     colm() functions.
   - Fixed dlib::abs() so that it returns the right type when used
     with complex matrices.
   - Fixed a race condition in the logger object.  It was missing a needed call
     to unregister_thread_end_handler().  What could happen in some scenarios is,
     during program termination, a global part of the logger object could be destructed
     when it still had outstanding thread end handlers registered to it.

Other:
   - Added an example program that shows how to use the optimization
     functions.
   - Gave the matrix object the ability to factor expressions containing
     trans() function calls into more efficient forms.
   - Generally cleaned up the matrix code

Release 17.14

Release date: Jan 18, 2009
Major Changes in this Release:
New Features:
   - Added the multi-line text_box GUI widget.
   - Added the type_safe_union object

Non-Backwards Compatible Changes:
   - Renamed the array::expand() function to array::resize() since it does
     basically the same thing as std::vector::resize() and more than one
     user has told me they found the name "expand" to be confusing.

Bug fixes:

Other:
   - Added an example showing how to use the type_safe_union and pipe
     together.
   - Added a page to the documentation that discusses the dlib coding
     standards and how to contribute to the project.

Release 17.13

Release date: Jan 05, 2009
Major Changes in this Release:
New Features:
   - Added the bound_function_pointer object.
   - Added support for futures to the thread_pool object.
   - Added a set of objects that makes it possible to create simulations
     of quantum computing algorithms.
   - Added copy and paste support to the text_field.
   - matrix object stuff
      - Added the range() function as well as overloads of all the various
        sub-matrix selection functions so that you can pick out slices of
        matrices like in Matlab.
      - Added a new template argument to the matrix object that allows the
        user to select the memory layout.  Also added a row_major_layout
        and column_major_layout.
      - The matrix object can now be initialized using a comma separated
        list of values.

Non-Backwards Compatible Changes:
   - Changed the fatal_error exception class so that it aborts your program
     and prints a message if you try to construct it more than once since
     doing so indicates that you ignored the first fatal error.
   - The way matrix expressions work in the library has been changed
     since the last release.  So if you created custom matrix expressions
     then they will need to be updated to use the new matrix expression stuff.

Bug fixes:
   - Fixed a minor bug in how the zoomable_region widget drew itself after
     a resize in some cases.
   - Fixed a problem with draw_line where it didn't always redraw the line
     properly.

Other:
   - A lot of the matrix code has been refactored and optimized.  The matrix
     object will now introduce temporary objects when doing so results in
     better performance.  I also added a simple system for binding
     arbitrary matrix expressions to optimized BLAS routines.
   - Cleaned up the vector and point classes.  Now there is only one class,
     the vector class, and it is capable of representing everything the old
     vector and point class could.  I also added code to make sure the
     vector class does the appropriate type promotions when vector objects
     with different types are used together.
   - Made the vector class inherit from matrix

Release 17.12

Release date: Nov 10, 2008
Major Changes in this Release:
New Features:
   - Added user settable styles to most of the gui widgets
   - Added the diagm(), svd2() and svd3() matrix functions
   - Added the thread_pool object

Non-Backwards Compatible Changes:
   - Removed the arrow_button widget and moved its functionality into the
     button widget.
   - Renamed the dragable class to draggable
   - Removed the confusing and unnecessary hidden bool argument to the
     gui widget style drawing functions.
   - Changed some of the events that are about the mouse leaving a widget so
     that they still trigger even if the widget has been disabled or hidden.

Bug fixes:
   - Added some missing mutex locks to the scroll_bar widget
   - Fixed a bug in the fill_gradient_rounded() function. It didn't always
     draw the entire rectangle.
   - Fixed a compile time bug in the pinv() function.  It didn't compile
     when used on statically sized matrices when they weren't square.

Other:
   - The member_function_pointer object now never calls new or delete.
     So it is safe to use in a real time environment.

Release 17.11

Release date: Oct 20, 2008
Major Changes in this Release:
New Features:
   - Added the sort_columns() and rsort_columns() functions
   - Added the vector_normalizer object
   - Added the normalized_function object.
   - Added a tensor_product() function for the matrix object.

Non-Backwards Compatible Changes:

Bug fixes:
   - Made it so that the gui event handler thread isn't created at all
     unless some part of an application calls some of the gui_core code.
     In the previous release the event handler thread was executed
     briefly during program termination and could cause problems if no
     windowing environment was available.
   - Fixed an #include statement in the matrix utilities so that it works
     even if you don't specify an include path argument to your compiler.

Other:

Release 17.10

Release date: Oct 09, 2008
Major Changes in this Release:
New Features:
   - Added a thread safe shared pointer object
   - Added the popup_menu_region widget.

Non-Backwards Compatible Changes:
   - The on_wheel_up() and on_wheel_down() gui events now take an unsigned long
     argument.
   - Removed the register_program_ending_handler() function from the threading
     API and also changed the dlib thread pool so that it no longer causes
     a terminating program to wait for any outstanding threads to finish
     before allowing the application to end.
   - Changed the serialization format of the linearly_independent_subset_finder
     class.
   - Changed all the font pointers in the gui API's interfaces
     to shared_ptr_thread_safe objects.

Bug fixes:
   - Made the kkmeans class actually use the min_change parameter.
   - Fixed a bug in the linearly_independent_subset_finder object.  Also
     added a way to set a minimum tolerance.
   - Fixed a bug in the scrollable_region widget that caused it to scroll in an
     unpleasant way when the horizontal and vertical scroll increments weren't
     set to the same value.
   - Made one of the arguments to font::draw_string() not be a reference because
     some versions of gcc don't end up doing the right thing when -O3 is
     supplied.
   - Fixed a bug in the covariance() function that prevented it from compiling
     sometimes.

Other:
   - Changed the gui core code around so that it should be safe to make window
     objects at the global scope.
   - Added more control over how the scrollable_region scrolls its region.
     You can now adjust how much it scrolls when the mouse wheel is scrolled
     as well as enabling scrolling via a mouse drag.
   - Modified the library so that it compiles with the Intel compiler.
   - Added some example programs that use the relevance vector machine

Release 17.9

Release date: Sep 06, 2008
Major Changes in this Release:
New Features:

Non-Backwards Compatible Changes:

Bug fixes:
   - Fixed a bug in the tooltip widget
   - Fixed the cmake option to toggle the ENABLE_ASSERTS macro
   - Fixed some bugs in the rvm
   - Fixed the serialization code for the kkmeans object so that it actually
     works
   - Fixed a bug that can trigger when the thread_specific_data object is
     destructed
   - Fixed a bug in the directory navigation gui.  If you tried to go
     into a drive on windows that wasn't mounted you got an error.
     This is now fixed.

Other:
   - Made the dir_nav stuff work with std::vector and dlib::std_vector_c
     as well as dlib::queue objects.
   - Generally cleaned up a bunch of things

Release 17.8

Release date: Aug 14, 2008
Major Changes in this Release:
New Features:
   - Added relevance vector machine regression and classification support.
   - Added the cross_validate_trainer_threaded() function
   - Added the length and length_squared matrix functions.

Non-Backwards Compatible Changes:

Bug fixes:
   - Changed gui code a little so that windows don't popup in funny
     places when used with the cygwin X windows system.

Other:
   - Made it easier to use the scoped_ptr with the TCP connection object
   - Optimized the matrix object a little

Release 17.7

Release date: Jul 25, 2008
Major Changes in this Release:
New Features:
   - Machine Learning
      - Added the ability to compare kcentroid objects to each other
      - Added the rank_features() function
      - Added the distance_function object
      - Added the reduced_decision_function_trainer object and
        reduced() function
      - Added the reduced_decision_function_trainer2 object and
        reduced2() function
      - Added a radial basis function network trainer
      - Added the linearly_independent_subset_finder object
      - Added the sigmoid_kernel
   - Matrix Utilities
      - Added the inv_upper_triangular() and inv_upper_triangular()
        functions.

Non-Backwards Compatible Changes:
   - Refactored a bunch of the kernel learning code into a much cleaner form.
     But this does change the interface to all the training functions.

Bug fixes:
   - Fixed a bug in the min and max calculation in the running_stats object
   - Removed a bug in the sum() and variance() functions that
     caused them to seg fault when they were used on certain
     matrix of matrix objects.
   - Added a missing check for division by zero to the conjugate gradient
     optimization functions.
   - Added some missing member variables to the .swap and serialization
     functions for the kcentroid object.  So now they should work right.

Other:
   - Added an option to the cmake file to toggle the DLIB_ASSERT macro
   - Added an option to the cmake file to toggle the dlib stack trace macros
   - Made the library compile in Cygwin

Release 17.6

Release date: Jun 22, 2008
Major Changes in this Release:
New Features:
   - Merged in Keita Mochizuki's unicode patches to the GUI components.  So
     the dlib GUI now has better unicode support.
   - Added the remove_row and remove_col matrix functions.  Also made all
     three of the above functions capable of taking arguments at run time
     as well as compile time.
   - Added the ability to cap the number of dictionary vectors used by the krls
     and kcentroid object at a user specified number.
   - Added the pick_initial_centers() function
   - Added the running_stats object

Non-Backwards Compatible Changes:
   - Changed the interface to the krls and kcentroid objects somewhat.
   - All of the style objects in the GUI part of the library now use
     dlib::ustring instead of std::string.  This only matters to you if
     you have made your own style objects.
   - Changed the serialization format of the krls, kcentroid, and
     directed_graph_drawer objects.  Note that is also means that the
     files saved by previous versions of the bayes_net_gui_ex program
     won't load with the current version.

Bug fixes:
   - Fixed an aliasing bug in the set_subm(), set_rowm(), and set_colm()
     functions.  It was possible that you could get incorrect results
     if you used these functions to copy one part of a matrix to another
     part of the same matrix if the two areas overlapped.
   - Fixed a minor numerical error in the krls code so now it gets slightly
     better results.

Other:
   - Made the types generated by the matrix operations a lot shorter.  This
     avoids some compiler warnings from visual studio and even some potential
     internal compiler errors in some instances.

Release 17.5

Release date: Jun 2, 2008
Major Changes in this Release:
New Features:
   - Added some macros that allow dlib to create a stack trace
   - Added the wrap_function and is_function templates.
   - Added two new events to the text_field object.  One for detecting when the
     user hits enter and another for detecting when input focus is lost.
   - Machine Learning
      - Added a kernel based centroid estimator/novelty detector
      - Added a kernel based k-means clustering algorithm
   - Numerical
      - Added an identity_matrix() function that can take a runtime defined size.
      - Added a bunch of unconstrained optimization stuff to the library.
        It now has a conjugate gradient optimization algorithm as well as
        a quasi-newton algorithm.
      - Added the set_subm, set_rowm, and set_colm functions.

Non-Backwards Compatible Changes:
   - In the krls object:  Added a requires clause to the set_tolerance() member
     function and renamed clear() to clear_dictionary().

Bug fixes:
   - Fixed a bug in the requires clause of the subm() function.  It was
     more restrictive than it should have been.

Other:
   - Added example programs for the krls object as well as the new
     kcentroid and kkmeans objects.

Release 17.4

Release date: May 12, 2008
Major Changes in this Release:
New Features:
   - Added an implementation of the kernel recursive least squares algorithm

Non-Backwards Compatible Changes:
   - Broke backwards compatibility in the directed_graph_drawer's serialization
     format when I fixed the bug below.

Bug fixes:
   - Fixed two bugs in the directed_graph_drawer widget.  First, it sometimes
     threw a dlib::fatal_error due to a race condition.  Second, the color of
     the nodes wasn't being serialized when save_graph() was called.
   - Made vector_to_matrix() work for std::vector objects that have non-default
     allocators.

Other:
   - Added some stuff to make people get a really obvious error message
     when they set up the include path incorrectly.

Release 17.3

Release date: Apr 28, 2008
Major Changes in this Release:
New Features:
   - Added the vector_to_matrix() function.
   - Added a cholesky_decomposition() function.
   - Added the toggle_button GUI widget
      - Added a default toggle button style as well as check box and
        radio button styles.
   - Added a single click event to list_box
   - Added a save_file_box() and open_existing_file_box() function.

Non-Backwards Compatible Changes:
   - Changed the check_box and radio_button widgets to be specializations of
     the new toggle_button object.  This is a nearly backwards compatible
     change except that the events registered to check_box and radio_button
     clicks must now take the form void event(toggle_button&) or
     void event(void) instead of the previous void event(check_box&) and
     void event(radio_button&).
   - Removed the is_mouse_over bool from the button_style::draw_button()
     function.

Bug fixes:
   - Fixed a compiler error in mingw.
   - Changed the preprocessor checks for the wchar_t overload of
     is_built_in_scalar_type so that it works properly with visual studio.

Other:
   - Added a Bayesian Network GUI that allows you to create a network
     and serialize it to disk.

Release 17.2

Release date: Apr 21, 2008
Major Changes in this Release:
New Features:
   - GUI Related
      - Added the scrollable_region widget
      - Added the text_grid widget
      - Added an event to the text_field so you can tell when the
        user modifies it.
      - Added the fit_to_contents() function to the tabbed_display
        widget.
   - Bayesian Network Related
      - Added the node_first_parent_assignment(), node_next_parent_assignment(),
        and node_cpt_filled_out() functions.

Non-Backwards Compatible Changes:
   - Reverted the change in 17.0 where I made drawable::lastx and
     drawable::lasty not match the current location of the mouse inside
     the on_mouse_move() event.  I changed this back to how it was before,
     so now lastx and lasty represent the most current record of where
     the mouse is in *all* events.
   - Changed the functions that control text color in the label and text_field
     widgets to use rgb_pixel objects.  Also added a function to set the
     background color of a text_field.

Bug fixes:
   - Fixed a bug in the bayesian_network_join_tree object that caused it to
     compute incorrect results for some networks.
   - GUI Related
      - Fixed a minor bug in the cursor drawing of the text_field
        gui widget.
      - Fixed a bug in the compute_cursor_rect() function.  It would return an
        incorrectly positioned rectangle for 0 length strings.
      - Changed the way wchar_t is handled in the serialize.h file.  Now
        everything should compile correctly in visual studio regardless of how
        you set the /Zc:wchar_t compiler option.
      - Fixed a bug in the menu_bar widget.  One of the members wasn't being
        initialized when it needed to be.
      - Fixed a bug in the tabbed_display where it didn't redraw itself
        correctly after it was moved by set_pos()

Other:
   - Changed the xml parser so that it counts line numbers
     from the start of the input stream instead of from the
     root tag.
   - Changed the xml parser so that you will only get the fatal_error
     event once if it occurs.

Release 17.1

Release date: Apr 13, 2008
Major Changes in this Release:
New Features:
   - Added a zoomable_region widget
   - Added a directed_graph_drawer widget

Non-Backwards Compatible Changes:
   - Changed the first_pixel argument of the draw_string() function
     to be a rectangle like all the other draw functions now use.

Bug fixes:
   - Fixed a bug in the tooltip widget that was triggered when calling
     its member functions without calling set_tooltip_text().  This also
     fixed a bug in the button object that triggered when calling some button
     functions that referenced the tooltip widget.
   - Fixed a problem in the draw_circle and draw_solid_circle functions.
     They didn't draw themselves quite correctly in all cases.

Other:

Release 17.0

Release date: Apr 07, 2008
Major Changes in this Release:
New Features:
  - Added a png_loader object
  - GUI related
    - Added a popup_menu widget
    - Added a menu_bar widget
    - Added a tooltip widget
    - Added a user selectable style to the gui button.
    - Added the draw_rounded_rectangle() and fill_gradient_rounded() functions
    - Added the mouse_over_event object to the base_widgets and made the
      button_action inherit from it.
    - Added the drawable::next_free_user_event_number() function
  - matrix and geometry:
    - Added a size() function to matrix_exp and matrix_ref objects.
    - Added a class that represents 2D points
    - Added the following matrix functions:
      - squared(), cubed(), get_rect(), a subm() function that takes
        rectangles, and normalize()
    - Added the following rectangle functions:
      - area(), centered_rect(), translate_rect(), move_rect(), resize_rect(),
        resize_rect_height(), resize_rect_width(), and nearest_point()

Non-Backwards Compatible Changes:
  - Renamed atom() to array_to_matrix()
  - Moved the rectangle object from the gui_core into a new geometry folder
    (only matters if you were directly including the rectangle file)
  - Moved the vector object into the geometry folder.  Also removed the kernel_1a
    stuff.  So there is now only one possible vector implementation.
  - Changed the default position for a rectangle to (0,0) instead of (1,1)
  - Added edge data to the directed_graph.  This breaks backwards compatibility
    with the previous serialization format for directed_graphs.
  - GUI related:
    - Changed the base_window::on_keydown event signature so that it now
      reports more keyboard modifier keys (e.g. alt)
    - Made the functions for drawing on canvas objects take points and pixels
      instead of just a bunch of integers.  Also changed the order of the
      arguments so that the canvas comes first, followed by the location
      to draw on, then what to draw.
    - Moved the canvas drawing functions into the gui_widgets/canvas_drawing.h
      file.
    - Modified the drawable_window so that the drawable::lastx and drawable::lasty
      fields are updated after calls to on_mouse_move.  This way the x and y that
      go into the on_mouse_move actually tell you something.

Bug fixes:
  - Fixed a bug in the floating point serialization code.  It
    didn't handle NaN or infinities correctly.
  - Fixed a bug in the win32 version of the gui_core component.  It was
    possible that calling set_size(), set_pos(), or set_title() could cause
    the program to deadlock.
  - Made the load_bmp() function more robust in the face of weirdly
    written BMP files.
  - Modified the draw_circle() and draw_solid_circle() functions so that they
    only touch each canvas pixel once.  This avoids messing up alpha blending
    if an rgb_alpha_pixel is used.

Other:
  - Removed the old win32 only gui code in the dlib/gui folder.
  - Changed the default GUI font to a nicer Sans Serif font

Release 16.5

Release date: Mar 04, 2008
Major Changes in this Release:
New Features:
   - Added another constructor to the thread_function object.
     Now it can take proper function objects as well as normal function
     pointers.
   - Added the probabilistic_decision_function object and svm_nu_train_prob()
     function.

Non-Backwards Compatible Changes:
   - Changed the svm train functions so that the cache_size argument
     now measures the max number of megabytes of memory to use rather
     than number of kernel matrix rows to cache.  It's default
     value is now 200MB.
   - changed the type typedef in the SVM kernel function objects to
     be named sample_type instead of type.

Bug fixes:
   - Fixed a bug in the trim, rtrim, and ltrim functions.  They
     didn't return empty strings when the input string contained all
     trim characters.
   - Fixed a bug in the decision_function's copy constructor

Other:
   - Added an optimization to the working set selection for the svm training code.
     Now the algorithm will prefer to select indices that are in the kernel
     matrix cache when possible.
   - Fixed a problem with the chm documentation file where many of the links
     didn't work.
   - Made the support vector functions capable of operating with floats, doubles,
     and long doubles instead of just the double type.

Release 16.4

Release date: Feb 22, 2008
Major Changes in this Release:
New Features:
   - Added aversion of the draw_line() function for images.
   - Added the atom(), rowm(), colm(), and subm() matrix functions.
   - Added some push/pop_back() functions to the array object that are similar
     to the ones in the std::vector.
   - Added the std_vector_c class that wraps std::vector and checks its
     function's preconditions.
   - Added the polynomial_kernel object for use with the svm algorithm.

Non-Backwards Compatible Changes:
   - Changed the svm_nu_cross_validate() function to return a vector
     of both the +1 and -1 cross validation accuracies.

Bug fixes:
   - Fixed a bug in the list_box that caused it to not hide itself properly
     when told to do so.
   - Fixed canvas::fill() gui function so that it should work right
     on 64 bit platforms.

Other:

Release 16.3

Release date: Feb 12, 2008
Major Changes in this Release:
New Features:
   - Added memory manager support to the matrix object.

Non-Backwards Compatible Changes:
   - Made the assign_pixel() function saturate grayscale values bigger
     than the target pixel type can handle.  Previously it would just
     truncate the numbers.
   - Removed rand_kernel_1 and rand_kernel_2 because they gave very
     inferior results compared to rand_kernel_3.  I then renamed
     rand_kernel_3 to rand_kernel_1.
   - Renamed rand::get_random_number() to get_random_8bit_number() and also
     added a get_random_16bit_number() and get_random_32bit_number()
   - Added a checksum to compress_stream_kernel_1 and kernel_2.  This
     breaks backwards compatibility with the previous versions.  That is,
     the new implementations will complain that decompression fails if
     you give them data compressed with the old non-checksum version of
     the compression routines.
   - Removed the width() and height() functions from the array2d object.
     Now only the equivalent nc() and nr() member functions remain.
   - Changed array2d::set_size(width,height) to set_size(num_rows, num_cols).
     That is, I switched the order of the two arguments to this function.
     The reason for doing this is to make it have the same form as the
     set_size() member of the matrix object.  This way the usage of the
     set_size() member for these two very similar data structures is
     the same.  Hopefully this will reduce confusion rather than
     make things worse.

Bug fixes:
   - Fixed a bug in the image_widget.  It didn't repaint the screen
     all the way if you gave it a smaller image to display.
   - Fixed a bug in the cat() function that caused the state of the queue
     to be broken if you called cat with an empty queue.
   - Made the queue_sort_1 use a better sorting algorithm.  In particular, it
     will not sort slowly for nearly sorted data.
   - Fixed a bug in the queue_kernel_2 object that caused it to not work
     correctly with the non-default memory managers.

Other:
   - Added example code for the member_function_pointer as well as the matrix
     object.
   - Added some more regression tests and made some of the longer running
     ones execute a lot quicker.
   - Made the unit test suite easier to use.  Now tests just throw an exception
     to indicate an error rather than returning an error code.
   - Added an example program for the multi-layer perceptron neural network.

Release 16.2

Release date: Jan 25, 2008
Major Changes in this Release:
New Features:
   - Added the is_signed_type and is_unsigned_type templates
   - Image Processing stuff
      - Added the assign_all_pixels() function
      - Added the assign_border_pixels() function
      - Added the assign_pixel_intensity() function
      - Added the auto_threshold_image() function
      - Added the binary_union() function
      - Added the edge_orientation() function
      - Added the get_histogram() function
      - Added the get_pixel_intensity() function
      - Added the hysteresis_threshold() function
      - Added the sobel_edge_detector() function
      - Added the suppress_non_maximum_edges() function
      - Added the zero_border_pixels() function
      - Changed the pixel_traits structure so that it can support 8, 16, and 32
        bit grayscale pixels.

Non-Backwards Compatible Changes:
   - Added more fields to the pixel_traits template so if you had defined your
     own pixel types you will need to update them.

Bug fixes:
   - Fixed some compiler errors in Visual Studio 2008

Other:
   - Generally tried to clean up the documentation and code in this release

Release 16.1

Release date: Jan 1, 2008
Major Changes in this Release:
New Features:
   - Added the randomize_samples() function
   - Added the set_main_font() and main_font() functions to the drawable object.
     So now the drawable widgets can use a user provided font.

Non-Backwards Compatible Changes:
   - Made the named_rectangle object a little easier to use.  It now won't
     let you size it so small that it doesn't display its entire name.

Bug fixes:
   - Fixed a bug in the svm_nu_train() function that caused a crash with
     some inputs.
   - Fixed a compile time error that occurred when compiling the bayesian
     network code in Mac OS X.
   - Fixed a bug in the compute_cursor_pos() function where it would
     return the incorrect value.

Other:
   - Added an example showing how to use the svm functions.

Release 16.0

Release date: Dec 10, 2007
Major Changes in this Release:
New Features:
   - Added the left_substr() and right_substr() functions
   - Added the zero_extend_cast() function
   - Added the unsigned_type template
   - Added the uint8 typedef
   - Bayesian Network related
      - Added the assignment object
      - Added the bayes_node object
      - Added the joint_probability_table object
      - Added the conditional_probability_table object
      - Added the bayesian_network_gibbs_sampler object
        This object implements an algorithm that performs approximate inference
        in a Bayesian Network.
      - Added the bayesian_network_join_tree object
        This object implements an algorithm that performs exact inference
        in a Bayesian Network.
   - Set related
      - Added the set_intersection_size() function
      - Added the set_union() function
      - Added the set_intersection() function
      - Added the set_difference() function
   - Graph related
      - Added the graph object
      - Added the is_graph template
      - Added the is_directed_graph template
      - Added the create_moral_graph() function
      - Added the triangulate_graph_and_find_cliques() function
      - Added the graph_contains_length_one_cycle() function
      - Added the find_connected_nodes() function
      - Added the graph_is_connected() function
      - Added the is_clique() function
      - Added the is_maximal_clique() function
      - Added the copy_graph_structure() function
      - Added the create_join_tree() function
      - Added the is_join_tree() function
      - Added the edge() function
   - GUI related
      - Added the base_window::get_display_size() function
      - Added message_box_blocking()
      - Added the bdf_font object which is capable of loading BDF font files into
        the font object used by the gui_widgets
   - Better Unicode support
      - Added the basic_utf8_ifstream: An input stream that can read UTF-8 files
      - Added serialization support for wchar_t and std::wstring
      - Added the is_combining_char() function
      - Added the convert_utf8_to_utf32() function
      - Modified most of the string manipulation functions in dlib/string.h
        to work with any kind of character type
      - The gui widgets' font object now works with Unicode text (i.e. wchar_t
        and unichar strings) as well as with normal char data.

Non-Backwards Compatible Changes:
   - The dlib/all_console.cpp and dlib/all_gui.cpp files have been deprecated
     in favor of a new file.  Now to build with dlib you simply add
     dlib/all/source.cpp to your project regardless of what type of project
     you are building.
   - The GUI program entry point, winmain(), has been removed.  You can now use
     the normal main() entry point or some other non-standard entry point
     provided by your compiler.
   - Renamed directed_graph::node::item to directed_graph::node::data

Bug fixes:
   - Fixed some build issues in gcc 4.2 involving some uses of the std_allocator
   - Fixed some build issues in Visual Studio involving the dir_nav component
     and building with NO_MAKEFILE #defined.
   - Moved the #define that disables the old WinSock API into the sockets cpp
     file.  This should avoid conflicts with people who are using the old WinSock
     API.
   - Changed the tuple template slightly to avoid a bug in Visual Studio 7.1
     that caused a compile time error in some instances.

Other:

Release 15.12

Release date: Nov 18, 2007
Major Changes in this Release:
New Features:
   - Added a destroy() function to the map, set, hash_map, and hash_set objects.
   - Added the tuple object
   - Added an overload of connect() that has a timeout
   - Added rand_kernel_3 as a random number generator that uses the Mersenne Twister
     algorithm.
   - Added the directed_graph object
   - Added the graph_contains_undirected_cycle() and graph_contains_directed_cycle()
     functions.
   - Added the std_allocator object.   It is a STL style allocator that can use
     the dlib memory manager objects.
   - std::string manipulation functions:
      - Added the cast_to_string() function.
      - Added the tolower() function
      - Added the toupper() function
      - Added the ltrim() function
      - Added the rtrim() function
      - Added the trim() function
      - Added the lpad() function
      - Added the rpad() function
      - Added the pad() function

Non-Backwards Compatible Changes:
   - Changed the default logging level from LNONE to LERROR
   - Renamed the ASSERT macro to DLIB_ASSERT and CASSERT to DLIB_CASSERT.
     This rename avoids a conflict with a macro inside MFC.
   - Changed the logger so that settings are inherited when a new logger
     is instantiated rather than just having the new logger use the
     default settings.
   - Removed the logger::clear() function since it no longer really
     makes sense given the above change.
   - Removed the get_main_thread_id() function and replaced it with the
     is_dlib_thread() function.

Bug fixes:
   - Pushed some things into cpp files because doing so avoids build and/or
     runtime errors on some platforms.

Other:
   - Changed the string_cast() function so that it will recognize the words true
     and false as boolean values.  Also improved the error message inside the
     string_cast_error exception object.

Release 15.11

Release date: Oct 25, 2007
Major Changes in this Release:
New Features:
   - Added the covariance() function
   - Added the rgb_alpha_pixel pixel type and modified all relevant functions to
     support it.

Non-Backwards Compatible Changes:
  - The GUI changes that are non-backwards compatible:
       - The alpha parameter is now an unsigned char instead of unsigned int
         and its range is now 0 to 255 instead of 0 to 256.
       - The image_widget no longer has any member functions dealing with
         alpha values.  If you want to use alpha blending you just give it an
         image that has an alpha channel.  The same goes for draw_image().
  - There are now more fields in the pixel_traits template.  So if you were
    defining your own pixels before you will need to update your pixel_traits
    specializations.

Bug fixes:
  - Made some functions non-inline and put some things on the stack
    instead of heap.  Doing this avoids some problems with certain
    kinds of builds in visual studio.

Other:
  - Modified the message_box() function so that it is safe to call end_program()
    from within its callback event.

Release 15.10

Release date: Oct 09, 2007
Major Changes in this Release:
New Features:
   - Modified the GUI drawing functions to take an alpha argument to allow
     alpha blending.
   - Added the svm_nu_cross_validate() function to perform k-fold
     cross validation using the svm_nu_train() function.
   - Added the boost enable_if templates
   - Added the rand_float extension to the rand object.
   - New matrix features:
      - Added the pinv() function
      - Changed round_zeros() to use the machine epsilon instead of 1e-6 as
        its default epsilon.
      - Modified the matrix object so that you can declare them with
        a static dimension and a dynamic dimension.  E.g. matrix<float,0,10>
        is now legal and declares a matrix with a fixed number of columns(10)
        and a variable number of rows.
      - Added the equal() function to compare two matrices of floating
        point numbers for near equality.
      - Changed the matrix so that operator(long) works for both
        column vectors and now also for row vectors.
      - Added a set_size() and constructor that takes a single long for use in
        sizing row and column vectors.
      - Added the scale_columns() function

Non-Backwards Compatible Changes:

Bug fixes:
   - Fixed an error in svm_nu_train() where it would incorrectly
     complain of incorrect nu values for some datasets.
   - Added a missing std:: qualifier at two points in the dlib/vector code that
     could cause a compiler error in some instances.

Other:
   - Added a term index to the documentation.

Release 15.9

Release date: Sep 25, 2007
Major Changes in this Release:
New Features:
   - Added a nu support vector classifier training function.
   - Added a multilayer neural network object.
   - Added the "destructive aliasing" checks into the matrix code.  Now temporary
     matrices are only created during assignment if the right hand side aliases
     the left hand side in a destructive way.  This removes many of the previous
     uses of temporary matrices.
   - Made the sum() matrix function be able to sum matrices of matrices
   - New matrix functions:
      - acos(), asin(), atan(), ceil(), cos(), cosh(), exp(), floor(), log(),
        log10(), mean(), norm(), pow(), reciprocal(), round_zeros(), sin(),
        sinh(), sqrt(), tan(), tanh(), variance(), and more overloads of
        uniform_matrix().

Non-Backwards Compatible Changes:

Bug fixes:
   - Added missing nr() and nc() functions to the uniform_matrix() and
     identity_matrix() functions.
   - Forgot to add a destructor for the dynamically sized matrix resulting in a
     memory leak.  This is now fixed.
   - Fixed various potential compile time errors

Other:

Release 15.8

Release date: Sep 11, 2007
Major Changes in this Release:
New Features:
   - Added a copy of the boost noncopyable base class.
   - added some smart pointers:
      - added shared_ptr
      - added weak_ptr
      - added scoped_ptr

Non-Backwards Compatible Changes:

Bug fixes:

Other:
   - Cleaned up the assert code and removed the need for the dlib/error.ccp file
   - Made the matrix take better advantage of the compile time sized
     dimensions when it can.

Release 15.7

Release date: Aug 26, 2007
Major Changes in this Release:
New Features:
   - Made it so that command line options have a default conversion to bool
     and the bool tells you if they are on the command line or not.
   - Added an implicit conversion to a scalar to the matrix object
     when it is of dimension 1x1.
   - Added the thread_function object
   - Added a function to compute the singular value decomposition of a matrix.

Non-Backwards Compatible Changes:
   - Added two new arguments to the on_request() function.  They allow you to
     see what HTTP headers the client sends you and to control which ones
     you send back.

Bug fixes:

Other:

Release 15.6

Release date: Aug 18, 2007
Major Changes in this Release:
New Features:
  - matrix object additions:
     - Added some functions to convert between matrix and pixel objects.
     - Added the clamp() function that operates on matrix objects.
     - Added the sigmoid function.
     - Made the matrix object capable of being sized at runtime in addition
       to its original compile time static sizing capability.
     - Added 3 and 4 argument versions of pointwise_multiply()
     - Added the +=, -=, *= and /= operators to the matrix object.

Non-Backwards Compatible Changes:

Bug fixes:
  - Fixed the line numbering in the color pretty printer.  Wasn't being
    done correctly.
  - Fixed a bug in the matrix round() function.
  - Fixed some miscellaneous compile time errors
  - Fixed a bug in the matrix removerc() function.
  - Added some missing checks to catch invalid negative index inputs to
    matrix objects.
  - Fixed a bug in the matrix inv() function.  It could sometimes
    segfault if used on certain singular matrices

Other:
  - string_cast() can now convert hex strings to integers
  - You can now say myarray2d.set_size(0,0) and have it do what
    you would naturally expect.
  - Added some #pragma statements that tell visual studio
    to link the right system libraries automatically.
    So now you don't have to add these things in the
    project settings anymore.

Release 15.5

Release date: Jul 12, 2007
Major Changes in this Release:
New Features:
  - Added the set_all_logging_levels(), set_all_logging_output_streams()
    functions
  - Added the configure_loggers_from_file() function which allows you to
    easily configure all logger objects using a textual configuration
    file.

Non-Backwards Compatible Changes:

Bug fixes:
   - Added a workaround into the code that avoids a potential compilation
     error on Mac OS X systems.

Other:

Release 15.4

Release date: Jun 30, 2007
Major Changes in this Release:
New Features:

Non-Backwards Compatible Changes:

Bug fixes:
   - Fixed a bug in the POSIX version of the hostname_to_ip() function. It was
     screwy if you asked for more than the first IP address (the same address
     might be returned more than once).
   - Fixed a bug in the pipe object's timeout functions.  The timeouts weren't
     working correctly.

Other:

Release 15.3

Release date: Jun 25, 2007
Major Changes in this Release:
New Features:
   - Added the wait_for_num_blocked_dequeues(), enable_enqueue(),
     disable_enqueue(), and is_enqueue_enabled() functions to the pipe object.
   - The pipe object can now be used with a zero length buffer.

Non-Backwards Compatible Changes:
   - There is no longer a pipe::kernel_1a_c typedef since the pipe
     no longer has any requirements to check (due to the change of allowing
     zero length buffer sizes)

Bug fixes:

Other:
   - Made the ASSERT and CASSERT macros call dlib_assert_breakpoint() when they
     fail.  This way you can easily set a breakpoint on them in a debugging
     tool by breaking on calls to this new function.
   - Fixed some typos and unclear parts of the pipe spec.

Release 15.2

Release date: Jun 11, 2007
Major Changes in this Release:
New Features:
   - Added a thread safe version of the config_reader object (in the form of an
     extension to the config_reader)
   - Added the wait_until_empty() function to the pipe object.

Non-Backwards Compatible Changes:
   - Removed the connection::close() and listener::close() functions.  They have
     been replaced by destructors.  To upgrade old code all you have to do is
     replace statements of the form "object->close();" with "delete object;".
     Both statements do exactly the same thing.  However, for connection objects,
     you should probably be using the close_gracefully() function instead.

Bug fixes:
   - Removed a potential compile time error in the dng image format handling code.
   - Fixed a bug in the bigint object.  The destructor was using "delete"
     when it should have been using "delete []"
   - Fixed a resource leak in the POSIX version hostname_to_ip()
   - Fixed a significant memory leak in memory_manager_kernel_1
   - Fixed a memory leak that could occur in memory_manager_kernel_2
     and memory_manager_kernel_3 when the constructor for the object
     being constructed threw an exception.
   - Added a missing delete statement to plug a memory leak
     in the md5 computation code.
   - Fixed an uninitialized variable warning from valgrind
     (in lz77_buffer/lz77_buffer_kernel_2.h).  I think this could
     also potentially result in an error when decoding data but I'm not totally
     sure.  But either way it is fixed now.
   - Changed a call to memcpy to memmove in the sockstreambuf_kernel_2
     implementation since the copy could potentially be of overlapped memory.

Other:
   - Changed the connection::read() and connection::write() functions to take
     longs instead of unsigned longs as the buffer sizes.  They also now
     return longs instead of ints.  This should be a backwards compatible change.
   - Started using the valgrind tool to check for memory errors in the project and
     found a few things.  Very nice tool :)

Release 15.1

Release date: Jun 04, 2007
Major Changes in this Release:
New Features:
   - Added the multithreaded_object extension to the threads API
   - Added the load_dng() and save_dng() functions which can load and store
     the DNG lossless compressed image format (which I just made up).

Non-Backwards Compatible Changes:
   - Changed the serialization format for bool to use a 1 byte code rather than 2
     bytes.  So this breaks compatibility with the old format.

Bug fixes:
   - The serialization for bool didn't always work right.  This is now fixed.

Other:

Release 15.0

Release date: May 16, 2007
Major Changes in this Release:
New Features:
   - New faster version of the bigint object (bigint_kernel_2) that uses
     the Fast Fourier Transform to perform multiplications.
   - The base_window can now be an "undecorated" window.  This new type is suitable
     for making things like popup menus and the like.
   - Added the on_focus_lost() event to the base_window object
   - Added the on_focus_gained() event to the base_window object
   - Added the on_window_moved() event to the base_window object
   - Added the get_pos() function to the base_window object
   - Updated the gui_widgets's drawable interface stuff to support the three
     new event types and the new window type.
   - Added the drawable::draw_rectangle() function
   - Added serialization support for std::complex.
   - Added the assign_image() function

Non-Backwards Compatible Changes:
   - Removed the color arguments from the drawable_window object's constructor and
     added a new boolean argument (if it is an undecorated window or not).  This
     probably won't break any code but if it does you should get a compiler error
     about it.
   - Made it so you must disable the events in the destructor for your
     drawable gui widgets.  Doing so avoids potential race conditions when
     destructing drawable objects.
   - Made it so that you are required to call close_window() in a window object's
     destructor.  This avoids a potential race condition.

Bug fixes:
   - Added a workaround for a bug in MinGW that caused the regression test suite
     to crash when compiled with -O3.
   - Fixed a potential bug in the X Windows version of the gui_core component.
      Added an extra XFlush() to end_program() because without it a
      program can crash when calling end_program() in certain instances.
   - The spec for the pipe object said that objects you enqueue into it
     had an "initial value for their type" after the function completes. This
     is incorrect, they are swapped into the pipe so they have an undefined
     value afterwards.  I fixed the spec for the pipe to say this.
   - Fixed a bug in the font rendering functions in the gui_widgets
     component.  It could cause a segmentation fault sometimes.
   - Fixed some potential deadlocks in the windows version of the gui_core
     component.
   - Fixed a bug in the rsignaler object.  When you called wait() or
     wait_or_timeout() it only unlocked the associated rmutex once (it could be
     locked more than once and thus might cause a deadlock since the thread
     calling wait() wouldn't actually unlock the mutex in this case).
   - Fixed the initialize_array() function in memory_manger_kernel_3 to be
     exception safe.  Previously if an exception occurred while creating
     an array then a resource leak was created.

Other:
   - Changed the package format for the library somewhat.  The examples are now
     located in their own top level folder.  Additionally, the HTML version of the
     documentation also comes in the same archive as the source rather than in a
     separate download.
   - Started using major and minor version numbers rather than just major ones.

Release 14

Release date: Apr 11, 2007
Major Changes in this Release:
New Features:
   - Added operator<< and operator>> iostream operators to the vector object.

Non-Backwards Compatible Changes:
   - Changed the xml_parser's document_handler interface:
     made empty element tags (<like_this/>) trigger the end_element() callback
     and removed the is_empty bool from start_element().

Bug fixes:
   - Fixed a potential race condition between the destruction of the thread pool
     and the "program ending handlers" stuff.

Other:
   - Made the xml parser more robust to different types of new line characters.
   - Modified the source slightly so that it works with mingw.

Release 13

Release date: Mar 01, 2007
Major Changes in this Release:
New Features:
   - The config_reader is now enumerable.
   - Added the image_widget gui object.
   - Added nr() and nc() to the array2d object.
   - Added the shutdown_connection() function to the iostream extension
     to the server object.
   - Added the timer_kernel_2 implementation which is a version of the timer object
     that is more efficient in its allocation of threads.
   - Added the timeout object.
   - There is now a CMakeLists.txt file located in the dlib folder.  See
     dlib/examples/CMakeLists.txt and dlib/test/CMakeLists.txt for examples
     that use CMake to build projects using this library.
   - Added the register_program_ending_handler() function to the threading API.

Non-Backwards Compatible Changes:
   - Removed the config_reader::get_blocks() function.  Use the
     new enumerable interface for the config_reader instead.
   - The array2d object now uses longs instead of unsigned longs to report
     its dimensions and access its elements.
   - Added a uint64 to the on_connect() callback in the iostream
     extension to the server object.
   - timer::set_delay_time() now throws and timer::start() now may throw
     std::bad_alloc.

Bug fixes:
   - Fixed a bug in end_program().  In X Windows it might not cause the
     program to end right away if it was called from outside the event
     handling thread.
   - Fixed a bug in the implementation of the timeout part of the
     close_gracefully() function.

Other:
   - The library now works on HP-UX
   - The regression test suite now has command line arguments that
     enable tests to send debug messages to a file.

Release 12

Release date: Feb 07, 2007
Major Changes in this Release:
New Features:
   - The http server extension now supports the POST HTTP method.
   - The attribute list object in the xml_parser is now enumerable.
   - Added the threaded object extension
   - Added the uintn.h file which defines fixed sized unsigned integral types.

Non-Backwards Compatible Changes:
   - Renamed the on_get() callback in the http extension to the server object to
     on_request()
   - Removed the network byte order functions from the sockets api.  (They are still
     really there though since they come from actual OS header files.  But
     officially they have been replaced by the byte_orderer component).
   - Renamed dlib/uint64.h to dlib/uintn.h

Bug fixes:

Other:
   - The command line parser will now let you declare long named options with -
     characters in them.
   - Made it so you can use the COMPILE_TIME_ASSERT macros anywhere rather than
     just inside functions.

Release 11

Release date: Dec 27, 2006
Major Changes in this Release:
New Features:
   - For dlib::matrix
      - Added the tmp() function
      - Added optimized specializations of inv() and det() for 1x1, 2x2, 3x3 and
        4x4 matrices.
      - Added the removerc() function
   - Sockets related
      - Added the connect() function
      - Added the is_ip_address() function.
      - Added the close_gracefully() function
      - Added the iostream extension to the server object.
      - Added the http extension to the server object.

Non-Backwards Compatible Changes:
   - Changed the cpp_tokenizer to not convert characters to their html form.

Bug fixes:
   - Removed some potential compile time errors.  See the change log for details.

Other:
   - Improved the web site
   - Added some more example code
   - Added more colors to cpp_pretty_printer_kernel_1.

Release 10

Release date: Nov 28, 2006
Major Changes in this Release:
New Features:
   - std::map is now serializable
   - Added the matrix object and a bunch of supporting code.
   - Added the list_box graphical widget
   - Added the fill_rect_with_vertical_gradient() function to the
     drawable interfaces list of drawing helpers.
   - Added the open_file_box() function which provides a simple file chooser.

Non-Backwards Compatible Changes:

Bug fixes:
   - Made timestamper::get_timestamp() be a const function like it should.  Fixes
     some compile errors.
   - Fixed a bug in the font::draw_string() function.  It didn't redraw
     multi-line strings right.
   - Fixed a bug in the scroll_bar object that would cause a compile
     error if you tried to call its width() function.
   - Fixed a bug in the array_kernel_1 object.  It would cause a segmentation fault
     when used sometimes.

Other:

Release 9

Release date: Oct 23, 2006
Major Changes in this Release:
New Features:
   - Added the following image transformation functions:
      - Added the equalize_histogram() function
      - Added the spatially_filter_image() function
      - Added the threshold_image() function
      - Added the binary_dilation() function
      - Added the binary_erosion() function
      - Added the binary_open() function
      - Added the binary_close() function
      - Added the binary_intersection() function
      - Added the binary_difference() function
      - Added the binary_complement() function
   - Added the clear(), load_from() and default constructor back into the
     config_reader.
   - Made the member_function_pointer copyable and also added operator== and !=
     to it.

Non-Backwards Compatible Changes:
   - Made the vector object templated so you can use types other than double with it.
     But now you
     have to specify what type you want to use which is slightly different.
   - The asc_pair_remover and asc_remover abstract classes now take a third template
     argument.  I highly doubt this effects any code outside the library but it is
     possible.

Bug fixes:
   - Fixed a bug in the base_window::set_size() function.  If you specified a size
     of (0,0) it caused your program to error out.  This has now been fixed.
   - Fixed a bug in the scroll_bar widget.
   - Fixed a bug in save_bmp().  For some image sizes it would output a goofy
     looking skewed image.

Other:
   - Switched everything that used to call operator< directly to instead use
     std::less or to take a template argument that provides a compare functor that
     defaults to std::less.

Release 8

Release date: Oct 03, 2006
Major Changes in this Release:
New Features:
   - Added the assign_pixel() function
   - Added the hsi pixel type
   - Added the save_bmp() function
   - Added the static_switch template

Non-Backwards Compatible Changes:
   - Changed how the config_reader works.  It now has a more powerful syntax and
     improved interface.  Converting any old code to use the new version should be
     simple since the new file syntax is very nearly backwards compatible with the
     old syntax.  (i.e. You probably won't have to change anything about your
     config files)
   - Renamed the dlib/image_loader.h file to dlib/image_io.h since it now includes
     the image saver stuff.
   - Renamed the pixel struct to rgb_pixel
   - Renamed pixel_traits::color to pixel_traits::rgb
   - Renamed pixel_traits::scalar to pixel_traits::grayscale

Bug fixes:
   - Fixed a bug in the load_bmp() function.  It would load 24bit bmp files
     incorrectly.
   - Changed the logger so that it won't deadlock if you write something similar to
     my_log << LINFO << function_that_also_logs();.  Although this is a
     dumb thing to do.  But even so, it shouldn't deadlock.
   - Fixed a potential linking problem with the vector object.

Other:
   - I decided I'm not going to support Borland v5.5.1 anymore.  There are just too
     many bugs in this compiler.  It is very old at this point so I don't see this
     being a big deal.
   - Made the drawable::draw_image() and load_bmp() functions able to handle images
     of any type of pixel.
   - Pulled the imaging, algorithmic and metaprogramming stuff out of the
     miscellaneous section of the web page and gave them all their own sections.

Release 7

Release date: Sep 18, 2006
Major Changes in this Release:
New Features:
   - Added a logger header that prints the date and time.
   - Added the LTRACE logging level
   - Added a buffered implementation of sockstreambuf.

Non-Backwards Compatible Changes:
   - Changed the specs to say that sockstreambuf may be buffered.
     sockstreambuf_kernel_1 is still just as it always has been though.  So all old
     code will still work just as it always has.  But all the same, the specs have
     been changed and now allow for an implementation that is not 100% backwards
     compatible.
   - rand_kernel_2 now emits a different string of random numbers.

Bug fixes:
   - Changed the logger object's implementation to not try to register
     a thread end handler for the main program thread anymore.  This was
     technically a bug according to the spec but it actually did end up
     working the way it was supposed to.  But even so, it shouldn't have
     been doing that.
   - Changed binary_search_tree_kernel_1 so that it avoids a bug in the version of
     gcc on SuSE Enterprise Linux 9.
   - Fixed a bug in the rand_kernel_2 implementation.  It wasn't giving good
     random numbers.

Other:
   - Modified the code so that you don't get any warnings when -Wall is used with
     GCC.

Release 6

Release date: Aug 30, 2006
Major Changes in this Release:
New Features:
   - Added the ASSERT_ARE_SAME_TYPE macro
   - Added the is_same_type template
   - Added the get_main_thread_id() function to the threading API
   - Added the thread_specific_data extension to the threading API
   - Added the logger object.
   - Added the auto_unlock object to the threading API.

Non-Backwards Compatible Changes:

Bug fixes:

Other:
   - Added an example that is specifically about using threads
   - Added two examples about using the logger object

Release 5

Release date: Aug 18, 2006
Major Changes in this Release:
New Features:
   - Added the memory_manager_stateless object and two implementations of it.
   - Added the MACOSX macro to dlib/platform.h
   - Added a templated version of create_new_thread() that allow you to start
     a thread with a member function.
   - Added the register_thread_end_handler() function to the threading kernel API.
   - Added memory_manager_kernel_3

Non-Backwards Compatible Changes:
   - Changed the meaning of the memory_manager_global::get_number_of_allocations()
     function because the previous definition of it didn't really make sense for
     this object.
   - Changed the threading API to wait for all outstanding threads to terminate
     before allowing the program to end.  It used to just let the OS trash those
     threads when main() ended but this isn't a safe or portable thing to do.  I
     used to assume the user would make sure all their threads were done and had
     cleaned up whatever they were doing before main() ended but this is too much
     of a burden on the end user.  So now the library will wait for your threads to
     end.  You still need to have some way of telling them it is time to stop though.

Bug fixes:
   - Fixed a minor bug in dlib/timer/timer_kernel_1.h.  Its implementation was
     slightly off according to the specification of a timer object.

Other:
   - The byte_order object is now capable of flipping entire arrays.
   - Made it so that the ENABLE_ASSERTS macro is defined whenever ASSERT is
     on.
   - Made the array container use the memory managers.

Release 4

Release date: Jul 18, 2006
Major Changes in this Release:
New Features:
   - Added functions to explicitly convert to/from little and big endian to the
     byte_order object.
   - Added the allocate_array() and deallocate_array() functions to the
     memory_manager.
   - Created the memory_manager_global object
   - Added the remove_last_in_order(), position_enumerator() and
     remove_current_element() functions to the binary_search_tree object.

Non-Backwards Compatible Changes:
   - I put an #error directive in the old GUI component to notify anyone
     trying to use it that it is deprecated.  I will be removing it from the
     library in a few months.
   - Switched the reference_counter object back to not using the memory_manager.
     I realized it isn't safe for this object to use the memory_manager since
     it could result in memory_managers freeing each other's allocations.
   - I redefined the pixel_traits template.  It is now a lot simpler and more
     convenient.

Bug fixes:
   - Fixed a minor bug in dlib/rand/rand_kernel_2.cpp

Other:
   - Added some more compile time checks to the byte_orderer object.
   - Changed some includes and preprocessor macros around a little so now
     everything but the GUI stuff compiles in mac OS X.
   - Added inclusion guards to all the .cpp files
   - Added the all_gui.cpp and all_console.cpp files.  They
     include all the .cpp files you need to make gui and
     console applications respectively into one file.
   - Made more containers use the memory_manager.

Release 3

Release date: May 06, 2006
Major Changes in this Release:
New Features:
   - Added the enqueue_or_timeout() and dequeue_or_timeout() functions
     to the pipe object.
   - Gave the mouse_tracker the ability to display the mouse position
     relative to a user selected point.
   - Added the message_box() function to the gui_widgets component.
   - Gave the label widget the ability to draw newlines in strings.
   - added the close_window() and is_closed() methods to the base_window
     object.
   - Added the rsignaler extension to the threading API.
   - You can now control the thread pool timeout time by setting the
     DLIB_THREAD_POOL_TIMEOUT #define.
   - Added the get_from_clipboard() and put_on_clipboard() functions
     to the gui_core component.
   - Added the stop_and_wait() function to the timer object.
   - Added the trigger_user_event() function and on_user_event() event
     to the base_window object.  This new event is also forwarded
     to drawable interfaces inside the receiving window.
   - Added the wrap_around() function to the named_rectangle widget.
   - Added the top(), left(), right(), bottom(), width() and height()
     functions to the drawable interface.

Non-Backwards Compatible Changes:
   - Made the radio_button and check_box widgets pass references to themselves
     when they call their click handlers.
   - Switched the sync_extension to use the rmutex and rsignaler objects
     rather than the normal non-reentrant ones. ( Chances are that old
     code that used this will still compile fine anyway. )
   - Changed the return type of rand::get_random_number() to be an
     unsigned char.  I also changed both the implementations of
     rand because they weren't very good at all.
   - Changed the functions related to drawing strings in the font class.
   - Changed the drawable's rectangle to default to being empty
     rather than being a single point.  Most code should not notice
     the difference.

Bug fixes:
   - The event handlers in gui_widgets/drawable.h were private.  They
     should be protected.  This is now fixed.
   - Fixed a bug in the way the scroll_bar was drawn when it was
     the HORIZONTAL type.
   - Changed how the thread pool destructs itself when the program
     is ending.  Previously it was possible to get an error on
     NetBSD when the program was ending.  This is now fixed.
   - The functions related to setting the jump size in the scroll_bar
     widget were private.  They are now public.
   - There was a bug in the MS Windows version of the gui_core component
     where the members of the base_window would not work if called from
     within the on_window_close() event.  This has now been fixed.
   - Made the set_pos() function work right for the mouse_tracker widget.
   - Fixed a bug in the base64 object where the string "" could potentially
     be decoded incorrectly.
   - Made the global swap function for crc32_kernel_1 inline.  This fixes a
     potential linker error.
   - Fixed some potential deadlocking that could occur while using the
     gui widgets.

Other:
   - I moved all the regression tests into the dlib/test folder and
     made a nice driver program to run all of them.
   - I have been using the sourceforge compile farms to test the library
     on various platforms.  It now works for Solaris and some of the BSDs
     in addition to Linux and Windows.

Release 2

Release date: Apr 08, 2006
Major Changes in this Release:
New Features:
   - Added the array_expand extension to the array object.
   - Added the cmd_line_parser_check extension to the command line parser.
   - Added the pipe object.
   - All applicable container classes now use the memory_manager component for
     their memory allocation.
   - New implementations of the memory_manager object.
   - Added the copy_functor class.

Non-Backwards Compatible Changes:
   - Moved the wrap_string, narrow, and string_cast functions
     to a new file.  You now have to include dlib/string.h to get
     them.  (This makes a bunch of other things work right in gcc 2.95)
   - Renamed the _L macro to _dT
   - Removed the scopy class
   - Simplified the interface to the memory manager.  It is basically the same
     though.
   - Removed the max_size() methods from the hash_table and binary_search_tree
     objects.
   - Removed the T_is_POD template arguments from the hash_table and
     binary_search_tree objects.
   - Simplified the template arguments to all checking components and extensions.
     They now take the class they are to extend or check as their only template
     argument.  This only affects you if you haven't been using the kernel_nx
     typedefs.

Bug fixes:

Other:
   - I changed a few things around and now a majority of the library
     again compiles under gcc 2.95.  But some things don't and I currently
     don't plan on making them work because it involves hackish workarounds
     of 2.95's bugs.
   - Changed the compress_stream_kernel_1 object so that it will detect data
     corruptions better.  This change will prevent it from correctly decompressing
     data that was compressed with a previous version and has an uncompressed size
     greater than about 20,000 bytes.
   - There is a new cpp file you need to compile:  dlib/error.cpp
   - Moved all the regression testing stuff into the dlib/test folder and made
     a nicer test driver to run them.

Release 1

Release date: Mar 19, 2006
Major Changes in this Release:
New Features:
    - Created the byte_orderer object.
    - Created the mouse_tracker gui widget.
    - The sliding_buffer object is now enumerable and serializable.
    - Added the get_filesystem_roots() function to the dir_nar component.
    - Added the create_directory() function to the misc_api component.

Non-Backwards Compatible Changes:
    - The ASSERT macro is now only enabled if DEBUG or ENABLE_ASSERTS
      is defined.

Bug fixes:
    - Fixed a minor bug in the cmd_line_parser object.  If you gave
      an option such as --option=arg when option didn't take any
      arguments it could hang your program.
    - Fixed a bug in wait_or_timeout() in the posix version of the threading
      api.  The time to wait for was being calculated incorrectly and could
      result in an excessive number of spurious returns.
    - Fixed a minor bug in the on_keydown() event for windows.
      I had it set such that the shift and ctrl bools would be false
      if they were the actual keys being pressed.  This isn't what the
      specs say should happen but I had a comment in the windows code
      that made it clear that I did it on purpose.  Go figure :)
      This is now fixed.

Other:
    - Improved the cpp_tokenizer object's ability to recognize numerical
      constants.
    - Improved the text_field gui widget.
    - There are now two assert macros.  One called ASSERT
      and another CASSERT.  They both do the same thing but ASSERT
      is only enabled when DEBUG or ENABLE_ASSERTS is defined.
      All the old ASSERT statements were changed to CASSERT statements.

Release 2006-02-23.01

Major Changes in this Release:
New Features:
    - Added array_kernel_2 which is a simple layer on top of a C array.
    - Added the tabbed_display GUI widget
    - Added the widget_group GUI widget
    - Added the named_rectangle GUI widget
    - Added the pixel_traits template

Non-Backwards Compatible Changes:
    - The default maximum size for an array object is now 0 rather than
      20,000.
Bug fixes:

Other:
    - made the cpp_pretty_printer a little better about how it handles
      C style code.  Also added support for /*!A html_anchor_name !*/
      style comments.

Release 2006-01-31.02

Major Changes in this Release:
New Features:
    - Created the array2d object.
    - Created the base64 object.
    - Created the pixel struct.
    - Created the load_bmp() function which can load a BMP image file
      into an array2d object of pixels.
    - Created the drawable::draw_image() function

Non-Backwards Compatible Changes:
    - In the drawable interface I made the z order a long rather
      than unsigned long.
    - The cpp_tokenizer object now has a NUMBER token type.
    - removed the get_ prefix from functions in the cmd_line_parser
      and cmd_line_parser_option objects.  Also changed the
      cmd_line_parser_option::operator[] function to a normal member
      function called argument().

Bug fixes:

Other:
    - cpp_pretty_printer now colors numeric literals a shade of yellow.

Release 2006-01-15.03

Major Changes in this Release:
New Features:
    - Created the member_function_pointer object.
    - Created the button_action object.
    - Created the arrow_button object.
    - Created the check_box object.
    - Created the radio_button object.
    - Created the scroll_bar object.
    - More drawing functions to draw various things
      onto a canvas object.
    - Added enable/disable functions to the
      drawable interface.

Non-Backwards Compatible Changes:
    - The gui widgets are no longer templated at the
      class level.
    - The drawable object's constructor now takes a
      bit set rather than a bunch of bools to tell it
      which events to enable.
    - I changed the names of some of the functions in the
      gui_widgets component so that they all reflected a
      uniform naming style.

Bug fixes:
    - Fixed a minor bug in the cpp_tokenizer.
    - Minor bug in the timer object. See change log for
      details.

Other:
    - Made the timer object a little more robust


dlib C++ Library - any.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_AnY_
#define DLIB_AnY_

#include "any/any.h"
#include "any/any_trainer.h"
#include "any/any_decision_function.h"
#include "any/any_function.h"

#endif // DLIB_AnY_


dlib C++ Library - array2d.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ARRAY2d_
#define DLIB_ARRAY2d_

#include "array2d/array2d_kernel.h"
#include "array2d/serialize_pixel_overloads.h"
#include "array2d/array2d_generic_image.h"

#endif // DLIB_ARRAY2d_


dlib C++ Library - array.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ARRAy_
#define DLIB_ARRAy_

#include "array/array_kernel.h"
#include "array/array_tools.h"

#endif // DLIB_ARRAy_


dlib C++ Library - base64.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_BASe64_
#define DLIB_BASe64_

#include "base64/base64_kernel_1.h"

#endif // DLIB_BASe64_


dlib C++ Library - binary_search_tree.h

// 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_
#define DLIB_BINARY_SEARCH_TREe_

#include "binary_search_tree/binary_search_tree_kernel_1.h"
#include "binary_search_tree/binary_search_tree_kernel_2.h"
#include "binary_search_tree/binary_search_tree_kernel_c.h"

#include "algs.h"
#include <functional>

namespace dlib
{

    template <
        typename domain,
        typename range,
        typename mem_manager = default_memory_manager,
        typename compare = std::less<domain>
        >
    class binary_search_tree
    {
        binary_search_tree() {}

    public:

        //----------- kernels ---------------

        // kernel_1a
        typedef     binary_search_tree_kernel_1<domain,range,mem_manager,compare>
                    kernel_1a;
        typedef     binary_search_tree_kernel_c<kernel_1a>
                    kernel_1a_c;

        // kernel_2a
        typedef     binary_search_tree_kernel_2<domain,range,mem_manager,compare>
                    kernel_2a;
        typedef     binary_search_tree_kernel_c<kernel_2a>
                    kernel_2a_c;

    };
}

#endif // DLIB_BINARY_SEARCH_TREe_


dlib C++ Library - bound_function_pointer.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_BOUND_FUNCTION_POINTEr_
#define DLIB_BOUND_FUNCTION_POINTEr_

#include "bound_function_pointer/bound_function_pointer_kernel_1.h"

#endif // DLIB_BOUND_FUNCTION_POINTEr_


dlib C++ Library - byte_orderer.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_BYTE_ORDEREr_
#define DLIB_BYTE_ORDEREr_

#include "byte_orderer/byte_orderer_kernel_1.h"

#endif // DLIB_BYTE_ORDEREr_


dlib C++ Library - compress_stream.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_COMPRESS_STREAm_
#define DLIB_COMPRESS_STREAm_

#include "compress_stream/compress_stream_kernel_1.h"
#include "compress_stream/compress_stream_kernel_2.h"
#include "compress_stream/compress_stream_kernel_3.h"

#include "conditioning_class.h"
#include "entropy_encoder.h"
#include "entropy_decoder.h"

#include "entropy_encoder_model.h"
#include "entropy_decoder_model.h"
#include "lz77_buffer.h"
#include "sliding_buffer.h"
#include "lzp_buffer.h"
#include "crc32.h"

namespace dlib
{

    class compress_stream
    {
        compress_stream() {}

        typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_1b fce1;
        typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_1b fcd1;

        typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_2b fce2;
        typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_2b fcd2;

        typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_3b fce3;
        typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_3b fcd3;

        typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_4a fce4a;
        typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_4a fcd4a;
        typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_4b fce4b;
        typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_4b fcd4b;

        typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_5a fce5a;
        typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_5a fcd5a;
        typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_5b fce5b;
        typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_5b fcd5b;
        typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_5c fce5c;
        typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_5c fcd5c;

        typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_6a fce6;
        typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_6a fcd6;

        typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_2d fce2d;
        typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_2d fcd2d;

        typedef sliding_buffer<unsigned char>::kernel_1a sliding_buffer1;
        typedef lz77_buffer::kernel_2a lz77_buffer2a;

        typedef lzp_buffer::kernel_1a lzp_buf_1;
        typedef lzp_buffer::kernel_2a lzp_buf_2;

        typedef entropy_encoder_model<513,entropy_encoder::kernel_2a>::kernel_1b fce_length;
        typedef entropy_decoder_model<513,entropy_decoder::kernel_2a>::kernel_1b fcd_length;

        typedef entropy_encoder_model<65534,entropy_encoder::kernel_2a>::kernel_1b fce_length_2;
        typedef entropy_decoder_model<65534,entropy_decoder::kernel_2a>::kernel_1b fcd_length_2;

        typedef entropy_encoder_model<32257,entropy_encoder::kernel_2a>::kernel_1b fce_index;
        typedef entropy_decoder_model<32257,entropy_decoder::kernel_2a>::kernel_1b fcd_index;

    public:

        //----------- kernels ---------------

        // kernel_1a
        typedef      compress_stream_kernel_1 <fce1,fcd1,crc32::kernel_1a>
                     kernel_1a;

        // kernel_1b
        typedef      compress_stream_kernel_1 <fce2,fcd2,crc32::kernel_1a>
                     kernel_1b;

        // kernel_1c
        typedef      compress_stream_kernel_1 <fce3,fcd3,crc32::kernel_1a>
                     kernel_1c;

        // kernel_1da
        typedef      compress_stream_kernel_1 <fce4a,fcd4a,crc32::kernel_1a>
                     kernel_1da;

        // kernel_1ea
        typedef      compress_stream_kernel_1 <fce5a,fcd5a,crc32::kernel_1a>
                     kernel_1ea;

        // kernel_1db
        typedef      compress_stream_kernel_1 <fce4b,fcd4b,crc32::kernel_1a>
                     kernel_1db;

        // kernel_1eb
        typedef      compress_stream_kernel_1 <fce5b,fcd5b,crc32::kernel_1a>
                     kernel_1eb;

        // kernel_1ec
        typedef      compress_stream_kernel_1 <fce5c,fcd5c,crc32::kernel_1a>
                     kernel_1ec;

        // kernel_2a
        typedef      compress_stream_kernel_2 <fce2,fcd2,lz77_buffer2a,sliding_buffer1,fce_length,fcd_length,fce_index,fcd_index,crc32::kernel_1a>
                     kernel_2a;

        // kernel_3a
        typedef      compress_stream_kernel_3 <lzp_buf_1,crc32::kernel_1a,16>
                     kernel_3a;
        // kernel_3b
        typedef      compress_stream_kernel_3 <lzp_buf_2,crc32::kernel_1a,16>
                     kernel_3b;

    };
}

#endif // DLIB_COMPRESS_STREAm_


dlib C++ Library - conditioning_class.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_CONDITIONING_CLASs_
#define DLIB_CONDITIONING_CLASs_

#include "conditioning_class/conditioning_class_kernel_1.h"
#include "conditioning_class/conditioning_class_kernel_2.h"
#include "conditioning_class/conditioning_class_kernel_3.h"
#include "conditioning_class/conditioning_class_kernel_4.h"
#include "conditioning_class/conditioning_class_kernel_c.h"

#include "memory_manager.h"

namespace dlib
{

    template <
        unsigned long alphabet_size
        >
    class conditioning_class
    {
        conditioning_class() {}

        typedef memory_manager<char>::kernel_2b mm;

    public:

        //----------- kernels ---------------

        // kernel_1a
        typedef      conditioning_class_kernel_1<alphabet_size>
                     kernel_1a;
        typedef      conditioning_class_kernel_c<kernel_1a>
                     kernel_1a_c;

        // kernel_2a
        typedef      conditioning_class_kernel_2<alphabet_size>
                     kernel_2a;
        typedef      conditioning_class_kernel_c<kernel_2a>
                     kernel_2a_c;

        // kernel_3a
        typedef      conditioning_class_kernel_3<alphabet_size>
                     kernel_3a;
        typedef      conditioning_class_kernel_c<kernel_3a>
                     kernel_3a_c;

        // -------- kernel_4 ---------

        // kernel_4a
        typedef      conditioning_class_kernel_4<alphabet_size,10000,mm>
                     kernel_4a;
        typedef      conditioning_class_kernel_c<kernel_4a>
                     kernel_4a_c;

        // kernel_4b
        typedef      conditioning_class_kernel_4<alphabet_size,100000,mm>
                     kernel_4b;
        typedef      conditioning_class_kernel_c<kernel_4b>
                     kernel_4b_c;

        // kernel_4c
        typedef      conditioning_class_kernel_4<alphabet_size,1000000,mm>
                     kernel_4c;
        typedef      conditioning_class_kernel_c<kernel_4c>
                     kernel_4c_c;

        // kernel_4d
        typedef      conditioning_class_kernel_4<alphabet_size,10000000,mm>
                     kernel_4d;
        typedef      conditioning_class_kernel_c<kernel_4d>
                     kernel_4d_c;

    };
}

#endif // DLIB_CONDITIONING_CLASS_


dlib C++ Library - config.h

// If you are compiling dlib as a shared library and installing it somewhere on your system
// then it is important that any programs that use dlib agree on the state of the
// DLIB_ASSERT statements (i.e. they are either always on or always off).  Therefore,
// uncomment one of the following lines to force all DLIB_ASSERTs to either always on or
// always off.  If you don't define one of these two macros then DLIB_ASSERT will toggle
// automatically depending on the state of certain other macros, which is not what you want
// when creating a shared library.
//#define ENABLE_ASSERTS       // asserts always enabled
//#define DLIB_DISABLE_ASSERTS // asserts always disabled

// You should also consider telling dlib to link against libjpeg, libpng, fftw, and a BLAS
// and LAPACK library.  To do this you need to uncomment the following #defines.
// #define DLIB_JPEG_SUPPORT
// #define DLIB_PNG_SUPPORT
// #define DLIB_USE_FFTW
// #define DLIB_USE_BLAS
// #define DLIB_USE_LAPACK


dlib C++ Library - config_reader.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_CONFIG_READEr_
#define DLIB_CONFIG_READEr_

#include "config_reader/config_reader_kernel_1.h"
#include "map.h"
#include "tokenizer.h"
#include "cmd_line_parser/get_option.h"

#include "algs.h"
#include "is_kind.h"

namespace dlib
{

    typedef config_reader_kernel_1<
        map<std::string,std::string>::kernel_1b,
        map<std::string,void*>::kernel_1b,
        tokenizer::kernel_1a
        > config_reader;

    template <> struct is_config_reader<config_reader> { const static bool value = true; };

#ifndef DLIB_ISO_CPP_ONLY
    typedef config_reader_thread_safe_1<
        config_reader,
        map<std::string,void*>::kernel_1b
        > config_reader_thread_safe;

    template <> struct is_config_reader<config_reader_thread_safe> { const static bool value = true; };
#endif // DLIB_ISO_CPP_ONLY

}

#endif // DLIB_CONFIG_READEr_


dlib C++ Library - crc32.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_CRc32_
#define DLIB_CRc32_

#include "crc32/crc32_kernel_1.h"

#endif // DLIB_CRc32_


dlib C++ Library - dir_nav.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_DIR_NAv_
#define DLIB_DIR_NAv_

#include "platform.h"

#ifdef WIN32
#include "dir_nav/windows.h"
#endif

#ifndef WIN32
#include "dir_nav/posix.h"
#endif

#include "dir_nav/dir_nav_extensions.h"

#endif // DLIB_DIR_NAv_


dlib C++ Library - directed_graph.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_DIRECTED_GRAPh_
#define DLIB_DIRECTED_GRAPh_

#include "directed_graph/directed_graph_kernel_1.h"

#include "algs.h"

namespace dlib
{

    template <
        typename T,
        typename E = char,
        typename mem_manager = default_memory_manager
        >
    class directed_graph
    {
        directed_graph() {}
    public:

        //----------- kernels ---------------

        // kernel_1a
        typedef     directed_graph_kernel_1<T,E,mem_manager,false>
                    kernel_1a;
        typedef     directed_graph_kernel_1<T,E,mem_manager,true>
                    kernel_1a_c;

    };
}

#endif // DLIB_DIRECTED_GRAPh_


dlib C++ Library - disjoint_subsets.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_DISJOINt_SUBSETS_
#define DLIB_DISJOINt_SUBSETS_

#include "disjoint_subsets/disjoint_subsets.h"

#endif // DLIB_DISJOINt_SUBSETS_


dlib C++ Library - enable_if.h

// Copyright 2003 (C) The Trustees of Indiana University.
// Use, modification, and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//    Authors: Jaakko Jarvi (jajarvi at osl.iu.edu)
//             Jeremiah Willcock (jewillco at osl.iu.edu)
//             Andrew Lumsdaine (lums at osl.iu.edu)
#ifndef DLIB_BOOST_UTILITY_ENABLE_IF_HPP
#define DLIB_BOOST_UTILITY_ENABLE_IF_HPP

namespace dlib
{

  template <bool B, class T = void>
  struct enable_if_c {
    typedef T type;
  };

  template <class T>
  struct enable_if_c<false, T> {};

  template <class Cond, class T = void>
  struct enable_if : public enable_if_c<Cond::value, T> {};

  template <bool B, class T>
  struct lazy_enable_if_c {
    typedef typename T::type type;
  };

  template <class T>
  struct lazy_enable_if_c<false, T> {};

  template <class Cond, class T>
  struct lazy_enable_if : public lazy_enable_if_c<Cond::value, T> {};

  template <bool B, class T = void>
  struct disable_if_c {
    typedef T type;
  };

  template <class T>
  struct disable_if_c<true, T> {};

  template <class Cond, class T = void>
  struct disable_if : public disable_if_c<Cond::value, T> {};

  template <bool B, class T>
  struct lazy_disable_if_c {
    typedef typename T::type type;
  };

  template <class T>
  struct lazy_disable_if_c<true, T> {};

  template <class Cond, class T>
  struct lazy_disable_if : public lazy_disable_if_c<Cond::value, T> {};

} // namespace dlib

#endif // DLIB_BOOST_UTILITY_ENABLE_IF_HPP


dlib C++ Library - entropy_decoder.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ENTROPY_DECODEr_
#define DLIB_ENTROPY_DECODEr_

#include "entropy_decoder/entropy_decoder_kernel_1.h"
#include "entropy_decoder/entropy_decoder_kernel_2.h"
#include "entropy_decoder/entropy_decoder_kernel_c.h"

namespace dlib
{

    class entropy_decoder
    {
        entropy_decoder() {}

    public:

        //----------- kernels ---------------

        // kernel_1a
        typedef     entropy_decoder_kernel_1
                    kernel_1a;
        typedef     entropy_decoder_kernel_c<kernel_1a>
                    kernel_1a_c;

        // kernel_2a
        typedef     entropy_decoder_kernel_2
                    kernel_2a;
        typedef     entropy_decoder_kernel_c<kernel_2a>
                    kernel_2a_c;

    };
}

#endif // DLIB_ENTROPY_DECODEr_


dlib C++ Library - entropy_decoder_model.h

// Copyright (C) 2004  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ENTROPY_DECODER_MODEl_
#define DLIB_ENTROPY_DECODER_MODEl_

#include "entropy_decoder_model/entropy_decoder_model_kernel_1.h"
#include "entropy_decoder_model/entropy_decoder_model_kernel_2.h"
#include "entropy_decoder_model/entropy_decoder_model_kernel_3.h"
#include "entropy_decoder_model/entropy_decoder_model_kernel_4.h"
#include "entropy_decoder_model/entropy_decoder_model_kernel_5.h"
#include "entropy_decoder_model/entropy_decoder_model_kernel_6.h"

#include "conditioning_class.h"
#include "memory_manager.h"

namespace dlib
{

    template <
        unsigned long alphabet_size,
        typename entropy_decoder
        >
    class entropy_decoder_model
    {
        entropy_decoder_model() {}

        typedef typename conditioning_class<alphabet_size+1>::kernel_1a cc1;
        typedef typename conditioning_class<alphabet_size+1>::kernel_2a cc2;
        typedef typename conditioning_class<alphabet_size+1>::kernel_3a cc3;
        typedef typename conditioning_class<alphabet_size+1>::kernel_4a cc4a;
        typedef typename conditioning_class<alphabet_size+1>::kernel_4b cc4b;
        typedef typename conditioning_class<alphabet_size+1>::kernel_4c cc4c;
        typedef typename conditioning_class<alphabet_size+1>::kernel_4d cc4d;

    public:

        //----------- kernels ---------------

        // kernel_1
        typedef     entropy_decoder_model_kernel_1<alphabet_size,entropy_decoder,cc1>
                    kernel_1a;

        typedef     entropy_decoder_model_kernel_1<alphabet_size,entropy_decoder,cc2>
                    kernel_1b;

        typedef     entropy_decoder_model_kernel_1<alphabet_size,entropy_decoder,cc3>
                    kernel_1c;

        // --------------------

        // kernel_2
        typedef     entropy_decoder_model_kernel_2<alphabet_size,entropy_decoder,cc1,cc1>
                    kernel_2a;

        typedef     entropy_decoder_model_kernel_2<alphabet_size,entropy_decoder,cc2,cc2>
                    kernel_2b;

        typedef     entropy_decoder_model_kernel_2<alphabet_size,entropy_decoder,cc3,cc3>
                    kernel_2c;

        typedef     entropy_decoder_model_kernel_2<alphabet_size,entropy_decoder,cc2,cc4b>
                    kernel_2d;

        // --------------------

        // kernel_3
        typedef     entropy_decoder_model_kernel_3<alphabet_size,entropy_decoder,cc1,cc4b>
                    kernel_3a;

        typedef     entropy_decoder_model_kernel_3<alphabet_size,entropy_decoder,cc2,cc4b>
                    kernel_3b;

        typedef     entropy_decoder_model_kernel_3<alphabet_size,entropy_decoder,cc3,cc4b>
                    kernel_3c;

        // --------------------

        // kernel_4
        typedef     entropy_decoder_model_kernel_4<alphabet_size,entropy_decoder,200000,4>
                    kernel_4a;
        typedef     entropy_decoder_model_kernel_4<alphabet_size,entropy_decoder,1000000,5>
                    kernel_4b;

        // --------------------

        // kernel_5
        typedef     entropy_decoder_model_kernel_5<alphabet_size,entropy_decoder,200000,4>
                    kernel_5a;
        typedef     entropy_decoder_model_kernel_5<alphabet_size,entropy_decoder,1000000,5>
                    kernel_5b;
        typedef     entropy_decoder_model_kernel_5<alphabet_size,entropy_decoder,2500000,7>
                    kernel_5c;

        // --------------------

        // kernel_6
        typedef     entropy_decoder_model_kernel_6<alphabet_size,entropy_decoder>
                    kernel_6a;

    };
}

#endif // DLIB_ENTROPY_DECODER_MODEl_


dlib C++ Library - entropy_encoder.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ENTROPY_ENCODEr_
#define DLIB_ENTROPY_ENCODEr_

#include "entropy_encoder/entropy_encoder_kernel_1.h"
#include "entropy_encoder/entropy_encoder_kernel_2.h"
#include "entropy_encoder/entropy_encoder_kernel_c.h"

namespace dlib
{

    class entropy_encoder
    {
        entropy_encoder() {}

    public:

        //----------- kernels ---------------

        // kernel_1a
        typedef     entropy_encoder_kernel_1
                    kernel_1a;
        typedef     entropy_encoder_kernel_c<kernel_1a>
                    kernel_1a_c;

        // kernel_2a
        typedef     entropy_encoder_kernel_2
                    kernel_2a;
        typedef     entropy_encoder_kernel_c<kernel_2a>
                    kernel_2a_c;

    };
}

#endif // DLIB_ENTROPY_ENCODEr_


dlib C++ Library - entropy_encoder_model.h

// Copyright (C) 2004  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ENTROPY_ENCODER_MODEl_
#define DLIB_ENTROPY_ENCODER_MODEl_

#include "entropy_encoder_model/entropy_encoder_model_kernel_1.h"
#include "entropy_encoder_model/entropy_encoder_model_kernel_2.h"
#include "entropy_encoder_model/entropy_encoder_model_kernel_3.h"
#include "entropy_encoder_model/entropy_encoder_model_kernel_4.h"
#include "entropy_encoder_model/entropy_encoder_model_kernel_5.h"
#include "entropy_encoder_model/entropy_encoder_model_kernel_6.h"
#include "entropy_encoder_model/entropy_encoder_model_kernel_c.h"

#include "conditioning_class.h"
#include "memory_manager.h"
#include "sliding_buffer.h"

namespace dlib
{

    template <
        unsigned long alphabet_size,
        typename entropy_encoder
        >
    class entropy_encoder_model
    {
        entropy_encoder_model() {}

        typedef typename conditioning_class<alphabet_size+1>::kernel_1a cc1;
        typedef typename conditioning_class<alphabet_size+1>::kernel_2a cc2;
        typedef typename conditioning_class<alphabet_size+1>::kernel_3a cc3;
        typedef typename conditioning_class<alphabet_size+1>::kernel_4a cc4a;
        typedef typename conditioning_class<alphabet_size+1>::kernel_4b cc4b;
        typedef typename conditioning_class<alphabet_size+1>::kernel_4c cc4c;
        typedef typename conditioning_class<alphabet_size+1>::kernel_4d cc4d;

    public:

        //----------- kernels ---------------

        // kernel_1
        typedef     entropy_encoder_model_kernel_1<alphabet_size,entropy_encoder,cc1>
                    kernel_1a;
        typedef     entropy_encoder_model_kernel_c<kernel_1a>
                    kernel_1a_c;

        typedef     entropy_encoder_model_kernel_1<alphabet_size,entropy_encoder,cc2>
                    kernel_1b;
        typedef     entropy_encoder_model_kernel_c<kernel_1b>
                    kernel_1b_c;

        typedef     entropy_encoder_model_kernel_1<alphabet_size,entropy_encoder,cc3>
                    kernel_1c;
        typedef     entropy_encoder_model_kernel_c<kernel_1c>
                    kernel_1c_c;

        // --------------------

        // kernel_2
        typedef     entropy_encoder_model_kernel_2<alphabet_size,entropy_encoder,cc1,cc1>
                    kernel_2a;
        typedef     entropy_encoder_model_kernel_c<kernel_2a>
                    kernel_2a_c;

        typedef     entropy_encoder_model_kernel_2<alphabet_size,entropy_encoder,cc2,cc2>
                    kernel_2b;
        typedef     entropy_encoder_model_kernel_c<kernel_2b>
                    kernel_2b_c;

        typedef     entropy_encoder_model_kernel_2<alphabet_size,entropy_encoder,cc3,cc3>
                    kernel_2c;
        typedef     entropy_encoder_model_kernel_c<kernel_2c>
                    kernel_2c_c;

        typedef     entropy_encoder_model_kernel_2<alphabet_size,entropy_encoder,cc2,cc4b>
                    kernel_2d;
        typedef     entropy_encoder_model_kernel_c<kernel_2d>
                    kernel_2d_c;

        // --------------------

        // kernel_3
        typedef     entropy_encoder_model_kernel_3<alphabet_size,entropy_encoder,cc1,cc4b>
                    kernel_3a;
        typedef     entropy_encoder_model_kernel_c<kernel_3a>
                    kernel_3a_c;

        typedef     entropy_encoder_model_kernel_3<alphabet_size,entropy_encoder,cc2,cc4b>
                    kernel_3b;
        typedef     entropy_encoder_model_kernel_c<kernel_3b>
                    kernel_3b_c;

        typedef     entropy_encoder_model_kernel_3<alphabet_size,entropy_encoder,cc3,cc4b>
                    kernel_3c;
        typedef     entropy_encoder_model_kernel_c<kernel_3c>
                    kernel_3c_c;

        // --------------------

        // kernel_4
        typedef     entropy_encoder_model_kernel_4<alphabet_size,entropy_encoder,200000,4>
                    kernel_4a;
        typedef     entropy_encoder_model_kernel_c<kernel_4a>
                    kernel_4a_c;

        typedef     entropy_encoder_model_kernel_4<alphabet_size,entropy_encoder,1000000,5>
                    kernel_4b;
        typedef     entropy_encoder_model_kernel_c<kernel_4b>
                    kernel_4b_c;

        // --------------------

        // kernel_5
        typedef     entropy_encoder_model_kernel_5<alphabet_size,entropy_encoder,200000,4>
                    kernel_5a;
        typedef     entropy_encoder_model_kernel_c<kernel_5a>
                    kernel_5a_c;

        typedef     entropy_encoder_model_kernel_5<alphabet_size,entropy_encoder,1000000,5>
                    kernel_5b;
        typedef     entropy_encoder_model_kernel_c<kernel_5b>
                    kernel_5b_c;

        typedef     entropy_encoder_model_kernel_5<alphabet_size,entropy_encoder,2500000,7>
                    kernel_5c;
        typedef     entropy_encoder_model_kernel_c<kernel_5c>
                    kernel_5c_c;

        // --------------------

        // kernel_6
        typedef     entropy_encoder_model_kernel_6<alphabet_size,entropy_encoder>
                    kernel_6a;
        typedef     entropy_encoder_model_kernel_c<kernel_6a>
                    kernel_6a_c;

    };
}

#endif // DLIB_ENTROPY_ENCODER_MODEl_


dlib C++ Library - float_details.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_FLOAT_DEtAILS_Hh_
#define DLIB_FLOAT_DEtAILS_Hh_

#include <cmath>
#include "algs.h"
#include <limits>

namespace dlib
{
    struct float_details
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object is a tool for converting floating point numbers into an
                explicit integer representation and then also converting back.  In
                particular, a float_details object represents a floating point number with
                a 64 bit mantissa and 16 bit exponent.  These are stored in the public
                fields of the same names.

                The main use of this object is to convert floating point values into a
                known uniform representation so they can be serialized to an output stream.
                This allows dlib serialization code to work on any system, regardless of
                the floating point representation used by the hardware.  It also means
                that, for example, a double can be serialized and then deserialized into a
                float and it will perform the appropriate conversion.

                In more detail, this object represents a floating point value equal to
                mantissa*pow(2,exponent), except when exponent takes on any of the
                following special values:
                    - is_inf
                    - is_ninf
                    - is_nan
                These values are used to indicate that the floating point value should be
                either infinity, negative infinity, or not-a-number respectively.
        !*/

        float_details(
            int64 man,
            int16 exp
        ) : mantissa(man), exponent(exp) {}
        /*!
            ensures
                - #mantissa == man
                - #exponent == exp
        !*/

        float_details() :
            mantissa(0), exponent(0)
        {}
        /*!
            ensures
                - this object represents a floating point value of 0
        !*/

        float_details ( const double&      val) { *this = val; }
        float_details ( const float&       val) { *this = val; }
        float_details ( const long double& val) { *this = val; }
        /*!
            ensures
                - converts the given value into a float_details representation.  This
                  means that converting #*this back into a floating point number should
                  recover the input val.
        !*/

        float_details& operator= ( const double&      val) { convert_from_T(val); return *this; }
        float_details& operator= ( const float&       val) { convert_from_T(val); return *this; }
        float_details& operator= ( const long double& val) { convert_from_T(val); return *this; }
        /*!
            ensures
                - converts the given value into a float_details representation.  This
                  means that converting #*this back into a floating point number should
                  recover the input val.
        !*/

        operator double      () const { return convert_to_T<double>(); }
        operator float       () const { return convert_to_T<float>(); }
        operator long double () const { return convert_to_T<long double>(); }
        /*!
            ensures
                - converts the contents of this float_details object into a floating point number.
        !*/

        const static int16 is_inf  = 32000;
        const static int16 is_ninf = 32001;
        const static int16 is_nan  = 32002;

        int64 mantissa;
        int16 exponent;

    private:

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                                  IMPLEMENTATION DETAILS
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

        template <typename T>
        void convert_from_T (
            const T& val
        )
        {
            mantissa = 0;

            const int digits = dlib::tmin<std::numeric_limits<T>::digits, 63>::value;

            if (val == std::numeric_limits<T>::infinity())
            {
                exponent = is_inf;
            }
            else if (val == -std::numeric_limits<T>::infinity())
            {
                exponent = is_ninf;
            }
            else if (val < std::numeric_limits<T>::infinity())
            {
                int exp;
                mantissa = static_cast<int64>(std::frexp(val, &exp)*(((uint64)1)<<digits));
                exponent = exp - digits;

                // Compact the representation a bit by shifting off any low order bytes
                // which are zero in the mantissa.  This makes the numbers in mantissa and
                // exponent generally smaller which can make serialization and other things
                // more efficient in some cases.
                for (int i = 0; i < 8 && ((mantissa&0xFF)==0); ++i)
                {
                    mantissa >>= 8;
                    exponent += 8;
                }
            }
            else
            {
                exponent = is_nan;
            }
        }

        template <typename T>
        T convert_to_T (
        ) const
        {
            if (exponent < is_inf)
                return std::ldexp((T)mantissa, exponent);
            else if (exponent == is_inf)
                return std::numeric_limits<T>::infinity();
            else if (exponent == is_ninf)
                return -std::numeric_limits<T>::infinity();
            else
                return std::numeric_limits<T>::quiet_NaN();
        }

    };

}

#endif // DLIB_FLOAT_DEtAILS_Hh_


dlib C++ Library - geometry.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_GEOMETRy_HEADER
#define DLIB_GEOMETRy_HEADER

#include "geometry/rectangle.h"
#include "geometry/drectangle.h"
#include "geometry/vector.h"
#include "geometry/border_enumerator.h"
#include "geometry/point_transforms.h"

#endif // DLIB_GEOMETRy_HEADER


dlib C++ Library - graph_utils.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_GRAPH_UTILs_H_
#define DLIB_GRAPH_UTILs_H_

#include "graph_utils/graph_utils.h"
#include "graph_utils/edge_list_graphs.h"
#include "graph_utils/function_objects.h"

#endif // DLIB_GRAPH_UTILs_H_


dlib C++ Library - gui_core.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_GUI_CORe_
#define DLIB_GUI_CORe_

#include "platform.h"

#ifdef WIN32
#include "gui_core/windows.h"
#else
#include "gui_core/xlib.h"
#endif

#endif // DLIB_GUI_CORe_


dlib C++ Library - gui_widgets.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_GUI_WIDGETs_
#define DLIB_GUI_WIDGETs_

#include "gui_widgets/widgets.h"

#endif // DLIB_GUI_WIDGETs_


dlib C++ Library - hash.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_HASh_
#define DLIB_HASh_

#include "general_hash/hash.h"
#include "general_hash/random_hashing.h"
#include "general_hash/count_bits.h"

#endif // DLIB_HASh_


dlib C++ Library - image_keypoint.h

// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_IMAGE_KEYPOINt_H_
#define DLIB_IMAGE_KEYPOINt_H_

#include "image_keypoint/surf.h"
#include "image_keypoint/hessian_pyramid.h"
#include "image_keypoint/hog.h"
#include "image_keypoint/poly_image.h"
#include "image_keypoint/fine_hog_image.h"
#include "image_keypoint/hashed_feature_image.h"
#include "image_keypoint/nearest_neighbor_feature_image.h"
#include "image_keypoint/binned_vector_feature_image.h"

#endif // DLIB_IMAGE_KEYPOINt_H_


dlib C++ Library - image_processing.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_IMAGE_PROCESSInG_H_h_
#define DLIB_IMAGE_PROCESSInG_H_h_

#include "image_processing/scan_image.h"
#include "image_processing/scan_image_pyramid.h"
#include "image_processing/detection_template_tools.h"
#include "image_processing/object_detector.h"
#include "image_processing/box_overlap_testing.h"
#include "image_processing/scan_image_pyramid_tools.h"
#include "image_processing/setup_hashed_features.h"
#include "image_processing/scan_image_boxes.h"
#include "image_processing/scan_image_custom.h"
#include "image_processing/remove_unobtainable_rectangles.h"
#include "image_processing/scan_fhog_pyramid.h"
#include "image_processing/shape_predictor.h"
#include "image_processing/correlation_tracker.h"

#endif // DLIB_IMAGE_PROCESSInG_H_h_


dlib C++ Library - image_transforms.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_IMAGE_TRANSFORMs_
#define DLIB_IMAGE_TRANSFORMs_

#include "image_transforms/assign_image.h"
#include "image_transforms/equalize_histogram.h"
#include "image_transforms/morphological_operations.h"
#include "image_transforms/spatial_filtering.h"
#include "image_transforms/thresholding.h"
#include "image_transforms/edge_detector.h"
#include "image_transforms/draw.h"
#include "image_transforms/integral_image.h"
#include "image_transforms/image_pyramid.h"
#include "image_transforms/hough_transform.h"
#include "image_transforms/label_connected_blobs.h"
#include "image_transforms/colormaps.h"
#include "image_transforms/segment_image.h"
#include "image_transforms/interpolation.h"
#include "image_transforms/fhog.h"
#include "image_transforms/lbp.h"

#endif // DLIB_IMAGE_TRANSFORMs_


dlib C++ Library - logger.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_LOGGEr_
#define DLIB_LOGGEr_

#include "logger/logger_kernel_1.h"
#include "logger/extra_logger_headers.h"
#include "logger/logger_config_file.h"

#endif // DLIB_LOGGEr_


dlib C++ Library - lsh.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_LSh_
#define DLIB_LSh_

#include "lsh/projection_hash.h"
#include "lsh/create_random_projection_hash.h"
#include "lsh/hashes.h"

#endif // DLIB_LSh_


dlib C++ Library - lz77_buffer.h

// Copyright (C) 2004  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_LZ77_BUFFEr_
#define DLIB_LZ77_BUFFEr_

#include "lz77_buffer/lz77_buffer_kernel_1.h"
#include "lz77_buffer/lz77_buffer_kernel_2.h"
#include "lz77_buffer/lz77_buffer_kernel_c.h"

#include "sliding_buffer.h"

namespace dlib
{

    class lz77_buffer
    {

        lz77_buffer() {}

        typedef sliding_buffer<unsigned char>::kernel_1a sb1;

    public:

        //----------- kernels ---------------

        // kernel_1a
        typedef     lz77_buffer_kernel_1<sb1>
                    kernel_1a;
        typedef     lz77_buffer_kernel_c<kernel_1a>
                    kernel_1a_c;

        // kernel_2a
        typedef     lz77_buffer_kernel_2<sb1>
                    kernel_2a;
        typedef     lz77_buffer_kernel_c<kernel_2a>
                    kernel_2a_c;

    };
}

#endif // DLIB_LZ77_BUFFEr_


dlib C++ Library - lzp_buffer.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_LZP_BUFFEr_
#define DLIB_LZP_BUFFEr_

#include "lzp_buffer/lzp_buffer_kernel_1.h"
#include "lzp_buffer/lzp_buffer_kernel_2.h"
#include "lzp_buffer/lzp_buffer_kernel_c.h"

#include "sliding_buffer.h"

namespace dlib
{

    class lzp_buffer
    {

        lzp_buffer() {}

        typedef sliding_buffer<unsigned char>::kernel_1a sb1;

    public:

        //----------- kernels ---------------

        // kernel_1a
        typedef     lzp_buffer_kernel_1<sb1>
                    kernel_1a;
        typedef     lzp_buffer_kernel_c<kernel_1a>
                    kernel_1a_c;

        // kernel_2a
        typedef     lzp_buffer_kernel_2<sb1>
                    kernel_2a;
        typedef     lzp_buffer_kernel_c<kernel_2a>
                    kernel_2a_c;

    };
}

#endif // DLIB_LZP_BUFFEr_


dlib C++ Library - map.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MAp_
#define DLIB_MAp_

#include "map/map_kernel_1.h"
#include "map/map_kernel_c.h"

#include "binary_search_tree.h"

#include "algs.h"
#include <functional>

namespace dlib
{

    template <
        typename domain,
        typename range,
        typename mem_manager = default_memory_manager,
        typename compare = std::less<domain>
        >
    class map
    {
        map() {}

        // a typedef for the binary search tree used by kernel_2
        typedef typename binary_search_tree<domain,range,mem_manager,compare>::kernel_1a
                binary_search_tree_1;

        // a typedef for the binary search tree used by kernel_2
        typedef typename binary_search_tree<domain,range,mem_manager,compare>::kernel_2a
                binary_search_tree_2;

    public:

        //----------- kernels ---------------

        // kernel_1a
        typedef     map_kernel_1<domain,range,binary_search_tree_1,mem_manager>
                    kernel_1a;
        typedef     map_kernel_c<kernel_1a >
                    kernel_1a_c;

        // kernel_1b
        typedef     map_kernel_1<domain,range,binary_search_tree_2,mem_manager>
                    kernel_1b;
        typedef     map_kernel_c<kernel_1b >
                    kernel_1b_c;

    };
}

#endif // DLIB_MAp_


dlib C++ Library - matrix.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MATRIx_HEADER
#define DLIB_MATRIx_HEADER

#include "matrix/matrix.h"
#include "matrix/matrix_utilities.h"
#include "matrix/matrix_subexp.h"
#include "matrix/matrix_math_functions.h"
#include "matrix/matrix_assign.h"
#include "matrix/matrix_la.h"
#include "matrix/symmetric_matrix_cache.h"
#include "matrix/matrix_conv.h"
#include "matrix/matrix_read_from_istream.h"
#include "matrix/matrix_fft.h"
#include "matrix/matrix_generic_image.h"

#ifdef DLIB_USE_BLAS
#include "matrix/matrix_blas_bindings.h"
#endif

#endif // DLIB_MATRIx_HEADER


dlib C++ Library - member_function_pointer.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MEMBER_FUNCTION_POINTEr_
#define DLIB_MEMBER_FUNCTION_POINTEr_

#include "member_function_pointer/member_function_pointer_kernel_1.h"
#include "member_function_pointer/make_mfp.h"

#endif // DLIB_MEMBER_FUNCTION_POINTEr_


dlib C++ Library - memory_manager.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MEMORY_MANAGEr_
#define DLIB_MEMORY_MANAGEr_

#include "memory_manager/memory_manager_kernel_1.h"
#include "memory_manager/memory_manager_kernel_2.h"
#include "memory_manager/memory_manager_kernel_3.h"

namespace dlib
{

    template <
        typename T
        >
    class memory_manager
    {
        memory_manager() {}

    public:

        //----------- kernels ---------------

        // kernel_1
        typedef      memory_manager_kernel_1<T,0>
                     kernel_1a;
        typedef      memory_manager_kernel_1<T,10>
                     kernel_1b;
        typedef      memory_manager_kernel_1<T,100>
                     kernel_1c;
        typedef      memory_manager_kernel_1<T,1000>
                     kernel_1d;
        typedef      memory_manager_kernel_1<T,10000>
                     kernel_1e;
        typedef      memory_manager_kernel_1<T,100000>
                     kernel_1f;

        // kernel_2
        typedef      memory_manager_kernel_2<T,10>
                     kernel_2a;
        typedef      memory_manager_kernel_2<T,100>
                     kernel_2b;
        typedef      memory_manager_kernel_2<T,1000>
                     kernel_2c;
        typedef      memory_manager_kernel_2<T,10000>
                     kernel_2d;
        typedef      memory_manager_kernel_2<T,100000>
                     kernel_2e;

        // kernel_3
        typedef      memory_manager_kernel_3<T,10>
                     kernel_3a;
        typedef      memory_manager_kernel_3<T,100>
                     kernel_3b;
        typedef      memory_manager_kernel_3<T,1000>
                     kernel_3c;
        typedef      memory_manager_kernel_3<T,10000>
                     kernel_3d;
        typedef      memory_manager_kernel_3<T,100000>
                     kernel_3e;

    };
}

#endif // DLIB_MEMORY_MANAGEr_


dlib C++ Library - misc_api.h

// Copyright (C) 2004  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.

#ifndef DLIB_MISC_APi_
#define DLIB_MISC_APi_

#include "platform.h"

#ifdef WIN32
#include "misc_api/windows.h"
#endif

#ifndef WIN32
#include "misc_api/posix.h"
#endif

#include "misc_api/misc_api_shared.h"

#endif // DLIB_MISC_APi_


dlib C++ Library - optimization.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_OPTIMIZATIOn_HEADER
#define DLIB_OPTIMIZATIOn_HEADER

#include "optimization/optimization.h"
#include "optimization/optimization_bobyqa.h"
#include "optimization/optimization_solve_qp_using_smo.h"
#include "optimization/optimization_solve_qp2_using_smo.h"
#include "optimization/optimization_solve_qp3_using_smo.h"
#include "optimization/optimization_oca.h"
#include "optimization/optimization_trust_region.h"
#include "optimization/optimization_least_squares.h"
#include "optimization/max_cost_assignment.h"
#include "optimization/max_sum_submatrix.h"
#include "optimization/find_max_factor_graph_nmplp.h"
#include "optimization/find_max_factor_graph_viterbi.h"
#include "optimization/find_max_parse_cky.h"

#endif // DLIB_OPTIMIZATIOn_HEADER


dlib C++ Library - queue.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_QUEUe_
#define DLIB_QUEUe_

#include "queue/queue_kernel_1.h"
#include "queue/queue_kernel_2.h"
#include "queue/queue_kernel_c.h"

#include "queue/queue_sort_1.h"

#include "algs.h"

namespace dlib
{

    template <
        typename T,
        typename mem_manager = default_memory_manager
        >
    class queue
    {
        queue() {}
    public:

        //----------- kernels ---------------

        // kernel_1a
        typedef     queue_kernel_1<T,mem_manager>
                    kernel_1a;
        typedef     queue_kernel_c<kernel_1a>
                    kernel_1a_c;

        // kernel_2a
        typedef     queue_kernel_2<T,20,mem_manager>
                    kernel_2a;
        typedef     queue_kernel_c<kernel_2a>
                    kernel_2a_c;

        // kernel_2b
        typedef     queue_kernel_2<T,100,mem_manager>
                    kernel_2b;
        typedef     queue_kernel_c<kernel_2b>
                    kernel_2b_c;

        //---------- extensions ------------

        // sort_1 extend kernel_1a
        typedef     queue_sort_1<kernel_1a>
                    sort_1a;
        typedef     queue_sort_1<kernel_1a_c>
                    sort_1a_c;

        // sort_1 extend kernel_2a
        typedef     queue_sort_1<kernel_2a>
                    sort_1b;
        typedef     queue_sort_1<kernel_2a_c>
                    sort_1b_c;

        // sort_1 extend kernel_2b
        typedef     queue_sort_1<kernel_2b>
                    sort_1c;
        typedef     queue_sort_1<kernel_2b_c>
                    sort_1c_c;

    };
}

#endif // DLIB_QUEUe_


dlib C++ Library - rand.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_RANd_
#define DLIB_RANd_

#include "rand/rand_kernel_1.h"

#endif // DLIB_RANd_


dlib C++ Library - revision.h

#ifndef DLIB_REVISION_H
// Version:  18.18
// Date:     Wed Oct 28 20:26:06 EDT 2015
// Mercurial Revision ID:  cea7cff961e1
#define DLIB_MAJOR_VERSION  18
#define DLIB_MINOR_VERSION  18
#define DLIB_PATCH_VERSION  0
#endif


dlib C++ Library - sequence.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SEQUENCe_
#define DLIB_SEQUENCe_

#include "sequence/sequence_kernel_1.h"
#include "sequence/sequence_kernel_2.h"
#include "sequence/sequence_kernel_c.h"

#include "sequence/sequence_compare_1.h"
#include "sequence/sequence_sort_1.h"
#include "sequence/sequence_sort_2.h"
#include "algs.h"

namespace dlib
{

    template <
        typename T,
        typename mem_manager = default_memory_manager
        >
    class sequence
    {

        sequence() {}
    public:

        //----------- kernels ---------------

        // kernel_1a
        typedef     sequence_kernel_1<T,mem_manager>
                    kernel_1a;
        typedef     sequence_kernel_c<kernel_1a>
                    kernel_1a_c;

        // kernel_2a
        typedef     sequence_kernel_2<T,mem_manager>
                    kernel_2a;
        typedef     sequence_kernel_c<kernel_2a>
                    kernel_2a_c;

        //---------- extensions ------------

        // compare_1 extend kernel_1a
        typedef     sequence_compare_1<kernel_1a >
                    compare_1a;
        typedef     sequence_compare_1<kernel_1a_c>
                    compare_1a_c;

        // compare_1 extend kernel_2a
        typedef     sequence_compare_1<kernel_2a >
                    compare_1b;
        typedef     sequence_compare_1<kernel_2a_c>
                    compare_1b_c;

        // sort_1 extend kernel_2a
        typedef     sequence_sort_1<kernel_2a>
                    sort_1a;
        typedef     sequence_sort_1<kernel_2a_c>
                    sort_1a_c;

        // sort_2 extend kernel_1a
        typedef     sequence_sort_2<kernel_1a>
                    sort_2a;
        typedef     sequence_sort_2<kernel_1a_c>
                    sort_2a_c;

    };
}

#endif // DLIB_SEQUENCe_


dlib C++ Library - set.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SEt_
#define DLIB_SEt_

#include "set/set_kernel_1.h"
#include "set/set_kernel_c.h"

#include "binary_search_tree.h"

#include "set/set_compare_1.h"

#include "algs.h"
#include <functional>

namespace dlib
{

    template <
        typename T,
        typename mem_manager = default_memory_manager,
        typename compare = std::less<T>
        >
    class set
    {
        set() {}

        typedef typename binary_search_tree<T,char,mem_manager,compare>::kernel_1a
                binary_search_tree_1;

        typedef typename binary_search_tree<T,char,mem_manager,compare>::kernel_2a
                binary_search_tree_2;

    public:

        //----------- kernels ---------------

        // kernel_1a
        typedef     set_kernel_1<T,binary_search_tree_1,mem_manager>
                    kernel_1a;
        typedef     set_kernel_c<kernel_1a>
                    kernel_1a_c;

        // kernel_1b
        typedef     set_kernel_1<T,binary_search_tree_2,mem_manager>
                    kernel_1b;
        typedef     set_kernel_c<kernel_1b>
                    kernel_1b_c;

        //---------- extensions ------------

        // compare extensions
        typedef     set_compare_1<kernel_1a>
                    compare_1a;
        typedef     set_compare_1<kernel_1a_c>
                    compare_1a_c;

        typedef     set_compare_1<kernel_1b>
                    compare_1b;
        typedef     set_compare_1<kernel_1b_c>
                    compare_1b_c;

    };
}

#endif // DLIB_SEt_


dlib C++ Library - set_utils.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SET_UTILs_H_
#define DLIB_SET_UTILs_H_

#include "set_utils/set_utils.h"

#endif // DLIB_SET_UTILs_H_


dlib C++ Library - simd.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SIMd_Hh_
#define DLIB_SIMd_Hh_

#include "simd/simd4f.h"
#include "simd/simd4i.h"
#include "simd/simd8f.h"
#include "simd/simd8i.h"

#endif // DLIB_SIMd_Hh_


dlib C++ Library - sliding_buffer.h

// Copyright (C) 2004  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SLIDING_BUFFEr_
#define DLIB_SLIDING_BUFFEr_

#include "sliding_buffer/sliding_buffer_kernel_1.h"
#include "sliding_buffer/sliding_buffer_kernel_c.h"
#include "sliding_buffer/circular_buffer.h"

namespace dlib
{

    template <
        typename T
        >
    class sliding_buffer
    {

        sliding_buffer() {}
    public:

        //----------- kernels ---------------

        // kernel_1a
        typedef     sliding_buffer_kernel_1<T>
                    kernel_1a;
        typedef     sliding_buffer_kernel_c<kernel_1a>
                    kernel_1a_c;

    };
}

#endif // DLIB_SLIDING_BUFFEr_


dlib C++ Library - smart_pointers.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SMART_POINTERs_H_
#define DLIB_SMART_POINTERs_H_

#include "smart_pointers/scoped_ptr.h"
#include "smart_pointers/shared_ptr.h"
#include "smart_pointers/weak_ptr.h"

#endif // DLIB_SMART_POINTERs_H_


dlib C++ Library - smart_pointers_thread_safe.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SMART_POINTERs_THREAD_SAFE_H_
#define DLIB_SMART_POINTERs_THREAD_SAFE_H_

#include "smart_pointers/shared_ptr_thread_safe.h"

#endif // DLIB_SMART_POINTERs_THREAD_SAFE_H_


dlib C++ Library - sockets.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SOCKETs_
#define DLIB_SOCKETs_

#include "platform.h"

#ifdef WIN32
#include "sockets/windows.h"
#endif

#ifndef WIN32
#include "sockets/posix.h"
#endif

#include "sockets/sockets_extensions.h"

#endif // DLIB_SOCKETs_


dlib C++ Library - sockstreambuf.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SOCKSTREAMBUf_H_h_
#define DLIB_SOCKSTREAMBUf_H_h_

#include "sockstreambuf/sockstreambuf.h"
#include "sockstreambuf/sockstreambuf_unbuffered.h"

#endif // DLIB_SOCKSTREAMBUf_H_h_


dlib C++ Library - sparse_vector.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SPaRSE_VECTOR_Hh_
#define DLIB_SPaRSE_VECTOR_Hh_

#include "svm/sparse_vector.h"

#endif // DLIB_SPaRSE_VECTOR_Hh_


dlib C++ Library - stack.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_STACk_
#define DLIB_STACk_

#include "stack/stack_kernel_1.h"
#include "stack/stack_kernel_c.h"
#include "algs.h"

namespace dlib
{

    template <
        typename T,
        typename mem_manager = default_memory_manager
        >
    class stack
    {
        stack() {}
    public:

        //----------- kernels ---------------

        // kernel_1a
        typedef     stack_kernel_1<T,mem_manager>
                    kernel_1a;
        typedef     stack_kernel_c<kernel_1a>
                    kernel_1a_c;

    };
}

#endif // DLIB_STACk_


dlib C++ Library - stack_trace.cpp

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_STACK_TRACE_CPp_
#define DLIB_STACK_TRACE_CPp_

#if defined(DLIB_ENABLE_STACK_TRACE) && !defined(NO_MAKEFILE)

#include <sstream>
#include <cstring>
#include "stack_trace.h"
#include "threads.h"
#include "stack.h"
#include "memory_manager.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    namespace
    {
        struct stack_tracer_data
        {
            stack_tracer_data(
            ) :  funct_name(0),
                 file_name(0),
                 line_number(0)
            {}
            const char* funct_name;
            const char* file_name;
            int line_number;
        };

        thread_specific_data<stack<stack_tracer_data,memory_manager<char>::kernel_2a>::kernel_1a>& get_dlib_stack_trace_stack()
        {
            static thread_specific_data<stack<stack_tracer_data,memory_manager<char>::kernel_2a>::kernel_1a> a;
            return a;
        }
    }

// ----------------------------------------------------------------------------------------

    stack_tracer::
    stack_tracer (
        const char* funct_name,
        const char* file_name,
        const int line_number
    )
    {
        stack_tracer_data data;
        data.funct_name = funct_name;
        data.file_name = file_name;
        data.line_number = line_number;

        // pop the info onto the function stack trace
        get_dlib_stack_trace_stack().data().push(data);
    }

// ----------------------------------------------------------------------------------------

    stack_tracer::
    ~stack_tracer()
    {
        stack_tracer_data temp;
        get_dlib_stack_trace_stack().data().pop(temp);
    }

// ----------------------------------------------------------------------------------------

    const std::string get_stack_trace()
    {
        std::ostringstream sout;
        get_dlib_stack_trace_stack().data().reset();
        while (get_dlib_stack_trace_stack().data().move_next())
        {
            stack_tracer_data data = get_dlib_stack_trace_stack().data().element();
            sout << data.file_name << ":" << data.line_number << "\n    " << data.funct_name << "\n";
        }
        return sout.str();
    }

// ----------------------------------------------------------------------------------------

}
#endif

#endif // DLIB_STACK_TRACE_CPp_


dlib C++ Library - statistics.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_STATISTICs_H_
#define DLIB_STATISTICs_H_

#include "statistics/statistics.h"
#include "statistics/dpca.h"
#include "statistics/random_subset_selector.h"
#include "statistics/image_feature_sampling.h"
#include "statistics/sammon.h"
#include "statistics/cca.h"
#include "statistics/average_precision.h"
#include "statistics/vector_normalizer_frobmetric.h"
#include "statistics/lda.h"

#endif // DLIB_STATISTICs_H_


dlib C++ Library - stl_checked.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_STL_CHECKEd_HEADER
#define DLIB_STL_CHECKEd_HEADER

#include "stl_checked/std_vector_c.h"

#endif // DLIB_STL_CHECKEd_HEADER


dlib C++ Library - string.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_STRINg_TOP_
#define DLIB_STRINg_TOP_

#include "string/string.h"

#endif // DLIB_STRINg_TOP_


dlib C++ Library - svm.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SVm_HEADER
#define DLIB_SVm_HEADER

#include "svm/svm_rank_trainer.h"
#include "svm/svm.h"
#include "svm/krls.h"
#include "svm/rls.h"
#include "svm/kcentroid.h"
#include "svm/kcentroid_overloads.h"
#include "svm/kkmeans.h"
#include "svm/feature_ranking.h"
#include "svm/rbf_network.h"
#include "svm/linearly_independent_subset_finder.h"
#include "svm/reduced.h"
#include "svm/rvm.h"
#include "svm/pegasos.h"
#include "svm/sparse_kernel.h"
#include "svm/null_trainer.h"
#include "svm/roc_trainer.h"
#include "svm/kernel_matrix.h"
#include "svm/empirical_kernel_map.h"
#include "svm/svm_c_linear_trainer.h"
#include "svm/svm_c_linear_dcd_trainer.h"
#include "svm/svm_c_ekm_trainer.h"
#include "svm/simplify_linear_decision_function.h"
#include "svm/krr_trainer.h"
#include "svm/sort_basis_vectors.h"
#include "svm/svm_c_trainer.h"
#include "svm/svm_one_class_trainer.h"
#include "svm/svr_trainer.h"

#include "svm/one_vs_one_decision_function.h"
#include "svm/multiclass_tools.h"
#include "svm/cross_validate_multiclass_trainer.h"
#include "svm/cross_validate_regression_trainer.h"
#include "svm/cross_validate_object_detection_trainer.h"
#include "svm/cross_validate_sequence_labeler.h"
#include "svm/cross_validate_sequence_segmenter.h"
#include "svm/cross_validate_assignment_trainer.h"

#include "svm/one_vs_all_decision_function.h"

#include "svm/structural_svm_problem.h"
#include "svm/sequence_labeler.h"
#include "svm/assignment_function.h"
#include "svm/track_association_function.h"
#include "svm/active_learning.h"
#include "svm/svr_linear_trainer.h"
#include "svm/sequence_segmenter.h"

#endif // DLIB_SVm_HEADER


dlib C++ Library - sync_extension.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SYNC_EXTENSIOn_
#define DLIB_SYNC_EXTENSIOn_

#include "sync_extension/sync_extension_kernel_1.h"

namespace dlib
{

    template <
        typename base
        >
    class sync_extension
    {
        sync_extension() {}
    public:

        //----------- kernels ---------------

        // kernel_1a
        typedef     sync_extension_kernel_1<base>
                    kernel_1a;

    };
}

#endif // DLIB_SYNC_EXTENSIOn_


dlib C++ Library - threads.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_THREADs_
#define DLIB_THREADs_

#include "threads/threads_kernel.h"

#include "threads/auto_mutex_extension.h"
#include "threads/auto_unlock_extension.h"
#include "threads/create_new_thread_extension.h"
#include "threads/multithreaded_object_extension.h"
#include "threads/rmutex_extension.h"
#include "threads/rsignaler_extension.h"
#include "threads/threaded_object_extension.h"
#include "threads/thread_specific_data_extension.h"
#include "threads/thread_function_extension.h"
#include "threads/thread_pool_extension.h"
#include "threads/read_write_mutex_extension.h"
#include "threads/parallel_for_extension.h"

#endif // DLIB_THREADs_


dlib C++ Library - timeout.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_TIMEOUt_
#define DLIB_TIMEOUt_

#include "timeout/timeout.h"

#endif // DLIB_TIMEOUt_


dlib C++ Library - timer.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_TIMEr_
#define DLIB_TIMEr_

#include "timer/timer.h"
#include "timer/timer_heavy.h"

#endif // DLIB_TIMEr_


dlib C++ Library - tokenizer.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_TOKENIZEr_
#define DLIB_TOKENIZEr_

#include "tokenizer/tokenizer_kernel_1.h"
#include "tokenizer/tokenizer_kernel_c.h"

namespace dlib
{

    class tokenizer
    {
        tokenizer() {}

    public:

        //----------- kernels ---------------

        // kernel_1a
        typedef     tokenizer_kernel_1
                    kernel_1a;
        typedef     tokenizer_kernel_c<kernel_1a>
                    kernel_1a_c;

    };
}

#endif // DLIB_TOKENIZEr_


dlib C++ Library - type_safe_union.h

// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_TYPE_SAFE_UNIOn_TOP_
#define DLIB_TYPE_SAFE_UNIOn_TOP_

#include "type_safe_union/type_safe_union_kernel.h"

#endif // DLIB_TYPE_SAFE_UNIOn_TOP_


dlib C++ Library - unicode.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_UNICODe_TOP_
#define DLIB_UNICODe_TOP_

#include "unicode/unicode.h"

#endif // DLIB_UNICODe_TOP_


dlib C++ Library - vectorstream.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_VECTORSTReAMh_
#define DLIB_VECTORSTReAMh_

#include "vectorstream/vectorstream.h"

#endif // DLIB_VECTORSTReAMh_


dlib C++ Library - windows_magic.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_WINDOWS_MAGIc_
#define DLIB_WINDOWS_MAGIc_

#include "platform.h"

#ifdef WIN32

// This file contains all the magical #defines you have to setup  before you
// include the windows header files.

#ifndef NOMINMAX
#define NOMINMAX // prevent windows from messing with std::min and std::max
#endif

// Prevent windows from #defining IN or OUT
#ifndef _NO_W32_PSEUDO_MODIFIERS
#define _NO_W32_PSEUDO_MODIFIERS
#endif

// now just for good measure undefine min and max if they are defined
#ifdef min
#undef min
#endif

#ifdef max
#undef max
#endif

#ifdef NO_MAKEFILE
// only define this if all the cpp files are going to be sucked into the headers
// because otherwise we don't need it since everything is isolated in the sockets
// cpp file and this declaration for _WINSOCKAPI_ appears there also.
#ifndef _WINSOCKAPI_
#define _WINSOCKAPI_   /* Prevent inclusion of winsock.h in windows.h */
#endif
#endif

// This is something stupid you have to do to make visual studio include the right
// stuff.  I don't really know what the deal is with this.
#if _WIN32_WINNT < 0x0500
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x0500
#endif

#endif // WIN32

#endif // DLIB_WINDOWS_MAGIc_


dlib C++ Library - xml_parser.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_XML_PARSEr_
#define DLIB_XML_PARSEr_

#include <string>

#include "xml_parser/xml_parser_kernel_interfaces.h"
#include "xml_parser/xml_parser_kernel_1.h"

#endif // DLIB_XML_PARSEr_


dlib C++ Library - source.cpp

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ALL_SOURCe_
#define DLIB_ALL_SOURCe_

// ISO C++ code
#include "../base64/base64_kernel_1.cpp"
#include "../bigint/bigint_kernel_1.cpp"
#include "../bigint/bigint_kernel_2.cpp"
#include "../bit_stream/bit_stream_kernel_1.cpp"
#include "../entropy_decoder/entropy_decoder_kernel_1.cpp"
#include "../entropy_decoder/entropy_decoder_kernel_2.cpp"
#include "../entropy_encoder/entropy_encoder_kernel_1.cpp"
#include "../entropy_encoder/entropy_encoder_kernel_2.cpp"
#include "../md5/md5_kernel_1.cpp"
#include "../tokenizer/tokenizer_kernel_1.cpp"
#include "../unicode/unicode.cpp"
#include "../data_io/image_dataset_metadata.cpp"

#ifndef DLIB_ISO_CPP_ONLY
// Code that depends on OS specific APIs

// include this first so that it can disable the older version
// of the winsock API when compiled in windows.
#include "../sockets/sockets_kernel_1.cpp"
#include "../bsp/bsp.cpp"

#include "../dir_nav/dir_nav_kernel_1.cpp"
#include "../dir_nav/dir_nav_kernel_2.cpp"
#include "../dir_nav/dir_nav_extensions.cpp"
#include "../linker/linker_kernel_1.cpp"
#include "../logger/extra_logger_headers.cpp"
#include "../logger/logger_kernel_1.cpp"
#include "../logger/logger_config_file.cpp"
#include "../misc_api/misc_api_kernel_1.cpp"
#include "../misc_api/misc_api_kernel_2.cpp"
#include "../sockets/sockets_extensions.cpp"
#include "../sockets/sockets_kernel_2.cpp"
#include "../sockstreambuf/sockstreambuf.cpp"
#include "../sockstreambuf/sockstreambuf_unbuffered.cpp"
#include "../server/server_kernel.cpp"
#include "../server/server_iostream.cpp"
#include "../server/server_http.cpp"
#include "../threads/multithreaded_object_extension.cpp"
#include "../threads/threaded_object_extension.cpp"
#include "../threads/threads_kernel_1.cpp"
#include "../threads/threads_kernel_2.cpp"
#include "../threads/threads_kernel_shared.cpp"
#include "../threads/thread_pool_extension.cpp"
#include "../timer/timer.cpp"
#include "../stack_trace.cpp"

#ifdef DLIB_PNG_SUPPORT
#include "../image_loader/png_loader.cpp"
#include "../image_saver/save_png.cpp"
#endif

#ifdef DLIB_JPEG_SUPPORT
#include "../image_loader/jpeg_loader.cpp"
#include "../image_saver/save_jpeg.cpp"
#endif

#ifndef DLIB_NO_GUI_SUPPORT
#include "../gui_widgets/fonts.cpp"
#include "../gui_widgets/widgets.cpp"
#include "../gui_widgets/drawable.cpp"
#include "../gui_widgets/canvas_drawing.cpp"
#include "../gui_widgets/style.cpp"
#include "../gui_widgets/base_widgets.cpp"
#include "../gui_core/gui_core_kernel_1.cpp"
#include "../gui_core/gui_core_kernel_2.cpp"
#endif // DLIB_NO_GUI_SUPPORT

#endif // DLIB_ISO_CPP_ONLY

#endif // DLIB_ALL_SOURCe_


dlib C++ Library - any.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_AnY_H_
#define DLIB_AnY_H_

#include "any_abstract.h"
#include "../smart_pointers.h"
#include <typeinfo>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class bad_any_cast : public std::bad_cast
    {
    public:
          virtual const char * what() const throw()
          {
              return "bad_any_cast";
          }
    };

// ----------------------------------------------------------------------------------------

    class any
    {

    public:

        any()
        {
        }

        any (
            const any& item
        )
        {
            if (item.data)
            {
                item.data->copy_to(data);
            }
        }

        template <typename T>
        any (
            const T& item
        )
        {
            typedef typename basic_type<T>::type U;
            data.reset(new derived<U>(item));
        }

        void clear (
        )
        {
            data.reset();
        }

        template <typename T>
        bool contains (
        ) const
        {
            typedef typename basic_type<T>::type U;
            return dynamic_cast<derived<U>*>(data.get()) != 0;
        }

        bool is_empty(
        ) const
        {
            return data.get() == 0;
        }

        template <typename T>
        T& cast_to(
        )
        {
            typedef typename basic_type<T>::type U;
            derived<U>* d = dynamic_cast<derived<U>*>(data.get());
            if (d == 0)
            {
                throw bad_any_cast();
            }

            return d->item;
        }

        template <typename T>
        const T& cast_to(
        ) const
        {
            typedef typename basic_type<T>::type U;
            derived<U>* d = dynamic_cast<derived<U>*>(data.get());
            if (d == 0)
            {
                throw bad_any_cast();
            }

            return d->item;
        }

        template <typename T>
        T& get(
        )
        {
            typedef typename basic_type<T>::type U;
            derived<U>* d = dynamic_cast<derived<U>*>(data.get());
            if (d == 0)
            {
                d = new derived<U>();
                data.reset(d);
            }

            return d->item;
        }

        any& operator= (
            const any& item
        )
        {
            any(item).swap(*this);
            return *this;
        }

        void swap (
            any& item
        )
        {
            data.swap(item.data);
        }

    private:

        struct base
        {
            virtual ~base() {}

            virtual void copy_to (
                scoped_ptr<base>& dest
            ) const = 0;
        };

        template <typename T>
        struct derived : public base
        {
            T item;
            derived() {}
            derived(const T& val) : item(val) {}

            virtual void copy_to (
                scoped_ptr<base>& dest
            ) const
            {
                dest.reset(new derived<T>(item));
            }
        };

        scoped_ptr<base> data;
    };

// ----------------------------------------------------------------------------------------

    inline void swap (
        any& a,
        any& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------

    template <typename T> T& any_cast(any& a) { return a.cast_to<T>(); }
    template <typename T> const T& any_cast(const any& a) { return a.cast_to<T>(); }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_AnY_H_


dlib C++ Library - any_decision_function.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_AnY_DECISION_FUNCTION_Hh_
#define DLIB_AnY_DECISION_FUNCTION_Hh_

#include "any.h"
#include "../smart_pointers.h"

#include "any_decision_function_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename sample_type_,
        typename result_type_ = double
        >
    class any_decision_function
    {

    public:

        typedef sample_type_ sample_type;
        typedef result_type_ result_type;
        typedef default_memory_manager mem_manager_type;

        any_decision_function()
        {
        }

        any_decision_function (
            const any_decision_function& item
        )
        {
            if (item.data)
            {
                item.data->copy_to(data);
            }
        }

        template <typename T>
        any_decision_function (
            const T& item
        )
        {
            typedef typename basic_type<T>::type U;
            data.reset(new derived<U>(item));
        }

        void clear (
        )
        {
            data.reset();
        }

        template <typename T>
        bool contains (
        ) const
        {
            typedef typename basic_type<T>::type U;
            return dynamic_cast<derived<U>*>(data.get()) != 0;
        }

        bool is_empty(
        ) const
        {
            return data.get() == 0;
        }

        result_type operator() (
            const sample_type& item
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(is_empty() == false,
                "\t result_type any_decision_function::operator()"
                << "\n\t You can't call operator() on an empty any_decision_function"
                << "\n\t this: " << this
                );

            return data->evaluate(item);
        }

        template <typename T>
        T& cast_to(
        )
        {
            typedef typename basic_type<T>::type U;
            derived<U>* d = dynamic_cast<derived<U>*>(data.get());
            if (d == 0)
            {
                throw bad_any_cast();
            }

            return d->item;
        }

        template <typename T>
        const T& cast_to(
        ) const
        {
            typedef typename basic_type<T>::type U;
            derived<U>* d = dynamic_cast<derived<U>*>(data.get());
            if (d == 0)
            {
                throw bad_any_cast();
            }

            return d->item;
        }

        template <typename T>
        T& get(
        )
        {
            typedef typename basic_type<T>::type U;
            derived<U>* d = dynamic_cast<derived<U>*>(data.get());
            if (d == 0)
            {
                d = new derived<U>();
                data.reset(d);
            }

            return d->item;
        }

        any_decision_function& operator= (
            const any_decision_function& item
        )
        {
            any_decision_function(item).swap(*this);
            return *this;
        }

        void swap (
            any_decision_function& item
        )
        {
            data.swap(item.data);
        }

    private:

        struct base
        {
            virtual ~base() {}

            virtual void copy_to (
                scoped_ptr<base>& dest
            ) const = 0;

            virtual result_type evaluate (
                const sample_type& samp
            ) const = 0;
        };

        template <typename T>
        struct derived : public base
        {
            T item;
            derived() {}
            derived(const T& val) : item(val) {}

            virtual void copy_to (
                scoped_ptr<base>& dest
            ) const
            {
                dest.reset(new derived<T>(item));
            }

            virtual result_type evaluate (
                const sample_type& samp
            ) const
            {
                return item(samp);
            }
        };

        scoped_ptr<base> data;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename sample_type,
        typename result_type
        >
    inline void swap (
        any_decision_function<sample_type, result_type>& a,
        any_decision_function<sample_type, result_type>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------

    template <typename T, typename U, typename V>
    T& any_cast(any_decision_function<U,V>& a) { return a.template cast_to<T>(); }

    template <typename T, typename U, typename V>
    const T& any_cast(const any_decision_function<U,V>& a) { return a.template cast_to<T>(); }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_AnY_DECISION_FUNCTION_Hh_


dlib C++ Library - any_function.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_AnY_FUNCTION_Hh_
#define DLIB_AnY_FUNCTION_Hh_

#include "any.h"
#include "../smart_pointers.h"

#include "any_function_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <typename T>
    struct sig_traits {};

    template <
        typename T
        >
    struct sig_traits<T ()>
    {
        typedef T result_type;
        typedef void arg1_type;
        typedef void arg2_type;
        typedef void arg3_type;
        typedef void arg4_type;
        typedef void arg5_type;
        typedef void arg6_type;
        typedef void arg7_type;
        typedef void arg8_type;
        typedef void arg9_type;
        typedef void arg10_type;

        const static unsigned long num_args = 0;
    };

    template <
        typename T,
        typename A1
        >
    struct sig_traits<T (A1)>
    {
        typedef T result_type;
        typedef A1 arg1_type;
        typedef void arg2_type;
        typedef void arg3_type;
        typedef void arg4_type;
        typedef void arg5_type;
        typedef void arg6_type;
        typedef void arg7_type;
        typedef void arg8_type;
        typedef void arg9_type;
        typedef void arg10_type;

        const static unsigned long num_args = 1;
    };

    template <
        typename T,
        typename A1, typename A2
        >
    struct sig_traits<T (A1,A2)>
    {
        typedef T result_type;
        typedef A1 arg1_type;
        typedef A2 arg2_type;
        typedef void arg3_type;
        typedef void arg4_type;
        typedef void arg5_type;
        typedef void arg6_type;
        typedef void arg7_type;
        typedef void arg8_type;
        typedef void arg9_type;
        typedef void arg10_type;

        const static unsigned long num_args = 2;
    };

    template <
        typename T,
        typename A1, typename A2, typename A3
        >
    struct sig_traits<T (A1,A2,A3)>
    {
        typedef T result_type;
        typedef A1 arg1_type;
        typedef A2 arg2_type;
        typedef A3 arg3_type;
        typedef void arg4_type;
        typedef void arg5_type;
        typedef void arg6_type;
        typedef void arg7_type;
        typedef void arg8_type;
        typedef void arg9_type;
        typedef void arg10_type;

        const static unsigned long num_args = 3;
    };

    template <
        typename T,
        typename A1, typename A2, typename A3,
        typename A4
        >
    struct sig_traits<T (A1,A2,A3,A4)>
    {
        typedef T result_type;
        typedef A1 arg1_type;
        typedef A2 arg2_type;
        typedef A3 arg3_type;
        typedef A4 arg4_type;
        typedef void arg5_type;
        typedef void arg6_type;
        typedef void arg7_type;
        typedef void arg8_type;
        typedef void arg9_type;
        typedef void arg10_type;

        const static unsigned long num_args = 4;
    };

    template <
        typename T,
        typename A1, typename A2, typename A3,
        typename A4, typename A5
        >
    struct sig_traits<T (A1,A2,A3,A4,A5)>
    {
        typedef T result_type;
        typedef A1 arg1_type;
        typedef A2 arg2_type;
        typedef A3 arg3_type;
        typedef A4 arg4_type;
        typedef A5 arg5_type;
        typedef void arg6_type;
        typedef void arg7_type;
        typedef void arg8_type;
        typedef void arg9_type;
        typedef void arg10_type;

        const static unsigned long num_args = 5;
    };

    template <
        typename T,
        typename A1, typename A2, typename A3,
        typename A4, typename A5, typename A6
        >
    struct sig_traits<T (A1,A2,A3,A4,A5,A6)>
    {
        typedef T result_type;
        typedef A1 arg1_type;
        typedef A2 arg2_type;
        typedef A3 arg3_type;
        typedef A4 arg4_type;
        typedef A5 arg5_type;
        typedef A6 arg6_type;
        typedef void arg7_type;
        typedef void arg8_type;
        typedef void arg9_type;
        typedef void arg10_type;

        const static unsigned long num_args = 6;
    };

    template <
        typename T,
        typename A1, typename A2, typename A3,
        typename A4, typename A5, typename A6,
        typename A7
        >
    struct sig_traits<T (A1,A2,A3,A4,A5,A6,A7)>
    {
        typedef T result_type;
        typedef A1 arg1_type;
        typedef A2 arg2_type;
        typedef A3 arg3_type;
        typedef A4 arg4_type;
        typedef A5 arg5_type;
        typedef A6 arg6_type;
        typedef A7 arg7_type;
        typedef void arg8_type;
        typedef void arg9_type;
        typedef void arg10_type;

        const static unsigned long num_args = 7;
    };

    template <
        typename T,
        typename A1, typename A2, typename A3,
        typename A4, typename A5, typename A6,
        typename A7, typename A8
        >
    struct sig_traits<T (A1,A2,A3,A4,A5,A6,A7,A8)>
    {
        typedef T result_type;
        typedef A1 arg1_type;
        typedef A2 arg2_type;
        typedef A3 arg3_type;
        typedef A4 arg4_type;
        typedef A5 arg5_type;
        typedef A6 arg6_type;
        typedef A7 arg7_type;
        typedef A8 arg8_type;
        typedef void arg9_type;
        typedef void arg10_type;

        const static unsigned long num_args = 8;
    };

    template <
        typename T,
        typename A1, typename A2, typename A3,
        typename A4, typename A5, typename A6,
        typename A7, typename A8, typename A9
        >
    struct sig_traits<T (A1,A2,A3,A4,A5,A6,A7,A8,A9)>
    {
        typedef T result_type;
        typedef A1 arg1_type;
        typedef A2 arg2_type;
        typedef A3 arg3_type;
        typedef A4 arg4_type;
        typedef A5 arg5_type;
        typedef A6 arg6_type;
        typedef A7 arg7_type;
        typedef A8 arg8_type;
        typedef A9 arg9_type;
        typedef void arg10_type;

        const static unsigned long num_args = 9;
    };

    template <
        typename T,
        typename A1, typename A2, typename A3,
        typename A4, typename A5, typename A6,
        typename A7, typename A8, typename A9,
        typename A10
        >
    struct sig_traits<T (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10)>
    {
        typedef T result_type;
        typedef A1 arg1_type;
        typedef A2 arg2_type;
        typedef A3 arg3_type;
        typedef A4 arg4_type;
        typedef A5 arg5_type;
        typedef A6 arg6_type;
        typedef A7 arg7_type;
        typedef A8 arg8_type;
        typedef A9 arg9_type;
        typedef A10 arg10_type;

        const static unsigned long num_args = 10;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename function_type,
        // These arguments are used to control the overloading.  A user should
        // not mess with them.
        typename Enabled = void,
        unsigned long Num_args = sig_traits<function_type>::num_args
        >
    class any_function
    {
    private:
        any_function() {}
    /* !!!!!!!!    ERRORS ON THE ABOVE LINE    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        An error on this line means you are trying to use a function signature
        with more than the supported number of arguments.  The current version
        of dlib only supports up to 10 arguments.
    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
    };

    // The following preprocessor commands build the various overloaded versions
    // of any_function for different numbers of commands and void vs. non-void return
    // types.

//  0 arguments
#define DLIB_ANY_FUNCTION_ARG_LIST
#define DLIB_ANY_FUNCTION_ARGS
#define DLIB_ANY_FUNCTION_NUM_ARGS 0
#include "any_function_impl2.h"

//  1 argument
#define DLIB_ANY_FUNCTION_ARG_LIST arg1_type a1
#define DLIB_ANY_FUNCTION_ARGS a1
#define DLIB_ANY_FUNCTION_NUM_ARGS 1
#include "any_function_impl2.h"

//  2 arguments
#define DLIB_ANY_FUNCTION_ARG_LIST arg1_type a1, arg2_type a2
#define DLIB_ANY_FUNCTION_ARGS a1,a2
#define DLIB_ANY_FUNCTION_NUM_ARGS 2
#include "any_function_impl2.h"

//  3 arguments
#define DLIB_ANY_FUNCTION_ARG_LIST arg1_type a1, arg2_type a2, arg3_type a3
#define DLIB_ANY_FUNCTION_ARGS a1,a2,a3
#define DLIB_ANY_FUNCTION_NUM_ARGS 3
#include "any_function_impl2.h"

//  4 arguments
#define DLIB_ANY_FUNCTION_ARG_LIST arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4
#define DLIB_ANY_FUNCTION_ARGS a1,a2,a3,a4
#define DLIB_ANY_FUNCTION_NUM_ARGS 4
#include "any_function_impl2.h"

//  5 arguments
#define DLIB_ANY_FUNCTION_ARG_LIST arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, \
                                   arg5_type a5
#define DLIB_ANY_FUNCTION_ARGS a1,a2,a3,a4,a5
#define DLIB_ANY_FUNCTION_NUM_ARGS 5
#include "any_function_impl2.h"

//  6 arguments
#define DLIB_ANY_FUNCTION_ARG_LIST arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, \
                                   arg5_type a5, arg6_type a6
#define DLIB_ANY_FUNCTION_ARGS a1,a2,a3,a4,a5,a6
#define DLIB_ANY_FUNCTION_NUM_ARGS 6
#include "any_function_impl2.h"

//  7 arguments
#define DLIB_ANY_FUNCTION_ARG_LIST arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, \
                                   arg5_type a5, arg6_type a6, arg7_type a7
#define DLIB_ANY_FUNCTION_ARGS a1,a2,a3,a4,a5,a6,a7
#define DLIB_ANY_FUNCTION_NUM_ARGS 7
#include "any_function_impl2.h"

//  8 arguments
#define DLIB_ANY_FUNCTION_ARG_LIST arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, \
                                   arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8
#define DLIB_ANY_FUNCTION_ARGS a1,a2,a3,a4,a5,a6,a7,a8
#define DLIB_ANY_FUNCTION_NUM_ARGS 8
#include "any_function_impl2.h"

//  9 arguments
#define DLIB_ANY_FUNCTION_ARG_LIST arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, \
                                   arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8, \
                                   arg9_type a9
#define DLIB_ANY_FUNCTION_ARGS a1,a2,a3,a4,a5,a6,a7,a8,a9
#define DLIB_ANY_FUNCTION_NUM_ARGS 9
#include "any_function_impl2.h"

//  10 arguments
#define DLIB_ANY_FUNCTION_ARG_LIST arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, \
                                   arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8, \
                                   arg9_type a9, arg10_type a10
#define DLIB_ANY_FUNCTION_ARGS a1,a2,a3,a4,a5,a6,a7,a8,a9,a10
#define DLIB_ANY_FUNCTION_NUM_ARGS 10
#include "any_function_impl2.h"

// ----------------------------------------------------------------------------------------

    template <typename function_type>
    inline void swap (
        any_function<function_type>& a,
        any_function<function_type>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------

    template <typename T, typename function_type>
    T& any_cast(any_function<function_type>& a) { return a.template cast_to<T>(); }

    template <typename T, typename function_type>
    const T& any_cast(const any_function<function_type>& a) { return a.template cast_to<T>(); }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_AnY_FUNCTION_Hh_


dlib C++ Library - any_function_impl2.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ANY_FUNCTION_ARG_LIST
#error "You aren't supposed to directly #include this file.  #include <dlib/any.h> instead."
#endif

#ifdef DLIB_ANY_FUNCTION_ARG_LIST

// The case where function_type has a non-void return type
    template <typename function_type, typename Enabled>
    class any_function<function_type, Enabled, DLIB_ANY_FUNCTION_NUM_ARGS>
    {
#define DLIB_ANY_FUNCTION_RETURN return
#include "any_function_impl.h"
#undef DLIB_ANY_FUNCTION_RETURN

    private:
        // You get a compiler error about this function being private if you try to assign
        // or copy between any_functions with different types.  You must only copy between
        // any_functions that represent functions with the same signature.
        template <typename T, typename U> any_function(const any_function<T,U>&);
    };

// The case where function_type has a void return type
    template <typename function_type>
    class any_function<function_type, typename sig_traits<function_type>::type, DLIB_ANY_FUNCTION_NUM_ARGS>
    {
#define DLIB_ANY_FUNCTION_RETURN
#include "any_function_impl.h"
#undef DLIB_ANY_FUNCTION_RETURN

    private:
        // You get a compiler error about this function being private if you try to assign
        // or copy between any_functions with different types.  You must only copy between
        // any_functions that represent functions with the same signature.
        template <typename T> any_function(const any_function<T>&);
    };

#undef DLIB_ANY_FUNCTION_ARG_LIST
#undef DLIB_ANY_FUNCTION_ARGS
#undef DLIB_ANY_FUNCTION_NUM_ARGS

#endif // DLIB_ANY_FUNCTION_ARG_LIST


dlib C++ Library - any_function_impl.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ANY_FUNCTION_RETURN
#error "You aren't supposed to directly #include this file.  #include <dlib/any.h> instead."
#endif

#ifdef _MSC_VER
// When using visual studio 2012, disable the warning "warning C4180: qualifier applied to function type has no meaning; ignored"
// that you get about some template expansions applying & to function types.
#pragma warning(disable : 4180)
#endif

#ifdef DLIB_ANY_FUNCTION_RETURN

// This file contains the body of the any_function class.  We use the
// preprocessor to generate many different versions.  There are
// versions which return a value and those which return void.  For
// each of these types there are versions with differing numbers
// of arguments.

public:
typedef typename sig_traits<function_type>::result_type result_type;
typedef typename sig_traits<function_type>::arg1_type arg1_type;
typedef typename sig_traits<function_type>::arg2_type arg2_type;
typedef typename sig_traits<function_type>::arg3_type arg3_type;
typedef typename sig_traits<function_type>::arg4_type arg4_type;
typedef typename sig_traits<function_type>::arg5_type arg5_type;
typedef typename sig_traits<function_type>::arg6_type arg6_type;
typedef typename sig_traits<function_type>::arg7_type arg7_type;
typedef typename sig_traits<function_type>::arg8_type arg8_type;
typedef typename sig_traits<function_type>::arg9_type arg9_type;
typedef typename sig_traits<function_type>::arg10_type arg10_type;
const static unsigned long num_args = sig_traits<function_type>::num_args;

any_function()
{
}

any_function (
    const any_function& item
)
{
    if (item.data)
    {
        item.data->copy_to(data);
    }
}

template <typename T>
any_function (
    const T& item
)
{
    typedef typename basic_type<T>::type U;
    data.reset(new derived<U,function_type>(item));
}

void clear (
)
{
    data.reset();
}

template <typename T>
bool contains (
) const
{
    typedef typename basic_type<T>::type U;
    return dynamic_cast<derived<U,function_type>*>(data.get()) != 0;
}

bool is_empty(
) const
{
    return data.get() == 0;
}

bool is_set(
) const
{
    return !is_empty();
}

template <typename T>
T& cast_to(
)
{
    typedef typename basic_type<T>::type U;
    derived<U,function_type>* d = dynamic_cast<derived<U,function_type>*>(data.get());
    if (d == 0)
    {
        throw bad_any_cast();
    }

    return d->item;
}

template <typename T>
const T& cast_to(
) const
{
    typedef typename basic_type<T>::type U;
    derived<U,function_type>* d = dynamic_cast<derived<U,function_type>*>(data.get());
    if (d == 0)
    {
        throw bad_any_cast();
    }

    return d->item;
}

template <typename T>
T& get(
)
{
    typedef typename basic_type<T>::type U;
    derived<U,function_type>* d = dynamic_cast<derived<U,function_type>*>(data.get());
    if (d == 0)
    {
        d = new derived<U,function_type>();
        data.reset(d);
    }

    return d->item;
}

any_function& operator= (
    const any_function& item
)
{
    any_function(item).swap(*this);
    return *this;
}

void swap (
    any_function& item
)
{
    data.swap(item.data);
}

result_type operator()(DLIB_ANY_FUNCTION_ARG_LIST) const
{ validate(); DLIB_ANY_FUNCTION_RETURN data->evaluate(DLIB_ANY_FUNCTION_ARGS); }
/* !!!!!!!!    ERRORS ON THE ABOVE LINE    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    If you are getting an error on the above line then it means you
    have attempted to call a dlib::any_function but you have supplied
    arguments which don't match the function signature used by the
    dlib::any_function.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/

private:

void validate () const
{
    // make sure requires clause is not broken
    DLIB_ASSERT(is_empty() == false,
        "\t result_type any_function::operator()"
        << "\n\t You can't call operator() on an empty any_function"
        << "\n\t this: " << this
        );
}

template <typename FT>
struct Tbase
{
    virtual ~Tbase() {}
    virtual result_type evaluate () const = 0;
    virtual void copy_to ( scoped_ptr<Tbase>& dest) const = 0;
};

template <
    typename T,
    typename A1
    >
struct Tbase<T (A1)>
{
    virtual ~Tbase() {}
    virtual T evaluate ( A1) const = 0;
    virtual void copy_to ( scoped_ptr<Tbase>& dest) const = 0;
};

template <
    typename T,
    typename A1, typename A2
    >
struct Tbase<T (A1,A2)>
{
    virtual ~Tbase() {}
    virtual T evaluate (A1,A2) const = 0;
    virtual void copy_to ( scoped_ptr<Tbase>& dest) const = 0;
};

template <
    typename T,
    typename A1, typename A2, typename A3
    >
struct Tbase<T (A1,A2,A3)>
{
    virtual ~Tbase() {}
    virtual T evaluate (A1,A2,A3) const = 0;
    virtual void copy_to ( scoped_ptr<Tbase>& dest) const = 0;
};

template <
    typename T,
    typename A1, typename A2, typename A3,
    typename A4
    >
struct Tbase<T (A1,A2,A3,A4)>
{
    virtual ~Tbase() {}
    virtual T evaluate (A1,A2,A3,A4) const = 0;
    virtual void copy_to ( scoped_ptr<Tbase>& dest) const = 0;
};

template <
    typename T,
    typename A1, typename A2, typename A3,
    typename A4, typename A5
    >
struct Tbase<T (A1,A2,A3,A4,A5)>
{
    virtual ~Tbase() {}
    virtual T evaluate (A1,A2,A3,A4,A5) const = 0;
    virtual void copy_to ( scoped_ptr<Tbase>& dest) const = 0;
};

template <
    typename T,
    typename A1, typename A2, typename A3,
    typename A4, typename A5, typename A6
    >
struct Tbase<T (A1,A2,A3,A4,A5,A6)>
{
    virtual ~Tbase() {}
    virtual T evaluate (A1,A2,A3,A4,A5,A6) const = 0;
    virtual void copy_to ( scoped_ptr<Tbase>& dest) const = 0;
};

template <
    typename T,
    typename A1, typename A2, typename A3,
    typename A4, typename A5, typename A6,
    typename A7
    >
struct Tbase<T (A1,A2,A3,A4,A5,A6,A7)>
{
    virtual ~Tbase() {}
    virtual T evaluate (A1,A2,A3,A4,A5,A6,A7) const = 0;
    virtual void copy_to ( scoped_ptr<Tbase>& dest) const = 0;
};

template <
    typename T,
    typename A1, typename A2, typename A3,
    typename A4, typename A5, typename A6,
    typename A7, typename A8
    >
struct Tbase<T (A1,A2,A3,A4,A5,A6,A7,A8)>
{
    virtual ~Tbase() {}
    virtual T evaluate (A1,A2,A3,A4,A5,A6,A7,A8) const = 0;
    virtual void copy_to ( scoped_ptr<Tbase>& dest) const = 0;
};

template <
    typename T,
    typename A1, typename A2, typename A3,
    typename A4, typename A5, typename A6,
    typename A7, typename A8, typename A9
    >
struct Tbase<T (A1,A2,A3,A4,A5,A6,A7,A8,A9)>
{
    virtual ~Tbase() {}
    virtual T evaluate (A1,A2,A3,A4,A5,A6,A7,A8,A9) const = 0;
    virtual void copy_to ( scoped_ptr<Tbase>& dest) const = 0;
};

template <
    typename T,
    typename A1, typename A2, typename A3,
    typename A4, typename A5, typename A6,
    typename A7, typename A8, typename A9,
    typename A10
    >
struct Tbase<T (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10)>
{
    virtual ~Tbase() {}
    virtual T evaluate (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10) const = 0;
    virtual void copy_to ( scoped_ptr<Tbase>& dest) const = 0;
};

typedef Tbase<function_type> base;

// -----------------------------------------------

// Some templates to help deal with the weirdness of storing C function types (rather than pointer to functions).
// Basically, we make sure things always get turned into function pointers even if the user gives a function reference.
template <typename T, typename enabled = void>
struct funct_type { typedef T type; };
template <typename T>
struct funct_type<T, typename enable_if<is_function<T> >::type> { typedef T* type; };

template <typename T>
static typename enable_if<is_function<T>,const T*>::type copy (const T& item) { return &item; }
template <typename T>
static typename disable_if<is_function<T>,const T&>::type copy (const T& item) { return item; }

template <typename T, typename U>
static typename enable_if<is_function<T>,const T&>::type deref (const U& item) { return *item; }
template <typename T, typename U>
static typename disable_if<is_function<T>,const T&>::type deref (const U& item) { return item; }

// -----------------------------------------------

#define DLIB_ANY_FUNCTION_DERIVED_BOILERPLATE               \
    typename funct_type<T>::type item;                      \
    derived() {}                                            \
    derived(const T& val) : item(copy(val)) {}              \
    virtual void copy_to ( scoped_ptr<base>& dest) const    \
    { dest.reset(new derived(deref<T>(item))); }

template <typename T, typename FT>
struct derived : public base
{
    DLIB_ANY_FUNCTION_DERIVED_BOILERPLATE

    virtual result_type evaluate (
    ) const { DLIB_ANY_FUNCTION_RETURN item(); }
    /* !!!!!!!!    ERRORS ON THE ABOVE LINE    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        If you are getting an error on the above line then it means you
        have attempted to assign a function or function object to a
        dlib::any_function but the signatures of the source and
        destination functions don't match.
    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
};

template <typename T, typename A1>
struct derived<T,result_type (A1)> : public base
{
    DLIB_ANY_FUNCTION_DERIVED_BOILERPLATE

    virtual result_type evaluate (
        A1 a1
    ) const { DLIB_ANY_FUNCTION_RETURN item(a1); }
    /* !!!!!!!!    ERRORS ON THE ABOVE LINE    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        If you are getting an error on the above line then it means you
        have attempted to assign a function or function object to a
        dlib::any_function but the signatures of the source and
        destination functions don't match.
    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
};

template <typename T, typename A1, typename A2>
struct derived<T,result_type (A1,A2)> : public base
{
    DLIB_ANY_FUNCTION_DERIVED_BOILERPLATE

    virtual result_type evaluate (
        A1 a1, A2 a2
    ) const { DLIB_ANY_FUNCTION_RETURN item(a1,a2); }
    /* !!!!!!!!    ERRORS ON THE ABOVE LINE    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        If you are getting an error on the above line then it means you
        have attempted to assign a function or function object to a
        dlib::any_function but the signatures of the source and
        destination functions don't match.
    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
};

template <typename T, typename A1, typename A2, typename A3>
struct derived<T,result_type (A1,A2,A3)> : public base
{
    DLIB_ANY_FUNCTION_DERIVED_BOILERPLATE

    virtual result_type evaluate (
        A1 a1, A2 a2, A3 a3
    ) const { DLIB_ANY_FUNCTION_RETURN item(a1,a2,a3); }
    /* !!!!!!!!    ERRORS ON THE ABOVE LINE    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        If you are getting an error on the above line then it means you
        have attempted to assign a function or function object to a
        dlib::any_function but the signatures of the source and
        destination functions don't match.
    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
};

template <typename T, typename A1, typename A2, typename A3,
                      typename A4>
struct derived<T,result_type (A1,A2,A3,A4)> : public base
{
    DLIB_ANY_FUNCTION_DERIVED_BOILERPLATE

    virtual result_type evaluate (
        A1 a1, A2 a2, A3 a3, A4 a4
    ) const { DLIB_ANY_FUNCTION_RETURN item(a1,a2,a3,a4); }
    /* !!!!!!!!    ERRORS ON THE ABOVE LINE    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        If you are getting an error on the above line then it means you
        have attempted to assign a function or function object to a
        dlib::any_function but the signatures of the source and
        destination functions don't match.
    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
};

template <typename T, typename A1, typename A2, typename A3,
                      typename A4, typename A5>
struct derived<T,result_type (A1,A2,A3,A4,A5)> : public base
{
    DLIB_ANY_FUNCTION_DERIVED_BOILERPLATE

    virtual result_type evaluate (
        A1 a1, A2 a2, A3 a3, A4 a4, A5 a5
    ) const { DLIB_ANY_FUNCTION_RETURN item(a1,a2,a3,a4,a5); }
    /* !!!!!!!!    ERRORS ON THE ABOVE LINE    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        If you are getting an error on the above line then it means you
        have attempted to assign a function or function object to a
        dlib::any_function but the signatures of the source and
        destination functions don't match.
    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
};

template <typename T, typename A1, typename A2, typename A3,
                      typename A4, typename A5, typename A6>
struct derived<T,result_type (A1,A2,A3,A4,A5,A6)> : public base
{
    DLIB_ANY_FUNCTION_DERIVED_BOILERPLATE

    virtual result_type evaluate (
        A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6
    ) const { DLIB_ANY_FUNCTION_RETURN item(a1,a2,a3,a4,a5,a6); }
    /* !!!!!!!!    ERRORS ON THE ABOVE LINE    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        If you are getting an error on the above line then it means you
        have attempted to assign a function or function object to a
        dlib::any_function but the signatures of the source and
        destination functions don't match.
    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
};

template <typename T, typename A1, typename A2, typename A3,
                      typename A4, typename A5, typename A6,
                      typename A7>
struct derived<T,result_type (A1,A2,A3,A4,A5,A6,A7)> : public base
{
    DLIB_ANY_FUNCTION_DERIVED_BOILERPLATE

    virtual result_type evaluate (
        A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7
    ) const { DLIB_ANY_FUNCTION_RETURN item(a1,a2,a3,a4,a5,a6,a7); }
    /* !!!!!!!!    ERRORS ON THE ABOVE LINE    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        If you are getting an error on the above line then it means you
        have attempted to assign a function or function object to a
        dlib::any_function but the signatures of the source and
        destination functions don't match.
    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
};

template <typename T, typename A1, typename A2, typename A3,
                      typename A4, typename A5, typename A6,
                      typename A7, typename A8>
struct derived<T,result_type (A1,A2,A3,A4,A5,A6,A7,A8)> : public base
{
    DLIB_ANY_FUNCTION_DERIVED_BOILERPLATE

    virtual result_type evaluate (
        A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8
    ) const { DLIB_ANY_FUNCTION_RETURN item(a1,a2,a3,a4,a5,a6,a7,a8); }
    /* !!!!!!!!    ERRORS ON THE ABOVE LINE    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        If you are getting an error on the above line then it means you
        have attempted to assign a function or function object to a
        dlib::any_function but the signatures of the source and
        destination functions don't match.
    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
};

template <typename T, typename A1, typename A2, typename A3,
                      typename A4, typename A5, typename A6,
                      typename A7, typename A8, typename A9>
struct derived<T,result_type (A1,A2,A3,A4,A5,A6,A7,A8,A9)> : public base
{
    DLIB_ANY_FUNCTION_DERIVED_BOILERPLATE

    virtual result_type evaluate (
        A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9
    ) const { DLIB_ANY_FUNCTION_RETURN item(a1,a2,a3,a4,a5,a6,a7,a8,a9); }
    /* !!!!!!!!    ERRORS ON THE ABOVE LINE    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        If you are getting an error on the above line then it means you
        have attempted to assign a function or function object to a
        dlib::any_function but the signatures of the source and
        destination functions don't match.
    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
};

template <typename T, typename A1, typename A2, typename A3,
                      typename A4, typename A5, typename A6,
                      typename A7, typename A8, typename A9,
                      typename A10>
struct derived<T,result_type (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10)> : public base
{
    DLIB_ANY_FUNCTION_DERIVED_BOILERPLATE

    virtual result_type evaluate (
        A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10
    ) const { DLIB_ANY_FUNCTION_RETURN item(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10); }
    /* !!!!!!!!    ERRORS ON THE ABOVE LINE    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        If you are getting an error on the above line then it means you
        have attempted to assign a function or function object to a
        dlib::any_function but the signatures of the source and
        destination functions don't match.
    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
};

scoped_ptr<base> data;

#undef DLIB_ANY_FUNCTION_DERIVED_BOILERPLATE

#endif // DLIB_ANY_FUNCTION_RETURN


dlib C++ Library - any_trainer.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_AnY_TRAINER_H_
#define DLIB_AnY_TRAINER_H_

#include "any.h"
#include "../smart_pointers.h"

#include "any_decision_function.h"

#include "any_trainer_abstract.h"
#include <vector>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename sample_type_,
        typename scalar_type_ = double
        >
    class any_trainer
    {
    public:
        typedef sample_type_ sample_type;
        typedef scalar_type_ scalar_type;
        typedef default_memory_manager mem_manager_type;
        typedef any_decision_function<sample_type, scalar_type> trained_function_type;

        any_trainer()
        {
        }

        any_trainer (
            const any_trainer& item
        )
        {
            if (item.data)
            {
                item.data->copy_to(data);
            }
        }

        template <typename T>
        any_trainer (
            const T& item
        )
        {
            typedef typename basic_type<T>::type U;
            data.reset(new derived<U>(item));
        }

        void clear (
        )
        {
            data.reset();
        }

        template <typename T>
        bool contains (
        ) const
        {
            typedef typename basic_type<T>::type U;
            return dynamic_cast<derived<U>*>(data.get()) != 0;
        }

        bool is_empty(
        ) const
        {
            return data.get() == 0;
        }

        trained_function_type train (
            const std::vector<sample_type>& samples,
            const std::vector<scalar_type>& labels
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(is_empty() == false,
                "\t trained_function_type any_trainer::train()"
                << "\n\t You can't call train() on an empty any_trainer"
                << "\n\t this: " << this
                );

            return data->train(samples, labels);
        }

        template <typename T>
        T& cast_to(
        )
        {
            typedef typename basic_type<T>::type U;
            derived<U>* d = dynamic_cast<derived<U>*>(data.get());
            if (d == 0)
            {
                throw bad_any_cast();
            }

            return d->item;
        }

        template <typename T>
        const T& cast_to(
        ) const
        {
            typedef typename basic_type<T>::type U;
            derived<U>* d = dynamic_cast<derived<U>*>(data.get());
            if (d == 0)
            {
                throw bad_any_cast();
            }

            return d->item;
        }

        template <typename T>
        T& get(
        )
        {
            typedef typename basic_type<T>::type U;
            derived<U>* d = dynamic_cast<derived<U>*>(data.get());
            if (d == 0)
            {
                d = new derived<U>();
                data.reset(d);
            }

            return d->item;
        }

        any_trainer& operator= (
            const any_trainer& item
        )
        {
            any_trainer(item).swap(*this);
            return *this;
        }

        void swap (
            any_trainer& item
        )
        {
            data.swap(item.data);
        }

    private:

        struct base
        {
            virtual ~base() {}

            virtual trained_function_type train (
                const std::vector<sample_type>& samples,
                const std::vector<scalar_type>& labels
            ) const = 0;

            virtual void copy_to (
                scoped_ptr<base>& dest
            ) const = 0;
        };

        template <typename T>
        struct derived : public base
        {
            T item;
            derived() {}
            derived(const T& val) : item(val) {}

            virtual void copy_to (
                scoped_ptr<base>& dest
            ) const
            {
                dest.reset(new derived<T>(item));
            }

            virtual trained_function_type train (
                const std::vector<sample_type>& samples,
                const std::vector<scalar_type>& labels
            ) const
            {
                return item.train(samples, labels);
            }
        };

        scoped_ptr<base> data;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename sample_type,
        typename scalar_type
        >
    inline void swap (
        any_trainer<sample_type,scalar_type>& a,
        any_trainer<sample_type,scalar_type>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------

    template <typename T, typename U, typename V>
    T& any_cast(any_trainer<U,V>& a) { return a.template cast_to<T>(); }

    template <typename T, typename U, typename V>
    const T& any_cast(const any_trainer<U,V>& a) { return a.template cast_to<T>(); }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_AnY_TRAINER_H_


dlib C++ Library - array_kernel.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ARRAY_KERNEl_2_
#define DLIB_ARRAY_KERNEl_2_

#include "array_kernel_abstract.h"
#include "../interfaces/enumerable.h"
#include "../algs.h"
#include "../serialize.h"
#include "../sort.h"
#include "../is_kind.h"

namespace dlib
{

    template <
        typename T,
        typename mem_manager = default_memory_manager
        >
    class array : public enumerable<T>
    {

        /*!
            INITIAL VALUE
                - array_size == 0
                - max_array_size == 0
                - array_elements == 0
                - pos == 0
                - last_pos == 0
                - _at_start == true

            CONVENTION
                - array_size == size()
                - max_array_size == max_size()
                - if (max_array_size > 0)
                    - array_elements == pointer to max_array_size elements of type T
                - else
                    - array_elements == 0

                - if (array_size > 0)
                    - last_pos == array_elements + array_size - 1
                - else
                    - last_pos == 0

                - at_start() == _at_start
                - current_element_valid() == pos != 0
                - if (current_element_valid()) then
                    - *pos == element()
        !*/

    public:

        // These typedefs are here for backwards compatibility with old versions of dlib.
        typedef array kernel_1a;
        typedef array kernel_1a_c;
        typedef array kernel_2a;
        typedef array kernel_2a_c;
        typedef array sort_1a;
        typedef array sort_1a_c;
        typedef array sort_1b;
        typedef array sort_1b_c;
        typedef array sort_2a;
        typedef array sort_2a_c;
        typedef array sort_2b;
        typedef array sort_2b_c;
        typedef array expand_1a;
        typedef array expand_1a_c;
        typedef array expand_1b;
        typedef array expand_1b_c;
        typedef array expand_1c;
        typedef array expand_1c_c;
        typedef array expand_1d;
        typedef array expand_1d_c;

        typedef T type;
        typedef T value_type;
        typedef mem_manager mem_manager_type;

        array (
        ) :
            array_size(0),
            max_array_size(0),
            array_elements(0),
            pos(0),
            last_pos(0),
            _at_start(true)
        {}

        explicit array (
            unsigned long new_size
        ) :
            array_size(0),
            max_array_size(0),
            array_elements(0),
            pos(0),
            last_pos(0),
            _at_start(true)
        {
            resize(new_size);
        }

        ~array (
        );

        void clear (
        );

        inline const T& operator[] (
            unsigned long pos
        ) const;

        inline T& operator[] (
            unsigned long pos
        );

        void set_size (
            unsigned long size
        );

        inline unsigned long max_size(
        ) const;

        void set_max_size(
            unsigned long max
        );

        void swap (
            array& item
        );

        // functions from the enumerable interface
        inline unsigned long size (
        ) const;

        inline bool at_start (
        ) const;

        inline void reset (
        ) const;

        bool current_element_valid (
        ) const;

        inline const T& element (
        ) const;

        inline T& element (
        );

        bool move_next (
        ) const;

        void sort (
        );

        void resize (
            unsigned long new_size
        );

        const T& back (
        ) const;

        T& back (
        );

        void pop_back (
        );

        void pop_back (
            T& item
        );

        void push_back (
            T& item
        );

        typedef T* iterator;
        typedef const T* const_iterator;
        iterator                begin()                         { return array_elements; }
        const_iterator          begin() const                   { return array_elements; }
        iterator                end()                           { return array_elements+array_size; }
        const_iterator          end() const                     { return array_elements+array_size; }

    private:

        typename mem_manager::template rebind<T>::other pool;

        // data members
        unsigned long array_size;
        unsigned long max_array_size;
        T* array_elements;

        mutable T* pos;
        T* last_pos;
        mutable bool _at_start;

        // restricted functions
        array(array<T>&);        // copy constructor
        array<T>& operator=(array<T>&);    // assignment operator

    };

    template <
        typename T,
        typename mem_manager
        >
    inline void swap (
        array<T,mem_manager>& a,
        array<T,mem_manager>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void serialize (
        const array<T,mem_manager>& item,
        std::ostream& out
    )
    {
        try
        {
            serialize(item.max_size(),out);
            serialize(item.size(),out);

            for (unsigned long i = 0; i < item.size(); ++i)
                serialize(item[i],out);
        }
        catch (serialization_error e)
        {
            throw serialization_error(e.info + "\n   while serializing object of type array");
        }
    }

    template <
        typename T,
        typename mem_manager
        >
    void deserialize (
        array<T,mem_manager>& item,
        std::istream& in
    )
    {
        try
        {
            unsigned long max_size, size;
            deserialize(max_size,in);
            deserialize(size,in);
            item.set_max_size(max_size);
            item.set_size(size);
            for (unsigned long i = 0; i < size; ++i)
                deserialize(item[i],in);
        }
        catch (serialization_error e)
        {
            item.clear();
            throw serialization_error(e.info + "\n   while deserializing object of type array");
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    array<T,mem_manager>::
    ~array (
    )
    {
        if (array_elements)
        {
            pool.deallocate_array(array_elements);
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void array<T,mem_manager>::
    clear (
    )
    {
        reset();
        last_pos = 0;
        array_size = 0;
        if (array_elements)
        {
            pool.deallocate_array(array_elements);
        }
        array_elements = 0;
        max_array_size = 0;

    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    const T& array<T,mem_manager>::
    operator[] (
        unsigned long pos
    ) const
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( pos < this->size() ,
            "\tconst T& array::operator[]"
            << "\n\tpos must < size()"
            << "\n\tpos: " << pos
            << "\n\tsize(): " << this->size()
            << "\n\tthis: " << this
            );

        return array_elements[pos];
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    T& array<T,mem_manager>::
    operator[] (
        unsigned long pos
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( pos < this->size() ,
            "\tT& array::operator[]"
            << "\n\tpos must be < size()"
            << "\n\tpos: " << pos
            << "\n\tsize(): " << this->size()
            << "\n\tthis: " << this
            );

        return array_elements[pos];
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void array<T,mem_manager>::
    set_size (
        unsigned long size
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(( size <= this->max_size() ),
            "\tvoid array::set_size"
            << "\n\tsize must be <= max_size()"
            << "\n\tsize: " << size
            << "\n\tmax size: " << this->max_size()
            << "\n\tthis: " << this
            );

        reset();
        array_size = size;
        if (size > 0)
            last_pos = array_elements + size - 1;
        else
            last_pos = 0;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    unsigned long array<T,mem_manager>::
    size (
    ) const
    {
        return array_size;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void array<T,mem_manager>::
    set_max_size(
        unsigned long max
    )
    {
        reset();
        array_size = 0;
        last_pos = 0;
        if (max != 0)
        {
            // if new max size is different
            if (max != max_array_size)
            {
                if (array_elements)
                {
                    pool.deallocate_array(array_elements);
                }
                // try to get more memroy
                try { array_elements = pool.allocate_array(max); }
                catch (...) { array_elements = 0;  max_array_size = 0; throw; }
                max_array_size = max;
            }

        }
        // if the array is being made to be zero
        else
        {
            if (array_elements)
                pool.deallocate_array(array_elements);
            max_array_size = 0;
            array_elements = 0;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    unsigned long array<T,mem_manager>::
    max_size (
    ) const
    {
        return max_array_size;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void array<T,mem_manager>::
    swap (
        array<T,mem_manager>& item
    )
    {
        unsigned long    array_size_temp        = item.array_size;
        unsigned long    max_array_size_temp    = item.max_array_size;
        T*               array_elements_temp    = item.array_elements;

        item.array_size         = array_size;
        item.max_array_size     = max_array_size;
        item.array_elements     = array_elements;

        array_size        = array_size_temp;
        max_array_size    = max_array_size_temp;
        array_elements    = array_elements_temp;

        exchange(_at_start,item._at_start);
        exchange(pos,item.pos);
        exchange(last_pos,item.last_pos);
        pool.swap(item.pool);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//           enumerable function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    bool array<T,mem_manager>::
    at_start (
    ) const
    {
        return _at_start;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void array<T,mem_manager>::
    reset (
    ) const
    {
        _at_start = true;
        pos = 0;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    bool array<T,mem_manager>::
    current_element_valid (
    ) const
    {
        return pos != 0;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    const T& array<T,mem_manager>::
    element (
    ) const
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(this->current_element_valid(),
            "\tconst T& array::element()"
            << "\n\tThe current element must be valid if you are to access it."
            << "\n\tthis: " << this
            );

        return *pos;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    T& array<T,mem_manager>::
    element (
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(this->current_element_valid(),
            "\tT& array::element()"
            << "\n\tThe current element must be valid if you are to access it."
            << "\n\tthis: " << this
            );

        return *pos;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    bool array<T,mem_manager>::
    move_next (
    ) const
    {
        if (!_at_start)
        {
            if (pos < last_pos)
            {
                ++pos;
                return true;
            }
            else
            {
                pos = 0;
                return false;
            }
        }
        else
        {
            _at_start = false;
            if (array_size > 0)
            {
                pos = array_elements;
                return true;
            }
            else
            {
                return false;
            }
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                              Yet more functions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void array<T,mem_manager>::
    sort (
    )
    {
        if (this->size() > 1)
        {
            // call the quick sort function for arrays that is in algs.h
            dlib::qsort_array(*this,0,this->size()-1);
        }
        this->reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void array<T,mem_manager>::
    resize (
        unsigned long new_size
    )
    {
        if (this->max_size() < new_size)
        {
            array temp;
            temp.set_max_size(new_size);
            temp.set_size(new_size);
            for (unsigned long i = 0; i < this->size(); ++i)
            {
                exchange((*this)[i],temp[i]);
            }
            temp.swap(*this);
        }
        else
        {
            this->set_size(new_size);
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    T& array<T,mem_manager>::
    back (
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( this->size() > 0 ,
                      "\tT& array::back()"
                      << "\n\tsize() must be bigger than 0"
                      << "\n\tsize(): " << this->size()
                      << "\n\tthis:   " << this
        );

        return (*this)[this->size()-1];
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    const T& array<T,mem_manager>::
    back (
    ) const
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( this->size() > 0 ,
                      "\tconst T& array::back()"
                      << "\n\tsize() must be bigger than 0"
                      << "\n\tsize(): " << this->size()
                      << "\n\tthis:   " << this
        );

        return (*this)[this->size()-1];
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void array<T,mem_manager>::
    pop_back (
        T& item
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( this->size() > 0 ,
                      "\tvoid array::pop_back()"
                      << "\n\tsize() must be bigger than 0"
                      << "\n\tsize(): " << this->size()
                      << "\n\tthis:   " << this
        );

        exchange(item,(*this)[this->size()-1]);
        this->set_size(this->size()-1);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void array<T,mem_manager>::
    pop_back (
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( this->size() > 0 ,
                      "\tvoid array::pop_back()"
                      << "\n\tsize() must be bigger than 0"
                      << "\n\tsize(): " << this->size()
                      << "\n\tthis:   " << this
        );

        this->set_size(this->size()-1);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void array<T,mem_manager>::
    push_back (
        T& item
    )
    {
        if (this->max_size() == this->size())
        {
            // double the size of the array
            array temp;
            temp.set_max_size(this->size()*2 + 1);
            temp.set_size(this->size()+1);
            for (unsigned long i = 0; i < this->size(); ++i)
            {
                exchange((*this)[i],temp[i]);
            }
            exchange(item,temp[temp.size()-1]);
            temp.swap(*this);
        }
        else
        {
            this->set_size(this->size()+1);
            exchange(item,(*this)[this->size()-1]);
        }
    }

// ----------------------------------------------------------------------------------------

    template <typename T, typename MM>
    struct is_array <array<T,MM> >
    {
        const static bool value = true;
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_ARRAY_KERNEl_2_


dlib C++ Library - array_tools.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ARRAY_tOOLS_H_
#define DLIB_ARRAY_tOOLS_H_

#include "../assert.h"
#include "array_tools_abstract.h"

namespace dlib
{
    template <typename T>
    void split_array (
        T& a,
        T& b,
        double frac
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(0 <= frac && frac <= 1,
            "\t void split_array()"
            << "\n\t frac must be between 0 and 1."
            << "\n\t frac: " << frac
            );

        const unsigned long asize = static_cast<unsigned long>(a.size()*frac);
        const unsigned long bsize = a.size()-asize;

        b.resize(bsize);
        for (unsigned long i = 0; i < b.size(); ++i)
        {
            swap(b[i], a[i+asize]);
        }
        a.resize(asize);
    }
}

#endif // DLIB_ARRAY_tOOLS_H_


dlib C++ Library - array2d_generic_image.h

// Copyright (C) 2014  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ARRAY2D_GENERIC_iMAGE_Hh_
#define DLIB_ARRAY2D_GENERIC_iMAGE_Hh_

#include "array2d_kernel.h"
#include "../image_processing/generic_image.h"

namespace dlib
{
    template <typename T, typename mm>
    struct image_traits<array2d<T,mm> >
    {
        typedef T pixel_type;
    };
    template <typename T, typename mm>
    struct image_traits<const array2d<T,mm> >
    {
        typedef T pixel_type;
    };

    template <typename T, typename mm>
    inline long num_rows( const array2d<T,mm>& img) { return img.nr(); }
    template <typename T, typename mm>
    inline long num_columns( const array2d<T,mm>& img) { return img.nc(); }

    template <typename T, typename mm>
    inline void set_image_size(
        array2d<T,mm>& img,
        long rows,
        long cols
    ) { img.set_size(rows,cols); }

    template <typename T, typename mm>
    inline void* image_data(
        array2d<T,mm>& img
    )
    {
        if (img.size() != 0)
            return &img[0][0];
        else
            return 0;
    }

    template <typename T, typename mm>
    inline const void* image_data(
        const array2d<T,mm>& img
    )
    {
        if (img.size() != 0)
            return &img[0][0];
        else
            return 0;
    }

    template <typename T, typename mm>
    inline long width_step(
        const array2d<T,mm>& img
    )
    {
        return img.width_step();
    }

}

#endif // DLIB_ARRAY2D_GENERIC_iMAGE_Hh_


dlib C++ Library - array2d_kernel.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ARRAY2D_KERNEl_1_
#define DLIB_ARRAY2D_KERNEl_1_

#include "array2d_kernel_abstract.h"
#include "../algs.h"
#include "../interfaces/enumerable.h"
#include "../serialize.h"
#include "../geometry/rectangle.h"

namespace dlib
{
    template <
        typename T,
        typename mem_manager = default_memory_manager
        >
    class array2d : public enumerable<T>
    {

        /*!
            INITIAL VALUE
                - nc_ == 0
                - nr_ == 0
                - data == 0
                - at_start_ == true
                - cur == 0
                - last == 0

            CONVENTION
                - nc_ == nc()
                - nr_ == nc()
                - if (data != 0) then
                    - last == a pointer to the last element in the data array
                    - data == pointer to an array of nc_*nr_ T objects
                - else
                    - nc_ == 0
                    - nr_ == 0
                    - data == 0
                    - last == 0

                - nr_ * nc_ == size()
                - if (cur == 0) then
                    - current_element_valid() == false
                - else
                    - current_element_valid() == true
                    - *cur == element()

                - at_start_ == at_start()
        !*/

        class row_helper;
    public:

        // These typedefs are here for backwards compatibility with older versions of dlib.
        typedef array2d kernel_1a;
        typedef array2d kernel_1a_c;

        typedef T type;
        typedef mem_manager mem_manager_type;

        // -----------------------------------

        class row
        {
            /*!
                CONVENTION
                    - nc_ == nc()
                    - for all x < nc_:
                        - (*this)[x] == data[x]
            !*/

            friend class array2d;
            friend class row_helper;

        public:
            long nc (
            ) const { return nc_; }

            const T& operator[] (
                long column
            ) const
            {
                // make sure requires clause is not broken
                DLIB_ASSERT(column < nc() && column >= 0,
                    "\tconst T& array2d::operator[](long column) const"
                    << "\n\tThe column index given must be less than the number of columns."
                    << "\n\tthis:    " << this
                    << "\n\tcolumn:  " << column
                    << "\n\tnc(): " << nc()
                );

                return data[column];
            }

            T& operator[] (
                long column
            )
            {
                // make sure requires clause is not broken
                DLIB_ASSERT(column < nc() && column >= 0,
                    "\tT& array2d::operator[](long column)"
                    << "\n\tThe column index given must be less than the number of columns."
                    << "\n\tthis:    " << this
                    << "\n\tcolumn:  " << column
                    << "\n\tnc(): " << nc()
                );

                return data[column];
            }

        private:

            row(T* data_, long cols) : data(data_), nc_(cols) {}

            T* data;
            long nc_;

            // restricted functions
            row(){}
            row& operator=(row&);
        };

        // -----------------------------------

        array2d (
        ) :
            data(0),
            nc_(0),
            nr_(0),
            cur(0),
            last(0),
            at_start_(true)
        {
        }

        array2d(
            long rows,
            long cols
        ) :
            data(0),
            nc_(0),
            nr_(0),
            cur(0),
            last(0),
            at_start_(true)
        {
            // make sure requires clause is not broken
            DLIB_ASSERT((cols >= 0 && rows >= 0),
                        "\t array2d::array2d(long rows, long cols)"
                        << "\n\t The array2d can't have negative rows or columns."
                        << "\n\t this: " << this
                        << "\n\t cols: " << cols
                        << "\n\t rows: " << rows
            );

            set_size(rows,cols);
        }

        virtual ~array2d (
        ) { clear(); }

        long nc (
        ) const { return nc_; }

        long nr (
        ) const { return nr_; }

        row operator[] (
            long row_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(row_ < nr() && row_ >= 0,
                "\trow array2d::operator[](long row_)"
                << "\n\tThe row index given must be less than the number of rows."
                << "\n\tthis:     " << this
                << "\n\trow_:      " << row_
                << "\n\tnr(): " << nr()
                );

            return row(data+row_*nc_, nc_);
        }

        const row operator[] (
            long row_
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(row_ < nr() && row_ >= 0,
                "\tconst row array2d::operator[](long row_) const"
                << "\n\tThe row index given must be less than the number of rows."
                << "\n\tthis:     " << this
                << "\n\trow_:      " << row_
                << "\n\tnr(): " << nr()
            );

            return row(data+row_*nc_, nc_);
        }

        void swap (
            array2d& item
        )
        {
            exchange(data,item.data);
            exchange(nr_,item.nr_);
            exchange(nc_,item.nc_);
            exchange(at_start_,item.at_start_);
            exchange(cur,item.cur);
            exchange(last,item.last);
            pool.swap(item.pool);
        }

        void clear (
        )
        {
            if (data != 0)
            {
                pool.deallocate_array(data);
                nc_ = 0;
                nr_ = 0;
                data = 0;
                at_start_ = true;
                cur = 0;
                last = 0;
            }
        }

        void set_size (
            long rows,
            long cols
        );

        bool at_start (
        ) const { return at_start_; }

        void reset (
        ) const { at_start_ = true; cur = 0; }

        bool current_element_valid (
        ) const { return (cur != 0); }

        const T& element (
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(current_element_valid() == true,
                "\tconst T& array2d::element()()"
                << "\n\tYou can only call element() when you are at a valid one."
                << "\n\tthis:    " << this
            );

            return *cur;
        }

        T& element (
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(current_element_valid() == true,
                         "\tT& array2d::element()()"
                         << "\n\tYou can only call element() when you are at a valid one."
                         << "\n\tthis:    " << this
            );

            return *cur;
        }

        bool move_next (
        ) const
        {
            if (cur != 0)
            {
                if (cur != last)
                {
                    ++cur;
                    return true;
                }
                cur = 0;
                return false;
            }
            else if (at_start_)
            {
                cur = data;
                at_start_ = false;
                return (data != 0);
            }
            else
            {
                return false;
            }
        }

        unsigned long size (
        ) const { return static_cast<unsigned long>(nc_ * nr_); }

        long width_step (
        ) const
        {
            return nc_*sizeof(T);
        }

    private:

        T* data;
        long nc_;
        long nr_;

        typename mem_manager::template rebind<T>::other pool;
        mutable T* cur;
        T* last;
        mutable bool at_start_;

        // restricted functions
        array2d(array2d&);        // copy constructor
        array2d& operator=(array2d&);    // assignment operator

    };

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    inline void swap (
        array2d<T,mem_manager>& a,
        array2d<T,mem_manager>& b
    ) { a.swap(b); }

    template <
        typename T,
        typename mem_manager
        >
    void serialize (
        const array2d<T,mem_manager>& item,
        std::ostream& out
    )
    {
        try
        {
            // The reason the serialization is a little funny is because we are trying to
            // maintain backwards compatibility with an older serialization format used by
            // dlib while also encoding things in a way that lets the array2d and matrix
            // objects have compatible serialization formats.
            serialize(-item.nr(),out);
            serialize(-item.nc(),out);

            item.reset();
            while (item.move_next())
                serialize(item.element(),out);
            item.reset();
        }
        catch (serialization_error e)
        {
            throw serialization_error(e.info + "\n   while serializing object of type array2d");
        }
    }

    template <
        typename T,
        typename mem_manager
        >
    void deserialize (
        array2d<T,mem_manager>& item,
        std::istream& in
    )
    {
        try
        {
            long nr, nc;
            deserialize(nr,in);
            deserialize(nc,in);

            // this is the newer serialization format
            if (nr < 0 || nc < 0)
            {
                nr *= -1;
                nc *= -1;
            }
            else
            {
                std::swap(nr,nc);
            }

            item.set_size(nr,nc);

            while (item.move_next())
                deserialize(item.element(),in);
            item.reset();
        }
        catch (serialization_error e)
        {
            item.clear();
            throw serialization_error(e.info + "\n   while deserializing object of type array2d");
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void array2d<T,mem_manager>::
    set_size (
        long rows,
        long cols
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT((cols >= 0 && rows >= 0) ,
               "\tvoid array2d::set_size(long rows, long cols)"
               << "\n\tThe array2d can't have negative rows or columns."
               << "\n\tthis: " << this
               << "\n\tcols: " << cols
               << "\n\trows: " << rows
        );

        // set the enumerator back at the start
        at_start_ = true;
        cur = 0;

        // don't do anything if we are already the right size.
        if (nc_ == cols && nr_ == rows)
        {
            return;
        }

        nc_ = cols;
        nr_ = rows;

        // free any existing memory
        if (data != 0)
        {
            pool.deallocate_array(data);
            data = 0;
        }

        // now setup this object to have the new size
        try
        {
            if (nr_ > 0)
            {
                data = pool.allocate_array(nr_*nc_);
                last = data + nr_*nc_ - 1;
            }
        }
        catch (...)
        {
            if (data)
                pool.deallocate_array(data);

            data = 0;
            nc_ = 0;
            nr_ = 0;
            last = 0;
            throw;
        }
    }

// ----------------------------------------------------------------------------------------

    template <typename T, typename MM>
    struct is_array2d <array2d<T,MM> >
    {
        const static bool value = true;
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_ARRAY2D_KERNEl_1_


dlib C++ Library - serialize_pixel_overloads.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ARRAY2D_SERIALIZE_PIXEL_OvERLOADS_Hh_
#define DLIB_ARRAY2D_SERIALIZE_PIXEL_OvERLOADS_Hh_

#include "array2d_kernel.h"
#include "../pixel.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    /*
        This file contains overloads of the serialize functions for array2d object
        for the case where they contain simple 8bit POD pixel types.  In these
        cases we can perform a much faster serialization by writing data in chunks
        instead of one pixel at a time (this avoids a lot of function call overhead
        inside the iostreams).
    */

// ----------------------------------------------------------------------------------------

    template <
        typename mem_manager
        >
    void serialize (
        const array2d<rgb_pixel,mem_manager>& item,
        std::ostream& out
    )
    {
        try
        {
            // The reason the serialization is a little funny is because we are trying to
            // maintain backwards compatibility with an older serialization format used by
            // dlib while also encoding things in a way that lets the array2d and matrix
            // objects have compatible serialization formats.
            serialize(-item.nr(),out);
            serialize(-item.nc(),out);

            COMPILE_TIME_ASSERT(sizeof(rgb_pixel) == 3);

            if (item.size() != 0)
                out.write((char*)&item[0][0], sizeof(rgb_pixel)*item.size());
        }
        catch (serialization_error e)
        {
            throw serialization_error(e.info + "\n   while serializing object of type array2d");
        }
    }

    template <
        typename mem_manager
        >
    void deserialize (
        array2d<rgb_pixel,mem_manager>& item,
        std::istream& in
    )
    {
        try
        {
            COMPILE_TIME_ASSERT(sizeof(rgb_pixel) == 3);

            long nr, nc;
            deserialize(nr,in);
            deserialize(nc,in);

            // this is the newer serialization format
            if (nr < 0 || nc < 0)
            {
                nr *= -1;
                nc *= -1;
            }
            else
            {
                std::swap(nr,nc);
            }

            item.set_size(nr,nc);

            if (item.size() != 0)
                in.read((char*)&item[0][0], sizeof(rgb_pixel)*item.size());
        }
        catch (serialization_error e)
        {
            item.clear();
            throw serialization_error(e.info + "\n   while deserializing object of type array2d");
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename mem_manager
        >
    void serialize (
        const array2d<bgr_pixel,mem_manager>& item,
        std::ostream& out
    )
    {
        try
        {
            // The reason the serialization is a little funny is because we are trying to
            // maintain backwards compatibility with an older serialization format used by
            // dlib while also encoding things in a way that lets the array2d and matrix
            // objects have compatible serialization formats.
            serialize(-item.nr(),out);
            serialize(-item.nc(),out);

            COMPILE_TIME_ASSERT(sizeof(bgr_pixel) == 3);

            if (item.size() != 0)
                out.write((char*)&item[0][0], sizeof(bgr_pixel)*item.size());
        }
        catch (serialization_error e)
        {
            throw serialization_error(e.info + "\n   while serializing object of type array2d");
        }
    }

    template <
        typename mem_manager
        >
    void deserialize (
        array2d<bgr_pixel,mem_manager>& item,
        std::istream& in
    )
    {
        try
        {
            COMPILE_TIME_ASSERT(sizeof(bgr_pixel) == 3);

            long nr, nc;
            deserialize(nr,in);
            deserialize(nc,in);

            // this is the newer serialization format
            if (nr < 0 || nc < 0)
            {
                nr *= -1;
                nc *= -1;
            }
            else
            {
                std::swap(nr,nc);
            }

            item.set_size(nr,nc);

            if (item.size() != 0)
                in.read((char*)&item[0][0], sizeof(bgr_pixel)*item.size());
        }
        catch (serialization_error e)
        {
            item.clear();
            throw serialization_error(e.info + "\n   while deserializing object of type array2d");
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename mem_manager
        >
    void serialize (
        const array2d<hsi_pixel,mem_manager>& item,
        std::ostream& out
    )
    {
        try
        {
            // The reason the serialization is a little funny is because we are trying to
            // maintain backwards compatibility with an older serialization format used by
            // dlib while also encoding things in a way that lets the array2d and matrix
            // objects have compatible serialization formats.
            serialize(-item.nr(),out);
            serialize(-item.nc(),out);

            COMPILE_TIME_ASSERT(sizeof(hsi_pixel) == 3);

            if (item.size() != 0)
                out.write((char*)&item[0][0], sizeof(hsi_pixel)*item.size());
        }
        catch (serialization_error e)
        {
            throw serialization_error(e.info + "\n   while serializing object of type array2d");
        }
    }

    template <
        typename mem_manager
        >
    void deserialize (
        array2d<hsi_pixel,mem_manager>& item,
        std::istream& in
    )
    {
        try
        {
            COMPILE_TIME_ASSERT(sizeof(hsi_pixel) == 3);

            long nr, nc;
            deserialize(nr,in);
            deserialize(nc,in);

            // this is the newer serialization format
            if (nr < 0 || nc < 0)
            {
                nr *= -1;
                nc *= -1;
            }
            else
            {
                std::swap(nr,nc);
            }

            item.set_size(nr,nc);

            if (item.size() != 0)
                in.read((char*)&item[0][0], sizeof(hsi_pixel)*item.size());
        }
        catch (serialization_error e)
        {
            item.clear();
            throw serialization_error(e.info + "\n   while deserializing object of type array2d");
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename mem_manager
        >
    void serialize (
        const array2d<rgb_alpha_pixel,mem_manager>& item,
        std::ostream& out
    )
    {
        try
        {
            // The reason the serialization is a little funny is because we are trying to
            // maintain backwards compatibility with an older serialization format used by
            // dlib while also encoding things in a way that lets the array2d and matrix
            // objects have compatible serialization formats.
            serialize(-item.nr(),out);
            serialize(-item.nc(),out);

            COMPILE_TIME_ASSERT(sizeof(rgb_alpha_pixel) == 4);

            if (item.size() != 0)
                out.write((char*)&item[0][0], sizeof(rgb_alpha_pixel)*item.size());
        }
        catch (serialization_error e)
        {
            throw serialization_error(e.info + "\n   while serializing object of type array2d");
        }
    }

    template <
        typename mem_manager
        >
    void deserialize (
        array2d<rgb_alpha_pixel,mem_manager>& item,
        std::istream& in
    )
    {
        try
        {
            COMPILE_TIME_ASSERT(sizeof(rgb_alpha_pixel) == 4);

            long nr, nc;
            deserialize(nr,in);
            deserialize(nc,in);

            // this is the newer serialization format
            if (nr < 0 || nc < 0)
            {
                nr *= -1;
                nc *= -1;
            }
            else
            {
                std::swap(nr,nc);
            }

            item.set_size(nr,nc);

            if (item.size() != 0)
                in.read((char*)&item[0][0], sizeof(rgb_alpha_pixel)*item.size());
        }
        catch (serialization_error e)
        {
            item.clear();
            throw serialization_error(e.info + "\n   while deserializing object of type array2d");
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename mem_manager
        >
    void serialize (
        const array2d<unsigned char,mem_manager>& item,
        std::ostream& out
    )
    {
        try
        {
            // The reason the serialization is a little funny is because we are trying to
            // maintain backwards compatibility with an older serialization format used by
            // dlib while also encoding things in a way that lets the array2d and matrix
            // objects have compatible serialization formats.
            serialize(-item.nr(),out);
            serialize(-item.nc(),out);

            if (item.size() != 0)
                out.write((char*)&item[0][0], sizeof(unsigned char)*item.size());
        }
        catch (serialization_error e)
        {
            throw serialization_error(e.info + "\n   while serializing object of type array2d");
        }
    }

    template <
        typename mem_manager
        >
    void deserialize (
        array2d<unsigned char,mem_manager>& item,
        std::istream& in
    )
    {
        try
        {
            long nr, nc;
            deserialize(nr,in);
            deserialize(nc,in);
            // this is the newer serialization format
            if (nr < 0 || nc < 0)
            {
                nr *= -1;
                nc *= -1;
            }
            else
            {
                std::swap(nr,nc);
            }

            item.set_size(nr,nc);

            if (item.size() != 0)
                in.read((char*)&item[0][0], sizeof(unsigned char)*item.size());
        }
        catch (serialization_error e)
        {
            item.clear();
            throw serialization_error(e.info + "\n   while deserializing object of type array2d");
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_ARRAY2D_SERIALIZE_PIXEL_OvERLOADS_Hh_


dlib C++ Library - base64_kernel_1.cpp

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_BASE64_KERNEL_1_CPp_
#define DLIB_BASE64_KERNEL_1_CPp_

#include "base64_kernel_1.h"
#include <iostream>
#include <sstream>
#include <climits>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    base64::line_ending_type base64::
    line_ending (
    ) const
    {
        return eol_style;
    }

// ----------------------------------------------------------------------------------------

    void base64::
    set_line_ending (
        line_ending_type eol_style_
    )
    {
        eol_style = eol_style_;
    }

// ----------------------------------------------------------------------------------------

    base64::
    base64 (
    ) :
        encode_table(0),
        decode_table(0),
        bad_value(100),
        eol_style(LF)
    {
        try
        {
            encode_table = new char[64];
            decode_table = new unsigned char[UCHAR_MAX];
        }
        catch (...)
        {
            if (encode_table) delete [] encode_table;
            if (decode_table) delete [] decode_table;
            throw;
        }

        // now set up the tables with the right stuff
        encode_table[0] = 'A';
        encode_table[17] = 'R';
        encode_table[34] = 'i';
        encode_table[51] = 'z';

        encode_table[1] = 'B';
        encode_table[18] = 'S';
        encode_table[35] = 'j';
        encode_table[52] = '0';

        encode_table[2] = 'C';
        encode_table[19] = 'T';
        encode_table[36] = 'k';
        encode_table[53] = '1';

        encode_table[3] = 'D';
        encode_table[20] = 'U';
        encode_table[37] = 'l';
        encode_table[54] = '2';

        encode_table[4] = 'E';
        encode_table[21] = 'V';
        encode_table[38] = 'm';
        encode_table[55] = '3';

        encode_table[5] = 'F';
        encode_table[22] = 'W';
        encode_table[39] = 'n';
        encode_table[56] = '4';

        encode_table[6] = 'G';
        encode_table[23] = 'X';
        encode_table[40] = 'o';
        encode_table[57] = '5';

        encode_table[7] = 'H';
        encode_table[24] = 'Y';
        encode_table[41] = 'p';
        encode_table[58] = '6';

        encode_table[8] = 'I';
        encode_table[25] = 'Z';
        encode_table[42] = 'q';
        encode_table[59] = '7';

        encode_table[9] = 'J';
        encode_table[26] = 'a';
        encode_table[43] = 'r';
        encode_table[60] = '8';

        encode_table[10] = 'K';
        encode_table[27] = 'b';
        encode_table[44] = 's';
        encode_table[61] = '9';

        encode_table[11] = 'L';
        encode_table[28] = 'c';
        encode_table[45] = 't';
        encode_table[62] = '+';

        encode_table[12] = 'M';
        encode_table[29] = 'd';
        encode_table[46] = 'u';
        encode_table[63] = '/';

        encode_table[13] = 'N';
        encode_table[30] = 'e';
        encode_table[47] = 'v';

        encode_table[14] = 'O';
        encode_table[31] = 'f';
        encode_table[48] = 'w';

        encode_table[15] = 'P';
        encode_table[32] = 'g';
        encode_table[49] = 'x';

        encode_table[16] = 'Q';
        encode_table[33] = 'h';
        encode_table[50] = 'y';

        // we can now fill out the decode_table by using the encode_table
        for (int i = 0; i < UCHAR_MAX; ++i)
        {
            decode_table[i] = bad_value;
        }
        for (unsigned char i = 0; i < 64; ++i)
        {
            decode_table[(unsigned char)encode_table[i]] = i;
        }
    }

// ----------------------------------------------------------------------------------------

    base64::
    ~base64 (
    )
    {
        delete [] encode_table;
        delete [] decode_table;
    }

// ----------------------------------------------------------------------------------------

    void base64::
    encode (
        std::istream& in_,
        std::ostream& out_
    ) const
    {
        using namespace std;
        streambuf& in = *in_.rdbuf();
        streambuf& out = *out_.rdbuf();

        unsigned char inbuf[3];
        unsigned char outbuf[4];
        streamsize status = in.sgetn(reinterpret_cast<char*>(&inbuf),3);

        unsigned char c1, c2, c3, c4, c5, c6;

        int counter = 19;

        // while we haven't hit the end of the input stream
        while (status != 0)
        {
            if (counter == 0)
            {
                counter = 19;
                // write a newline
                char ch;
                switch (eol_style)
                {
                    case CR:
                        ch = '\r';
                        if (out.sputn(&ch,1)!=1)
                            throw std::ios_base::failure("error occured in the base64 object");
                        break;
                    case LF:
                        ch = '\n';
                        if (out.sputn(&ch,1)!=1)
                            throw std::ios_base::failure("error occured in the base64 object");
                        break;
                    case CRLF:
                        ch = '\r';
                        if (out.sputn(&ch,1)!=1)
                            throw std::ios_base::failure("error occured in the base64 object");
                        ch = '\n';
                        if (out.sputn(&ch,1)!=1)
                            throw std::ios_base::failure("error occured in the base64 object");
                        break;
                    default:
                        DLIB_CASSERT(false,"this should never happen");
                }
            }
            --counter;

            if (status == 3)
            {
                // encode the bytes in inbuf to base64 and write them to the output stream
                c1 = inbuf[0]&0xfc;
                c2 = inbuf[0]&0x03;
                c3 = inbuf[1]&0xf0;
                c4 = inbuf[1]&0x0f;
                c5 = inbuf[2]&0xc0;
                c6 = inbuf[2]&0x3f;

                outbuf[0] = c1>>2;
                outbuf[1] = (c2<<4)|(c3>>4);
                outbuf[2] = (c4<<2)|(c5>>6);
                outbuf[3] = c6;

                outbuf[0] = encode_table[outbuf[0]];
                outbuf[1] = encode_table[outbuf[1]];
                outbuf[2] = encode_table[outbuf[2]];
                outbuf[3] = encode_table[outbuf[3]];

                // write the encoded bytes to the output stream
                if (out.sputn(reinterpret_cast<char*>(&outbuf),4)!=4)
                {
                    throw std::ios_base::failure("error occured in the base64 object");
                }

                // get 3 more input bytes
                status = in.sgetn(reinterpret_cast<char*>(&inbuf),3);
                continue;
            }
            else if (status == 2)
            {
                // we are at the end of the input stream and need to add some padding

                // encode the bytes in inbuf to base64 and write them to the output stream
                c1 = inbuf[0]&0xfc;
                c2 = inbuf[0]&0x03;
                c3 = inbuf[1]&0xf0;
                c4 = inbuf[1]&0x0f;
                c5 = 0;

                outbuf[0] = c1>>2;
                outbuf[1] = (c2<<4)|(c3>>4);
                outbuf[2] = (c4<<2)|(c5>>6);
                outbuf[3] = '=';

                outbuf[0] = encode_table[outbuf[0]];
                outbuf[1] = encode_table[outbuf[1]];
                outbuf[2] = encode_table[outbuf[2]];

                // write the encoded bytes to the output stream
                if (out.sputn(reinterpret_cast<char*>(&outbuf),4)!=4)
                {
                    throw std::ios_base::failure("error occured in the base64 object");
                }

                break;
            }
            else // in this case status must be 1
            {
                // we are at the end of the input stream and need to add some padding

                // encode the bytes in inbuf to base64 and write them to the output stream
                c1 = inbuf[0]&0xfc;
                c2 = inbuf[0]&0x03;
                c3 = 0;

                outbuf[0] = c1>>2;
                outbuf[1] = (c2<<4)|(c3>>4);
                outbuf[2] = '=';
                outbuf[3] = '=';

                outbuf[0] = encode_table[outbuf[0]];
                outbuf[1] = encode_table[outbuf[1]];

                // write the encoded bytes to the output stream
                if (out.sputn(reinterpret_cast<char*>(&outbuf),4)!=4)
                {
                    throw std::ios_base::failure("error occured in the base64 object");
                }

                break;
            }
        } // while (status != 0)

        // make sure the stream buffer flushes to its I/O channel
        out.pubsync();
    }

// ----------------------------------------------------------------------------------------

    void base64::
    decode (
        std::istream& in_,
        std::ostream& out_
    ) const
    {
        using namespace std;
        streambuf& in = *in_.rdbuf();
        streambuf& out = *out_.rdbuf();

        unsigned char inbuf[4];
        unsigned char outbuf[3];
        int inbuf_pos = 0;
        streamsize status = in.sgetn(reinterpret_cast<char*>(inbuf),1);

        // only count this character if it isn't some kind of filler
        if (status == 1 && decode_table[inbuf[0]] != bad_value )
            ++inbuf_pos;

        unsigned char c1, c2, c3, c4, c5, c6;
        streamsize outsize;

        // while we haven't hit the end of the input stream
        while (status != 0)
        {
            // if we have 4 valid characters
            if (inbuf_pos == 4)
            {
                inbuf_pos = 0;

                // this might be the end of the encoded data so we need to figure out if
                // there was any padding applied.
                outsize = 3;
                if (inbuf[3] == '=')
                {
                    if (inbuf[2] == '=')
                        outsize = 1;
                    else
                        outsize = 2;
                }

                // decode the incoming characters
                inbuf[0] = decode_table[inbuf[0]];
                inbuf[1] = decode_table[inbuf[1]];
                inbuf[2] = decode_table[inbuf[2]];
                inbuf[3] = decode_table[inbuf[3]];

                // now pack these guys into bytes rather than 6 bit chunks
                c1 = inbuf[0]<<2;
                c2 = inbuf[1]>>4;
                c3 = inbuf[1]<<4;
                c4 = inbuf[2]>>2;
                c5 = inbuf[2]<<6;
                c6 = inbuf[3];

                outbuf[0] = c1|c2;
                outbuf[1] = c3|c4;
                outbuf[2] = c5|c6;

                // write the encoded bytes to the output stream
                if (out.sputn(reinterpret_cast<char*>(&outbuf),outsize)!=outsize)
                {
                    throw std::ios_base::failure("error occured in the base64 object");
                }
            }

            // get more input characters
            status = in.sgetn(reinterpret_cast<char*>(inbuf + inbuf_pos),1);
            // only count this character if it isn't some kind of filler
            if ((decode_table[inbuf[inbuf_pos]] != bad_value || inbuf[inbuf_pos] == '=') &&
                status != 0)
                ++inbuf_pos;
        } // while (status != 0)

        if (inbuf_pos != 0)
        {
            ostringstream sout;
            sout << inbuf_pos << " extra characters were found at the end of the encoded data."
                << "  This may indicate that the data stream has been truncated.";
            // this happens if we hit EOF in the middle of decoding a 24bit block.
            throw decode_error(sout.str());
        }

        // make sure the stream buffer flushes to its I/O channel
        out.pubsync();
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_BASE64_KERNEL_1_CPp_


dlib C++ Library - base64_kernel_1.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_BASE64_KERNEl_1_
#define DLIB_BASE64_KERNEl_1_

#include "../algs.h"
#include "base64_kernel_abstract.h"
#include <iosfwd>

namespace dlib
{

    class base64
    {
        /*!
            INITIAL VALUE
                - bad_value == 100
                - encode_table == a pointer to an array of 64 chars
                - where x is a 6 bit value the following is true:
                    - encode_table[x] == the base64 encoding of x
                - decode_table == a pointer to an array of UCHAR_MAX chars
                - where x is any char value:
                    - if (x is a valid character in the base64 coding scheme) then
                        - decode_table[x] == the 6 bit value that x encodes
                    - else
                        - decode_table[x] == bad_value

            CONVENTION
                - The state of this object never changes so just refer to its
                  initial value.

        !*/

    public:
        // this is here for backwards compatibility with older versions of dlib.
        typedef base64 kernel_1a;

        class decode_error : public dlib::error { public:
        decode_error( const std::string& e) : error(e) {}};

        base64 (
        );

        virtual ~base64 (
        );

        enum line_ending_type
        {
            CR,  // i.e. "\r"
            LF,  // i.e. "\n"
            CRLF // i.e. "\r\n"
        };

        line_ending_type line_ending (
        ) const;

        void set_line_ending (
            line_ending_type eol_style_
        );

        void encode (
            std::istream& in,
            std::ostream& out
        ) const;

        void decode (
            std::istream& in,
            std::ostream& out
        ) const;

    private:

        char* encode_table;
        unsigned char* decode_table;
        const unsigned char bad_value;
        line_ending_type eol_style;

        // restricted functions
        base64(base64&);        // copy constructor
        base64& operator=(base64&);    // assignment operator

    };

}

#ifdef NO_MAKEFILE
#include "base64_kernel_1.cpp"
#endif

#endif // DLIB_BASE64_KERNEl_1_


dlib C++ Library - bigint_kernel_1.cpp

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_BIGINT_KERNEL_1_CPp_
#define DLIB_BIGINT_KERNEL_1_CPp_
#include "bigint_kernel_1.h"

#include <iostream>

namespace dlib
{

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member/friend function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    bigint_kernel_1::
    bigint_kernel_1 (
    ) :
        slack(25),
        data(new data_record(slack))
    {}

// ----------------------------------------------------------------------------------------

    bigint_kernel_1::
    bigint_kernel_1 (
        uint32 value
    ) :
        slack(25),
        data(new data_record(slack))
    {
        *(data->number) = static_cast<uint16>(value&0xFFFF);
        *(data->number+1) = static_cast<uint16>((value>>16)&0xFFFF);
        if (*(data->number+1) != 0)
            data->digits_used = 2;
    }

// ----------------------------------------------------------------------------------------

    bigint_kernel_1::
    bigint_kernel_1 (
        const bigint_kernel_1& item
    ) :
        slack(25),
        data(item.data)
    {
        data->references += 1;
    }

// ----------------------------------------------------------------------------------------

    bigint_kernel_1::
    ~bigint_kernel_1 (
    )
    {
        if (data->references == 1)
        {
            delete data;
        }
        else
        {
            data->references -= 1;
        }
    }

// ----------------------------------------------------------------------------------------

    const bigint_kernel_1 bigint_kernel_1::
    operator+ (
        const bigint_kernel_1& rhs
    ) const
    {
        data_record* temp = new data_record (
                    std::max(rhs.data->digits_used,data->digits_used) + slack
                    );
        long_add(data,rhs.data,temp);
        return bigint_kernel_1(temp,0);
    }

// ----------------------------------------------------------------------------------------

    bigint_kernel_1& bigint_kernel_1::
    operator+= (
        const bigint_kernel_1& rhs
    )
    {
        // if there are other references to our data
        if (data->references != 1)
        {
            data_record* temp = new data_record(std::max(data->digits_used,rhs.data->digits_used)+slack);
            data->references -= 1;
            long_add(data,rhs.data,temp);
            data = temp;
        }
        // if data is not big enough for the result
        else if (data->size <= std::max(data->digits_used,rhs.data->digits_used))
        {
            data_record* temp = new data_record(std::max(data->digits_used,rhs.data->digits_used)+slack);
            long_add(data,rhs.data,temp);
            delete data;
            data = temp;
        }
        // there is enough size and no references
        else
        {
            long_add(data,rhs.data,data);
        }
        return *this;
    }

// ----------------------------------------------------------------------------------------

    const bigint_kernel_1 bigint_kernel_1::
    operator- (
        const bigint_kernel_1& rhs
    ) const
    {
        data_record* temp = new data_record (
                    data->digits_used + slack
                    );
        long_sub(data,rhs.data,temp);
        return bigint_kernel_1(temp,0);
    }

// ----------------------------------------------------------------------------------------

    bigint_kernel_1& bigint_kernel_1::
    operator-= (
        const bigint_kernel_1& rhs
    )
    {
        // if there are other references to this data
        if (data->references != 1)
        {
            data_record* temp = new data_record(data->digits_used+slack);
            data->references -= 1;
            long_sub(data,rhs.data,temp);
            data = temp;
        }
        else
        {
            long_sub(data,rhs.data,data);
        }
        return *this;
    }

// ----------------------------------------------------------------------------------------

    const bigint_kernel_1 bigint_kernel_1::
    operator* (
        const bigint_kernel_1& rhs
    ) const
    {
        data_record* temp = new data_record (
                    data->digits_used + rhs.data->digits_used + slack
                    );
        long_mul(data,rhs.data,temp);
        return bigint_kernel_1(temp,0);
    }

// ----------------------------------------------------------------------------------------

    bigint_kernel_1& bigint_kernel_1::
    operator*= (
        const bigint_kernel_1& rhs
    )
    {
        // create a data_record to store the result of the multiplication in
        data_record* temp = new data_record(rhs.data->digits_used+data->digits_used+slack);
        long_mul(data,rhs.data,temp);

        // if there are other references to data
        if (data->references != 1)
        {
            data->references -= 1;
        }
        else
        {
            delete data;
        }
        data = temp;
        return *this;
    }

// ----------------------------------------------------------------------------------------

    const bigint_kernel_1 bigint_kernel_1::
    operator/ (
        const bigint_kernel_1& rhs
    ) const
    {
        data_record* temp = new data_record(data->digits_used+slack);
        data_record* remainder;
        try {
            remainder = new data_record(data->digits_used+slack);
        } catch (...) { delete temp; throw; }

        long_div(data,rhs.data,temp,remainder);
        delete remainder;

        return bigint_kernel_1(temp,0);
    }

// ----------------------------------------------------------------------------------------

    bigint_kernel_1& bigint_kernel_1::
    operator/= (
        const bigint_kernel_1& rhs
    )
    {

        data_record* temp = new data_record(data->digits_used+slack);
        data_record* remainder;
        try {
            remainder = new data_record(data->digits_used+slack);
        } catch (...) { delete temp; throw; }

        long_div(data,rhs.data,temp,remainder);

        // check if there are other references to data
        if (data->references != 1)
        {
            data->references -= 1;
        }
        // if there are no references to data then it must be deleted
        else
        {
            delete data;
        }
        data = temp;
        delete remainder;

        return *this;
    }

// ----------------------------------------------------------------------------------------

    const bigint_kernel_1 bigint_kernel_1::
    operator% (
        const bigint_kernel_1& rhs
    ) const
    {
        data_record* temp = new data_record(data->digits_used+slack);
        data_record* remainder;
        try {
            remainder = new data_record(data->digits_used+slack);
        } catch (...) { delete temp; throw; }

        long_div(data,rhs.data,temp,remainder);
        delete temp;
        return bigint_kernel_1(remainder,0);
    }

// ----------------------------------------------------------------------------------------

    bigint_kernel_1& bigint_kernel_1::
    operator%= (
        const bigint_kernel_1& rhs
    )
    {
        data_record* temp = new data_record(data->digits_used+slack);
        data_record* remainder;
        try {
            remainder = new data_record(data->digits_used+slack);
        } catch (...) { delete temp; throw; }

        long_div(data,rhs.data,temp,remainder);

        // check if there are other references to data
        if (data->references != 1)
        {
            data->references -= 1;
        }
        // if there are no references to data then it must be deleted
        else
        {
            delete data;
        }
        data = remainder;
        delete temp;
        return *this;
    }

// ----------------------------------------------------------------------------------------

    bool bigint_kernel_1::
    operator < (
        const bigint_kernel_1& rhs
    ) const
    {
        return is_less_than(data,rhs.data);
    }

// ----------------------------------------------------------------------------------------

    bool bigint_kernel_1::
    operator == (
        const bigint_kernel_1& rhs
    ) const
    {
        return is_equal_to(data,rhs.data);
    }

// ----------------------------------------------------------------------------------------

    bigint_kernel_1& bigint_kernel_1::
    operator= (
        const bigint_kernel_1& rhs
    )
    {
        if (this == &rhs)
            return *this;

        // if we have the only reference to our data then delete it
        if (data->references == 1)
        {
            delete data;
            data = rhs.data;
            data->references += 1;
        }
        else
        {
            data->references -= 1;
            data = rhs.data;
            data->references += 1;
        }

        return *this;
    }

// ----------------------------------------------------------------------------------------

    std::ostream& operator<< (
        std::ostream& out_,
        const bigint_kernel_1& rhs
    )
    {
        std::ostream out(out_.rdbuf());

        typedef bigint_kernel_1 bigint;

        bigint::data_record* temp = new bigint::data_record(*rhs.data,0);

        // get a char array big enough to hold the number in ascii format
        char* str;
        try {
            str = new char[(rhs.data->digits_used)*5+10];
        } catch (...) { delete temp; throw; }

        char* str_start = str;
        str += (rhs.data->digits_used)*5+9;
        *str = 0; --str;

        uint16 remainder;
        rhs.short_div(temp,10000,temp,remainder);

        // pull the digits out of remainder
        char a = remainder % 10 + '0';
        remainder /= 10;
        char b = remainder % 10 + '0';
        remainder /= 10;
        char c = remainder % 10 + '0';
        remainder /= 10;
        char d = remainder % 10 + '0';
        remainder /= 10;

        *str = a; --str;
        *str = b; --str;
        *str = c; --str;
        *str = d; --str;

        // keep looping until temp represents zero
        while (temp->digits_used != 1 || *(temp->number) != 0)
        {
            rhs.short_div(temp,10000,temp,remainder);

            // pull the digits out of remainder
            char a = remainder % 10 + '0';
            remainder /= 10;
            char b = remainder % 10 + '0';
            remainder /= 10;
            char c = remainder % 10 + '0';
            remainder /= 10;
            char d = remainder % 10 + '0';
            remainder /= 10;

            *str = a; --str;
            *str = b; --str;
            *str = c; --str;
            *str = d; --str;
        }

        // throw away and extra leading zeros
        ++str;
        if (*str == '0')
            ++str;
        if (*str == '0')
            ++str;
        if (*str == '0')
            ++str;

        out << str;
        delete [] str_start;
        delete temp;
        return out_;

    }

// ----------------------------------------------------------------------------------------

    std::istream& operator>> (
        std::istream& in_,
        bigint_kernel_1& rhs
    )
    {
        std::istream in(in_.rdbuf());

        // ignore any leading whitespaces
        while (in.peek() == ' ' || in.peek() == '\t' || in.peek() == '\n')
        {
            in.get();
        }

        // if the first digit is not an integer then this is an error
        if ( !(in.peek() >= '0' && in.peek() <= '9'))
        {
            in_.clear(std::ios::failbit);
            return in_;
        }

        int num_read;
        bigint_kernel_1 temp;
        do
        {

            // try to get 4 chars from in
            num_read = 1;
            char a = 0;
            char b = 0;
            char c = 0;
            char d = 0;

            if (in.peek() >= '0' && in.peek() <= '9')
            {
                num_read *= 10;
                a = in.get();
            }
            if (in.peek() >= '0' && in.peek() <= '9')
            {
                num_read *= 10;
                b = in.get();
            }
            if (in.peek() >= '0' && in.peek() <= '9')
            {
                num_read *= 10;
                c = in.get();
            }
            if (in.peek() >= '0' && in.peek() <= '9')
            {
                num_read *= 10;
                d = in.get();
            }

            // merge the for digits into an uint16
            uint16 num = 0;
            if (a != 0)
            {
                num = a - '0';
            }
            if (b != 0)
            {
                num *= 10;
                num += b - '0';
            }
            if (c != 0)
            {
                num *= 10;
                num += c - '0';
            }
            if (d != 0)
            {
                num *= 10;
                num += d - '0';
            }

            if (num_read != 1)
            {
                // shift the digits in temp left by the number of new digits we just read
                temp *= num_read;
                // add in new digits
                temp += num;
            }

        } while (num_read == 10000);

        rhs = temp;
        return in_;
    }

// ----------------------------------------------------------------------------------------

    const bigint_kernel_1 operator+ (
        uint16 lhs,
        const bigint_kernel_1& rhs
    )
    {
        typedef bigint_kernel_1 bigint;
        bigint::data_record* temp = new bigint::data_record
                (rhs.data->digits_used+rhs.slack);

        rhs.short_add(rhs.data,lhs,temp);
        return bigint_kernel_1(temp,0);
    }

// ----------------------------------------------------------------------------------------

    const bigint_kernel_1 operator+ (
        const bigint_kernel_1& lhs,
        uint16 rhs
    )
    {
        typedef bigint_kernel_1 bigint;
        bigint::data_record* temp = new bigint::data_record
                (lhs.data->digits_used+lhs.slack);

        lhs.short_add(lhs.data,rhs,temp);
        return bigint_kernel_1(temp,0);
    }

// ----------------------------------------------------------------------------------------

    bigint_kernel_1& bigint_kernel_1::
    operator+= (
        uint16 rhs
    )
    {
        // if there are other references to this data
        if (data->references != 1)
        {
            data_record* temp = new data_record(data->digits_used+slack);
            data->references -= 1;
            short_add(data,rhs,temp);
            data = temp;
        }
        // or if we need to enlarge data then do so
        else if (data->digits_used == data->size)
        {
            data_record* temp = new data_record(data->digits_used+slack);
            short_add(data,rhs,temp);
            delete data;
            data = temp;
        }
        // or if there is plenty of space and no references
        else
        {
            short_add(data,rhs,data);
        }
        return *this;
    }

// ----------------------------------------------------------------------------------------

    const bigint_kernel_1 operator- (
        uint16 lhs,
        const bigint_kernel_1& rhs
    )
    {
        typedef bigint_kernel_1 bigint;
        bigint::data_record* temp = new bigint::data_record(rhs.slack);

        *(temp->number) = lhs - *(rhs.data->number);

        return bigint_kernel_1(temp,0);
    }

// ----------------------------------------------------------------------------------------

    const bigint_kernel_1 operator- (
        const bigint_kernel_1& lhs,
        uint16 rhs
    )
    {
        typedef bigint_kernel_1 bigint;
        bigint::data_record* temp = new bigint::data_record
                (lhs.data->digits_used+lhs.slack);

        lhs.short_sub(lhs.data,rhs,temp);
        return bigint_kernel_1(temp,0);
    }

// ----------------------------------------------------------------------------------------

    bigint_kernel_1& bigint_kernel_1::
    operator-= (
        uint16 rhs
    )
    {
        // if there are other references to this data
        if (data->references != 1)
        {
            data_record* temp = new data_record(data->digits_used+slack);
            data->references -= 1;
            short_sub(data,rhs,temp);
            data = temp;
        }
        else
        {
            short_sub(data,rhs,data);
        }
        return *this;
    }

// ----------------------------------------------------------------------------------------

    const bigint_kernel_1 operator* (
        uint16 lhs,
        const bigint_kernel_1& rhs
    )
    {
        typedef bigint_kernel_1 bigint;
        bigint::data_record* temp = new bigint::data_record
                (rhs.data->digits_used+rhs.slack);

        rhs.short_mul(rhs.data,lhs,temp);
        return bigint_kernel_1(temp,0);
    }

// ----------------------------------------------------------------------------------------

    const bigint_kernel_1 operator* (
        const bigint_kernel_1& lhs,
        uint16 rhs
    )
    {
        typedef bigint_kernel_1 bigint;
        bigint::data_record* temp = new bigint::data_record
                (lhs.data->digits_used+lhs.slack);

        lhs.short_mul(lhs.data,rhs,temp);
        return bigint_kernel_1(temp,0);
    }

// ----------------------------------------------------------------------------------------

    bigint_kernel_1& bigint_kernel_1::
    operator*= (
        uint16 rhs
    )
    {
        // if there are other references to this data
        if (data->references != 1)
        {
            data_record* temp = new data_record(data->digits_used+slack);
            data->references -= 1;
            short_mul(data,rhs,temp);
            data = temp;
        }
        // or if we need to enlarge data
        else if (data->digits_used == data->size)
        {
            data_record* temp = new data_record(data->digits_used+slack);
            short_mul(data,rhs,temp);
            delete data;
            data = temp;
        }
        else
        {
            short_mul(data,rhs,data);
        }
        return *this;
    }

// ----------------------------------------------------------------------------------------

    const bigint_kernel_1 operator/ (
        uint16 lhs,
        const bigint_kernel_1& rhs
    )
    {
        typedef bigint_kernel_1 bigint;
        bigint::data_record* temp = new bigint::data_record(rhs.slack);

        // if rhs might not be bigger than lhs
        if (rhs.data->digits_used == 1)
        {
            *(temp->number) = lhs/ *(rhs.data->number);
        }

        return bigint_kernel_1(temp,0);
    }

// ----------------------------------------------------------------------------------------

    const bigint_kernel_1 operator/ (
        const bigint_kernel_1& lhs,
        uint16 rhs
    )
    {
        typedef bigint_kernel_1 bigint;
        bigint::data_record* temp = new bigint::data_record
                (lhs.data->digits_used+lhs.slack);

        uint16 remainder;
        lhs.short_div(lhs.data,rhs,temp,remainder);
        return bigint_kernel_1(temp,0);
    }

// ----------------------------------------------------------------------------------------

    bigint_kernel_1& bigint_kernel_1::
    operator/= (
        uint16 rhs
    )
    {
        uint16 remainder;
        // if there are other references to this data
        if (data->references != 1)
        {
            data_record* temp = new data_record(data->digits_used+slack);
            data->references -= 1;
            short_div(data,rhs,temp,remainder);
            data = temp;
        }
        else
        {
            short_div(data,rhs,data,remainder);
        }
        return *this;
    }

// ----------------------------------------------------------------------------------------

    const bigint_kernel_1 operator% (
        uint16 lhs,
        const bigint_kernel_1& rhs
    )
    {
        typedef bigint_kernel_1 bigint;
        // temp is zero by default
        bigint::data_record* temp = new bigint::data_record(rhs.slack);

        if (rhs.data->digits_used == 1)
        {
            // if rhs is just an uint16 inside then perform the modulus
            *(temp->number) = lhs % *(rhs.data->number);
        }
        else
        {
            // if rhs is bigger than lhs then the answer is lhs
            *(temp->number) = lhs;
        }

        return bigint_kernel_1(temp,0);
    }

// ----------------------------------------------------------------------------------------

    const bigint_kernel_1 operator% (
        const bigint_kernel_1& lhs,
        uint16 rhs
    )
    {
        typedef bigint_kernel_1 bigint;
        bigint::data_record* temp = new bigint::data_record(lhs.data->digits_used+lhs.slack);

        uint16 remainder;

        lhs.short_div(lhs.data,rhs,temp,remainder);
        temp->digits_used = 1;
        *(temp->number) = remainder;
        return bigint_kernel_1(temp,0);
    }

// ----------------------------------------------------------------------------------------

    bigint_kernel_1& bigint_kernel_1::
    operator%= (
        uint16 rhs
    )
    {
        uint16 remainder;
        // if there are other references to this data
        if (data->references != 1)
        {
            data_record* temp = new data_record(data->digits_used+slack);
            data->references -= 1;
            short_div(data,rhs,temp,remainder);
            data = temp;
        }
        else
        {
            short_div(data,rhs,data,remainder);
        }

        data->digits_used = 1;
        *(data->number) = remainder;
        return *this;
    }

// ----------------------------------------------------------------------------------------

    bool operator < (
        uint16 lhs,
        const bigint_kernel_1& rhs
    )
    {
        return (rhs.data->digits_used > 1 || lhs < *(rhs.data->number) );
    }

// ----------------------------------------------------------------------------------------

    bool operator < (
        const bigint_kernel_1& lhs,
        uint16 rhs
    )
    {
        return (lhs.data->digits_used == 1 && *(lhs.data->number) < rhs);
    }

// ----------------------------------------------------------------------------------------

    bool operator == (
        const bigint_kernel_1& lhs,
        uint16 rhs
    )
    {
        return (lhs.data->digits_used == 1 && *(lhs.data->number) == rhs);
    }

// ----------------------------------------------------------------------------------------

    bool operator == (
        uint16 lhs,
        const bigint_kernel_1& rhs
    )
    {
        return (rhs.data->digits_used == 1 && *(rhs.data->number) == lhs);
    }

// ----------------------------------------------------------------------------------------

    bigint_kernel_1& bigint_kernel_1::
    operator= (
        uint16 rhs
    )
    {
        // check if there are other references to our data
        if (data->references != 1)
        {
            data->references -= 1;
            try {
                data = new data_record(slack);
            } catch (...) { data->references += 1; throw; }
        }
        else
        {
            data->digits_used = 1;
        }

        *(data->number) = rhs;

        return *this;
    }

// ----------------------------------------------------------------------------------------

    bigint_kernel_1& bigint_kernel_1::
    operator++ (
    )
    {
        // if there are other references to this data then make a copy of it
        if (data->references != 1)
        {
            data_record* temp = new data_record(data->digits_used+slack);
            data->references -= 1;
            increment(data,temp);
            data = temp;
        }
        // or if we need to enlarge data then do so
        else if (data->digits_used == data->size)
        {
            data_record* temp = new data_record(data->digits_used+slack);
            increment(data,temp);
            delete data;
            data = temp;
        }
        else
        {
            increment(data,data);
        }

        return *this;
    }

// ----------------------------------------------------------------------------------------

    const bigint_kernel_1 bigint_kernel_1::
    operator++ (
        int
    )
    {
        data_record* temp; // this is the copy of temp we will return in the end

        data_record* temp2 = new data_record(data->digits_used+slack);
        increment(data,temp2);

        temp = data;
        data = temp2;

        return bigint_kernel_1(temp,0);
    }

// ----------------------------------------------------------------------------------------

    bigint_kernel_1& bigint_kernel_1::
    operator-- (
    )
    {
        // if there are other references to this data
        if (data->references != 1)
        {
            data_record* temp = new data_record(data->digits_used+slack);
            data->references -= 1;
            decrement(data,temp);
            data = temp;
        }
        else
        {
            decrement(data,data);
        }

        return *this;
    }

// ----------------------------------------------------------------------------------------

    const bigint_kernel_1 bigint_kernel_1::
    operator-- (
        int
    )
    {
        data_record* temp; // this is the copy of temp we will return in the end

        data_record* temp2 = new data_record(data->digits_used+slack);
        decrement(data,temp2);

        temp = data;
        data = temp2;

        return bigint_kernel_1(temp,0);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // private member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    void bigint_kernel_1::
    short_add (
        const data_record* data,
        uint16 value,
        data_record* result
    ) const
    {
        // put value into the carry part of temp
        uint32 temp = value;
        temp <<= 16;

        const uint16* number = data->number;
        const uint16* end = number + data->digits_used; // one past the end of number
        uint16* r = result->number;

        while (number != end)
        {
            // add *number and the current carry
            temp = *number + (temp>>16);
            // put the low word of temp into *r
            *r = static_cast<uint16>(temp & 0xFFFF);

            ++number;
            ++r;
        }

        // if there is a final carry
        if ((temp>>16) != 0)
        {
            result->digits_used = data->digits_used + 1;
            // store the carry in the most significant digit of the result
            *r = static_cast<uint16>(temp>>16);
        }
        else
        {
            result->digits_used = data->digits_used;
        }
    }

// ----------------------------------------------------------------------------------------

    void bigint_kernel_1::
    short_sub (
        const data_record* data,
        uint16 value,
        data_record* result
    ) const
    {

        const uint16* number = data->number;
        const uint16* end = number + data->digits_used - 1;
        uint16* r = result->number;

        uint32 temp = *number - value;

        // put the low word of temp into *data
        *r = static_cast<uint16>(temp & 0xFFFF);

        while (number != end)
        {
            ++number;
            ++r;

            // subtract the carry from *number
            temp = *number - (temp>>31);

            // put the low word of temp into *r
            *r = static_cast<uint16>(temp & 0xFFFF);
        }

        // if we lost a digit in the subtraction
        if (*r == 0)
        {
            if (data->digits_used == 1)
                result->digits_used = 1;
            else
                result->digits_used = data->digits_used - 1;
        }
        else
        {
            result->digits_used = data->digits_used;
        }

    }

// ----------------------------------------------------------------------------------------

    void bigint_kernel_1::
    short_mul (
        const data_record* data,
        uint16 value,
        data_record* result
    ) const
    {

        uint32 temp = 0;

        const uint16* number = data->number;
        uint16* r = result->number;
        const uint16* end = r + data->digits_used;

        while ( r != end)
        {

            // multiply *data and value and add in the carry
            temp = *number*(uint32)value + (temp>>16);

            // put the low word of temp into *data
            *r = static_cast<uint16>(temp & 0xFFFF);

            ++number;
            ++r;
        }

        // if there is a final carry
        if ((temp>>16) != 0)
        {
            result->digits_used = data->digits_used + 1;
            // put the final carry into the most significant digit of the result
            *r = static_cast<uint16>(temp>>16);
        }
        else
        {
            result->digits_used = data->digits_used;
        }

    }

// ----------------------------------------------------------------------------------------

    void bigint_kernel_1::
    short_div (
        const data_record* data,
        uint16 value,
        data_record* result,
        uint16& rem
    ) const
    {

        uint16 remainder = 0;
        uint32 temp;

        const uint16* number = data->number + data->digits_used - 1;
        const uint16* end = number - data->digits_used;
        uint16* r = result->number + data->digits_used - 1;

        // if we are losing a digit in this division
        if (*number < value)
        {
            if (data->digits_used == 1)
                result->digits_used = 1;
            else
                result->digits_used = data->digits_used - 1;
        }
        else
        {
            result->digits_used = data->digits_used;
        }

        // perform the actual division
        while (number != end)
        {

            temp = *number + (((uint32)remainder)<<16);

            *r = static_cast<uint16>(temp/value);
            remainder = static_cast<uint16>(temp%value);

            --number;
            --r;
        }

        rem = remainder;
    }

// ----------------------------------------------------------------------------------------

    void bigint_kernel_1::
    long_add (
        const data_record* lhs,
        const data_record* rhs,
        data_record* result
    ) const
    {
        // put value into the carry part of temp
        uint32 temp=0;

        uint16* min_num;  // the number with the least digits used
        uint16* max_num;  // the number with the most digits used
        uint16* min_end;  // one past the end of min_num
        uint16* max_end;  // one past the end of max_num
        uint16* r = result->number;

        uint32 max_digits_used;
        if (lhs->digits_used < rhs->digits_used)
        {
            max_digits_used = rhs->digits_used;
            min_num = lhs->number;
            max_num = rhs->number;
            min_end = min_num + lhs->digits_used;
            max_end = max_num + rhs->digits_used;
        }
        else
        {
            max_digits_used = lhs->digits_used;
            min_num = rhs->number;
            max_num = lhs->number;
            min_end = min_num + rhs->digits_used;
            max_end = max_num + lhs->digits_used;
        }

        while (min_num != min_end)
        {
            // add *min_num, *max_num and the current carry
            temp = *min_num + *max_num + (temp>>16);
            // put the low word of temp into *r
            *r = static_cast<uint16>(temp & 0xFFFF);

            ++min_num;
            ++max_num;
            ++r;
        }

        while (max_num != max_end)
        {
            // add *max_num and the current carry
            temp = *max_num + (temp>>16);
            // put the low word of temp into *r
            *r = static_cast<uint16>(temp & 0xFFFF);

            ++max_num;
            ++r;
        }

        // check if there was a final carry
        if ((temp>>16) != 0)
        {
            result->digits_used = max_digits_used + 1;
            // put the carry into the most significant digit in the result
            *r = static_cast<uint16>(temp>>16);
        }
        else
        {
            result->digits_used = max_digits_used;
        }

    }

// ----------------------------------------------------------------------------------------

    void bigint_kernel_1::
    long_sub (
        const data_record* lhs,
        const data_record* rhs,
        data_record* result
    ) const
    {

        const uint16* number1 = lhs->number;
        const uint16* number2 = rhs->number;
        const uint16* end = number2 + rhs->digits_used;
        uint16* r = result->number;

        uint32 temp =0;

        while (number2 != end)
        {

            // subtract *number2 from *number1 and then subtract any carry
            temp = *number1 - *number2 - (temp>>31);

            // put the low word of temp into *r
            *r = static_cast<uint16>(temp & 0xFFFF);

            ++number1;
            ++number2;
            ++r;
        }

        end = lhs->number + lhs->digits_used;
        while (number1 != end)
        {

            // subtract the carry from *number1
            temp = *number1 - (temp>>31);

            // put the low word of temp into *r
            *r = static_cast<uint16>(temp & 0xFFFF);

            ++number1;
            ++r;
        }

        result->digits_used = lhs->digits_used;
        // adjust the number of digits used appropriately
        --r;
        while (*r == 0 && result->digits_used > 1)
        {
            --r;
            --result->digits_used;
        }
    }

// ----------------------------------------------------------------------------------------

    void bigint_kernel_1::
    long_div (
        const data_record* lhs,
        const data_record* rhs,
        data_record* result,
        data_record* remainder
    ) const
    {
        // zero result
        result->digits_used = 1;
        *(result->number) = 0;

        uint16* a;
        uint16* b;
        uint16* end;

        // copy lhs into remainder
        remainder->digits_used = lhs->digits_used;
        a = remainder->number;
        end = a + remainder->digits_used;
        b = lhs->number;
        while (a != end)
        {
            *a = *b;
            ++a;
            ++b;
        }

        // if rhs is bigger than lhs then result == 0 and remainder == lhs
        // so then we can quit right now
        if (is_less_than(lhs,rhs))
        {
            return;
        }

        // make a temporary number
        data_record temp(lhs->digits_used + slack);

        // shift rhs left until it is one shift away from being larger than lhs and
        // put the number of left shifts necessary into shifts
        uint32 shifts;
        shifts = (lhs->digits_used - rhs->digits_used) * 16;

        shift_left(rhs,&temp,shifts);

        // while (lhs > temp)
        while (is_less_than(&temp,lhs))
        {
            shift_left(&temp,&temp,1);
            ++shifts;
        }
        // make sure lhs isn't smaller than temp
        while (is_less_than(lhs,&temp))
        {
            shift_right(&temp,&temp);
            --shifts;
        }

        // we want to execute the loop shifts +1 times
        ++shifts;
        while (shifts != 0)
        {
            shift_left(result,result,1);
            // if (temp <= remainder)
            if (!is_less_than(remainder,&temp))
            {
                long_sub(remainder,&temp,remainder);

                // increment result
                uint16* r = result->number;
                uint16* end = r + result->digits_used;
                while (true)
                {
                    ++(*r);
                    // if there was no carry then we are done
                    if (*r != 0)
                        break;

                    ++r;

                    // if we hit the end of r and there is still a carry then
                    // the next digit of r is 1 and there is one more digit used
                    if (r == end)
                    {
                        *r = 1;
                        ++(result->digits_used);
                        break;
                    }
                }
            }
            shift_right(&temp,&temp);
            --shifts;
        }

    }

// ----------------------------------------------------------------------------------------

    void bigint_kernel_1::
    long_mul (
        const data_record* lhs,
        const data_record* rhs,
        data_record* result
    ) const
    {
        // make result be zero
        result->digits_used = 1;
        *(result->number) = 0;

        const data_record* aa;
        const data_record* bb;

        if (lhs->digits_used < rhs->digits_used)
        {
            // make copies of lhs and rhs and give them an appropriate amount of
            // extra memory so there won't be any overflows
            aa = lhs;
            bb = rhs;
        }
        else
        {
            // make copies of lhs and rhs and give them an appropriate amount of
            // extra memory so there won't be any overflows
            aa = rhs;
            bb = lhs;
        }
        // this is where we actually copy lhs and rhs
        data_record b(*bb,aa->digits_used+slack); // the larger(approximately) of lhs and rhs

        uint32 shift_value = 0;
        uint16* anum = aa->number;
        uint16* end = anum + aa->digits_used;
        while (anum != end )
        {
            uint16 bit = 0x0001;

            for (int i = 0; i < 16; ++i)
            {
                // if the specified bit of a is 1
                if ((*anum & bit) != 0)
                {
                    shift_left(&b,&b,shift_value);
                    shift_value = 0;
                    long_add(&b,result,result);
                }
                ++shift_value;
                bit <<= 1;
            }

            ++anum;
        }
    }

// ----------------------------------------------------------------------------------------

    void bigint_kernel_1::
    shift_left (
        const data_record* data,
        data_record* result,
        uint32 shift_amount
    ) const
    {
        uint32 offset = shift_amount/16;
        shift_amount &= 0xf;  // same as shift_amount %= 16;

        uint16* r = result->number + data->digits_used + offset; // result
        uint16* end = data->number;
        uint16* s = end + data->digits_used; // source
        const uint32 temp = 16 - shift_amount;

        *r = (*(--s) >> temp);
        // set the number of digits used in the result
        // if the upper bits from *s were zero then don't count this first word
        if (*r == 0)
        {
            result->digits_used = data->digits_used + offset;
        }
        else
        {
            result->digits_used = data->digits_used + offset + 1;
        }
        --r;

        while (s != end)
        {
            *r = ((*s << shift_amount) | ( *(s-1) >> temp));
            --r;
            --s;
        }
        *r = *s << shift_amount;

        // now zero the rest of the result
        end = result->number;
        while (r != end)
            *(--r) = 0;

    }

// ----------------------------------------------------------------------------------------

    void bigint_kernel_1::
    shift_right (
        const data_record* data,
        data_record* result
    ) const
    {

            uint16* r = result->number; // result
            uint16* s = data->number; // source
            uint16* end = s + data->digits_used - 1;

            while (s != end)
            {
                *r = (*s >> 1) | (*(s+1) << 15);
                ++r;
                ++s;
            }
            *r = *s >> 1;

            // calculate the new number for digits_used
            if (*r == 0)
            {
                if (data->digits_used != 1)
                    result->digits_used = data->digits_used - 1;
                else
                    result->digits_used = 1;
            }
            else
            {
                result->digits_used = data->digits_used;
            }

    }

// ----------------------------------------------------------------------------------------

    bool bigint_kernel_1::
    is_less_than (
        const data_record* lhs,
        const data_record* rhs
    ) const
    {
        uint32 lhs_digits_used = lhs->digits_used;
        uint32 rhs_digits_used = rhs->digits_used;

        // if lhs is definitely less than rhs
        if (lhs_digits_used < rhs_digits_used )
            return true;
        // if lhs is definitely greater than rhs
        else if (lhs_digits_used > rhs_digits_used)
            return false;
        else
        {
            uint16* end = lhs->number;
            uint16* l = end         + lhs_digits_used;
            uint16* r = rhs->number + rhs_digits_used;

            while (l != end)
            {
                --l;
                --r;
                if (*l < *r)
                    return true;
                else if (*l > *r)
                    return false;
            }

            // at this point we know that they are equal
            return false;
        }

    }

// ----------------------------------------------------------------------------------------

    bool bigint_kernel_1::
    is_equal_to (
        const data_record* lhs,
        const data_record* rhs
    ) const
    {
        // if lhs and rhs are definitely not equal
        if (lhs->digits_used != rhs->digits_used )
        {
            return false;
        }
        else
        {
            uint16* l = lhs->number;
            uint16* r = rhs->number;
            uint16* end = l + lhs->digits_used;

            while (l != end)
            {
                if (*l != *r)
                    return false;
                ++l;
                ++r;
            }

            // at this point we know that they are equal
            return true;
        }

    }

// ----------------------------------------------------------------------------------------

    void bigint_kernel_1::
    increment (
        const data_record* source,
        data_record* dest
    ) const
    {
        uint16* s = source->number;
        uint16* d = dest->number;
        uint16* end = s + source->digits_used;
        while (true)
        {
            *d = *s + 1;

            // if there was no carry then break out of the loop
            if (*d != 0)
            {
                dest->digits_used = source->digits_used;

                // copy the rest of the digits over to d
                ++d; ++s;
                while (s != end)
                {
                    *d = *s;
                    ++d;
                    ++s;
                }

                break;
            }

            ++s;

            // if we have hit the end of s and there was a carry up to this point
            // then just make the next digit 1 and add one to the digits used
            if (s == end)
            {
                ++d;
                dest->digits_used = source->digits_used + 1;
                *d = 1;
                break;
            }

            ++d;
        }
    }

// ----------------------------------------------------------------------------------------

    void bigint_kernel_1::
    decrement (
        const data_record* source,
        data_record* dest
    ) const
    {
        uint16* s = source->number;
        uint16* d = dest->number;
        uint16* end = s + source->digits_used;
        while (true)
        {
            *d = *s - 1;

            // if there was no carry then break out of the loop
            if (*d != 0xFFFF)
            {
                // if we lost a digit in the subtraction
                if (*d == 0 && s+1 == end)
                {
                    if (source->digits_used == 1)
                        dest->digits_used = 1;
                    else
                        dest->digits_used = source->digits_used - 1;
                }
                else
                {
                    dest->digits_used = source->digits_used;
                }
                break;
            }
            else
            {
                ++d;
                ++s;
            }

        }

        // copy the rest of the digits over to d
        ++d;
        ++s;
        while (s != end)
        {
            *d = *s;
            ++d;
            ++s;
        }
    }

// ----------------------------------------------------------------------------------------

}
#endif // DLIB_BIGINT_KERNEL_1_CPp_


dlib C++ Library - bigint_kernel_1.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_BIGINT_KERNEl_1_
#define DLIB_BIGINT_KERNEl_1_

#include "bigint_kernel_abstract.h"
#include "../algs.h"
#include "../serialize.h"
#include "../uintn.h"
#include <iosfwd>

namespace dlib
{

    using namespace dlib::relational_operators; // defined in algs.h

    class bigint_kernel_1
    {
        /*!
            INITIAL VALUE
                slack               == 25
                data->number[0]     == 0
                data->size          == slack
                data->references    == 1
                data->digits_used   == 1

            CONVENTION
                slack  == the number of extra digits placed into the number when it is
                    created.  the slack value should never be less than 1

                data->number == pointer to an array of data->size uint16s.
                    data represents a string of base 65535 numbers with data[0] being
                    the least significant bit and data[data->digits_used-1] being the most
                    significant

                NOTE: In the comments I will consider a word to be a 16 bit value

                data->digits_used == the number of significant digits in the number.
                    data->digits_used tells us the number of used elements in the
                    data->number array so everything beyond data->number[data->digits_used-1]
                    is undefined

                data->references == the number of bigint_kernel_1 objects which refer
                    to this data_record

        !*/

        struct data_record
        {

            explicit data_record(
                uint32 size_
            ) :
                size(size_),
                number(new uint16[size_]),
                references(1),
                digits_used(1)
            {*number = 0;}
            /*!
                ensures
                    - initializes *this to represent zero
            !*/

            data_record(
                const data_record& item,
                uint32 additional_size
            ) :
                size(item.digits_used + additional_size),
                number(new uint16[size]),
                references(1),
                digits_used(item.digits_used)
            {
                uint16* source = item.number;
                uint16* dest = number;
                uint16* end = source + digits_used;
                while (source != end)
                {
                    *dest = *source;
                    ++dest;
                    ++source;
                }
            }
            /*!
                ensures
                    - *this is a copy of item except with
                      size == item.digits_used + additional_size
            !*/

            ~data_record(
            )
            {
                delete [] number;
            }

            const uint32 size;
            uint16* number;
            uint32 references;
            uint32 digits_used;

        private:
            // no copy constructor
            data_record ( data_record&);
        };

        // note that the second parameter is just there
        // to resolve the ambiguity between this constructor and
        // bigint_kernel_1(uint32)
        explicit bigint_kernel_1 (
            data_record* data_, int
        ): slack(25),data(data_) {}
        /*!
            ensures
                - *this is initialized with data_ as its data member
        !*/

    public:

        bigint_kernel_1 (
        );

        bigint_kernel_1 (
            uint32 value
        );

        bigint_kernel_1 (
            const bigint_kernel_1& item
        );

        virtual ~bigint_kernel_1 (
        );

        const bigint_kernel_1 operator+ (
            const bigint_kernel_1& rhs
        ) const;

        bigint_kernel_1& operator+= (
            const bigint_kernel_1& rhs
        );

        const bigint_kernel_1 operator- (
            const bigint_kernel_1& rhs
        ) const;

        bigint_kernel_1& operator-= (
            const bigint_kernel_1& rhs
        );

        const bigint_kernel_1 operator* (
            const bigint_kernel_1& rhs
        ) const;

        bigint_kernel_1& operator*= (
            const bigint_kernel_1& rhs
        );

        const bigint_kernel_1 operator/ (
            const bigint_kernel_1& rhs
        ) const;

        bigint_kernel_1& operator/= (
            const bigint_kernel_1& rhs
        );

        const bigint_kernel_1 operator% (
            const bigint_kernel_1& rhs
        ) const;

        bigint_kernel_1& operator%= (
            const bigint_kernel_1& rhs
        );

        bool operator < (
            const bigint_kernel_1& rhs
        ) const;

        bool operator == (
            const bigint_kernel_1& rhs
        ) const;

        bigint_kernel_1& operator= (
            const bigint_kernel_1& rhs
        );

        friend std::ostream& operator<< (
            std::ostream& out,
            const bigint_kernel_1& rhs
        );

        friend std::istream& operator>> (
            std::istream& in,
            bigint_kernel_1& rhs
        );

        bigint_kernel_1& operator++ (
        );

        const bigint_kernel_1 operator++ (
            int
        );

        bigint_kernel_1& operator-- (
        );

        const bigint_kernel_1 operator-- (
            int
        );

        friend const bigint_kernel_1 operator+ (
            uint16 lhs,
            const bigint_kernel_1& rhs
        );

        friend const bigint_kernel_1 operator+ (
            const bigint_kernel_1& lhs,
            uint16 rhs
        );

        bigint_kernel_1& operator+= (
            uint16 rhs
        );

        friend const bigint_kernel_1 operator- (
            uint16 lhs,
            const bigint_kernel_1& rhs
        );

        friend const bigint_kernel_1 operator- (
            const bigint_kernel_1& lhs,
            uint16 rhs
        );

        bigint_kernel_1& operator-= (
            uint16 rhs
        );

        friend const bigint_kernel_1 operator* (
            uint16 lhs,
            const bigint_kernel_1& rhs
        );

        friend const bigint_kernel_1 operator* (
            const bigint_kernel_1& lhs,
            uint16 rhs
        );

        bigint_kernel_1& operator*= (
            uint16 rhs
        );

        friend const bigint_kernel_1 operator/ (
            uint16 lhs,
            const bigint_kernel_1& rhs
        );

        friend const bigint_kernel_1 operator/ (
            const bigint_kernel_1& lhs,
            uint16 rhs
        );

        bigint_kernel_1& operator/= (
            uint16 rhs
        );

        friend const bigint_kernel_1 operator% (
            uint16 lhs,
            const bigint_kernel_1& rhs
        );

        friend const bigint_kernel_1 operator% (
            const bigint_kernel_1& lhs,
            uint16 rhs
        );

        bigint_kernel_1& operator%= (
            uint16 rhs
        );

        friend bool operator < (
            uint16 lhs,
            const bigint_kernel_1& rhs
        );

        friend bool operator < (
            const bigint_kernel_1& lhs,
            uint16 rhs
        );

        friend bool operator == (
            const bigint_kernel_1& lhs,
            uint16 rhs
        );

        friend bool operator == (
            uint16 lhs,
            const bigint_kernel_1& rhs
        );

        bigint_kernel_1& operator= (
            uint16 rhs
        );

        void swap (
            bigint_kernel_1& item
        ) { data_record* temp = data; data = item.data; item.data = temp; }

    private:

        void long_add (
            const data_record* lhs,
            const data_record* rhs,
            data_record* result
        ) const;
        /*!
            requires
                - result->size >= max(lhs->digits_used,rhs->digits_used) + 1
            ensures
                - result == lhs + rhs
        !*/

        void long_sub (
            const data_record* lhs,
            const data_record* rhs,
            data_record* result
        ) const;
        /*!
            requires
                - lhs >= rhs
                - result->size >= lhs->digits_used
            ensures
                - result == lhs - rhs
        !*/

        void long_div (
            const data_record* lhs,
            const data_record* rhs,
            data_record* result,
            data_record* remainder
        ) const;
        /*!
            requires
                - rhs != 0
                - result->size >= lhs->digits_used
                - remainder->size >= lhs->digits_used
                - each parameter is unique (i.e. lhs != result, lhs != remainder, etc.)
            ensures
                - result == lhs / rhs
                - remainder == lhs % rhs
        !*/

        void long_mul (
            const data_record* lhs,
            const data_record* rhs,
            data_record* result
        ) const;
        /*!
            requires
                - result->size >= lhs->digits_used + rhs->digits_used
                - result != lhs
                - result != rhs
            ensures
                - result == lhs * rhs
        !*/

        void short_add (
            const data_record* data,
            uint16 value,
            data_record* result
        ) const;
        /*!
            requires
                - result->size >= data->size + 1
            ensures
                - result == data + value
        !*/

        void short_sub (
            const data_record* data,
            uint16 value,
            data_record* result
        ) const;
        /*!
            requires
                - data >= value
                - result->size >= data->digits_used
            ensures
                - result == data - value
        !*/

        void short_mul (
            const data_record* data,
            uint16 value,
            data_record* result
        ) const;
        /*!
            requires
                - result->size >= data->digits_used + 1
            ensures
                - result == data * value
        !*/

        void short_div (
            const data_record* data,
            uint16 value,
            data_record* result,
            uint16& remainder
        ) const;
        /*!
            requires
                - value != 0
                - result->size >= data->digits_used
            ensures
                - result = data*value
                - remainder = data%value
        !*/

        void shift_left (
            const data_record* data,
            data_record* result,
            uint32 shift_amount
        ) const;
        /*!
            requires
                - result->size >= data->digits_used + shift_amount/8 + 1
            ensures
                - result == data << shift_amount
        !*/

        void shift_right (
            const data_record* data,
            data_record* result
        ) const;
        /*!
            requires
                - result->size >= data->digits_used
            ensures
                - result == data >> 1
        !*/

        bool is_less_than (
            const data_record* lhs,
            const data_record* rhs
        ) const;
        /*!
            ensures
                - returns true if lhs < rhs
                - returns false otherwise
        !*/

        bool is_equal_to (
            const data_record* lhs,
            const data_record* rhs
        ) const;
        /*!
            ensures
                - returns true if lhs == rhs
                - returns false otherwise
        !*/

        void increment (
            const data_record* source,
            data_record* dest
        ) const;
        /*!
            requires
                - dest->size >= source->digits_used + 1
            ensures
                - dest = source + 1
        !*/

        void decrement (
            const data_record* source,
            data_record* dest
        ) const;
        /*!
            requires
                source != 0
            ensuers
                dest = source - 1
        !*/

        // member data
        const uint32 slack;
        data_record* data;

    };

    inline void swap (
        bigint_kernel_1& a,
        bigint_kernel_1& b
    ) { a.swap(b); }

    inline void serialize (
        const bigint_kernel_1& item,
        std::ostream& out
    )
    {
        std::ios::fmtflags oldflags = out.flags();
        out.flags();
        out << item << ' ';
        out.flags(oldflags);
        if (!out) throw serialization_error("Error serializing object of type bigint_kernel_c");
    }

    inline void deserialize (
        bigint_kernel_1& item,
        std::istream& in
    )
    {
        std::ios::fmtflags oldflags = in.flags();
        in.flags();
        in >> item; in.flags(oldflags);
        if (in.get() != ' ')
        {
            item = 0;
            throw serialization_error("Error deserializing object of type bigint_kernel_c");
        }
    }

}

#ifdef NO_MAKEFILE
#include "bigint_kernel_1.cpp"
#endif

#endif // DLIB_BIGINT_KERNEl_1_


dlib C++ Library - bigint_kernel_2.cpp

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_BIGINT_KERNEL_2_CPp_
#define DLIB_BIGINT_KERNEL_2_CPp_
#include "bigint_kernel_2.h"

#include <iostream>
#include <cmath>

namespace dlib
{

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member/friend function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    bigint_kernel_2::
    bigint_kernel_2 (
    ) :
        slack(25),
        data(new data_record(slack))
    {}

// ----------------------------------------------------------------------------------------

    bigint_kernel_2::
    bigint_kernel_2 (
        uint32 value
    ) :
        slack(25),
        data(new data_record(slack))
    {
        *(data->number) = static_cast<uint16>(value&0xFFFF);
        *(data->number+1) = static_cast<uint16>((value>>16)&0xFFFF);
        if (*(data->number+1) != 0)
            data->digits_used = 2;
    }

// ----------------------------------------------------------------------------------------

    bigint_kernel_2::
    bigint_kernel_2 (
        const bigint_kernel_2& item
    ) :
        slack(25),
        data(item.data)
    {
        data->references += 1;
    }

// ----------------------------------------------------------------------------------------

    bigint_kernel_2::
    ~bigint_kernel_2 (
    )
    {
        if (data->references == 1)
        {
            delete data;
        }
        else
        {
            data->references -= 1;
        }
    }

// ----------------------------------------------------------------------------------------

    const bigint_kernel_2 bigint_kernel_2::
    operator+ (
        const bigint_kernel_2& rhs
    ) const
    {
        data_record* temp = new data_record (
                    std::max(rhs.data->digits_used,data->digits_used) + slack
                    );
        long_add(data,rhs.data,temp);
        return bigint_kernel_2(temp,0);
    }

// ----------------------------------------------------------------------------------------

    bigint_kernel_2& bigint_kernel_2::
    operator+= (
        const bigint_kernel_2& rhs
    )
    {
        // if there are other references to our data
        if (data->references != 1)
        {
            data_record* temp = new data_record(std::max(data->digits_used,rhs.data->digits_used)+slack);
            data->references -= 1;
            long_add(data,rhs.data,temp);
            data = temp;
        }
        // if data is not big enough for the result
        else if (data->size <= std::max(data->digits_used,rhs.data->digits_used))
        {
            data_record* temp = new data_record(std::max(data->digits_used,rhs.data->digits_used)+slack);
            long_add(data,rhs.data,temp);
            delete data;
            data = temp;
        }
        // there is enough size and no references
        else
        {
            long_add(data,rhs.data,data);
        }
        return *this;
    }

// ----------------------------------------------------------------------------------------

    const bigint_kernel_2 bigint_kernel_2::
    operator- (
        const bigint_kernel_2& rhs
    ) const
    {
        data_record* temp = new data_record (
                    data->digits_used + slack
                    );
        long_sub(data,rhs.data,temp);
        return bigint_kernel_2(temp,0);
    }

// ----------------------------------------------------------------------------------------

    bigint_kernel_2& bigint_kernel_2::
    operator-= (
        const bigint_kernel_2& rhs
    )
    {
        // if there are other references to this data
        if (data->references != 1)
        {
            data_record* temp = new data_record(data->digits_used+slack);
            data->references -= 1;
            long_sub(data,rhs.data,temp);
            data = temp;
        }
        else
        {
            long_sub(data,rhs.data,data);
        }
        return *this;
    }

// ----------------------------------------------------------------------------------------

    const bigint_kernel_2 bigint_kernel_2::
    operator* (
        const bigint_kernel_2& rhs
    ) const
    {
        data_record* temp = new data_record (
                    data->digits_used + rhs.data->digits_used + slack
                    );
        long_mul(data,rhs.data,temp);
        return bigint_kernel_2(temp,0);
    }

// ----------------------------------------------------------------------------------------

    bigint_kernel_2& bigint_kernel_2::
    operator*= (
        const bigint_kernel_2& rhs
    )
    {
        // create a data_record to store the result of the multiplication in
        data_record* temp = new data_record(rhs.data->digits_used+data->digits_used+slack);
        long_mul(data,rhs.data,temp);

        // if there are other references to data
        if (data->references != 1)
        {
            data->references -= 1;
        }
        else
        {
            delete data;
        }
        data = temp;
        return *this;
    }

// ----------------------------------------------------------------------------------------

    const bigint_kernel_2 bigint_kernel_2::
    operator/ (
        const bigint_kernel_2& rhs
    ) const
    {
        data_record* temp = new data_record(data->digits_used+slack);
        data_record* remainder;
        try {
            remainder = new data_record(data->digits_used+slack);
        } catch (...) { delete temp; throw; }

        long_div(data,rhs.data,temp,remainder);
        delete remainder;

        return bigint_kernel_2(temp,0);
    }

// ----------------------------------------------------------------------------------------

    bigint_kernel_2& bigint_kernel_2::
    operator/= (
        const bigint_kernel_2& rhs
    )
    {

        data_record* temp = new data_record(data->digits_used+slack);
        data_record* remainder;
        try {
            remainder = new data_record(data->digits_used+slack);
        } catch (...) { delete temp; throw; }

        long_div(data,rhs.data,temp,remainder);

        // check if there are other references to data
        if (data->references != 1)
        {
            data->references -= 1;
        }
        // if there are no references to data then it must be deleted
        else
        {
            delete data;
        }
        data = temp;
        delete remainder;

        return *this;
    }

// ----------------------------------------------------------------------------------------

    const bigint_kernel_2 bigint_kernel_2::
    operator% (
        const bigint_kernel_2& rhs
    ) const
    {
        data_record* temp = new data_record(data->digits_used+slack);
        data_record* remainder;
        try {
            remainder = new data_record(data->digits_used+slack);
        } catch (...) { delete temp; throw; }

        long_div(data,rhs.data,temp,remainder);
        delete temp;
        return bigint_kernel_2(remainder,0);
    }

// ----------------------------------------------------------------------------------------

    bigint_kernel_2& bigint_kernel_2::
    operator%= (
        const bigint_kernel_2& rhs
    )
    {
        data_record* temp = new data_record(data->digits_used+slack);
        data_record* remainder;
        try {
            remainder = new data_record(data->digits_used+slack);
        } catch (...) { delete temp; throw; }

        long_div(data,rhs.data,temp,remainder);

        // check if there are other references to data
        if (data->references != 1)
        {
            data->references -= 1;
        }
        // if there are no references to data then it must be deleted
        else
        {
            delete data;
        }
        data = remainder;
        delete temp;
        return *this;
    }

// ----------------------------------------------------------------------------------------

    bool bigint_kernel_2::
    operator < (
        const bigint_kernel_2& rhs
    ) const
    {
        return is_less_than(data,rhs.data);
    }

// ----------------------------------------------------------------------------------------

    bool bigint_kernel_2::
    operator == (
        const bigint_kernel_2& rhs
    ) const
    {
        return is_equal_to(data,rhs.data);
    }

// ----------------------------------------------------------------------------------------

    bigint_kernel_2& bigint_kernel_2::
    operator= (
        const bigint_kernel_2& rhs
    )
    {
        if (this == &rhs)
            return *this;

        // if we have the only reference to our data then delete it
        if (data->references == 1)
        {
            delete data;
            data = rhs.data;
            data->references += 1;
        }
        else
        {
            data->references -= 1;
            data = rhs.data;
            data->references += 1;
        }

        return *this;
    }

// ----------------------------------------------------------------------------------------

    std::ostream& operator<< (
        std::ostream& out_,
        const bigint_kernel_2& rhs
    )
    {
        std::ostream out(out_.rdbuf());

        typedef bigint_kernel_2 bigint;

        bigint::data_record* temp = new bigint::data_record(*rhs.data,0);

        // get a char array big enough to hold the number in ascii format
        char* str;
        try {
            str = new char[(rhs.data->digits_used)*5+10];
        } catch (...) { delete temp; throw; }

        char* str_start = str;
        str += (rhs.data->digits_used)*5+9;
        *str = 0; --str;

        uint16 remainder;
        rhs.short_div(temp,10000,temp,remainder);

        // pull the digits out of remainder
        char a = remainder % 10 + '0';
        remainder /= 10;
        char b = remainder % 10 + '0';
        remainder /= 10;
        char c = remainder % 10 + '0';
        remainder /= 10;
        char d = remainder % 10 + '0';
        remainder /= 10;

        *str = a; --str;
        *str = b; --str;
        *str = c; --str;
        *str = d; --str;

        // keep looping until temp represents zero
        while (temp->digits_used != 1 || *(temp->number) != 0)
        {
            rhs.short_div(temp,10000,temp,remainder);

            // pull the digits out of remainder
            char a = remainder % 10 + '0';
            remainder /= 10;
            char b = remainder % 10 + '0';
            remainder /= 10;
            char c = remainder % 10 + '0';
            remainder /= 10;
            char d = remainder % 10 + '0';
            remainder /= 10;

            *str = a; --str;
            *str = b; --str;
            *str = c; --str;
            *str = d; --str;
        }

        // throw away and extra leading zeros
        ++str;
        if (*str == '0')
            ++str;
        if (*str == '0')
            ++str;
        if (*str == '0')
            ++str;

        out << str;
        delete [] str_start;
        delete temp;
        return out_;

    }

// ----------------------------------------------------------------------------------------

    std::istream& operator>> (
        std::istream& in_,
        bigint_kernel_2& rhs
    )
    {
        std::istream in(in_.rdbuf());

        // ignore any leading whitespaces
        while (in.peek() == ' ' || in.peek() == '\t' || in.peek() == '\n')
        {
            in.get();
        }

        // if the first digit is not an integer then this is an error
        if ( !(in.peek() >= '0' && in.peek() <= '9'))
        {
            in_.clear(std::ios::failbit);
            return in_;
        }

        int num_read;
        bigint_kernel_2 temp;
        do
        {

            // try to get 4 chars from in
            num_read = 1;
            char a = 0;
            char b = 0;
            char c = 0;
            char d = 0;

            if (in.peek() >= '0' && in.peek() <= '9')
            {
                num_read *= 10;
                a = in.get();
            }
            if (in.peek() >= '0' && in.peek() <= '9')
            {
                num_read *= 10;
                b = in.get();
            }
            if (in.peek() >= '0' && in.peek() <= '9')
            {
                num_read *= 10;
                c = in.get();
            }
            if (in.peek() >= '0' && in.peek() <= '9')
            {
                num_read *= 10;
                d = in.get();
            }

            // merge the for digits into an uint16
            uint16 num = 0;
            if (a != 0)
            {
                num = a - '0';
            }
            if (b != 0)
            {
                num *= 10;
                num += b - '0';
            }
            if (c != 0)
            {
                num *= 10;
                num += c - '0';
            }
            if (d != 0)
            {
                num *= 10;
                num += d - '0';
            }

            if (num_read != 1)
            {
                // shift the digits in temp left by the number of new digits we just read
                temp *= num_read;
                // add in new digits
                temp += num;
            }

        } while (num_read == 10000);

        rhs = temp;
        return in_;
    }

// ----------------------------------------------------------------------------------------

    const bigint_kernel_2 operator+ (
        uint16 lhs,
        const bigint_kernel_2& rhs
    )
    {
        typedef bigint_kernel_2 bigint;
        bigint::data_record* temp = new bigint::data_record
                (rhs.data->digits_used+rhs.slack);

        rhs.short_add(rhs.data,lhs,temp);
        return bigint_kernel_2(temp,0);
    }

// ----------------------------------------------------------------------------------------

    const bigint_kernel_2 operator+ (
        const bigint_kernel_2& lhs,
        uint16 rhs
    )
    {
        typedef bigint_kernel_2 bigint;
        bigint::data_record* temp = new bigint::data_record
                (lhs.data->digits_used+lhs.slack);

        lhs.short_add(lhs.data,rhs,temp);
        return bigint_kernel_2(temp,0);
    }

// ----------------------------------------------------------------------------------------

    bigint_kernel_2& bigint_kernel_2::
    operator+= (
        uint16 rhs
    )
    {
        // if there are other references to this data
        if (data->references != 1)
        {
            data_record* temp = new data_record(data->digits_used+slack);
            data->references -= 1;
            short_add(data,rhs,temp);
            data = temp;
        }
        // or if we need to enlarge data then do so
        else if (data->digits_used == data->size)
        {
            data_record* temp = new data_record(data->digits_used+slack);
            short_add(data,rhs,temp);
            delete data;
            data = temp;
        }
        // or if there is plenty of space and no references
        else
        {
            short_add(data,rhs,data);
        }
        return *this;
    }

// ----------------------------------------------------------------------------------------

    const bigint_kernel_2 operator- (
        uint16 lhs,
        const bigint_kernel_2& rhs
    )
    {
        typedef bigint_kernel_2 bigint;
        bigint::data_record* temp = new bigint::data_record(rhs.slack);

        *(temp->number) = lhs - *(rhs.data->number);

        return bigint_kernel_2(temp,0);
    }

// ----------------------------------------------------------------------------------------

    const bigint_kernel_2 operator- (
        const bigint_kernel_2& lhs,
        uint16 rhs
    )
    {
        typedef bigint_kernel_2 bigint;
        bigint::data_record* temp = new bigint::data_record
                (lhs.data->digits_used+lhs.slack);

        lhs.short_sub(lhs.data,rhs,temp);
        return bigint_kernel_2(temp,0);
    }

// ----------------------------------------------------------------------------------------

    bigint_kernel_2& bigint_kernel_2::
    operator-= (
        uint16 rhs
    )
    {
        // if there are other references to this data
        if (data->references != 1)
        {
            data_record* temp = new data_record(data->digits_used+slack);
            data->references -= 1;
            short_sub(data,rhs,temp);
            data = temp;
        }
        else
        {
            short_sub(data,rhs,data);
        }
        return *this;
    }

// ----------------------------------------------------------------------------------------

    const bigint_kernel_2 operator* (
        uint16 lhs,
        const bigint_kernel_2& rhs
    )
    {
        typedef bigint_kernel_2 bigint;
        bigint::data_record* temp = new bigint::data_record
                (rhs.data->digits_used+rhs.slack);

        rhs.short_mul(rhs.data,lhs,temp);
        return bigint_kernel_2(temp,0);
    }

// ----------------------------------------------------------------------------------------

    const bigint_kernel_2 operator* (
        const bigint_kernel_2& lhs,
        uint16 rhs
    )
    {
        typedef bigint_kernel_2 bigint;
        bigint::data_record* temp = new bigint::data_record
                (lhs.data->digits_used+lhs.slack);

        lhs.short_mul(lhs.data,rhs,temp);
        return bigint_kernel_2(temp,0);
    }

// ----------------------------------------------------------------------------------------

    bigint_kernel_2& bigint_kernel_2::
    operator*= (
        uint16 rhs
    )
    {
        // if there are other references to this data
        if (data->references != 1)
        {
            data_record* temp = new data_record(data->digits_used+slack);
            data->references -= 1;
            short_mul(data,rhs,temp);
            data = temp;
        }
        // or if we need to enlarge data
        else if (data->digits_used == data->size)
        {
            data_record* temp = new data_record(data->digits_used+slack);
            short_mul(data,rhs,temp);
            delete data;
            data = temp;
        }
        else
        {
            short_mul(data,rhs,data);
        }
        return *this;
    }

// ----------------------------------------------------------------------------------------

    const bigint_kernel_2 operator/ (
        uint16 lhs,
        const bigint_kernel_2& rhs
    )
    {
        typedef bigint_kernel_2 bigint;
        bigint::data_record* temp = new bigint::data_record(rhs.slack);

        // if rhs might not be bigger than lhs
        if (rhs.data->digits_used == 1)
        {
            *(temp->number) = lhs/ *(rhs.data->number);
        }

        return bigint_kernel_2(temp,0);
    }

// ----------------------------------------------------------------------------------------

    const bigint_kernel_2 operator/ (
        const bigint_kernel_2& lhs,
        uint16 rhs
    )
    {
        typedef bigint_kernel_2 bigint;
        bigint::data_record* temp = new bigint::data_record
                (lhs.data->digits_used+lhs.slack);

        uint16 remainder;
        lhs.short_div(lhs.data,rhs,temp,remainder);
        return bigint_kernel_2(temp,0);
    }

// ----------------------------------------------------------------------------------------

    bigint_kernel_2& bigint_kernel_2::
    operator/= (
        uint16 rhs
    )
    {
        uint16 remainder;
        // if there are other references to this data
        if (data->references != 1)
        {
            data_record* temp = new data_record(data->digits_used+slack);
            data->references -= 1;
            short_div(data,rhs,temp,remainder);
            data = temp;
        }
        else
        {
            short_div(data,rhs,data,remainder);
        }
        return *this;
    }

// ----------------------------------------------------------------------------------------

    const bigint_kernel_2 operator% (
        uint16 lhs,
        const bigint_kernel_2& rhs
    )
    {
        typedef bigint_kernel_2 bigint;
        // temp is zero by default
        bigint::data_record* temp = new bigint::data_record(rhs.slack);

        if (rhs.data->digits_used == 1)
        {
            // if rhs is just an uint16 inside then perform the modulus
            *(temp->number) = lhs % *(rhs.data->number);
        }
        else
        {
            // if rhs is bigger than lhs then the answer is lhs
            *(temp->number) = lhs;
        }

        return bigint_kernel_2(temp,0);
    }

// ----------------------------------------------------------------------------------------

    const bigint_kernel_2 operator% (
        const bigint_kernel_2& lhs,
        uint16 rhs
    )
    {
        typedef bigint_kernel_2 bigint;
        bigint::data_record* temp = new bigint::data_record(lhs.data->digits_used+lhs.slack);

        uint16 remainder;

        lhs.short_div(lhs.data,rhs,temp,remainder);
        temp->digits_used = 1;
        *(temp->number) = remainder;
        return bigint_kernel_2(temp,0);
    }

// ----------------------------------------------------------------------------------------

    bigint_kernel_2& bigint_kernel_2::
    operator%= (
        uint16 rhs
    )
    {
        uint16 remainder;
        // if there are other references to this data
        if (data->references != 1)
        {
            data_record* temp = new data_record(data->digits_used+slack);
            data->references -= 1;
            short_div(data,rhs,temp,remainder);
            data = temp;
        }
        else
        {
            short_div(data,rhs,data,remainder);
        }

        data->digits_used = 1;
        *(data->number) = remainder;
        return *this;
    }

// ----------------------------------------------------------------------------------------

    bool operator < (
        uint16 lhs,
        const bigint_kernel_2& rhs
    )
    {
        return (rhs.data->digits_used > 1 || lhs < *(rhs.data->number) );
    }

// ----------------------------------------------------------------------------------------

    bool operator < (
        const bigint_kernel_2& lhs,
        uint16 rhs
    )
    {
        return (lhs.data->digits_used == 1 && *(lhs.data->number) < rhs);
    }

// ----------------------------------------------------------------------------------------

    bool operator == (
        const bigint_kernel_2& lhs,
        uint16 rhs
    )
    {
        return (lhs.data->digits_used == 1 && *(lhs.data->number) == rhs);
    }

// ----------------------------------------------------------------------------------------

    bool operator == (
        uint16 lhs,
        const bigint_kernel_2& rhs
    )
    {
        return (rhs.data->digits_used == 1 && *(rhs.data->number) == lhs);
    }

// ----------------------------------------------------------------------------------------

    bigint_kernel_2& bigint_kernel_2::
    operator= (
        uint16 rhs
    )
    {
        // check if there are other references to our data
        if (data->references != 1)
        {
            data->references -= 1;
            try {
                data = new data_record(slack);
            } catch (...) { data->references += 1; throw; }
        }
        else
        {
            data->digits_used = 1;
        }

        *(data->number) = rhs;

        return *this;
    }

// ----------------------------------------------------------------------------------------

    bigint_kernel_2& bigint_kernel_2::
    operator++ (
    )
    {
        // if there are other references to this data then make a copy of it
        if (data->references != 1)
        {
            data_record* temp = new data_record(data->digits_used+slack);
            data->references -= 1;
            increment(data,temp);
            data = temp;
        }
        // or if we need to enlarge data then do so
        else if (data->digits_used == data->size)
        {
            data_record* temp = new data_record(data->digits_used+slack);
            increment(data,temp);
            delete data;
            data = temp;
        }
        else
        {
            increment(data,data);
        }

        return *this;
    }

// ----------------------------------------------------------------------------------------

    const bigint_kernel_2 bigint_kernel_2::
    operator++ (
        int
    )
    {
        data_record* temp; // this is the copy of temp we will return in the end

        data_record* temp2 = new data_record(data->digits_used+slack);
        increment(data,temp2);

        temp = data;
        data = temp2;

        return bigint_kernel_2(temp,0);
    }

// ----------------------------------------------------------------------------------------

    bigint_kernel_2& bigint_kernel_2::
    operator-- (
    )
    {
        // if there are other references to this data
        if (data->references != 1)
        {
            data_record* temp = new data_record(data->digits_used+slack);
            data->references -= 1;
            decrement(data,temp);
            data = temp;
        }
        else
        {
            decrement(data,data);
        }

        return *this;
    }

// ----------------------------------------------------------------------------------------

    const bigint_kernel_2 bigint_kernel_2::
    operator-- (
        int
    )
    {
        data_record* temp; // this is the copy of temp we will return in the end

        data_record* temp2 = new data_record(data->digits_used+slack);
        decrement(data,temp2);

        temp = data;
        data = temp2;

        return bigint_kernel_2(temp,0);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // private member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    void bigint_kernel_2::
    short_add (
        const data_record* data,
        uint16 value,
        data_record* result
    ) const
    {
        // put value into the carry part of temp
        uint32 temp = value;
        temp <<= 16;

        const uint16* number = data->number;
        const uint16* end = number + data->digits_used; // one past the end of number
        uint16* r = result->number;

        while (number != end)
        {
            // add *number and the current carry
            temp = *number + (temp>>16);
            // put the low word of temp into *r
            *r = static_cast<uint16>(temp & 0xFFFF);

            ++number;
            ++r;
        }

        // if there is a final carry
        if ((temp>>16) != 0)
        {
            result->digits_used = data->digits_used + 1;
            // store the carry in the most significant digit of the result
            *r = static_cast<uint16>(temp>>16);
        }
        else
        {
            result->digits_used = data->digits_used;
        }
    }

// ----------------------------------------------------------------------------------------

    void bigint_kernel_2::
    short_sub (
        const data_record* data,
        uint16 value,
        data_record* result
    ) const
    {

        const uint16* number = data->number;
        const uint16* end = number + data->digits_used - 1;
        uint16* r = result->number;

        uint32 temp = *number - value;

        // put the low word of temp into *data
        *r = static_cast<uint16>(temp & 0xFFFF);

        while (number != end)
        {
            ++number;
            ++r;

            // subtract the carry from *number
            temp = *number - (temp>>31);

            // put the low word of temp into *r
            *r = static_cast<uint16>(temp & 0xFFFF);
        }

        // if we lost a digit in the subtraction
        if (*r == 0)
        {
            if (data->digits_used == 1)
                result->digits_used = 1;
            else
                result->digits_used = data->digits_used - 1;
        }
        else
        {
            result->digits_used = data->digits_used;
        }

    }

// ----------------------------------------------------------------------------------------

    void bigint_kernel_2::
    short_mul (
        const data_record* data,
        uint16 value,
        data_record* result
    ) const
    {

        uint32 temp = 0;

        const uint16* number = data->number;
        uint16* r = result->number;
        const uint16* end = r + data->digits_used;

        while ( r != end)
        {

            // multiply *data and value and add in the carry
            temp = *number*(uint32)value + (temp>>16);

            // put the low word of temp into *data
            *r = static_cast<uint16>(temp & 0xFFFF);

            ++number;
            ++r;
        }

        // if there is a final carry
        if ((temp>>16) != 0)
        {
            result->digits_used = data->digits_used + 1;
            // put the final carry into the most significant digit of the result
            *r = static_cast<uint16>(temp>>16);
        }
        else
        {
            result->digits_used = data->digits_used;
        }

    }

// ----------------------------------------------------------------------------------------

    void bigint_kernel_2::
    short_div (
        const data_record* data,
        uint16 value,
        data_record* result,
        uint16& rem
    ) const
    {

        uint16 remainder = 0;
        uint32 temp;

        const uint16* number = data->number + data->digits_used - 1;
        const uint16* end = number - data->digits_used;
        uint16* r = result->number + data->digits_used - 1;

        // if we are losing a digit in this division
        if (*number < value)
        {
            if (data->digits_used == 1)
                result->digits_used = 1;
            else
                result->digits_used = data->digits_used - 1;
        }
        else
        {
            result->digits_used = data->digits_used;
        }

        // perform the actual division
        while (number != end)
        {

            temp = *number + (((uint32)remainder)<<16);

            *r = static_cast<uint16>(temp/value);
            remainder = static_cast<uint16>(temp%value);

            --number;
            --r;
        }

        rem = remainder;
    }

// ----------------------------------------------------------------------------------------

    void bigint_kernel_2::
    long_add (
        const data_record* lhs,
        const data_record* rhs,
        data_record* result
    ) const
    {
        // put value into the carry part of temp
        uint32 temp=0;

        uint16* min_num;  // the number with the least digits used
        uint16* max_num;  // the number with the most digits used
        uint16* min_end;  // one past the end of min_num
        uint16* max_end;  // one past the end of max_num
        uint16* r = result->number;

        uint32 max_digits_used;
        if (lhs->digits_used < rhs->digits_used)
        {
            max_digits_used = rhs->digits_used;
            min_num = lhs->number;
            max_num = rhs->number;
            min_end = min_num + lhs->digits_used;
            max_end = max_num + rhs->digits_used;
        }
        else
        {
            max_digits_used = lhs->digits_used;
            min_num = rhs->number;
            max_num = lhs->number;
            min_end = min_num + rhs->digits_used;
            max_end = max_num + lhs->digits_used;
        }

        while (min_num != min_end)
        {
            // add *min_num, *max_num and the current carry
            temp = *min_num + *max_num + (temp>>16);
            // put the low word of temp into *r
            *r = static_cast<uint16>(temp & 0xFFFF);

            ++min_num;
            ++max_num;
            ++r;
        }

        while (max_num != max_end)
        {
            // add *max_num and the current carry
            temp = *max_num + (temp>>16);
            // put the low word of temp into *r
            *r = static_cast<uint16>(temp & 0xFFFF);

            ++max_num;
            ++r;
        }

        // check if there was a final carry
        if ((temp>>16) != 0)
        {
            result->digits_used = max_digits_used + 1;
            // put the carry into the most significant digit in the result
            *r = static_cast<uint16>(temp>>16);
        }
        else
        {
            result->digits_used = max_digits_used;
        }

    }

// ----------------------------------------------------------------------------------------

    void bigint_kernel_2::
    long_sub (
        const data_record* lhs,
        const data_record* rhs,
        data_record* result
    ) const
    {

        const uint16* number1 = lhs->number;
        const uint16* number2 = rhs->number;
        const uint16* end = number2 + rhs->digits_used;
        uint16* r = result->number;

        uint32 temp =0;

        while (number2 != end)
        {

            // subtract *number2 from *number1 and then subtract any carry
            temp = *number1 - *number2 - (temp>>31);

            // put the low word of temp into *r
            *r = static_cast<uint16>(temp & 0xFFFF);

            ++number1;
            ++number2;
            ++r;
        }

        end = lhs->number + lhs->digits_used;
        while (number1 != end)
        {

            // subtract the carry from *number1
            temp = *number1 - (temp>>31);

            // put the low word of temp into *r
            *r = static_cast<uint16>(temp & 0xFFFF);

            ++number1;
            ++r;
        }

        result->digits_used = lhs->digits_used;
        // adjust the number of digits used appropriately
        --r;
        while (*r == 0 && result->digits_used > 1)
        {
            --r;
            --result->digits_used;
        }
    }

// ----------------------------------------------------------------------------------------

    void bigint_kernel_2::
    long_div (
        const data_record* lhs,
        const data_record* rhs,
        data_record* result,
        data_record* remainder
    ) const
    {
        // zero result
        result->digits_used = 1;
        *(result->number) = 0;

        uint16* a;
        uint16* b;
        uint16* end;

        // copy lhs into remainder
        remainder->digits_used = lhs->digits_used;
        a = remainder->number;
        end = a + remainder->digits_used;
        b = lhs->number;
        while (a != end)
        {
            *a = *b;
            ++a;
            ++b;
        }

        // if rhs is bigger than lhs then result == 0 and remainder == lhs
        // so then we can quit right now
        if (is_less_than(lhs,rhs))
        {
            return;
        }

        // make a temporary number
        data_record temp(lhs->digits_used + slack);

        // shift rhs left until it is one shift away from being larger than lhs and
        // put the number of left shifts necessary into shifts
        uint32 shifts;
        shifts = (lhs->digits_used - rhs->digits_used) * 16;

        shift_left(rhs,&temp,shifts);

        // while (lhs > temp)
        while (is_less_than(&temp,lhs))
        {
            shift_left(&temp,&temp,1);
            ++shifts;
        }
        // make sure lhs isn't smaller than temp
        while (is_less_than(lhs,&temp))
        {
            shift_right(&temp,&temp);
            --shifts;
        }

        // we want to execute the loop shifts +1 times
        ++shifts;
        while (shifts != 0)
        {
            shift_left(result,result,1);
            // if (temp <= remainder)
            if (!is_less_than(remainder,&temp))
            {
                long_sub(remainder,&temp,remainder);

                // increment result
                uint16* r = result->number;
                uint16* end = r + result->digits_used;
                while (true)
                {
                    ++(*r);
                    // if there was no carry then we are done
                    if (*r != 0)
                        break;

                    ++r;

                    // if we hit the end of r and there is still a carry then
                    // the next digit of r is 1 and there is one more digit used
                    if (r == end)
                    {
                        *r = 1;
                        ++(result->digits_used);
                        break;
                    }
                }
            }
            shift_right(&temp,&temp);
            --shifts;
        }

    }

// ----------------------------------------------------------------------------------------

    void bigint_kernel_2::
    long_mul (
        const data_record* lhs,
        const data_record* rhs,
        data_record* result
    ) const
    {
        // if one of the numbers is small then use this simple but O(n^2) algorithm
        if (std::min(lhs->digits_used, rhs->digits_used) < 10)
        {
            // make result be zero
            result->digits_used = 1;
            *(result->number) = 0;

            const data_record* aa;
            const data_record* bb;

            if (lhs->digits_used < rhs->digits_used)
            {
                // make copies of lhs and rhs and give them an appropriate amount of
                // extra memory so there won't be any overflows
                aa = lhs;
                bb = rhs;
            }
            else
            {
                // make copies of lhs and rhs and give them an appropriate amount of
                // extra memory so there won't be any overflows
                aa = rhs;
                bb = lhs;
            }

            // copy the larger(approximately) of lhs and rhs into b
            data_record b(*bb,aa->digits_used+slack);

            uint32 shift_value = 0;
            uint16* anum = aa->number;
            uint16* end = anum + aa->digits_used;
            while (anum != end )
            {
                uint16 bit = 0x0001;

                for (int i = 0; i < 16; ++i)
                {
                    // if the specified bit of a is 1
                    if ((*anum & bit) != 0)
                    {
                        shift_left(&b,&b,shift_value);
                        shift_value = 0;
                        long_add(&b,result,result);
                    }
                    ++shift_value;
                    bit <<= 1;
                }

                ++anum;
            }
        }
        else  // else if both lhs and rhs are large then use the more complex
              // O(n*logn) algorithm
        {
            uint32 size = 1;
            // make size a power of 2
            while (size < (lhs->digits_used + rhs->digits_used)*2)
            {
                size *= 2;
            }

            // allocate some temporary space so we can do the FFT
            ct* a = new ct[size];
            ct* b; try {b = new ct[size]; } catch (...) { delete [] a; throw; }

            // load lhs into the a array.  We are breaking the input number into
            // 8bit chunks for the purpose of using this fft algorithm.  The reason
            // for this is so that we have smaller numbers coming out of the final
            // ifft.  This helps avoid overflow.
            for (uint32 i = 0; i < lhs->digits_used; ++i)
            {
                a[i*2] = ct((t)(lhs->number[i]&0xFF),0);
                a[i*2+1] = ct((t)(lhs->number[i]>>8),0);
            }
            for (uint32 i = lhs->digits_used*2; i < size; ++i)
            {
                a[i] = 0;
            }

            // load rhs into the b array
            for (uint32 i = 0; i < rhs->digits_used; ++i)
            {
                b[i*2] = ct((t)(rhs->number[i]&0xFF),0);
                b[i*2+1] = ct((t)(rhs->number[i]>>8),0);
            }
            for (uint32 i = rhs->digits_used*2; i < size; ++i)
            {
                b[i] = 0;
            }

            // perform the forward fft of a and b
            fft(a,size);
            fft(b,size);

            const double l = 1.0/size;

            // do the pointwise multiply of a and b and also apply the scale
            // factor in this loop too.
            for (unsigned long i = 0; i < size; ++i)
            {
                a[i] = l*a[i]*b[i];
            }

            // Now compute the inverse fft of the pointwise multiplication of a and b.
            // This is basically the result.  We just have to take care of any carries
            // that should happen.
            ifft(a,size);

            // loop over the result and propagate any carries that need to take place.
            // We will also be moving the resulting numbers into result->number at
            // the same time.
            uint64 carry = 0;
            result->digits_used = 0;
            int zeros = 0;
            const uint32 len = lhs->digits_used + rhs->digits_used;
            for (unsigned long i = 0; i < len; ++i)
            {
                uint64 num1 = static_cast<uint64>(std::floor(a[i*2].real()+0.5));
                num1 += carry;
                carry = 0;
                if (num1 > 255)
                {
                    carry = num1 >> 8;
                    num1 = (num1&0xFF);
                }

                uint64 num2 = static_cast<uint64>(std::floor(a[i*2+1].real()+0.5));
                num2 += carry;
                carry = 0;
                if (num2 > 255)
                {
                    carry = num2 >> 8;
                    num2 = (num2&0xFF);
                }

                // put the new number into its final place
                num1 = (num2<<8) | num1;
                result->number[i] = static_cast<uint16>(num1);

                // keep track of the number of leading zeros
                if (num1 == 0)
                    ++zeros;
                else
                    zeros = 0;
                ++(result->digits_used);
            }

            // adjust digits_used so that it reflects the actual number
            // of non-zero digits in our representation.
            result->digits_used -= zeros;

            // if the result was zero then adjust the result accordingly
            if (result->digits_used == 0)
            {
                // make result be zero
                result->digits_used = 1;
                *(result->number) = 0;
            }

            // free all the temporary buffers
            delete [] a;
            delete [] b;
        }
    }

// ----------------------------------------------------------------------------------------

    void bigint_kernel_2::
    shift_left (
        const data_record* data,
        data_record* result,
        uint32 shift_amount
    ) const
    {
        uint32 offset = shift_amount/16;
        shift_amount &= 0xf;  // same as shift_amount %= 16;

        uint16* r = result->number + data->digits_used + offset; // result
        uint16* end = data->number;
        uint16* s = end + data->digits_used; // source
        const uint32 temp = 16 - shift_amount;

        *r = (*(--s) >> temp);
        // set the number of digits used in the result
        // if the upper bits from *s were zero then don't count this first word
        if (*r == 0)
        {
            result->digits_used = data->digits_used + offset;
        }
        else
        {
            result->digits_used = data->digits_used + offset + 1;
        }
        --r;

        while (s != end)
        {
            *r = ((*s << shift_amount) | ( *(s-1) >> temp));
            --r;
            --s;
        }
        *r = *s << shift_amount;

        // now zero the rest of the result
        end = result->number;
        while (r != end)
            *(--r) = 0;

    }

// ----------------------------------------------------------------------------------------

    void bigint_kernel_2::
    shift_right (
        const data_record* data,
        data_record* result
    ) const
    {

            uint16* r = result->number; // result
            uint16* s = data->number; // source
            uint16* end = s + data->digits_used - 1;

            while (s != end)
            {
                *r = (*s >> 1) | (*(s+1) << 15);
                ++r;
                ++s;
            }
            *r = *s >> 1;

            // calculate the new number for digits_used
            if (*r == 0)
            {
                if (data->digits_used != 1)
                    result->digits_used = data->digits_used - 1;
                else
                    result->digits_used = 1;
            }
            else
            {
                result->digits_used = data->digits_used;
            }

    }

// ----------------------------------------------------------------------------------------

    bool bigint_kernel_2::
    is_less_than (
        const data_record* lhs,
        const data_record* rhs
    ) const
    {
        uint32 lhs_digits_used = lhs->digits_used;
        uint32 rhs_digits_used = rhs->digits_used;

        // if lhs is definitely less than rhs
        if (lhs_digits_used < rhs_digits_used )
            return true;
        // if lhs is definitely greater than rhs
        else if (lhs_digits_used > rhs_digits_used)
            return false;
        else
        {
            uint16* end = lhs->number;
            uint16* l = end         + lhs_digits_used;
            uint16* r = rhs->number + rhs_digits_used;

            while (l != end)
            {
                --l;
                --r;
                if (*l < *r)
                    return true;
                else if (*l > *r)
                    return false;
            }

            // at this point we know that they are equal
            return false;
        }

    }

// ----------------------------------------------------------------------------------------

    bool bigint_kernel_2::
    is_equal_to (
        const data_record* lhs,
        const data_record* rhs
    ) const
    {
        // if lhs and rhs are definitely not equal
        if (lhs->digits_used != rhs->digits_used )
        {
            return false;
        }
        else
        {
            uint16* l = lhs->number;
            uint16* r = rhs->number;
            uint16* end = l + lhs->digits_used;

            while (l != end)
            {
                if (*l != *r)
                    return false;
                ++l;
                ++r;
            }

            // at this point we know that they are equal
            return true;
        }

    }

// ----------------------------------------------------------------------------------------

    void bigint_kernel_2::
    increment (
        const data_record* source,
        data_record* dest
    ) const
    {
        uint16* s = source->number;
        uint16* d = dest->number;
        uint16* end = s + source->digits_used;
        while (true)
        {
            *d = *s + 1;

            // if there was no carry then break out of the loop
            if (*d != 0)
            {
                dest->digits_used = source->digits_used;

                // copy the rest of the digits over to d
                ++d; ++s;
                while (s != end)
                {
                    *d = *s;
                    ++d;
                    ++s;
                }

                break;
            }

            ++s;

            // if we have hit the end of s and there was a carry up to this point
            // then just make the next digit 1 and add one to the digits used
            if (s == end)
            {
                ++d;
                dest->digits_used = source->digits_used + 1;
                *d = 1;
                break;
            }

            ++d;
        }
    }

// ----------------------------------------------------------------------------------------

    void bigint_kernel_2::
    decrement (
        const data_record* source,
        data_record* dest
    ) const
    {
        uint16* s = source->number;
        uint16* d = dest->number;
        uint16* end = s + source->digits_used;
        while (true)
        {
            *d = *s - 1;

            // if there was no carry then break out of the loop
            if (*d != 0xFFFF)
            {
                // if we lost a digit in the subtraction
                if (*d == 0 && s+1 == end)
                {
                    if (source->digits_used == 1)
                        dest->digits_used = 1;
                    else
                        dest->digits_used = source->digits_used - 1;
                }
                else
                {
                    dest->digits_used = source->digits_used;
                }
                break;
            }
            else
            {
                ++d;
                ++s;
            }

        }

        // copy the rest of the digits over to d
        ++d;
        ++s;
        while (s != end)
        {
            *d = *s;
            ++d;
            ++s;
        }
    }

// ----------------------------------------------------------------------------------------

    void bigint_kernel_2::
    fft (
        ct* data,
        unsigned long len
    ) const
    {
        const t pi2 = -2.0*3.1415926535897932384626433832795028841971693993751;

        const unsigned long half = len/2;

        std::vector<ct> twiddle_factors;
        twiddle_factors.resize(half);

        // compute the complex root of unity w
        const t temp = pi2/len;
        ct w = ct(std::cos(temp),std::sin(temp));

        ct w_pow = 1;

        // compute the twiddle factors
        for (std::vector<ct>::size_type j = 0; j < twiddle_factors.size(); ++j)
        {
            twiddle_factors[j] = w_pow;
            w_pow *= w;
        }

        ct a, b;

        // now compute the decimation in frequency.  This first
        // outer loop loops log2(len) number of times
        unsigned long skip = 1;
        for (unsigned long step = half; step != 0; step >>= 1)
        {
            // do blocks of butterflies in this loop
            for (unsigned long j = 0; j < len; j += step*2)
            {
                // do step butterflies
                for (unsigned long k = 0; k < step; ++k)
                {
                    const unsigned long a_idx = j+k;
                    const unsigned long b_idx = j+k+step;
                    a = data[a_idx] + data[b_idx];
                    b = (data[a_idx] - data[b_idx])*twiddle_factors[k*skip];
                    data[a_idx] = a;
                    data[b_idx] = b;
                }
            }
            skip *= 2;
        }
    }

// ----------------------------------------------------------------------------------------

    void bigint_kernel_2::
    ifft(
        ct* data,
        unsigned long len
    ) const
    {
        const t pi2 = 2.0*3.1415926535897932384626433832795028841971693993751;

        const unsigned long half = len/2;

        std::vector<ct> twiddle_factors;
        twiddle_factors.resize(half);

        // compute the complex root of unity w
        const t temp = pi2/len;
        ct w = ct(std::cos(temp),std::sin(temp));

        ct w_pow = 1;

        // compute the twiddle factors
        for (std::vector<ct>::size_type j = 0; j < twiddle_factors.size(); ++j)
        {
            twiddle_factors[j] = w_pow;
            w_pow *= w;
        }

        ct a, b;

        // now compute the inverse decimation in frequency.  This first
        // outer loop loops log2(len) number of times
        unsigned long skip = half;
        for (unsigned long step = 1; step <= half; step <<= 1)
        {
            // do blocks of butterflies in this loop
            for (unsigned long j = 0; j < len; j += step*2)
            {
                // do step butterflies
                for (unsigned long k = 0; k < step; ++k)
                {
                    const unsigned long a_idx = j+k;
                    const unsigned long b_idx = j+k+step;
                    data[b_idx] *= twiddle_factors[k*skip];
                    a = data[a_idx] + data[b_idx];
                    b = data[a_idx] - data[b_idx];
                    data[a_idx] = a;
                    data[b_idx] = b;
                }
            }
            skip /= 2;
        }
    }

// ----------------------------------------------------------------------------------------

}
#endif // DLIB_BIGINT_KERNEL_2_CPp_


dlib C++ Library - bigint_kernel_2.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_BIGINT_KERNEl_2_
#define DLIB_BIGINT_KERNEl_2_

#include "bigint_kernel_abstract.h"
#include "../algs.h"
#include "../serialize.h"
#include "../uintn.h"
#include <iosfwd>
#include <cmath>
#include <complex>
#include <vector>

namespace dlib
{

    using namespace dlib::relational_operators; // defined in algs.h

    class bigint_kernel_2
    {
        /*!
            INITIAL VALUE
                slack               == 25
                data->number[0]     == 0
                data->size          == slack
                data->references    == 1
                data->digits_used   == 1

            CONVENTION
                slack  == the number of extra digits placed into the number when it is
                    created.  the slack value should never be less than 1

                data->number == pointer to an array of data->size uint16s.
                    data represents a string of base 65535 numbers with data[0] being
                    the least significant bit and data[data->digits_used-1] being the most
                    significant

                NOTE: In the comments I will consider a word to be a 16 bit value

                data->digits_used == the number of significant digits in the number.
                    data->digits_used tells us the number of used elements in the
                    data->number array so everything beyond data->number[data->digits_used-1]
                    is undefined

                data->references == the number of bigint_kernel_2 objects which refer
                    to this data_record
        !*/

        struct data_record
        {

            explicit data_record(
                uint32 size_
            ) :
                size(size_),
                number(new uint16[size_]),
                references(1),
                digits_used(1)
            {*number = 0;}
            /*!
                ensures
                    - initializes *this to represent zero
            !*/

            data_record(
                const data_record& item,
                uint32 additional_size
            ) :
                size(item.digits_used + additional_size),
                number(new uint16[size]),
                references(1),
                digits_used(item.digits_used)
            {
                uint16* source = item.number;
                uint16* dest = number;
                uint16* end = source + digits_used;
                while (source != end)
                {
                    *dest = *source;
                    ++dest;
                    ++source;
                }
            }
            /*!
                ensures
                    - *this is a copy of item except with
                      size == item.digits_used + additional_size
            !*/

            ~data_record(
            )
            {
                delete [] number;
            }

            const uint32 size;
            uint16* number;
            uint32 references;
            uint32 digits_used;

        private:
            // no copy constructor
            data_record ( data_record&);
        };

        // note that the second parameter is just there
        // to resolve the ambiguity between this constructor and
        // bigint_kernel_2(uint32)
        explicit bigint_kernel_2 (
            data_record* data_, int
        ): slack(25),data(data_) {}
        /*!
            ensures
                - *this is initialized with data_ as its data member
        !*/

    public:

        bigint_kernel_2 (
        );

        bigint_kernel_2 (
            uint32 value
        );

        bigint_kernel_2 (
            const bigint_kernel_2& item
        );

        virtual ~bigint_kernel_2 (
        );

        const bigint_kernel_2 operator+ (
            const bigint_kernel_2& rhs
        ) const;

        bigint_kernel_2& operator+= (
            const bigint_kernel_2& rhs
        );

        const bigint_kernel_2 operator- (
            const bigint_kernel_2& rhs
        ) const;

        bigint_kernel_2& operator-= (
            const bigint_kernel_2& rhs
        );

        const bigint_kernel_2 operator* (
            const bigint_kernel_2& rhs
        ) const;

        bigint_kernel_2& operator*= (
            const bigint_kernel_2& rhs
        );

        const bigint_kernel_2 operator/ (
            const bigint_kernel_2& rhs
        ) const;

        bigint_kernel_2& operator/= (
            const bigint_kernel_2& rhs
        );

        const bigint_kernel_2 operator% (
            const bigint_kernel_2& rhs
        ) const;

        bigint_kernel_2& operator%= (
            const bigint_kernel_2& rhs
        );

        bool operator < (
            const bigint_kernel_2& rhs
        ) const;

        bool operator == (
            const bigint_kernel_2& rhs
        ) const;

        bigint_kernel_2& operator= (
            const bigint_kernel_2& rhs
        );

        friend std::ostream& operator<< (
            std::ostream& out,
            const bigint_kernel_2& rhs
        );

        friend std::istream& operator>> (
            std::istream& in,
            bigint_kernel_2& rhs
        );

        bigint_kernel_2& operator++ (
        );

        const bigint_kernel_2 operator++ (
            int
        );

        bigint_kernel_2& operator-- (
        );

        const bigint_kernel_2 operator-- (
            int
        );

        friend const bigint_kernel_2 operator+ (
            uint16 lhs,
            const bigint_kernel_2& rhs
        );

        friend const bigint_kernel_2 operator+ (
            const bigint_kernel_2& lhs,
            uint16 rhs
        );

        bigint_kernel_2& operator+= (
            uint16 rhs
        );

        friend const bigint_kernel_2 operator- (
            uint16 lhs,
            const bigint_kernel_2& rhs
        );

        friend const bigint_kernel_2 operator- (
            const bigint_kernel_2& lhs,
            uint16 rhs
        );

        bigint_kernel_2& operator-= (
            uint16 rhs
        );

        friend const bigint_kernel_2 operator* (
            uint16 lhs,
            const bigint_kernel_2& rhs
        );

        friend const bigint_kernel_2 operator* (
            const bigint_kernel_2& lhs,
            uint16 rhs
        );

        bigint_kernel_2& operator*= (
            uint16 rhs
        );

        friend const bigint_kernel_2 operator/ (
            uint16 lhs,
            const bigint_kernel_2& rhs
        );

        friend const bigint_kernel_2 operator/ (
            const bigint_kernel_2& lhs,
            uint16 rhs
        );

        bigint_kernel_2& operator/= (
            uint16 rhs
        );

        friend const bigint_kernel_2 operator% (
            uint16 lhs,
            const bigint_kernel_2& rhs
        );

        friend const bigint_kernel_2 operator% (
            const bigint_kernel_2& lhs,
            uint16 rhs
        );

        bigint_kernel_2& operator%= (
            uint16 rhs
        );

        friend bool operator < (
            uint16 lhs,
            const bigint_kernel_2& rhs
        );

        friend bool operator < (
            const bigint_kernel_2& lhs,
            uint16 rhs
        );

        friend bool operator == (
            const bigint_kernel_2& lhs,
            uint16 rhs
        );

        friend bool operator == (
            uint16 lhs,
            const bigint_kernel_2& rhs
        );

        bigint_kernel_2& operator= (
            uint16 rhs
        );

        void swap (
            bigint_kernel_2& item
        ) { data_record* temp = data; data = item.data; item.data = temp; }

    private:

        typedef double t;
        typedef std::complex<t> ct;

        void fft(
            ct* data,
            unsigned long len
        ) const;
        /*!
            requires
                - len == x^n for some integer n (i.e. len is a power of 2)
                - len > 0
            ensures
                - #data == the FT decimation in frequency of data
        !*/

        void ifft(
            ct* data,
            unsigned long len
        ) const;
        /*!
            requires
                - len == x^n for some integer n (i.e. len is a power of 2)
                - len > 0
            ensures
                - #data == the inverse decimation in frequency of data.
                  (i.e. the inverse of what fft(data,len,-1) does to data)
        !*/

        void long_add (
            const data_record* lhs,
            const data_record* rhs,
            data_record* result
        ) const;
        /*!
            requires
                - result->size >= max(lhs->digits_used,rhs->digits_used) + 1
            ensures
                - result == lhs + rhs
        !*/

        void long_sub (
            const data_record* lhs,
            const data_record* rhs,
            data_record* result
        ) const;
        /*!
            requires
                - lhs >= rhs
                - result->size >= lhs->digits_used
            ensures
                - result == lhs - rhs
        !*/

        void long_div (
            const data_record* lhs,
            const data_record* rhs,
            data_record* result,
            data_record* remainder
        ) const;
        /*!
            requires
                - rhs != 0
                - result->size >= lhs->digits_used
                - remainder->size >= lhs->digits_used
                - each parameter is unique (i.e. lhs != result, lhs != remainder, etc.)
            ensures
                - result == lhs / rhs
                - remainder == lhs % rhs
        !*/

        void long_mul (
            const data_record* lhs,
            const data_record* rhs,
            data_record* result
        ) const;
        /*!
            requires
                - result->size >= lhs->digits_used + rhs->digits_used
                - result != lhs
                - result != rhs
            ensures
                - result == lhs * rhs
        !*/

        void short_add (
            const data_record* data,
            uint16 value,
            data_record* result
        ) const;
        /*!
            requires
                - result->size >= data->size + 1
            ensures
                - result == data + value
        !*/

        void short_sub (
            const data_record* data,
            uint16 value,
            data_record* result
        ) const;
        /*!
            requires
                - data >= value
                - result->size >= data->digits_used
            ensures
                - result == data - value
        !*/

        void short_mul (
            const data_record* data,
            uint16 value,
            data_record* result
        ) const;
        /*!
            requires
                - result->size >= data->digits_used + 1
            ensures
                - result == data * value
        !*/

        void short_div (
            const data_record* data,
            uint16 value,
            data_record* result,
            uint16& remainder
        ) const;
        /*!
            requires
                - value != 0
                - result->size >= data->digits_used
            ensures
                - result = data*value
                - remainder = data%value
        !*/

        void shift_left (
            const data_record* data,
            data_record* result,
            uint32 shift_amount
        ) const;
        /*!
            requires
                - result->size >= data->digits_used + shift_amount/8 + 1
            ensures
                - result == data << shift_amount
        !*/

        void shift_right (
            const data_record* data,
            data_record* result
        ) const;
        /*!
            requires
                - result->size >= data->digits_used
            ensures
                - result == data >> 1
        !*/

        bool is_less_than (
            const data_record* lhs,
            const data_record* rhs
        ) const;
        /*!
            ensures
                - returns true if lhs < rhs
                - returns false otherwise
        !*/

        bool is_equal_to (
            const data_record* lhs,
            const data_record* rhs
        ) const;
        /*!
            ensures
                - returns true if lhs == rhs
                - returns false otherwise
        !*/

        void increment (
            const data_record* source,
            data_record* dest
        ) const;
        /*!
            requires
                - dest->size >= source->digits_used + 1
            ensures
                - dest = source + 1
        !*/

        void decrement (
            const data_record* source,
            data_record* dest
        ) const;
        /*!
            requires
                source != 0
            ensuers
                dest = source - 1
        !*/

        // member data
        const uint32 slack;
        data_record* data;

    };

    inline void swap (
        bigint_kernel_2& a,
        bigint_kernel_2& b
    ) { a.swap(b); }

    inline void serialize (
        const bigint_kernel_2& item,
        std::ostream& out
    )
    {
        std::ios::fmtflags oldflags = out.flags();
        out.flags();
        out << item << ' ';
        out.flags(oldflags);
        if (!out) throw serialization_error("Error serializing object of type bigint_kernel_c");
    }

    inline void deserialize (
        bigint_kernel_2& item,
        std::istream& in
    )
    {
        std::ios::fmtflags oldflags = in.flags();
        in.flags();
        in >> item; in.flags(oldflags);
        if (in.get() != ' ')
        {
            item = 0;
            throw serialization_error("Error deserializing object of type bigint_kernel_c");
        }
    }

}

#ifdef NO_MAKEFILE
#include "bigint_kernel_2.cpp"
#endif

#endif // DLIB_BIGINT_KERNEl_2_


dlib C++ Library - binary_search_tree_kernel_1.h

// 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_1_
#define DLIB_BINARY_SEARCH_TREE_KERNEl_1_

#include "binary_search_tree_kernel_abstract.h"
#include "../algs.h"
#include "../interfaces/map_pair.h"
#include "../interfaces/enumerable.h"
#include "../interfaces/remover.h"
#include "../serialize.h"
#include <cstdlib>
#include <functional>

namespace dlib
{

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare = std::less<domain>
        >
    class binary_search_tree_kernel_1 : public enumerable<map_pair<domain,range> >,
                                        public asc_pair_remover<domain,range,compare>
    {

        /*!
            INITIAL VALUE
                tree_size == 0
                tree_root == 0
                tree_height == 0
                at_start_ == true
                current_element == 0
                stack == array of 50 node pointers
                stack_pos == 0

            CONVENTION
                tree_size   == size()
                tree_height == height()

                stack[stack_pos-1] == pop()

                current_element_valid() == (current_element != 0)
                if (current_element_valid()) then
                    element() == current_element->d and current_element->r
                at_start_ == at_start()
                if (current_element != 0 && current_element != tree_root) then
                    stack[stack_pos-1] == the parent of the node pointed to by current_element

                if (tree_size != 0)
                    tree_root == pointer to the root node of the binary search tree
                else
                    tree_root == 0

                for all nodes:
                {
                    left points to the left subtree or 0 if there is no left subtree and
                    right points to the right subtree or 0 if there is no right subtree and
                    all elements in a left subtree are <= the root and
                    all elements in a right subtree are >= the root and
                    d is the item in the domain of *this contained in the node
                    r is the item in the range of *this contained in the node
                    balance:
                        balance == 0 if both subtrees have the same height
                        balance == -1 if the left subtree has a height that is greater
                                   than the height of the right subtree by 1
                        balance == 1 if the right subtree has a height that is greater
                                   than the height of the left subtree by 1
                    for all trees:
                        the height of the left and right subtrees differ by at most one
                }

        !*/

        class node
        {
        public:
            node* left;
            node* right;
            domain d;
            range r;
            signed char balance;
        };

        class mpair : public map_pair<domain,range>
        {
        public:
            const domain* d;
            range* r;

            const domain& key(
            ) const { return *d; }

            const range& value(
            ) const { return *r; }

            range& value(
            ) { return *r; }
        };

        public:

            typedef domain domain_type;
            typedef range range_type;
            typedef compare compare_type;
            typedef mem_manager mem_manager_type;

            binary_search_tree_kernel_1(
            ) :
                tree_size(0),
                tree_root(0),
                current_element(0),
                tree_height(0),
                at_start_(true),
                stack_pos(0),
                stack(ppool.allocate_array(50))
            {
            }

            virtual ~binary_search_tree_kernel_1(
            );

            inline void clear(
            );

            inline short height (
            ) const;

            inline unsigned long count (
                const domain& item
            ) const;

            inline void add (
                domain& d,
                range& r
            );

            void remove (
                const domain& d,
                domain& d_copy,
                range& r
            );

            void destroy (
                const domain& item
            );

            inline const range* operator[] (
                const domain& item
            ) const;

            inline range* operator[] (
                const domain& item
            );

            inline void swap (
                binary_search_tree_kernel_1& item
            );

            // function from the asc_pair_remover interface
            void remove_any (
                domain& d,
                range& r
            );

            // functions from the enumerable interface
            inline unsigned long size (
            ) const;

            bool at_start (
            ) const;

            inline void reset (
            ) const;

            bool current_element_valid (
            ) const;

            const map_pair<domain,range>& element (
            ) const;

            map_pair<domain,range>& element (
            );

            bool move_next (
            ) const;

            void remove_last_in_order (
                domain& d,
                range& r
            );

            void remove_current_element (
                domain& d,
                range& r
            );

            void position_enumerator (
                const domain& d
            ) const;

        private:

            inline void rotate_left (
                node*& t
            );
            /*!
                requires
                    - t->balance == 2
                    - t->right->balance == 0 or 1
                    - t == reference to the pointer in t's parent node that points to t
                ensures
                    - #t is still a binary search tree
                    - #t->balance is between 1 and -1
                    - #t now has a height smaller by 1 if #t->balance == 0
            !*/

            inline void rotate_right (
                node*& t
            );
            /*!
                requires
                    - t->balance == -2
                    - t->left->balance == 0 or -1
                    - t == reference to the pointer in t's parent node that points to t
                ensures
                    - #t is still a binary search tree
                    - #t->balance is between 1 and -1
                    - #t now has a height smaller by 1 if #t->balance == 0

            !*/

            inline void double_rotate_right (
                node*& t
            );
            /*!
                requires
                    - t->balance == -2
                    - t->left->balance == 1
                    - t == reference to the pointer in t's parent node that points to t
                ensures
                    - #t is still a binary search tree
                    - #t now has a balance of 0
                    - #t now has a height smaller by 1
            !*/

            inline void double_rotate_left (
                node*& t
            );
            /*!
                requires
                    - t->balance == 2
                    - t->right->balance == -1
                    - t == reference to the pointer in t's parent node that points to t
                ensures
                    - #t is still a binary search tree
                    - #t now has a balance of 0
                    - #t now has a height smaller by 1
            !*/

            bool remove_biggest_element_in_tree (
                node*& t,
                domain& d,
                range& r
            );
            /*!
                requires
                    - t != 0  (i.e. there must be something in the tree to remove)
                    - t == reference to the pointer in t's parent node that points to t
                ensures
                    - the biggest node in t has been removed
                    - the biggest node domain element in t has been put into #d
                    - the biggest node range element in t has been put into #r
                    - #t is still a binary search tree
                    - returns false if the height of the tree has not changed
                    - returns true if the height of the tree has shrunk by one
            !*/

            bool remove_least_element_in_tree (
                node*& t,
                domain& d,
                range& r
            );
            /*!
                requires
                    - t != 0  (i.e. there must be something in the tree to remove)
                    - t == reference to the pointer in t's parent node that points to t
                ensures
                    - the least node in t has been removed
                    - the least node domain element in t has been put into #d
                    - the least node range element in t has been put into #r
                    - #t is still a binary search tree
                    - returns false if the height of the tree has not changed
                    - returns true if the height of the tree has shrunk by one
            !*/

            bool add_to_tree (
                node*& t,
                domain& d,
                range& r
            );
            /*!
                requires
                    - t == reference to the pointer in t's parent node that points to t
                ensures
                    - the mapping (d --> r) has been added to #t
                    - #d and #r have initial values for their types
                    - #t is still a binary search tree
                    - returns false if the height of the tree has not changed
                    - returns true if the height of the tree has grown by one
            !*/

            bool remove_from_tree (
                node*& t,
                const domain& d,
                domain& d_copy,
                range& r
            );
            /*!
                requires
                    - return_reference(t,d) != 0
                    - t == reference to the pointer in t's parent node that points to t
                ensures
                    - #d_copy is equivalent to d
                    - an element in t equivalent to d has been removed and swapped
                      into #d_copy and its associated range object has been
                      swapped into #r
                    - #t is still a binary search tree
                    - returns false if the height of the tree has not changed
                    - returns true if the height of the tree has shrunk by one
            !*/

            bool remove_from_tree (
                node*& t,
                const domain& item
            );
            /*!
                requires
                    - return_reference(t,item) != 0
                    - t == reference to the pointer in t's parent node that points to t
                ensures
                    - an element in t equivalent to item has been removed
                    - #t is still a binary search tree
                    - returns false if the height of the tree has not changed
                    - returns true if the height of the tree has shrunk by one
            !*/

            const range* return_reference (
                const node* t,
                const domain& d
            ) const;
            /*!
                ensures
                    - if (there is a domain element equivalent to d in t) then
                        - returns a pointer to the element in the range equivalent to d
                    - else
                        - returns 0
            !*/

            range* return_reference (
                node* t,
                const domain& d
            );
            /*!
                ensures
                    - if (there is a domain element equivalent to d in t) then
                        - returns a pointer to the element in the range equivalent to d
                    - else
                        - returns 0
            !*/

            inline bool keep_node_balanced (
                node*& t
            );
            /*!
                requires
                    - t != 0
                    - t == reference to the pointer in t's parent node that points to t
                ensures
                    - if (t->balance is < 1 or > 1) then
                        - keep_node_balanced() will ensure that #t->balance == 0, -1, or 1
                    - #t is still a binary search tree
                    - returns true if it made the tree one height shorter
                    - returns false if it didn't change the height
            !*/

            unsigned long get_count (
                const domain& item,
                node* tree_root
            ) const;
            /*!
                requires
                    - tree_root == the root of a binary search tree or 0
                ensures
                    - if (tree_root == 0) then
                        - returns 0
                    - else
                        - returns the number of elements in tree_root that are
                          equivalent to item
            !*/

            void delete_tree (
                node* t
            );
            /*!
                requires
                    - t != 0
                ensures
                    - deallocates the node pointed to by t and all of t's left and right children
            !*/

            void push (
                node* n
            ) const { stack[stack_pos] = n; ++stack_pos; }
            /*!
                ensures
                    - pushes n onto the stack
            !*/

            node* pop (
            ) const { --stack_pos; return stack[stack_pos]; }
            /*!
                ensures
                    - pops the top of the stack and returns it
            !*/

            bool fix_stack (
                node* t,
                unsigned char depth = 0
            );
            /*!
                requires
                    - current_element != 0
                    - depth == 0
                    - t == tree_root
                ensures
                    - makes the stack contain the correct set of parent pointers.
                      also adjusts stack_pos so it is correct.
                    - #t is still a binary search tree
            !*/

            bool remove_current_element_from_tree (
                node*& t,
                domain& d,
                range& r,
                unsigned long cur_stack_pos = 1
            );
            /*!
                requires
                    - t == tree_root
                    - cur_stack_pos == 1
                    - current_element != 0
                ensures
                    - removes the data in the node given by current_element and swaps it into
                      #d and #r.
                    - #t is still a binary search tree
                    - the enumerator is advances on to the next element but its stack is
                      potentially corrupted.  so you must call fix_stack(tree_root) to fix
                      it.
                    - returns false if the height of the tree has not changed
                    - returns true if the height of the tree has shrunk by one
            !*/

            // data members

            mutable mpair p;
            unsigned long tree_size;
            node* tree_root;
            mutable node* current_element;
            typename mem_manager::template rebind<node>::other pool;
            typename mem_manager::template rebind<node*>::other ppool;
            short tree_height;
            mutable bool at_start_;
            mutable unsigned char stack_pos;
            mutable node** stack;
            compare comp;

            // restricted functions
            binary_search_tree_kernel_1(binary_search_tree_kernel_1&);
            binary_search_tree_kernel_1& operator=(binary_search_tree_kernel_1&);

    };

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    inline void swap (
        binary_search_tree_kernel_1<domain,range,mem_manager,compare>& a,
        binary_search_tree_kernel_1<domain,range,mem_manager,compare>& b
    ) { a.swap(b); }

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void deserialize (
        binary_search_tree_kernel_1<domain,range,mem_manager,compare>& item,
        std::istream& in
    )
    {
        try
        {
            item.clear();
            unsigned long size;
            deserialize(size,in);
            domain d;
            range r;
            for (unsigned long i = 0; i < size; ++i)
            {
                deserialize(d,in);
                deserialize(r,in);
                item.add(d,r);
            }
        }
        catch (serialization_error e)
        {
            item.clear();
            throw serialization_error(e.info + "\n   while deserializing object of type binary_search_tree_kernel_1");
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    binary_search_tree_kernel_1<domain,range,mem_manager,compare>::
    ~binary_search_tree_kernel_1 (
    )
    {
        ppool.deallocate_array(stack);
        if (tree_size != 0)
        {
            delete_tree(tree_root);
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void binary_search_tree_kernel_1<domain,range,mem_manager,compare>::
    clear (
    )
    {
        if (tree_size > 0)
        {
            delete_tree(tree_root);
            tree_root = 0;
            tree_size = 0;
            tree_height = 0;
        }
        // reset the enumerator
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    unsigned long binary_search_tree_kernel_1<domain,range,mem_manager,compare>::
    size (
    ) const
    {
        return tree_size;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    short binary_search_tree_kernel_1<domain,range,mem_manager,compare>::
    height (
    ) const
    {
        return tree_height;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    unsigned long binary_search_tree_kernel_1<domain,range,mem_manager,compare>::
    count (
        const domain& item
    ) const
    {
        return get_count(item,tree_root);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void binary_search_tree_kernel_1<domain,range,mem_manager,compare>::
    add (
        domain& d,
        range& r
    )
    {
        tree_height += add_to_tree(tree_root,d,r);
        ++tree_size;
        // reset the enumerator
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void binary_search_tree_kernel_1<domain,range,mem_manager,compare>::
    remove (
        const domain& d,
        domain& d_copy,
        range& r
    )
    {
        tree_height -= remove_from_tree(tree_root,d,d_copy,r);
        --tree_size;
        // reset the enumerator
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void binary_search_tree_kernel_1<domain,range,mem_manager,compare>::
    destroy (
        const domain& item
    )
    {
        tree_height -= remove_from_tree(tree_root,item);
        --tree_size;
        // reset the enumerator
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void binary_search_tree_kernel_1<domain,range,mem_manager,compare>::
    remove_any (
        domain& d,
        range& r
    )
    {
        tree_height -= remove_least_element_in_tree(tree_root,d,r);
        --tree_size;
        // reset the enumerator
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    range* binary_search_tree_kernel_1<domain,range,mem_manager,compare>::
    operator[] (
        const domain& item
    )
    {
        return return_reference(tree_root,item);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    const range* binary_search_tree_kernel_1<domain,range,mem_manager,compare>::
    operator[] (
        const domain& item
    ) const
    {
        return return_reference(tree_root,item);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void binary_search_tree_kernel_1<domain,range,mem_manager,compare>::
    swap (
        binary_search_tree_kernel_1<domain,range,mem_manager,compare>& item
    )
    {
        pool.swap(item.pool);
        ppool.swap(item.ppool);
        exchange(p,item.p);
        exchange(stack,item.stack);
        exchange(stack_pos,item.stack_pos);
        exchange(comp,item.comp);

        node* tree_root_temp            = item.tree_root;
        unsigned long tree_size_temp    = item.tree_size;
        short tree_height_temp          = item.tree_height;
        node* current_element_temp      = item.current_element;
        bool at_start_temp              = item.at_start_;

        item.tree_root   = tree_root;
        item.tree_size   = tree_size;
        item.tree_height = tree_height;
        item.current_element = current_element;
        item.at_start_   = at_start_;

        tree_root   = tree_root_temp;
        tree_size   = tree_size_temp;
        tree_height = tree_height_temp;
        current_element = current_element_temp;
        at_start_   = at_start_temp;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void binary_search_tree_kernel_1<domain,range,mem_manager,compare>::
    remove_last_in_order (
        domain& d,
        range& r
    )
    {
        tree_height -= remove_biggest_element_in_tree(tree_root,d,r);
        --tree_size;
        // reset the enumerator
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void binary_search_tree_kernel_1<domain,range,mem_manager,compare>::
    remove_current_element (
        domain& d,
        range& r
    )
    {
        tree_height -= remove_current_element_from_tree(tree_root,d,r);
        --tree_size;

        // fix the enumerator stack if we need to
        if (current_element)
            fix_stack(tree_root);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void binary_search_tree_kernel_1<domain,range,mem_manager,compare>::
    position_enumerator (
        const domain& d
    ) const
    {
        // clear the enumerator state and make sure the stack is empty
        reset();
        at_start_ = false;
        node* t = tree_root;
        bool went_left = false;
        while (t != 0)
        {
            if ( comp(d , t->d) )
            {
                push(t);
                // if item is on the left then look in left
                t = t->left;
                went_left = true;
            }
            else if (comp(t->d , d))
            {
                push(t);
                // if item is on the right then look in right
                t = t->right;
                went_left = false;
            }
            else
            {
                current_element = t;
                return;
            }
        }

        // if we didn't find any matches but there might be something after the
        // d in this tree.
        if (stack_pos > 0)
        {
            current_element = pop();
            // if we went left from this node then this node is the next
            // biggest.
            if (went_left)
            {
                return;
            }
            else
            {
                move_next();
            }
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // enumerable function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    bool binary_search_tree_kernel_1<domain,range,mem_manager,compare>::
    at_start (
    ) const
    {
        return at_start_;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void binary_search_tree_kernel_1<domain,range,mem_manager,compare>::
    reset (
    ) const
    {
        at_start_ = true;
        current_element = 0;
        stack_pos = 0;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    bool binary_search_tree_kernel_1<domain,range,mem_manager,compare>::
    current_element_valid (
    ) const
    {
        return (current_element != 0);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    const map_pair<domain,range>& binary_search_tree_kernel_1<domain,range,mem_manager,compare>::
    element (
    ) const
    {
        p.d = &(current_element->d);
        p.r = &(current_element->r);
        return p;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    map_pair<domain,range>& binary_search_tree_kernel_1<domain,range,mem_manager,compare>::
    element (
    )
    {
        p.d = &(current_element->d);
        p.r = &(current_element->r);
        return p;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    bool binary_search_tree_kernel_1<domain,range,mem_manager,compare>::
    move_next (
    ) const
    {
        // if we haven't started iterating yet
        if (at_start_)
        {
            at_start_ = false;
            if (tree_size == 0)
            {
                return false;
            }
            else
            {
                // find the first element in the tree
                current_element = tree_root;
                node* temp = current_element->left;
                while (temp != 0)
                {
                    push(current_element);
                    current_element = temp;
                    temp = current_element->left;
                }
                return true;
            }
        }
        else
        {
            if (current_element == 0)
            {
                return false;
            }
            else
            {
                node* temp;
                bool went_up;  // true if we went up the tree from a child node to parent
                bool from_left = false; // true if we went up and were coming from a left child node
                // find the next element in the tree
                if (current_element->right != 0)
                {
                    // go right and down
                    temp = current_element;
                    push(current_element);
                    current_element = temp->right;
                    went_up = false;
                }
                else
                {
                    // go up to the parent if we can
                    if (current_element == tree_root)
                    {
                        // in this case we have iterated over all the element of the tree
                        current_element = 0;
                        return false;
                    }
                    went_up = true;
                    node* parent = pop();

                    from_left = (parent->left == current_element);
                    // go up to parent
                    current_element = parent;
                }

                while (true)
                {
                    if (went_up)
                    {
                        if (from_left)
                        {
                            // in this case we have found the next node
                            break;
                        }
                        else
                        {
                            if (current_element == tree_root)
                            {
                                // in this case we have iterated over all the elements
                                // in the tree
                                current_element = 0;
                                return false;
                            }
                            // we should go up
                            node* parent = pop();
                            from_left = (parent->left == current_element);
                            current_element = parent;
                        }
                    }
                    else
                    {
                        // we just went down to a child node
                        if (current_element->left != 0)
                        {
                            // go left
                            went_up = false;
                            temp = current_element;
                            push(current_element);
                            current_element = temp->left;
                        }
                        else
                        {
                            // if there is no left child then we have found the next node
                            break;
                        }
                    }
                }

                return true;
            }
        }

    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // private member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void binary_search_tree_kernel_1<domain,range,mem_manager,compare>::
    delete_tree (
        node* t
    )
    {
        if (t->left != 0)
            delete_tree(t->left);
        if (t->right != 0)
            delete_tree(t->right);
        pool.deallocate(t);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void binary_search_tree_kernel_1<domain,range,mem_manager,compare>::
    rotate_left (
        node*& t
    )
    {

        // set the new balance numbers
        if (t->right->balance == 1)
        {
            t->balance = 0;
            t->right->balance = 0;
        }
        else
        {
            t->balance = 1;
            t->right->balance = -1;
        }

        // perform the rotation
        node* temp = t->right;
        t->right = temp->left;
        temp->left = t;
        t = temp;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void binary_search_tree_kernel_1<domain,range,mem_manager,compare>::
    rotate_right (
        node*& t
    )
    {
        // set the new balance numbers
        if (t->left->balance == -1)
        {
            t->balance = 0;
            t->left->balance = 0;
        }
        else
        {
            t->balance = -1;
            t->left->balance = 1;
        }

        // preform the rotation
        node* temp = t->left;
        t->left = temp->right;
        temp->right = t;
        t = temp;

    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void binary_search_tree_kernel_1<domain,range,mem_manager,compare>::
    double_rotate_right (
        node*& t
    )
    {

        node* temp = t;
        t = t->left->right;

        temp->left->right = t->left;
        t->left = temp->left;

        temp->left = t->right;
        t->right = temp;

        if (t->balance < 0)
        {
            t->left->balance = 0;
            t->right->balance = 1;
        }
        else if (t->balance > 0)
        {
            t->left->balance = -1;
            t->right->balance = 0;
        }
        else
        {
            t->left->balance = 0;
            t->right->balance = 0;
        }
        t->balance = 0;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void binary_search_tree_kernel_1<domain,range,mem_manager,compare>::
    double_rotate_left (
        node*& t
    )
    {
        node* temp = t;
        t = t->right->left;

        temp->right->left = t->right;
        t->right = temp->right;

        temp->right = t->left;
        t->left = temp;

        if (t->balance < 0)
        {
            t->left->balance = 0;
            t->right->balance = 1;
        }
        else if (t->balance > 0)
        {
            t->left->balance = -1;
            t->right->balance = 0;
        }
        else
        {
            t->left->balance = 0;
            t->right->balance = 0;
        }

        t->balance = 0;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    bool binary_search_tree_kernel_1<domain,range,mem_manager,compare>::
    remove_biggest_element_in_tree (
        node*& t,
        domain& d,
        range& r
    )
    {
        // make a reference to the current node so we don't have to dereference a
        // pointer a bunch of times
        node& tree = *t;

        // if the right tree is an empty tree
        if ( tree.right == 0)
        {
            // swap nodes domain and range elements into d and r
            exchange(d,tree.d);
            exchange(r,tree.r);

            // plug hole left by removing this node
            t = tree.left;

            // delete the node that was just removed
            pool.deallocate(&tree);

            // return that the height of this part of the tree has decreased
            return true;
        }
        else
        {

            // keep going right

            // if remove made the tree one height shorter
            if ( remove_biggest_element_in_tree(tree.right,d,r) )
            {
                // if this caused the current tree to strink then report that
                if ( tree.balance == 1)
                {
                    --tree.balance;
                    return true;
                }
                else
                {
                    --tree.balance;
                    return keep_node_balanced(t);
                }
            }

            return false;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    bool binary_search_tree_kernel_1<domain,range,mem_manager,compare>::
    remove_least_element_in_tree (
        node*& t,
        domain& d,
        range& r
    )
    {
        // make a reference to the current node so we don't have to dereference a
        // pointer a bunch of times
        node& tree = *t;

        // if the left tree is an empty tree
        if ( tree.left == 0)
        {
            // swap nodes domain and range elements into d and r
            exchange(d,tree.d);
            exchange(r,tree.r);

            // plug hole left by removing this node
            t = tree.right;

            // delete the node that was just removed
            pool.deallocate(&tree);

            // return that the height of this part of the tree has decreased
            return true;
        }
        else
        {

            // keep going left

            // if remove made the tree one height shorter
            if ( remove_least_element_in_tree(tree.left,d,r) )
            {
                // if this caused the current tree to strink then report that
                if ( tree.balance == -1)
                {
                    ++tree.balance;
                    return true;
                }
                else
                {
                    ++tree.balance;
                    return keep_node_balanced(t);
                }
            }

            return false;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    bool binary_search_tree_kernel_1<domain,range,mem_manager,compare>::
    add_to_tree (
        node*& t,
        domain& d,
        range& r
    )
    {

        // if found place to add
        if (t == 0)
        {
            // create a node to add new item into
            t = pool.allocate();

            // make a reference to the current node so we don't have to dereference a
            // pointer a bunch of times
            node& tree = *t;

            // set left and right pointers to NULL to indicate that there are no
            // left or right subtrees
            tree.left = 0;
            tree.right = 0;
            tree.balance = 0;

            // put d and r into t
            exchange(tree.d,d);
            exchange(tree.r,r);

            // indicate that the height of this tree has increased
            return true;
        }
        else  // keep looking for a place to add the new item
        {
            // make a reference to the current node so we don't have to dereference
            // a pointer a bunch of times
            node& tree = *t;
            signed char old_balance = tree.balance;

            // add the new item to whatever subtree it should go into
            if (comp( d , tree.d) )
                tree.balance -= add_to_tree(tree.left,d,r);
            else
                tree.balance += add_to_tree(tree.right,d,r);

            // if the tree was balanced to start with
            if (old_balance == 0)
            {
                // if its not balanced anymore then it grew in height
                if (tree.balance != 0)
                    return true;
                else
                    return false;
            }
            else
            {
                // if the tree is now balanced then it didn't grow
                if (tree.balance == 0)
                {
                    return false;
                }
                else
                {
                    // if the tree needs to be balanced
                    if (tree.balance != old_balance)
                    {
                        return !keep_node_balanced(t);
                    }
                    // if there has been no change in the heights
                    else
                    {
                        return false;
                    }
                }
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    bool binary_search_tree_kernel_1<domain,range,mem_manager,compare>::
    fix_stack (
        node* t,
        unsigned char depth
    )
    {
        // if we found the node we were looking for
        if (t == current_element)
        {
            stack_pos = depth;
            return true;
        }
        else if (t == 0)
        {
            return false;
        }

        if (!( comp(t->d , current_element->d)))
        {
            // go left
            if (fix_stack(t->left,depth+1))
            {
                stack[depth] = t;
                return true;
            }
        }
        if (!(comp(current_element->d , t->d)))
        {
            // go right
            if (fix_stack(t->right,depth+1))
            {
                stack[depth] = t;
                return true;
            }
        }
        return false;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    bool binary_search_tree_kernel_1<domain,range,mem_manager,compare>::
    remove_current_element_from_tree (
        node*& t,
        domain& d,
        range& r,
        unsigned long cur_stack_pos
    )
    {
        // make a reference to the current node so we don't have to dereference
        // a pointer a bunch of times
        node& tree = *t;

        // if we found the node we were looking for
        if (t == current_element)
        {

            // swap nodes domain and range elements into d_copy and r
            exchange(d,tree.d);
            exchange(r,tree.r);

            // if there is no left node
            if (tree.left == 0)
            {
                // move the enumerator on to the next element before we mess with the
                // tree
                move_next();

                // plug hole left by removing this node and free memory
                t = tree.right;  // plug hole with right subtree

                // delete old node
                pool.deallocate(&tree);

                // indicate that the height has changed
                return true;
            }
            // if there is no right node
            else if (tree.right == 0)
            {
                // move the enumerator on to the next element before we mess with the
                // tree
                move_next();

                // plug hole left by removing this node and free memory
                t = tree.left;  // plug hole with left subtree

                // delete old node
                pool.deallocate(&tree);

                // indicate that the height of this tree has changed
                return true;
            }
            // if there are both a left and right sub node
            else
            {

                // in this case the next current element is going to get swapped back
                // into this t node.
                current_element = t;

                // get an element that can replace the one being removed and do this
                // if it made the right subtree shrink by one
                if (remove_least_element_in_tree(tree.right,tree.d,tree.r))
                {
                    // adjust the tree height
                    --tree.balance;

                    // if the height of the current tree has dropped by one
                    if (tree.balance == 0)
                    {
                        return true;
                    }
                    else
                    {
                        return keep_node_balanced(t);
                    }
                }
                // else this remove did not effect the height of this tree
                else
                {
                    return false;
                }

            }

        }
        else if (  (cur_stack_pos < stack_pos && stack[cur_stack_pos] == tree.left) ||
                    tree.left == current_element )
        {
            // go left
            if (tree.balance == -1)
            {
                int balance = tree.balance;
                balance += remove_current_element_from_tree(tree.left,d,r,cur_stack_pos+1);
                tree.balance = balance;
                return !tree.balance;
            }
            else
            {
                int balance = tree.balance;
                balance += remove_current_element_from_tree(tree.left,d,r,cur_stack_pos+1);
                tree.balance = balance;
                return keep_node_balanced(t);
            }
        }
        else if (  (cur_stack_pos < stack_pos && stack[cur_stack_pos] == tree.right) ||
                    tree.right == current_element )
        {
            // go right
            if (tree.balance == 1)
            {
                int balance = tree.balance;
                balance -= remove_current_element_from_tree(tree.right,d,r,cur_stack_pos+1);
                tree.balance = balance;
                return !tree.balance;
            }
            else
            {
                int balance = tree.balance;
                balance -= remove_current_element_from_tree(tree.right,d,r,cur_stack_pos+1);
                tree.balance = balance;
                return keep_node_balanced(t);
            }
        }

        // this return should never happen but do it anyway to suppress compiler warnings
        return false;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    bool binary_search_tree_kernel_1<domain,range,mem_manager,compare>::
    remove_from_tree (
        node*& t,
        const domain& d,
        domain& d_copy,
        range& r
    )
    {
        // make a reference to the current node so we don't have to dereference
        // a pointer a bunch of times
        node& tree = *t;

        // if item is on the left
        if (comp(d , tree.d))
        {
            // if the left side of the tree has the greatest height
            if (tree.balance == -1)
            {
                int balance = tree.balance;
                balance += remove_from_tree(tree.left,d,d_copy,r);
                tree.balance = balance;
                return !tree.balance;
            }
            else
            {
                int balance = tree.balance;
                balance += remove_from_tree(tree.left,d,d_copy,r);
                tree.balance = balance;
                return keep_node_balanced(t);
            }

        }
        // if item is on the right
        else if (comp(tree.d , d))
        {

            // if the right side of the tree has the greatest height
            if (tree.balance == 1)
            {
                int balance = tree.balance;
                balance -= remove_from_tree(tree.right,d,d_copy,r);
                tree.balance = balance;
                return !tree.balance;
            }
            else
            {
                int balance = tree.balance;
                balance -= remove_from_tree(tree.right,d,d_copy,r);
                tree.balance = balance;
                return keep_node_balanced(t);
            }
        }
        // if item is found
        else
        {

            // swap nodes domain and range elements into d_copy and r
            exchange(d_copy,tree.d);
            exchange(r,tree.r);

            // if there is no left node
            if (tree.left == 0)
            {

                // plug hole left by removing this node and free memory
                t = tree.right;  // plug hole with right subtree

                // delete old node
                pool.deallocate(&tree);

                // indicate that the height has changed
                return true;
            }
            // if there is no right node
            else if (tree.right == 0)
            {

                // plug hole left by removing this node and free memory
                t = tree.left;  // plug hole with left subtree

                // delete old node
                pool.deallocate(&tree);

                // indicate that the height of this tree has changed
                return true;
            }
            // if there are both a left and right sub node
            else
            {

                // get an element that can replace the one being removed and do this
                // if it made the right subtree shrink by one
                if (remove_least_element_in_tree(tree.right,tree.d,tree.r))
                {
                    // adjust the tree height
                    --tree.balance;

                    // if the height of the current tree has dropped by one
                    if (tree.balance == 0)
                    {
                        return true;
                    }
                    else
                    {
                        return keep_node_balanced(t);
                    }
                }
                // else this remove did not effect the height of this tree
                else
                {
                    return false;
                }

            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    bool binary_search_tree_kernel_1<domain,range,mem_manager,compare>::
    remove_from_tree (
        node*& t,
        const domain& d
    )
    {
        // make a reference to the current node so we don't have to dereference
        // a pointer a bunch of times
        node& tree = *t;

        // if item is on the left
        if (comp(d , tree.d))
        {
            // if the left side of the tree has the greatest height
            if (tree.balance == -1)
            {
                int balance = tree.balance;
                balance += remove_from_tree(tree.left,d);
                tree.balance = balance;
                return !tree.balance;
            }
            else
            {
                int balance = tree.balance;
                balance += remove_from_tree(tree.left,d);
                tree.balance = balance;
                return keep_node_balanced(t);
            }

        }
        // if item is on the right
        else if (comp(tree.d , d))
        {

            // if the right side of the tree has the greatest height
            if (tree.balance == 1)
            {
                int balance = tree.balance;
                balance -= remove_from_tree(tree.right,d);
                tree.balance = balance;
                return !tree.balance;
            }
            else
            {
                int balance = tree.balance;
                balance -= remove_from_tree(tree.right,d);
                tree.balance = balance;
                return keep_node_balanced(t);
            }
        }
        // if item is found
        else
        {

            // if there is no left node
            if (tree.left == 0)
            {

                // plug hole left by removing this node and free memory
                t = tree.right;  // plug hole with right subtree

                // delete old node
                pool.deallocate(&tree);

                // indicate that the height has changed
                return true;
            }
            // if there is no right node
            else if (tree.right == 0)
            {

                // plug hole left by removing this node and free memory
                t = tree.left;  // plug hole with left subtree

                // delete old node
                pool.deallocate(&tree);

                // indicate that the height of this tree has changed
                return true;
            }
            // if there are both a left and right sub node
            else
            {

                // get an element that can replace the one being removed and do this
                // if it made the right subtree shrink by one
                if (remove_least_element_in_tree(tree.right,tree.d,tree.r))
                {
                    // adjust the tree height
                    --tree.balance;

                    // if the height of the current tree has dropped by one
                    if (tree.balance == 0)
                    {
                        return true;
                    }
                    else
                    {
                        return keep_node_balanced(t);
                    }
                }
                // else this remove did not effect the height of this tree
                else
                {
                    return false;
                }

            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    range* binary_search_tree_kernel_1<domain,range,mem_manager,compare>::
    return_reference (
        node* t,
        const domain& d
    )
    {
        while (t != 0)
        {

            if ( comp(d , t->d ))
            {
                // if item is on the left then look in left
                t = t->left;
            }
            else if (comp(t->d , d))
            {
                // if item is on the right then look in right
                t = t->right;
            }
            else
            {
                // if it's found then return a reference to it
                return &(t->r);
            }
        }
        return 0;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    const range* binary_search_tree_kernel_1<domain,range,mem_manager,compare>::
    return_reference (
        const node* t,
        const domain& d
    ) const
    {
        while (t != 0)
        {

            if ( comp(d , t->d) )
            {
                // if item is on the left then look in left
                t = t->left;
            }
            else if (comp(t->d , d))
            {
                // if item is on the right then look in right
                t = t->right;
            }
            else
            {
                // if it's found then return a reference to it
                return &(t->r);
            }
        }
        return 0;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    bool binary_search_tree_kernel_1<domain,range,mem_manager,compare>::
    keep_node_balanced (
        node*& t
    )
    {
        // make a reference to the current node so we don't have to dereference
        // a pointer a bunch of times
        node& tree = *t;

        // if tree does not need to be balanced then return false
        if (tree.balance == 0)
            return false;

        // if tree needs to be rotated left
        if (tree.balance == 2)
        {
            if (tree.right->balance >= 0)
                rotate_left(t);
            else
                double_rotate_left(t);
        }
        // else if the tree needs to be rotated right
        else if (tree.balance == -2)
        {
            if (tree.left->balance <= 0)
                rotate_right(t);
            else
                double_rotate_right(t);
        }

        if (t->balance == 0)
            return true;
        else
            return false;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    unsigned long binary_search_tree_kernel_1<domain,range,mem_manager,compare>::
    get_count (
        const domain& d,
        node* tree_root
    ) const
    {
        if (tree_root != 0)
        {
            if (comp(d , tree_root->d))
            {
                // go left
                return get_count(d,tree_root->left);
            }
            else if (comp(tree_root->d , d))
            {
                // go right
                return get_count(d,tree_root->right);
            }
            else
            {
                // go left and right to look for more matches
                return   get_count(d,tree_root->left)
                       + get_count(d,tree_root->right)
                       + 1;
            }
        }
        return 0;
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_BINARY_SEARCH_TREE_KERNEl_1_


dlib C++ Library - binary_search_tree_kernel_2.h

// 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_2_
#define DLIB_BINARY_SEARCH_TREE_KERNEl_2_

#include "binary_search_tree_kernel_abstract.h"
#include "../algs.h"
#include "../interfaces/map_pair.h"
#include "../interfaces/enumerable.h"
#include "../interfaces/remover.h"
#include "../serialize.h"
#include <functional>

namespace dlib
{

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare = std::less<domain>
        >
    class binary_search_tree_kernel_2 : public enumerable<map_pair<domain,range> >,
                                        public asc_pair_remover<domain,range,compare>
    {

        /*!
            INITIAL VALUE
                NIL == pointer to a node that represents a leaf
                tree_size == 0
                tree_root == NIL
                at_start == true
                current_element == 0

            CONVENTION
                current_element_valid() == (current_element != 0)
                if (current_element_valid()) then
                    element() == current_element->d and current_element->r
                at_start_ == at_start()

                tree_size   == size()

                NIL == pointer to a node that represents a leaf

                if (tree_size != 0)
                    tree_root == pointer to the root node of the binary search tree
                else
                    tree_root == NIL

                tree_root->color == black
                Every leaf is black and all leafs are the NIL node.
                The number of black nodes in any path from the root to a leaf is the
                same.

                for all nodes:
                {
                    - left points to the left subtree or NIL if there is no left subtree
                    - right points to the right subtree or NIL if there is no right
                      subtree
                    - parent points to the parent node or NIL if the node is the root
                    - ordering of nodes is determined by comparing each node's d member
                    - all elements in a left subtree are <= the node
                    - all elements in a right subtree are >= the node
                    - color == red or black
                    - if (color == red)
                        - the node's children are black
                }

        !*/

        class node
        {
        public:
            node* left;
            node* right;
            node* parent;
            domain d;
            range r;
            char color;
        };

        class mpair : public map_pair<domain,range>
        {
        public:
            const domain* d;
            range* r;

            const domain& key(
            ) const { return *d; }

            const range& value(
            ) const { return *r; }

            range& value(
            ) { return *r; }
        };

        const static char red = 0;
        const static char black = 1;

        public:

            typedef domain domain_type;
            typedef range range_type;
            typedef compare compare_type;
            typedef mem_manager mem_manager_type;

            binary_search_tree_kernel_2(
            ) :
                NIL(pool.allocate()),
                tree_size(0),
                tree_root(NIL),
                current_element(0),
                at_start_(true)
            {
                NIL->color = black;
                NIL->left = 0;
                NIL->right = 0;
                NIL->parent = 0;
            }

            virtual ~binary_search_tree_kernel_2(
            );

            inline void clear(
            );

            inline short height (
            ) const;

            inline unsigned long count (
                const domain& d
            ) const;

            inline void add (
                domain& d,
                range& r
            );

            void remove (
                const domain& d,
                domain& d_copy,
                range& r
            );

            void destroy (
                const domain& d
            );

            void remove_any (
                domain& d,
                range& r
            );

            inline const range* operator[] (
                const domain& item
            ) const;

            inline range* operator[] (
                const domain& item
            );

            inline void swap (
                binary_search_tree_kernel_2& item
            );

            // functions from the enumerable interface
            inline unsigned long size (
            ) const;

            bool at_start (
            ) const;

            inline void reset (
            ) const;

            bool current_element_valid (
            ) const;

            const map_pair<domain,range>& element (
            ) const;

            map_pair<domain,range>& element (
            );

            bool move_next (
            ) const;

            void remove_last_in_order (
                domain& d,
                range& r
            );

            void remove_current_element (
                domain& d,
                range& r
            );

            void position_enumerator (
                const domain& d
            ) const;

        private:

            inline void rotate_left (
                node* t
            );
            /*!
                requires
                    - t != NIL
                    - t->right != NIL
                ensures
                    - performs a left rotation around t and its right child
            !*/

            inline void rotate_right (
                node* t
            );
            /*!
                requires
                    - t != NIL
                    - t->left != NIL
                ensures
                    - performs a right rotation around t and its left child
            !*/

            inline void double_rotate_right (
                node* t
            );
            /*!
                requires
                    - t != NIL
                    - t->left != NIL
                    - t->left->right != NIL
                    - double_rotate_right() is only called in fix_after_add()
                ensures
                    - performs a left rotation around t->left
                    - then performs a right rotation around t
            !*/

            inline void double_rotate_left (
                node* t
            );
            /*!
                requires
                    - t != NIL
                    - t->right != NIL
                    - t->right->left != NIL
                    - double_rotate_left() is only called in fix_after_add()
                ensures
                    - performs a right rotation around t->right
                    - then performs a left rotation around t
            !*/

            void remove_biggest_element_in_tree (
                node* t,
                domain& d,
                range& r
            );
            /*!
                requires
                    - t != NIL  (i.e. there must be something in the tree to remove)
                ensures
                    - the biggest node in t has been removed
                    - the biggest node element in t has been put into #d and #r
                    - #t is still a binary search tree
            !*/

            bool remove_least_element_in_tree (
                node* t,
                domain& d,
                range& r
            );
            /*!
                requires
                    - t != NIL  (i.e. there must be something in the tree to remove)
                ensures
                    - the least node in t has been removed
                    - the least node element in t has been put into #d and #r
                    - #t is still a binary search tree
                    - if (the node that was removed was the one pointed to by current_element) then
                        - returns true
                    - else
                        - returns false
            !*/

            void add_to_tree (
                node* t,
                domain& d,
                range& r
            );
            /*!
                requires
                    - t != NIL
                ensures
                    - d and r are now in #t
                    - there is a mapping from d to r in #t
                    - #d and #r have initial values for their types
                    - #t is still a binary search tree
            !*/

            void remove_from_tree (
                node* t,
                const domain& d,
                domain& d_copy,
                range& r
            );
            /*!
                requires
                    - return_reference(t,d) != 0
                ensures
                    - #d_copy is equivalent to d
                    - the first element in t equivalent to d that is encountered when searching down the tree
                      from t has been removed and swapped into #d_copy.  Also, the associated range element
                      has been removed and swapped into #r.
                    - if (the node that got removed wasn't current_element) then
                        - adjusts the current_element pointer if the data in the node that it points to gets moved.
                    - else
                        - the value of current_element is now invalid
                    - #t is still a binary search tree
            !*/

            void remove_from_tree (
                node* t,
                const domain& d
            );
            /*!
                requires
                    - return_reference(t,d) != 0
                ensures
                    - an element in t equivalent to d has been removed
                    - #t is still a binary search tree
            !*/

            const range* return_reference (
                const node* t,
                const domain& d
            ) const;
            /*!
                ensures
                    - if (there is a domain element equivalent to d in t) then
                        - returns a pointer to the element in the range equivalent to d
                    - else
                        - returns 0
            !*/

            range* return_reference (
                node* t,
                const domain& d
            );
            /*!
                ensures
                    - if (there is a domain element equivalent to d in t) then
                        - returns a pointer to the element in the range equivalent to d
                    - else
                        - returns 0
            !*/

            void fix_after_add (
                node* t
            );
            /*!
                requires
                    - t == pointer to the node just added
                    - t->color == red
                    - t->parent != NIL (t must not be the root)
                    - fix_after_add() is only called after a new node has been added
                      to t
                ensures
                    - fixes any deviations from the CONVENTION caused by adding a node
            !*/

            void fix_after_remove (
                node* t
            );
            /*!
                requires
                    - t == pointer to the only child of the node that was spliced out
                    - fix_after_remove() is only called after a node has been removed
                      from t
                    - the color of the spliced out node was black
                ensures
                    - fixes any deviations from the CONVENTION causes by removing a node
            !*/

            short tree_height (
                node* t
            ) const;
            /*!
                ensures
                    - returns the number of nodes in the longest path from the root of the
                      tree to a leaf
            !*/

            void delete_tree (
                node* t
            );
            /*!
                requires
                    - t == root of binary search tree
                    - t != NIL
                ensures
                    - deletes all nodes in t except for NIL
            !*/

            unsigned long get_count (
                const domain& item,
                node* tree_root
            ) const;
            /*!
                requires
                    - tree_root == the root of a binary search tree or NIL
                ensures
                    - if (tree_root == NIL) then
                        - returns 0
                    - else
                        - returns the number of elements in tree_root that are
                          equivalent to item
            !*/

            // data members
            typename mem_manager::template rebind<node>::other pool;
            node* NIL;
            unsigned long tree_size;
            node* tree_root;
            mutable node* current_element;
            mutable bool at_start_;
            mutable mpair p;
            compare comp;

            // restricted functions
            binary_search_tree_kernel_2(binary_search_tree_kernel_2&);
            binary_search_tree_kernel_2& operator=(binary_search_tree_kernel_2&);

    };

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    inline void swap (
        binary_search_tree_kernel_2<domain,range,mem_manager,compare>& a,
        binary_search_tree_kernel_2<domain,range,mem_manager,compare>& b
    ) { a.swap(b); }

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void deserialize (
        binary_search_tree_kernel_2<domain,range,mem_manager,compare>& item,
        std::istream& in
    )
    {
        try
        {
            item.clear();
            unsigned long size;
            deserialize(size,in);
            domain d;
            range r;
            for (unsigned long i = 0; i < size; ++i)
            {
                deserialize(d,in);
                deserialize(r,in);
                item.add(d,r);
            }
        }
        catch (serialization_error e)
        {
            item.clear();
            throw serialization_error(e.info + "\n   while deserializing object of type binary_search_tree_kernel_2");
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    binary_search_tree_kernel_2<domain,range,mem_manager,compare>::
    ~binary_search_tree_kernel_2 (
    )
    {
        if (tree_root != NIL)
            delete_tree(tree_root);
        pool.deallocate(NIL);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::
    clear (
    )
    {
        if (tree_size > 0)
        {
            delete_tree(tree_root);
            tree_root = NIL;
            tree_size = 0;
        }
        // reset the enumerator
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    unsigned long binary_search_tree_kernel_2<domain,range,mem_manager,compare>::
    size (
    ) const
    {
        return tree_size;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    short binary_search_tree_kernel_2<domain,range,mem_manager,compare>::
    height (
    ) const
    {
        return tree_height(tree_root);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    unsigned long binary_search_tree_kernel_2<domain,range,mem_manager,compare>::
    count (
        const domain& item
    ) const
    {
        return get_count(item,tree_root);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::
    add (
        domain& d,
        range& r
    )
    {
        if (tree_size == 0)
        {
            tree_root = pool.allocate();
            tree_root->color = black;
            tree_root->left = NIL;
            tree_root->right = NIL;
            tree_root->parent = NIL;
            exchange(tree_root->d,d);
            exchange(tree_root->r,r);
        }
        else
        {
            add_to_tree(tree_root,d,r);
        }
        ++tree_size;
        // reset the enumerator
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::
    remove (
        const domain& d,
        domain& d_copy,
        range& r
    )
    {
        remove_from_tree(tree_root,d,d_copy,r);
        --tree_size;
        // reset the enumerator
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::
    destroy (
        const domain& item
    )
    {
        remove_from_tree(tree_root,item);
        --tree_size;
        // reset the enumerator
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::
    remove_any (
        domain& d,
        range& r
    )
    {
        remove_least_element_in_tree(tree_root,d,r);
        --tree_size;
        // reset the enumerator
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    range* binary_search_tree_kernel_2<domain,range,mem_manager,compare>::
    operator[] (
        const domain& d
    )
    {
        return return_reference(tree_root,d);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    const range* binary_search_tree_kernel_2<domain,range,mem_manager,compare>::
    operator[] (
        const domain& d
    ) const
    {
        return return_reference(tree_root,d);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::
    swap (
        binary_search_tree_kernel_2<domain,range,mem_manager,compare>& item
    )
    {
        pool.swap(item.pool);

        exchange(p,item.p);
        exchange(comp,item.comp);

        node* tree_root_temp            = item.tree_root;
        unsigned long tree_size_temp    = item.tree_size;
        node* const NIL_temp            = item.NIL;
        node* current_element_temp      = item.current_element;
        bool at_start_temp              = item.at_start_;

        item.tree_root                  = tree_root;
        item.tree_size                  = tree_size;
        item.NIL                        = NIL;
        item.current_element            = current_element;
        item.at_start_                  = at_start_;

        tree_root                       = tree_root_temp;
        tree_size                       = tree_size_temp;
        NIL                             = NIL_temp;
        current_element                 = current_element_temp;
        at_start_                       = at_start_temp;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::
    remove_last_in_order (
        domain& d,
        range& r
    )
    {
        remove_biggest_element_in_tree(tree_root,d,r);
        --tree_size;
        // reset the enumerator
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::
    remove_current_element (
        domain& d,
        range& r
    )
    {
        node* t = current_element;
        move_next();
        remove_from_tree(t,t->d,d,r);
        --tree_size;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::
    position_enumerator (
        const domain& d
    ) const
    {
        // clear the enumerator state and make sure the stack is empty
        reset();
        at_start_ = false;
        node* t = tree_root;
        node* parent = NIL;
        bool went_left = false;
        while (t != NIL)
        {
            if ( comp(d , t->d ))
            {
                // if item is on the left then look in left
                parent = t;
                t = t->left;
                went_left = true;
            }
            else if (comp(t->d , d))
            {
                // if item is on the right then look in right
                parent = t;
                t = t->right;
                went_left = false;
            }
            else
            {
                current_element = t;
                return;
            }
        }

        // if we didn't find any matches but there might be something after the
        // d in this tree.
        if (parent != NIL)
        {
            current_element = parent;
            // if we went left from this node then this node is the next
            // biggest.
            if (went_left)
            {
                return;
            }
            else
            {
                move_next();
            }
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // enumerable function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    bool binary_search_tree_kernel_2<domain,range,mem_manager,compare>::
    at_start (
    ) const
    {
        return at_start_;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::
    reset (
    ) const
    {
        at_start_ = true;
        current_element = 0;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    bool binary_search_tree_kernel_2<domain,range,mem_manager,compare>::
    current_element_valid (
    ) const
    {
        return (current_element != 0);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    const map_pair<domain,range>& binary_search_tree_kernel_2<domain,range,mem_manager,compare>::
    element (
    ) const
    {
        p.d = &(current_element->d);
        p.r = &(current_element->r);
        return p;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    map_pair<domain,range>& binary_search_tree_kernel_2<domain,range,mem_manager,compare>::
    element (
    )
    {
        p.d = &(current_element->d);
        p.r = &(current_element->r);
        return p;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    bool binary_search_tree_kernel_2<domain,range,mem_manager,compare>::
    move_next (
    ) const
    {
        // if we haven't started iterating yet
        if (at_start_)
        {
            at_start_ = false;
            if (tree_size == 0)
            {
                return false;
            }
            else
            {
                // find the first element in the tree
                current_element = tree_root;
                node* temp = current_element->left;
                while (temp != NIL)
                {
                    current_element = temp;
                    temp = current_element->left;
                }
                return true;
            }
        }
        else
        {
            if (current_element == 0)
            {
                return false;
            }
            else
            {
                bool went_up;  // true if we went up the tree from a child node to parent
                bool from_left = false; // true if we went up and were coming from a left child node
                // find the next element in the tree
                if (current_element->right != NIL)
                {
                    // go right and down
                    current_element = current_element->right;
                    went_up = false;
                }
                else
                {
                    went_up = true;
                    node* parent = current_element->parent;
                    if (parent == NIL)
                    {
                        // in this case we have iterated over all the element of the tree
                        current_element = 0;
                        return false;
                    }

                    from_left = (parent->left == current_element);
                    // go up to parent
                    current_element = parent;
                }

                while (true)
                {
                    if (went_up)
                    {
                        if (from_left)
                        {
                            // in this case we have found the next node
                            break;
                        }
                        else
                        {
                            // we should go up
                            node* parent = current_element->parent;
                            from_left = (parent->left == current_element);
                            current_element = parent;
                            if (current_element == NIL)
                            {
                                // in this case we have iterated over all the elements
                                // in the tree
                                current_element = 0;
                                return false;
                            }
                        }
                    }
                    else
                    {
                        // we just went down to a child node
                        if (current_element->left != NIL)
                        {
                            // go left
                            went_up = false;
                            current_element = current_element->left;
                        }
                        else
                        {
                            // if there is no left child then we have found the next node
                            break;
                        }
                    }
                }

                return true;
            }
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // private member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::
    delete_tree (
        node* t
    )
    {
        if (t->left != NIL)
            delete_tree(t->left);
        if (t->right != NIL)
            delete_tree(t->right);
        pool.deallocate(t);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::
    rotate_left (
        node* t
    )
    {

        // perform the rotation
        node* temp = t->right;
        t->right = temp->left;
        if (temp->left != NIL)
            temp->left->parent = t;
        temp->left = t;
        temp->parent = t->parent;

        if (t == tree_root)
            tree_root = temp;
        else
        {
            // if t was on the left
            if (t->parent->left == t)
                t->parent->left = temp;
            else
                t->parent->right = temp;
        }

        t->parent = temp;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::
    rotate_right (
        node* t
    )
    {
        // perform the rotation
        node* temp = t->left;
        t->left = temp->right;
        if (temp->right != NIL)
            temp->right->parent = t;
        temp->right = t;
        temp->parent = t->parent;

        if (t == tree_root)
            tree_root = temp;
        else
        {
            // if t is a left child
            if (t->parent->left == t)
                t->parent->left = temp;
            else
                t->parent->right = temp;
        }

        t->parent = temp;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::
    double_rotate_right (
        node* t
    )
    {

        // preform the rotation
        node& temp = *(t->left->right);
        t->left = temp.right;
        temp.right->parent = t;
        temp.left->parent = temp.parent;
        temp.parent->right = temp.left;
        temp.parent->parent = &temp;
        temp.right = t;
        temp.left = temp.parent;
        temp.parent = t->parent;

        if (tree_root == t)
            tree_root = &temp;
        else
        {
            // t is a left child
            if (t->parent->left == t)
                t->parent->left = &temp;
            else
                t->parent->right = &temp;
        }
        t->parent = &temp;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::
    double_rotate_left (
        node* t
    )
    {

        // preform the rotation
        node& temp = *(t->right->left);
        t->right = temp.left;
        temp.left->parent = t;
        temp.right->parent = temp.parent;
        temp.parent->left = temp.right;
        temp.parent->parent = &temp;
        temp.left = t;
        temp.right = temp.parent;
        temp.parent = t->parent;

        if (tree_root == t)
            tree_root = &temp;
        else
        {
            // t is a left child
            if (t->parent->left == t)
                t->parent->left = &temp;
            else
                t->parent->right = &temp;
        }
        t->parent = &temp;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::
    remove_biggest_element_in_tree (
        node* t,
        domain& d,
        range& r
    )
    {

        node* next = t->right;
        node* child;  // the child node of the one we will slice out

        if (next == NIL)
        {
            // need to determine if t is a right or left child
            if (t->parent->right == t)
                child = t->parent->right = t->left;
            else
                child = t->parent->left = t->left;

            // update tree_root if necessary
            if (t == tree_root)
                tree_root = child;
        }
        else
        {
            // find the least node
            do
            {
                t = next;
                next = next->right;
            } while (next != NIL);
            // t is a right child
            child = t->parent->right = t->left;

        }

        // swap the item from this node into d and r
        exchange(d,t->d);
        exchange(r,t->r);

        // plug hole right by removing this node
        child->parent = t->parent;

        // keep the red-black properties true
        if (t->color == black)
            fix_after_remove(child);

        // free the memory for this removed node
        pool.deallocate(t);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    bool binary_search_tree_kernel_2<domain,range,mem_manager,compare>::
    remove_least_element_in_tree (
        node* t,
        domain& d,
        range& r
    )
    {

        node* next = t->left;
        node* child;  // the child node of the one we will slice out

        if (next == NIL)
        {
            // need to determine if t is a left or right child
            if (t->parent->left == t)
                child = t->parent->left = t->right;
            else
                child = t->parent->right = t->right;

            // update tree_root if necessary
            if (t == tree_root)
                tree_root = child;
        }
        else
        {
            // find the least node
            do
            {
                t = next;
                next = next->left;
            } while (next != NIL);
            // t is a left child
            child = t->parent->left = t->right;

        }

        // swap the item from this node into d and r
        exchange(d,t->d);
        exchange(r,t->r);

        // plug hole left by removing this node
        child->parent = t->parent;

        // keep the red-black properties true
        if (t->color == black)
            fix_after_remove(child);

        bool rvalue = (t == current_element);
        // free the memory for this removed node
        pool.deallocate(t);
        return rvalue;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::
    add_to_tree (
        node* t,
        domain& d,
        range& r
    )
    {
        // parent of the current node
        node* parent;

        // find a place to add node
        while (true)
        {
            parent = t;
            // if item should be put on the left then go left
            if (comp(d , t->d))
            {
                t = t->left;
                if (t == NIL)
                {
                    t = parent->left = pool.allocate();
                    break;
                }
            }
            // if item should be put on the right then go right
            else
            {
                t = t->right;
                if (t == NIL)
                {
                    t = parent->right = pool.allocate();
                    break;
                }
            }
        }

        // t is now the node where we will add item and
        // parent is the parent of t

        t->parent = parent;
        t->left = NIL;
        t->right = NIL;
        t->color = red;
        exchange(t->d,d);
        exchange(t->r,r);

        // keep the red-black properties true
        fix_after_add(t);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::
    remove_from_tree (
        node* t,
        const domain& d,
        domain& d_copy,
        range& r
    )
    {
        while (true)
        {
            if ( comp(d , t->d) )
            {
                // if item is on the left then look in left
                t = t->left;
            }
            else if (comp(t->d , d))
            {
                // if item is on the right then look in right
                t = t->right;
            }
            else
            {
                // found the node we want to remove

                // swap out the item into d_copy and r
                exchange(d_copy,t->d);
                exchange(r,t->r);

                if (t->left == NIL)
                {
                    // if there is no left subtree

                    node* parent = t->parent;

                    // plug hole with right subtree

                    // if t is on the left
                    if (parent->left == t)
                        parent->left = t->right;
                    else
                        parent->right = t->right;
                    t->right->parent = parent;

                    // update tree_root if necessary
                    if (t == tree_root)
                        tree_root = t->right;

                    if (t->color == black)
                        fix_after_remove(t->right);

                    // delete old node
                    pool.deallocate(t);
                }
                else if (t->right == NIL)
                {
                    // if there is no right subtree

                    node* parent = t->parent;

                    // plug hole with left subtree
                    if (parent->left == t)
                        parent->left = t->left;
                    else
                        parent->right = t->left;
                    t->left->parent = parent;

                    // update tree_root if necessary
                    if (t == tree_root)
                        tree_root = t->left;

                    if (t->color == black)
                        fix_after_remove(t->left);

                    // delete old node
                    pool.deallocate(t);
                }
                else
                {
                    // if there is both a left and right subtree
                    // get an element to fill this node now that its been swapped into
                    // item_copy
                    if (remove_least_element_in_tree(t->right,t->d,t->r))
                    {
                        // the node removed was the one pointed to by current_element so we
                        // need to update it so that it points to the right spot.
                        current_element = t;
                    }
                }

                // quit loop
                break;
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::
    remove_from_tree (
        node* t,
        const domain& d
    )
    {
        while (true)
        {
            if ( comp(d , t->d) )
            {
                // if item is on the left then look in left
                t = t->left;
            }
            else if (comp(t->d , d))
            {
                // if item is on the right then look in right
                t = t->right;
            }
            else
            {
                // found the node we want to remove

                if (t->left == NIL)
                {
                    // if there is no left subtree

                    node* parent = t->parent;

                    // plug hole with right subtree

                    if (parent->left == t)
                        parent->left = t->right;
                    else
                        parent->right = t->right;
                    t->right->parent = parent;

                    // update tree_root if necessary
                    if (t == tree_root)
                        tree_root = t->right;

                    if (t->color == black)
                        fix_after_remove(t->right);

                    // delete old node
                    pool.deallocate(t);
                }
                else if (t->right == NIL)
                {
                    // if there is no right subtree

                    node* parent = t->parent;

                    // plug hole with left subtree
                    if (parent->left == t)
                        parent->left = t->left;
                    else
                        parent->right = t->left;
                    t->left->parent = parent;

                    // update tree_root if necessary
                    if (t == tree_root)
                        tree_root = t->left;

                    if (t->color == black)
                        fix_after_remove(t->left);

                    // delete old node
                    pool.deallocate(t);
                }
                else
                {
                    // if there is both a left and right subtree
                    // get an element to fill this node now that its been swapped into
                    // item_copy
                    remove_least_element_in_tree(t->right,t->d,t->r);

                }

                // quit loop
                break;
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    range* binary_search_tree_kernel_2<domain,range,mem_manager,compare>::
    return_reference (
        node* t,
        const domain& d
    )
    {
        while (t != NIL)
        {
            if ( comp(d , t->d ))
            {
                // if item is on the left then look in left
                t = t->left;
            }
            else if (comp(t->d , d))
            {
                // if item is on the right then look in right
                t = t->right;
            }
            else
            {
                // if it's found then return a reference to it
                return &(t->r);
            }
        }
        return 0;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    const range* binary_search_tree_kernel_2<domain,range,mem_manager,compare>::
    return_reference (
        const node* t,
        const domain& d
    ) const
    {
        while (t != NIL)
        {
            if ( comp(d , t->d) )
            {
                // if item is on the left then look in left
                t = t->left;
            }
            else if (comp(t->d , d))
            {
                // if item is on the right then look in right
                t = t->right;
            }
            else
            {
                // if it's found then return a reference to it
                return &(t->r);
            }
        }
        return 0;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::
    fix_after_add (
        node* t
    )
    {

        while (t->parent->color == red)
        {
            node& grandparent = *(t->parent->parent);

            // if both t's parent and its sibling are red
            if (grandparent.left->color == grandparent.right->color)
            {
                grandparent.color = red;
                grandparent.left->color = black;
                grandparent.right->color = black;
                t = &grandparent;
            }
            else
            {
                // if t is a left child
                if (t == t->parent->left)
                {
                    // if t's parent is a left child
                    if (t->parent == grandparent.left)
                    {
                        grandparent.color = red;
                        grandparent.left->color = black;
                        rotate_right(&grandparent);
                    }
                    // if t's parent is a right child
                    else
                    {
                        t->color = black;
                        grandparent.color = red;
                        double_rotate_left(&grandparent);
                    }
                }
                // if t is a right child
                else
                {
                    // if t's parent is a left child
                    if (t->parent == grandparent.left)
                    {
                        t->color = black;
                        grandparent.color = red;
                        double_rotate_right(&grandparent);
                    }
                    // if t's parent is a right child
                    else
                    {
                        grandparent.color = red;
                        grandparent.right->color = black;
                        rotate_left(&grandparent);
                    }
                }
                break;
            }
        }
        tree_root->color = black;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::
    fix_after_remove (
        node* t
    )
    {

        while (t != tree_root && t->color == black)
        {
            if (t->parent->left == t)
            {
                node* sibling = t->parent->right;
                if (sibling->color == red)
                {
                    sibling->color = black;
                    t->parent->color = red;
                    rotate_left(t->parent);
                    sibling = t->parent->right;
                }

                if (sibling->left->color == black && sibling->right->color == black)
                {
                    sibling->color = red;
                    t = t->parent;
                }
                else
                {
                    if (sibling->right->color == black)
                    {
                        sibling->left->color = black;
                        sibling->color = red;
                        rotate_right(sibling);
                        sibling = t->parent->right;
                    }

                    sibling->color = t->parent->color;
                    t->parent->color = black;
                    sibling->right->color = black;
                    rotate_left(t->parent);
                    t = tree_root;

                }

            }
            else
            {

                node* sibling = t->parent->left;
                if (sibling->color == red)
                {
                    sibling->color = black;
                    t->parent->color = red;
                    rotate_right(t->parent);
                    sibling = t->parent->left;
                }

                if (sibling->left->color == black && sibling->right->color == black)
                {
                    sibling->color = red;
                    t = t->parent;
                }
                else
                {
                    if (sibling->left->color == black)
                    {
                        sibling->right->color = black;
                        sibling->color = red;
                        rotate_left(sibling);
                        sibling = t->parent->left;
                    }

                    sibling->color = t->parent->color;
                    t->parent->color = black;
                    sibling->left->color = black;
                    rotate_right(t->parent);
                    t = tree_root;

                }

            }

        }
        t->color = black;

    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    short binary_search_tree_kernel_2<domain,range,mem_manager,compare>::
    tree_height (
        node* t
    ) const
    {
        if (t == NIL)
            return 0;

        short height1 = tree_height(t->left);
        short height2 = tree_height(t->right);
        if (height1 > height2)
            return height1 + 1;
        else
            return height2 + 1;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    unsigned long binary_search_tree_kernel_2<domain,range,mem_manager,compare>::
    get_count (
        const domain& d,
        node* tree_root
    ) const
    {
        if (tree_root != NIL)
        {
            if (comp(d , tree_root->d))
            {
                // go left
                return get_count(d,tree_root->left);
            }
            else if (comp(tree_root->d , d))
            {
                // go right
                return get_count(d,tree_root->right);
            }
            else
            {
                // go left and right to look for more matches
                return   get_count(d,tree_root->left)
                       + get_count(d,tree_root->right)
                       + 1;
            }
        }
        return 0;
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_BINARY_SEARCH_TREE_KERNEl_2_


dlib C++ Library - binary_search_tree_kernel_c.h

// 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_C_
#define DLIB_BINARY_SEARCH_TREE_KERNEl_C_

#include "../interfaces/map_pair.h"
#include "binary_search_tree_kernel_abstract.h"
#include "../algs.h"
#include "../assert.h"

namespace dlib
{

    template <
        typename bst_base
        >
    class binary_search_tree_kernel_c : public bst_base
    {
        typedef typename bst_base::domain_type domain;
        typedef typename bst_base::range_type range;

        public:

            binary_search_tree_kernel_c () {}

            void remove (
                const domain& d,
                domain& d_copy,
                range& r
            );

            void destroy (
                const domain& d
            );

            void add (
                domain& d,
                range& r
            );

            void remove_any (
                domain& d,
                range& r
            );

            const map_pair<domain, range>& element(
            ) const
            {
                DLIB_CASSERT(this->current_element_valid() == true,
                    "\tconst map_pair<domain,range>& binary_search_tree::element() const"
                    << "\n\tyou can't access the current element if it doesn't exist"
                    << "\n\tthis: " << this
                );

                return bst_base::element();
            }

            map_pair<domain, range>& element(
            )
            {
                DLIB_CASSERT(this->current_element_valid() == true,
                    "\tmap_pair<domain,range>& binary_search_tree::element()"
                    << "\n\tyou can't access the current element if it doesn't exist"
                    << "\n\tthis: " << this
                );

                return bst_base::element();
            }

            void remove_last_in_order (
                domain& d,
                range& r
            );

            void remove_current_element (
                domain& d,
                range& r
            );

    };

    template <
        typename bst_base
        >
    inline void swap (
        binary_search_tree_kernel_c<bst_base>& a,
        binary_search_tree_kernel_c<bst_base>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename bst_base
        >
    void binary_search_tree_kernel_c<bst_base>::
    add (
        domain& d,
        range& r
    )
    {
        DLIB_CASSERT( static_cast<const void*>(&d) != static_cast<void*>(&r),
            "\tvoid binary_search_tree::add"
            << "\n\tyou can't call add() and give the same object to both parameters."
            << "\n\tthis:       " << this
            << "\n\t&d:         " << &d
            << "\n\t&r:         " << &r
            << "\n\tsize():     " << this->size()
            );

        bst_base::add(d,r);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename bst_base
        >
    void binary_search_tree_kernel_c<bst_base>::
    destroy (
        const domain& d
    )
    {
        DLIB_CASSERT(this->operator[](d) != 0,
            "\tvoid binary_search_tree::destroy"
            << "\n\tthe element must be in the tree for it to be removed"
            << "\n\tthis:    " << this
            << "\n\t&d:      " << &d
            );

        bst_base::destroy(d);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename bst_base
        >
    void binary_search_tree_kernel_c<bst_base>::
    remove (
        const domain& d,
        domain& d_copy,
        range& r
    )
    {
        DLIB_CASSERT(this->operator[](d) != 0 &&
                (static_cast<const void*>(&d) != static_cast<void*>(&d_copy)) &&
                (static_cast<const void*>(&d) != static_cast<void*>(&r)) &&
                (static_cast<const void*>(&r) != static_cast<void*>(&d_copy)),
            "\tvoid binary_search_tree::remove"
            << "\n\tthe element must be in the tree for it to be removed"
            << "\n\tthis:       " << this
            << "\n\t&d:         " << &d
            << "\n\t&d_copy:    " << &d_copy
            << "\n\t&r:         " << &r
            );

        bst_base::remove(d,d_copy,r);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename bst_base
        >
    void binary_search_tree_kernel_c<bst_base>::
    remove_any(
        domain& d,
        range& r
    )
    {
        DLIB_CASSERT(this->size() != 0 &&
            (static_cast<const void*>(&d) != static_cast<void*>(&r)),
            "\tvoid binary_search_tree::remove_any"
            << "\n\ttree must not be empty if something is going to be removed"
            << "\n\tthis: " << this
            << "\n\t&d:   " << &d
            << "\n\t&r:   " << &r
            );

        bst_base::remove_any(d,r);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename bst_base
        >
    void binary_search_tree_kernel_c<bst_base>::
    remove_last_in_order (
        domain& d,
        range& r
    )
    {
        DLIB_CASSERT(this->size() > 0,
            "\tvoid binary_search_tree::remove_last_in_order()"
            << "\n\tyou can't remove an element if it doesn't exist"
            << "\n\tthis: " << this
            );

        bst_base::remove_last_in_order(d,r);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename bst_base
        >
    void binary_search_tree_kernel_c<bst_base>::
    remove_current_element (
        domain& d,
        range& r
    )
    {
        DLIB_CASSERT(this->current_element_valid() == true,
            "\tvoid binary_search_tree::remove_current_element()"
            << "\n\tyou can't remove the current element if it doesn't exist"
            << "\n\tthis: " << this
            );

        bst_base::remove_current_element(d,r);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_BINARY_SEARCH_TREE_KERNEl_C_


dlib C++ Library - bit_stream_kernel_1.cpp

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_BIT_STREAM_KERNEL_1_CPp_
#define DLIB_BIT_STREAM_KERNEL_1_CPp_

#include "bit_stream_kernel_1.h"
#include "../algs.h"

#include <iostream>

namespace dlib
{

    inline void swap (
        bit_stream_kernel_1& a,
        bit_stream_kernel_1& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    void bit_stream_kernel_1::
    clear (
    )
    {
        if (write_mode)
        {
            write_mode = false;

            // flush output buffer
            if (buffer_size > 0)
            {
                buffer <<= 8 - buffer_size;
                osp->write(reinterpret_cast<char*>(&buffer),1);
            }
        }
        else
            read_mode = false;

    }

// ----------------------------------------------------------------------------------------

    void bit_stream_kernel_1::
    set_input_stream (
        std::istream& is
    )
    {
        isp = &is;
        read_mode = true;

        buffer_size = 0;
    }

// ----------------------------------------------------------------------------------------

    void bit_stream_kernel_1::
    set_output_stream (
        std::ostream& os
    )
    {
        osp = &os;
        write_mode = true;

        buffer_size = 0;
    }

// ----------------------------------------------------------------------------------------

    void bit_stream_kernel_1::
    close (
    )
    {
        if (write_mode)
        {
            write_mode = false;

            // flush output buffer
            if (buffer_size > 0)
            {
                buffer <<= 8 - buffer_size;
                osp->write(reinterpret_cast<char*>(&buffer),1);
            }
        }
        else
            read_mode = false;
    }

// ----------------------------------------------------------------------------------------

    bool bit_stream_kernel_1::
    is_in_write_mode (
    ) const
    {
        return write_mode;
    }

// ----------------------------------------------------------------------------------------

    bool bit_stream_kernel_1::
    is_in_read_mode (
    ) const
    {
        return read_mode;
    }

// ----------------------------------------------------------------------------------------

    void bit_stream_kernel_1::
    write (
        int bit
    )
    {
        // flush buffer if necessary
        if (buffer_size == 8)
        {
            buffer <<= 8 - buffer_size;
            if (osp->rdbuf()->sputn(reinterpret_cast<char*>(&buffer),1) == 0)
            {
                throw std::ios_base::failure("error occured in the bit_stream object");
            }

            buffer_size = 0;
        }

        ++buffer_size;
        buffer <<= 1;
        buffer += static_cast<unsigned char>(bit);
    }

// ----------------------------------------------------------------------------------------

    bool bit_stream_kernel_1::
    read (
        int& bit
    )
    {
        // get new byte if necessary
        if (buffer_size == 0)
        {
            if (isp->rdbuf()->sgetn(reinterpret_cast<char*>(&buffer), 1) == 0)
            {
                // if we didn't read anything then return false
                return false;
            }

            buffer_size = 8;
        }

        // put the most significant bit from buffer into bit
        bit = static_cast<int>(buffer >> 7);

        // shift out the bit that was just read
        buffer <<= 1;
        --buffer_size;

        return true;
    }

// ----------------------------------------------------------------------------------------

    void bit_stream_kernel_1::
    swap (
        bit_stream_kernel_1& item
    )
    {

        std::istream*   isp_temp            = item.isp;
        std::ostream*   osp_temp            = item.osp;
        bool            write_mode_temp     = item.write_mode;
        bool            read_mode_temp      = item.read_mode;
        unsigned char   buffer_temp         = item.buffer;
        unsigned short  buffer_size_temp    = item.buffer_size;

        item.isp            = isp;
        item.osp            = osp;
        item.write_mode     = write_mode;
        item.read_mode      = read_mode;
        item.buffer         = buffer;
        item.buffer_size    = buffer_size;

        isp             = isp_temp;
        osp             = osp_temp;
        write_mode      = write_mode_temp;
        read_mode       = read_mode_temp;
        buffer          = buffer_temp;
        buffer_size     = buffer_size_temp;

    }

// ----------------------------------------------------------------------------------------

}
#endif // DLIB_BIT_STREAM_KERNEL_1_CPp_


dlib C++ Library - bit_stream_kernel_1.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_BIT_STREAM_KERNEl_1_
#define DLIB_BIT_STREAM_KERNEl_1_

#include "bit_stream_kernel_abstract.h"
#include <iosfwd>

namespace dlib
{

    class bit_stream_kernel_1
    {

        /*!
            INITIAL VALUE
                write_mode          == false
                read_mode           == false

            CONVENTION
                write_mode          == is_in_write_mode()
                read_mode           == is_in_read_mode()

                if (write_mode)
                {
                    osp             == pointer to an ostream object
                    buffer          == the low order bits of buffer are the bits to be
                                       written
                    buffer_size     == the number of low order bits in buffer that are
                                       bits that should be written
                    the lowest order bit is the last bit entered by the user
                }

                if (read_mode)
                {
                    isp             == pointer to an istream object
                    buffer          == the high order bits of buffer are the bits
                                       waiting to be read by the user
                    buffer_size     == the number of high order bits in buffer that
                                       are bits that are waiting to be read
                    the highest order bit is the next bit to give to the user
                }
        !*/

    public:

        bit_stream_kernel_1 (
        ) :
            write_mode(false),
            read_mode(false)
        {}

        virtual ~bit_stream_kernel_1 (
        )
        {}

        void clear (
        );

        void set_input_stream (
            std::istream& is
        );

        void set_output_stream (
            std::ostream& os
        );

        void close (
        );

        inline bool is_in_write_mode (
        ) const;

        inline bool is_in_read_mode (
        ) const;

        inline void write (
            int bit
        );

        bool read (
            int& bit
        );

        void swap (
            bit_stream_kernel_1& item
        );

        private:

            // member data
            std::istream* isp;
            std::ostream* osp;
            bool write_mode;
            bool read_mode;
            unsigned char buffer;
            unsigned short buffer_size;

            // restricted functions
            bit_stream_kernel_1(bit_stream_kernel_1&);        // copy constructor
            bit_stream_kernel_1& operator=(bit_stream_kernel_1&);  // assignment operator

    };

    inline void swap (
        bit_stream_kernel_1& a,
        bit_stream_kernel_1& b
    );

// ----------------------------------------------------------------------------------------

}

#ifdef NO_MAKEFILE
#include "bit_stream_kernel_1.cpp"
#endif

#endif // DLIB_BIT_STREAM_KERNEl_1_


dlib C++ Library - bit_stream_multi_1.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_BIT_STREAM_MULTi_1_
#define DLIB_BIT_STREAM_MULTi_1_

#include "bit_stream_multi_abstract.h"

namespace dlib
{
    template <
        typename bit_stream_base
        >
    class bit_stream_multi_1 : public bit_stream_base
    {

    public:

        void multi_write (
            unsigned long data,
            int num_to_write
        );

        int multi_read (
            unsigned long& data,
            int num_to_read
        );

    };

    template <
        typename bit_stream_base
        >
    inline void swap (
        bit_stream_multi_1<bit_stream_base>& a,
        bit_stream_multi_1<bit_stream_base>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename bit_stream_base
        >
    void bit_stream_multi_1<bit_stream_base>::
    multi_write (
        unsigned long data,
        int num_to_write
    )
    {
        // move the first bit into the most significant position
        data <<= 32 - num_to_write;

        for (int i = 0; i < num_to_write; ++i)
        {
            // write the first bit from data
            this->write(static_cast<char>(data >> 31));

            // shift the next bit into position
            data <<= 1;

        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename bit_stream_base
        >
    int bit_stream_multi_1<bit_stream_base>::
    multi_read (
        unsigned long& data,
        int num_to_read
    )
    {
        int bit, i;
        data = 0;
        for (i = 0; i < num_to_read; ++i)
        {

            // get a bit
            if (this->read(bit) == false)
                break;

            // shift data to make room for this new bit
            data <<= 1;

            // put bit into the least significant position in data
            data += static_cast<unsigned long>(bit);

        }

        return i;
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_BIT_STREAM_MULTi_1_


dlib C++ Library - bound_function_pointer_kernel_1.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_BOUND_FUNCTION_POINTER_KERNEl_1_
#define DLIB_BOUND_FUNCTION_POINTER_KERNEl_1_

#include "../algs.h"
#include "../member_function_pointer.h"
#include "bound_function_pointer_kernel_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    namespace bfp1_helpers
    {
        template <typename T> struct strip { typedef T type; };
        template <typename T> struct strip<T&> { typedef T type; };

    // ------------------------------------------------------------------------------------

        class bound_function_helper_base_base
        {
        public:
            virtual ~bound_function_helper_base_base(){}
            virtual void call() const = 0;
            virtual bool is_set() const = 0;
            virtual void clone(void* ptr) const = 0;
        };

    // ------------------------------------------------------------------------------------

        template <typename T1, typename T2, typename T3, typename T4>
        class bound_function_helper_base : public bound_function_helper_base_base
        {
        public:
            bound_function_helper_base():arg1(0), arg2(0), arg3(0), arg4(0) {}

            typename strip<T1>::type* arg1;
            typename strip<T2>::type* arg2;
            typename strip<T3>::type* arg3;
            typename strip<T4>::type* arg4;

            member_function_pointer<T1,T2,T3,T4> mfp;
        };

    // ----------------

        template <typename F, typename T1 = void, typename T2 = void, typename T3 = void, typename T4 = void>
        class bound_function_helper : public bound_function_helper_base<T1,T2,T3,T4>
        {
        public:
            void call() const
            {
                (*fp)(*this->arg1, *this->arg2, *this->arg3, *this->arg4);
            }

            typename strip<F>::type* fp;
        };

        template <typename T1, typename T2, typename T3, typename T4>
        class bound_function_helper<void,T1,T2,T3,T4> : public bound_function_helper_base<T1,T2,T3,T4>
        {
        public:
            void call() const
            {
                if (this->mfp)    this->mfp(*this->arg1, *this->arg2, *this->arg3, *this->arg4);
                else if (fp) fp(*this->arg1, *this->arg2, *this->arg3, *this->arg4);
            }

            void (*fp)(T1, T2, T3, T4);
        };

    // ----------------

        template <typename F>
        class bound_function_helper<F,void,void,void,void> : public bound_function_helper_base<void,void,void,void>
        {
        public:
            void call() const
            {
                (*fp)();
            }

            typename strip<F>::type* fp;
        };

        template <>
        class bound_function_helper<void,void,void,void,void> : public bound_function_helper_base<void,void,void,void>
        {
        public:
            void call() const
            {
                if (this->mfp)    this->mfp();
                else if (fp) fp();
            }

            void (*fp)();
        };

    // ----------------

        template <typename F, typename T1>
        class bound_function_helper<F,T1,void,void,void> : public bound_function_helper_base<T1,void,void,void>
        {
        public:
            void call() const
            {
                (*fp)(*this->arg1);
            }

            typename strip<F>::type* fp;
        };

        template <typename T1>
        class bound_function_helper<void,T1,void,void,void> : public bound_function_helper_base<T1,void,void,void>
        {
        public:
            void call() const
            {
                if (this->mfp)    this->mfp(*this->arg1);
                else if (fp) fp(*this->arg1);
            }

            void (*fp)(T1);
        };

    // ----------------

        template <typename F, typename T1, typename T2>
        class bound_function_helper<F,T1,T2,void,void> : public bound_function_helper_base<T1,T2,void,void>
        {
        public:
            void call() const
            {
                (*fp)(*this->arg1, *this->arg2);
            }

            typename strip<F>::type* fp;
        };

        template <typename T1, typename T2>
        class bound_function_helper<void,T1,T2,void,void> : public bound_function_helper_base<T1,T2,void,void>
        {
        public:
            void call() const
            {
                if (this->mfp)    this->mfp(*this->arg1, *this->arg2);
                else if (fp) fp(*this->arg1, *this->arg2);
            }

            void (*fp)(T1, T2);
        };

    // ----------------

        template <typename F, typename T1, typename T2, typename T3>
        class bound_function_helper<F,T1,T2,T3,void> : public bound_function_helper_base<T1,T2,T3,void>
        {
        public:
            void call() const
            {
                (*fp)(*this->arg1, *this->arg2, *this->arg3);
            }

            typename strip<F>::type* fp;
        };

        template <typename T1, typename T2, typename T3>
        class bound_function_helper<void,T1,T2,T3,void> : public bound_function_helper_base<T1,T2,T3,void>
        {
        public:

            void call() const
            {
                if (this->mfp)    this->mfp(*this->arg1, *this->arg2, *this->arg3);
                else if (fp) fp(*this->arg1, *this->arg2, *this->arg3);
            }

            void (*fp)(T1, T2, T3);
        };

    // ------------------------------------------------------------------------------------
    // ------------------------------------------------------------------------------------

        template <typename T>
        class bound_function_helper_T : public T
        {
        public:
            bound_function_helper_T(){ this->fp = 0;}

            bool is_set() const
            {
                return this->fp != 0 || this->mfp.is_set();
            }

            template <unsigned long mem_size>
            void safe_clone(stack_based_memory_block<mem_size>& buf)
            {
                // This is here just to validate the assumption that our block of memory we have made
                // in bf_memory is the right size to store the data for this object.  If you
                // get a compiler error on this line then email me :)
                COMPILE_TIME_ASSERT(sizeof(bound_function_helper_T) <= mem_size);
                clone(buf.get());
            }

            void clone   (void* ptr) const
            {
                bound_function_helper_T* p = new(ptr) bound_function_helper_T();
                p->arg1 = this->arg1;
                p->arg2 = this->arg2;
                p->arg3 = this->arg3;
                p->arg4 = this->arg4;
                p->fp = this->fp;
                p->mfp = this->mfp;
            }
        };

    }

// ----------------------------------------------------------------------------------------

    class bound_function_pointer
    {
        typedef bfp1_helpers::bound_function_helper_T<bfp1_helpers::bound_function_helper<void,int> > bf_null_type;

    public:

        // These typedefs are here for backwards compatibility with previous versions of
        // dlib.
        typedef bound_function_pointer kernel_1a;
        typedef bound_function_pointer kernel_1a_c;

        bound_function_pointer (
        ) { bf_null_type().safe_clone(bf_memory); }

        bound_function_pointer (
            const bound_function_pointer& item
        ) { item.bf()->clone(bf_memory.get()); }

        ~bound_function_pointer()
        { destroy_bf_memory(); }

        bound_function_pointer& operator= (
            const bound_function_pointer& item
        ) { bound_function_pointer(item).swap(*this); return *this; }

        void clear (
        ) { bound_function_pointer().swap(*this); }

        bool is_set (
        ) const
        {
            return bf()->is_set();
        }

        void swap (
            bound_function_pointer& item
        )
        {
            // make a temp copy of item
            bound_function_pointer temp(item);

            // destory the stuff in item
            item.destroy_bf_memory();
            // copy *this into item
            bf()->clone(item.bf_memory.get());

            // destory the stuff in this
            destroy_bf_memory();
            // copy temp into *this
            temp.bf()->clone(bf_memory.get());
        }

        void operator() (
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(is_set() == true ,
                "\tvoid bound_function_pointer::operator()"
                << "\n\tYou must call set() before you can use this function"
                << "\n\tthis: " << this
            );

            bf()->call();
        }

    private:
        struct dummy{ void nonnull() {}};
        typedef void (dummy::*safe_bool)();

    public:
        operator safe_bool () const { return is_set() ? &dummy::nonnull : 0; }
        bool operator!() const { return !is_set(); }

    // -------------------------------------------
    //      set function object overloads
    // -------------------------------------------

        template <typename F>
        void set (
            F& function_object
        )
        {
            COMPILE_TIME_ASSERT(is_function<F>::value == false);
            COMPILE_TIME_ASSERT(is_pointer_type<F>::value == false);

            using namespace bfp1_helpers;
            destroy_bf_memory();
            typedef bound_function_helper_T<bound_function_helper<F> > bf_helper_type;

            bf_helper_type temp;
            temp.fp = &function_object;

            temp.safe_clone(bf_memory);
        }

        template <typename F, typename A1 >
        void set (
            F& function_object,
            A1& arg1
        )
        {
            COMPILE_TIME_ASSERT(is_function<F>::value == false);
            COMPILE_TIME_ASSERT(is_pointer_type<F>::value == false);

            using namespace bfp1_helpers;
            destroy_bf_memory();
            typedef bound_function_helper_T<bound_function_helper<F,A1> > bf_helper_type;

            bf_helper_type temp;
            temp.arg1 = &arg1;
            temp.fp = &function_object;

            temp.safe_clone(bf_memory);
        }

        template <typename F, typename A1, typename A2 >
        void set (
            F& function_object,
            A1& arg1,
            A2& arg2
        )
        {
            COMPILE_TIME_ASSERT(is_function<F>::value == false);
            COMPILE_TIME_ASSERT(is_pointer_type<F>::value == false);

            using namespace bfp1_helpers;
            destroy_bf_memory();
            typedef bound_function_helper_T<bound_function_helper<F,A1,A2> > bf_helper_type;

            bf_helper_type temp;
            temp.arg1 = &arg1;
            temp.arg2 = &arg2;
            temp.fp = &function_object;

            temp.safe_clone(bf_memory);
        }

        template <typename F, typename A1, typename A2, typename A3 >
        void set (
            F& function_object,
            A1& arg1,
            A2& arg2,
            A3& arg3
        )
        {
            COMPILE_TIME_ASSERT(is_function<F>::value == false);
            COMPILE_TIME_ASSERT(is_pointer_type<F>::value == false);

            using namespace bfp1_helpers;
            destroy_bf_memory();
            typedef bound_function_helper_T<bound_function_helper<F,A1,A2,A3> > bf_helper_type;

            bf_helper_type temp;
            temp.arg1 = &arg1;
            temp.arg2 = &arg2;
            temp.arg3 = &arg3;
            temp.fp = &function_object;

            temp.safe_clone(bf_memory);
        }

        template <typename F, typename A1, typename A2, typename A3, typename A4>
        void set (
            F& function_object,
            A1& arg1,
            A2& arg2,
            A3& arg3,
            A4& arg4
        )
        {
            COMPILE_TIME_ASSERT(is_function<F>::value == false);
            COMPILE_TIME_ASSERT(is_pointer_type<F>::value == false);

            using namespace bfp1_helpers;
            destroy_bf_memory();
            typedef bound_function_helper_T<bound_function_helper<F,A1,A2,A3,A4> > bf_helper_type;

            bf_helper_type temp;
            temp.arg1 = &arg1;
            temp.arg2 = &arg2;
            temp.arg3 = &arg3;
            temp.arg4 = &arg4;
            temp.fp = &function_object;

            temp.safe_clone(bf_memory);
        }

    // -------------------------------------------
    //      set mfp overloads
    // -------------------------------------------

        template <typename T>
        void set (
            T& object,
            void (T::*funct)()
        )
        {
            using namespace bfp1_helpers;
            destroy_bf_memory();
            typedef bound_function_helper_T<bound_function_helper<void> > bf_helper_type;

            bf_helper_type temp;
            temp.mfp.set(object,funct);

            temp.safe_clone(bf_memory);
        }

        template <typename T >
        void set (
            const T& object,
            void (T::*funct)()const
        )
        {
            using namespace bfp1_helpers;
            destroy_bf_memory();
            typedef bound_function_helper_T<bound_function_helper<void> > bf_helper_type;

            bf_helper_type temp;
            temp.mfp.set(object,funct);

            temp.safe_clone(bf_memory);
        }

    // -------------------------------------------

        template <typename T, typename T1, typename A1 >
        void set (
            T& object,
            void (T::*funct)(T1),
            A1& arg1
        )
        {
            using namespace bfp1_helpers;
            destroy_bf_memory();
            typedef bound_function_helper_T<bound_function_helper<void,T1> > bf_helper_type;

            bf_helper_type temp;
            temp.arg1 = &arg1;
            temp.mfp.set(object,funct);

            temp.safe_clone(bf_memory);
        }

        template <typename T, typename T1, typename A1 >
        void set (
            const T& object,
            void (T::*funct)(T1)const,
            A1& arg1
        )
        {
            using namespace bfp1_helpers;
            destroy_bf_memory();
            typedef bound_function_helper_T<bound_function_helper<void,T1> > bf_helper_type;

            bf_helper_type temp;
            temp.arg1 = &arg1;
            temp.mfp.set(object,funct);

            temp.safe_clone(bf_memory);
        }

    // ----------------

        template <typename T, typename T1, typename A1,
        typename T2, typename A2>
        void set (
            T& object,
            void (T::*funct)(T1, T2),
            A1& arg1,
            A2& arg2
        )
        {
            using namespace bfp1_helpers;
            destroy_bf_memory();
            typedef bound_function_helper_T<bound_function_helper<void,T1,T2> > bf_helper_type;

            bf_helper_type temp;
            temp.arg1 = &arg1;
            temp.arg2 = &arg2;
            temp.mfp.set(object,funct);

            temp.safe_clone(bf_memory);
        }

        template <typename T, typename T1, typename A1,
        typename T2, typename A2>
        void set (
            const T& object,
            void (T::*funct)(T1, T2)const,
            A1& arg1,
            A2& arg2
        )
        {
            using namespace bfp1_helpers;
            destroy_bf_memory();
            typedef bound_function_helper_T<bound_function_helper<void,T1,T2> > bf_helper_type;

            bf_helper_type temp;
            temp.arg1 = &arg1;
            temp.arg2 = &arg2;
            temp.mfp.set(object,funct);

            temp.safe_clone(bf_memory);
        }

    // ----------------

        template <typename T, typename T1, typename A1,
        typename T2, typename A2,
        typename T3, typename A3>
        void set (
            T& object,
            void (T::*funct)(T1, T2, T3),
            A1& arg1,
            A2& arg2,
            A3& arg3
        )
        {
            using namespace bfp1_helpers;
            destroy_bf_memory();
            typedef bound_function_helper_T<bound_function_helper<void,T1,T2,T3> > bf_helper_type;

            bf_helper_type temp;
            temp.arg1 = &arg1;
            temp.arg2 = &arg2;
            temp.arg3 = &arg3;
            temp.mfp.set(object,funct);

            temp.safe_clone(bf_memory);
        }

        template <typename T, typename T1, typename A1,
        typename T2, typename A2,
        typename T3, typename A3>
        void set (
            const T& object,
            void (T::*funct)(T1, T2, T3)const,
            A1& arg1,
            A2& arg2,
            A3& arg3
        )
        {
            using namespace bfp1_helpers;
            destroy_bf_memory();
            typedef bound_function_helper_T<bound_function_helper<void,T1,T2,T3> > bf_helper_type;

            bf_helper_type temp;
            temp.arg1 = &arg1;
            temp.arg2 = &arg2;
            temp.arg3 = &arg3;
            temp.mfp.set(object,funct);

            temp.safe_clone(bf_memory);
        }

    // ----------------

        template <typename T, typename T1, typename A1,
        typename T2, typename A2,
        typename T3, typename A3,
        typename T4, typename A4>
        void set (
            T& object,
            void (T::*funct)(T1, T2, T3, T4),
            A1& arg1,
            A2& arg2,
            A3& arg3,
            A4& arg4
        )
        {
            using namespace bfp1_helpers;
            destroy_bf_memory();
            typedef bound_function_helper_T<bound_function_helper<void,T1,T2,T3,T4> > bf_helper_type;

            bf_helper_type temp;
            temp.arg1 = &arg1;
            temp.arg2 = &arg2;
            temp.arg3 = &arg3;
            temp.arg4 = &arg4;
            temp.mfp.set(object,funct);

            temp.safe_clone(bf_memory);
        }

        template <typename T, typename T1, typename A1,
        typename T2, typename A2,
        typename T3, typename A3,
        typename T4, typename A4>
        void set (
            const T& object,
            void (T::*funct)(T1, T2, T3, T4)const,
            A1& arg1,
            A2& arg2,
            A3& arg3,
            A4& arg4
        )
        {
            using namespace bfp1_helpers;
            destroy_bf_memory();
            typedef bound_function_helper_T<bound_function_helper<void,T1,T2,T3,T4> > bf_helper_type;

            bf_helper_type temp;
            temp.arg1 = &arg1;
            temp.arg2 = &arg2;
            temp.arg3 = &arg3;
            temp.arg4 = &arg4;
            temp.mfp.set(object,funct);

            temp.safe_clone(bf_memory);
        }

    // -------------------------------------------
    //      set fp overloads
    // -------------------------------------------

        void set (
            void (*funct)()
        )
        {
            using namespace bfp1_helpers;
            destroy_bf_memory();
            typedef bound_function_helper_T<bound_function_helper<void> > bf_helper_type;

            bf_helper_type temp;
            temp.fp = funct;

            temp.safe_clone(bf_memory);
        }

        template <typename T1, typename A1>
        void set (
            void (*funct)(T1),
            A1& arg1
        )
        {
            using namespace bfp1_helpers;
            destroy_bf_memory();
            typedef bound_function_helper_T<bound_function_helper<void,T1> > bf_helper_type;

            bf_helper_type temp;
            temp.arg1 = &arg1;
            temp.fp = funct;

            temp.safe_clone(bf_memory);
        }

        template <typename T1, typename A1,
        typename T2, typename A2>
        void set (
            void (*funct)(T1, T2),
            A1& arg1,
            A2& arg2
        )
        {
            using namespace bfp1_helpers;
            destroy_bf_memory();
            typedef bound_function_helper_T<bound_function_helper<void,T1,T2> > bf_helper_type;

            bf_helper_type temp;
            temp.arg1 = &arg1;
            temp.arg2 = &arg2;
            temp.fp = funct;

            temp.safe_clone(bf_memory);
        }

        template <typename T1, typename A1,
        typename T2, typename A2,
        typename T3, typename A3>
        void set (
            void (*funct)(T1, T2, T3),
            A1& arg1,
            A2& arg2,
            A3& arg3
        )
        {
            using namespace bfp1_helpers;
            destroy_bf_memory();
            typedef bound_function_helper_T<bound_function_helper<void,T1,T2,T3> > bf_helper_type;

            bf_helper_type temp;
            temp.arg1 = &arg1;
            temp.arg2 = &arg2;
            temp.arg3 = &arg3;
            temp.fp = funct;

            temp.safe_clone(bf_memory);
        }

        template <typename T1, typename A1,
        typename T2, typename A2,
        typename T3, typename A3,
        typename T4, typename A4>
        void set (
            void (*funct)(T1, T2, T3, T4),
            A1& arg1,
            A2& arg2,
            A3& arg3,
            A4& arg4
        )
        {
            using namespace bfp1_helpers;
            destroy_bf_memory();
            typedef bound_function_helper_T<bound_function_helper<void,T1,T2,T3,T4> > bf_helper_type;

            bf_helper_type temp;
            temp.arg1 = &arg1;
            temp.arg2 = &arg2;
            temp.arg3 = &arg3;
            temp.arg4 = &arg4;
            temp.fp = funct;

            temp.safe_clone(bf_memory);
        }

    // -------------------------------------------

    private:

        stack_based_memory_block<sizeof(bf_null_type)> bf_memory;

        void destroy_bf_memory (
        )
        {
            // Honestly, this probably doesn't even do anything but I'm putting
            // it here just for good measure.
            bf()->~bound_function_helper_base_base();
        }

        bfp1_helpers::bound_function_helper_base_base*       bf ()
        { return static_cast<bfp1_helpers::bound_function_helper_base_base*>(bf_memory.get()); }

        const bfp1_helpers::bound_function_helper_base_base* bf () const
        { return static_cast<const bfp1_helpers::bound_function_helper_base_base*>(bf_memory.get()); }

    };

// ----------------------------------------------------------------------------------------

    inline void swap (
        bound_function_pointer& a,
        bound_function_pointer& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_BOUND_FUNCTION_POINTER_KERNEl_1_


dlib C++ Library - bsp.cpp

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_BSP_CPph_
#define DLIB_BSP_CPph_

#include "bsp.h"
#include <stack>

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

namespace dlib
{

    namespace impl1
    {

        void connect_all (
            map_id_to_con& cons,
            const std::vector<network_address>& hosts,
            unsigned long node_id
        )
        {
            cons.clear();
            for (unsigned long i = 0; i < hosts.size(); ++i)
            {
                scoped_ptr<bsp_con> con(new bsp_con(hosts[i]));
                dlib::serialize(node_id, con->stream); // tell the other end our node_id
                unsigned long id = i+1;
                cons.add(id, con);
            }
        }

        void connect_all_hostinfo (
            map_id_to_con& cons,
            const std::vector<hostinfo>& hosts,
            unsigned long node_id,
            std::string& error_string
        )
        {
            cons.clear();
            for (unsigned long i = 0; i < hosts.size(); ++i)
            {
                try
                {
                    scoped_ptr<bsp_con> con(new bsp_con(hosts[i].addr));
                    dlib::serialize(node_id, con->stream); // tell the other end our node_id
                    con->stream.flush();
                    unsigned long id = hosts[i].node_id;
                    cons.add(id, con);
                }
                catch (std::exception&)
                {
                    std::ostringstream sout;
                    sout << "Could not connect to " << hosts[i].addr;
                    error_string = sout.str();
                    break;
                }
            }
        }

        void send_out_connection_orders (
            map_id_to_con& cons,
            const std::vector<network_address>& hosts
        )
        {
            // tell everyone their node ids
            cons.reset();
            while (cons.move_next())
            {
                dlib::serialize(cons.element().key(), cons.element().value()->stream);
            }

            // now tell them who to connect to
            std::vector<hostinfo> targets;
            for (unsigned long i = 0; i < hosts.size(); ++i)
            {
                hostinfo info(hosts[i], i+1);

                dlib::serialize(targets, cons[info.node_id]->stream);
                targets.push_back(info);

                // let the other host know how many incoming connections to expect
                const unsigned long num = hosts.size()-targets.size();
                dlib::serialize(num, cons[info.node_id]->stream);
                cons[info.node_id]->stream.flush();
            }
        }

    // ------------------------------------------------------------------------------------

    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    namespace impl2
    {
        // These control bytes are sent before each message between nodes.  Note that many
        // of these are only sent between the control node (node 0) and the other nodes.
        // This is because the controller node is responsible for handling the
        // synchronization that needs to happen when all nodes block on calls to
        // receive_data()
        // at the same time.

        // denotes a normal content message.
        const static char MESSAGE_HEADER            = 0;

        // sent to the controller node when someone receives a message via receive_data().
        const static char GOT_MESSAGE               = 1;

        // sent to the controller node when someone sends a message via send().
        const static char SENT_MESSAGE              = 2;

        // sent to the controller node when someone enters a call to receive_data()
        const static char IN_WAITING_STATE          = 3;

        // broadcast when a node terminates itself.
        const static char NODE_TERMINATE            = 5;

        // broadcast by the controller node when it determines that all nodes are blocked
        // on calls to receive_data() and there aren't any messages in flight.  This is also
        // what makes us go to the next epoch.
        const static char SEE_ALL_IN_WAITING_STATE  = 6;

        // This isn't ever transmitted between nodes.  It is used internally to indicate
        // that an error occurred.
        const static char READ_ERROR                = 7;

    // ------------------------------------------------------------------------------------

        void read_thread (
            impl1::bsp_con* con,
            unsigned long node_id,
            unsigned long sender_id,
            impl1::thread_safe_message_queue& msg_buffer
        )
        {
            try
            {
                while(true)
                {
                    impl1::msg_data msg;
                    deserialize(msg.msg_type, con->stream);
                    msg.sender_id = sender_id;

                    if (msg.msg_type == MESSAGE_HEADER)
                    {
                        msg.data.reset(new std::vector<char>);
                        deserialize(msg.epoch, con->stream);
                        deserialize(*msg.data, con->stream);
                    }

                    msg_buffer.push_and_consume(msg);

                    if (msg.msg_type == NODE_TERMINATE)
                        break;
                }
            }
            catch (std::exception& e)
            {
                impl1::msg_data msg;
                msg.data.reset(new std::vector<char>);
                vectorstream sout(*msg.data);
                sout << "An exception was thrown while attempting to receive a message from processing node " << sender_id << ".\n";
                sout << "  Sending processing node address:   " << con->con->get_foreign_ip() << ":" << con->con->get_foreign_port() << std::endl;
                sout << "  Receiving processing node address: " << con->con->get_local_ip() << ":" << con->con->get_local_port() << std::endl;
                sout << "  Receiving processing node id:      " << node_id << std::endl;
                sout << "  Error message in the exception:    " << e.what() << std::endl;

                msg.sender_id = sender_id;
                msg.msg_type = READ_ERROR;

                msg_buffer.push_and_consume(msg);
            }
            catch (...)
            {
                impl1::msg_data msg;
                msg.data.reset(new std::vector<char>);
                vectorstream sout(*msg.data);
                sout << "An exception was thrown while attempting to receive a message from processing node " << sender_id << ".\n";
                sout << "  Sending processing node address:   " << con->con->get_foreign_ip() << ":" << con->con->get_foreign_port() << std::endl;
                sout << "  Receiving processing node address: " << con->con->get_local_ip() << ":" << con->con->get_local_port() << std::endl;
                sout << "  Receiving processing node id:      " << node_id << std::endl;

                msg.sender_id = sender_id;
                msg.msg_type = READ_ERROR;

                msg_buffer.push_and_consume(msg);
            }
        }

    // ------------------------------------------------------------------------------------

    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                          IMPLEMENTATION OF bsp_context OBJECT MEMBERS
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    void bsp_context::
    close_all_connections_gracefully(
    )
    {
        if (node_id() != 0)
        {
            _cons.reset();
            while (_cons.move_next())
            {
                // tell the other end that we are intentionally dropping the connection
                serialize(impl2::NODE_TERMINATE,_cons.element().value()->stream);
                _cons.element().value()->stream.flush();
            }
        }

        impl1::msg_data msg;
        // now wait for all the other nodes to terminate
        while (num_terminated_nodes < _cons.size() )
        {
            if (node_id() == 0 && num_waiting_nodes + num_terminated_nodes == _cons.size() && outstanding_messages == 0)
            {
                num_waiting_nodes = 0;
                broadcast_byte(impl2::SEE_ALL_IN_WAITING_STATE);
                ++current_epoch;
            }

            if (!msg_buffer.pop(msg))
                throw dlib::socket_error("Error reading from msg_buffer in dlib::bsp_context.");

            if (msg.msg_type == impl2::NODE_TERMINATE)
            {
                ++num_terminated_nodes;
                _cons[msg.sender_id]->terminated = true;
            }
            else if (msg.msg_type == impl2::READ_ERROR)
            {
                throw dlib::socket_error(msg.data_to_string());
            }
            else if (msg.msg_type == impl2::MESSAGE_HEADER)
            {
                throw dlib::socket_error("A BSP node received a message after it has terminated.");
            }
            else if (msg.msg_type == impl2::GOT_MESSAGE)
            {
                --num_waiting_nodes;
                --outstanding_messages;
            }
            else if (msg.msg_type == impl2::SENT_MESSAGE)
            {
                ++outstanding_messages;
            }
            else if (msg.msg_type == impl2::IN_WAITING_STATE)
            {
                ++num_waiting_nodes;
            }
        }

        if (node_id() == 0)
        {
            _cons.reset();
            while (_cons.move_next())
            {
                // tell the other end that we are intentionally dropping the connection
                serialize(impl2::NODE_TERMINATE,_cons.element().value()->stream);
                _cons.element().value()->stream.flush();
            }

            if (outstanding_messages != 0)
            {
                std::ostringstream sout;
                sout << "A BSP job was allowed to terminate before all sent messages have been received.\n";
                sout << "There are at least " << outstanding_messages << " messages still in flight.   Make sure all sent messages\n";
                sout << "have a corresponding call to receive().";
                throw dlib::socket_error(sout.str());
            }
        }
    }

// ----------------------------------------------------------------------------------------

    bsp_context::
    ~bsp_context()
    {
        _cons.reset();
        while (_cons.move_next())
        {
            _cons.element().value()->con->shutdown();
        }

        msg_buffer.disable();

        // this will wait for all the threads to terminate
        threads.clear();
    }

// ----------------------------------------------------------------------------------------

    bsp_context::
    bsp_context(
        unsigned long node_id_,
        impl1::map_id_to_con& cons_
    ) :
        outstanding_messages(0),
        num_waiting_nodes(0),
        num_terminated_nodes(0),
        current_epoch(1),
        _cons(cons_),
        _node_id(node_id_)
    {
        // spawn a bunch of read threads, one for each connection
        _cons.reset();
        while (_cons.move_next())
        {
            scoped_ptr<thread_function> ptr(new thread_function(&impl2::read_thread,
                                                                _cons.element().value().get(),
                                                                _node_id,
                                                                _cons.element().key(),
                                                                ref(msg_buffer)));
            threads.push_back(ptr);
        }

    }

// ----------------------------------------------------------------------------------------

    bool bsp_context::
    receive_data (
        shared_ptr<std::vector<char> >& item,
        unsigned long& sending_node_id
    )
    {
        notify_control_node(impl2::IN_WAITING_STATE);

        while (true)
        {
            // If there aren't any nodes left to give us messages then return right now.
            // We need to check the msg_buffer size to make sure there aren't any
            // unprocessed message there.  Recall that this can happen because status
            // messages always jump to the front of the message buffer.  So we might have
            // learned about the node terminations before processing their messages for us.
            if (num_terminated_nodes == _cons.size() && msg_buffer.size() == 0)
            {
                return false;
            }

            // if all running nodes are currently blocking forever on receive_data()
            if (node_id() == 0 && outstanding_messages == 0 && num_terminated_nodes + num_waiting_nodes == _cons.size())
            {
                num_waiting_nodes = 0;
                broadcast_byte(impl2::SEE_ALL_IN_WAITING_STATE);

                // Note that the reason we have this epoch counter is so we can tell if a
                // sent message is from before or after one of these "all nodes waiting"
                // synchronization events.  If we didn't have the epoch count we would have
                // a race condition where one node gets the SEE_ALL_IN_WAITING_STATE
                // message before others and then sends out a message to another node
                // before that node got the SEE_ALL_IN_WAITING_STATE message.  Then that
                // node would think the normal message came before SEE_ALL_IN_WAITING_STATE
                // which would be bad.
                ++current_epoch;
                return false;
            }

            impl1::msg_data data;
            if (!msg_buffer.pop(data, current_epoch))
                throw dlib::socket_error("Error reading from msg_buffer in dlib::bsp_context.");

            switch(data.msg_type)
            {
                case impl2::MESSAGE_HEADER: {
                    item = data.data;
                    sending_node_id = data.sender_id;
                    notify_control_node(impl2::GOT_MESSAGE);
                    return true;
                } break;

                case impl2::IN_WAITING_STATE: {
                    ++num_waiting_nodes;
                } break;

                case impl2::GOT_MESSAGE: {
                    --outstanding_messages;
                    --num_waiting_nodes;
                } break;

                case impl2::SENT_MESSAGE: {
                    ++outstanding_messages;
                } break;

                case impl2::NODE_TERMINATE: {
                    ++num_terminated_nodes;
                    _cons[data.sender_id]->terminated = true;
                } break;

                case impl2::SEE_ALL_IN_WAITING_STATE: {
                    ++current_epoch;
                    return false;
                } break;

                case impl2::READ_ERROR: {
                    throw dlib::socket_error(data.data_to_string());
                } break;

                default: {
                    throw dlib::socket_error("Unknown message received by dlib::bsp_context");
                } break;
            } // end switch()
        } // end while (true)
    }

// ----------------------------------------------------------------------------------------

    void bsp_context::
    notify_control_node (
        char val
    )
    {
        if (node_id() == 0)
        {
            using namespace impl2;
            switch(val)
            {
                case SENT_MESSAGE: {
                    ++outstanding_messages;
                } break;

                case GOT_MESSAGE: {
                    --outstanding_messages;
                } break;

                case IN_WAITING_STATE: {
                    // nothing to do in this case
                } break;

                default:
                    DLIB_CASSERT(false,"This should never happen");
            }
        }
        else
        {
            serialize(val, _cons[0]->stream);
            _cons[0]->stream.flush();
        }
    }

// ----------------------------------------------------------------------------------------

    void bsp_context::
    broadcast_byte (
        char val
    )
    {
        for (unsigned long i = 0; i < number_of_nodes(); ++i)
        {
            // don't send to yourself or to terminated nodes
            if (i == node_id() || _cons[i]->terminated)
                continue;

            serialize(val, _cons[i]->stream);
            _cons[i]->stream.flush();
        }
    }

// ----------------------------------------------------------------------------------------

    void bsp_context::
    send_data(
        const std::vector<char>& item,
        unsigned long target_node_id
    )
    {
        using namespace impl2;
        if (_cons[target_node_id]->terminated)
            throw socket_error("Attempt to send a message to a node that has terminated.");

        serialize(MESSAGE_HEADER, _cons[target_node_id]->stream);
        serialize(current_epoch, _cons[target_node_id]->stream);
        serialize(item, _cons[target_node_id]->stream);
        _cons[target_node_id]->stream.flush();

        notify_control_node(SENT_MESSAGE);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_BSP_CPph_


dlib C++ Library - bsp.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_BsP_Hh_
#define DLIB_BsP_Hh_

#include "bsp_abstract.h"
#include "../sockets.h"
#include "../array.h"
#include "../smart_pointers.h"
#include "../sockstreambuf.h"
#include "../string.h"
#include "../serialize.h"
#include "../map.h"
#include "../ref.h"
#include "../vectorstream.h"
#include <queue>
#include <vector>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    namespace impl1
    {
        inline void null_notify(
            unsigned short
        ) {}

        struct bsp_con
        {
            bsp_con(
                const network_address& dest
            ) :
                con(connect(dest)),
                buf(con),
                stream(&buf),
                terminated(false)
            {
                con->disable_nagle();
            }

            bsp_con(
               scoped_ptr<connection>& conptr
            ) :
                buf(conptr),
                stream(&buf),
                terminated(false)
            {
                // make sure we own the connection
                conptr.swap(con);

                con->disable_nagle();
            }

            scoped_ptr<connection> con;
            sockstreambuf buf;
            std::iostream stream;
            bool terminated;
        };

        typedef dlib::map<unsigned long, scoped_ptr<bsp_con> >::kernel_1a_c map_id_to_con;

        void connect_all (
            map_id_to_con& cons,
            const std::vector<network_address>& hosts,
            unsigned long node_id
        );
        /*!
            ensures
                - creates connections to all the given hosts and stores them into cons
        !*/

        void send_out_connection_orders (
            map_id_to_con& cons,
            const std::vector<network_address>& hosts
        );

    // ------------------------------------------------------------------------------------

        struct hostinfo
        {
            hostinfo() {}
            hostinfo (
                const network_address& addr_,
                unsigned long node_id_
            ) :
                addr(addr_),
                node_id(node_id_)
            {
            }

            network_address addr;
            unsigned long node_id;
        };

        inline void serialize (
            const hostinfo& item,
            std::ostream& out
        )
        {
            dlib::serialize(item.addr, out);
            dlib::serialize(item.node_id, out);
        }

        inline void deserialize (
            hostinfo& item,
            std::istream& in
        )
        {
            dlib::deserialize(item.addr, in);
            dlib::deserialize(item.node_id, in);
        }

    // ------------------------------------------------------------------------------------

        void connect_all_hostinfo (
            map_id_to_con& cons,
            const std::vector<hostinfo>& hosts,
            unsigned long node_id,
            std::string& error_string
        );

    // ------------------------------------------------------------------------------------

        template <
            typename port_notify_function_type
        >
        void listen_and_connect_all(
            unsigned long& node_id,
            map_id_to_con& cons,
            unsigned short port,
            port_notify_function_type port_notify_function
        )
        {
            cons.clear();
            scoped_ptr<listener> list;
            const int status = create_listener(list, port);
            if (status == PORTINUSE)
            {
                throw socket_error("Unable to create listening port " + cast_to_string(port) +
                                   ".  The port is already in use");
            }
            else if (status != 0)
            {
                throw socket_error("Unable to create listening port " + cast_to_string(port) );
            }

            port_notify_function(list->get_listening_port());

            scoped_ptr<connection> con;
            if (list->accept(con))
            {
                throw socket_error("Error occurred while accepting new connection");
            }

            scoped_ptr<bsp_con> temp(new bsp_con(con));

            unsigned long remote_node_id;
            dlib::deserialize(remote_node_id, temp->stream);
            dlib::deserialize(node_id, temp->stream);
            std::vector<hostinfo> targets;
            dlib::deserialize(targets, temp->stream);
            unsigned long num_incoming_connections;
            dlib::deserialize(num_incoming_connections, temp->stream);

            cons.add(remote_node_id,temp);

            // make a thread that will connect to all the targets
            map_id_to_con cons2;
            std::string error_string;
            thread_function thread(connect_all_hostinfo, dlib::ref(cons2), dlib::ref(targets), node_id, dlib::ref(error_string));
            if (error_string.size() != 0)
                throw socket_error(error_string);

            // accept any incoming connections
            for (unsigned long i = 0; i < num_incoming_connections; ++i)
            {
                // If it takes more than 10 seconds for the other nodes to connect to us
                // then something has gone horribly wrong and it almost certainly will
                // never connect at all.  So just give up if that happens.
                const unsigned long timeout_milliseconds = 10000;
                if (list->accept(con, timeout_milliseconds))
                {
                    throw socket_error("Error occurred while accepting new connection");
                }

                temp.reset(new bsp_con(con));

                dlib::deserialize(remote_node_id, temp->stream);
                cons.add(remote_node_id,temp);
            }

            // put all the connections created by the thread into cons
            thread.wait();
            while (cons2.size() > 0)
            {
                unsigned long id;
                scoped_ptr<bsp_con> temp;
                cons2.remove_any(id,temp);
                cons.add(id,temp);
            }
        }

    // ------------------------------------------------------------------------------------

        struct msg_data
        {
            shared_ptr<std::vector<char> > data;
            unsigned long sender_id;
            char msg_type;
            dlib::uint64 epoch;

            msg_data() : sender_id(0xFFFFFFFF), msg_type(-1), epoch(0) {}

            std::string data_to_string() const
            {
                if (data && data->size() != 0)
                    return std::string(&(*data)[0], data->size());
                else
                    return "";
            }
        };

    // ------------------------------------------------------------------------------------

        class thread_safe_message_queue : noncopyable
        {
            /*!
                WHAT THIS OBJECT REPRESENTS
                    This is a simple message queue for msg_data objects.  Note that it
                    has the special property that, while messages will generally leave
                    the queue in the order they are inserted, any message with a smaller
                    epoch value will always be popped out first.  But for all messages
                    with equal epoch values the queue functions as a normal FIFO queue.
            !*/
        private:
            struct msg_wrap
            {
                msg_wrap(
                    const msg_data& data_,
                    const dlib::uint64& sequence_number_
                ) : data(data_), sequence_number(sequence_number_) {}

                msg_wrap() : sequence_number(0){}

                msg_data data;
                dlib::uint64 sequence_number;

                // Make it so that when msg_wrap objects are in a std::priority_queue,
                // messages with a smaller epoch number always come first.  Then, within an
                // epoch, messages are ordered by their sequence number (so smaller first
                // there as well).
                bool operator<(const msg_wrap& item) const
                {
                    if (data.epoch < item.data.epoch)
                    {
                        return false;
                    }
                    else if (data.epoch > item.data.epoch)
                    {
                        return true;
                    }
                    else
                    {
                        if (sequence_number < item.sequence_number)
                            return false;
                        else
                            return true;
                    }
                }
            };

        public:
            thread_safe_message_queue() : sig(class_mutex),disabled(false),next_seq_num(1) {}

            ~thread_safe_message_queue()
            {
                disable();
            }

            void disable()
            {
                auto_mutex lock(class_mutex);
                disabled = true;
                sig.broadcast();
            }

            unsigned long size() const
            {
                auto_mutex lock(class_mutex);
                return data.size();
            }

            void push_and_consume( msg_data& item)
            {
                auto_mutex lock(class_mutex);
                data.push(msg_wrap(item, next_seq_num++));
                // do this here so that we don't have to worry about different threads touching the shared_ptr.
                item.data.reset();
                sig.signal();
            }

            bool pop (
                msg_data& item
            )
            /*!
                ensures
                    - if (this function returns true) then
                        - #item == the next thing from the queue
                    - else
                        - this object is disabled
            !*/
            {
                auto_mutex lock(class_mutex);
                while (data.size() == 0 && !disabled)
                    sig.wait();

                if (disabled)
                    return false;

                item = data.top().data;
                data.pop();

                return true;
            }

            bool pop (
                msg_data& item,
                const dlib::uint64& max_epoch
            )
            /*!
                ensures
                    - if (this function returns true) then
                        - #item == the next thing from the queue that has an epoch <= max_epoch
                    - else
                        - this object is disabled
            !*/
            {
                auto_mutex lock(class_mutex);
                while ((data.size() == 0 || data.top().data.epoch > max_epoch) && !disabled)
                    sig.wait();

                if (disabled)
                    return false;

                item = data.top().data;
                data.pop();

                return true;
            }

        private:
            std::priority_queue<msg_wrap> data;
            dlib::mutex class_mutex;
            dlib::signaler sig;
            bool disabled;
            dlib::uint64 next_seq_num;
        };

    }

// ----------------------------------------------------------------------------------------

    class bsp_context : noncopyable
    {

    public:

        template <typename T>
        void send(
            const T& item,
            unsigned long target_node_id
        )
        {
            // make sure requires clause is not broken
            DLIB_CASSERT(target_node_id < number_of_nodes() &&
                        target_node_id != node_id(),
                "\t void bsp_context::send()"
                << "\n\t Invalid arguments were given to this function."
                << "\n\t target_node_id:    " << target_node_id
                << "\n\t node_id():         " << node_id()
                << "\n\t number_of_nodes(): " << number_of_nodes()
                << "\n\t this: " << this
                );

            std::vector<char> buf;
            vectorstream sout(buf);
            serialize(item, sout);
            send_data(buf, target_node_id);
        }

        template <typename T>
        void broadcast (
            const T& item
        )
        {
            std::vector<char> buf;
            vectorstream sout(buf);
            serialize(item, sout);
            for (unsigned long i = 0; i < number_of_nodes(); ++i)
            {
                // Don't send to yourself.
                if (i == node_id())
                    continue;

                send_data(buf, i);
            }
        }

        unsigned long node_id (
        ) const { return _node_id; }

        unsigned long number_of_nodes (
        ) const { return _cons.size()+1; }

        void receive (
        )
        {
            unsigned long id;
            shared_ptr<std::vector<char> > temp;
            if (receive_data(temp,id))
                throw dlib::socket_error("Call to bsp_context::receive() got an unexpected message.");
        }

        template <typename T>
        void receive (
            T& item
        )
        {
            if(!try_receive(item))
                throw dlib::socket_error("bsp_context::receive(): no messages to receive, all nodes currently blocked.");
        }

        template <typename T>
        bool try_receive (
            T& item
        )
        {
            unsigned long sending_node_id;
            return try_receive(item, sending_node_id);
        }

        template <typename T>
        void receive (
            T& item,
            unsigned long& sending_node_id
        )
        {
            if(!try_receive(item, sending_node_id))
                throw dlib::socket_error("bsp_context::receive(): no messages to receive, all nodes currently blocked.");
        }

        template <typename T>
        bool try_receive (
            T& item,
            unsigned long& sending_node_id
        )
        {
            shared_ptr<std::vector<char> > temp;
            if (receive_data(temp, sending_node_id))
            {
                vectorstream sin(*temp);
                deserialize(item, sin);
                if (sin.peek() != EOF)
                    throw serialization_error("deserialize() did not consume all bytes produced by serialize().  "
                                              "This probably means you are calling a receive method with a different type "
                                              "of object than the one which was sent.");
                return true;
            }
            else
            {
                return false;
            }
        }

        ~bsp_context();

    private:

        bsp_context();

        bsp_context(
            unsigned long node_id_,
            impl1::map_id_to_con& cons_
        );

        void close_all_connections_gracefully();
        /*!
            ensures
                - closes all the connections to other nodes and lets them know that
                  we are terminating normally rather than as the result of some kind
                  of error.
        !*/

        bool receive_data (
            shared_ptr<std::vector<char> >& item,
            unsigned long& sending_node_id
        );

        void notify_control_node (
            char val
        );

        void broadcast_byte (
            char val
        );

        void send_data(
            const std::vector<char>& item,
            unsigned long target_node_id
        );
        /*!
            requires
                - target_node_id < number_of_nodes()
                - target_node_id != node_id()
            ensures
                - sends a copy of item to the node with the given id.
        !*/

        unsigned long outstanding_messages;
        unsigned long num_waiting_nodes;
        unsigned long num_terminated_nodes;
        dlib::uint64 current_epoch;

        impl1::thread_safe_message_queue msg_buffer;

        impl1::map_id_to_con& _cons;
        const unsigned long _node_id;
        array<scoped_ptr<thread_function> > threads;

    // -----------------------------------

        template <
            typename funct_type
            >
        friend void bsp_connect (
            const std::vector<network_address>& hosts,
            funct_type funct
        );

        template <
            typename funct_type,
            typename ARG1
            >
        friend void bsp_connect (
            const std::vector<network_address>& hosts,
            funct_type funct,
            ARG1 arg1
        );

        template <
            typename funct_type,
            typename ARG1,
            typename ARG2
            >
        friend void bsp_connect (
            const std::vector<network_address>& hosts,
            funct_type funct,
            ARG1 arg1,
            ARG2 arg2
        );

        template <
            typename funct_type,
            typename ARG1,
            typename ARG2,
            typename ARG3
            >
        friend void bsp_connect (
            const std::vector<network_address>& hosts,
            funct_type funct,
            ARG1 arg1,
            ARG2 arg2,
            ARG3 arg3
        );

        template <
            typename funct_type,
            typename ARG1,
            typename ARG2,
            typename ARG3,
            typename ARG4
            >
        friend void bsp_connect (
            const std::vector<network_address>& hosts,
            funct_type funct,
            ARG1 arg1,
            ARG2 arg2,
            ARG3 arg3,
            ARG4 arg4
        );

    // -----------------------------------

        template <
            typename port_notify_function_type,
            typename funct_type
            >
        friend void bsp_listen_dynamic_port (
            unsigned short listening_port,
            port_notify_function_type port_notify_function,
            funct_type funct
        );

        template <
            typename port_notify_function_type,
            typename funct_type,
            typename ARG1
            >
        friend void bsp_listen_dynamic_port (
            unsigned short listening_port,
            port_notify_function_type port_notify_function,
            funct_type funct,
            ARG1 arg1
        );

        template <
            typename port_notify_function_type,
            typename funct_type,
            typename ARG1,
            typename ARG2
            >
        friend void bsp_listen_dynamic_port (
            unsigned short listening_port,
            port_notify_function_type port_notify_function,
            funct_type funct,
            ARG1 arg1,
            ARG2 arg2
        );

        template <
            typename port_notify_function_type,
            typename funct_type,
            typename ARG1,
            typename ARG2,
            typename ARG3
            >
        friend void bsp_listen_dynamic_port (
            unsigned short listening_port,
            port_notify_function_type port_notify_function,
            funct_type funct,
            ARG1 arg1,
            ARG2 arg2,
            ARG3 arg3
        );

        template <
            typename port_notify_function_type,
            typename funct_type,
            typename ARG1,
            typename ARG2,
            typename ARG3,
            typename ARG4
            >
        friend void bsp_listen_dynamic_port (
            unsigned short listening_port,
            port_notify_function_type port_notify_function,
            funct_type funct,
            ARG1 arg1,
            ARG2 arg2,
            ARG3 arg3,
            ARG4 arg4
        );

    // -----------------------------------

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename funct_type
        >
    void bsp_connect (
        const std::vector<network_address>& hosts,
        funct_type funct
    )
    {
        impl1::map_id_to_con cons;
        const unsigned long node_id = 0;
        connect_all(cons, hosts, node_id);
        send_out_connection_orders(cons, hosts);
        bsp_context obj(node_id, cons);
        funct(obj);
        obj.close_all_connections_gracefully();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename funct_type,
        typename ARG1
        >
    void bsp_connect (
        const std::vector<network_address>& hosts,
        funct_type funct,
        ARG1 arg1
    )
    {
        impl1::map_id_to_con cons;
        const unsigned long node_id = 0;
        connect_all(cons, hosts, node_id);
        send_out_connection_orders(cons, hosts);
        bsp_context obj(node_id, cons);
        funct(obj,arg1);
        obj.close_all_connections_gracefully();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename funct_type,
        typename ARG1,
        typename ARG2
        >
    void bsp_connect (
        const std::vector<network_address>& hosts,
        funct_type funct,
        ARG1 arg1,
        ARG2 arg2
    )
    {
        impl1::map_id_to_con cons;
        const unsigned long node_id = 0;
        connect_all(cons, hosts, node_id);
        send_out_connection_orders(cons, hosts);
        bsp_context obj(node_id, cons);
        funct(obj,arg1,arg2);
        obj.close_all_connections_gracefully();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename funct_type,
        typename ARG1,
        typename ARG2,
        typename ARG3
        >
    void bsp_connect (
        const std::vector<network_address>& hosts,
        funct_type funct,
        ARG1 arg1,
        ARG2 arg2,
        ARG3 arg3
    )
    {
        impl1::map_id_to_con cons;
        const unsigned long node_id = 0;
        connect_all(cons, hosts, node_id);
        send_out_connection_orders(cons, hosts);
        bsp_context obj(node_id, cons);
        funct(obj,arg1,arg2,arg3);
        obj.close_all_connections_gracefully();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename funct_type,
        typename ARG1,
        typename ARG2,
        typename ARG3,
        typename ARG4
        >
    void bsp_connect (
        const std::vector<network_address>& hosts,
        funct_type funct,
        ARG1 arg1,
        ARG2 arg2,
        ARG3 arg3,
        ARG4 arg4
    )
    {
        impl1::map_id_to_con cons;
        const unsigned long node_id = 0;
        connect_all(cons, hosts, node_id);
        send_out_connection_orders(cons, hosts);
        bsp_context obj(node_id, cons);
        funct(obj,arg1,arg2,arg3,arg4);
        obj.close_all_connections_gracefully();
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename funct_type
        >
    void bsp_listen (
        unsigned short listening_port,
        funct_type funct
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(listening_port != 0,
            "\t void bsp_listen()"
            << "\n\t Invalid arguments were given to this function."
            );

        bsp_listen_dynamic_port(listening_port, impl1::null_notify, funct);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename funct_type,
        typename ARG1
        >
    void bsp_listen (
        unsigned short listening_port,
        funct_type funct,
        ARG1 arg1
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(listening_port != 0,
            "\t void bsp_listen()"
            << "\n\t Invalid arguments were given to this function."
            );

        bsp_listen_dynamic_port(listening_port, impl1::null_notify, funct, arg1);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename funct_type,
        typename ARG1,
        typename ARG2
        >
    void bsp_listen (
        unsigned short listening_port,
        funct_type funct,
        ARG1 arg1,
        ARG2 arg2
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(listening_port != 0,
            "\t void bsp_listen()"
            << "\n\t Invalid arguments were given to this function."
            );

        bsp_listen_dynamic_port(listening_port, impl1::null_notify, funct, arg1, arg2);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename funct_type,
        typename ARG1,
        typename ARG2,
        typename ARG3
        >
    void bsp_listen (
        unsigned short listening_port,
        funct_type funct,
        ARG1 arg1,
        ARG2 arg2,
        ARG3 arg3
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(listening_port != 0,
            "\t void bsp_listen()"
            << "\n\t Invalid arguments were given to this function."
            );

        bsp_listen_dynamic_port(listening_port, impl1::null_notify, funct, arg1, arg2, arg3);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename funct_type,
        typename ARG1,
        typename ARG2,
        typename ARG3,
        typename ARG4
        >
    void bsp_listen (
        unsigned short listening_port,
        funct_type funct,
        ARG1 arg1,
        ARG2 arg2,
        ARG3 arg3,
        ARG4 arg4
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(listening_port != 0,
            "\t void bsp_listen()"
            << "\n\t Invalid arguments were given to this function."
            );

        bsp_listen_dynamic_port(listening_port, impl1::null_notify, funct, arg1, arg2, arg3, arg4);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename port_notify_function_type,
        typename funct_type
        >
    void bsp_listen_dynamic_port (
        unsigned short listening_port,
        port_notify_function_type port_notify_function,
        funct_type funct
    )
    {
        impl1::map_id_to_con cons;
        unsigned long node_id;
        listen_and_connect_all(node_id, cons, listening_port, port_notify_function);
        bsp_context obj(node_id, cons);
        funct(obj);
        obj.close_all_connections_gracefully();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename port_notify_function_type,
        typename funct_type,
        typename ARG1
        >
    void bsp_listen_dynamic_port (
        unsigned short listening_port,
        port_notify_function_type port_notify_function,
        funct_type funct,
        ARG1 arg1
    )
    {
        impl1::map_id_to_con cons;
        unsigned long node_id;
        listen_and_connect_all(node_id, cons, listening_port, port_notify_function);
        bsp_context obj(node_id, cons);
        funct(obj,arg1);
        obj.close_all_connections_gracefully();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename port_notify_function_type,
        typename funct_type,
        typename ARG1,
        typename ARG2
        >
    void bsp_listen_dynamic_port (
        unsigned short listening_port,
        port_notify_function_type port_notify_function,
        funct_type funct,
        ARG1 arg1,
        ARG2 arg2
    )
    {
        impl1::map_id_to_con cons;
        unsigned long node_id;
        listen_and_connect_all(node_id, cons, listening_port, port_notify_function);
        bsp_context obj(node_id, cons);
        funct(obj,arg1,arg2);
        obj.close_all_connections_gracefully();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename port_notify_function_type,
        typename funct_type,
        typename ARG1,
        typename ARG2,
        typename ARG3
        >
    void bsp_listen_dynamic_port (
        unsigned short listening_port,
        port_notify_function_type port_notify_function,
        funct_type funct,
        ARG1 arg1,
        ARG2 arg2,
        ARG3 arg3
    )
    {
        impl1::map_id_to_con cons;
        unsigned long node_id;
        listen_and_connect_all(node_id, cons, listening_port, port_notify_function);
        bsp_context obj(node_id, cons);
        funct(obj,arg1,arg2,arg3);
        obj.close_all_connections_gracefully();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename port_notify_function_type,
        typename funct_type,
        typename ARG1,
        typename ARG2,
        typename ARG3,
        typename ARG4
        >
    void bsp_listen_dynamic_port (
        unsigned short listening_port,
        port_notify_function_type port_notify_function,
        funct_type funct,
        ARG1 arg1,
        ARG2 arg2,
        ARG3 arg3,
        ARG4 arg4
    )
    {
        impl1::map_id_to_con cons;
        unsigned long node_id;
        listen_and_connect_all(node_id, cons, listening_port, port_notify_function);
        bsp_context obj(node_id, cons);
        funct(obj,arg1,arg2,arg3,arg4);
        obj.close_all_connections_gracefully();
    }
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

}

#ifdef NO_MAKEFILE
#include "bsp.cpp"
#endif

#endif // DLIB_BsP_Hh_


dlib C++ Library - byte_orderer_kernel_1.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_BYTE_ORDEREr_KERNEL_1_
#define DLIB_BYTE_ORDEREr_KERNEL_1_

#include "byte_orderer_kernel_abstract.h"
#include "../algs.h"
#include "../assert.h"

namespace dlib
{

    class byte_orderer
    {
        /*!
            INITIAL VALUE
                - if (this machine is little endian) then
                    - little_endian == true
                - else
                    - little_endian == false

            CONVENTION
                - host_is_big_endian() == !little_endian
                - host_is_little_endian() == little_endian

                - if (this machine is little endian) then
                    - little_endian == true
                - else
                    - little_endian == false

        !*/

    public:

        // this is here for backwards compatibility with older versions of dlib.
        typedef byte_orderer kernel_1a;

        byte_orderer (
        )
        {
            // This will probably never be false but if it is then it means chars are not 8bits
            // on this system.  Which is a problem for this object.
            COMPILE_TIME_ASSERT(sizeof(short) >= 2);

            unsigned long temp = 1;
            unsigned char* ptr = reinterpret_cast<unsigned char*>(&temp);
            if (*ptr == 1)
                little_endian = true;
            else
                little_endian = false;
        }

        virtual ~byte_orderer (
        ){}

        bool host_is_big_endian (
        ) const { return !little_endian; }

        bool host_is_little_endian (
        ) const { return little_endian; }

        template <
            typename T
            >
        inline void host_to_network (
            T& item
        ) const
        { if (little_endian) flip(item); }

        template <
            typename T
            >
        inline void network_to_host (
            T& item
        ) const { if (little_endian) flip(item); }

        template <
            typename T
            >
        void host_to_big (
            T& item
        ) const { if (little_endian) flip(item); }

        template <
            typename T
            >
        void big_to_host (
            T& item
        ) const { if (little_endian) flip(item); }

        template <
            typename T
            >
        void host_to_little (
            T& item
        ) const { if (!little_endian) flip(item); }

        template <
            typename T
            >
        void little_to_host (
            T& item
        ) const { if (!little_endian) flip(item); }

    private:

        template <
            typename T,
            size_t size
            >
        inline void flip (
            T (&array)[size]
        ) const
        /*!
            ensures
                - flips the bytes in every element of this array
        !*/
        {
            for (size_t i = 0; i < size; ++i)
            {
                flip(array[i]);
            }
        }

        template <
            typename T
            >
        inline void flip (
            T& item
        ) const
        /*!
            ensures
                - reverses the byte ordering in item
        !*/
        {
            DLIB_ASSERT_HAS_STANDARD_LAYOUT(T);

            T value;

            // If you are getting this as an error then you are probably using
            // this object wrong.  If you think you aren't then send me (Davis) an
            // email and I'll either set you straight or change/remove this check so
            // your stuff works :)
            COMPILE_TIME_ASSERT(sizeof(T) <= sizeof(long double));

            // If you are getting a compile error on this line then it means T is
            // a pointer type.  It doesn't make any sense to byte swap pointers
            // since they have no meaning outside the context of their own process.
            // So you probably just forgot to dereference that pointer before passing
            // it to this function  :)
            COMPILE_TIME_ASSERT(is_pointer_type<T>::value == false);

            const size_t size = sizeof(T);
            unsigned char* const ptr = reinterpret_cast<unsigned char*>(&item);
            unsigned char* const ptr_temp = reinterpret_cast<unsigned char*>(&value);
            for (size_t i = 0; i < size; ++i)
                ptr_temp[size-i-1] = ptr[i];

            item = value;
        }

        bool little_endian;
    };

    // make flip not do anything at all for chars
    template <> inline void byte_orderer::flip<char> ( char& ) const {}
    template <> inline void byte_orderer::flip<unsigned char> ( unsigned char& ) const {}
    template <> inline void byte_orderer::flip<signed char> ( signed char& ) const {}
}

#endif // DLIB_BYTE_ORDEREr_KERNEL_1_


dlib C++ Library - get_option.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_GET_OPTiON_Hh_
#define DLIB_GET_OPTiON_Hh_

#include "get_option_abstract.h"
#include "../string.h"
#include "../is_kind.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class option_parse_error : public error
    {
    public:
        option_parse_error(const std::string& option_string, const std::string& str):
            error(EOPTION_PARSE,"Error parsing argument for option '" + option_string + "', offending string is '" + str + "'.") {}
    };

// ----------------------------------------------------------------------------------------

    template <typename config_reader_type, typename T>
    T impl_config_reader_get_option (
        const config_reader_type& cr,
        const std::string& option_name,
        const std::string& full_option_name,
        T default_value
    )
    {
        std::string::size_type pos = option_name.find_first_of(".");
        if (pos == std::string::npos)
        {
            if (cr.is_key_defined(option_name))
            {
                try{ return string_cast<T>(cr[option_name]); }
                catch (string_cast_error&) { throw option_parse_error(full_option_name, cr[option_name]); }
            }
        }
        else
        {
            std::string block_name = option_name.substr(0,pos);
            if (cr.is_block_defined(block_name))
            {
                return impl_config_reader_get_option(cr.block(block_name),
                                                     option_name.substr(pos+1),
                                                     full_option_name,
                                                     default_value);
            }
        }

        return default_value;
    }

// ----------------------------------------------------------------------------------------

    template <typename cr_type, typename T>
    typename enable_if<is_config_reader<cr_type>,T>::type get_option (
        const cr_type& cr,
        const std::string& option_name,
        T default_value
    )
    {
        return impl_config_reader_get_option(cr, option_name, option_name, default_value);
    }

// ----------------------------------------------------------------------------------------

    template <typename parser_type, typename T>
    typename disable_if<is_config_reader<parser_type>,T>::type get_option (
        const parser_type& parser,
        const std::string& option_name,
        T default_value
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( parser.option_is_defined(option_name) == true &&
                     parser.option(option_name).number_of_arguments() == 1,
            "\t T get_option()"
            << "\n\t option_name: " << option_name
            << "\n\t parser.option_is_defined(option_name):            " << parser.option_is_defined(option_name)
            << "\n\t parser.option(option_name).number_of_arguments(): " << parser.option(option_name).number_of_arguments()
            );

        if (parser.option(option_name))
        {
            try
            {
                default_value = string_cast<T>(parser.option(option_name).argument());
            }
            catch (string_cast_error&)
            {
                throw option_parse_error(option_name, parser.option(option_name).argument());
            }
        }
        return default_value;
    }

// ----------------------------------------------------------------------------------------

    template <typename parser_type, typename cr_type, typename T>
    typename disable_if<is_config_reader<parser_type>,T>::type get_option (
        const parser_type& parser,
        const cr_type& cr,
        const std::string& option_name,
        T default_value
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( parser.option_is_defined(option_name) == true &&
                     parser.option(option_name).number_of_arguments() == 1,
            "\t T get_option()"
            << "\n\t option_name: " << option_name
            << "\n\t parser.option_is_defined(option_name):            " << parser.option_is_defined(option_name)
            << "\n\t parser.option(option_name).number_of_arguments(): " << parser.option(option_name).number_of_arguments()
            );

        if (parser.option(option_name))
            return get_option(parser, option_name, default_value);
        else
            return get_option(cr, option_name, default_value);
    }

// ----------------------------------------------------------------------------------------

    template <typename parser_type, typename cr_type, typename T>
    typename disable_if<is_config_reader<parser_type>,T>::type get_option (
        const cr_type& cr,
        const parser_type& parser,
        const std::string& option_name,
        T default_value
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( parser.option_is_defined(option_name) == true &&
                     parser.option(option_name).number_of_arguments() == 1,
            "\t T get_option()"
            << "\n\t option_name: " << option_name
            << "\n\t parser.option_is_defined(option_name):            " << parser.option_is_defined(option_name)
            << "\n\t parser.option(option_name).number_of_arguments(): " << parser.option(option_name).number_of_arguments()
            );

        if (parser.option(option_name))
            return get_option(parser, option_name, default_value);
        else
            return get_option(cr, option_name, default_value);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <typename T>
    inline std::string get_option (
        const T& cr,
        const std::string& option_name,
        const char* default_value
    )
    {
        return get_option(cr, option_name, std::string(default_value));
    }

// ----------------------------------------------------------------------------------------

    template <typename T, typename U>
    inline std::string get_option (
        const T& parser,
        const U& cr,
        const std::string& option_name,
        const char* default_value
    )
    {
        return get_option(parser, cr, option_name, std::string(default_value));
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_GET_OPTiON_Hh_


dlib C++ Library - compress_stream_kernel_1.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_COMPRESS_STREAM_KERNEl_1_
#define DLIB_COMPRESS_STREAM_KERNEl_1_

#include "../algs.h"
#include <iostream>
#include <streambuf>
#include <cstdio>
#include "compress_stream_kernel_abstract.h"

namespace dlib
{

    template <
        typename fce,
        typename fcd,
        typename crc32
        >
    class compress_stream_kernel_1
    {
        /*!
            REQUIREMENTS ON fce
                is an implementation of entropy_encoder_model/entropy_encoder_model_kernel_abstract.h
                the alphabet_size of fce must be 257.
                fce and fcd share the same kernel number.

            REQUIREMENTS ON fcd
                is an implementation of entropy_decoder_model/entropy_decoder_model_kernel_abstract.h
                the alphabet_size of fcd must be 257.
                fce and fcd share the same kernel number.

            REQUIREMENTS ON crc32
                is an implementation of crc32/crc32_kernel_abstract.h

            INITIAL VALUE
                this object has no state

            CONVENTION
                this object has no state
        !*/

        const static unsigned long eof_symbol = 256;

    public:

        class decompression_error : public dlib::error
        {
            public:
                decompression_error(
                    const char* i
                ) :
                    dlib::error(std::string(i))
                {}

                decompression_error(
                    const std::string& i
                ) :
                    dlib::error(i)
                {}
        };

        compress_stream_kernel_1 (
        )
        {}

        ~compress_stream_kernel_1 (
        )
        {}

        void compress (
            std::istream& in,
            std::ostream& out
        ) const;

        void decompress (
            std::istream& in,
            std::ostream& out
        ) const;

    private:

        // restricted functions
        compress_stream_kernel_1(compress_stream_kernel_1&);        // copy constructor
        compress_stream_kernel_1& operator=(compress_stream_kernel_1&);    // assignment operator

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename fce,
        typename fcd,
        typename crc32
        >
    void compress_stream_kernel_1<fce,fcd,crc32>::
    compress (
        std::istream& in_,
        std::ostream& out_
    ) const
    {
        std::streambuf::int_type temp;

        std::streambuf& in = *in_.rdbuf();

        typename fce::entropy_encoder_type coder;
        coder.set_stream(out_);

        fce model(coder);

        crc32 crc;

        unsigned long count = 0;

        while (true)
        {
            // write out a known value every 20000 symbols
            if (count == 20000)
            {
                count = 0;
                coder.encode(1500,1501,8000);
            }
            ++count;

            // get the next character
            temp = in.sbumpc();

            // if we have hit EOF then encode the marker symbol
            if (temp != EOF)
            {
                // encode the symbol
                model.encode(static_cast<unsigned long>(temp));
                crc.add(static_cast<unsigned char>(temp));
                continue;
            }
            else
            {
                model.encode(eof_symbol);

                // now write the checksum
                unsigned long checksum = crc.get_checksum();
                unsigned char byte1 = static_cast<unsigned char>((checksum>>24)&0xFF);
                unsigned char byte2 = static_cast<unsigned char>((checksum>>16)&0xFF);
                unsigned char byte3 = static_cast<unsigned char>((checksum>>8)&0xFF);
                unsigned char byte4 = static_cast<unsigned char>((checksum)&0xFF);

                model.encode(byte1);
                model.encode(byte2);
                model.encode(byte3);
                model.encode(byte4);

                break;
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename fce,
        typename fcd,
        typename crc32
        >
    void compress_stream_kernel_1<fce,fcd,crc32>::
    decompress (
        std::istream& in_,
        std::ostream& out_
    ) const
    {

        std::streambuf& out = *out_.rdbuf();

        typename fcd::entropy_decoder_type coder;
        coder.set_stream(in_);

        fcd model(coder);

        unsigned long symbol;
        unsigned long count = 0;

        crc32 crc;

        // decode until we hit the marker symbol
        while (true)
        {
            // make sure this is the value we expect
            if (count == 20000)
            {
                if (coder.get_target(8000) != 1500)
                {
                    throw decompression_error("Error detected in compressed data stream.");
                }
                count = 0;
                coder.decode(1500,1501);
            }
            ++count;

            // decode the next symbol
            model.decode(symbol);
            if (symbol != eof_symbol)
            {
                crc.add(static_cast<unsigned char>(symbol));
                // write this symbol to out
                if (out.sputc(static_cast<char>(symbol)) != static_cast<int>(symbol))
                {
                    throw std::ios::failure("error occurred in compress_stream_kernel_1::decompress");
                }
                continue;
            }
            else
            {
                // we read eof from the encoded data.  now we just have to check the checksum and we are done.
                unsigned char byte1;
                unsigned char byte2;
                unsigned char byte3;
                unsigned char byte4;

                model.decode(symbol); byte1 = static_cast<unsigned char>(symbol);
                model.decode(symbol); byte2 = static_cast<unsigned char>(symbol);
                model.decode(symbol); byte3 = static_cast<unsigned char>(symbol);
                model.decode(symbol); byte4 = static_cast<unsigned char>(symbol);

                unsigned long checksum = byte1;
                checksum <<= 8;
                checksum |= byte2;
                checksum <<= 8;
                checksum |= byte3;
                checksum <<= 8;
                checksum |= byte4;

                if (checksum != crc.get_checksum())
                    throw decompression_error("Error detected in compressed data stream.");

                break;
            }
        } // while (true)

    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_COMPRESS_STREAM_KERNEl_1_


dlib C++ Library - compress_stream_kernel_2.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_COMPRESS_STREAM_KERNEl_2_
#define DLIB_COMPRESS_STREAM_KERNEl_2_

#include "../algs.h"
#include <iostream>
#include <streambuf>
#include "compress_stream_kernel_abstract.h"

namespace dlib
{

    template <
        typename fce,
        typename fcd,
        typename lz77_buffer,
        typename sliding_buffer,
        typename fce_length,
        typename fcd_length,
        typename fce_index,
        typename fcd_index,
        typename crc32
        >
    class compress_stream_kernel_2
    {
        /*!
            REQUIREMENTS ON fce
                is an implementation of entropy_encoder_model/entropy_encoder_model_kernel_abstract.h
                the alphabet_size of fce must be 257.
                fce and fcd share the same kernel number.

            REQUIREMENTS ON fcd
                is an implementation of entropy_decoder_model/entropy_decoder_model_kernel_abstract.h
                the alphabet_size of fcd must be 257.
                fce and fcd share the same kernel number.

            REQUIREMENTS ON lz77_buffer
                is an implementation of lz77_buffer/lz77_buffer_kernel_abstract.h

            REQUIREMENTS ON sliding_buffer
                is an implementation of sliding_buffer/sliding_buffer_kernel_abstract.h
                is instantiated with T = unsigned char

            REQUIREMENTS ON fce_length
                is an implementation of entropy_encoder_model/entropy_encoder_model_kernel_abstract.h
                the alphabet_size of fce must be 513.  This will be used to encode the length of lz77 matches.
                fce_length and fcd share the same kernel number.

            REQUIREMENTS ON fcd_length
                is an implementation of entropy_decoder_model/entropy_decoder_model_kernel_abstract.h
                the alphabet_size of fcd must be 513.  This will be used to decode the length of lz77 matches.
                fce_length and fcd share the same kernel number.

            REQUIREMENTS ON fce_index
                is an implementation of entropy_encoder_model/entropy_encoder_model_kernel_abstract.h
                the alphabet_size of fce must be 32257.  This will be used to encode the index of lz77 matches.
                fce_index and fcd share the same kernel number.

            REQUIREMENTS ON fcd_index
                is an implementation of entropy_decoder_model/entropy_decoder_model_kernel_abstract.h
                the alphabet_size of fcd must be 32257.  This will be used to decode the index of lz77 matches.
                fce_index and fcd share the same kernel number.

            REQUIREMENTS ON crc32
                is an implementation of crc32/crc32_kernel_abstract.h

            INITIAL VALUE
                this object has no state

            CONVENTION
                this object has no state
        !*/

        const static unsigned long eof_symbol = 256;

    public:

        class decompression_error : public dlib::error
        {
            public:
                decompression_error(
                    const char* i
                ) :
                    dlib::error(std::string(i))
                {}

                decompression_error(
                    const std::string& i
                ) :
                    dlib::error(i)
                {}
        };

        compress_stream_kernel_2 (
        )
        {}

        ~compress_stream_kernel_2 (
        )
        {}

        void compress (
            std::istream& in,
            std::ostream& out
        ) const;

        void decompress (
            std::istream& in,
            std::ostream& out
        ) const;

    private:

        // restricted functions
        compress_stream_kernel_2(compress_stream_kernel_2&);        // copy constructor
        compress_stream_kernel_2& operator=(compress_stream_kernel_2&);    // assignment operator

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename fce,
        typename fcd,
        typename lz77_buffer,
        typename sliding_buffer,
        typename fce_length,
        typename fcd_length,
        typename fce_index,
        typename fcd_index,
        typename crc32
        >
    void compress_stream_kernel_2<fce,fcd,lz77_buffer,sliding_buffer,fce_length,fcd_length,fce_index,fcd_index,crc32>::
    compress (
        std::istream& in_,
        std::ostream& out_
    ) const
    {
        std::streambuf::int_type temp;

        std::streambuf& in = *in_.rdbuf();

        typename fce::entropy_encoder_type coder;
        coder.set_stream(out_);

        fce model(coder);
        fce_length model_length(coder);
        fce_index model_index(coder);

        const unsigned long LOOKAHEAD_LIMIT = 512;
        lz77_buffer buffer(15,LOOKAHEAD_LIMIT);

        crc32 crc;

        unsigned long count = 0;

        unsigned long lz77_count = 1;  // number of times we used lz77 to encode
        unsigned long ppm_count = 1;   // number of times we used ppm to encode

        while (true)
        {
            // write out a known value every 20000 symbols
            if (count == 20000)
            {
                count = 0;
                coder.encode(150,151,400);
            }
            ++count;

            // try to fill the lookahead buffer
            if (buffer.get_lookahead_buffer_size() < buffer.get_lookahead_buffer_limit())
            {
                temp = in.sbumpc();
                while (temp != EOF)
                {
                    crc.add(static_cast<unsigned char>(temp));
                    buffer.add(static_cast<unsigned char>(temp));
                    if (buffer.get_lookahead_buffer_size() == buffer.get_lookahead_buffer_limit())
                        break;
                    temp = in.sbumpc();
                }
            }

            // compute the sum of ppm_count and lz77_count but make sure
            // it is less than 65536
            unsigned long sum = ppm_count + lz77_count;
            if (sum >= 65536)
            {
                ppm_count >>= 1;
                lz77_count >>= 1;
                ppm_count |= 1;
                lz77_count |= 1;
                sum = ppm_count+lz77_count;
            }

            // if there are still more symbols in the lookahead buffer to encode
            if (buffer.get_lookahead_buffer_size() > 0)
            {
                unsigned long match_index, match_length;
                buffer.find_match(match_index,match_length,6);
                if (match_length != 0)
                {

                    // signal the decoder that we are using lz77
                    coder.encode(0,lz77_count,sum);
                    ++lz77_count;

                    // encode the index and length pair
                    model_index.encode(match_index);
                    model_length.encode(match_length);

                }
                else
                {

                    // signal the decoder that we are using ppm
                    coder.encode(lz77_count,sum,sum);
                    ++ppm_count;

                    // encode the symbol using the ppm model
                    model.encode(buffer.lookahead_buffer(0));
                    buffer.shift_buffers(1);
                }
            }
            else
            {
                // signal the decoder that we are using ppm
                coder.encode(lz77_count,sum,sum);

                model.encode(eof_symbol);
                // now write the checksum
                unsigned long checksum = crc.get_checksum();
                unsigned char byte1 = static_cast<unsigned char>((checksum>>24)&0xFF);
                unsigned char byte2 = static_cast<unsigned char>((checksum>>16)&0xFF);
                unsigned char byte3 = static_cast<unsigned char>((checksum>>8)&0xFF);
                unsigned char byte4 = static_cast<unsigned char>((checksum)&0xFF);

                model.encode(byte1);
                model.encode(byte2);
                model.encode(byte3);
                model.encode(byte4);

                break;
            }
        } // while (true)
    }

// ----------------------------------------------------------------------------------------

    template <
        typename fce,
        typename fcd,
        typename lz77_buffer,
        typename sliding_buffer,
        typename fce_length,
        typename fcd_length,
        typename fce_index,
        typename fcd_index,
        typename crc32
        >
    void compress_stream_kernel_2<fce,fcd,lz77_buffer,sliding_buffer,fce_length,fcd_length,fce_index,fcd_index,crc32>::
    decompress (
        std::istream& in_,
        std::ostream& out_
    ) const
    {

        std::streambuf& out = *out_.rdbuf();

        typename fcd::entropy_decoder_type coder;
        coder.set_stream(in_);

        fcd model(coder);
        fcd_length model_length(coder);
        fcd_index model_index(coder);

        unsigned long symbol;
        unsigned long count = 0;

        sliding_buffer buffer;
        buffer.set_size(15);

        // Initialize the buffer to all zeros.  There is no algorithmic reason to
        // do this.  But doing so avoids a warning from valgrind so that is why
        // I'm doing this.
        for (unsigned long i = 0; i < buffer.size(); ++i)
              buffer[i] = 0;

        crc32 crc;

        unsigned long lz77_count = 1;  // number of times we used lz77 to encode
        unsigned long ppm_count = 1;   // number of times we used ppm to encode
        bool next_block_lz77;

        // decode until we hit the marker symbol
        while (true)
        {
            // make sure this is the value we expect
            if (count == 20000)
            {
                if (coder.get_target(400) != 150)
                {
                    throw decompression_error("Error detected in compressed data stream.");
                }
                count = 0;
                coder.decode(150,151);
            }
            ++count;

            // compute the sum of ppm_count and lz77_count but make sure
            // it is less than 65536
            unsigned long sum = ppm_count + lz77_count;
            if (sum >= 65536)
            {
                ppm_count >>= 1;
                lz77_count >>= 1;
                ppm_count |= 1;
                lz77_count |= 1;
                sum = ppm_count+lz77_count;
            }

            // check if we are decoding a lz77 or ppm block
            if (coder.get_target(sum) < lz77_count)
            {
                coder.decode(0,lz77_count);
                next_block_lz77 = true;
                ++lz77_count;
            }
            else
            {
                coder.decode(lz77_count,sum);
                next_block_lz77 = false;
                ++ppm_count;
            }

            if (next_block_lz77)
            {

                unsigned long match_length, match_index;
                // decode the match index
                model_index.decode(match_index);

                // decode the match length
                model_length.decode(match_length);

                match_index += match_length;
                buffer.rotate_left(match_length);
                for (unsigned long i = 0; i < match_length; ++i)
                {
                    unsigned char ch = buffer[match_index-i];
                    buffer[match_length-i-1] = ch;

                    crc.add(ch);
                    // write this ch to out
                    if (out.sputc(static_cast<char>(ch)) != static_cast<int>(ch))
                    {
                        throw std::ios::failure("error occurred in compress_stream_kernel_2::decompress");
                    }
                }

            }
            else
            {

                // decode the next symbol
                model.decode(symbol);
                if (symbol != eof_symbol)
                {
                    buffer.rotate_left(1);
                    buffer[0] = static_cast<unsigned char>(symbol);

                    crc.add(static_cast<unsigned char>(symbol));
                    // write this symbol to out
                    if (out.sputc(static_cast<char>(symbol)) != static_cast<int>(symbol))
                    {
                        throw std::ios::failure("error occurred in compress_stream_kernel_2::decompress");
                    }
                }
                else
                {
                    // this was the eof marker symbol so we are done.  now check the checksum

                    // now get the checksum and make sure it matches
                    unsigned char byte1;
                    unsigned char byte2;
                    unsigned char byte3;
                    unsigned char byte4;

                    model.decode(symbol); byte1 = static_cast<unsigned char>(symbol);
                    model.decode(symbol); byte2 = static_cast<unsigned char>(symbol);
                    model.decode(symbol); byte3 = static_cast<unsigned char>(symbol);
                    model.decode(symbol); byte4 = static_cast<unsigned char>(symbol);

                    unsigned long checksum = byte1;
                    checksum <<= 8;
                    checksum |= byte2;
                    checksum <<= 8;
                    checksum |= byte3;
                    checksum <<= 8;
                    checksum |= byte4;

                    if (checksum != crc.get_checksum())
                        throw decompression_error("Error detected in compressed data stream.");

                    break;
                }
            }

        } // while (true)
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_COMPRESS_STREAM_KERNEl_2_


dlib C++ Library - compress_stream_kernel_3.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_COMPRESS_STREAM_KERNEl_3_
#define DLIB_COMPRESS_STREAM_KERNEl_3_

#include "../algs.h"
#include "compress_stream_kernel_abstract.h"
#include "../assert.h"

namespace dlib
{

    template <
        typename lzp_buf,
        typename crc32,
        unsigned long buffer_size
        >
    class compress_stream_kernel_3
    {
        /*!
            REQUIREMENTS ON lzp_buf
                is an implementation of lzp_buffer/lzp_buffer_kernel_abstract.h

            REQUIREMENTS ON buffer_size
                10 < buffer_size < 32

            REQUIREMENTS ON crc32
                is an implementation of crc32/crc32_kernel_abstract.h

            INITIAL VALUE
                this object has no state

            CONVENTION
                this object has no state

                This implementation uses the lzp_buffer and writes out matches
                in a byte aligned format.

        !*/

    public:

        class decompression_error : public dlib::error
        {
            public:
                decompression_error(
                    const char* i
                ) :
                    dlib::error(std::string(i))
                {}

                decompression_error(
                    const std::string& i
                ) :
                    dlib::error(i)
                {}
        };

        compress_stream_kernel_3 (
        )
        {
            COMPILE_TIME_ASSERT(10 < buffer_size && buffer_size < 32);
        }

        ~compress_stream_kernel_3 (
        )
        {}

        void compress (
            std::istream& in,
            std::ostream& out
        ) const;

        void decompress (
            std::istream& in,
            std::ostream& out
        ) const;

    private:

        inline void write (
            unsigned char symbol
        ) const
        {
            if (out->sputn(reinterpret_cast<char*>(&symbol),1)==0)
                throw std::ios_base::failure("error writing to output stream in compress_stream_kernel_3");
        }

        inline void decode (
            unsigned char& symbol,
            unsigned char& flag
        ) const
        {
            if (count == 0)
            {
                if (((size_t)in->sgetn(reinterpret_cast<char*>(buffer),sizeof(buffer)))!=sizeof(buffer))
                    throw decompression_error("Error detected in compressed data stream.");
                count = 8;
            }
            --count;
            symbol = buffer[8-count];
            flag = buffer[0] >> 7;
            buffer[0] <<= 1;
        }

        inline void encode (
            unsigned char symbol,
            unsigned char flag
        ) const
        /*!
            requires
                - 0 <= flag <= 1
            ensures
                - writes symbol with the given one bit flag
        !*/
        {
            // add this symbol and flag to the buffer
            ++count;
            buffer[0] <<= 1;
            buffer[count] = symbol;
            buffer[0] |= flag;

            if (count == 8)
            {
                if (((size_t)out->sputn(reinterpret_cast<char*>(buffer),sizeof(buffer)))!=sizeof(buffer))
                    throw std::ios_base::failure("error writing to output stream in compress_stream_kernel_3");
                count = 0;
                buffer[0] = 0;
            }
        }

        void clear (
        ) const
        /*!
            ensures
                - resets the buffers
        !*/
        {
            count = 0;
        }

        void flush (
        ) const
        /*!
            ensures
                - flushes any data in the buffers to out
        !*/
        {
            if (count != 0)
            {
                buffer[0] <<= (8-count);
                if (((size_t)out->sputn(reinterpret_cast<char*>(buffer),sizeof(buffer)))!=sizeof(buffer))
                    throw std::ios_base::failure("error writing to output stream in compress_stream_kernel_3");
            }
        }

        mutable unsigned int count;
        // count tells us how many bytes are buffered in buffer and how many flag
        // bit are currently in buffer[0]
        mutable unsigned char buffer[9];
        // buffer[0] holds the flag bits to be writen.
        // the rest of the buffer holds the bytes to be writen.

        mutable std::streambuf* in;
        mutable std::streambuf* out;

        // restricted functions
        compress_stream_kernel_3(compress_stream_kernel_3<lzp_buf,crc32,buffer_size>&);        // copy constructor
        compress_stream_kernel_3<lzp_buf,crc32,buffer_size>& operator=(compress_stream_kernel_3<lzp_buf,crc32,buffer_size>&);    // assignment operator

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename lzp_buf,
        typename crc32,
        unsigned long buffer_size
        >
    void compress_stream_kernel_3<lzp_buf,crc32,buffer_size>::
    compress (
        std::istream& in_,
        std::ostream& out_
    ) const
    {
        in = in_.rdbuf();
        out = out_.rdbuf();
        clear();

        crc32 crc;

        lzp_buf buffer(buffer_size);

        std::streambuf::int_type temp = in->sbumpc();
        unsigned long index;
        unsigned char symbol;
        unsigned char length;

        while (temp != EOF)
        {
            symbol = static_cast<unsigned char>(temp);
            if (buffer.predict_match(index))
            {
                if (buffer[index] == symbol)
                {
                    // this is a match so we must find out how long it is
                    length = 1;

                    buffer.add(symbol);
                    crc.add(symbol);

                    temp = in->sbumpc();
                    while (length < 255)
                    {
                        if (temp == EOF)
                        {
                            break;
                        }
                        else if (static_cast<unsigned long>(length) >= index)
                        {
                            break;
                        }
                        else if (static_cast<unsigned char>(temp) == buffer[index])
                        {
                            ++length;
                            buffer.add(static_cast<unsigned char>(temp));
                            crc.add(static_cast<unsigned char>(temp));
                            temp = in->sbumpc();
                        }
                        else
                        {
                            break;
                        }
                    }

                    encode(length,1);
                }
                else
                {
                    // this is also not a match
                    encode(symbol,0);
                    buffer.add(symbol);
                    crc.add(symbol);

                    // get the next symbol
                    temp = in->sbumpc();
                }
            }
            else
            {
                // there wasn't a match so just write this symbol
                encode(symbol,0);
                buffer.add(symbol);
                crc.add(symbol);

                // get the next symbol
                temp = in->sbumpc();
            }
        }

        // use a match of zero length to indicate EOF
        encode(0,1);

        // now write the checksum
        unsigned long checksum = crc.get_checksum();
        unsigned char byte1 = static_cast<unsigned char>((checksum>>24)&0xFF);
        unsigned char byte2 = static_cast<unsigned char>((checksum>>16)&0xFF);
        unsigned char byte3 = static_cast<unsigned char>((checksum>>8)&0xFF);
        unsigned char byte4 = static_cast<unsigned char>((checksum)&0xFF);

        encode(byte1,0);
        encode(byte2,0);
        encode(byte3,0);
        encode(byte4,0);

        flush();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename lzp_buf,
        typename crc32,
        unsigned long buffer_size
        >
    void compress_stream_kernel_3<lzp_buf,crc32,buffer_size>::
    decompress (
        std::istream& in_,
        std::ostream& out_
    ) const
    {
        in = in_.rdbuf();
        out = out_.rdbuf();
        clear();

        crc32 crc;

        lzp_buf buffer(buffer_size);

        unsigned long index = 0;
        unsigned char symbol;
        unsigned char length;
        unsigned char flag;

        decode(symbol,flag);
        while (flag == 0 || symbol != 0)
        {
            buffer.predict_match(index);

            if (flag == 1)
            {
                length = symbol;
                do
                {
                    --length;
                    symbol = buffer[index];
                    write(symbol);
                    buffer.add(symbol);
                    crc.add(symbol);
                } while (length != 0);
            }
            else
            {
                // this is just a literal
                write(symbol);
                buffer.add(symbol);
                crc.add(symbol);
            }
            decode(symbol,flag);
        }

        // now get the checksum and make sure it matches
        unsigned char byte1;
        unsigned char byte2;
        unsigned char byte3;
        unsigned char byte4;

        decode(byte1,flag);
        if (flag != 0)
            throw decompression_error("Error detected in compressed data stream.");
        decode(byte2,flag);
        if (flag != 0)
            throw decompression_error("Error detected in compressed data stream.");
        decode(byte3,flag);
        if (flag != 0)
            throw decompression_error("Error detected in compressed data stream.");
        decode(byte4,flag);
        if (flag != 0)
            throw decompression_error("Error detected in compressed data stream.");

        unsigned long checksum = byte1;
        checksum <<= 8;
        checksum |= byte2;
        checksum <<= 8;
        checksum |= byte3;
        checksum <<= 8;
        checksum |= byte4;

        if (checksum != crc.get_checksum())
            throw decompression_error("Error detected in compressed data stream.");

    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_COMPRESS_STREAM_KERNEl_3_


dlib C++ Library - conditioning_class_kernel_1.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_CONDITIONING_CLASS_KERNEl_1_
#define DLIB_CONDITIONING_CLASS_KERNEl_1_

#include "conditioning_class_kernel_abstract.h"
#include "../assert.h"
#include "../algs.h"

namespace dlib
{

    template <
        unsigned long alphabet_size
        >
    class conditioning_class_kernel_1
    {
        /*!
            INITIAL VALUE
                total == 1
                counts == pointer to an array of alphabet_size unsigned shorts
                for all i except i == alphabet_size-1: counts[i] == 0
                counts[alphabet_size-1] == 1

            CONVENTION
                counts == pointer to an array of alphabet_size unsigned shorts
                get_total() == total
                get_count(symbol) == counts[symbol]

                LOW_COUNT(symbol) == sum of counts[0] though counts[symbol-1]
                                     or 0 if symbol == 0

                get_memory_usage() == global_state.memory_usage
        !*/

    public:

        class global_state_type
        {
        public:
            global_state_type () : memory_usage(0) {}
        private:
            unsigned long memory_usage;

            friend class conditioning_class_kernel_1<alphabet_size>;
        };

        conditioning_class_kernel_1 (
            global_state_type& global_state_
        );

        ~conditioning_class_kernel_1 (
        );

        void clear(
        );

        bool increment_count (
            unsigned long symbol,
            unsigned short amount = 1
        );

        unsigned long get_count (
            unsigned long symbol
        ) const;

        unsigned long get_total (
        ) const;

        unsigned long get_range (
            unsigned long symbol,
            unsigned long& low_count,
            unsigned long& high_count,
            unsigned long& total_count
        ) const;

        void get_symbol (
            unsigned long target,
            unsigned long& symbol,
            unsigned long& low_count,
            unsigned long& high_count
        ) const;

        unsigned long get_memory_usage (
        ) const;

        global_state_type& get_global_state (
        );

        static unsigned long get_alphabet_size (
        );

    private:

        // restricted functions
        conditioning_class_kernel_1(conditioning_class_kernel_1<alphabet_size>&);        // copy constructor
        conditioning_class_kernel_1& operator=(conditioning_class_kernel_1<alphabet_size>&);    // assignment operator

        // data members
        unsigned short total;
        unsigned short* counts;
        global_state_type& global_state;

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size
        >
    conditioning_class_kernel_1<alphabet_size>::
    conditioning_class_kernel_1 (
        global_state_type& global_state_
    ) :
        total(1),
        counts(new unsigned short[alphabet_size]),
        global_state(global_state_)
    {
        COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65536 );

        unsigned short* start = counts;
        unsigned short* end = counts+alphabet_size-1;
        while (start != end)
        {
            *start = 0;
            ++start;
        }
        *start = 1;

        // update memory usage
        global_state.memory_usage += sizeof(unsigned short)*alphabet_size +
                                     sizeof(conditioning_class_kernel_1);
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size
        >
    conditioning_class_kernel_1<alphabet_size>::
    ~conditioning_class_kernel_1 (
    )
    {
        delete [] counts;
        // update memory usage
        global_state.memory_usage -= sizeof(unsigned short)*alphabet_size +
                                     sizeof(conditioning_class_kernel_1);
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size
        >
    void conditioning_class_kernel_1<alphabet_size>::
    clear(
    )
    {
        total = 1;
        unsigned short* start = counts;
        unsigned short* end = counts+alphabet_size-1;
        while (start != end)
        {
            *start = 0;
            ++start;
        }
        *start = 1;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size
        >
    unsigned long conditioning_class_kernel_1<alphabet_size>::
    get_memory_usage(
    ) const
    {
        return global_state.memory_usage;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size
        >
    typename conditioning_class_kernel_1<alphabet_size>::global_state_type& conditioning_class_kernel_1<alphabet_size>::
    get_global_state(
    )
    {
        return global_state;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size
        >
    bool conditioning_class_kernel_1<alphabet_size>::
    increment_count (
        unsigned long symbol,
        unsigned short amount
    )
    {
        // if we are going over a total of 65535 then scale down all counts by 2
        if (static_cast<unsigned long>(total)+static_cast<unsigned long>(amount) >= 65536)
        {
            total = 0;
            unsigned short* start = counts;
            unsigned short* end = counts+alphabet_size;
            while (start != end)
            {
                *start >>= 1;
                total += *start;
                ++start;
            }
            // make sure it is at least one
            if (counts[alphabet_size-1]==0)
            {
                ++total;
                counts[alphabet_size-1] = 1;
            }
        }
        counts[symbol] += amount;
        total += amount;
        return true;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size
        >
    unsigned long conditioning_class_kernel_1<alphabet_size>::
    get_count (
        unsigned long symbol
    ) const
    {
        return counts[symbol];
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size
        >
    unsigned long conditioning_class_kernel_1<alphabet_size>::
    get_alphabet_size (
    )
    {
        return alphabet_size;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size
        >
    unsigned long conditioning_class_kernel_1<alphabet_size>::
    get_total (
    ) const
    {
        return total;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size
        >
    unsigned long conditioning_class_kernel_1<alphabet_size>::
    get_range (
        unsigned long symbol,
        unsigned long& low_count,
        unsigned long& high_count,
        unsigned long& total_count
    ) const
    {
        if (counts[symbol] == 0)
            return 0;

        total_count = total;

        const unsigned short* start = counts;
        const unsigned short* end = counts+symbol;
        unsigned short high_count_temp = *start;
        while (start != end)
        {
            ++start;
            high_count_temp += *start;
        }
        low_count = high_count_temp - *start;
        high_count = high_count_temp;
        return *start;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size
        >
    void conditioning_class_kernel_1<alphabet_size>::
    get_symbol (
        unsigned long target,
        unsigned long& symbol,
        unsigned long& low_count,
        unsigned long& high_count
    ) const
    {
        unsigned long high_count_temp = *counts;
        const unsigned short* start = counts;
        while (target >= high_count_temp)
        {
            ++start;
            high_count_temp += *start;
        }

        low_count = high_count_temp - *start;
        high_count = high_count_temp;
        symbol = static_cast<unsigned long>(start-counts);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_CONDITIONING_CLASS_KERNEl_1_


dlib C++ Library - conditioning_class_kernel_2.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_CONDITIONING_CLASS_KERNEl_2_
#define DLIB_CONDITIONING_CLASS_KERNEl_2_

#include "conditioning_class_kernel_abstract.h"
#include "../assert.h"
#include "../algs.h"

namespace dlib
{

    template <
        unsigned long alphabet_size
        >
    class conditioning_class_kernel_2
    {
        /*!
            INITIAL VALUE
                total == 1
                symbols == pointer to array of alphabet_size data structs
                for all i except i == alphabet_size-1: symbols[i].count == 0
                                                       symbols[i].left_count == 0

                symbols[alphabet_size-1].count == 1
                symbols[alpahbet_size-1].left_count == 0

            CONVENTION
                symbols == pointer to array of alphabet_size data structs
                get_total() == total
                get_count(symbol) == symbols[symbol].count

                symbols is organized as a tree with symbols[0] as the root.

                the left subchild of symbols[i] is symbols[i*2+1] and
                the right subchild is symbols[i*2+2].
                the partent of symbols[i] == symbols[(i-1)/2]

                symbols[i].left_count == the sum of the counts of all the
                                         symbols to the left of symbols[i]

                get_memory_usage() == global_state.memory_usage
        !*/

    public:

        class global_state_type
        {
        public:
            global_state_type () : memory_usage(0) {}
        private:
            unsigned long memory_usage;

            friend class conditioning_class_kernel_2<alphabet_size>;
        };

        conditioning_class_kernel_2 (
            global_state_type& global_state_
        );

        ~conditioning_class_kernel_2 (
        );

        void clear(
        );

        bool increment_count (
            unsigned long symbol,
            unsigned short amount = 1
        );

        unsigned long get_count (
            unsigned long symbol
        ) const;

        inline unsigned long get_total (
        ) const;

        unsigned long get_range (
            unsigned long symbol,
            unsigned long& low_count,
            unsigned long& high_count,
            unsigned long& total_count
        ) const;

        void get_symbol (
            unsigned long target,
            unsigned long& symbol,
            unsigned long& low_count,
            unsigned long& high_count
        ) const;

        unsigned long get_memory_usage (
        ) const;

        global_state_type& get_global_state (
        );

        static unsigned long get_alphabet_size (
        );

    private:

        // restricted functions
        conditioning_class_kernel_2(conditioning_class_kernel_2<alphabet_size>&);        // copy constructor
        conditioning_class_kernel_2& operator=(conditioning_class_kernel_2<alphabet_size>&);    // assignment operator

        // data members
        unsigned short total;
        struct data
        {
            unsigned short count;
            unsigned short left_count;
        };

        data* symbols;
        global_state_type& global_state;

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size
        >
    conditioning_class_kernel_2<alphabet_size>::
    conditioning_class_kernel_2 (
        global_state_type& global_state_
    ) :
        total(1),
        symbols(new data[alphabet_size]),
        global_state(global_state_)
    {
        COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65536 );

        data* start = symbols;
        data* end = symbols + alphabet_size-1;

        while (start != end)
        {
            start->count = 0;
            start->left_count = 0;
            ++start;
        }

        start->count = 1;
        start->left_count = 0;

        // update the left_counts for the symbol alphabet_size-1
        unsigned short temp;
        unsigned long symbol = alphabet_size-1;
        while (symbol != 0)
        {
            // temp will be 1 if symbol is odd, 0 if it is even
            temp = static_cast<unsigned short>(symbol&0x1);

            // set symbol to its parent
            symbol = (symbol-1)>>1;

            // note that all left subchidren are odd and also that
            // if symbol was a left subchild then we want to increment
            // its parents left_count
            if (temp)
                ++symbols[symbol].left_count;
        }

        global_state.memory_usage += sizeof(data)*alphabet_size +
                                     sizeof(conditioning_class_kernel_2);
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size
        >
    conditioning_class_kernel_2<alphabet_size>::
    ~conditioning_class_kernel_2 (
    )
    {
        delete [] symbols;
        global_state.memory_usage -= sizeof(data)*alphabet_size +
                                     sizeof(conditioning_class_kernel_2);
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size
        >
    void conditioning_class_kernel_2<alphabet_size>::
    clear(
    )
    {
        data* start = symbols;
        data* end = symbols + alphabet_size-1;

        total = 1;

        while (start != end)
        {
            start->count = 0;
            start->left_count = 0;
            ++start;
        }

        start->count = 1;
        start->left_count = 0;

        // update the left_counts
        unsigned short temp;
        unsigned long symbol = alphabet_size-1;
        while (symbol != 0)
        {
            // temp will be 1 if symbol is odd, 0 if it is even
            temp = static_cast<unsigned short>(symbol&0x1);

            // set symbol to its parent
            symbol = (symbol-1)>>1;

            // note that all left subchidren are odd and also that
            // if symbol was a left subchild then we want to increment
            // its parents left_count
            symbols[symbol].left_count += temp;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size
        >
    unsigned long conditioning_class_kernel_2<alphabet_size>::
    get_memory_usage(
    ) const
    {
        return global_state.memory_usage;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size
        >
    typename conditioning_class_kernel_2<alphabet_size>::global_state_type& conditioning_class_kernel_2<alphabet_size>::
    get_global_state(
    )
    {
        return global_state;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size
        >
    bool conditioning_class_kernel_2<alphabet_size>::
    increment_count (
        unsigned long symbol,
        unsigned short amount
    )
    {
        // if we need to renormalize then do so
        if (static_cast<unsigned long>(total)+static_cast<unsigned long>(amount) >= 65536)
        {
            unsigned long s;
            unsigned short temp;
            for (unsigned short i = 0; i < alphabet_size-1; ++i)
            {
                s = i;

                // divide the count for this symbol by 2
                symbols[i].count >>= 1;

                symbols[i].left_count = 0;

                // bubble this change up though the tree
                while (s != 0)
                {
                    // temp will be 1 if symbol is odd, 0 if it is even
                    temp = static_cast<unsigned short>(s&0x1);

                    // set s to its parent
                    s = (s-1)>>1;

                    // note that all left subchidren are odd and also that
                    // if s was a left subchild then we want to increment
                    // its parents left_count
                    if (temp)
                        symbols[s].left_count += symbols[i].count;
                }
            }

            // update symbols alphabet_size-1
            {
                s = alphabet_size-1;

                // divide alphabet_size-1 symbol by 2 if it's > 1
                if (symbols[alphabet_size-1].count > 1)
                    symbols[alphabet_size-1].count >>= 1;

                // bubble this change up though the tree
                while (s != 0)
                {
                    // temp will be 1 if symbol is odd, 0 if it is even
                    temp = static_cast<unsigned short>(s&0x1);

                    // set s to its parent
                    s = (s-1)>>1;

                    // note that all left subchidren are odd and also that
                    // if s was a left subchild then we want to increment
                    // its parents left_count
                    if (temp)
                        symbols[s].left_count += symbols[alphabet_size-1].count;
                }
            }

            // calculate the new total
            total = 0;
            unsigned long m = 0;
            while (m < alphabet_size)
            {
                total += symbols[m].count + symbols[m].left_count;
                m = (m<<1) + 2;
            }

        }

        // increment the count for the specified symbol
        symbols[symbol].count += amount;;
        total += amount;

        unsigned short temp;
        while (symbol != 0)
        {
            // temp will be 1 if symbol is odd, 0 if it is even
            temp = static_cast<unsigned short>(symbol&0x1);

            // set symbol to its parent
            symbol = (symbol-1)>>1;

            // note that all left subchidren are odd and also that
            // if symbol was a left subchild then we want to increment
            // its parents left_count
            if (temp)
                symbols[symbol].left_count += amount;
        }

        return true;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size
        >
    unsigned long conditioning_class_kernel_2<alphabet_size>::
    get_count (
        unsigned long symbol
    ) const
    {
        return symbols[symbol].count;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size
        >
    unsigned long conditioning_class_kernel_2<alphabet_size>::
    get_alphabet_size (
    )
    {
        return alphabet_size;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size
        >
    unsigned long conditioning_class_kernel_2<alphabet_size>::
    get_total (
    ) const
    {
        return total;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size
        >
    unsigned long conditioning_class_kernel_2<alphabet_size>::
    get_range (
        unsigned long symbol,
        unsigned long& low_count,
        unsigned long& high_count,
        unsigned long& total_count
    ) const
    {
        if (symbols[symbol].count == 0)
            return 0;

        unsigned long current = symbol;
        total_count = total;
        unsigned long high_count_temp = 0;
        bool came_from_right = true;
        while (true)
        {
            if (came_from_right)
            {
                high_count_temp += symbols[current].count + symbols[current].left_count;
            }

            // note that if current is even then it is a right child
            came_from_right = !(current&0x1);

            if (current == 0)
                break;

            // set current to its parent
            current = (current-1)>>1 ;
        }

        low_count = high_count_temp - symbols[symbol].count;
        high_count = high_count_temp;

        return symbols[symbol].count;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size
        >
    void conditioning_class_kernel_2<alphabet_size>::
    get_symbol (
        unsigned long target,
        unsigned long& symbol,
        unsigned long& low_count,
        unsigned long& high_count
    ) const
    {
        unsigned long current = 0;
        unsigned long low_count_temp = 0;

        while (true)
        {
            if (static_cast<unsigned short>(target) < symbols[current].left_count)
            {
                // we should go left
                current = (current<<1) + 1;
            }
            else
            {
                target -= symbols[current].left_count;
                low_count_temp += symbols[current].left_count;
                if (static_cast<unsigned short>(target) < symbols[current].count)
                {
                    // we have found our target
                    symbol = current;
                    high_count = low_count_temp + symbols[current].count;
                    low_count = low_count_temp;
                    break;
                }
                else
                {
                    // go right
                    target -= symbols[current].count;
                    low_count_temp += symbols[current].count;
                    current = (current<<1) + 2;
                }
            }

        }

    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_CONDITIONING_CLASS_KERNEl_1_


dlib C++ Library - conditioning_class_kernel_3.h

// Copyright (C) 2004  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_CONDITIONING_CLASS_KERNEl_3_
#define DLIB_CONDITIONING_CLASS_KERNEl_3_

#include "conditioning_class_kernel_abstract.h"
#include "../assert.h"
#include "../algs.h"

namespace dlib
{

    template <
        unsigned long alphabet_size
        >
    class conditioning_class_kernel_3
    {
        /*!
            INITIAL VALUE
                total == 1
                counts == pointer to an array of alphabet_size data structs
                for all i except i == 0: counts[i].count == 0
                counts[0].count == 1
                counts[0].symbol == alphabet_size-1
                for all i except i == alphabet_size-1:  counts[i].present == false
                counts[alphabet_size-1].present == true

            CONVENTION
                counts == pointer to an array of alphabet_size data structs
                get_total() == total
                get_count(symbol) == counts[x].count where
                                     counts[x].symbol == symbol

                LOW_COUNT(symbol) == sum of counts[0].count though counts[x-1].count
                                     where counts[x].symbol == symbol
                                     if (counts[0].symbol == symbol) LOW_COUNT(symbol)==0

                if (counts[i].count == 0) then
                    counts[i].symbol == undefined value

                if (symbol has a nonzero count) then
                    counts[symbol].present == true

                get_memory_usage() == global_state.memory_usage
        !*/

    public:

        class global_state_type
        {
        public:
            global_state_type () : memory_usage(0) {}
        private:
            unsigned long memory_usage;

            friend class conditioning_class_kernel_3<alphabet_size>;
        };

        conditioning_class_kernel_3 (
            global_state_type& global_state_
        );

        ~conditioning_class_kernel_3 (
        );

        void clear(
        );

        bool increment_count (
            unsigned long symbol,
            unsigned short amount = 1
        );

        unsigned long get_count (
            unsigned long symbol
        ) const;

        unsigned long get_total (
        ) const;

        unsigned long get_range (
            unsigned long symbol,
            unsigned long& low_count,
            unsigned long& high_count,
            unsigned long& total_count
        ) const;

        void get_symbol (
            unsigned long target,
            unsigned long& symbol,
            unsigned long& low_count,
            unsigned long& high_count
        ) const;

        unsigned long get_memory_usage (
        ) const;

        global_state_type& get_global_state (
        );

        static unsigned long get_alphabet_size (
        );

    private:

        // restricted functions
        conditioning_class_kernel_3(conditioning_class_kernel_3<alphabet_size>&);        // copy constructor
        conditioning_class_kernel_3& operator=(conditioning_class_kernel_3<alphabet_size>&);    // assignment operator

        struct data
        {
            unsigned short count;
            unsigned short symbol;
            bool present;
        };

        // data members
        unsigned short total;
        data* counts;
        global_state_type& global_state;

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size
        >
    conditioning_class_kernel_3<alphabet_size>::
    conditioning_class_kernel_3 (
        global_state_type& global_state_
    ) :
        total(1),
        counts(new data[alphabet_size]),
        global_state(global_state_)
    {
        COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65536 );

        data* start = counts;
        data* end = counts+alphabet_size;
        start->count = 1;
        start->symbol = alphabet_size-1;
        start->present = false;
        ++start;
        while (start != end)
        {
            start->count = 0;
            start->present = false;
            ++start;
        }
        counts[alphabet_size-1].present = true;

        // update memory usage
        global_state.memory_usage += sizeof(data)*alphabet_size +
                                     sizeof(conditioning_class_kernel_3);

    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size
        >
    conditioning_class_kernel_3<alphabet_size>::
    ~conditioning_class_kernel_3 (
    )
    {
        delete [] counts;
        // update memory usage
        global_state.memory_usage -= sizeof(data)*alphabet_size +
                                     sizeof(conditioning_class_kernel_3);
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size
        >
    void conditioning_class_kernel_3<alphabet_size>::
    clear(
    )
    {
        total = 1;
        data* start = counts;
        data* end = counts+alphabet_size;
        start->count = 1;
        start->symbol = alphabet_size-1;
        start->present = false;
        ++start;
        while (start != end)
        {
            start->count = 0;
            start->present = false;
            ++start;
        }
        counts[alphabet_size-1].present = true;

    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size
        >
    typename conditioning_class_kernel_3<alphabet_size>::global_state_type& conditioning_class_kernel_3<alphabet_size>::
    get_global_state(
    )
    {
        return global_state;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size
        >
    unsigned long conditioning_class_kernel_3<alphabet_size>::
    get_memory_usage(
    ) const
    {
        return global_state.memory_usage;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size
        >
    bool conditioning_class_kernel_3<alphabet_size>::
    increment_count (
        unsigned long symbol,
        unsigned short amount
    )
    {
        // if we are going over a total of 65535 then scale down all counts by 2
        if (static_cast<unsigned long>(total)+static_cast<unsigned long>(amount) >= 65536)
        {
            total = 0;
            data* start = counts;
            data* end = counts+alphabet_size;

            while (start != end)
            {
                if (start->count == 1)
                {
                    if (start->symbol == alphabet_size-1)
                    {
                        // this symbol must never be zero so we will leave its count at 1
                        ++total;
                    }
                    else
                    {
                        start->count = 0;
                        counts[start->symbol].present = false;
                    }
                }
                else
                {
                    start->count >>= 1;
                    total += start->count;
                }

                ++start;
            }
        }

        data* start = counts;
        data* swap_spot = counts;

        if (counts[symbol].present)
        {
            while (true)
            {
                if (start->symbol == symbol && start->count!=0)
                {
                    unsigned short temp = start->count + amount;

                    start->symbol = swap_spot->symbol;
                    start->count = swap_spot->count;

                    swap_spot->symbol = static_cast<unsigned short>(symbol);
                    swap_spot->count  = temp;
                    break;
                }

                if ( (start->count) < (swap_spot->count))
                {
                    swap_spot = start;
                }

                ++start;
            }
        }
        else
        {
            counts[symbol].present = true;
            while (true)
            {
                if (start->count == 0)
                {
                    start->symbol = swap_spot->symbol;
                    start->count = swap_spot->count;

                    swap_spot->symbol = static_cast<unsigned short>(symbol);
                    swap_spot->count  = amount;
                    break;
                }

                if ((start->count) < (swap_spot->count))
                {
                    swap_spot = start;
                }

                ++start;
            }
        }

        total += amount;

        return true;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size
        >
    unsigned long conditioning_class_kernel_3<alphabet_size>::
    get_count (
        unsigned long symbol
    ) const
    {
        if (counts[symbol].present == false)
            return 0;

        data* start = counts;
        while (start->symbol != symbol)
        {
            ++start;
        }
        return start->count;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size
        >
    unsigned long conditioning_class_kernel_3<alphabet_size>::
    get_alphabet_size (
    )
    {
        return alphabet_size;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size
        >
    unsigned long conditioning_class_kernel_3<alphabet_size>::
    get_total (
    ) const
    {
        return total;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size
        >
    unsigned long conditioning_class_kernel_3<alphabet_size>::
    get_range (
        unsigned long symbol,
        unsigned long& low_count,
        unsigned long& high_count,
        unsigned long& total_count
    ) const
    {
        if (counts[symbol].present == false)
            return 0;

        total_count = total;
        unsigned long low_count_temp = 0;
        data* start = counts;
        while (start->symbol != symbol)
        {
            low_count_temp += start->count;
            ++start;
        }

        low_count = low_count_temp;
        high_count = low_count_temp + start->count;
        return start->count;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size
        >
    void conditioning_class_kernel_3<alphabet_size>::
    get_symbol (
        unsigned long target,
        unsigned long& symbol,
        unsigned long& low_count,
        unsigned long& high_count
    ) const
    {
        unsigned long high_count_temp = counts->count;
        const data* start = counts;
        while (target >= high_count_temp)
        {
            ++start;
            high_count_temp += start->count;
        }

        low_count = high_count_temp - start->count;
        high_count = high_count_temp;
        symbol = static_cast<unsigned long>(start->symbol);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_CONDITIONING_CLASS_KERNEl_3_


dlib C++ Library - conditioning_class_kernel_4.h

// Copyright (C) 2004  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_CONDITIONING_CLASS_KERNEl_4_
#define DLIB_CONDITIONING_CLASS_KERNEl_4_

#include "conditioning_class_kernel_abstract.h"
#include "../assert.h"
#include "../algs.h"

namespace dlib
{
    template <
        unsigned long alphabet_size,
        unsigned long pool_size,
        typename mem_manager
        >
    class conditioning_class_kernel_4
    {
        /*!
            REQUIREMENTS ON pool_size
                pool_size > 0
                this will be the number of nodes contained in our memory pool

            REQUIREMENTS ON mem_manager
                mem_manager is an implementation of memory_manager/memory_manager_kernel_abstract.h

            INITIAL VALUE
                total == 1
                escapes == 1
                next == 0

            CONVENTION
                get_total() == total
                get_count(alphabet_size-1) == escapes

                if (next != 0) then
                    next == pointer to the start of a linked list and the linked list
                            is terminated by a node with a next pointer of 0.

                get_count(symbol) == node::count for the node where node::symbol==symbol
                                     or 0 if no such node currently exists.

                if (there is a node for the symbol) then
                    LOW_COUNT(symbol) == the sum of all node's counts in the linked list
                    up to but not including the node for the symbol.

                get_memory_usage() == global_state.memory_usage
        !*/

        struct node
        {
            unsigned short symbol;
            unsigned short count;
            node* next;
        };

    public:

        class global_state_type
        {
        public:
            global_state_type (
            ) :
                memory_usage(pool_size*sizeof(node)+sizeof(global_state_type))
                {}
        private:
            unsigned long memory_usage;

            typename mem_manager::template rebind<node>::other pool;

            friend class conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>;
        };

        conditioning_class_kernel_4 (
            global_state_type& global_state_
        );

        ~conditioning_class_kernel_4 (
        );

        void clear(
        );

        bool increment_count (
            unsigned long symbol,
            unsigned short amount = 1
        );

        unsigned long get_count (
            unsigned long symbol
        ) const;

        inline unsigned long get_total (
        ) const;

        unsigned long get_range (
            unsigned long symbol,
            unsigned long& low_count,
            unsigned long& high_count,
            unsigned long& total_count
        ) const;

        void get_symbol (
            unsigned long target,
            unsigned long& symbol,
            unsigned long& low_count,
            unsigned long& high_count
        ) const;

        unsigned long get_memory_usage (
        ) const;

        global_state_type& get_global_state (
        );

        static unsigned long get_alphabet_size (
        );

    private:

        void half_counts (
        );
        /*!
            ensures
                - divides all counts by 2 but ensures that escapes is always at least 1
        !*/

        // restricted functions
        conditioning_class_kernel_4(conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>&);        // copy constructor
        conditioning_class_kernel_4& operator=(conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>&);    // assignment operator

        // data members
        unsigned short total;
        unsigned short escapes;
        node* next;
        global_state_type& global_state;

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        unsigned long pool_size,
        typename mem_manager
        >
    conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>::
    conditioning_class_kernel_4 (
        global_state_type& global_state_
    ) :
        total(1),
        escapes(1),
        next(0),
        global_state(global_state_)
    {
        COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65536 );

        // update memory usage
        global_state.memory_usage += sizeof(conditioning_class_kernel_4);
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        unsigned long pool_size,
        typename mem_manager
        >
    conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>::
    ~conditioning_class_kernel_4 (
    )
    {
        clear();
        // update memory usage
        global_state.memory_usage -= sizeof(conditioning_class_kernel_4);
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        unsigned long pool_size,
        typename mem_manager
        >
    void conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>::
    clear(
    )
    {
        total = 1;
        escapes = 1;
        while (next)
        {
            node* temp = next;
            next = next->next;
            global_state.pool.deallocate(temp);
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        unsigned long pool_size,
        typename mem_manager
        >
    unsigned long conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>::
    get_memory_usage(
    ) const
    {
        return global_state.memory_usage;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        unsigned long pool_size,
        typename mem_manager
        >
    typename conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>::global_state_type& conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>::
    get_global_state(
    )
    {
        return global_state;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        unsigned long pool_size,
        typename mem_manager
        >
    bool conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>::
    increment_count (
        unsigned long symbol,
        unsigned short amount
    )
    {
        if (symbol == alphabet_size-1)
        {
            // make sure we won't cause any overflow
            if (total >= 65536 - amount )
                half_counts();

            escapes += amount;
            total += amount;
            return true;
        }

        // find the symbol and increment it or add a new node to the list
        if (next)
        {
            node* temp = next;
            node* previous = 0;
            while (true)
            {
                if (temp->symbol == static_cast<unsigned short>(symbol))
                {
                    // make sure we won't cause any overflow
                    if (total >= 65536 - amount )
                        half_counts();

                    // we have found the symbol
                    total += amount;
                    temp->count += amount;

                    // if this node now has a count greater than its parent node
                    if (previous && temp->count > previous->count)
                    {
                        // swap the nodes so that the nodes will be in semi-sorted order
                        swap(temp->count,previous->count);
                        swap(temp->symbol,previous->symbol);
                    }
                    return true;
                }
                else if (temp->next == 0)
                {
                    // we did not find the symbol so try to add it to the list
                    if (global_state.pool.get_number_of_allocations() < pool_size)
                    {
                        // make sure we won't cause any overflow
                        if (total >= 65536 - amount )
                            half_counts();

                        node* t = global_state.pool.allocate();
                        t->next = 0;
                        t->symbol = static_cast<unsigned short>(symbol);
                        t->count = amount;
                        temp->next = t;
                        total += amount;
                        return true;
                    }
                    else
                    {
                        // no memory left
                        return false;
                    }
                }
                else if (temp->count == 0)
                {
                    // remove nodes that have a zero count
                    if (previous)
                    {
                        previous->next = temp->next;
                        node* t = temp;
                        temp = temp->next;
                        global_state.pool.deallocate(t);
                    }
                    else
                    {
                        next = temp->next;
                        node* t = temp;
                        temp = temp->next;
                        global_state.pool.deallocate(t);
                    }
                }
                else
                {
                    previous = temp;
                    temp = temp->next;
                }
            } // while (true)
        }
        // if there aren't any nodes in the list yet then do this instead
        else
        {
            if (global_state.pool.get_number_of_allocations() < pool_size)
            {
                // make sure we won't cause any overflow
                if (total >= 65536 - amount )
                    half_counts();

                next = global_state.pool.allocate();
                next->next = 0;
                next->symbol = static_cast<unsigned short>(symbol);
                next->count = amount;
                total += amount;
                return true;
            }
            else
            {
                // no memory left
                return false;
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        unsigned long pool_size,
        typename mem_manager
        >
    unsigned long conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>::
    get_count (
        unsigned long symbol
    ) const
    {
        if (symbol == alphabet_size-1)
        {
            return escapes;
        }
        else
        {
            node* temp = next;
            while (temp)
            {
                if (temp->symbol == symbol)
                    return temp->count;
                temp = temp->next;
            }
            return 0;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        unsigned long pool_size,
        typename mem_manager
        >
    unsigned long conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>::
    get_alphabet_size (
    )
    {
        return alphabet_size;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        unsigned long pool_size,
        typename mem_manager
        >
    unsigned long conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>::
    get_total (
    ) const
    {
        return total;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        unsigned long pool_size,
        typename mem_manager
        >
    unsigned long conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>::
    get_range (
        unsigned long symbol,
        unsigned long& low_count,
        unsigned long& high_count,
        unsigned long& total_count
    ) const
    {
        if (symbol != alphabet_size-1)
        {
            node* temp = next;
            unsigned long low = 0;
            while (temp)
            {
                if (temp->symbol == static_cast<unsigned short>(symbol))
                {
                    high_count = temp->count + low;
                    low_count = low;
                    total_count = total;
                    return temp->count;
                }
                low += temp->count;
                temp = temp->next;
            }
            return 0;
        }
        else
        {
            total_count = total;
            high_count = total;
            low_count = total-escapes;
            return escapes;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        unsigned long pool_size,
        typename mem_manager
        >
    void conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>::
    get_symbol (
        unsigned long target,
        unsigned long& symbol,
        unsigned long& low_count,
        unsigned long& high_count
    ) const
    {
        node* temp = next;
        unsigned long high = 0;
        while (true)
        {
            if (temp != 0)
            {
                high += temp->count;
                if (target < high)
                {
                    symbol = temp->symbol;
                    high_count = high;
                    low_count = high - temp->count;
                    return;
                }
                temp = temp->next;
            }
            else
            {
                // this must be the escape symbol
                symbol = alphabet_size-1;
                low_count = total-escapes;
                high_count = total;
                return;
            }
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // private member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        unsigned long pool_size,
        typename mem_manager
        >
    void conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>::
    half_counts (
    )
    {
        total = 0;
        if (escapes > 1)
            escapes >>= 1;

        //divide all counts by 2
        node* temp = next;
        while (temp)
        {
            temp->count >>= 1;
            total += temp->count;
            temp = temp->next;
        }
        total += escapes;
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_CONDITIONING_CLASS_KERNEl_4_


dlib C++ Library - conditioning_class_kernel_c.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_CONDITIONING_CLASS_KERNEl_C_
#define DLIB_CONDITIONING_CLASS_KERNEl_C_

#include "conditioning_class_kernel_abstract.h"
#include "../algs.h"
#include "../assert.h"
#include <iostream>

namespace dlib
{

    template <
        typename cc_base
        >
    class conditioning_class_kernel_c : public cc_base
    {
        const unsigned long alphabet_size;

    public:

        conditioning_class_kernel_c (
            typename cc_base::global_state_type& global_state
            ) : cc_base(global_state),alphabet_size(cc_base::get_alphabet_size()) {}

        bool increment_count (
            unsigned long symbol,
            unsigned short amount = 1
        );

        unsigned long get_count (
            unsigned long symbol
        ) const;

        unsigned long get_range (
            unsigned long symbol,
            unsigned long& low_count,
            unsigned long& high_count,
            unsigned long& total_count
        ) const;

        void get_symbol (
            unsigned long target,
            unsigned long& symbol,
            unsigned long& low_count,
            unsigned long& high_count
        ) const;
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename cc_base
        >
    bool conditioning_class_kernel_c<cc_base>::
    increment_count (
        unsigned long symbol,
        unsigned short amount
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(symbol < alphabet_size &&
                0 < amount && amount < 32768,
                "\tvoid conditioning_class::increment_count()"
                << "\n\tthe symbol must be in the range 0 to alphabet_size-1. and"
                << "\n\tamount must be in the range 1 to 32767"
                << "\n\talphabet_size: " << alphabet_size
                << "\n\tsymbol:        " << symbol
                << "\n\tamount:        " << amount
                << "\n\tthis:          " << this
        );

        // call the real function
        return cc_base::increment_count(symbol,amount);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename cc_base
        >
    unsigned long conditioning_class_kernel_c<cc_base>::
    get_count (
        unsigned long symbol
    ) const
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(symbol < alphabet_size,
                "\tvoid conditioning_class::get_count()"
                << "\n\tthe symbol must be in the range 0 to alphabet_size-1"
                << "\n\talphabet_size: " << alphabet_size
                << "\n\tsymbol:        " << symbol
                << "\n\tthis:          " << this
        );

        // call the real function
        return cc_base::get_count(symbol);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename cc_base
        >
    unsigned long conditioning_class_kernel_c<cc_base>::
    get_range (
        unsigned long symbol,
        unsigned long& low_count,
        unsigned long& high_count,
        unsigned long& total_count
    ) const
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(symbol < alphabet_size,
                "\tvoid conditioning_class::get_range()"
                << "\n\tthe symbol must be in the range 0 to alphabet_size-1"
                << "\n\talphabet_size: " << alphabet_size
                << "\n\tsymbol:        " << symbol
                << "\n\tthis:          " << this
        );

        // call the real function
        return cc_base::get_range(symbol,low_count,high_count,total_count);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename cc_base
        >
    void conditioning_class_kernel_c<cc_base>::
    get_symbol (
        unsigned long target,
        unsigned long& symbol,
        unsigned long& low_count,
        unsigned long& high_count
    ) const
    {
        // make sure requires clause is not broken
        DLIB_CASSERT( target < this->get_total(),
                 "\tvoid conditioning_class::get_symbol()"
                 << "\n\tthe target must be in the range 0 to get_total()-1"
                 << "\n\tget_total(): " << this->get_total()
                 << "\n\ttarget:       " << target
                 << "\n\tthis:         " << this
        );

        // call the real function
        cc_base::get_symbol(target,symbol,low_count,high_count);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_CONDITIONING_CLASS_KERNEl_C_


dlib C++ Library - config_reader_kernel_1.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_CONFIG_READER_KERNEl_1_
#define DLIB_CONFIG_READER_KERNEl_1_

#include "config_reader_kernel_abstract.h"
#include <string>
#include <iostream>
#include <sstream>
#include <fstream>
#include "../algs.h"
#include "../stl_checked/std_vector_c.h"

#ifndef DLIB_ISO_CPP_ONLY
#include "config_reader_thread_safe_1.h"
#endif

namespace dlib
{

    template <
        typename map_string_string,
        typename map_string_void,
        typename tokenizer
        >
    class config_reader_kernel_1
    {

        /*!
            REQUIREMENTS ON map_string_string
                is an implementation of map/map_kernel_abstract.h that maps std::string to std::string

            REQUIREMENTS ON map_string_void
                is an implementation of map/map_kernel_abstract.h that maps std::string to void*

            REQUIREMENTS ON tokenizer
                is an implementation of tokenizer/tokenizer_kernel_abstract.h

            CONVENTION
                key_table.is_in_domain(x) == is_key_defined(x)
                block_table.is_in_domain(x) == is_block_defined(x)

                key_table[x] == operator[](x)
                block_table[x] == (void*)&block(x)
        !*/

    public:

        // These two typedefs are defined for backwards compatibility with older versions of dlib.
        typedef config_reader_kernel_1 kernel_1a;
#ifndef DLIB_ISO_CPP_ONLY
        typedef config_reader_thread_safe_1<
            config_reader_kernel_1,
            map_string_void
            > thread_safe_1a;
#endif // DLIB_ISO_CPP_ONLY

        config_reader_kernel_1();

        class config_reader_error : public dlib::error
        {
            friend class config_reader_kernel_1;
            config_reader_error(
                unsigned long ln,
                bool r = false
            ) :
                dlib::error(ECONFIG_READER),
                line_number(ln),
                redefinition(r)
            {
                std::ostringstream sout;
                sout << "Error in config_reader while parsing at line number " << line_number << ".";
                if (redefinition)
                    sout << "\nThe identifier on this line has already been defined in this scope.";
                const_cast<std::string&>(info) = sout.str();
            }
        public:
            const unsigned long line_number;
            const bool redefinition;
        };

        class file_not_found : public dlib::error
        {
            friend class config_reader_kernel_1;
            file_not_found(
                const std::string& file_name_
            ) :
                dlib::error(ECONFIG_READER, "Error in config_reader, unable to open file " + file_name_),
                file_name(file_name_)
            {}

            ~file_not_found() throw() {}

        public:
            const std::string file_name;
        };

        class config_reader_access_error : public dlib::error
        {
        public:
            config_reader_access_error(
                const std::string& block_name_,
                const std::string& key_name_
            ) :
                dlib::error(ECONFIG_READER),
                block_name(block_name_),
                key_name(key_name_)
            {
                std::ostringstream sout;
                sout << "Error in config_reader.\n";
                if (block_name.size() > 0)
                    sout << "   A block with the name '" << block_name << "' was expected but not found.";
                else if (key_name.size() > 0)
                    sout << "   A key with the name '" << key_name << "' was expected but not found.";

                const_cast<std::string&>(info) = sout.str();
            }

            ~config_reader_access_error() throw() {}
            const std::string block_name;
            const std::string key_name;
        };

        config_reader_kernel_1(
            const std::string& config_file
        );

        config_reader_kernel_1(
            std::istream& in
        );

        virtual ~config_reader_kernel_1(
        );

        void clear (
        );

        void load_from (
            std::istream& in
        );

        void load_from (
            const std::string& config_file
        );

        bool is_key_defined (
            const std::string& key
        ) const;

        bool is_block_defined (
            const std::string& name
        ) const;

        typedef config_reader_kernel_1 this_type;
        const this_type& block (
            const std::string& name
        ) const;

        const std::string& operator[] (
            const std::string& key
        ) const;

        template <
            typename queue_of_strings
            >
        void get_keys (
            queue_of_strings& keys
        ) const;

        template <
            typename alloc
            >
        void get_keys (
            std::vector<std::string,alloc>& keys
        ) const;

        template <
            typename alloc
            >
        void get_keys (
            std_vector_c<std::string,alloc>& keys
        ) const;

        template <
            typename queue_of_strings
            >
        void get_blocks (
            queue_of_strings& blocks
        ) const;

        template <
            typename alloc
            >
        void get_blocks (
            std::vector<std::string,alloc>& blocks
        ) const;

        template <
            typename alloc
            >
        void get_blocks (
            std_vector_c<std::string,alloc>& blocks
        ) const;

    private:

        static void parse_config_file (
            config_reader_kernel_1& cr,
            tokenizer& tok,
            unsigned long& line_number,
            const bool top_of_recursion = true
        );
        /*!
            requires
                - line_number == 1
                - cr == *this
                - top_of_recursion == true
            ensures
                - parses the data coming from tok and puts it into cr.
            throws
                - config_reader_error
        !*/

        map_string_string key_table;
        map_string_void block_table;

        // restricted functions
        config_reader_kernel_1(config_reader_kernel_1&);
        config_reader_kernel_1& operator=(config_reader_kernel_1&);

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename map_string_string,
        typename map_string_void,
        typename tokenizer
        >
    config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::
    config_reader_kernel_1(
    )
    {
    }

// ----------------------------------------------------------------------------------------

    template <
        typename map_string_string,
        typename map_string_void,
        typename tokenizer
        >
    void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::
    clear(
    )
    {
        // free all our blocks
        block_table.reset();
        while (block_table.move_next())
        {
            delete static_cast<config_reader_kernel_1*>(block_table.element().value());
        }
        block_table.clear();
        key_table.clear();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename map_string_string,
        typename map_string_void,
        typename tokenizer
        >
    void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::
    load_from(
        std::istream& in
    )
    {
        clear();

        tokenizer tok;
        tok.set_stream(in);
        tok.set_identifier_token(
            tok.lowercase_letters() + tok.uppercase_letters(),
            tok.lowercase_letters() + tok.uppercase_letters() + tok.numbers() + "_-."
        );

        unsigned long line_number = 1;
        try
        {
            parse_config_file(*this,tok,line_number);
        }
        catch (...)
        {
            clear();
            throw;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename map_string_string,
        typename map_string_void,
        typename tokenizer
        >
    void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::
    load_from(
        const std::string& config_file
    )
    {
        clear();
        std::ifstream fin(config_file.c_str());
        if (!fin)
            throw file_not_found(config_file);

        load_from(fin);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename map_string_string,
        typename map_string_void,
        typename tokenizer
        >
    config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::
    config_reader_kernel_1(
        std::istream& in
    )
    {
        load_from(in);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename map_string_string,
        typename map_string_void,
        typename tokenizer
        >
    config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::
    config_reader_kernel_1(
        const std::string& config_file
    )
    {
        load_from(config_file);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename map_string_string,
        typename map_string_void,
        typename tokenizer
        >
    void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::
    parse_config_file(
        config_reader_kernel_1<map_string_string,map_string_void,tokenizer>& cr,
        tokenizer& tok,
        unsigned long& line_number,
        const bool top_of_recursion
    )
    {
        int type;
        std::string token;
        bool in_comment = false;
        bool seen_identifier = false;
        std::string identifier;
        while (true)
        {
            tok.get_token(type,token);
            // ignore white space
            if (type == tokenizer::WHITE_SPACE)
                continue;

            // basically ignore end of lines
            if (type == tokenizer::END_OF_LINE)
            {
                ++line_number;
                in_comment = false;
                continue;
            }

            // we are in a comment still so ignore this
            if (in_comment)
                continue;

            // if this is the start of a comment
            if (type == tokenizer::CHAR && token[0] == '#')
            {
                in_comment = true;
                continue;
            }

            // if this is the case then we have just finished parsing a block so we should
            // quit this function
            if ( (type == tokenizer::CHAR && token[0] == '}' && !top_of_recursion) ||
                 (type == tokenizer::END_OF_FILE && top_of_recursion) )
            {
                break;
            }

            if (seen_identifier)
            {
                seen_identifier = false;
                // the next character should be either a '=' or a '{'
                if (type != tokenizer::CHAR || (token[0] != '=' && token[0] != '{'))
                    throw config_reader_error(line_number);

                if (token[0] == '=')
                {
                    // we should parse the value out now
                    // first discard any white space
                    if (tok.peek_type() == tokenizer::WHITE_SPACE)
                        tok.get_token(type,token);

                    std::string value;
                    type = tok.peek_type();
                    token = tok.peek_token();
                    while (true)
                    {
                        if (type == tokenizer::END_OF_FILE || type == tokenizer::END_OF_LINE)
                            break;

                        if (type == tokenizer::CHAR && token[0] == '\\')
                        {
                            tok.get_token(type,token);
                            if (tok.peek_type() == tokenizer::CHAR &&
                                tok.peek_token()[0] == '#')
                            {
                                tok.get_token(type,token);
                                value += '#';
                            }
                            else if (tok.peek_type() == tokenizer::CHAR &&
                                tok.peek_token()[0] == '}')
                            {
                                tok.get_token(type,token);
                                value += '}';
                            }
                            else
                            {
                                value += '\\';
                            }
                        }
                        else if (type == tokenizer::CHAR &&
                                 (token[0] == '#' || token[0] == '}'))
                        {
                            break;
                        }
                        else
                        {
                            value += token;
                            tok.get_token(type,token);
                        }
                        type = tok.peek_type();
                        token = tok.peek_token();
                    } // while(true)

                    // strip of any tailing white space from value
                    std::string::size_type pos = value.find_last_not_of(" \t\r\n");
                    if (pos == std::string::npos)
                        value.clear();
                    else
                        value.erase(pos+1);

                    // make sure this key isn't already in the key_table
                    if (cr.key_table.is_in_domain(identifier))
                        throw config_reader_error(line_number,true);

                    // add this key/value pair to the key_table
                    cr.key_table.add(identifier,value);

                }
                else  // when token[0] == '{'
                {
                    // make sure this identifier isn't already in the block_table
                    if (cr.block_table.is_in_domain(identifier))
                        throw config_reader_error(line_number,true);

                    config_reader_kernel_1* new_cr = new config_reader_kernel_1;
                    void* vtemp = new_cr;
                    try { cr.block_table.add(identifier,vtemp); }
                    catch (...) { delete new_cr; throw; }

                    // now parse this block
                    parse_config_file(*new_cr,tok,line_number,false);
                }
            }
            else
            {
                // the next thing should be an identifier but if it isn't this is an error
                if (type != tokenizer::IDENTIFIER)
                    throw config_reader_error(line_number);

                seen_identifier = true;
                identifier = token;
            }
        } // while (true)
    }

// ----------------------------------------------------------------------------------------

    template <
        typename map_string_string,
        typename map_string_void,
        typename tokenizer
        >
    config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::
    ~config_reader_kernel_1(
    )
    {
        clear();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename map_string_string,
        typename map_string_void,
        typename tokenizer
        >
    bool config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::
    is_key_defined (
        const std::string& key
    ) const
    {
        return key_table.is_in_domain(key);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename map_string_string,
        typename map_string_void,
        typename tokenizer
        >
    bool config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::
    is_block_defined (
        const std::string& name
    ) const
    {
        return block_table.is_in_domain(name);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename mss,
        typename msv,
        typename tokenizer
        >
    const config_reader_kernel_1<mss,msv,tokenizer>& config_reader_kernel_1<mss,msv,tokenizer>::
    block (
        const std::string& name
    ) const
    {
        if (is_block_defined(name) == false)
        {
            throw config_reader_access_error(name,"");
        }

        return *static_cast<config_reader_kernel_1*>(block_table[name]);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename map_string_string,
        typename map_string_void,
        typename tokenizer
        >
    const std::string& config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::
    operator[] (
        const std::string& key
    ) const
    {
        if (is_key_defined(key) == false)
        {
            throw config_reader_access_error("",key);
        }

        return key_table[key];
    }

// ----------------------------------------------------------------------------------------

    template <
        typename map_string_string,
        typename map_string_void,
        typename tokenizer
        >
    template <
        typename queue_of_strings
        >
    void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::
    get_keys (
        queue_of_strings& keys
    ) const
    {
        keys.clear();
        key_table.reset();
        std::string temp;
        while (key_table.move_next())
        {
            temp = key_table.element().key();
            keys.enqueue(temp);
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename map_string_string,
        typename map_string_void,
        typename tokenizer
        >
    template <
        typename alloc
        >
    void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::
    get_keys (
        std::vector<std::string,alloc>& keys
    ) const
    {
        keys.clear();
        key_table.reset();
        while (key_table.move_next())
        {
            keys.push_back(key_table.element().key());
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename map_string_string,
        typename map_string_void,
        typename tokenizer
        >
    template <
        typename alloc
        >
    void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::
    get_keys (
        std_vector_c<std::string,alloc>& keys
    ) const
    {
        keys.clear();
        key_table.reset();
        while (key_table.move_next())
        {
            keys.push_back(key_table.element().key());
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename map_string_string,
        typename map_string_void,
        typename tokenizer
        >
    template <
        typename queue_of_strings
        >
    void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::
    get_blocks (
        queue_of_strings& blocks
    ) const
    {
        blocks.clear();
        block_table.reset();
        std::string temp;
        while (block_table.move_next())
        {
            temp = block_table.element().key();
            blocks.enqueue(temp);
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename map_string_string,
        typename map_string_void,
        typename tokenizer
        >
    template <
        typename alloc
        >
    void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::
    get_blocks (
        std::vector<std::string,alloc>& blocks
    ) const
    {
        blocks.clear();
        block_table.reset();
        while (block_table.move_next())
        {
            blocks.push_back(block_table.element().key());
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename map_string_string,
        typename map_string_void,
        typename tokenizer
        >
    template <
        typename alloc
        >
    void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::
    get_blocks (
        std_vector_c<std::string,alloc>& blocks
    ) const
    {
        blocks.clear();
        block_table.reset();
        while (block_table.move_next())
        {
            blocks.push_back(block_table.element().key());
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_CONFIG_READER_KERNEl_1_


dlib C++ Library - config_reader_thread_safe_1.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_CONFIG_READER_THREAD_SAFe_
#define DLIB_CONFIG_READER_THREAD_SAFe_

#include "config_reader_kernel_abstract.h"
#include <string>
#include <iostream>
#include <sstream>
#include "../algs.h"
#include "../interfaces/enumerable.h"
#include "../threads.h"
#include "config_reader_thread_safe_abstract.h"

namespace dlib
{

    template <
        typename config_reader_base,
        typename map_string_void
        >
    class config_reader_thread_safe_1
    {

        /*!
            CONVENTION
                - get_mutex() == *m
                - *cr == the config reader being extended
                - block_table[x] == (void*)&block(x)
                - block_table.size() == the number of blocks in *cr
                - block_table[key] == a config_reader_thread_safe_1 that contains &cr.block(key)
                - if (own_pointers) then
                    - this object owns the m and cr pointers and should delete them when destructed
        !*/

    public:

        config_reader_thread_safe_1 (
            const config_reader_base* base,
            rmutex* m_
        );

        config_reader_thread_safe_1();

        typedef typename config_reader_base::config_reader_error config_reader_error;
        typedef typename config_reader_base::config_reader_access_error config_reader_access_error;

        config_reader_thread_safe_1(
            std::istream& in
        );

        config_reader_thread_safe_1(
            const std::string& config_file
        );

        virtual ~config_reader_thread_safe_1(
        );

        void clear (
        );

        void load_from (
            std::istream& in
        );

        void load_from (
            const std::string& config_file
        );

        bool is_key_defined (
            const std::string& key
        ) const;

        bool is_block_defined (
            const std::string& name
        ) const;

        typedef config_reader_thread_safe_1 this_type;
        const this_type& block (
            const std::string& name
        ) const;

        const std::string& operator[] (
            const std::string& key
        ) const;

        template <
            typename queue_of_strings
            >
        void get_keys (
            queue_of_strings& keys
        ) const;

        template <
            typename queue_of_strings
            >
        void get_blocks (
            queue_of_strings& blocks
        ) const;

        inline const rmutex& get_mutex (
        ) const;

    private:

        void fill_block_table (
        );
        /*!
            ensures
                - block_table.size() == the number of blocks in cr
                - block_table[key] == a config_reader_thread_safe_1 that contains &cr.block(key)
        !*/

        rmutex* m;
        config_reader_base* cr;
        map_string_void block_table;
        const bool own_pointers;

        // restricted functions
        config_reader_thread_safe_1(config_reader_thread_safe_1&);
        config_reader_thread_safe_1& operator=(config_reader_thread_safe_1&);

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename config_reader_base,
        typename map_string_void
        >
    config_reader_thread_safe_1<config_reader_base,map_string_void>::
    config_reader_thread_safe_1(
        const config_reader_base* base,
        rmutex* m_
    ) :
        m(m_),
        cr(const_cast<config_reader_base*>(base)),
        own_pointers(false)
    {
        fill_block_table();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename config_reader_base,
        typename map_string_void
        >
    config_reader_thread_safe_1<config_reader_base,map_string_void>::
    config_reader_thread_safe_1(
    ) :
        m(0),
        cr(0),
        own_pointers(true)
    {
        try
        {
            m = new rmutex;
            cr = new config_reader_base;
        }
        catch (...)
        {
            if (m) delete m;
            if (cr) delete cr;
            throw;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename config_reader_base,
        typename map_string_void
        >
    void config_reader_thread_safe_1<config_reader_base,map_string_void>::
    clear(
    )
    {
        auto_mutex M(*m);
        cr->clear();
        fill_block_table();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename config_reader_base,
        typename map_string_void
        >
    void config_reader_thread_safe_1<config_reader_base,map_string_void>::
    load_from(
        std::istream& in
    )
    {
        auto_mutex M(*m);
        cr->load_from(in);
        fill_block_table();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename config_reader_base,
        typename map_string_void
        >
    void config_reader_thread_safe_1<config_reader_base,map_string_void>::
    load_from(
        const std::string& config_file
    )
    {
        auto_mutex M(*m);
        cr->load_from(config_file);
        fill_block_table();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename config_reader_base,
        typename map_string_void
        >
    config_reader_thread_safe_1<config_reader_base,map_string_void>::
    config_reader_thread_safe_1(
        std::istream& in
    ) :
        m(0),
        cr(0),
        own_pointers(true)
    {
        try
        {
            m = new rmutex;
            cr = new config_reader_base(in);
            fill_block_table();
        }
        catch (...)
        {
            if (m) delete m;
            if (cr) delete cr;
            throw;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename config_reader_base,
        typename map_string_void
        >
    config_reader_thread_safe_1<config_reader_base,map_string_void>::
    config_reader_thread_safe_1(
        const std::string& config_file
    ) :
        m(0),
        cr(0),
        own_pointers(true)
    {
        try
        {
            m = new rmutex;
            cr = new config_reader_base(config_file);
            fill_block_table();
        }
        catch (...)
        {
            if (m) delete m;
            if (cr) delete cr;
            throw;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename config_reader_base,
        typename map_string_void
        >
    config_reader_thread_safe_1<config_reader_base,map_string_void>::
    ~config_reader_thread_safe_1(
    )
    {
        if (own_pointers)
        {
            delete m;
            delete cr;
        }

        // clear out the block table
        block_table.reset();
        while (block_table.move_next())
        {
            delete static_cast<config_reader_thread_safe_1*>(block_table.element().value());
        }
        block_table.clear();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename config_reader_base,
        typename map_string_void
        >
    bool config_reader_thread_safe_1<config_reader_base,map_string_void>::
    is_key_defined (
        const std::string& key
    ) const
    {
        auto_mutex M(*m);
        return cr->is_key_defined(key);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename config_reader_base,
        typename map_string_void
        >
    bool config_reader_thread_safe_1<config_reader_base,map_string_void>::
    is_block_defined (
        const std::string& name
    ) const
    {
        auto_mutex M(*m);
        return cr->is_block_defined(name);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename config_reader_base,
        typename map_string_void
        >
    const config_reader_thread_safe_1<config_reader_base,map_string_void>& config_reader_thread_safe_1<config_reader_base,map_string_void>::
    block (
        const std::string& name
    ) const
    {
        auto_mutex M(*m);
        if (block_table.is_in_domain(name) == false)
        {
            throw config_reader_access_error(name,"");
        }

        return *static_cast<config_reader_thread_safe_1*>(block_table[name]);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename config_reader_base,
        typename map_string_void
        >
    const std::string& config_reader_thread_safe_1<config_reader_base,map_string_void>::
    operator[] (
        const std::string& key
    ) const
    {
        auto_mutex M(*m);
        return (*cr)[key];
    }

// ----------------------------------------------------------------------------------------

    template <
        typename config_reader_base,
        typename map_string_void
        >
    template <
        typename queue_of_strings
        >
    void config_reader_thread_safe_1<config_reader_base,map_string_void>::
    get_keys (
        queue_of_strings& keys
    ) const
    {
        auto_mutex M(*m);
        cr->get_keys(keys);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename config_reader_base,
        typename map_string_void
        >
    template <
        typename queue_of_strings
        >
    void config_reader_thread_safe_1<config_reader_base,map_string_void>::
    get_blocks (
        queue_of_strings& blocks
    ) const
    {
        auto_mutex M(*m);
        cr->get_blocks(blocks);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename config_reader_base,
        typename map_string_void
        >
    const rmutex& config_reader_thread_safe_1<config_reader_base,map_string_void>::
    get_mutex (
    ) const
    {
        return *m;
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//      private member functions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename config_reader_base,
        typename map_string_void
        >
    void config_reader_thread_safe_1<config_reader_base,map_string_void>::
    fill_block_table (
    )
    {
        using namespace std;
        // first empty out the block table
        block_table.reset();
        while (block_table.move_next())
        {
            delete static_cast<config_reader_thread_safe_1*>(block_table.element().value());
        }
        block_table.clear();

        std::vector<std::string> blocks;
        cr->get_blocks(blocks);

        // now fill the block table up to match what is in cr
        for (unsigned long i = 0; i < blocks.size(); ++i)
        {
            config_reader_thread_safe_1* block = new config_reader_thread_safe_1(&cr->block(blocks[i]),m);
            void* temp = block;
            block_table.add(blocks[i],temp);
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_CONFIG_READER_THREAD_SAFe_


dlib C++ Library - cpp_pretty_printer_kernel_1.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_CPP_PRETTY_PRINTER_KERNEl_1_
#define DLIB_CPP_PRETTY_PRINTER_KERNEl_1_

#include <string>
#include <iostream>
#include <sstream>
#include "cpp_pretty_printer_kernel_abstract.h"
#include "../algs.h"

namespace dlib
{

    template <
        typename stack,
        typename tok
        >
    class cpp_pretty_printer_kernel_1
    {
        /*!
            REQUIREMENTS ON stack
                must be an implementation of stack/stack_kernel_abstract.h and
                stack::type == unsigned long

            REQUIREMENTS ON tok
                must be an implementation of tokenizer/tokenizer_kernel_abstract.h

            INFO
                This implementation applies a color scheme, turns include directives
                such as #include "file.h" into links to file.h.html, and it also puts
                HTML anchor points on function and class declarations.
        !*/

    public:

        cpp_pretty_printer_kernel_1 (
        );

        virtual ~cpp_pretty_printer_kernel_1 (
        );

        void print (
            std::istream& in,
            std::ostream& out,
            const std::string& title
        ) const;

        void print_and_number (
            std::istream& in,
            std::ostream& out,
            const std::string& title
        ) const;

    private:

        const std::string htmlify (
            const std::string& str
        ) const;
        /*!
            ensures
                - str == str but with any '<' replaced with '&lt;', any '>' replaced
                  with '&gt;', and any '&' replaced with '&amp;'
        !*/

        // data members
        mutable tok t;

        void number (
            std::istream& in,
            std::ostream& out
        ) const;
        /*!
            ensures
                - prints in to out and adds line numbers
        !*/

        // restricted functions
        cpp_pretty_printer_kernel_1(const cpp_pretty_printer_kernel_1&);        // copy constructor
        cpp_pretty_printer_kernel_1& operator=(const cpp_pretty_printer_kernel_1&);    // assignment operator

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename stack,
        typename tok
        >
    cpp_pretty_printer_kernel_1<stack,tok>::
    cpp_pretty_printer_kernel_1 (
    )
    {
    }

// ----------------------------------------------------------------------------------------

    template <
        typename stack,
        typename tok
        >
    cpp_pretty_printer_kernel_1<stack,tok>::
    ~cpp_pretty_printer_kernel_1 (
    )
    {
    }

// ----------------------------------------------------------------------------------------

    template <
        typename stack,
        typename tok
        >
    void cpp_pretty_printer_kernel_1<stack,tok>::
    print (
        std::istream& in,
        std::ostream& out,
        const std::string& title
    ) const
    {
        using namespace std;

        if (!out)
            throw std::ios::failure("error occurred in cpp_pretty_printer_kernel_1::print");

        t.set_stream(in);

        out << "<html><!-- "
            << "Created using the cpp_pretty_printer from the dlib C++ library.  See http://dlib.net for updates."
            << " --><head><title>" << title << "</title></head><body bgcolor='white'><pre>\n";
        if (!out)
            throw std::ios::failure("error occurred in cpp_pretty_printer_kernel_1::print");

        unsigned long scope = 0; // counts the number of new scopes we have entered
                        // since we were at a scope where functions can be declared

        bool recently_seen_class_keyword = false;
            // true if we have seen the keywords class, struct, or enum and
            // we have not seen any identifiers or { characters

        bool recently_seen_include = false;
            // true if we have seen the #include keyword and have not seen double
            // quoted text or >

        bool recently_seen_new_scope = false;
            // true if we have seen the keywords class, namespace, or struct and
            // we have not seen the characters {, ), or ; since then

        bool recently_seen_paren = false;
            // true if we have seen a ) and we have only seen white_space or comments since

        bool in_initialization_list = false;
            // true if we have seen a ) followed by any white space or comments and then
            // followed by a : (in scope==0 with recently_seen_preprocessor==false) and we
            // have not yet seen the character { or ;

        bool recently_seen_preprocessor = false;
            // true if we have seen the #pragma or #if or #define or #elif keywords and have
            // not seen an end of line.

        bool recently_seen_extern = false;
            // true if we have seen the extern keyword and haven't seen a ; or { yet.

        unsigned long paren_count = 0;
            // this is the number of ( we have seen minus the number of ) we have
            // seen.

        int type;
        stack scopes; // a stack to hold old scopes
        string token, temp;
        t.get_token(type,token);
        while (type != tok::END_OF_FILE)
        {
            switch (type)
            {
            case tok::IDENTIFIER: // ------------------------------------------
                if ( recently_seen_class_keyword)
                {
                    // this might be a class name so check if there is a
                    // ; or identifier or * or & coming up.
                    type = t.peek_type();
                    temp.clear();
                    if (type == tok::WHITE_SPACE)
                    {
                        t.get_token(type,temp);
                        if (temp.find_first_of("\n\r") != string::npos)
                            recently_seen_preprocessor = false;
                    }
                    if (t.peek_token() != ";" && t.peek_type() != tok::IDENTIFIER &&
                        t.peek_token() != "*" && t.peek_token() != "&")
                    {
                        // this is the name of a class or struct in a class or
                        // struct declaration.
                        out << "<b><a name='" << token << "'></a>" << token << "</b>" << temp;
                    }
                    else
                    {
                        out << token << temp;
                    }
                }
                else if ( !in_initialization_list &&
                     !recently_seen_preprocessor )
                {
                    // this might be a function name so check if there is a
                    // ( coming up.
                    type = t.peek_type();
                    temp.clear();
                    if (type == tok::WHITE_SPACE)
                    {
                        t.get_token(type,temp);
                        type = t.peek_type();
                    }
                    if (type == tok::OTHER && t.peek_token() == "(")
                    {
                        if (scope == 0 && paren_count == 0)
                        {
                            // this is a function definition or prototype
                            out << "<b><a name='" << token << "'></a>" << token << "</b>" << temp;
                        }
                        else
                        {
                            // this is a function call (probably)
                            out << "<font color='#BB00BB'>" << token << "</font>" << temp;
                        }
                    }
                    else
                    {
                        out << token << temp;
                    }
                }
                else
                {
                    out << token;
                }

                recently_seen_class_keyword = false;
                recently_seen_paren = false;
                break;

            case tok::KEYWORD: // ---------------------------------------------
                if (scope == 0 && token == "operator")
                {
                    // Doing this is sort of weird since operator is really a keyword
                    // but I just like how this looks.
                    out << "<b><a name='" << token << "'></a>" << token << "</b>";
                }
                // this isn't a keyword if it is something like #include <new>
                else if ( token == "true" || token == "false")
                {
                    // color 'true' and 'false' the same way we color numbers
                    out << "<font color='#979000'>" << token << "</font>";
                }
                else if (!recently_seen_include)
                {
                    // This is a normal keyword
                    if (token == "char" || token == "unsigned" || token == "signed" ||
                        token == "short" || token == "int" || token == "long" ||
                        token == "float" || token == "double" || token == "bool" ||
                        token == "void" || token == "size_t" || token == "wchar_t")
                    {
                        out << "<font color='#0000FF'><u>" << token << "</u></font>";
                    }
                    else
                    {
                        out << "<font color='#0000FF'>" << token << "</font>";
                    }
                }
                else
                {
                    out << token;
                }

                if (token == "#include")
                {
                    recently_seen_include = true;
                }
                else if (token == "class")
                {
                    recently_seen_new_scope = true;
                    recently_seen_class_keyword = true;
                }
                else if (token == "namespace")
                {
                    recently_seen_new_scope = true;
                }
                else if (token == "enum")
                {
                    recently_seen_class_keyword = true;
                }
                else if (token == "struct")
                {
                    recently_seen_new_scope = true;
                    recently_seen_class_keyword = true;
                }
                else if (token == "#pragma" || token == "#if" || token == "#define" || token == "#elif")
                {
                    recently_seen_preprocessor = true;
                }
                else if (token == "extern")
                {
                    recently_seen_extern = true;
                }
                recently_seen_paren = false;
                break;

            case tok::COMMENT: // ---------------------------------------------
                {
                    // if this is a special anchor comment
                    if (token.size() > 4 &&
                        token[0] == '/' &&
                        token[1] == '*' &&
                        token[2] == '!' &&
                        token[3] == 'A' &&
                        token[4] == ' '
                    )
                    {
                        temp = token;
                        istringstream sin(token);
                        sin >> temp;
                        sin >> temp;
                        sin.get();
                        // if there was still more stuff in the token then we are ok.
                        if (sin)
                            out << "<a name='" << temp << "'/>";
                    }
                    out << "<font color='#009900'>" << htmlify(token) << "</font>";
                }
                break;

            case tok::SINGLE_QUOTED_TEXT: // ----------------------------------
                {
                    out << "<font color='#FF0000'>" << htmlify(token) << "</font>";
                    recently_seen_paren = false;
                }
                break;

            case tok::NUMBER: // -----------------------------------------
                {
                    out << "<font color='#979000'>" << token << "</font>";
                    recently_seen_include = false;
                }
                break;

            case tok::WHITE_SPACE: // -----------------------------------------
                {
                    out << token;
                    if (token.find_first_of("\n\r") != string::npos)
                        recently_seen_preprocessor = false;
                }
                break;

            case tok::DOUBLE_QUOTED_TEXT: // ----------------------------------
                {
                    if (recently_seen_include)
                    {
                        // this is the name of an included file
                        recently_seen_include = false;
                        out << "<a style='text-decoration:none' href='" << htmlify(token) << ".html'>" << htmlify(token) << "</a>";
                    }
                    else
                    {
                        // this is just a normal quoted string
                        out << "<font color='#CC0000'>" << htmlify(token) << "</font>";
                    }
                    recently_seen_paren = false;
                }
                break;

            case tok::OTHER: // -----------------------------------------------
                switch (token[0])
                {
                case '{':
                    out << "<b>{</b>";
                    // if we are entering a new scope
                    if (recently_seen_new_scope || recently_seen_extern)
                    {
                        recently_seen_new_scope = false;
                        scopes.push(scope);
                        scope = 0;
                    }
                    else
                    {
                        ++scope;
                    }
                    in_initialization_list = false;
                    recently_seen_paren = false;
                    recently_seen_class_keyword = false;
                    recently_seen_extern = false;
                    break;
                case '}':
                    out << "<b>}</b>";
                    if (scope > 0)
                    {
                        --scope;
                    }
                    else if (scopes.size())
                    {
                        scopes.pop(scope);
                    }
                    recently_seen_paren = false;
                    break;

                case ':':
                    out << ':';
                    if (recently_seen_paren && scope == 0 &&
                        recently_seen_preprocessor == false)
                    {
                        in_initialization_list = true;
                    }
                    recently_seen_paren = false;
                    break;

                case ';':
                    out << ';';
                    recently_seen_new_scope = false;
                    recently_seen_paren = false;
                    recently_seen_extern = false;
                    break;

                case ')':
                    out << "<font face='Lucida Console'>)</font>";
                    recently_seen_paren = true;
                    recently_seen_new_scope = false;
                    --paren_count;
                    break;

                case '(':
                    out << "<font face='Lucida Console'>(</font>";
                    recently_seen_paren = false;
                    ++paren_count;
                    break;

                case '>':
                    recently_seen_include = false;
                    out << "<font color='#5555FF'>&gt;</font>";
                    recently_seen_paren = false;
                    break;

                case '<':
                    out << "<font color='#5555FF'>&lt;</font>";
                    recently_seen_paren = false;
                    break;

                case '&':
                    out << "<font color='#5555FF'>&amp;</font>";
                    recently_seen_paren = false;
                    break;

                case '=':
                case '+':
                case '-':
                case '/':
                case '*':
                case '!':
                case '|':
                case '%':
                    out << "<font color='#5555FF'>" << token << "</font>";
                    recently_seen_paren = false;
                    break;

                default:
                    out << token;
                    recently_seen_paren = false;
                    break;

                } // switch (token[0])
                break;

            } // switch (type)

            t.get_token(type,token);
        } // while (type != tok::END_OF_FILE)

        out << "\n</pre></body></html>";
        if (!out)
            throw std::ios::failure("error occurred in cpp_pretty_printer_kernel_1::print");
    }

// ----------------------------------------------------------------------------------------

    template <
        typename stack,
        typename tok
        >
    void cpp_pretty_printer_kernel_1<stack,tok>::
    print_and_number (
        std::istream& in,
        std::ostream& out,
        const std::string& title
    ) const
    {
        using namespace std;
        ostringstream sout;
        print(in,sout,title);
        istringstream sin(sout.str());
        number(sin,out);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // private member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename stack,
        typename tok
        >
    void cpp_pretty_printer_kernel_1<stack,tok>::
    number (
        std::istream& in,
        std::ostream& out
    ) const
    {
        if (!out)
            throw std::ios::failure("error occurred in cpp_pretty_printer_kernel_1::number");

        std::string space = "&nbsp;&nbsp;&nbsp;";
        std::ios::int_type ch;
        unsigned long count = 1;
        while ((ch=in.get()) != EOF)
        {
            if (ch != '\n')
            {
                out << (char)ch;
            }
            else
            {
                out << "\n<font color='555555'>" << count << " </font> " + space;
                ++count;
                if (count == 10)
                    space = "&nbsp;&nbsp;";
                if (count == 100)
                    space = "&nbsp;";
                if (count == 1000)
                    space = "";
            }
        }
        if (!out)
            throw std::ios::failure("error occurred in cpp_pretty_printer_kernel_1::number");
    }

// ----------------------------------------------------------------------------------------

    template <
        typename stack,
        typename tok
        >
    const std::string cpp_pretty_printer_kernel_1<stack,tok>::
    htmlify (
        const std::string& str
    ) const
    {
        std::string::size_type i;
        std::string temp;
        for (i = 0; i < str.size(); ++i)
        {
            if (str[i] == '<')
                temp += "&lt;";
            else if (str[i] == '>')
                temp += "&gt;";
            else if (str[i] == '&')
                temp += "&amp;";
            else
                temp += str[i];
        }
        return temp;
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_CPP_PRETTY_PRINTER_KERNEl_1_


dlib C++ Library - cpp_pretty_printer_kernel_2.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_CPP_PRETTY_PRINTER_KERNEl_2_
#define DLIB_CPP_PRETTY_PRINTER_KERNEl_2_

#include <string>
#include <iostream>
#include <sstream>
#include "cpp_pretty_printer_kernel_abstract.h"
#include "../algs.h"

namespace dlib
{

    template <
        typename stack,
        typename tok
        >
    class cpp_pretty_printer_kernel_2
    {
        /*!
            REQUIREMENTS ON stack
                must be an implementation of stack/stack_kernel_abstract.h and
                stack::type == unsigned long

            REQUIREMENTS ON tok
                must be an implementation of tokenizer/tokenizer_kernel_abstract.h

            INFO
                This implementation applies a black and white color scheme suitable
                for printing on a black and white printer.  It also places the document
                title prominently at the top of the pretty printed source file.
        !*/

    public:

        cpp_pretty_printer_kernel_2 (
        );

        virtual ~cpp_pretty_printer_kernel_2 (
        );

        void print (
            std::istream& in,
            std::ostream& out,
            const std::string& title
        ) const;

        void print_and_number (
            std::istream& in,
            std::ostream& out,
            const std::string& title
        ) const;

    private:

        // data members
        mutable tok t;

        const std::string htmlify (
            const std::string& str
        ) const;
        /*!
            ensures
                - str == str but with any '<' replaced with '&lt;', any '>' replaced
                  with '&gt;', and any '&' replaced with '&amp;'
        !*/

        void number (
            std::istream& in,
            std::ostream& out
        ) const;
        /*!
            ensures
                - prints in to out and adds line numbers
        !*/

        // restricted functions
        cpp_pretty_printer_kernel_2(const cpp_pretty_printer_kernel_2&);        // copy constructor
        cpp_pretty_printer_kernel_2& operator=(const cpp_pretty_printer_kernel_2&);    // assignment operator

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename stack,
        typename tok
        >
    cpp_pretty_printer_kernel_2<stack,tok>::
    cpp_pretty_printer_kernel_2 (
    )
    {
    }

// ----------------------------------------------------------------------------------------

    template <
        typename stack,
        typename tok
        >
    cpp_pretty_printer_kernel_2<stack,tok>::
    ~cpp_pretty_printer_kernel_2 (
    )
    {
    }

// ----------------------------------------------------------------------------------------

    template <
        typename stack,
        typename tok
        >
    void cpp_pretty_printer_kernel_2<stack,tok>::
    print (
        std::istream& in,
        std::ostream& out,
        const std::string& title
    ) const
    {
        using namespace std;

        if (!out)
            throw std::ios::failure("error occurred in cpp_pretty_printer_kernel_2::print");

        t.set_stream(in);

        out << "<html><!-- "
            << "Created using the cpp_pretty_printer from the dlib C++ library.  See http://dlib.net for updates."
            << " --><head>"
            << "<title>" << title << "</title></head><body bgcolor='white'>"
            << "<h1><center>" << title << "</center></h1><pre>\n"
            << "<font style='font-size:9pt' face='Lucida Console'>\n";
        if (!out)
            throw std::ios::failure("error occurred in cpp_pretty_printer_kernel_2::print");

        unsigned long scope = 0; // counts the number of new scopes we have entered
                        // since we were at a scope where functions can be declared

        bool recently_seen_class_keyword = false;
            // true if we have seen the keywords class or struct and
            // we have not seen any identifiers or { characters

        bool recently_seen_include = false;
            // true if we have seen the #include keyword and have not seen double
            // quoted text or >

        bool recently_seen_new_scope = false;
            // true if we have seen the keywords class, namespace, or struct and
            // we have not seen the characters {, ), or ; since then

        bool recently_seen_paren = false;
            // true if we have seen a ) and we have only seen white_space or comments since

        bool in_initialization_list = false;
            // true if we have seen a ) followed by any white space or comments and then
            // followed by a : (in scope==0 with recently_seen_preprocessor==false) and we
            // have not yet seen the character { or ;

        bool recently_seen_preprocessor = false;
            // true if we have seen the #pragma or #if or #define or #elif keyword and
            // have not seen an identifier.

        bool recently_seen_extern = false;
            // true if we have seen the extern keyword and haven't yet seen a
            // { or ; character.

        unsigned long paren_count = 0;
            // this is the number of ( we have seen minus the number of ) we have
            // seen.

        int type;
        stack scopes; // a stack to hold old scopes
        string token, temp;
        t.get_token(type,token);
        while (type != tok::END_OF_FILE)
        {
            switch (type)
            {
            case tok::IDENTIFIER: // ------------------------------------------
                if ( recently_seen_class_keyword)
                {
                    // this might be a class name so check if there is a
                    // ; or identifier or * or &amp; coming up.
                    type = t.peek_type();
                    temp.clear();
                    if (type == tok::WHITE_SPACE)
                    {
                        t.get_token(type,temp);
                        if (temp.find_first_of("\n\r") != string::npos)
                            recently_seen_preprocessor = false;
                    }
                    if (t.peek_token() != ";" && t.peek_type() != tok::IDENTIFIER &&
                        t.peek_token() != "*" && t.peek_token() != "&amp;")
                    {
                        // this is the name of a class or struct in a class or
                        // struct declaration.
                        out << "<b><i>" << token << "</i></b>" << temp;
                    }
                    else
                    {
                        out << token << temp;
                    }
                }
                else if ( !in_initialization_list &&
                     !recently_seen_preprocessor &&
                     scope == 0 &&
                     paren_count == 0)
                {
                    // this might be a function name so check if there is a
                    // ( coming up.
                    type = t.peek_type();
                    temp.clear();
                    if (type == tok::WHITE_SPACE)
                    {
                        t.get_token(type,temp);
                        type = t.peek_type();
                    }
                    if (type == tok::OTHER && t.peek_token() == "(")
                    {
                        // this is a function definition or prototype
                        out << "<b><i>" << token << "</i></b>" << temp;
                    }
                    else
                    {
                        out << token << temp;
                    }
                }
                else
                {
                    out << token;
                }

                recently_seen_class_keyword = false;
                recently_seen_paren = false;
                break;

            case tok::KEYWORD: // ---------------------------------------------
                if (scope == 0 && token == "operator")
                {
                    // Doing this is sort of weird since operator is really a keyword
                    // but I just like how this looks.
                    out << "<b><i>" << token << "</i></b>";
                }
                // this isn't a keyword if it is something like #include <new>
                else if (!recently_seen_include)
                {
                    // This is a normal keyword
                    out << "<u><font face='Fixedsys'>" << token << "</font></u>";
                }
                else
                {
                    out << token;
                }

                if (token == "#include")
                {
                    recently_seen_include = true;
                }
                else if (token == "class")
                {
                    recently_seen_new_scope = true;
                    recently_seen_class_keyword = true;
                }
                else if (token == "namespace")
                {
                    recently_seen_new_scope = true;
                }
                else if (token == "struct")
                {
                    recently_seen_new_scope = true;
                    recently_seen_class_keyword = true;
                }
                else if (token == "#pragma" || token == "#define" || token == "#elif" || token == "#if")
                {
                    recently_seen_preprocessor = true;
                }
                else if (token == "extern")
                {
                    recently_seen_extern = true;
                }
                recently_seen_paren = false;
                break;

            case tok::COMMENT: // ---------------------------------------------
                {
                    out << "<font face='Courier New'>" << htmlify(token) << "</font>";
                }
                break;

            case tok::SINGLE_QUOTED_TEXT: // ----------------------------------
                {
                    out << htmlify(token);
                    recently_seen_paren = false;
                }
                break;

            case tok::WHITE_SPACE: // -----------------------------------------
                {
                    out << token;
                    if (token.find_first_of("\n\r") != string::npos)
                        recently_seen_preprocessor = false;
                }
                break;

            case tok::DOUBLE_QUOTED_TEXT: // ----------------------------------
                {
                    out << htmlify(token);
                    recently_seen_paren = false;
                    recently_seen_include = false;
                }
                break;

            case tok::NUMBER:
            case tok::OTHER: // -----------------------------------------------
                switch (token[0])
                {
                case '{':
                    out << "<b>{</b>";
                    // if we are entering a new scope
                    if (recently_seen_new_scope || recently_seen_extern)
                    {
                        recently_seen_new_scope = false;
                        scopes.push(scope);
                        scope = 0;
                    }
                    else
                    {
                        ++scope;
                    }
                    in_initialization_list = false;
                    recently_seen_paren = false;
                    recently_seen_class_keyword = false;
                    recently_seen_extern = false;
                    break;
                case '}':
                    out << "<b>}</b>";
                    if (scope > 0)
                    {
                        --scope;
                    }
                    else if (scopes.size())
                    {
                        scopes.pop(scope);
                    }
                    recently_seen_paren = false;
                    break;

                case ':':
                    out << ':';
                    if (recently_seen_paren && scope == 0 &&
                        recently_seen_preprocessor == false)
                    {
                        in_initialization_list = true;
                    }
                    recently_seen_paren = false;
                    break;

                case ';':
                    out << ';';
                    recently_seen_new_scope = false;
                    recently_seen_paren = false;
                    recently_seen_extern = false;
                    break;

                case ')':
                    out << ')';
                    recently_seen_paren = true;
                    recently_seen_new_scope = false;
                    --paren_count;
                    break;

                case '(':
                    out << '(';
                    recently_seen_paren = false;
                    ++paren_count;
                    break;

                case '>':
                    recently_seen_include = false;
                    out << "&gt;";
                    recently_seen_paren = true;
                    break;

                case '<':
                    out << "&lt;";
                    recently_seen_paren = true;
                    break;

                case '&':
                    out << "&amp;";
                    recently_seen_paren = true;
                    break;

                default:
                    out << token;
                    recently_seen_paren = false;
                    if (token == "&gt;")
                        recently_seen_include = false;
                    break;

                } // switch (token[0])
                break;

            } // switch (type)

            t.get_token(type,token);
        } // while (type != tok::END_OF_FILE)

        out << "</font></pre></body></html>";
        if (!out)
            throw std::ios::failure("error occurred in cpp_pretty_printer_kernel_2::print");
    }

// ----------------------------------------------------------------------------------------

    template <
        typename stack,
        typename tok
        >
    void cpp_pretty_printer_kernel_2<stack,tok>::
    print_and_number (
        std::istream& in,
        std::ostream& out,
        const std::string& title
    ) const
    {
        using namespace std;
        ostringstream sout;
        print(in,sout,title);
        istringstream sin(sout.str());
        number(sin,out);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // private member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename stack,
        typename tok
        >
    void cpp_pretty_printer_kernel_2<stack,tok>::
    number (
        std::istream& in,
        std::ostream& out
    ) const
    {
        if (!out)
            throw std::ios::failure("error occurred in cpp_pretty_printer_kernel_2::number");

        std::string space = "&nbsp;&nbsp;&nbsp;";
        std::ios::int_type ch;
        unsigned long count = 1;
        while ((ch=in.get()) != EOF)
        {
            if (ch != '\n')
            {
                out << (char)ch;
            }
            else
            {
                out << "\n<i><font face='Courier New'>" << count << " </font></i> " + space;
                ++count;
                if (count == 10)
                    space = "&nbsp;&nbsp;";
                if (count == 100)
                    space = "&nbsp;";
                if (count == 1000)
                    space = "";
            }
        }
        if (!out)
            throw std::ios::failure("error occurred in cpp_pretty_printer_kernel_2::number");
    }

// ----------------------------------------------------------------------------------------

    template <
        typename stack,
        typename tok
        >
    const std::string cpp_pretty_printer_kernel_2<stack,tok>::
    htmlify (
        const std::string& str
    ) const
    {
        std::string::size_type i;
        std::string temp;
        for (i = 0; i < str.size(); ++i)
        {
            if (str[i] == '<')
                temp += "&lt;";
            else if (str[i] == '>')
                temp += "&gt;";
            else if (str[i] == '&')
                temp += "&amp;";
            else
                temp += str[i];
        }
        return temp;
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_CPP_PRETTY_PRINTER_KERNEl_2_


dlib C++ Library - cpp_tokenizer_kernel_1.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_CPP_TOKENIZER_KERNEl_1_
#define DLIB_CPP_TOKENIZER_KERNEl_1_

#include <string>
#include <iostream>
#include "cpp_tokenizer_kernel_abstract.h"
#include "../algs.h"

namespace dlib
{

    namespace cpp_tok_kernel_1_helper
    {
        struct token_text_pair
        {
            std::string token;
            int type;
        };

    }

    template <
        typename tok,
        typename queue,
        typename set
        >
    class cpp_tokenizer_kernel_1
    {
        /*!
            REQUIREMENTS ON tok
                tok must be an implementation of tokenizer/tokenizer_kernel_abstract.h

            REQUIREMENTS ON queue
                queue must be an implementation of queue/queue_kernel_abstract.h
                and must have T==cpp_tok_kernel_1_helper::token_text_pair

            REQUIREMENTS ON set
                set must be an implemention of set/set_kernel_abstract.h or
                hash_set/hash_set_kernel_abstract.h and must have T==std::string.

            INITIAL VALUE
                - keywords == a set of all the C++ keywords
                - tokenizer.stream_is_set() == false
                - buffer.size() == 0
                - tokenizer.get_identifier_head() == "$_" + tokenizer.lowercase_letters() +
                  tokenizer.uppercase_letters()
                - tokenizer.get_identifier_body() == "$_" + tokenizer.lowercase_letters() +
                  tokenizer.uppercase_letters() + tokenizer.numbers()
                - have_peeked == false

            CONVENTION
                - tokenizer.stream_is_set() == stream_is_set()
                - tokenizer.get_stream() == get_stream()
                - keywords == a set of all the C++ keywords

                - tokenizer.get_identifier_head() == "$_" + tokenizer.lowercase_letters() +
                  tokenizer.uppercase_letters()
                - tokenizer.get_identifier_body() == "$_" + tokenizer.lowercase_letters() +
                  tokenizer.uppercase_letters() + tokenizer.numbers()

                - buffer == a queue of tokens.  This is where we put tokens
                  we gathered early due to looking ahead.

                - if (have_peeked) then
                    - next_token == the next token to be returned from get_token()
                    - next_type == the type of token in peek_token
      !*/

        typedef cpp_tok_kernel_1_helper::token_text_pair token_text_pair;

    public:

        enum
        {
            END_OF_FILE,
            KEYWORD,
            COMMENT,
            SINGLE_QUOTED_TEXT,
            DOUBLE_QUOTED_TEXT,
            IDENTIFIER,
            OTHER,
            NUMBER,
            WHITE_SPACE
        };

        cpp_tokenizer_kernel_1 (
        );

        virtual ~cpp_tokenizer_kernel_1 (
        );

        void clear(
        );

        void set_stream (
            std::istream& in
        );

        bool stream_is_set (
        ) const;

        std::istream& get_stream (
        ) const;

        void get_token (
            int& type,
            std::string& token
        );

        int peek_type (
        ) const;

        const std::string& peek_token (
        ) const;

        void swap (
            cpp_tokenizer_kernel_1<tok,queue,set>& item
        );

    private:

        void buffer_token(
            int type,
            const std::string& token
        )
        /*!
            ensures
                - stores the token and its type into buffer
        !*/
        {
            token_text_pair temp;
            temp.token = token;
            temp.type = type;
            buffer.enqueue(temp);
        }

        void buffer_token(
            int type,
            char token
        )
        /*!
            ensures
                - stores the token and its type into buffer
        !*/
        {
            token_text_pair temp;
            temp.token = token;
            temp.type = type;
            buffer.enqueue(temp);
        }

        // restricted functions
        cpp_tokenizer_kernel_1(const cpp_tokenizer_kernel_1<tok,queue,set>&);        // copy constructor
        cpp_tokenizer_kernel_1<tok,queue,set>& operator=(const cpp_tokenizer_kernel_1<tok,queue,set>&);    // assignment operator

        // data members
        set keywords;
        queue buffer;
        tok tokenizer;

        mutable std::string next_token;
        mutable int next_type;
        mutable bool have_peeked;

    };

    template <
        typename tok,
        typename queue,
        typename set
        >
    inline void swap (
        cpp_tokenizer_kernel_1<tok,queue,set>& a,
        cpp_tokenizer_kernel_1<tok,queue,set>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename tok,
        typename queue,
        typename set
        >
    cpp_tokenizer_kernel_1<tok,queue,set>::
    cpp_tokenizer_kernel_1(
    ) :
        have_peeked(false)
    {
        // add C++ keywords to keywords
        std::string temp;
        temp = "#include";              keywords.add(temp);
        temp = "__asm";                 keywords.add(temp);
        temp = "_asm";                  keywords.add(temp);
        temp = "if";                    keywords.add(temp);
        temp = "int";                   keywords.add(temp);
        temp = "else";                  keywords.add(temp);
        temp = "template";              keywords.add(temp);
        temp = "void";                  keywords.add(temp);
        temp = "false";                 keywords.add(temp);
        temp = "class";                 keywords.add(temp);
        temp = "public";                keywords.add(temp);
        temp = "while";                 keywords.add(temp);
        temp = "bool";                  keywords.add(temp);
        temp = "new";                   keywords.add(temp);
        temp = "delete";                keywords.add(temp);
        temp = "true";                  keywords.add(temp);
        temp = "typedef";               keywords.add(temp);
        temp = "const";                 keywords.add(temp);
        temp = "virtual";               keywords.add(temp);
        temp = "inline";                keywords.add(temp);
        temp = "for";                   keywords.add(temp);
        temp = "break";                 keywords.add(temp);
        temp = "struct";                keywords.add(temp);
        temp = "float";                 keywords.add(temp);
        temp = "case";                  keywords.add(temp);
        temp = "enum";                  keywords.add(temp);
        temp = "this";                  keywords.add(temp);
        temp = "typeid";                keywords.add(temp);
        temp = "double";                keywords.add(temp);
        temp = "char";                  keywords.add(temp);
        temp = "typename";              keywords.add(temp);
        temp = "signed";                keywords.add(temp);
        temp = "friend";                keywords.add(temp);
        temp = "wint_t";                keywords.add(temp);
        temp = "default";               keywords.add(temp);
        temp = "asm";                   keywords.add(temp);
        temp = "reinterpret_cast";      keywords.add(temp);
        temp = "#define";               keywords.add(temp);
        temp = "do";                    keywords.add(temp);
        temp = "continue";              keywords.add(temp);
        temp = "auto";                  keywords.add(temp);
        temp = "unsigned";              keywords.add(temp);
        temp = "size_t";                keywords.add(temp);
        temp = "#undef";                keywords.add(temp);
        temp = "#pragma";               keywords.add(temp);
        temp = "namespace";             keywords.add(temp);
        temp = "private";               keywords.add(temp);
        temp = "#endif";                keywords.add(temp);
        temp = "catch";                 keywords.add(temp);
        temp = "#else";                 keywords.add(temp);
        temp = "register";              keywords.add(temp);
        temp = "volatile";              keywords.add(temp);
        temp = "const_cast";            keywords.add(temp);
        temp = "#end";                  keywords.add(temp);
        temp = "mutable";               keywords.add(temp);
        temp = "static_cast";           keywords.add(temp);
        temp = "wchar_t";               keywords.add(temp);
        temp = "#if";                   keywords.add(temp);
        temp = "protected";             keywords.add(temp);
        temp = "throw";                 keywords.add(temp);
        temp = "using";                 keywords.add(temp);
        temp = "dynamic_cast";          keywords.add(temp);
        temp = "#ifdef";                keywords.add(temp);
        temp = "return";                keywords.add(temp);
        temp = "short";                 keywords.add(temp);
        temp = "#error";                keywords.add(temp);
        temp = "#line";                 keywords.add(temp);
        temp = "explicit";              keywords.add(temp);
        temp = "union";                 keywords.add(temp);
        temp = "#ifndef";               keywords.add(temp);
        temp = "try";                   keywords.add(temp);
        temp = "sizeof";                keywords.add(temp);
        temp = "goto";                  keywords.add(temp);
        temp = "long";                  keywords.add(temp);
        temp = "#elif";                 keywords.add(temp);
        temp = "static";                keywords.add(temp);
        temp = "operator";              keywords.add(temp);
        temp = "switch";                keywords.add(temp);
        temp = "extern";                keywords.add(temp);

        // set the tokenizer's IDENTIFIER token for C++ identifiers
        tokenizer.set_identifier_token(
            "$_" + tokenizer.lowercase_letters() + tokenizer.uppercase_letters(),
            "$_" + tokenizer.lowercase_letters() + tokenizer.uppercase_letters() +
            tokenizer.numbers()
            );
    }

// ----------------------------------------------------------------------------------------

    template <
        typename tok,
        typename queue,
        typename set
        >
    cpp_tokenizer_kernel_1<tok,queue,set>::
    ~cpp_tokenizer_kernel_1 (
    )
    {
    }

// ----------------------------------------------------------------------------------------

    template <
        typename tok,
        typename queue,
        typename set
        >
    void cpp_tokenizer_kernel_1<tok,queue,set>::
    clear(
    )
    {
        tokenizer.clear();
        buffer.clear();
        have_peeked = false;

        // set the tokenizer's IDENTIFIER token for C++ identifiers
        tokenizer.set_identifier_token(
            "$_" + tokenizer.lowercase_letters() + tokenizer.uppercase_letters(),
            "$_" + tokenizer.lowercase_letters() + tokenizer.uppercase_letters() +
            tokenizer.numbers()
            );
    }

// ----------------------------------------------------------------------------------------

    template <
        typename tok,
        typename queue,
        typename set
        >
    void cpp_tokenizer_kernel_1<tok,queue,set>::
    set_stream (
        std::istream& in
    )
    {
        tokenizer.set_stream(in);
        buffer.clear();
        have_peeked = false;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename tok,
        typename queue,
        typename set
        >
    bool cpp_tokenizer_kernel_1<tok,queue,set>::
    stream_is_set (
    ) const
    {
        return tokenizer.stream_is_set();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename tok,
        typename queue,
        typename set
        >
    std::istream& cpp_tokenizer_kernel_1<tok,queue,set>::
    get_stream (
    ) const
    {
        return tokenizer.get_stream();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename tok,
        typename queue,
        typename set
        >
    void cpp_tokenizer_kernel_1<tok,queue,set>::
    get_token (
        int& type,
        std::string& token
    )
    {
        using namespace std;

        if (!have_peeked)
        {

            if (buffer.size() > 0)
            {
                // just return what is in the buffer
                token_text_pair temp;
                buffer.dequeue(temp);
                type = temp.type;
                token = temp.token;
                return;
            }

            tokenizer.get_token(type,token);

            switch (type)
            {
            case tok::END_OF_FILE:
                {
                    type = END_OF_FILE;
                } break;

            case tok::END_OF_LINE:
            case tok::WHITE_SPACE:
                {
                    type = tokenizer.peek_type();
                    if (type == tok::END_OF_LINE || type == tok::WHITE_SPACE)
                    {
                        std::string temp;
                        do
                        {
                            tokenizer.get_token(type,temp);
                            token += temp;
                            type = tokenizer.peek_type();
                        }while (type == tok::END_OF_LINE || type == tok::WHITE_SPACE);
                    }
                    type = WHITE_SPACE;

                } break;

            case tok::NUMBER:
                {
                    // this could be a hex number such as 0xa33.  we should check for this.
                    if (tokenizer.peek_type() == tok::IDENTIFIER && token == "0" &&
                        (tokenizer.peek_token()[0] == 'x' || tokenizer.peek_token()[0] == 'X'))
                    {
                        // this is a hex number so accumulate all the numbers and identifiers that follow
                        // because they have to be part of the number
                        std::string temp;
                        tokenizer.get_token(type,temp);
                        token = "0" + temp;

                        // get the rest of the hex number
                        while (tokenizer.peek_type() == tok::IDENTIFIER ||
                               tokenizer.peek_type() == tok::NUMBER
                               )
                        {
                            tokenizer.get_token(type,temp);
                            token += temp;
                        }

                    }
                    // or this could be a floating point value or something with an 'e' or 'E' in it.
                    else if ((tokenizer.peek_type() == tok::CHAR && tokenizer.peek_token()[0] == '.') ||
                             (tokenizer.peek_type() == tok::IDENTIFIER && std::tolower(tokenizer.peek_token()[0]) == 'e'))
                    {
                        std::string temp;
                        tokenizer.get_token(type,temp);
                        token += temp;
                        // now get the rest of the floating point value
                        while (tokenizer.peek_type() == tok::IDENTIFIER ||
                               tokenizer.peek_type() == tok::NUMBER
                               )
                        {
                            tokenizer.get_token(type,temp);
                            token += temp;
                        }
                    }
                    type = NUMBER;

                } break;

            case tok::IDENTIFIER:
                {
                    if (keywords.is_member(token))
                    {
                        type = KEYWORD;
                    }
                    else
                    {
                        type = IDENTIFIER;
                    }
                } break;

            case tok::CHAR:
                type = OTHER;
                switch (token[0])
                {
                case '#':
                    {
                        // this might be a preprocessor keyword so we should check the
                        // next token
                        if (tokenizer.peek_type() == tok::IDENTIFIER &&
                            keywords.is_member('#'+tokenizer.peek_token()))
                        {
                            tokenizer.get_token(type,token);
                            token = '#' + token;
                            type = KEYWORD;
                        }
                        else
                        {
                            token = '#';
                            type = OTHER;
                        }
                    }
                    break;

                case '"':
                    {
                        string temp;
                        tokenizer.get_token(type,token);
                        while (type != tok::END_OF_FILE)
                        {
                            // if this is the end of the quoted string
                            if (type == tok::CHAR && token[0] == '"' &&
                                (temp.size() == 0 || temp[temp.size()-1] != '\\' ||
                                (temp.size() > 1 && temp[temp.size()-2] == '\\') ))
                            {
                                buffer_token(DOUBLE_QUOTED_TEXT,temp);
                                buffer_token(OTHER,"\"");
                                break;
                            }
                            else
                            {
                                temp += token;
                            }
                            tokenizer.get_token(type,token);
                        }

                        type = OTHER;
                        token = '"';
                    } break;

                case '\'':
                    {
                        string temp;
                        tokenizer.get_token(type,token);
                        if (type == tok::CHAR && token[0] == '\\')
                        {
                            temp += '\\';
                            tokenizer.get_token(type,token);
                        }
                        temp += token;
                        buffer_token(SINGLE_QUOTED_TEXT,temp);

                        // The next character should be a ' so take it out and put it in
                        // the buffer.
                        tokenizer.get_token(type,token);
                        buffer_token(OTHER,token);

                        type = OTHER;
                        token = '\'';
                    } break;

                case '/':
                    {
                        // look ahead to see if this is the start of a comment
                        if (tokenizer.peek_type() == tok::CHAR)
                        {
                            if (tokenizer.peek_token()[0] == '/')
                            {
                                tokenizer.get_token(type,token);
                                // this is the start of a line comment
                                token = "//";
                                string temp;
                                tokenizer.get_token(type,temp);
                                while (type != tok::END_OF_FILE)
                                {
                                    // if this is the end of the comment
                                    if (type == tok::END_OF_LINE &&
                                        token[token.size()-1] != '\\' )
                                    {
                                        token += '\n';
                                        break;
                                    }
                                    else
                                    {
                                        token += temp;
                                    }
                                    tokenizer.get_token(type,temp);
                                }
                                type = COMMENT;

                            }
                            else if (tokenizer.peek_token()[0] == '*')
                            {
                                tokenizer.get_token(type,token);
                                // this is the start of a block comment
                                token = "/*";
                                string temp;
                                tokenizer.get_token(type,temp);
                                while (type != tok::END_OF_FILE)
                                {
                                    // if this is the end of the comment
                                    if (type == tok::CHAR && temp[0] == '/' &&
                                        token[token.size()-1] == '*')
                                    {
                                        token += '/';
                                        break;
                                    }
                                    else
                                    {
                                        token += temp;
                                    }
                                    tokenizer.get_token(type,temp);
                                }
                                type = COMMENT;
                            }
                        }
                    } break;

                default:
                    break;
                } // switch (token[0])
            } // switch (type)
        }
        else
        {
            // if we get this far it means we have peeked so we should
            // return the peek data.
            type = next_type;
            token = next_token;
            have_peeked = false;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename tok,
        typename queue,
        typename set
        >
    int cpp_tokenizer_kernel_1<tok,queue,set>::
    peek_type (
    ) const
    {
        const_cast<cpp_tokenizer_kernel_1<tok,queue,set>*>(this)->get_token(next_type,next_token);
        have_peeked = true;
        return next_type;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename tok,
        typename queue,
        typename set
        >
    const std::string& cpp_tokenizer_kernel_1<tok,queue,set>::
    peek_token (
    ) const
    {
        const_cast<cpp_tokenizer_kernel_1<tok,queue,set>*>(this)->get_token(next_type,next_token);
        have_peeked = true;
        return next_token;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename tok,
        typename queue,
        typename set
        >
    void cpp_tokenizer_kernel_1<tok,queue,set>::
    swap (
        cpp_tokenizer_kernel_1& item
    )
    {
        tokenizer.swap(item.tokenizer);
        buffer.swap(item.buffer);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_CPP_TOKENIZER_KERNEl_1_


dlib C++ Library - crc32_kernel_1.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_CRC32_KERNEl_1_
#define DLIB_CRC32_KERNEl_1_

#include "../algs.h"
#include <string>
#include <vector>
#include "crc32_kernel_abstract.h"

namespace dlib
{

    class crc32
    {
        /*!
            INITIAL VALUE
                checksum == 0xFFFFFFFF

            CONVENTION
                get_checksum() == checksum ^ 0xFFFFFFFF
        !*/

    public:

        // this is here for backwards compatibility with older versions of dlib.
        typedef crc32 kernel_1a;

        inline crc32 (
        );

        inline crc32 (
            const std::string& item
        );

        inline crc32 (
            const std::vector<char>& item
        );

        inline virtual ~crc32 (
        );

        inline void clear(
        );

        inline void add (
            unsigned char item
        );

        inline void add (
            const std::string& item
        );

        inline void add (
            const std::vector<char>& item
        );

        inline operator unsigned long (
        ) const { return get_checksum(); }

        inline unsigned long get_checksum (
        ) const;

        inline void swap (
            crc32& item
        );

        inline crc32& operator=(
            const crc32&
        );

    private:

        unsigned long checksum;

        inline unsigned long table (
            unsigned int idx
        ) const
        {
            /*
            // This code generates the crc_table used below.
            unsigned long crc_table[256];
            for (unsigned long i = 0; i < 256; ++i)
            {
                unsigned long temp = i;
                for (unsigned long j = 0; j < 8; ++j)
                {
                    if (temp&1)
                        temp = (temp>>1)^0xedb88320;
                    else
                        temp >>= 1;
                }
                crc_table[i] = temp;
                std::cout << std::hex << crc_table[i] << std::endl;
            }
            */

            const static unsigned long crc_table[256] = {
                0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x76dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
                0xedb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x9b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
                0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
                0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
                0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
                0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
                0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
                0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
                0x76dc4190, 0x1db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x6b6b51f, 0x9fbfe4a5, 0xe8b8d433,
                0x7807c9a2, 0xf00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x86d3d2d, 0x91646c97, 0xe6635c01,
                0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
                0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
                0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
                0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
                0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
                0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
                0xedb88320, 0x9abfb3b6, 0x3b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x4db2615, 0x73dc1683,
                0xe3630b12, 0x94643b84, 0xd6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0xa00ae27, 0x7d079eb1,
                0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
                0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
                0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
                0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
                0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
                0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
                0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x26d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x5005713,
                0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0xcb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0xbdbdf21,
                0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
                0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
                0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
                0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
                0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
                0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
            };

            return crc_table[idx];
        }

    };

    inline void swap (
        crc32& a,
        crc32& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    crc32::
    crc32 (
    )
    {
        checksum = 0xFFFFFFFF;
    }

// ----------------------------------------------------------------------------------------

    crc32::
    crc32 (
        const std::string& item
    )
    {
        checksum = 0xFFFFFFFF;
        add(item);
    }

// ----------------------------------------------------------------------------------------

    crc32::
    crc32 (
        const std::vector<char>& item
    )
    {
        checksum = 0xFFFFFFFF;
        add(item);
    }

// ----------------------------------------------------------------------------------------

    crc32::
    ~crc32 (
    )
    {
    }

// ----------------------------------------------------------------------------------------

    void crc32::
    clear(
    )
    {
        checksum = 0xFFFFFFFF;
    }

// ----------------------------------------------------------------------------------------

    void crc32::
    add (
        unsigned char item
    )
    {
        checksum = (checksum>>8) ^ table((checksum^item) & 0xFF);
    }

// ----------------------------------------------------------------------------------------

    void crc32::
    add (
        const std::string& item
    )
    {
        for (std::string::size_type i = 0; i < item.size(); ++i)
            checksum = (checksum>>8) ^ table((checksum^item[i]) & 0xFF);
    }

// ----------------------------------------------------------------------------------------

    void crc32::
    add (
        const std::vector<char>& item
    )
    {
        for (unsigned long i = 0; i < item.size(); ++i)
            checksum = (checksum>>8) ^ table((checksum^item[i]) & 0xFF);
    }

// ----------------------------------------------------------------------------------------

    unsigned long crc32::
    get_checksum (
    ) const
    {
        return checksum ^ 0xFFFFFFFF;
    }

// ----------------------------------------------------------------------------------------

    void crc32::
    swap (
        crc32& item
    )
    {
        exchange(checksum,item.checksum);
    }

// ----------------------------------------------------------------------------------------

    crc32& crc32::
    operator=(
        const crc32& item
    )
    {
        checksum = item.checksum;
        return *this;
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_CRC32_KERNEl_1_


dlib C++ Library - image_dataset_metadata.cpp

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_IMAGE_DAtASET_METADATA_CPPh_
#define DLIB_IMAGE_DAtASET_METADATA_CPPh_

#include "image_dataset_metadata.h"

#include <fstream>
#include <sstream>
#include "../compress_stream.h"
#include "../base64.h"
#include "../xml_parser.h"
#include "../string.h"

// ----------------------------------------------------------------------------------------

namespace dlib
{
    namespace image_dataset_metadata
    {

    // ------------------------------------------------------------------------------------

        const std::string get_decoded_string();
        void create_image_metadata_stylesheet_file(const std::string& main_filename)
        {
            std::string path;
            std::string::size_type pos = main_filename.find_last_of("/\\");
            if (pos != std::string::npos)
                path = main_filename.substr(0,pos+1);

            std::ofstream fout((path + "image_metadata_stylesheet.xsl").c_str());
            if (!fout)
                throw dlib::error("ERROR: Unable to open image_metadata_stylesheet.xsl for writing.");

            fout << get_decoded_string();

            if (!fout)
                throw dlib::error("ERROR: Unable to write to image_metadata_stylesheet.xsl.");
        }

        void save_image_dataset_metadata (
            const dataset& meta,
            const std::string& filename
        )
        {
            create_image_metadata_stylesheet_file(filename);

            const std::vector<image>& images = meta.images;

            std::ofstream fout(filename.c_str());
            if (!fout)
                throw dlib::error("ERROR: Unable to open " + filename + " for writing.");

            fout << "<?xml version='1.0' encoding='ISO-8859-1'?>\n";
            fout << "<?xml-stylesheet type='text/xsl' href='image_metadata_stylesheet.xsl'?>\n";
            fout << "<dataset>\n";
            fout << "<name>" << meta.name << "</name>\n";
            fout << "<comment>" << meta.comment << "</comment>\n";
            fout << "<images>\n";
            for (unsigned long i = 0; i < images.size(); ++i)
            {
                fout << "  <image file='" << images[i].filename << "'>\n";

                // save all the boxes
                for (unsigned long j = 0; j < images[i].boxes.size(); ++j)
                {
                    const box& b = images[i].boxes[j];
                    fout << "    <box top='" << b.rect.top() << "' "
                                 << "left='" << b.rect.left() << "' "
                                << "width='" << b.rect.width() << "' "
                               << "height='" << b.rect.height() << "'";
                    if (b.difficult)
                        fout << " difficult='" << b.difficult << "'";
                    if (b.truncated)
                        fout << " truncated='" << b.truncated << "'";
                    if (b.occluded)
                        fout << " occluded='" << b.occluded << "'";
                    if (b.ignore)
                        fout << " ignore='" << b.ignore << "'";
                    if (b.angle != 0)
                        fout << " angle='" << b.angle << "'";

                    if (b.has_label() || b.parts.size() != 0)
                    {
                        fout << ">\n";

                        if (b.has_label())
                            fout << "      <label>" << b.label << "</label>\n";

                        // save all the parts
                        std::map<std::string,point>::const_iterator itr;
                        for (itr = b.parts.begin(); itr != b.parts.end(); ++itr)
                        {
                            fout << "      <part name='"<< itr->first << "' x='"<< itr->second.x() <<"' y='"<< itr->second.y() <<"'/>\n";
                        }

                        fout << "    </box>\n";
                    }
                    else
                    {
                        fout << "/>\n";
                    }
                }

                fout << "  </image>\n";

                if (!fout)
                    throw dlib::error("ERROR: Unable to write to " + filename + ".");
            }
            fout << "</images>\n";
            fout << "</dataset>";
        }

    // ------------------------------------------------------------------------------------
    // ------------------------------------------------------------------------------------
    // ------------------------------------------------------------------------------------

        class doc_handler : public document_handler
        {
            std::vector<std::string> ts;
            image temp_image;
            box temp_box;

            dataset& meta;

        public:

            doc_handler(
                dataset& metadata_
            ):
                meta(metadata_)
            {}

            virtual void start_document (
            )
            {
                meta = dataset();
                ts.clear();
                temp_image = image();
                temp_box = box();
            }

            virtual void end_document (
            )
            {
            }

            virtual void start_element (
                const unsigned long line_number,
                const std::string& name,
                const dlib::attribute_list& atts
            )
            {
                try
                {
                    if (ts.size() == 0)
                    {
                        if (name != "dataset")
                        {
                            std::ostringstream sout;
                            sout << "Invalid XML document.  Root tag must be <dataset>.  Found <" << name << "> instead.";
                            throw dlib::error(sout.str());
                        }
                        else
                        {
                            ts.push_back(name);
                            return;
                        }
                    }

                    if (name == "box")
                    {
                        if (atts.is_in_list("top")) temp_box.rect.top() = sa = atts["top"];
                        else throw dlib::error("<box> missing required attribute 'top'");

                        if (atts.is_in_list("left")) temp_box.rect.left() = sa = atts["left"];
                        else throw dlib::error("<box> missing required attribute 'left'");

                        if (atts.is_in_list("width")) temp_box.rect.right() = sa = atts["width"];
                        else throw dlib::error("<box> missing required attribute 'width'");

                        if (atts.is_in_list("height")) temp_box.rect.bottom() = sa = atts["height"];
                        else throw dlib::error("<box> missing required attribute 'height'");

                        if (atts.is_in_list("difficult")) temp_box.difficult = sa = atts["difficult"];
                        if (atts.is_in_list("truncated")) temp_box.truncated = sa = atts["truncated"];
                        if (atts.is_in_list("occluded"))  temp_box.occluded  = sa = atts["occluded"];
                        if (atts.is_in_list("ignore"))  temp_box.ignore  = sa = atts["ignore"];
                        if (atts.is_in_list("angle"))  temp_box.angle  = sa = atts["angle"];

                        temp_box.rect.bottom() += temp_box.rect.top()-1;
                        temp_box.rect.right() += temp_box.rect.left()-1;
                    }
                    else if (name == "part" && ts.back() == "box")
                    {
                        point temp;
                        if (atts.is_in_list("x")) temp.x() = sa = atts["x"];
                        else throw dlib::error("<part> missing required attribute 'x'");

                        if (atts.is_in_list("y")) temp.y() = sa = atts["y"];
                        else throw dlib::error("<part> missing required attribute 'y'");

                        if (atts.is_in_list("name"))
                        {
                            if (temp_box.parts.count(atts["name"])==0)
                            {
                                temp_box.parts[atts["name"]] = temp;
                            }
                            else
                            {
                                throw dlib::error("<part> with name '" + atts["name"] + "' is defined more than one time in a single box.");
                            }
                        }
                        else
                        {
                            throw dlib::error("<part> missing required attribute 'name'");
                        }
                    }
                    else if (name == "image")
                    {
                        temp_image.boxes.clear();

                        if (atts.is_in_list("file")) temp_image.filename = atts["file"];
                        else throw dlib::error("<image> missing required attribute 'file'");
                    }

                    ts.push_back(name);
                }
                catch (error& e)
                {
                    throw dlib::error("Error on line " + cast_to_string(line_number) + ": " + e.what());
                }
            }

            virtual void end_element (
                const unsigned long ,
                const std::string& name
            )
            {
                ts.pop_back();
                if (ts.size() == 0)
                    return;

                if (name == "box" && ts.back() == "image")
                {
                    temp_image.boxes.push_back(temp_box);
                    temp_box = box();
                }
                else if (name == "image" && ts.back() == "images")
                {
                    meta.images.push_back(temp_image);
                    temp_image = image();
                }
            }

            virtual void characters (
                const std::string& data
            )
            {
                if (ts.size() == 2 && ts[1] == "name")
                {
                    meta.name = trim(data);
                }
                else if (ts.size() == 2 && ts[1] == "comment")
                {
                    meta.comment = trim(data);
                }
                else if (ts.size() >= 2 && ts[ts.size()-1] == "label" &&
                                           ts[ts.size()-2] == "box")
                {
                    temp_box.label = trim(data);
                }
            }

            virtual void processing_instruction (
                const unsigned long ,
                const std::string& ,
                const std::string&
            )
            {
            }
        };

    // ----------------------------------------------------------------------------------------

        class xml_error_handler : public error_handler
        {
        public:
            virtual void error (
                const unsigned long
            ) { }

            virtual void fatal_error (
                const unsigned long line_number
            )
            {
                std::ostringstream sout;
                sout << "There is a fatal error on line " << line_number << " so parsing will now halt.";
                throw dlib::error(sout.str());
            }
        };

    // ------------------------------------------------------------------------------------

        void load_image_dataset_metadata (
            dataset& meta,
            const std::string& filename
        )
        {
            xml_error_handler eh;
            doc_handler dh(meta);

            std::ifstream fin(filename.c_str());
            if (!fin)
                throw dlib::error("ERROR: unable to open " + filename + " for reading.");

            xml_parser parser;
            parser.add_document_handler(dh);
            parser.add_error_handler(eh);
            parser.parse(fin);
        }

    // ------------------------------------------------------------------------------------
    // ------------------------------------------------------------------------------------
    // ------------------------------------------------------------------------------------

        // This function returns the contents of the file 'images.xsl'
        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 'image_metadata_stylesheet.xsl' we want to decode and return.
            sout << "PFWfgmWfCHr1DkV63lbjjeY2dCc2FbHDOVh0Kd7dkvaOfRYrOG24f0x77/5iMVq8FtE3UBxtGwSd";
            sout << "1ZHOHRSHgieNoeBv8ssJQ75RRxYtFKRY3OTPX5eKQoCN9jUaUnHnR4QZtEHgmKqXSs50Yrdd+2Ah";
            sout << "gNyarPZCiR6nvqNvCjtP2MP5FxleqNf8Fylatm2KdsXmrv5K87LYVN7i7JMkmZ++cTXYSOxDmxZi";
            sout << "OiCH8funXUdF9apDW547gCjz9HOQUI6dkz5dYUeFjfp6dFugpnaJyyprFLKq048Qk7+QiL4CNF/G";
            sout << "7e0VpBw8dMpiyRNi2fSQGSZGfIAUQKKT6+rPwQoRH2spdjsdXVWj4XQAqBX87nmqMnqjMhn/Vd1s";
            sout << "W5aoC0drwRGu3Xe3gn9vBL8hBkRXcJvEy6q/lb9bYnsLemhE5Zp/+nTmTBjfT9UFYLcsmgsjC+4n";
            sout << "Bq6h9QlpuyMYqJ8RvW8pp3mFlvXc3Yg+18t5F0hSMQfaIFYAuDPU2lVzPpY+ba0B39iu9IrPCLsS";
            sout << "+tUtSNSmQ74CtzZgKKjkTMA3nwYP2SDmZE3firq42pihT7hdU5vYkes69K8AQl8WZyLPpMww+r0z";
            sout << "+veEHPlAuxF7kL3ZvVjdB+xABwwqDe0kSRHRZINYdUfJwJdfYLyDnYoMjj6afqIJZ7QOBPZ42tV5";
            sout << "3hYOQTFwTNovOastzJJXQe1kxPg1AQ8ynmfjjJZqD0xKedlyeJybP919mVAA23UryHsq9TVlabou";
            sout << "qNl3xZW/mKKktvVsd/nuH62HIv/kgomyhaEUY5HgupupBUbQFZfyljZ5bl3g3V3Y1400Z1xTM/LL";
            sout << "LJpeLdlqoGzIe/19vAN1zUUVId9F/OLNUl3Zoar63yZERSJHcsuq/Pasisp0HIGi7rfI9EIQF7C/";
            sout << "IhLKLZsJ+LOycreQGOJALZIEZHOqxYLSXG0qaPM5bQL/MQJ2OZfwEhQgYOrjaM7oPOHHEfTq5kcO";
            sout << "daMwzefKfxrF2GXbUs0bYsEXsIGwENIUKMliFaAI4qKLxxb94oc+O3BRjWueZjZty2zKawQyTHNd";
            sout << "ltFJBUzfffdZN9Wq4zbPzntkM3U6Ys4LRztx5M15dtbhFeKx5rAf2tPXT6wU01hx7EJxBJzpvoDE";
            sout << "YwEoYVDSYulRKpgk82cHFzzUDgWXbl4paFSe1L1w8r9KHr67SYJDTUG86Lrm6LJ0rw73Xp0NAFcU";
            sout << "MKpiG9g1cHW74HYbUb/yAbtVWt40eB7M637umdo2jWz/r/vP5WnfSMXEbkyWebsa1fFceg/TLWy6";
            sout << "E8OTc4XKB48h1oFIlGagOiprxho3+F3TIcxDSwA=";

            // 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();
        }

    }
}

// ----------------------------------------------------------------------------------------

#endif // DLIB_IMAGE_DAtASET_METADATA_CPPh_


dlib C++ Library - dir_nav_extensions.cpp

// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_DIR_NAV_EXTENSIONs_CPP_
#define DLIB_DIR_NAV_EXTENSIONs_CPP_

#include "dir_nav_extensions.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    namespace implementation_details
    {
        void get_all_sub_dirs (
            const directory& top_of_tree,
            unsigned long max_depth,
            std::vector<directory>& result,
            std::vector<directory>& temp
        )
        {
            if (max_depth > 0)
            {
                top_of_tree.get_dirs(temp);
                const unsigned long start = result.size();
                result.insert(result.end(), temp.begin(), temp.end());
                const unsigned long end = start + temp.size();

                for (unsigned long i = start; i < end; ++i)
                {
                    get_all_sub_dirs(result[i], max_depth-1, result, temp);
                }
            }
        }
    }

// ----------------------------------------------------------------------------------------

    bool file_exists (
        const std::string& filename
    )
    {
        try
        {
            dlib::file temp(filename);
            return true;
        }
        catch (file::file_not_found&)
        {
            return false;
        }
    }

// ----------------------------------------------------------------------------------------

    directory get_parent_directory (
        const directory& dir
    )
    {
        return dir.get_parent();
    }

// ----------------------------------------------------------------------------------------

    directory get_parent_directory (
        const file& f
    )
    {
        if (f.full_name().size() == 0)
            return directory();

        std::string::size_type pos = f.full_name().find_last_of("\\/");

        if (pos == std::string::npos)
            return directory();

        return directory(f.full_name().substr(0,pos));
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_DIR_NAV_EXTENSIONs_CPP_


dlib C++ Library - dir_nav_extensions.h

// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_DIR_NAV_EXTENSIONs_H_
#define DLIB_DIR_NAV_EXTENSIONs_H_

#include <string>
#include <vector>
#include <algorithm>
#include "dir_nav_extensions_abstract.h"
#include "../dir_nav.h"
#include "../string.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    bool file_exists (
        const std::string& filename
    );

// ----------------------------------------------------------------------------------------

    namespace implementation_details
    {
        void get_all_sub_dirs (
            const directory& top_of_tree,
            unsigned long max_depth,
            std::vector<directory>& result,
            std::vector<directory>& temp
        );
    }

// ----------------------------------------------------------------------------------------

    template <typename T>
    const std::vector<file> get_files_in_directory_tree (
        const directory& top_of_tree,
        const T& add_file,
        unsigned long max_depth = 30
    )
    {
        std::vector<file> result, temp;
        std::vector<directory> dirs, dirs_temp;
        dirs.push_back(top_of_tree);

        // get all the directories in the tree first
        implementation_details::get_all_sub_dirs(top_of_tree, max_depth, dirs, dirs_temp);

        // now just loop over all the directories and pick out the files we want to keep
        for (unsigned long d = 0; d < dirs.size(); ++d)
        {
            dirs[d].get_files(temp);

            // pick out the members of temp that we should keep
            for (unsigned long i = 0; i < temp.size(); ++i)
            {
                if (add_file(temp[i]))
                    result.push_back(temp[i]);
            }
        }

        return result;
    }

// ----------------------------------------------------------------------------------------

    class match_ending
    {

    public:
        match_ending (
            const std::string& ending_
        ) : ending(ending_) {}

        bool operator() (
            const file& f
        ) const
        {
            // if the ending is bigger than f's name then it obviously doesn't match
            if (ending.size() > f.name().size())
                return false;

            // now check if the actual characters that make up the end of the file name
            // matches what is in ending.
            return std::equal(ending.begin(), ending.end(), f.name().end()-ending.size());
        }

    private:
        std::string ending;
    };

// ----------------------------------------------------------------------------------------

    class match_endings
    {

    public:
        match_endings (
            const std::string& endings_
        )
        {
            const std::vector<std::string>& s = split(endings_);
            for (unsigned long i = 0; i < s.size(); ++i)
            {
                endings.push_back(match_ending(s[i]));
            }
        }

        bool operator() (
            const file& f
        ) const
        {
            for (unsigned long i = 0; i < endings.size(); ++i)
            {
                if (endings[i](f))
                    return true;
            }

            return false;
        }

    private:
        std::vector<match_ending> endings;
    };

// ----------------------------------------------------------------------------------------

    class match_all
    {
    public:
        bool operator() (
            const file&
        ) const { return true; }
    };

// ----------------------------------------------------------------------------------------

    directory get_parent_directory (
        const directory& dir
    );

// ----------------------------------------------------------------------------------------

    directory get_parent_directory (
        const file& f
    );

// ----------------------------------------------------------------------------------------

}

#ifdef NO_MAKEFILE
#include "dir_nav_extensions.cpp"
#endif

#endif // DLIB_DIR_NAV_EXTENSIONs_H_


dlib C++ Library - dir_nav_kernel_1.cpp

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_DIR_NAV_KERNEL_1_CPp_
#define DLIB_DIR_NAV_KERNEL_1_CPp_
#include "../platform.h"

#ifdef WIN32

#include "dir_nav_kernel_1.h"
#include "../string.h"

#ifdef __BORLANDC__
// Apparently the borland compiler doesn't define this.
#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
#endif

namespace dlib
{

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // file object implementation
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    void file::
    init (
        const std::string& name
    )
    {
        using namespace std;

        char buf[3000];
        char* str;
        if (GetFullPathNameA(name.c_str(),sizeof(buf),buf,&str) == 0)
        {
            // the file was not found
            throw file_not_found("Unable to find file " + name);
        }
        state.full_name = buf;

        string::size_type pos = state.full_name.find_last_of(directory::get_separator());
        if (pos == string::npos)
        {
            // no valid full path has no separator characters.
            throw file_not_found("Unable to find file " + name);
        }
        state.name = state.full_name.substr(pos+1);

        // now find the size of this file
        WIN32_FIND_DATAA data;
        HANDLE ffind = FindFirstFileA(state.full_name.c_str(), &data);
        if (ffind == INVALID_HANDLE_VALUE ||
            (data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) != 0)
        {
            throw file_not_found("Unable to find file " + name);
        }
        else
        {
            uint64 temp = data.nFileSizeHigh;
            temp <<= 32;
            temp |= data.nFileSizeLow;
            state.file_size = temp;
            FindClose(ffind);
        }

    }

// ----------------------------------------------------------------------------------------

    bool file::
    operator == (
        const file& rhs
    ) const
    {
        using namespace std;

        if (state.full_name.size() != rhs.state.full_name.size())
            return false;

        // compare the strings but ignore the case because file names
        // are not case sensitive on windows
        return tolower(state.full_name) == tolower(rhs.state.full_name);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // directory object implementation
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    void directory::
    init (
        const std::string& name
    )
    {
        using namespace std;

        char buf[3000];
        char* str;
        if (GetFullPathNameA(name.c_str(),sizeof(buf),buf,&str) == 0)
        {
            // the directory was not found
            throw dir_not_found("Unable to find directory " + name);
        }
        state.full_name = buf;

        const char sep = get_separator();
        if (is_root_path(state.full_name) == false)
        {
            // ensure that thre is not a trialing separator
            if (state.full_name[state.full_name.size()-1] == sep)
                state.full_name.erase(state.full_name.size()-1);

            // pick out the directory name
            string::size_type pos = state.full_name.find_last_of(sep);
            state.name = state.full_name.substr(pos+1);
        }
        else
        {
            // ensure that there is a trailing separator
            if (state.full_name[state.full_name.size()-1] != sep)
                state.full_name += sep;
        }

        // now check that this is actually a valid directory
        DWORD attribs = GetFileAttributesA(state.full_name.c_str());
        if (attribs == INVALID_FILE_ATTRIBUTES ||
            (attribs&FILE_ATTRIBUTE_DIRECTORY) == 0)
        {
            // the directory was not found
            throw dir_not_found("Unable to find directory " + name);
        }

    }

// ----------------------------------------------------------------------------------------

    char directory::
    get_separator (
    )
    {
        return '\\';
    }

// ----------------------------------------------------------------------------------------

    bool directory::
    operator == (
        const directory& rhs
    ) const
    {
        using namespace std;

        if (state.full_name.size() != rhs.state.full_name.size())
            return false;

        // compare the strings but ignore the case because file names
        // are not case sensitive on windows
        return tolower(state.full_name) == tolower(rhs.state.full_name);
    }

// ----------------------------------------------------------------------------------------

    const directory directory::
    get_parent (
    ) const
    {
        using namespace std;
        // if *this is the root then just return *this
        if (is_root())
        {
            return *this;
        }
        else
        {
            directory temp;

            const char sep = get_separator();

            string::size_type pos = state.full_name.find_last_of(sep);
            temp.state.full_name = state.full_name.substr(0,pos);

            if ( is_root_path(temp.state.full_name))
            {
                temp.state.full_name += sep;
            }
            else
            {
                pos = temp.state.full_name.find_last_of(sep);
                if (pos != string::npos)
                {
                    temp.state.name = temp.state.full_name.substr(pos+1);
                }
                else
                {
                    temp.state.full_name += sep;
                }
            }
            return temp;
        }
    }

// ----------------------------------------------------------------------------------------

    bool directory::
    is_root_path (
        const std::string& path
    ) const
    {
        using namespace std;
        const char sep = get_separator();
        bool root_path = false;
        if (path.size() > 2 && path[0] == sep && path[1] == sep)
        {
            // in this case this is a windows share path
            string::size_type pos = path.find_first_of(sep,2);
            if (pos != string::npos)
            {
                pos = path.find_first_of(sep,pos+1);

                if (pos == string::npos && path[path.size()-1] != sep)
                    root_path = true;
                else if (pos == path.size()-1)
                    root_path = true;
            }

        }
        else if ( (path.size() == 2 || path.size() == 3) && path[1] == ':')
        {
            // if this is a valid windows path then it must be a root path
            root_path = true;
        }

        return root_path;
    }

// ----------------------------------------------------------------------------------------

}

#endif // WIN32

#endif // DLIB_DIR_NAV_KERNEL_1_CPp_


dlib C++ Library - dir_nav_kernel_1.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_DIR_NAV_KERNEl_1_
#define DLIB_DIR_NAV_KERNEl_1_

#ifdef DLIB_ISO_CPP_ONLY
#error "DLIB_ISO_CPP_ONLY is defined so you can't use this OS dependent code.  Turn DLIB_ISO_CPP_ONLY off if you want to use it."
#endif

#include "../platform.h"

#include "dir_nav_kernel_abstract.h"
#include <string>
#include "../uintn.h"
#include "../algs.h"

#include "../windows_magic.h"
#include <windows.h>
#include <vector>
#include "../stl_checked.h"
#include "../enable_if.h"
#include "../queue.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // file object
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class file
    {
        /*!
            INITIAL VALUES
                state.name        == name()
                state.full_name   == full_name()
                state.file_size   == size()

            CONVENTION
                state.name        == name()
                state.full_name   == full_name()
                state.file_size   == size()

        !*/

        friend class directory;

        struct data
        {
            uint64 file_size;
            std::string name;
            std::string full_name;
        };

        void init ( const std::string& name);

    public:

        struct private_constructor{};
        inline file (
            const std::string& name,
            const std::string& full_name,
            const uint64 file_size,
            private_constructor
        )
        {
            state.file_size = file_size;
            state.name = name;
            state.full_name = full_name;
        }

        class file_not_found : public error {
            public: file_not_found(const std::string& s): error(s){}
        };

        inline file (
        )
        {
            state.file_size = 0;
        }

        file (
            const std::string& name
        ) { init(name); }

        file (
            const char* name
        ) { init(name); }

        inline const std::string& name (
        ) const { return state.name; }

        inline  const std::string& full_name (
        ) const { return state.full_name; }

        operator std::string (
        ) const { return full_name(); }

        inline uint64 size (
        ) const { return state.file_size; }

        bool operator == (
            const file& rhs
        ) const;

        bool operator != (
            const file& rhs
        ) const { return !(*this == rhs); }

        inline bool operator < (
            const file& item
        ) const { return full_name() < item.full_name(); }

        inline void swap (
            file& item
        )
        {
            exchange(state,item.state);
        }

    private:

        data state;

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // directory object
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class directory
    {
        /*!
            INITIAL VALUES
                state.name        == name()
                state.full_name   == full_name()

            CONVENTION
                state.name        == name()
                state.full_name   == full_name()
                is_root()          == state.name.size() == 0

        !*/

        void init (const std::string& name);

    public:

        struct data
        {
            std::string name;
            std::string full_name;
        };

        /*
            The reason we don't just make this constructor actually
            private is because doing it this way avoids a bug that
            sometimes occurs in visual studio 7.1.  The bug has
            something to do with templated friend functions
            such as the get_filesystem_roots() function below if
            it was declared as a friend template of this class.
        */
        struct private_constructor{};
        inline directory (
            const std::string& name,
            const std::string& full_name,
            private_constructor
        )
        {
            state.name = name;
            state.full_name = full_name;
        }

        class dir_not_found : public error {
            public: dir_not_found(const std::string& s):error(s){}
        };
        class listing_error : public error {
            public: listing_error(const std::string& s):error(s){}
        };

        inline directory (
        )
        {
        }

        directory (
            const std::string& name
        ) { init(name); }

        directory (
            const char* name
        ) { init(name); }

        static char get_separator (
        );

        template <
            typename queue_of_files
            >
        void get_files (
            queue_of_files& files
        ) const;

        template <
            typename queue_of_dirs
            >
        void get_dirs (
            queue_of_dirs& dirs
        ) const;

        std::vector<file> get_files (
        ) const
        {
            std::vector<file> temp_vector;
            get_files(temp_vector);
            return temp_vector;
        }

        std::vector<directory> get_dirs (
        ) const
        {
            std::vector<directory> temp_vector;
            get_dirs(temp_vector);
            return temp_vector;
        }

        const directory get_parent (
        ) const;

        inline bool is_root (
        ) const { return state.name.size() == 0; }

        inline const std::string& name (
        ) const { return state.name; }

        inline const std::string& full_name (
        ) const { return state.full_name; }

        operator std::string (
        ) const { return full_name(); }

        bool operator == (
            const directory& rhs
        ) const;

        bool operator != (
            const directory& rhs
        ) const { return !(*this == rhs); }

        inline bool operator < (
            const directory& item
        ) const { return full_name() < item.full_name(); }

        inline void swap (
            directory& item
        )
        {
            exchange(state,item.state);
        }

    private:

        // member data
        data state;

        bool is_root_path (
            const std::string& path
        ) const;
        /*!
            ensures
                - returns true if path is a root path.
                  Note that this function considers root paths that don't
                  have a trailing separator to also be valid.
        !*/

    };

// ----------------------------------------------------------------------------------------

    inline std::ostream& operator<< (
        std::ostream& out,
        const directory& item
    ) { out << (std::string)item; return out; }

    inline std::ostream& operator<< (
        std::ostream& out,
        const file& item
    ) { out << (std::string)item; return out; }

// ----------------------------------------------------------------------------------------

    template <
        typename queue_of_dir
        >
    typename disable_if<is_std_vector<queue_of_dir>,void>::type get_filesystem_roots (
        queue_of_dir& roots
    )
    {
        roots.clear();
        const DWORD mask = GetLogicalDrives();
        DWORD bit = 1;
        char buf[] = "A:\\";

        do
        {
            if (mask & bit)
            {
                directory dir("",buf,directory::private_constructor());
                roots.enqueue(dir);
            }
            bit <<= 1;
            ++buf[0];
        } while (buf[0] != 'Z');
    }

    template <
        typename queue_of_dir
        >
    typename enable_if<is_std_vector<queue_of_dir>,void>::type get_filesystem_roots (
        queue_of_dir& roots
    )
    {
        roots.clear();
        const DWORD mask = GetLogicalDrives();
        DWORD bit = 1;
        char buf[] = "A:\\";

        do
        {
            if (mask & bit)
            {
                directory dir("",buf,directory::private_constructor());
                roots.push_back(dir);
            }
            bit <<= 1;
            ++buf[0];
        } while (buf[0] != 'Z');
    }

// ----------------------------------------------------------------------------------------

    inline void swap (
        file& a,
        file& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------

    inline void swap (
        directory& a,
        directory& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // templated member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename queue_of_files
        >
    typename disable_if<is_std_vector<queue_of_files>,void>::type
    directory_helper_get_files (
        const directory::data& state,
        queue_of_files& files
    )
    {
        using namespace std;
        typedef directory::listing_error listing_error;
        typedef file::private_constructor private_constructor;

        files.clear();
        if (state.full_name.size() == 0)
            throw listing_error("This directory object currently doesn't represent any directory.");

        HANDLE ffind = INVALID_HANDLE_VALUE;
        try
        {
            WIN32_FIND_DATAA data;
            string path = state.full_name;
            // ensure that the path ends with a separator
            if (path[path.size()-1] != directory::get_separator())
                path += directory::get_separator();

            ffind = FindFirstFileA((path+"*").c_str(), &data);
            if (ffind == INVALID_HANDLE_VALUE)
            {
                throw listing_error("Unable to list the contents of " + state.full_name);
            }

            bool no_more_files = false;
            do
            {
                if ((data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) == 0)
                {
                    uint64 file_size = data.nFileSizeHigh;
                    file_size <<= 32;
                    file_size |= data.nFileSizeLow;
                    // this is a file so add it to the queue
                    file temp(data.cFileName,path+data.cFileName,file_size, private_constructor());
                    files.enqueue(temp);
                }

                if (FindNextFileA(ffind,&data) == 0)
                {
                    // an error occurred
                    if ( GetLastError() == ERROR_NO_MORE_FILES)
                    {
                        // there are no more files
                        no_more_files = true;
                    }
                    else
                    {
                        // there was an error
                        throw listing_error("Unable to list the contents of " + state.full_name);
                    }
                }
            } while (no_more_files == false);

            FindClose(ffind);
            ffind = INVALID_HANDLE_VALUE;
        }
        catch (...)
        {
            if (ffind != INVALID_HANDLE_VALUE)
                FindClose(ffind);
            files.clear();
            throw;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename queue_of_files
        >
    typename enable_if<is_std_vector<queue_of_files>,void>::type
    directory_helper_get_files (
        const directory::data& state,
        queue_of_files& files
    )
    {
        queue<file>::kernel_2a temp_files;
        directory_helper_get_files(state,temp_files);

        files.clear();

        // copy the queue of files into the vector
        temp_files.reset();
        while (temp_files.move_next())
        {
            files.push_back(temp_files.element());
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename queue_of_files
        >
    void directory::
    get_files (
        queue_of_files& files
    ) const
    {
        // the reason for this indirection here is because it avoids a bug in
        // the mingw version of gcc
        directory_helper_get_files(state,files);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename queue_of_dirs
        >
    typename disable_if<is_std_vector<queue_of_dirs>,void>::type
    directory_helper_get_dirs (
        const directory::data& state,
        queue_of_dirs& dirs
    )
    {
        using namespace std;
        typedef directory::listing_error listing_error;
        typedef directory::private_constructor private_constructor;

        dirs.clear();
        if (state.full_name.size() == 0)
            throw listing_error("This directory object currently doesn't represent any directory.");

        HANDLE dfind = INVALID_HANDLE_VALUE;
        try
        {
            WIN32_FIND_DATAA data;
            string path = state.full_name;
            // ensure that the path ends with a separator
            if (path[path.size()-1] != directory::get_separator())
                path += directory::get_separator();

            dfind = FindFirstFileA((path+"*").c_str(), &data);
            if (dfind == INVALID_HANDLE_VALUE)
            {
                throw listing_error("Unable to list the contents of " + state.full_name);
            }

            bool no_more_files = false;
            do
            {
                string tname(data.cFileName);
                if ((data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) != 0 &&
                    tname != "." &&
                    tname != "..")
                {
                    // this is a directory so add it to the queue
                    directory temp(tname,path+tname,private_constructor());
                    dirs.enqueue(temp);
                }

                if (FindNextFileA(dfind,&data) == 0)
                {
                    // an error occurred
                    if ( GetLastError() == ERROR_NO_MORE_FILES)
                    {
                        // there are no more files
                        no_more_files = true;
                    }
                    else
                    {
                        // there was an error
                        throw listing_error("Unable to list the contents of " + state.full_name);
                    }
                }
            } while (no_more_files == false);

            FindClose(dfind);
            dfind = INVALID_HANDLE_VALUE;
        }
        catch (...)
        {
            if (dfind != INVALID_HANDLE_VALUE)
                FindClose(dfind);
            dirs.clear();
            throw;
        }

    }

// ----------------------------------------------------------------------------------------

    template <
        typename queue_of_dirs
        >
    typename enable_if<is_std_vector<queue_of_dirs>,void>::type
    directory_helper_get_dirs (
        const directory::data& state,
        queue_of_dirs& dirs
    )
    {
        queue<directory>::kernel_2a temp_dirs;
        directory_helper_get_dirs(state,temp_dirs);

        dirs.clear();

        // copy the queue of dirs into the vector
        temp_dirs.reset();
        while (temp_dirs.move_next())
        {
            dirs.push_back(temp_dirs.element());
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename queue_of_dirs
        >
    void directory::
    get_dirs (
        queue_of_dirs& dirs
    ) const
    {
        // the reason for this indirection here is because it avoids a bug in
        // the mingw version of gcc
        directory_helper_get_dirs(state,dirs);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

}

#ifdef NO_MAKEFILE
#include "dir_nav_kernel_1.cpp"
#endif

#endif // DLIB_DIR_NAV_KERNEl_1_


dlib C++ Library - dir_nav_kernel_2.cpp

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_DIR_NAV_KERNEL_2_CPp_
#define DLIB_DIR_NAV_KERNEL_2_CPp_

#include "../platform.h"

#ifdef POSIX

#include "dir_nav_kernel_2.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // file object implementation
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    void file::
    init (
        const std::string& name
    )
    {
        using namespace std;

        char buf[PATH_MAX];
        if (realpath(name.c_str(),buf) == 0)
        {
            // the file was not found
            throw file_not_found("Unable to find file " + name);
        }
        state.full_name = buf;

        string::size_type pos = state.full_name.find_last_of(directory::get_separator());
        if (pos == string::npos)
        {
            // no valid full path has no separtor characters.
            throw file_not_found("Unable to find file " + name);
        }
        state.name = state.full_name.substr(pos+1);

        // now find the size of this file
        struct stat64 buffer;
        if (::stat64(state.full_name.c_str(), &buffer) ||
            S_ISDIR(buffer.st_mode))
        {
            // there was an error during the call to stat64 or
            // name is actually a directory
            throw file_not_found("Unable to find file " + name);
        }
        else
        {
            state.file_size = static_cast<uint64>(buffer.st_size);
        }

    }

// ----------------------------------------------------------------------------------------

    bool file::
    operator == (
        const file& rhs
    ) const
    {
        using namespace std;
        if (state.full_name.size() == 0 && rhs.state.full_name.size() == 0)
            return true;

        // These files might have different names but actually represent the same
        // file due to the presence of symbolic links.
        char buf[PATH_MAX];
        string left, right;
        if (realpath(state.full_name.c_str(),buf) == 0)
            return false;
        left = buf;

        if (realpath(rhs.state.full_name.c_str(),buf) == 0)
            return false;
        right = buf;

        return (left == right);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // directory object implementation
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    void directory::
    init (
        const std::string& name
    )
    {
        using namespace std;

        char buf[PATH_MAX];
        if (realpath(name.c_str(),buf) == 0)
        {
            // the directory was not found
            throw dir_not_found("Unable to find directory " + name);
        }
        state.full_name = buf;

        const char sep = get_separator();
        if (is_root_path(state.full_name) == false)
        {
            // ensure that thre is not a trialing separator
            if (state.full_name[state.full_name.size()-1] == sep)
                state.full_name.erase(state.full_name.size()-1);

            // pick out the directory name
            string::size_type pos = state.full_name.find_last_of(sep);
            state.name = state.full_name.substr(pos+1);
        }
        else
        {
            // ensure that there is a trailing separator
            if (state.full_name[state.full_name.size()-1] != sep)
                state.full_name += sep;
        }

        struct stat64 buffer;
        // now check that this is actually a valid directory
        if (::stat64(state.full_name.c_str(),&buffer))
        {
            // the directory was not found
            throw dir_not_found("Unable to find directory " + name);
        }
        else if (S_ISDIR(buffer.st_mode) == 0)
        {
            // It is not a directory
            throw dir_not_found("Unable to find directory " + name);
        }
    }

// ----------------------------------------------------------------------------------------

    char directory::
    get_separator (
    )
    {
        return '/';
    }

// ----------------------------------------------------------------------------------------

    bool directory::
    operator == (
        const directory& rhs
    ) const
    {
        using namespace std;
        if (state.full_name.size() == 0 && rhs.state.full_name.size() == 0)
            return true;

        // These directories might have different names but actually represent the same
        // directory due to the presence of symbolic links.
        char buf[PATH_MAX];
        string left, right;
        if (realpath(state.full_name.c_str(),buf) == 0)
            return false;
        left = buf;

        if (realpath(rhs.state.full_name.c_str(),buf) == 0)
            return false;
        right = buf;

        return (left == right);
    }

// ----------------------------------------------------------------------------------------

    const directory directory::
    get_parent (
    ) const
    {
        using namespace std;
        // if *this is the root then just return *this
        if (is_root())
        {
            return *this;
        }
        else
        {
            directory temp;

            const char sep = get_separator();

            string::size_type pos = state.full_name.find_last_of(sep);
            temp.state.full_name = state.full_name.substr(0,pos);

            if ( is_root_path(temp.state.full_name))
            {
                temp.state.full_name += sep;
            }
            else
            {
                pos = temp.state.full_name.find_last_of(sep);
                if (pos != string::npos)
                {
                    temp.state.name = temp.state.full_name.substr(pos+1);
                }
                else
                {
                    temp.state.full_name += sep;
                }
            }
            return temp;
        }
    }

// ----------------------------------------------------------------------------------------

    bool directory::
    is_root_path (
        const std::string& path
    ) const
    {
        const char sep = get_separator();
        if (path.size() == 1 && path[0] == sep)
            return true;
        else
            return false;
    }

// ----------------------------------------------------------------------------------------

}

#endif // POSIX

#endif // DLIB_DIR_NAV_KERNEL_2_CPp_


dlib C++ Library - dir_nav_kernel_2.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_DIR_NAV_KERNEl_2_
#define DLIB_DIR_NAV_KERNEl_2_

#ifdef DLIB_ISO_CPP_ONLY
#error "DLIB_ISO_CPP_ONLY is defined so you can't use this OS dependent code.  Turn DLIB_ISO_CPP_ONLY off if you want to use it."
#endif

#include "dir_nav_kernel_abstract.h"

#include <string>
#include "../uintn.h"
#include "../algs.h"

#include <sys/types.h>
#include <dirent.h>
#include <libgen.h>
#include <limits.h>
#include <unistd.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdlib.h>

#if !defined(__USE_LARGEFILE64 ) && !defined(_LARGEFILE64_SOURCE)
#define stat64 stat
#endif

#include <vector>
#include "../stl_checked.h"
#include "../enable_if.h"
#include "../queue.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // file object
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class file
    {
        /*!
            INITIAL VALUES
                state.name        == name()
                state.full_name   == full_name()
                state.file_size   == size()

            CONVENTION
                state.name        == name()
                state.full_name   == full_name()
                state.file_size   == size()

        !*/

        friend class directory;

        struct data
        {
            uint64 file_size;
            std::string name;
            std::string full_name;
        };

        void init(const std::string& name);

    public:

        struct private_constructor{};
        inline file (
            const std::string& name,
            const std::string& full_name,
            const uint64 file_size,
            private_constructor
        )
        {
            state.file_size = file_size;
            state.name = name;
            state.full_name = full_name;
        }

        class file_not_found : public error {
            public: file_not_found(const std::string& s): error(s){}
        };

        inline file (
        )
        {
            state.file_size = 0;
        }

        file (
            const std::string& name
        ) { init(name); }

        file (
            const char* name
        ) { init(name); }

        inline const std::string& name (
        ) const { return state.name; }

        inline  const std::string& full_name (
        ) const { return state.full_name; }

        inline uint64 size (
        ) const { return state.file_size; }

        operator std::string (
        ) const { return full_name(); }

        bool operator == (
            const file& rhs
        ) const;

        bool operator != (
            const file& rhs
        ) const { return !(*this == rhs); }

        inline bool operator < (
            const file& item
        ) const { return full_name() < item.full_name(); }

        inline void swap (
            file& item
        )
        {
            exchange(state,item.state);
        }

    private:

        // member data
        data state;

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // directory object
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class directory
    {
        /*!
            INITIAL VALUES
                state.name        == name()
                state.full_name   == full_name()

            CONVENTION
                state.name        == name()
                state.full_name   == full_name()
                is_root()          == state.name.size() == 0

        !*/

        void init(const std::string& name);

    public:
        struct private_constructor{};
        inline directory (
            const std::string& name,
            const std::string& full_name,
            private_constructor
        )
        {
            state.name = name;
            state.full_name = full_name;
        }

        struct data
        {
            std::string name;
            std::string full_name;
        };

        class dir_not_found : public error {
            public: dir_not_found(const std::string& s):error(s){}
        };
        class listing_error : public error {
            public: listing_error(const std::string& s):error(s){}
        };

        inline directory (
        )
        {
        }

        directory (
            const std::string& name
        ) { init(name); }

        directory (
            const char* name
        ) { init(name); }

        static char get_separator (
        );

        template <
            typename queue_of_files
            >
        void get_files (
            queue_of_files& files
        ) const;

        template <
            typename queue_of_dirs
            >
        void get_dirs (
            queue_of_dirs& dirs
        ) const;

        std::vector<file> get_files (
        ) const
        {
            std::vector<file> temp_vector;
            get_files(temp_vector);
            return temp_vector;
        }

        std::vector<directory> get_dirs (
        ) const
        {
            std::vector<directory> temp_vector;
            get_dirs(temp_vector);
            return temp_vector;
        }

        const directory get_parent (
        ) const;

        inline bool is_root (
        ) const { return state.name.size() == 0; }

        inline const std::string& name (
        ) const { return state.name; }

        inline const std::string& full_name (
        ) const { return state.full_name; }

        operator std::string (
        ) const { return full_name(); }

        bool operator == (
            const directory& rhs
        ) const;

        bool operator != (
            const directory& rhs
        ) const { return !(*this == rhs); }

        inline bool operator < (
            const directory& item
        ) const { return full_name() < item.full_name(); }

        inline void swap (
            directory& item
        )
        {
            exchange(state,item.state);
        }

    private:

        // member data
        data state;

        bool is_root_path (
            const std::string& path
        ) const;
        /*!
            ensures
                - returns true if path is a root path.
                  Note that this function considers root paths that don't
                  have a trailing separator to also be valid.
        !*/

    };

// ----------------------------------------------------------------------------------------

    inline std::ostream& operator<< (
        std::ostream& out,
        const directory& item
    ) { out << (std::string)item; return out; }

    inline std::ostream& operator<< (
        std::ostream& out,
        const file& item
    ) { out << (std::string)item; return out; }

// ----------------------------------------------------------------------------------------

    inline void swap (
        file& a,
        file& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------

    inline void swap (
        directory& a,
        directory& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // templated member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename queue_of_files
        >
    typename disable_if<is_std_vector<queue_of_files>,void>::type
    directory_helper_get_files (
        const directory::data& state,
        queue_of_files& files
    )
    {
        using namespace std;

        files.clear();
        if (state.full_name.size() == 0)
            throw directory::listing_error("This directory object currently doesn't represent any directory.");

        DIR* ffind = 0;
        struct dirent* data;
        struct stat64 buffer;

        try
        {
            string path = state.full_name;
            // ensure that the path ends with a separator
            if (path[path.size()-1] != directory::get_separator())
                path += directory::get_separator();

            // get a handle to something we can search with
            ffind = opendir(state.full_name.c_str());
            if (ffind == 0)
            {
                throw directory::listing_error("Unable to list the contents of " + state.full_name);
            }

            while(true)
            {
                errno = 0;
                if ( (data = readdir(ffind)) == 0)
                {
                    // there was an error or no more files
                    if ( errno == 0)
                    {
                        // there are no more files
                        break;
                    }
                    else
                    {
                        // there was an error
                        throw directory::listing_error("Unable to list the contents of " + state.full_name);
                    }
                }

                uint64 file_size;
                // get a stat64 structure so we can see if this is a file
                if (::stat64((path+data->d_name).c_str(), &buffer) != 0)
                {
                    // this might be a broken symbolic link.  We can check by calling
                    // readlink and seeing if it finds anything.
                    char buf[PATH_MAX];
                    ssize_t temp = readlink((path+data->d_name).c_str(),buf,sizeof(buf));
                    if (temp == -1)
                        throw directory::listing_error("Unable to list the contents of " + state.full_name);
                    else
                        file_size = static_cast<uint64>(temp);
                }
                else
                {
                    file_size = static_cast<uint64>(buffer.st_size);
                }

                if (S_ISDIR(buffer.st_mode) == 0)
                {
                    // this is actually a file
                    file temp(
                        data->d_name,
                        path+data->d_name,
                        file_size,
                        file::private_constructor()
                        );
                    files.enqueue(temp);
                }
            } // while (true)

            if (ffind != 0)
            {
                while (closedir(ffind))
                {
                    if (errno != EINTR)
                        break;
                }
                ffind = 0;
            }

        }
        catch (...)
        {
            if (ffind != 0)
            {
                while (closedir(ffind))
                {
                    if (errno != EINTR)
                        break;
                }
                ffind = 0;
            }
            files.clear();
            throw;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename queue_of_files
        >
    typename enable_if<is_std_vector<queue_of_files>,void>::type
    directory_helper_get_files (
        const directory::data& state,
        queue_of_files& files
    )
    {
        queue<file>::kernel_2a temp_files;
        directory_helper_get_files(state,temp_files);

        files.clear();

        // copy the queue of files into the vector
        temp_files.reset();
        while (temp_files.move_next())
        {
            files.push_back(temp_files.element());
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename queue_of_files
        >
    void directory::
    get_files (
        queue_of_files& files
    ) const
    {
        // the reason for this indirection here is because it avoids a bug in
        // the cygwin version of gcc
        directory_helper_get_files(state,files);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename queue_of_dirs
        >
    typename disable_if<is_std_vector<queue_of_dirs>,void>::type
    directory_helper_get_dirs (
        const directory::data& state,
        queue_of_dirs& dirs
    )
    {
        using namespace std;

        dirs.clear();
        if (state.full_name.size() == 0)
            throw directory::listing_error("This directory object currently doesn't represent any directory.");

        DIR* ffind = 0;
        struct dirent* data;
        struct stat64 buffer;

        try
        {
            string path = state.full_name;
            // ensure that the path ends with a separator
            if (path[path.size()-1] != directory::get_separator())
                path += directory::get_separator();

            // get a handle to something we can search with
            ffind = opendir(state.full_name.c_str());
            if (ffind == 0)
            {
                throw directory::listing_error("Unable to list the contents of " + state.full_name);
            }

            while(true)
            {
                errno = 0;
                if ( (data = readdir(ffind)) == 0)
                {
                    // there was an error or no more files
                    if ( errno == 0)
                    {
                        // there are no more files
                        break;
                    }
                    else
                    {
                        // there was an error
                        throw directory::listing_error("Unable to list the contents of " + state.full_name);
                    }
                }

                // get a stat64 structure so we can see if this is a file
                if (::stat64((path+data->d_name).c_str(), &buffer) != 0)
                {
                    // just assume this isn't a directory.  It is probably a broken
                    // symbolic link.
                    continue;
                }

                string dtemp(data->d_name);
                if (S_ISDIR(buffer.st_mode) &&
                    dtemp != "." &&
                    dtemp != ".." )
                {
                    // this is a directory so add it to dirs
                    directory temp(dtemp,path+dtemp, directory::private_constructor());
                    dirs.enqueue(temp);
                }
            } // while (true)

            if (ffind != 0)
            {
                while (closedir(ffind))
                {
                    if (errno != EINTR)
                        break;
                }
                ffind = 0;
            }

        }
        catch (...)
        {
            if (ffind != 0)
            {
                while (closedir(ffind))
                {
                    if (errno != EINTR)
                        break;
                }
                ffind = 0;
            }
            dirs.clear();
            throw;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename queue_of_dirs
        >
    typename enable_if<is_std_vector<queue_of_dirs>,void>::type
    directory_helper_get_dirs (
        const directory::data& state,
        queue_of_dirs& dirs
    )
    {
        queue<directory>::kernel_2a temp_dirs;
        directory_helper_get_dirs(state,temp_dirs);

        dirs.clear();

        // copy the queue of dirs into the vector
        temp_dirs.reset();
        while (temp_dirs.move_next())
        {
            dirs.push_back(temp_dirs.element());
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename queue_of_dirs
        >
    void directory::
    get_dirs (
        queue_of_dirs& dirs
    ) const
    {
        // the reason for this indirection here is because it avoids a bug in
        // the cygwin version of gcc
        directory_helper_get_dirs(state,dirs);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename queue_of_dir
        >
    typename disable_if<is_std_vector<queue_of_dir>,void>::type get_filesystem_roots (
        queue_of_dir& roots
    )
    {
        roots.clear();
        directory dir("/");
        roots.enqueue(dir);
    }

    template <
        typename queue_of_dir
        >
    typename enable_if<is_std_vector<queue_of_dir>,void>::type get_filesystem_roots (
        std::vector<directory>& roots
    )
    {
        roots.clear();
        directory dir("/");
        roots.push_back(dir);
    }

// ----------------------------------------------------------------------------------------

}

#ifdef NO_MAKEFILE
#include "dir_nav_kernel_2.cpp"
#endif

#endif // DLIB_DIR_NAV_KERNEl_2_


dlib C++ Library - posix.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_DIR_NAV_KERNEl_1_
#include "dir_nav_kernel_2.h"
#endif


dlib C++ Library - windows.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_DIR_NAV_KERNEl_2_
#include "dir_nav_kernel_1.h"
#endif


dlib C++ Library - directed_graph_kernel_1.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_DIRECTED_GRAPH_KERNEl_1_
#define DLIB_DIRECTED_GRAPH_KERNEl_1_

#include "../serialize.h"
#include "../noncopyable.h"
#include "../std_allocator.h"
#include "../smart_pointers.h"
#include "../algs.h"
#include <vector>
#include "directed_graph_kernel_abstract.h"
#include "../is_kind.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <typename node_type, typename directed_graph, bool is_checked>
    struct directed_graph_checker_helper
    {
        /*!
            This object is used to check preconditions based on the value of is_checked
        !*/

        static void check_parent_edge (
            unsigned long edge_index,
            const node_type& self
        )
        {
            // make sure requires clause is not broken
            DLIB_CASSERT(edge_index < self.number_of_parents(),
                         "\tnode_type& directed_graph::node_type::parent_edge(edge_index)"
                         << "\n\tYou have specified an invalid index"
                         << "\n\tedge_index:          " << edge_index
                         << "\n\tnumber_of_parents(): " << self.number_of_parents()
                         << "\n\tthis:              " << &self
            );
        }

        static void check_child_edge (
            unsigned long edge_index,
            const node_type& self
        )
        {
            // make sure requires clause is not broken
            DLIB_CASSERT(edge_index < self.number_of_children(),
                         "\tnode_type& directed_graph::node_type::child_edge(edge_index)"
                         << "\n\tYou have specified an invalid index"
                         << "\n\tedge_index:           " << edge_index
                         << "\n\tnumber_of_children(): " << self.number_of_children()
                         << "\n\tthis:              " << &self
            );
        }

        static void check_parent (
            unsigned long edge_index,
            const node_type& self
        )
        {
            // make sure requires clause is not broken
            DLIB_CASSERT(edge_index < self.number_of_parents(),
                         "\tnode_type& directed_graph::node_type::parent(edge_index)"
                         << "\n\tYou have specified an invalid index"
                         << "\n\tedge_index:          " << edge_index
                         << "\n\tnumber_of_parents(): " << self.number_of_parents()
                         << "\n\tthis:              " << &self
            );
        }

        static void check_child (
            unsigned long edge_index,
            const node_type& self
        )
        {
            // make sure requires clause is not broken
            DLIB_CASSERT(edge_index < self.number_of_children(),
                         "\tnode_type& directed_graph::node_type::child(edge_index)"
                         << "\n\tYou have specified an invalid index"
                         << "\n\tedge_index:           " << edge_index
                         << "\n\tnumber_of_children(): " << self.number_of_children()
                         << "\n\tthis:              " << &self
            );
        }

        static void check_node (
            unsigned long index,
            const directed_graph& self
        )
        {
            // make sure requires clause is not broken
            DLIB_CASSERT(index < self.number_of_nodes(),
                         "\tnode_type& directed_graph::node(index)"
                         << "\n\tYou have specified an invalid index"
                         << "\n\tindex:             " << index
                         << "\n\tnumber_of_nodes(): " << self.number_of_nodes()
                         << "\n\tthis:              " << &self
            );
        }

        static void check_has_edge (
            unsigned long parent_node_index,
            unsigned long child_node_index,
            const directed_graph& self
        )
        {
            // make sure requires clause is not broken
            DLIB_CASSERT(parent_node_index < self.number_of_nodes() &&
                         child_node_index < self.number_of_nodes(),
                         "\tvoid directed_graph::has_edge(parent_node_index, child_node_index)"
                         << "\n\tYou have specified an invalid index"
                         << "\n\tparent_node_index: " << parent_node_index
                         << "\n\tchild_node_index:  " << child_node_index
                         << "\n\tnumber_of_nodes(): " << self.number_of_nodes()
                         << "\n\tthis:              " << &self
            );
        }

        static void check_add_edge (
            unsigned long parent_node_index,
            unsigned long child_node_index,
            const directed_graph& self
        )
        {
            DLIB_CASSERT(parent_node_index < self.number_of_nodes() &&
                         child_node_index < self.number_of_nodes(),
                         "\tvoid directed_graph::add_edge(parent_node_index, child_node_index)"
                         << "\n\tYou have specified an invalid index"
                         << "\n\tparent_node_index: " << parent_node_index
                         << "\n\tchild_node_index:  " << child_node_index
                         << "\n\tnumber_of_nodes(): " << self.number_of_nodes()
                         << "\n\tthis:              " << &self
            );

            DLIB_CASSERT( self.has_edge(parent_node_index, child_node_index) == false,
                          "\tvoid directed_graph::add_edge(parent_node_index, child_node_index)"
                          << "\n\tYou can't add an edge if it already exists in the graph"
                          << "\n\tparent_node_index: " << parent_node_index
                          << "\n\tchild_node_index:  " << child_node_index
                          << "\n\tnumber_of_nodes(): " << self.number_of_nodes()
                          << "\n\tthis:              " << &self
            );

        }

        static void check_remove_edge (
            unsigned long parent_node_index,
            unsigned long child_node_index,
            const directed_graph& self
        )
        {
            DLIB_CASSERT(parent_node_index < self.number_of_nodes() &&
                         child_node_index < self.number_of_nodes(),
                         "\tvoid directed_graph::remove_edge(parent_node_index, child_node_index)"
                         << "\n\tYou have specified an invalid index"
                         << "\n\tparent_node_index: " << parent_node_index
                         << "\n\tchild_node_index:  " << child_node_index
                         << "\n\tnumber_of_nodes(): " << self.number_of_nodes()
                         << "\n\tthis:              " << &self
            );

            DLIB_CASSERT( self.has_edge(parent_node_index, child_node_index) == true,
                          "\tvoid directed_graph::remove_edge(parent_node_index, child_node_index)"
                          << "\n\tYou can't remove an edge if it isn't in the graph"
                          << "\n\tparent_node_index: " << parent_node_index
                          << "\n\tchild_node_index:  " << child_node_index
                          << "\n\tnumber_of_nodes(): " << self.number_of_nodes()
                          << "\n\tthis:              " << &self
            );

        }

        static void check_remove_node (
            unsigned long index,
            const directed_graph& self
        )
        {
            // make sure requires clause is not broken
            DLIB_CASSERT(index < self.number_of_nodes(),
                         "\tvoid directed_graph::remove_node(index)"
                         << "\n\tYou have specified an invalid index"
                         << "\n\tindex:             " << index
                         << "\n\tnumber_of_nodes(): " << self.number_of_nodes()
                         << "\n\tthis:              " << &self
            );
        }
    };

    template <typename node_type, typename directed_graph>
    struct directed_graph_checker_helper <node_type, directed_graph, false>
    {
        static inline void check_parent ( unsigned long , const node_type&) { }
        static inline void check_child ( unsigned long , const node_type& ) { }
        static inline void check_parent_edge ( unsigned long , const node_type&) { }
        static inline void check_child_edge ( unsigned long , const node_type& ) { }
        static inline void check_node ( unsigned long , const directed_graph& ) { }
        static inline void check_has_edge ( unsigned long , unsigned long , const directed_graph& ) { }
        static inline void check_add_edge ( unsigned long , unsigned long , const directed_graph& ) { }
        static inline void check_remove_edge ( unsigned long , unsigned long , const directed_graph& ) { }
        static inline void check_remove_node ( unsigned long , const directed_graph& ) { }
    };

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename E = char,
        typename mem_manager = default_memory_manager,
        bool is_checked = true
        >
    class directed_graph_kernel_1 : noncopyable
    {

        /*!
            INITIAL VALUE
                - nodes.size() == 0

            CONVENTION
                - nodes.size() == number_of_nodes()
                - for all valid i:
                    - *nodes[i] == node(i)
                    - nodes[i]->parents.size() == nodes[i]->number_of_parents(i)
                    - nodes[i]->children.size() == nodes[i]->number_of_children(i)
                    - nodes[i]->edge_parents.size() == nodes[i]->number_of_parents(i)
                    - nodes[i]->edge_children.size() == nodes[i]->number_of_children(i)
                    - nodes[i]->idx == i == nodes[i]->index()
                    - for all valid p:
                        - nodes[i]->parents[p] == pointer to the p'th parent node of i
                        - *nodes[i]->parents[p] == nodes[i]->parent(p)
                        - *nodes[i]->edge_parents[p] == nodes[i]->parent_edge(p)
                    - for all valid c:
                        - nodes[i]->children[c] == pointer to the c'th child node of i
                        - *nodes[i]->children[c] == nodes[i]->child(c)
                        - *nodes[i]->edge_children[c] == nodes[i]->child_edge(c)
        !*/

    public:
        struct node_type;

    private:
        typedef directed_graph_checker_helper<node_type, directed_graph_kernel_1, is_checked> checker;

    public:

        typedef T type;
        typedef E edge_type;
        typedef mem_manager mem_manager_type;

        template <typename Tr, typename Er, typename MMr>
        struct rebind {
            typedef directed_graph_kernel_1<Tr,Er,MMr> other;
        };

        directed_graph_kernel_1(
        ) {}

        virtual ~directed_graph_kernel_1(
        ) {}

        void clear(
        ) { nodes.clear(); }

        void set_number_of_nodes (
            unsigned long new_size
        );

        unsigned long number_of_nodes (
        ) const { return nodes.size(); }

        node_type& node (
            unsigned long index
        ) { checker::check_node(index,*this); return *nodes[index]; }

        const node_type& node (
            unsigned long index
        ) const { checker::check_node(index,*this); return *nodes[index]; }

        bool has_edge (
            unsigned long parent_node_index,
            unsigned long child_node_index
        ) const;

        void add_edge (
            unsigned long parent_node_index,
            unsigned long child_node_index
        );

        void remove_edge (
            unsigned long parent_node_index,
            unsigned long child_node_index
        );

        unsigned long add_node (
        );

        void remove_node (
            unsigned long index
        );

        void swap (
            directed_graph_kernel_1& item
        ) { nodes.swap(item.nodes); }

    private:

    public:

        struct node_type
        {
            T data;
            typedef directed_graph_kernel_1 graph_type;

            unsigned long index(
            ) const { return idx; }

            unsigned long number_of_parents (
            ) const { return parents.size(); }

            unsigned long number_of_children (
            ) const { return children.size(); }

            const node_type& parent (
                unsigned long edge_index
            ) const { checker::check_parent(edge_index,*this);  return *parents[edge_index]; }

            node_type& parent (
                unsigned long edge_index
            ) { checker::check_parent(edge_index,*this);  return *parents[edge_index]; }

            const node_type& child (
                unsigned long edge_index
            ) const { checker::check_child(edge_index,*this);  return *children[edge_index]; }

            node_type& child (
                unsigned long edge_index
            ) { checker::check_child(edge_index,*this);  return *children[edge_index]; }

            const E& parent_edge (
                unsigned long edge_index
            ) const { checker::check_parent_edge(edge_index,*this);  return *edge_parents[edge_index]; }

            E& parent_edge (
                unsigned long edge_index
            ) { checker::check_parent_edge(edge_index,*this);  return *edge_parents[edge_index]; }

            const E& child_edge (
                unsigned long edge_index
            ) const { checker::check_child_edge(edge_index,*this);  return *edge_children[edge_index]; }

            E& child_edge (
                unsigned long edge_index
            ) { checker::check_child_edge(edge_index,*this);  return *edge_children[edge_index]; }

        private:
            friend class directed_graph_kernel_1;
            typedef std_allocator<node_type*,mem_manager> alloc_type;
            typedef std_allocator<shared_ptr<E>,mem_manager> alloc_edge_type;
            std::vector<node_type*,alloc_type> parents;
            std::vector<node_type*,alloc_type> children;
            std::vector<shared_ptr<E>,alloc_edge_type> edge_parents;
            std::vector<shared_ptr<E>,alloc_edge_type> edge_children;
            unsigned long idx;
        };

    private:

        typedef std_allocator<shared_ptr<node_type>,mem_manager> alloc_type;
        typedef std::vector<shared_ptr<node_type>, alloc_type> vector_type;
        vector_type nodes;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename E,
        typename mem_manager,
        bool is_checked
        >
    struct is_directed_graph<directed_graph_kernel_1<T,E,mem_manager, is_checked> >
    {
        static const bool value = true;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename E,
        typename mem_manager,
        bool is_checked
        >
    inline void swap (
        directed_graph_kernel_1<T,E,mem_manager,is_checked>& a,
        directed_graph_kernel_1<T,E,mem_manager,is_checked>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename E,
        typename mem_manager,
        bool is_checked
        >
    void serialize (
        const directed_graph_kernel_1<T,E,mem_manager,is_checked>& item,
        std::ostream& out
    )
    {
        try
        {
            serialize(item.number_of_nodes(), out);

            // serialize each node
            for (unsigned long i = 0; i < item.number_of_nodes(); ++i)
            {
                serialize(item.node(i).data, out);

                // serialize all the child edges
                serialize(item.node(i).number_of_children(), out);
                for (unsigned long c = 0; c < item.node(i).number_of_children(); ++c)
                {
                    serialize(item.node(i).child(c).index(), out);
                    serialize(item.node(i).child_edge(c), out);
                }
            }
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while serializing object of type directed_graph_kernel_1");
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename E,
        typename mem_manager,
        bool is_checked
        >
    void deserialize (
        directed_graph_kernel_1<T,E,mem_manager,is_checked>& item,
        std::istream& in
    )
    {
        try
        {
            unsigned long size;
            deserialize(size, in);

            item.clear();
            item.set_number_of_nodes(size);

            // deserialize each node
            for (unsigned long i = 0; i < item.number_of_nodes(); ++i)
            {
                deserialize(item.node(i).data, in);

                unsigned long num_children;
                deserialize(num_children, in);

                // Add all the edges going to this nodes children nodes
                for (unsigned long c = 0; c < num_children; ++c)
                {
                    unsigned long child_index;
                    deserialize(child_index, in);

                    item.add_edge(i, child_index);

                    // find the edge we just added
                    for (unsigned long j = 0; j < item.node(i).number_of_children(); ++j)
                    {
                        if (item.node(i).child(j).index() == child_index)
                        {
                            deserialize(item.node(i).child_edge(j), in);
                            break;
                        }
                    }
                }
            }
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while deserializing object of type directed_graph_kernel_1");
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                             member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename E,
        typename mem_manager,
        bool is_checked
        >
    void directed_graph_kernel_1<T,E,mem_manager,is_checked>::
    set_number_of_nodes (
        unsigned long new_size
    )
    {
        try
        {
            nodes.resize(new_size);
            for (unsigned long i = 0; i < nodes.size(); ++i)
            {
                nodes[i].reset(new node_type);
                nodes[i]->idx = i;
            }
        }
        catch (...)
        {
            clear();
            throw;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename E,
        typename mem_manager,
        bool is_checked
        >
    bool directed_graph_kernel_1<T,E,mem_manager,is_checked>::
    has_edge (
        unsigned long parent_node_index,
        unsigned long child_node_index
    ) const
    {
        checker::check_has_edge(parent_node_index, child_node_index, *this);

        node_type& n = *nodes[parent_node_index];

        // search all the child nodes to see if there is a link to the right node
        for (unsigned long i = 0; i < n.children.size(); ++i)
        {
            if (n.children[i]->idx == child_node_index)
                return true;
        }

        return false;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename E,
        typename mem_manager,
        bool is_checked
        >
    void directed_graph_kernel_1<T,E,mem_manager,is_checked>::
    add_edge (
        unsigned long parent_node_index,
        unsigned long child_node_index
    )
    {
        checker::check_add_edge(parent_node_index, child_node_index, *this);
        try
        {
            node_type& p = *nodes[parent_node_index];
            node_type& c = *nodes[child_node_index];

            p.children.push_back(&c);
            c.parents.push_back(&p);

            p.edge_children.push_back(shared_ptr<E>(new E));
            c.edge_parents.push_back(p.edge_children.back());
        }
        catch (...)
        {
            clear();
            throw;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename E,
        typename mem_manager,
        bool is_checked
        >
    void directed_graph_kernel_1<T,E,mem_manager,is_checked>::
    remove_edge (
        unsigned long parent_node_index,
        unsigned long child_node_index
    )
    {
        checker::check_remove_edge(parent_node_index, child_node_index, *this);

        node_type& p = *nodes[parent_node_index];
        node_type& c = *nodes[child_node_index];

        // remove the record of the link from the parent node
        unsigned long pos = static_cast<unsigned long>(find( p.children.begin(),
                                  p.children.end(),
                                  &c) - p.children.begin());
        p.children.erase(p.children.begin()+pos);
        p.edge_children.erase(p.edge_children.begin()+pos);

        // remove the record of the link from the child node
        pos = static_cast<unsigned long>(find( c.parents.begin(),
                  c.parents.end(),
                  &p) - c.parents.begin());
        c.parents.erase(c.parents.begin() + pos);
        c.edge_parents.erase(c.edge_parents.begin() + pos);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename E,
        typename mem_manager,
        bool is_checked
        >
    unsigned long directed_graph_kernel_1<T,E,mem_manager,is_checked>::
    add_node (
    )
    {
        try
        {
            shared_ptr<node_type> n(new node_type);
            n->idx = nodes.size();
            nodes.push_back(n);
            return n->idx;
        }
        catch (...)
        {
            clear();
            throw;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename E,
        typename mem_manager,
        bool is_checked
        >
    void directed_graph_kernel_1<T,E,mem_manager,is_checked>::
    remove_node (
        unsigned long index
    )
    {
        checker::check_remove_node(index,*this);

        node_type& n = *nodes[index];

        // remove all edges pointing to this node from its parents
        for (unsigned long i = 0; i < n.parents.size(); ++i)
        {
            // remove the edge from this specific parent
            unsigned long pos = static_cast<unsigned long>(find(n.parents[i]->children.begin(),
                     n.parents[i]->children.end(),
                     &n) - n.parents[i]->children.begin());

            n.parents[i]->children.erase(n.parents[i]->children.begin() + pos);
            n.parents[i]->edge_children.erase(n.parents[i]->edge_children.begin() + pos);
        }

        // remove all edges pointing to this node from its children
        for (unsigned long i = 0; i < n.children.size(); ++i)
        {
            // remove the edge from this specific child
            unsigned long pos = static_cast<unsigned long>(find(n.children[i]->parents.begin(),
                     n.children[i]->parents.end(),
                     &n) - n.children[i]->parents.begin());

            n.children[i]->parents.erase(n.children[i]->parents.begin() + pos);
            n.children[i]->edge_parents.erase(n.children[i]->edge_parents.begin() + pos);
        }

        // now remove this node by replacing it with the last node in the nodes vector
        nodes[index] = nodes[nodes.size()-1];

        // update the index for the node we just moved
        nodes[index]->idx = index;

        // now remove the duplicated node at the end of the vector
        nodes.pop_back();
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_DIRECTED_GRAPH_KERNEl_1_


dlib C++ Library - disjoint_subsets.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_DISJOINT_SUBsETS_Hh_
#define DLIB_DISJOINT_SUBsETS_Hh_

#include "disjoint_subsets_abstract.h"
#include <vector>
#include "../algs.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class disjoint_subsets
    {
    public:

        void clear (
        )
        {
            items.clear();
        }

        void set_size (
            unsigned long new_size
        )
        {
            items.resize(new_size);
            for (unsigned long i = 0; i < items.size(); ++i)
            {
                items[i].parent = i;
                items[i].rank = 0;
            }
        }

        unsigned long size (
        ) const
        {
            return items.size();
        }

        unsigned long find_set (
            unsigned long item
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(item < size(),
                "\t unsigned long disjoint_subsets::find_set()"
                << "\n\t item must be less than size()"
                << "\n\t item: " << item
                << "\n\t size(): " << size()
                << "\n\t this: " << this
                );

            if (items[item].parent == item)
            {
                return item;
            }
            else
            {
                // find root of item
                unsigned long x = item;
                do
                {
                    x = items[x].parent;
                } while (items[x].parent != x);

                // do path compression
                const unsigned long root = x;
                x = item;
                while (items[x].parent != x)
                {
                    const unsigned long prev = x;
                    x = items[x].parent;
                    items[prev].parent = root;
                }

                return root;
            }
        }

        unsigned long merge_sets (
            unsigned long a,
            unsigned long b
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(a != b &&
                        a < size() &&
                        b < size() &&
                        find_set(a) == a &&
                        find_set(b) == b,
                "\t unsigned long disjoint_subsets::merge_sets(a,b)"
                << "\n\t invalid arguments were given to this function"
                << "\n\t a: " << a
                << "\n\t b: " << b
                << "\n\t size(): " << size()
                << "\n\t find_set(a): " << find_set(a)
                << "\n\t find_set(b): " << find_set(b)
                << "\n\t this: " << this
                );

            if (items[a].rank > items[b].rank)
            {
                items[b].parent = a;
                return a;
            }
            else
            {
                items[a].parent = b;
                if (items[a].rank == items[b].rank)
                {
                    items[b].rank = items[b].rank + 1;
                }
                return b;
            }
        }

    private:

        /*
            See the book Introduction to Algorithms by Cormen, Leiserson, Rivest and Stein
            for a discussion of how this algorithm works.
        */

        struct data
        {
            unsigned long rank;
            unsigned long parent;
        };

        mutable std::vector<data> items;

    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_DISJOINT_SUBsETS_Hh_


dlib C++ Library - entropy_decoder_kernel_1.cpp

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ENTROPY_DECODER_KERNEL_1_CPp_
#define DLIB_ENTROPY_DECODER_KERNEL_1_CPp_
#include "entropy_decoder_kernel_1.h"
#include <iostream>
#include <streambuf>
#include <sstream>

#include "../assert.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    entropy_decoder_kernel_1::
    entropy_decoder_kernel_1(
    ) :
        initial_low(0x00000001),
        initial_high(0xffffffff),
        in(0),
        low(initial_low),
        high(initial_high),
        buf(0),
        buf_used(0),
        target(0x00000000),
        r(0)
    {
    }

// ----------------------------------------------------------------------------------------

    entropy_decoder_kernel_1::
    ~entropy_decoder_kernel_1 (
    )
    {
    }

// ----------------------------------------------------------------------------------------

    void entropy_decoder_kernel_1::
    clear(
    )
    {
        in       = 0;
        buf_used = 0;
        buf      = 0;
        r        = 0;
        low      = initial_low;
        high     = initial_high;
        target   = 0x00000000;
    }

// ----------------------------------------------------------------------------------------

    void entropy_decoder_kernel_1::
    set_stream (
        std::istream& in_
    )
    {
        buf_used = 0;
        buf      = 0;
        r        = 0;
        low      = initial_low;
        high     = initial_high;
        target   = 0x00000000;

        in = &in_;
        streambuf = in_.rdbuf();

        unsigned char ch;

        streambuf->sgetn((char*)&ch,1);
        target = ch;

        target <<= 8;
        if (streambuf->sgetn((char*)&ch,1))
            target += ch;

        target <<= 8;
        if (streambuf->sgetn((char*)&ch,1))
            target += ch;

        target <<= 8;
        if (streambuf->sgetn((char*)&ch,1))
            target += ch;

    }

// ----------------------------------------------------------------------------------------

    bool entropy_decoder_kernel_1::
    stream_is_set (
    ) const
    {
        if (in != 0)
            return true;
        else
            return false;
    }

// ----------------------------------------------------------------------------------------

    std::istream& entropy_decoder_kernel_1::
    get_stream (
    ) const
    {
        return *in;
    }

// ----------------------------------------------------------------------------------------

    void entropy_decoder_kernel_1::
    decode (
        uint32 low_count,
        uint32 high_count
    )
    {
        // note that we must subtract 1 to preserve the convention that
        // high == the real upper range - 1
        high = low + r*high_count - 1;
        low = low + r*low_count;
        r = 0;

        while (true)
        {

            // if the highest order bit in high and low is the same
            if ( low >= 0x80000000 || high < 0x80000000)
            {
                // make sure buf isn't empty
                if (buf_used == 0)
                {
                    buf_used = 8;
                    if (streambuf->sgetn(reinterpret_cast<char*>(&buf),1)==0)
                    {
                        // if there isn't anything else in the streambuffer then just
                        // make buf zero.
                        buf = 0;
                    }
                }

                // we will be taking one bit from buf to replace the one we threw away
                --buf_used;

                // roll off the bit in target
                target <<= 1;

                // roll off the bit
                high <<= 1;
                low <<= 1;
                high |= 1;  // note that it is ok to add one to high here because
                            // of the convention that high == real upper range - 1.
                            // so that means that if we want to shift the upper range
                            // left by one then we must shift a one into high also
                            // since real upper range == high + 0.999999999...

                // make sure low is never zero
                if (low == 0)
                    low = 1;

                  // take a bit from buf to fill in the one we threw away
                target += (buf>>buf_used)&0x01;
            }
            // if the distance between high and low is small and there aren't
            // any bits we can roll off then round low up or high down.
            else if (high-low < 0x10000)
            {
                if (high == 0x80000000)
                    high = 0x7fffffff;
                else
                    low = 0x80000000;
            }
            else
            {
                break;
            }
        } // while (true)

    }

// ----------------------------------------------------------------------------------------

    bool entropy_decoder_kernel_1::
    get_target_called (
    ) const
    {
        return (r != 0);
    }

// ----------------------------------------------------------------------------------------

    uint32 entropy_decoder_kernel_1::
    get_target (
        uint32 total
    )
    {
        // note that we must add one because of the convention that
        // high == the real upper range minus 1
        r = (high-low+1)/total;
        uint32 temp = (target-low)/r;
        if (temp < total)
            return temp;
        else
            return total-1;
    }

// ----------------------------------------------------------------------------------------

}
#endif // DLIB_ENTROPY_DECODER_KERNEL_1_CPp_


dlib C++ Library - entropy_decoder_kernel_1.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ENTROPY_DECODER_KERNEl_1_
#define DLIB_ENTROPY_DECODER_KERNEl_1_

#include "../algs.h"
#include "entropy_decoder_kernel_abstract.h"
#include <iosfwd>
#include "../uintn.h"

namespace dlib
{

    class entropy_decoder_kernel_1
    {
        /*!
            GENERAL NOTES
                this decoder is implemented using arithmetic coding

            INITIAL VALUE
                in       == 0
                buf_used == 0
                buf      == 0
                initial_low      == 0x00000001  (slightly more than zero)
                initial_high     == 0xffffffff  (slightly less than one, 0.99999999976717)
                target   == 0x00000000  (zero)
                low      == initial_low
                high     == initial_high
                r        == 0

            CONVENTION
                if (in != 0)
                    *in       == get_stream()
                    true      == stream_is_set()
                    streambuf == in->rdbuf()
                else
                    false   == stream_is_set()

                buf      == used to hold fractional byte values which are fed to target.
                buf_used == the number of low order bits in buf that are currently
                            in use
                low      == the low end of the range used for arithmetic encoding.
                            this number is used as a 32bit fixed point real number.
                            the point is fixed just before the first bit, so it is
                            always in the range [0,1)

                            low is also never allowed to be zero to avoid overflow
                            in the calculation (high-low+1)/total.

                high     == the high end of the range - 1 used for arithmetic encoding.
                            this number is used as a 32bit fixed point real number.
                            the point is fixed just before the first bit, so when we
                            interpret high as a real number then it is always in the
                            range [0,1)

                            the range for arithmetic encoding is always
                            [low,high + 0.9999999...)   the 0.9999999... is why
                            high == real upper range - 1

                target  ==  32 bits of the fraction produced from an arithmetic encoder.
                            this number is used as a 32bit fixed point real number.
                            the point is fixed just before the first bit, so it is
                            always in the range [0,1)

                r       ==  the value (high-low+1)/total from the last call to
                            get_target() or 0 if get_target_called() should be false

                get_target_called() == (r != 0)

        !*/

    public:

        entropy_decoder_kernel_1 (
        );

        virtual ~entropy_decoder_kernel_1 (
        );

        void clear(
        );

        void set_stream (
            std::istream& in
        );

        bool stream_is_set (
        ) const;

        std::istream& get_stream (
        ) const;

        void decode (
            uint32 low_count,
            uint32 high_count
        );

        bool get_target_called (
        ) const;

        uint32 get_target (
            uint32 total
        );

    private:

        // restricted functions
        entropy_decoder_kernel_1(entropy_decoder_kernel_1&);        // copy constructor
        entropy_decoder_kernel_1& operator=(entropy_decoder_kernel_1&);    // assignment operator

        // data members
        const uint32 initial_low;
        const uint32 initial_high;
        std::istream* in;
        uint32 low;
        uint32 high;
        unsigned char buf;
        uint32 buf_used;
        uint32 target;
        uint32 r;
        std::streambuf* streambuf;

    };

}

#ifdef NO_MAKEFILE
#include "entropy_decoder_kernel_1.cpp"
#endif

#endif // DLIB_ENTROPY_DECODER_KERNEl_1_


dlib C++ Library - entropy_decoder_kernel_2.cpp

// Copyright (C) 2004  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ENTROPY_DECODER_KERNEL_2_CPp_
#define DLIB_ENTROPY_DECODER_KERNEL_2_CPp_
#include "entropy_decoder_kernel_2.h"
#include <iostream>
#include <streambuf>
#include <sstream>

#include "../assert.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    entropy_decoder_kernel_2::
    entropy_decoder_kernel_2(
    ) :
        initial_low(0x00000001),
        initial_high(0xffffffff),
        in(0),
        low(initial_low),
        high(initial_high),
        target(0x00000000),
        r(0)
    {
    }

// ----------------------------------------------------------------------------------------

    entropy_decoder_kernel_2::
    ~entropy_decoder_kernel_2 (
    )
    {
    }

// ----------------------------------------------------------------------------------------

    void entropy_decoder_kernel_2::
    clear(
    )
    {
        in       = 0;
        r        = 0;
        low      = initial_low;
        high     = initial_high;
        target   = 0x00000000;
    }

// ----------------------------------------------------------------------------------------

    void entropy_decoder_kernel_2::
    set_stream (
        std::istream& in_
    )
    {
        r        = 0;
        low      = initial_low;
        high     = initial_high;
        target   = 0x00000000;

        in = &in_;
        streambuf = in_.rdbuf();

        unsigned char ch;

        streambuf->sgetn((char*)&ch,1);
        target = ch;

        target <<= 8;
        if (streambuf->sgetn((char*)&ch,1))
            target += ch;

        target <<= 8;
        if (streambuf->sgetn((char*)&ch,1))
            target += ch;

        target <<= 8;
        if (streambuf->sgetn((char*)&ch,1))
            target += ch;
    }

// ----------------------------------------------------------------------------------------

    bool entropy_decoder_kernel_2::
    stream_is_set (
    ) const
    {
        if (in != 0)
            return true;
        else
            return false;
    }

// ----------------------------------------------------------------------------------------

    std::istream& entropy_decoder_kernel_2::
    get_stream (
    ) const
    {
        return *in;
    }

// ----------------------------------------------------------------------------------------

    void entropy_decoder_kernel_2::
    decode (
        uint32 low_count,
        uint32 high_count
    )
    {
        // note that we must subtract 1 to preserve the convention that
        // high == the real upper range - 1
        high = low + r*high_count - 1;
        low = low + r*low_count;
        r = 0;

        while (true )
        {

            // if high and low don't have the same 8 high order bits
            if ((high&0xFF000000) != (low&0xFF000000))
            {
                // if the distance between high and low is small and there aren't
                // any bits we can roll off then force high and low to have common high
                // order bits.
                if ((high-low < 0x10000))
                {
                    if (high-low > 0x1000)
                    {
                        high>>=1;
                        low>>=1;
                        high = low = high+low;
                        high += 0xFF;
                        low -= 0xFF;
                    }
                    else /**/
                    {
                        high>>=1;
                        low>>=1;
                        high = low = high+low;
                    }
                }
                else
                {
                    // there are no bits to roll off and high and low are not
                    // too close so just quit the loop
                    break;
                }

            }
            // else if there are 8 bits we can roll off
            else
            {
                unsigned char buf;
                if (streambuf->sgetn(reinterpret_cast<char*>(&buf),1)==0)
                {
                    // if there isn't anything else in the streambuffer then just
                    // make buf zero.
                    buf = 0;
                }

                // also roll off the bits in target
                target <<= 8;

                // roll off the bits
                high <<= 8;
                low <<= 8;
                high |= 0xFF;  // note that it is ok to add 0xFF to high here because
                            // of the convention that high == real upper range - 1.
                            // so that means that if we want to shift the upper range
                            // left by one then we must shift a one into high also
                            // since real upper range == high + 0.999999999...

                // make sure low is never zero
                if (low == 0)
                    low = 1;

                // put the new bits into target
                target |= static_cast<uint32>(buf);
            }

        } // while (true)
    }

// ----------------------------------------------------------------------------------------

    bool entropy_decoder_kernel_2::
    get_target_called (
    ) const
    {
        return (r != 0);
    }

// ----------------------------------------------------------------------------------------

    uint32 entropy_decoder_kernel_2::
    get_target (
        uint32 total
    )
    {
        // note that we must add one because of the convention that
        // high == the real upper range minus 1
        r = (high-low+1)/total;
        uint32 temp = (target-low)/r;
        if (temp < total)
            return temp;
        else
            return total-1;
    }

// ----------------------------------------------------------------------------------------

}
#endif // DLIB_ENTROPY_DECODER_KERNEL_2_CPp_


dlib C++ Library - entropy_decoder_kernel_2.h

// Copyright (C) 2004  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ENTROPY_DECODER_KERNEl_2_
#define DLIB_ENTROPY_DECODER_KERNEl_2_

#include "../algs.h"
#include "entropy_decoder_kernel_abstract.h"
#include <iosfwd>
#include "../uintn.h"

namespace dlib
{

    class entropy_decoder_kernel_2
    {
        /*!
            GENERAL NOTES
                this decoder is implemented using "range" coding

            INITIAL VALUE
                in       == 0
                initial_low      == 0x00000001  (slightly more than zero)
                initial_high     == 0xffffffff  (slightly less than one, 0.99999999976717)
                target   == 0x00000000  (zero)
                low      == initial_low
                high     == initial_high
                r        == 0

            CONVENTION
                if (in != 0)
                    *in       == get_stream()
                    true      == stream_is_set()
                    streambuf == in->rdbuf()
                else
                    false   == stream_is_set()

                low      == the low end of the range used for arithmetic encoding.
                            this number is used as a 32bit fixed point real number.
                            the point is fixed just before the first bit, so it is
                            always in the range [0,1)

                            low is also never allowed to be zero to avoid overflow
                            in the calculation (high-low+1)/total.

                high     == the high end of the range - 1 used for arithmetic encoding.
                            this number is used as a 32bit fixed point real number.
                            the point is fixed just before the first bit, so when we
                            interpret high as a real number then it is always in the
                            range [0,1)

                            the range for arithmetic encoding is always
                            [low,high + 0.9999999...)   the 0.9999999... is why
                            high == real upper range - 1

                target  ==  32 bits of the fraction produced from an arithmetic encoder.
                            this number is used as a 32bit fixed point real number.
                            the point is fixed just before the first bit, so it is
                            always in the range [0,1)

                r       ==  the value (high-low+1)/total from the last call to
                            get_target() or 0 if get_target_called() should be false

                get_target_called() == (r != 0)

        !*/

    public:

        entropy_decoder_kernel_2 (
        );

        virtual ~entropy_decoder_kernel_2 (
        );

        void clear(
        );

        void set_stream (
            std::istream& in
        );

        bool stream_is_set (
        ) const;

        std::istream& get_stream (
        ) const;

        void decode (
            uint32 low_count,
            uint32 high_count
        );

        bool get_target_called (
        ) const;

        uint32 get_target (
            uint32 total
        );

    private:

        // restricted functions
        entropy_decoder_kernel_2(entropy_decoder_kernel_2&);        // copy constructor
        entropy_decoder_kernel_2& operator=(entropy_decoder_kernel_2&);    // assignment operator

        // data members
        const uint32 initial_low;
        const uint32 initial_high;
        std::istream* in;
        uint32 low;
        uint32 high;
        uint32 target;
        uint32 r;
        std::streambuf* streambuf;

    };

}

#ifdef NO_MAKEFILE
#include "entropy_decoder_kernel_2.cpp"
#endif

#endif // DLIB_ENTROPY_DECODER_KERNEl_2_


dlib C++ Library - entropy_decoder_kernel_c.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ENTROPY_DECODER_KERNEl_C_
#define DLIB_ENTROPY_DECODER_KERNEl_C_

#include "entropy_decoder_kernel_abstract.h"
#include "../algs.h"
#include "../assert.h"
#include <iostream>

namespace dlib
{

    template <
        typename decoder
        >
    class entropy_decoder_kernel_c : public decoder
    {

        public:
            std::istream& get_stream (
            ) const;

            void decode (
                uint32 low_count,
                uint32 high_count
            );

            uint32 get_target (
                uint32 total
            );

    private:
        uint32 _get_target;
        uint32 TOTAL;
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename decoder
        >
    std::istream& entropy_decoder_kernel_c<decoder>::
    get_stream (
    ) const
    {
        // make sure requires clause is not broken
        DLIB_CASSERT( this->stream_is_set() == true,
            "\tstd::istream& entropy_decoder::get_stream()"
            << "\n\tyou must set a stream for this object before you can get it"
            << "\n\tthis: " << this
            );

        // call the real function
        return decoder::get_stream();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename decoder
        >
    void entropy_decoder_kernel_c<decoder>::
    decode (
        uint32 low_count,
        uint32 high_count
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT( (low_count <= _get_target) && (_get_target < high_count) &&
                (high_count <= TOTAL) &&
                (this->stream_is_set() == true) && (this->get_target_called() == true),
            "\tvoid entropy_decoder::decode()"
            << "\n\tRefer to the ensures clause for this function for further information."
            << "\n\tNote that _get_target refers to get_target(TOTAL)"
            << "\n\tthis:                " << this
            << "\n\tlow_count:           " << low_count
            << "\n\thigh_count:          " << high_count
            << "\n\tTOTAL:               " << TOTAL
            << "\n\tget_target(TOTAL):   " << _get_target
            << "\n\tis_stream_set():     " << (this->stream_is_set() ? "true" : "false" )
            << "\n\tget_target_called(): " << (this->get_target_called() ? "true" : "false" )
            );

        // call the real function
        decoder::decode(low_count,high_count);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename decoder
        >
    uint32 entropy_decoder_kernel_c<decoder>::
    get_target (
        uint32 total
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT( (total > 0) && (total < 65536) && (this->stream_is_set() == true),
            "\tvoid entropy_decoder::get_target()"
            << "\n\tyou must set a stream for this object before you can get the "
            << "\n\rnext target."
            << "\n\tthis: " << this
            << "\n\ttotal: " << total
            );

        // call the real function
        _get_target = decoder::get_target(total);
        TOTAL = total;
        return _get_target;
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_ENTROPY_ENCODER_KERNEl_C_


dlib C++ Library - entropy_decoder_model_kernel_1.h

// Copyright (C) 2004  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ENTROPY_DECODER_MODEL_KERNEl_1_
#define DLIB_ENTROPY_DECODER_MODEL_KERNEl_1_

#include "../algs.h"
#include "entropy_decoder_model_kernel_abstract.h"
#include "../assert.h"

namespace dlib
{

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        typename cc
        >
    class entropy_decoder_model_kernel_1
    {
        /*!
            REQUIREMENTS ON cc
                cc is an implementation of conditioning_class/conditioning_class_kernel_abstract.h
                cc::get_alphabet_size() == alphabet_size+1

            INITIAL VALUE
                Initially this object's finite context model is empty

            CONVENTION
                &get_entropy_decoder() == coder
                &order_0.get_global_state() == &gs

                This is an order-0 model. The last symbol in the order-0 context is
                an escape into the order minus 1 context.
        !*/

    public:

        typedef entropy_decoder entropy_decoder_type;

        entropy_decoder_model_kernel_1 (
            entropy_decoder& coder
        );

        virtual ~entropy_decoder_model_kernel_1 (
        );

        inline void clear(
        );

        inline void decode (
            unsigned long& symbol
        );

        entropy_decoder& get_entropy_decoder (
        ) { return coder; }

        static unsigned long get_alphabet_size (
        ) { return alphabet_size; }

    private:

        entropy_decoder& coder;
        typename cc::global_state_type gs;
        cc order_0;

        // restricted functions
        entropy_decoder_model_kernel_1(entropy_decoder_model_kernel_1<alphabet_size,entropy_decoder,cc>&);        // copy constructor
        entropy_decoder_model_kernel_1<alphabet_size,entropy_decoder,cc>& operator=(entropy_decoder_model_kernel_1<alphabet_size,entropy_decoder,cc>&);    // assignment operator

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        typename cc
        >
    entropy_decoder_model_kernel_1<alphabet_size,entropy_decoder,cc>::
    entropy_decoder_model_kernel_1 (
        entropy_decoder& coder_
    ) :
        coder(coder_),
        order_0(gs)
    {
        COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65535 );
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        typename cc
        >
    entropy_decoder_model_kernel_1<alphabet_size,entropy_decoder,cc>::
    ~entropy_decoder_model_kernel_1 (
    )
    {
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        typename cc
        >
    void entropy_decoder_model_kernel_1<alphabet_size,entropy_decoder,cc>::
    clear(
    )
    {
        order_0.clear();
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        typename cc
        >
    void entropy_decoder_model_kernel_1<alphabet_size,entropy_decoder,cc>::
    decode (
        unsigned long& symbol
    )
    {
        unsigned long current_symbol, low_count, high_count, target;

        // look in the order-0 context
        target = coder.get_target(order_0.get_total());
        order_0.get_symbol(target,current_symbol,low_count,high_count);

        // have coder decode the next symbol
        coder.decode(low_count,high_count);

        // if current_symbol is not an escape from the order-0 context
        if (current_symbol != alphabet_size)
        {
            // update the count for this symbol
            order_0.increment_count(current_symbol,2);

            symbol = current_symbol;
            return;
        }

        // update the count for the escape symbol
        order_0.increment_count(alphabet_size);

        // go into the order minus one context
        target = coder.get_target(alphabet_size);
        coder.decode(target,target+1);

        // update the count for this symbol in the order-0 context
        order_0.increment_count(target,2);

        symbol = target;

    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_ENTROPY_DECODER_MODEL_KERNEl_1_


dlib C++ Library - entropy_decoder_model_kernel_2.h

// Copyright (C) 2004  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ENTROPY_DECODER_MODEL_KERNEl_2_
#define DLIB_ENTROPY_DECODER_MODEL_KERNEl_2_

#include "../algs.h"
#include "entropy_decoder_model_kernel_abstract.h"
#include "../assert.h"

namespace dlib
{

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        typename cc,
        typename ccbig
        >
    class entropy_decoder_model_kernel_2
    {
        /*!
            REQUIREMENTS ON cc
                cc is an implementation of conditioning_class/conditioning_class_kernel_abstract.h
                cc::get_alphabet_size() == alphabet_size+1
                this will be used for the order-0 context

            REQUIREMENTS ON ccbig
                ccbig is an implementation of conditioning_class/conditioning_class_kernel_abstract.h
                ccbig::get_alphabet_size() == alphabet_size+1
                this will be used for the order-1 context

            INITIAL VALUE
                Initially this object's finite context model is empty
                previous_symbol == 0

            CONVENTION
                &get_entropy_decoder() == coder
                &order_0.get_global_state() == &gs
                &order_1[i]->get_global_state() == &gsbig

                This is an order-1-0 model. The last symbol in the order-0 and order-1
                context is an escape into the lower context.

                previous_symbol == the last symbol seen
        !*/

    public:

        typedef entropy_decoder entropy_decoder_type;

        entropy_decoder_model_kernel_2 (
            entropy_decoder& coder
        );

        virtual ~entropy_decoder_model_kernel_2 (
        );

        inline void clear(
        );

        inline void decode (
            unsigned long& symbol
        );

        entropy_decoder& get_entropy_decoder (
        ) { return coder; }

        static unsigned long get_alphabet_size (
        ) { return alphabet_size; }

    private:

        entropy_decoder& coder;
        typename cc::global_state_type gs;
        typename ccbig::global_state_type gsbig;
        cc order_0;
        ccbig* order_1[alphabet_size];
        unsigned long previous_symbol;

        // restricted functions
        entropy_decoder_model_kernel_2(entropy_decoder_model_kernel_2<alphabet_size,entropy_decoder,cc,ccbig>&);        // copy constructor
        entropy_decoder_model_kernel_2<alphabet_size,entropy_decoder,cc,ccbig>& operator=(entropy_decoder_model_kernel_2<alphabet_size,entropy_decoder,cc,ccbig>&);    // assignment operator

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        typename cc,
        typename ccbig
        >
    entropy_decoder_model_kernel_2<alphabet_size,entropy_decoder,cc,ccbig>::
    entropy_decoder_model_kernel_2 (
        entropy_decoder& coder_
    ) :
        coder(coder_),
        order_0(gs),
        previous_symbol(0)
    {
        COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65535);

        unsigned long i;
        try
        {
            for (i = 0; i < alphabet_size; ++i)
            {
                order_1[i] = new ccbig(gsbig);
            }
        }
        catch (...)
        {
            for (unsigned long j = 0; j < i; ++j)
            {
                delete order_1[j];
            }
            throw;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        typename cc,
        typename ccbig
        >
    entropy_decoder_model_kernel_2<alphabet_size,entropy_decoder,cc,ccbig>::
    ~entropy_decoder_model_kernel_2 (
    )
    {
        for (unsigned long i = 0; i < alphabet_size; ++i)
        {
            delete order_1[i];
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        typename cc,
        typename ccbig
        >
    void entropy_decoder_model_kernel_2<alphabet_size,entropy_decoder,cc,ccbig>::
    clear(
    )
    {
        previous_symbol = 0;
        order_0.clear();
        for (unsigned long i = 0; i < alphabet_size; ++i)
        {
            order_1[i]->clear();
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        typename cc,
        typename ccbig
        >
    void entropy_decoder_model_kernel_2<alphabet_size,entropy_decoder,cc,ccbig>::
    decode (
        unsigned long& symbol
    )
    {
        unsigned long current_symbol, low_count, high_count, target;

        // look in the order-1 context
        target = coder.get_target(order_1[previous_symbol]->get_total());
        order_1[previous_symbol]->get_symbol(target,current_symbol,low_count,high_count);

        // have the coder decode the next symbol
        coder.decode(low_count,high_count);

        // if the current_symbol is not an escape from the order-1 context
        if (current_symbol != alphabet_size)
        {
            symbol = current_symbol;
            order_1[previous_symbol]->increment_count(current_symbol,2);
            previous_symbol = current_symbol;
            return;
        }

        // since this is an escape to order-0 we should increment
        // the escape symbol
        order_1[previous_symbol]->increment_count(alphabet_size);

        // look in the order-0 context
        target = coder.get_target(order_0.get_total());
        order_0.get_symbol(target,current_symbol,low_count,high_count);

        // have coder decode the next symbol
        coder.decode(low_count,high_count);

        // if current_symbol is not an escape from the order-0 context
        if (current_symbol != alphabet_size)
        {
            // update the count for this symbol
            order_1[previous_symbol]->increment_count(current_symbol,2);
            order_0.increment_count(current_symbol,2);

            symbol = current_symbol;
            previous_symbol = current_symbol;
            return;
        }

        // update the count for the escape symbol
        order_0.increment_count(current_symbol);

        // go into the order minus one context
        target = coder.get_target(alphabet_size);
        coder.decode(target,target+1);

        // update the count for this symbol
        order_1[previous_symbol]->increment_count(target,2);
        order_0.increment_count(target,2);

        symbol = target;
        previous_symbol = target;

    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_ENTROPY_DECODER_MODEL_KERNEl_2_


dlib C++ Library - entropy_decoder_model_kernel_3.h

// Copyright (C) 2004  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ENTROPY_DECODER_MODEL_KERNEl_3_
#define DLIB_ENTROPY_DECODER_MODEL_KERNEl_3_

#include "../algs.h"
#include "entropy_decoder_model_kernel_abstract.h"
#include "../assert.h"

namespace dlib
{

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        typename cc,
        typename cc_high
        >
    class entropy_decoder_model_kernel_3
    {
        /*!
            REQUIREMENTS ON cc
                cc is an implementation of conditioning_class/conditioning_class_kernel_abstract.h
                cc::get_alphabet_size() == alphabet_size+1

            REQUIREMENTS ON cc_high
                cc_high is an implementation of conditioning_class/conditioning_class_kernel_abstract.h
                cc_high::get_alphabet_size() == alphabet_size+1

            INITIAL VALUE
                - Initially this object's finite context model is empty
                - previous_symbol == 0
                - previous_symbol2 == 0
                - order_1 == pointer to an array of alphabet_size elements
                - order_2 == pointer to an array of alphabet_size*alphabet_size elements
                - for all values of i: order_2[i] == 0

            CONVENTION
                &get_entropy_encoder() == coder
                &order_0.get_global_state() == &gs
                &order_1[i]->get_global_state() == &gs

                if (order_2[i] != 0) then
                    &order_2[i]->get_global_state() == &gs_high

                This is an order-2-1-0 model. The last symbol in the order-2, order-1 and
                order-0 contexts is an escape into the lower context.

                previous_symbol == the last symbol seen
                previous_symbol2 == the symbol we saw before previous_symbol
        !*/

    public:

        typedef entropy_decoder entropy_decoder_type;

        entropy_decoder_model_kernel_3 (
            entropy_decoder& coder
        );

        virtual ~entropy_decoder_model_kernel_3 (
        );

        inline void clear(
        );

        inline void decode (
            unsigned long& symbol
        );

        entropy_decoder& get_entropy_decoder (
        ) { return coder; }

        static unsigned long get_alphabet_size (
        ) { return alphabet_size; }

    private:

        entropy_decoder& coder;
        typename cc::global_state_type gs;
        typename cc_high::global_state_type gs_high;
        cc order_0;
        cc** order_1;
        unsigned long previous_symbol;
        cc_high** order_2;
        unsigned long previous_symbol2;

        // restricted functions
        entropy_decoder_model_kernel_3(entropy_decoder_model_kernel_3&);        // copy constructor
        entropy_decoder_model_kernel_3& operator=(entropy_decoder_model_kernel_3&);    // assignment operator

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        typename cc,
        typename cc_high
        >
    entropy_decoder_model_kernel_3<alphabet_size,entropy_decoder,cc,cc_high>::
    entropy_decoder_model_kernel_3 (
        entropy_decoder& coder_
    ) :
        coder(coder_),
        order_0(gs),
        order_1(0),
        previous_symbol(0),
        order_2(0),
        previous_symbol2(0)
    {
        COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65535);

        try
        {
            order_1 = new cc*[alphabet_size];
            order_2 = new cc_high*[alphabet_size*alphabet_size];
        }
        catch (...)
        {
            if (order_1) delete [] order_1;
            if (order_2) delete [] order_2;
            throw;
        }

        unsigned long i;

        for (i = 0; i < alphabet_size*alphabet_size; ++i)
        {
            order_2[i] = 0;
        }

        try
        {
            for (i = 0; i < alphabet_size; ++i)
            {
                order_1[i] = new cc(gs);
            }
        }
        catch (...)
        {
            for (unsigned long j = 0; j < i; ++j)
            {
                delete order_1[j];
            }
            throw;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        typename cc,
        typename cc_high
        >
    entropy_decoder_model_kernel_3<alphabet_size,entropy_decoder,cc,cc_high>::
    ~entropy_decoder_model_kernel_3 (
    )
    {
        for (unsigned long i = 0; i < alphabet_size; ++i)
        {
            delete order_1[i];
        }

        for (unsigned long i = 0; i < alphabet_size*alphabet_size; ++i)
        {
            if (order_2[i] != 0)
                delete order_2[i];
        }
        delete [] order_1;
        delete [] order_2;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        typename cc,
        typename cc_high
        >
    void entropy_decoder_model_kernel_3<alphabet_size,entropy_decoder,cc,cc_high>::
    clear(
    )
    {
        previous_symbol = 0;
        previous_symbol2 = 0;
        order_0.clear();
        for (unsigned long i = 0; i < alphabet_size; ++i)
        {
            order_1[i]->clear();
        }

        for (unsigned long i = 0; i < alphabet_size*alphabet_size; ++i)
        {
            if (order_2[i] != 0)
            {
                delete order_2[i];
                order_2[i] = 0;
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        typename cc,
        typename cc_high
        >
    void entropy_decoder_model_kernel_3<alphabet_size,entropy_decoder,cc,cc_high>::
    decode (
        unsigned long& symbol
    )
    {
        unsigned long current_symbol, low_count, high_count, target;

        // look in the order-2 context
        unsigned long temp = previous_symbol + (previous_symbol2 * alphabet_size);
        if (order_2[temp] != 0)
        {
            target = coder.get_target(order_2[temp]->get_total());
            order_2[temp]->get_symbol(target,current_symbol,low_count,high_count);

            // have the coder decode the next symbol
            coder.decode(low_count,high_count);

            // if the current_symbol is not an escape from the order-2 context
            if (current_symbol != alphabet_size)
            {
                symbol = current_symbol;
                order_2[temp]->increment_count(current_symbol,2);
                previous_symbol2 = previous_symbol;
                previous_symbol = current_symbol;
                return;
            }

            // since this is an escape to order-1 we should increment
            // the escape symbol
            order_2[temp]->increment_count(alphabet_size);
        }
        else
        {
            order_2[temp] = new cc_high(gs_high);
        }

        // look in the order-1 context
        target = coder.get_target(order_1[previous_symbol]->get_total());
        order_1[previous_symbol]->get_symbol(target,current_symbol,low_count,high_count);

        // have the coder decode the next symbol
        coder.decode(low_count,high_count);

        // if the current_symbol is not an escape from the order-1 context
        if (current_symbol != alphabet_size)
        {
            symbol = current_symbol;
            order_2[temp]->increment_count(current_symbol,2);
            order_1[previous_symbol]->increment_count(current_symbol,2);
            previous_symbol2 = previous_symbol;
            previous_symbol = current_symbol;
            return;
        }

        // since this is an escape to order-0 we should increment
        // the escape symbol
        order_1[previous_symbol]->increment_count(alphabet_size);

        // look in the order-0 context
        target = coder.get_target(order_0.get_total());
        order_0.get_symbol(target,current_symbol,low_count,high_count);

        // have coder decode the next symbol
        coder.decode(low_count,high_count);

        // if current_symbol is not an escape from the order-0 context
        if (current_symbol != alphabet_size)
        {
            // update the count for this symbol
            order_2[temp]->increment_count(current_symbol,2);
            order_1[previous_symbol]->increment_count(current_symbol,2);
            order_0.increment_count(current_symbol,2);

            symbol = current_symbol;
            previous_symbol2 = previous_symbol;
            previous_symbol = current_symbol;
            return;
        }

        // update the count for the escape symbol
        order_0.increment_count(current_symbol);

        // go into the order minus one context
        target = coder.get_target(alphabet_size);
        coder.decode(target,target+1);

        // update the count for this symbol
        order_2[temp]->increment_count(target,2);
        order_1[previous_symbol]->increment_count(target,2);
        order_0.increment_count(target,2);

        symbol = target;
        previous_symbol2 = previous_symbol;
        previous_symbol = target;

    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_ENTROPY_DECODER_MODEL_KERNEl_3_


dlib C++ Library - entropy_decoder_model_kernel_4.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ENTROPY_DECODER_MODEL_KERNEl_4_
#define DLIB_ENTROPY_DECODER_MODEL_KERNEl_4_

#include "../algs.h"
#include "entropy_decoder_model_kernel_abstract.h"
#include "../assert.h"

namespace dlib
{

    namespace edmk4
    {
        struct node
        {
            node* next;
            node* child_context;
            node* parent_context;

            unsigned short symbol;
            unsigned short count;
            unsigned short total;
            unsigned short escapes;
        };
    }

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        unsigned long total_nodes,
        unsigned long order
        >
    class entropy_decoder_model_kernel_4
    {
        /*!
            REQUIREMENTS ON total_nodes
                - 4096 < total_nodes
                - this is the total number of nodes that we will use in the tree

            REQUIREMENTS ON order
                - 0 <= order
                - this is the maximum depth-1 the tree will be allowed to go (note
                  that the root level is depth 0).

            GENERAL NOTES
                This implementation follows more or less the implementation
                strategy laid out by Alistair Moffat in his paper
                Implementing the PPM data compression scheme.  Published in IEEE
                Transactions on Communications, 38(11):1917-1921, 1990.

                The escape method used will be method D.

            INITIAL VALUE
                - root == pointer to an array of total_nodes nodes
                - next_node == 1
                - cur == root
                - cur_order = 0
                - root->next == 0
                - root->parent_context == 0
                - root->child_context == 0
                - root->escapes == 0
                - root->total == 0
                - stack_size == 0

            CONVENTION
                - pop() == stack[stack_size-1]
                - &get_entropy_decoder() == coder
                - root == pointer to an array of total_nodes nodes.
                  this is also the root of the tree.

                - if (next_node < total_nodes) then
                    - next_node == the next node in root that has not yet been allocated

                - root->next == 0
                - root->parent_context == 0

                - for every node in the tree:
                  {
                    - NOTATION:
                        - The "context" of a node is the string of symbols seen
                          when you go from the root of the tree down (down though
                          child context pointers) to the node, including the symbol at
                          the node itself.  (note that the context of the root node
                          is "" or the empty string)
                        - A set of nodes is in the same "context set" if all the node's
                          contexts are of length n and all the node's contexts share
                          the same prefix of length n-1.
                        - The "child context set" of a node is a set of nodes with
                          contexts that are one symbol longer and prefixed by the node's
                          context.  For example, if a node has a context "abc" then the
                          nodes for contexts "abca", "abcb", "abcc", etc. are all in
                          the child context set of the node.
                        - The "parent context" of a node is the context that is one
                          symbol shorter than the node's context and includes the
                          symbol in the node.  So the parent context of a node with
                          context "abcd" would be the context "bcd".

                    - if (next != 0) then
                        - next == pointer to the next node in the same context set
                    - if (child_context != 0) then
                        - child_context == pointer to the first node of the child
                          context set for this node.
                    - if (parent_context != 0) then
                        - parent_context == pointer to the parent context of this node.
                    - else
                        - this node is the root node of the tree

                    - if (this is not the root node) then
                        - symbol == the symbol represented with this node
                        - count == the number of times this symbol has been seen in its
                          parent context.
                    - else
                        - the root doesn't have a symbol.  i.e. the context for the
                          root node is "" or the empty string.

                    - total == The sum of the counts of all the nodes
                      in the child context set + escapes.
                    - escapes == the escape count for the context represented
                      by the node.
                }

                - cur_order < order
                - cur_order == the depth of the node cur in the tree.
                  (note that the root node has depth 0)
                - cur == pointer to the node in the tree who's context matches
                  the most recent symbols we have seen.

        !*/

        typedef edmk4::node node;

    public:

        typedef entropy_decoder entropy_decoder_type;

        entropy_decoder_model_kernel_4 (
            entropy_decoder& coder
        );

        virtual ~entropy_decoder_model_kernel_4 (
        );

        inline void clear(
        );

        inline void decode (
            unsigned long& symbol
        );

        entropy_decoder& get_entropy_decoder (
        ) { return coder; }

        static unsigned long get_alphabet_size (
        ) { return alphabet_size; }

    private:

        inline void push (
            edmk4::node* n
        );
        /*!
            requires
                - stack_size <= order
            ensures
                - #pop() == n
        !*/

        inline edmk4::node* pop (
        );
        /*!
            requires
                - stack_size > 0
            ensures
                - returns the node at the top of the stack
        !*/

        inline edmk4::node* allocate_node (
        );
        /*!
            requires
                - space_left() == true
            ensures
                - returns a pointer to a new node
        !*/

        inline void destroy_tree (
        );
        /*!
            ensures
                - deallocates all nodes except the root
                - #root->child_context == 0
                - #root->escapes == 0
                - #root->total == 0
                - #cur == root
                - #cur_order == 0
                - #stack_size == 0
        !*/

        inline bool space_left (
        ) const;
        /*!
            ensures
                - returns true if there is at least 1 free node left.
                - returns false otherwise
        !*/

        inline void scale_counts (
            node* n
        );
        /*!
            ensures
                - divides all the counts in the child context set of n by 2.
                - none of the nodes in the child context set will have a count of 0
        !*/

        entropy_decoder& coder;
        unsigned long next_node;
        node* root;
        node* cur;
        unsigned long cur_order;
        node* stack[order+1];
        unsigned long stack_size;

        // restricted functions
        entropy_decoder_model_kernel_4(entropy_decoder_model_kernel_4<alphabet_size,entropy_decoder,total_nodes,order>&);        // copy constructor
        entropy_decoder_model_kernel_4<alphabet_size,entropy_decoder,total_nodes,order>& operator=(entropy_decoder_model_kernel_4<alphabet_size,entropy_decoder,total_nodes,order>&);    // assignment operator

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        unsigned long total_nodes,
        unsigned long order
        >
    entropy_decoder_model_kernel_4<alphabet_size,entropy_decoder,total_nodes,order>::
    entropy_decoder_model_kernel_4 (
        entropy_decoder& coder_
    ) :
        coder(coder_),
        next_node(1),
        cur_order(0),
        stack_size(0)
    {
        COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65535);
        COMPILE_TIME_ASSERT( 4096 < total_nodes );

        root = new node[total_nodes];
        cur = root;

        root->child_context = 0;
        root->escapes = 0;
        root->next = 0;
        root->parent_context = 0;
        root->total = 0;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        unsigned long total_nodes,
        unsigned long order
        >
    entropy_decoder_model_kernel_4<alphabet_size,entropy_decoder,total_nodes,order>::
    ~entropy_decoder_model_kernel_4 (
    )
    {
        delete [] root;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        unsigned long total_nodes,
        unsigned long order
        >
    void entropy_decoder_model_kernel_4<alphabet_size,entropy_decoder,total_nodes,order>::
    clear(
    )
    {
        destroy_tree();
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        unsigned long total_nodes,
        unsigned long order
        >
    void entropy_decoder_model_kernel_4<alphabet_size,entropy_decoder,total_nodes,order>::
    decode (
        unsigned long& symbol
    )
    {
        node* temp = cur;
        cur = 0;
        unsigned long low_count, high_count, total_count;
        unsigned long target;
        node* new_node = 0;

        // local_order will track the level of temp in the tree
        unsigned long local_order = cur_order;

        while (true)
        {
            high_count = 0;
            if (space_left())
            {
                total_count = temp->total;

                if (total_count > 0)
                {
                    // check if we need to scale the counts
                    if (total_count > 10000)
                    {
                        scale_counts(temp);
                        total_count = temp->total;
                    }

                    target = coder.get_target(total_count);

                    // find either the symbol we are looking for or the
                    // end of the context set
                    node* n = temp->child_context;
                    node* last = 0;
                    while (true)
                    {
                        high_count += n->count;

                        if (high_count > target || n->next == 0)
                            break;
                        last = n;
                        n = n->next;
                    }

                    low_count = high_count - n->count;

                    // if we found the symbol
                    if (high_count > target)
                    {
                        if (new_node != 0)
                        {
                            new_node->parent_context = n;
                        }

                        symbol = n->symbol;

                        coder.decode(low_count,high_count);
                        n->count += 8;
                        temp->total += 8;

                        // move this node to the front
                        if (last)
                        {
                            last->next = n->next;
                            n->next = temp->child_context;
                            temp->child_context = n;
                        }

                        if (cur == 0)
                        {
                            if (local_order < order)
                            {
                                cur_order = local_order+1;
                                cur = n;
                            }
                            else
                            {
                                cur = n->parent_context;
                                cur_order = local_order;
                            }
                        }

                        break;

                    }
                    // if we hit the end of the context set without finding the symbol
                    else
                    {
                        if (new_node != 0)
                        {
                            new_node->parent_context = allocate_node();
                            new_node = new_node->parent_context;
                        }
                        else
                        {
                            new_node = allocate_node();
                        }

                        n->next = new_node;

                        // get the escape code
                        coder.decode(high_count,total_count);
                    }

                }
                else // if (total_count == 0)
                {
                    // this means that temp->child_context == 0 so we should make
                    // a new node here.
                    if (new_node != 0)
                    {
                        new_node->parent_context = allocate_node();
                        new_node = new_node->parent_context;
                    }
                    else
                    {
                        new_node = allocate_node();
                    }

                    temp->child_context = new_node;
                }

                if (cur == 0 && local_order < order)
                {
                    cur = new_node;
                    cur_order = local_order+1;
                }

                // fill out the new node
                new_node->child_context = 0;
                new_node->count = 4;
                new_node->escapes = 0;
                new_node->next = 0;
                push(new_node);
                new_node->total = 0;
                temp->escapes += 4;
                temp->total += 8;

                if (temp != root)
                {
                    temp = temp->parent_context;
                    --local_order;
                    continue;
                }

                // since this is the root we are going to the order-(-1) context
                // so we can just take care of that here.
                target = coder.get_target(alphabet_size);
                new_node->parent_context = root;
                coder.decode(target,target+1);
                symbol = target;

                if (cur == 0)
                {
                    cur = root;
                    cur_order = 0;
                }
                break;
            }
            else
            {
                // there isn't enough space so we should rebuild the tree
                destroy_tree();
                temp = cur;
                local_order = cur_order;
                cur = 0;
                new_node = 0;
            }
        } // while (true)

        while (stack_size > 0)
        {
            pop()->symbol = static_cast<unsigned short>(symbol);
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // private member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        unsigned long total_nodes,
        unsigned long order
        >
    edmk4::node* entropy_decoder_model_kernel_4<alphabet_size,entropy_decoder,total_nodes,order>::
    allocate_node (
    )
    {
        node* temp;
        temp = root + next_node;
        ++next_node;
        return temp;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        unsigned long total_nodes,
        unsigned long order
        >
    void entropy_decoder_model_kernel_4<alphabet_size,entropy_decoder,total_nodes,order>::
    destroy_tree (
    )
    {
        next_node = 1;
        root->child_context = 0;
        root->escapes = 0;
        root->total = 0;
        cur = root;
        cur_order = 0;
        stack_size = 0;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        unsigned long total_nodes,
        unsigned long order
        >
    bool entropy_decoder_model_kernel_4<alphabet_size,entropy_decoder,total_nodes,order>::
    space_left (
    ) const
    {
        return (next_node < total_nodes);
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        unsigned long total_nodes,
        unsigned long order
        >
    void entropy_decoder_model_kernel_4<alphabet_size,entropy_decoder,total_nodes,order>::
    push (
        edmk4::node* n
    )
    {
        stack[stack_size] = n;
        ++stack_size;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        unsigned long total_nodes,
        unsigned long order
        >
    edmk4::node* entropy_decoder_model_kernel_4<alphabet_size,entropy_decoder,total_nodes,order>::
    pop (
    )
    {
        --stack_size;
        return stack[stack_size];
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        unsigned long total_nodes,
        unsigned long order
        >
    void entropy_decoder_model_kernel_4<alphabet_size,entropy_decoder,total_nodes,order>::
    scale_counts (
        node* temp
    )
    {
        if (temp->escapes > 1)
            temp->escapes >>= 1;
        temp->total = temp->escapes;

        node* n = temp->child_context;
        while (n != 0)
        {
            if (n->count > 1)
                n->count >>= 1;

            temp->total += n->count;
            n = n->next;
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_ENTROPY_DECODER_MODEL_KERNEl_4_


dlib C++ Library - entropy_decoder_model_kernel_5.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ENTROPY_DECODER_MODEL_KERNEl_5_
#define DLIB_ENTROPY_DECODER_MODEL_KERNEl_5_

#include "../algs.h"
#include "entropy_decoder_model_kernel_abstract.h"
#include "../assert.h"

namespace dlib
{

    namespace edmk5
    {
        struct node
        {
            node* next;
            node* child_context;
            node* parent_context;

            unsigned short symbol;
            unsigned short count;
            unsigned short total;
            unsigned short escapes;
        };
    }

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        unsigned long total_nodes,
        unsigned long order
        >
    class entropy_decoder_model_kernel_5
    {
        /*!
            REQUIREMENTS ON total_nodes
                - 4096 < total_nodes
                - this is the total number of nodes that we will use in the tree

            REQUIREMENTS ON order
                - 0 <= order
                - this is the maximum depth-1 the tree will be allowed to go (note
                  that the root level is depth 0).

            GENERAL NOTES
                This implementation follows more or less the implementation
                strategy laid out by Alistair Moffat in his paper
                Implementing the PPM data compression scheme.  Published in IEEE
                Transactions on Communications, 38(11):1917-1921, 1990.

                The escape method used will be method D.

                This also uses Dmitry Shkarin's Information Inheritance scheme.
                (described in "PPM: one step to practicality" and "Improving the
                Efficiency of the PPM Algorithm")

            INITIAL VALUE
                - root == pointer to an array of total_nodes nodes
                - next_node == 1
                - cur == root
                - cur_order = 0
                - root->next == 0
                - root->parent_context == 0
                - root->child_context == 0
                - root->escapes == 0
                - root->total == 0
                - stack_size == 0
                - exc_used == false
                - for all i: exc[i] == 0

            CONVENTION
                - exc_used == something_is_excluded()
                - pop() == stack[stack_size-1].n and stack[stack_size-1].nc
                - is_excluded(symbol) == bit symbol&0x1F from exc[symbol>>5]
                - &get_entropy_decoder() == coder
                - root == pointer to an array of total_nodes nodes.
                  this is also the root of the tree.
                - if (next_node < total_nodes) then
                    - next_node == the next node in root that has not yet been allocated

                - root->next == 0
                - root->parent_context == 0

                - for every node in the tree:
                  {
                    - NOTATION:
                        - The "context" of a node is the string of symbols seen
                          when you go from the root of the tree down (down though
                          child context pointers) to the node, including the symbol at
                          the node itself.  (note that the context of the root node
                          is "" or the empty string)
                        - A set of nodes is in the same "context set" if all the node's
                          contexts are of length n and all the node's contexts share
                          the same prefix of length n-1.
                        - The "child context set" of a node is a set of nodes with
                          contexts that are one symbol longer and prefixed by the node's
                          context.  For example, if a node has a context "abc" then the
                          nodes for contexts "abca", "abcb", "abcc", etc. are all in
                          the child context set of the node.
                        - The "parent context" of a node is the context that is one
                          symbol shorter than the node's context and includes the
                          symbol in the node.  So the parent context of a node with
                          context "abcd" would be the context "bcd".

                    - if (next != 0) then
                        - next == pointer to the next node in the same context set
                    - if (child_context != 0) then
                        - child_context == pointer to the first node of the child
                          context set for this node.
                        - escapes > 0
                    - if (parent_context != 0) then
                        - parent_context == pointer to the parent context of this node.
                    - else
                        - this node is the root node of the tree

                    - if (this is not the root node) then
                        - symbol == the symbol represented with this node
                        - count == the number of times this symbol has been seen in its
                          parent context.
                    - else
                        - the root doesn't have a symbol.  i.e. the context for the
                          root node is "" or the empty string.

                    - total == The sum of the counts of all the nodes
                      in the child context set + escapes.
                    - escapes == the escape count for the context represented
                      by the node.
                    - count > 0
                }

                - cur_order < order
                - cur_order == the depth of the node cur in the tree.
                  (note that the root node has depth 0)
                - cur == pointer to the node in the tree who's context matches
                  the most recent symbols we have seen.

        !*/

        typedef edmk5::node node;

    public:

        typedef entropy_decoder entropy_decoder_type;

        entropy_decoder_model_kernel_5 (
            entropy_decoder& coder
        );

        virtual ~entropy_decoder_model_kernel_5 (
        );

        inline void clear(
        );

        inline void decode (
            unsigned long& symbol
        );

        entropy_decoder& get_entropy_decoder (
        ) { return coder; }

        static unsigned long get_alphabet_size (
        ) { return alphabet_size; }

    private:

        inline void push (
            node* n,
            node* nc
        );
        /*!
            requires
                - stack_size < order
            ensures
                - #pop(a,b): a == n && b == nc
        !*/

        inline void pop (
            node*& n,
            node*& nc
        );
        /*!
            requires
                - stack_size > 0
            ensures
                - returns the two nodes at the top of the stack
        !*/

        inline edmk5::node* allocate_node (
        );
        /*!
            requires
                - space_left() == true
            ensures
                - returns a pointer to a new node
        !*/

        inline bool space_left (
        ) const;
        /*!
            ensures
                - returns true if there is at least 1 free node left.
                - returns false otherwise
        !*/

        inline void exclude (
            unsigned short symbol
        );
        /*!
            ensures
                - #is_excluded(symbol) == true
                - #something_is_excluded() == true
        !*/

        inline bool is_excluded (
            unsigned short symbol
        );
        /*!
            ensures
                - if (symbol has been excluded) then
                    - returns true
                - else
                    - returns false
        !*/

        inline bool something_is_excluded (
        );
        /*!
            ensures
                - returns true if some symbol has been excluded.
                  returns false otherwise
        !*/

        inline void clear_exclusions (
        );
        /*!
            ensures
                - for all symbols #is_excluded(symbol) == false
                - #something_is_excluded() == false
        !*/

        inline void scale_counts (
            node* n
        );
        /*!
            ensures
                - divides all the counts in the child context set of n by 2.
                - none of the nodes in the child context set will have a count of 0
        !*/

        struct nodes
        {
            node* n;
            node* nc;
        };

        entropy_decoder& coder;
        unsigned long next_node;
        node* root;
        node* cur;
        unsigned long cur_order;
        unsigned long exc[alphabet_size/32+1];
        nodes stack[order+1];
        unsigned long stack_size;
        bool exc_used;

        // restricted functions
        entropy_decoder_model_kernel_5(entropy_decoder_model_kernel_5<alphabet_size,entropy_decoder,total_nodes,order>&);        // copy constructor
        entropy_decoder_model_kernel_5<alphabet_size,entropy_decoder,total_nodes,order>& operator=(entropy_decoder_model_kernel_5<alphabet_size,entropy_decoder,total_nodes,order>&);    // assignment operator

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        unsigned long total_nodes,
        unsigned long order
        >
    entropy_decoder_model_kernel_5<alphabet_size,entropy_decoder,total_nodes,order>::
    entropy_decoder_model_kernel_5 (
        entropy_decoder& coder_
    ) :
        coder(coder_),
        next_node(1),
        cur_order(0),
        stack_size(0)
    {
        COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65535);
        COMPILE_TIME_ASSERT( 4096 < total_nodes );

        root = new node[total_nodes];
        cur = root;

        root->child_context = 0;
        root->escapes = 0;
        root->next = 0;
        root->parent_context = 0;
        root->total = 0;

        clear_exclusions();
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        unsigned long total_nodes,
        unsigned long order
        >
    entropy_decoder_model_kernel_5<alphabet_size,entropy_decoder,total_nodes,order>::
    ~entropy_decoder_model_kernel_5 (
    )
    {
        delete [] root;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        unsigned long total_nodes,
        unsigned long order
        >
    void entropy_decoder_model_kernel_5<alphabet_size,entropy_decoder,total_nodes,order>::
    clear(
    )
    {
        next_node = 1;
        root->child_context = 0;
        root->escapes = 0;
        root->total = 0;
        cur = root;
        cur_order = 0;
        stack_size = 0;

        clear_exclusions();
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        unsigned long total_nodes,
        unsigned long order
        >
    void entropy_decoder_model_kernel_5<alphabet_size,entropy_decoder,total_nodes,order>::
    decode (
        unsigned long& symbol
    )
    {
        node* temp = cur;
        cur = 0;
        unsigned long low_count, high_count, total_count;
        unsigned long target;
        node* new_node = 0;

        // local_order will track the level of temp in the tree
        unsigned long local_order = cur_order;

        unsigned short c; // c == t(a|sk)
        unsigned short t; // t == T(sk)

        if (something_is_excluded())
            clear_exclusions();

        while (true)
        {
            high_count = 0;
            if (space_left())
            {
                total_count = temp->total;

                if (total_count > 0)
                {
                    // check if we need to scale the counts
                    if (total_count > 10000)
                    {
                        scale_counts(temp);
                        total_count = temp->total;
                    }

                    if (something_is_excluded())
                    {
                        node* n = temp->child_context;
                        total_count = temp->escapes;
                        while (true)
                        {
                            if (is_excluded(n->symbol) == false)
                            {
                                total_count += n->count;
                            }
                            if (n->next == 0)
                                break;
                            n = n->next;
                        }
                    }

                    target = coder.get_target(total_count);

                    // find either the symbol we are looking for or the
                    // end of the context set
                    node* n = temp->child_context;
                    node* last = 0;
                    while (true)
                    {
                        if (is_excluded(n->symbol) == false)
                        {
                            high_count += n->count;
                            exclude(n->symbol);
                        }

                        if (high_count > target || n->next == 0)
                            break;
                        last = n;
                        n = n->next;
                    }

                    // if we found the symbol
                    if (high_count > target)
                    {
                        low_count = high_count - n->count;

                        if (new_node != 0)
                        {
                            new_node->parent_context = n;
                        }

                        symbol = n->symbol;

                        coder.decode(low_count,high_count);
                        c = n->count += 8;
                        t = temp->total += 8;

                        // move this node to the front
                        if (last)
                        {
                            last->next = n->next;
                            n->next = temp->child_context;
                            temp->child_context = n;
                        }

                        if (cur == 0)
                        {
                            if (local_order < order)
                            {
                                cur_order = local_order+1;
                                cur = n;
                            }
                            else
                            {
                                cur = n->parent_context;
                                cur_order = local_order;
                            }
                        }

                        break;

                    }
                    // if we hit the end of the context set without finding the symbol
                    else
                    {
                        if (new_node != 0)
                        {
                            new_node->parent_context = allocate_node();
                            new_node = new_node->parent_context;
                        }
                        else
                        {
                            new_node = allocate_node();
                        }

                        n->next = new_node;

                        // get the escape code
                        coder.decode(high_count,total_count);
                    }

                }
                else // if (total_count == 0)
                {
                    // this means that temp->child_context == 0 so we should make
                    // a new node here.
                    if (new_node != 0)
                    {
                        new_node->parent_context = allocate_node();
                        new_node = new_node->parent_context;
                    }
                    else
                    {
                        new_node = allocate_node();
                    }

                    temp->child_context = new_node;
                }

                if (cur == 0 && local_order < order)
                {
                    cur = new_node;
                    cur_order = local_order+1;
                }

                // fill out the new node
                new_node->child_context = 0;
                new_node->escapes = 0;
                new_node->next = 0;
                push(new_node,temp);
                new_node->total = 0;

                if (temp != root)
                {
                    temp = temp->parent_context;
                    --local_order;
                    continue;
                }

                t = 2056;
                c = 8;

                // since this is the root we are going to the order-(-1) context
                // so we can just take care of that here.
                target = coder.get_target(alphabet_size);
                new_node->parent_context = root;
                coder.decode(target,target+1);
                symbol = target;

                if (cur == 0)
                {
                    cur = root;
                    cur_order = 0;
                }
                break;
            }
            else
            {
                // there isn't enough space so we should rebuild the tree
                clear();
                temp = cur;
                local_order = cur_order;
                cur = 0;
                new_node = 0;
            }
        } // while (true)

        // initialize the counts and symbol for any new nodes we have added
        // to the tree.
        node* n, *nc;
        while (stack_size > 0)
        {
            pop(n,nc);

            n->symbol = static_cast<unsigned short>(symbol);

            // if nc is not a determnistic context
            if (nc->total)
            {
                unsigned long temp2 = t-c+nc->total - nc->escapes - nc->escapes;
                unsigned long temp = nc->total;
                temp *= c;
                temp /= (temp2|1); // this oring by 1 is just to make sure that temp2 is never zero
                temp += 2;
                if (temp > 50000) temp = 50000;
                n->count = static_cast<unsigned short>(temp);

                nc->escapes += 4;
                nc->total += static_cast<unsigned short>(temp) + 4;
            }
            else
            {
                n->count = 3 + 5*(c)/(t-c);

                nc->escapes = 4;
                nc->total = n->count + 4;
            }

            while (nc->total > 10000)
            {
                scale_counts(nc);
            }
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // private member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        unsigned long total_nodes,
        unsigned long order
        >
    edmk5::node* entropy_decoder_model_kernel_5<alphabet_size,entropy_decoder,total_nodes,order>::
    allocate_node (
    )
    {
        node* temp;
        temp = root + next_node;
        ++next_node;
        return temp;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        unsigned long total_nodes,
        unsigned long order
        >
    bool entropy_decoder_model_kernel_5<alphabet_size,entropy_decoder,total_nodes,order>::
    space_left (
    ) const
    {
        return (next_node < total_nodes);
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        unsigned long total_nodes,
        unsigned long order
        >
    void entropy_decoder_model_kernel_5<alphabet_size,entropy_decoder,total_nodes,order>::
    exclude (
        unsigned short symbol
    )
    {
        exc_used = true;
        unsigned long temp = 1;
        temp <<= symbol&0x1F;
        exc[symbol>>5] |= temp;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        unsigned long total_nodes,
        unsigned long order
        >
    bool entropy_decoder_model_kernel_5<alphabet_size,entropy_decoder,total_nodes,order>::
    is_excluded (
        unsigned short symbol
    )
    {
        unsigned long temp = 1;
        temp <<= symbol&0x1F;
        return ((exc[symbol>>5]&temp) != 0);
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        unsigned long total_nodes,
        unsigned long order
        >
    void entropy_decoder_model_kernel_5<alphabet_size,entropy_decoder,total_nodes,order>::
    clear_exclusions (
    )
    {
        exc_used = false;
        for (unsigned long i = 0; i < alphabet_size/32+1; ++i)
        {
            exc[i] = 0;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        unsigned long total_nodes,
        unsigned long order
        >
    void entropy_decoder_model_kernel_5<alphabet_size,entropy_decoder,total_nodes,order>::
    push (
        node* n,
        node* nc
    )
    {
        stack[stack_size].n = n;
        stack[stack_size].nc = nc;
        ++stack_size;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        unsigned long total_nodes,
        unsigned long order
        >
    void entropy_decoder_model_kernel_5<alphabet_size,entropy_decoder,total_nodes,order>::
    pop (
        node*& n,
        node*& nc
    )
    {
        --stack_size;
        n = stack[stack_size].n;
        nc = stack[stack_size].nc;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        unsigned long total_nodes,
        unsigned long order
        >
    bool entropy_decoder_model_kernel_5<alphabet_size,entropy_decoder,total_nodes,order>::
    something_is_excluded (
    )
    {
        return exc_used;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_decoder,
        unsigned long total_nodes,
        unsigned long order
        >
    void entropy_decoder_model_kernel_5<alphabet_size,entropy_decoder,total_nodes,order>::
    scale_counts (
        node* temp
    )
    {
        if (temp->escapes > 1)
            temp->escapes >>= 1;
        temp->total = temp->escapes;

        node* n = temp->child_context;
        while (n != 0)
        {
            if (n->count > 1)
                n->count >>= 1;

            temp->total += n->count;
            n = n->next;
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_ENTROPY_DECODER_MODEL_KERNEl_5_


dlib C++ Library - entropy_decoder_model_kernel_6.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ENTROPY_DECODER_MODEL_KERNEl_6_
#define DLIB_ENTROPY_DECODER_MODEL_KERNEl_6_

#include "../algs.h"
#include "entropy_decoder_model_kernel_abstract.h"
#include "../assert.h"

namespace dlib
{

    template <
        unsigned long alphabet_size,
        typename entropy_decoder
        >
    class entropy_decoder_model_kernel_6
    {
        /*!
            INITIAL VALUE
                This object has no state

            CONVENTION
                &get_entropy_decoder() == coder

                This is an order-(-1) model.  So it doesn't really do anything.
                Every symbol has the same probability.
        !*/

    public:

        typedef entropy_decoder entropy_decoder_type;

        entropy_decoder_model_kernel_6 (
            entropy_decoder& coder
        );

        virtual ~entropy_decoder_model_kernel_6 (
        );

        inline void clear(
        );

        inline void decode (
            unsigned long& symbol
        );

        entropy_decoder& get_entropy_decoder (
        ) { return coder; }

        static unsigned long get_alphabet_size (
        ) { return alphabet_size; }

    private:

        entropy_decoder& coder;

        // restricted functions
        entropy_decoder_model_kernel_6(entropy_decoder_model_kernel_6<alphabet_size,entropy_decoder>&);        // copy constructor
        entropy_decoder_model_kernel_6<alphabet_size,entropy_decoder>& operator=(entropy_decoder_model_kernel_6<alphabet_size,entropy_decoder>&);    // assignment operator

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_decoder
        >
    entropy_decoder_model_kernel_6<alphabet_size,entropy_decoder>::
    entropy_decoder_model_kernel_6 (
        entropy_decoder& coder_
    ) :
        coder(coder_)
    {
        COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65535 );
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_decoder
        >
    entropy_decoder_model_kernel_6<alphabet_size,entropy_decoder>::
    ~entropy_decoder_model_kernel_6 (
    )
    {
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_decoder
        >
    void entropy_decoder_model_kernel_6<alphabet_size,entropy_decoder>::
    clear(
    )
    {
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_decoder
        >
    void entropy_decoder_model_kernel_6<alphabet_size,entropy_decoder>::
    decode (
        unsigned long& symbol
    )
    {
        unsigned long target;

        target = coder.get_target(alphabet_size);
        coder.decode(target,target+1);

        symbol = target;
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_ENTROPY_DECODER_MODEL_KERNEl_6_


dlib C++ Library - entropy_encoder_kernel_1.cpp

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ENTROPY_ENCODER_KERNEL_1_CPp_
#define DLIB_ENTROPY_ENCODER_KERNEL_1_CPp_
#include "entropy_encoder_kernel_1.h"
#include <iostream>
#include <streambuf>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    entropy_encoder_kernel_1::
    entropy_encoder_kernel_1(
    ) :
        initial_low(0x00000001),
        initial_high(0xffffffff),
        out(0),
        low(initial_low),
        high(initial_high),
        buf(0),
        buf_used(0)
    {
    }

// ----------------------------------------------------------------------------------------

    entropy_encoder_kernel_1::
    ~entropy_encoder_kernel_1 (
    )
    {
        try {
            if (out != 0)
            {
                flush();
            }
        } catch (...) {}
    }

// ----------------------------------------------------------------------------------------

    void entropy_encoder_kernel_1::
    clear(
    )
    {
        if (out != 0)
        {
            flush();
        }
        out = 0;
    }

// ----------------------------------------------------------------------------------------

    void entropy_encoder_kernel_1::
    set_stream (
        std::ostream& out_
    )
    {
        if (out != 0)
        {
            // if a stream is currently set then flush the buffers to it before
            // we switch to the new stream
            flush();
        }

        out = &out_;
        streambuf = out_.rdbuf();

        // reset the encoder state
        buf_used = 0;
        buf = 0;
        low = initial_low;
        high = initial_high;
    }

// ----------------------------------------------------------------------------------------

    bool entropy_encoder_kernel_1::
    stream_is_set (
    ) const
    {
        if (out != 0)
            return true;
        else
            return false;
    }

// ----------------------------------------------------------------------------------------

    std::ostream& entropy_encoder_kernel_1::
    get_stream (
    ) const
    {
        return *out;
    }

// ----------------------------------------------------------------------------------------

    void entropy_encoder_kernel_1::
    encode (
        uint32 low_count,
        uint32 high_count,
        uint32 total
    )
    {
        // note that we must add one because of the convention that
        // high == the real upper range minus 1
        uint32 r = (high-low+1)/total;

        // note that we must subtract 1 to preserve the convention that
        // high == the real upper range - 1
        high = low + r*high_count-1;
        low = low + r*low_count;

        while (true)
        {

            // if the highest order bit in high and low is the same
            if ( low >= 0x80000000 || high < 0x80000000)
            {
                // if buf is full then write it out
                if (buf_used == 8)
                {
                    if (streambuf->sputn(reinterpret_cast<char*>(&buf),1)==0)
                    {
                        throw std::ios_base::failure("error occured in the entropy_encoder object");
                    }
                    buf = 0;
                    buf_used = 0;
                }

                // write the high order bit from low into buf
                buf <<= 1;
                ++buf_used;
                if (low&0x80000000)
                    buf |= 0x1;

                // roll off the bit we just wrote to buf
                low <<= 1;
                high <<= 1;
                high |= 1;     // note that it is ok to add one to high here because
                            // of the convention that high == real upper range - 1.
                            // so that means that if we want to shift the upper range
                            // left by one then we must shift a one into high also
                            // since real upper range == high + 0.999999999...

                // make sure low is never zero
                if (low == 0)
                    low = 1;
            }
            // if the distance between high and low is small and there aren't
            // any bits we can roll off then round low up or high down.
            else if (high-low < 0x10000)
            {
                if (high == 0x80000000)
                    high = 0x7fffffff;
                else
                    low = 0x80000000;
            }
            else
            {
                break;
            }
        } // while (true)

    }

// ----------------------------------------------------------------------------------------

    void entropy_encoder_kernel_1::
    flush (
    )
    {
        // flush the next 4 or 5 bytes that are buffered
        // thats whatever is contained in buf and then all of low plus any extra
        // bits needed to pad that to be an even 4 or 5 bytes

        if (buf_used != 8)
        {
            buf <<= (8-buf_used);
            buf |= static_cast<unsigned char>(low>>(24+buf_used));
            low <<= (8-buf_used);
        }

        if (streambuf->sputn(reinterpret_cast<char*>(&buf),1) == 0)
            throw std::ios_base::failure("error occured in the entropy_encoder object");

        buf = static_cast<unsigned char>((low >> 24)&0xFF);
        if (streambuf->sputn(reinterpret_cast<char*>(&buf),1) == 0)
            throw std::ios_base::failure("error occured in the entropy_encoder object");

        buf = static_cast<unsigned char>((low >> 16)&0xFF);
        if (streambuf->sputn(reinterpret_cast<char*>(&buf),1)==0)
            throw std::ios_base::failure("error occured in the entropy_encoder object");

        buf = static_cast<unsigned char>((low >> 8)&0xFF);
        if (streambuf->sputn(reinterpret_cast<char*>(&buf),1)==0)
            throw std::ios_base::failure("error occured in the entropy_encoder object");

        if (buf_used != 0)
        {
            buf = static_cast<unsigned char>((low)&0xFF);
            if (streambuf->sputn(reinterpret_cast<char*>(&buf),1)==0)
                throw std::ios_base::failure("error occured in the entropy_encoder object");
        }

        // make sure the stream buffer flushes to its I/O channel
        streambuf->pubsync();

        // reset the encoder state
        buf_used = 0;
        buf = 0;
        low = initial_low;
        high = initial_high;
    }

// ----------------------------------------------------------------------------------------

}
#endif // DLIB_ENTROPY_ENCODER_KERNEL_1_CPp_


dlib C++ Library - entropy_encoder_kernel_1.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ENTROPY_ENCODER_KERNEl_1_
#define DLIB_ENTROPY_ENCODER_KERNEl_1_

#include "../algs.h"
#include "entropy_encoder_kernel_abstract.h"
#include <iosfwd>
#include "../uintn.h"

namespace dlib
{

    class entropy_encoder_kernel_1
    {
        /*!
            GENERAL NOTES
                this encoder is implemented using arithmetic coding

            INITIAL VALUE
                out      == 0
                buf_used == 0
                buf      == 0
                initial_low      == 0x00000001  (slightly more than zero)
                initial_high     == 0xffffffff  (slightly less than one, 0.99999999976717)
                low      == initial_low
                high     == initial_high

            CONVENTION
                if (out != 0)
                    *out      == get_stream()
                    true      == stream_is_set()
                    streambuf == out->rdbuf()
                else
                    false     == stream_is_set()

                buf      == used to accumulate bits before writing them to out.
                buf_used == the number of low order bits in buf that are currently
                            in use
                low      == the low end of the range used for arithmetic encoding.
                            this number is used as a 32bit fixed point real number.
                            the point is fixed just before the first bit, so it is
                            always in the range [0,1)

                            low is also never allowed to be zero to avoid overflow
                            in the calculation (high-low+1)/total.

                high     == the high end of the range - 1 used for arithmetic encoding.
                            this number is used as a 32bit fixed point real number.
                            the point is fixed just before the first bit, so when we
                            interpret high as a real number then it is always in the
                            range [0,1)

                            the range for arithmetic encoding is always
                            [low,high + 0.9999999...)   the 0.9999999... is why
                            high == real upper range - 1

        !*/

    public:

        entropy_encoder_kernel_1 (
        );

        virtual ~entropy_encoder_kernel_1 (
        );

        void clear(
        );

        void set_stream (
            std::ostream& out
        );

        bool stream_is_set (
        ) const;

        std::ostream& get_stream (
        ) const;

        void encode (
            uint32 low_count,
            uint32 high_count,
            uint32 total
        );

    private:

        void flush (
        );
        /*!
            requires
                out != 0 (i.e.  there is a stream object to flush the data to
        !*/

        // restricted functions
        entropy_encoder_kernel_1(entropy_encoder_kernel_1&);        // copy constructor
        entropy_encoder_kernel_1& operator=(entropy_encoder_kernel_1&);    // assignment operator

        // data members
        const uint32 initial_low;
        const uint32 initial_high;
        std::ostream* out;
        uint32 low;
        uint32 high;
        unsigned char buf;
        uint32 buf_used;
        std::streambuf* streambuf;

    };

}

#ifdef NO_MAKEFILE
#include "entropy_encoder_kernel_1.cpp"
#endif

#endif // DLIB_ENTROPY_ENCODER_KERNEl_1_


dlib C++ Library - entropy_encoder_kernel_2.cpp

// Copyright (C) 2004  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ENTROPY_ENCODER_KERNEL_2_CPp_
#define DLIB_ENTROPY_ENCODER_KERNEL_2_CPp_
#include "entropy_encoder_kernel_2.h"
#include <iostream>
#include <streambuf>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    entropy_encoder_kernel_2::
    entropy_encoder_kernel_2(
    ) :
        initial_low(0x00000001),
        initial_high(0xffffffff),
        out(0),
        low(initial_low),
        high(initial_high)
    {
    }

// ----------------------------------------------------------------------------------------

    entropy_encoder_kernel_2::
    ~entropy_encoder_kernel_2 (
    )
    {
        try {
            if (out != 0)
            {
                flush();
            }
        } catch (...) {}
    }

// ----------------------------------------------------------------------------------------

    void entropy_encoder_kernel_2::
    clear(
    )
    {
        if (out != 0)
        {
            flush();
        }
        out = 0;
    }

// ----------------------------------------------------------------------------------------

    void entropy_encoder_kernel_2::
    set_stream (
        std::ostream& out_
    )
    {
        if (out != 0)
        {
            // if a stream is currently set then flush the buffers to it before
            // we switch to the new stream
            flush();
        }

        out = &out_;
        streambuf = out_.rdbuf();

        // reset the encoder state
        low = initial_low;
        high = initial_high;
    }

// ----------------------------------------------------------------------------------------

    bool entropy_encoder_kernel_2::
    stream_is_set (
    ) const
    {
        if (out != 0)
            return true;
        else
            return false;
    }

// ----------------------------------------------------------------------------------------

    std::ostream& entropy_encoder_kernel_2::
    get_stream (
    ) const
    {
        return *out;
    }

// ----------------------------------------------------------------------------------------

    void entropy_encoder_kernel_2::
    encode (
        uint32 low_count,
        uint32 high_count,
        uint32 total
    )
    {
        // note that we must add one because of the convention that
        // high == the real upper range minus 1
        uint32 r = (high-low+1)/total;

        // note that we must subtract 1 to preserve the convention that
        // high == the real upper range - 1
        high = low + r*high_count-1;
        low = low + r*low_count;

        while (true )
        {

            // if high and low don't have the same 8 high order bits
            if ((high&0xFF000000) != (low&0xFF000000))
            {
                // if the distance between high and low is small and there aren't
                // any bits we can roll off then force high and low to have common high
                // order bits.
                if ((high-low < 0x10000))
                {
                    if (high-low > 0x1000)
                    {
                        high>>=1;
                        low>>=1;
                        high = low = high+low;
                        high += 0xFF;
                        low -= 0xFF;
                    }
                    else /**/
                    {
                        high>>=1;
                        low>>=1;
                        high = low = high+low;
                    }
                }
                else
                {
                    // there are no bits to roll off and high and low are not
                    // too close so just quit the loop
                    break;
                }

            }
            // else if there are 8 bits we can roll off
            else
            {
                // write the 8 high order bits from low into buf
                unsigned char buf = static_cast<unsigned char>(low>>24);

                // roll off the bits we just wrote to buf
                high <<= 8;
                low <<= 8;
                high |= 0xFF;  // note that it is ok to add 0xFF to high here because
                            // of the convention that high == real upper range - 1.
                            // so that means that if we want to shift the upper range
                            // left by one then we must shift a one into high also
                            // since real upper range == high + 0.999999999...

                // make sure low is never zero
                if (low == 0)
                    low = 1;

                // write buf to the output stream
                if (streambuf->sputn(reinterpret_cast<char*>(&buf),1)==0)
                {
                    throw std::ios_base::failure("error occured in the entropy_encoder object");
                }

            }

        } // while (true)

    }

// ----------------------------------------------------------------------------------------

    void entropy_encoder_kernel_2::
    flush (
    )
    {

        // flush low to the output stream

        unsigned char buf;

        buf = static_cast<unsigned char>((low >> 24)&0xFF);
        if (streambuf->sputn(reinterpret_cast<char*>(&buf),1) == 0)
            throw std::ios_base::failure("error occured in the entropy_encoder object");

        buf = static_cast<unsigned char>((low >> 16)&0xFF);
        if (streambuf->sputn(reinterpret_cast<char*>(&buf),1)==0)
            throw std::ios_base::failure("error occured in the entropy_encoder object");

        buf = static_cast<unsigned char>((low >> 8)&0xFF);
        if (streambuf->sputn(reinterpret_cast<char*>(&buf),1)==0)
            throw std::ios_base::failure("error occured in the entropy_encoder object");

        buf = static_cast<unsigned char>((low)&0xFF);
        if (streambuf->sputn(reinterpret_cast<char*>(&buf),1)==0)
            throw std::ios_base::failure("error occured in the entropy_encoder object");

        // make sure the stream buffer flushes to its I/O channel
        streambuf->pubsync();

        // reset the encoder state
        low = initial_low;
        high = initial_high;
    }

// ----------------------------------------------------------------------------------------

}
#endif // DLIB_ENTROPY_ENCODER_KERNEL_2_CPp_


dlib C++ Library - entropy_encoder_kernel_2.h

// Copyright (C) 2004  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ENTROPY_ENCODER_KERNEl_2_
#define DLIB_ENTROPY_ENCODER_KERNEl_2_

#include "../algs.h"
#include "entropy_encoder_kernel_abstract.h"
#include <iosfwd>
#include "../uintn.h"

namespace dlib
{

    class entropy_encoder_kernel_2
    {
        /*!
            GENERAL NOTES
                this encoder is implemented using "range" coding

            INITIAL VALUE
                out      == 0
                initial_low      == 0x00000001  (slightly more than zero)
                initial_high     == 0xffffffff  (slightly less than one, 0.99999999976717)
                low      == initial_low
                high     == initial_high

            CONVENTION
                if (out != 0)
                    *out      == get_stream()
                    true      == stream_is_set()
                    streambuf == out->rdbuf()
                else
                    false     == stream_is_set()

                low      == the low end of the range used for arithmetic encoding.
                            this number is used as a 32bit fixed point real number.
                            the point is fixed just before the first bit, so it is
                            always in the range [0,1)

                            low is also never allowed to be zero to avoid overflow
                            in the calculation (high-low+1)/total.

                high     == the high end of the range - 1 used for arithmetic encoding.
                            this number is used as a 32bit fixed point real number.
                            the point is fixed just before the first bit, so when we
                            interpret high as a real number then it is always in the
                            range [0,1)

                            the range for arithmetic encoding is always
                            [low,high + 0.9999999...)   the 0.9999999... is why
                            high == real upper range - 1
         !*/

    public:

        entropy_encoder_kernel_2 (
        );

        virtual ~entropy_encoder_kernel_2 (
        );

        void clear(
        );

        void set_stream (
            std::ostream& out
        );

        bool stream_is_set (
        ) const;

        std::ostream& get_stream (
        ) const;

        void encode (
            uint32 low_count,
            uint32 high_count,
            uint32 total
        );

    private:

        void flush (
        );
        /*!
            requires
                out != 0 (i.e.  there is a stream object to flush the data to
        !*/

        // restricted functions
        entropy_encoder_kernel_2(entropy_encoder_kernel_2&);        // copy constructor
        entropy_encoder_kernel_2& operator=(entropy_encoder_kernel_2&);    // assignment operator

        // data members
        const uint32 initial_low;
        const uint32 initial_high;
        std::ostream* out;
        uint32 low;
        uint32 high;
        std::streambuf* streambuf;

    };

}

#ifdef NO_MAKEFILE
#include "entropy_encoder_kernel_2.cpp"
#endif

#endif // DLIB_ENTROPY_ENCODER_KERNEl_2_


dlib C++ Library - entropy_encoder_kernel_c.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ENTROPY_ENCODER_KERNEl_C_
#define DLIB_ENTROPY_ENCODER_KERNEl_C_

#include "entropy_encoder_kernel_abstract.h"
#include "../algs.h"
#include "../assert.h"
#include <iostream>

namespace dlib
{

    template <
        typename encoder
        >
    class entropy_encoder_kernel_c : public encoder
    {

        public:
            std::ostream& get_stream (
            ) const;

            void encode (
                uint32 low_count,
                uint32 high_count,
                uint32 total
            );

            void flush (
            );

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename encoder
        >
    std::ostream& entropy_encoder_kernel_c<encoder>::
    get_stream (
    ) const
    {
        // make sure requires clause is not broken
        DLIB_CASSERT( this->stream_is_set() == true,
            "\tstd::ostream& entropy_encoder::get_stream()"
            << "\n\tyou must set a stream for this object before you can get it"
            << "\n\tthis: " << this
            );

        // call the real function
        return encoder::get_stream();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename encoder
        >
    void entropy_encoder_kernel_c<encoder>::
    encode (
        uint32 low_count,
        uint32 high_count,
        uint32 total
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT( (0 < total) && (total < 65536) && (low_count < high_count) && (high_count <= total) &&
                (this->stream_is_set() == true),
            "\tvoid entropy_encoder::encode()"
            << "\n\trefer to the ensures clause for this function for further information"
            << "\n\tthis:            " << this
            << "\n\ttotal:           " << total
            << "\n\tlow_count:       " << low_count
            << "\n\thigh_count:      " << high_count
            << "\n\tis_stream_set(): " << (this->stream_is_set() ? "true" : "false" )
            );

        // call the real function
        encoder::encode(low_count,high_count,total);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename encoder
        >
    void entropy_encoder_kernel_c<encoder>::
    flush (
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT( this->stream_is_set() == true,
            "\tvoid entropy_encoder::flush()"
            << "\n\tyou must set a stream for this object before you can flush to it"
            << "\n\tthis: " << this
            );

        // call the real function
        encoder::flush();
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_ENTROPY_ENCODER_KERNEl_C_


dlib C++ Library - entropy_encoder_model_kernel_1.h

// Copyright (C) 2004  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ENTROPY_ENCODER_MODEL_KERNEl_1_
#define DLIB_ENTROPY_ENCODER_MODEL_KERNEl_1_

#include "../algs.h"
#include "entropy_encoder_model_kernel_abstract.h"
#include "../assert.h"

namespace dlib
{

    template <
        unsigned long alphabet_size,
        typename entropy_encoder,
        typename cc
        >
    class entropy_encoder_model_kernel_1
    {
        /*!
            REQUIREMENTS ON cc
                cc is an implementation of conditioning_class/conditioning_class_kernel_abstract.h
                cc::get_alphabet_size() == alphabet_size+1

            INITIAL VALUE
                Initially this object's finite context model is empty

            CONVENTION
                &get_entropy_encoder() == coder
                &order_0.get_global_state() == &gs

                This is an order-0 model. The last symbol in the order-0 context is
                an escape into the order minus 1 context.
        !*/

    public:

        typedef entropy_encoder entropy_encoder_type;

        entropy_encoder_model_kernel_1 (
            entropy_encoder& coder
        );

        virtual ~entropy_encoder_model_kernel_1 (
        );

        inline void clear(
        );

        inline void encode (
            unsigned long symbol
        );

        entropy_encoder& get_entropy_encoder (
        ) { return coder; }

        static unsigned long get_alphabet_size (
        ) { return alphabet_size; }

    private:

        entropy_encoder& coder;
        typename cc::global_state_type gs;
        cc order_0;

        // restricted functions
        entropy_encoder_model_kernel_1(entropy_encoder_model_kernel_1<alphabet_size,entropy_encoder,cc>&);        // copy constructor
        entropy_encoder_model_kernel_1<alphabet_size,entropy_encoder,cc>& operator=(entropy_encoder_model_kernel_1<alphabet_size,entropy_encoder,cc>&);    // assignment operator

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_encoder,
        typename cc
        >
    entropy_encoder_model_kernel_1<alphabet_size,entropy_encoder,cc>::
    entropy_encoder_model_kernel_1 (
        entropy_encoder& coder_
    ) :
        coder(coder_),
        order_0(gs)
    {
        COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65535 );
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_encoder,
        typename cc
        >
    entropy_encoder_model_kernel_1<alphabet_size,entropy_encoder,cc>::
    ~entropy_encoder_model_kernel_1 (
    )
    {
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_encoder,
        typename cc
        >
    void entropy_encoder_model_kernel_1<alphabet_size,entropy_encoder,cc>::
    clear(
    )
    {
        order_0.clear();
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_encoder,
        typename cc
        >
    void entropy_encoder_model_kernel_1<alphabet_size,entropy_encoder,cc>::
    encode (
        unsigned long symbol
    )
    {
        unsigned long low_count = 0, high_count = 0, total_count = 0;

        // if we have seen this symbol in the order-0 context
        if (order_0.get_range(symbol,low_count,high_count,total_count))
        {
            // update the count for this symbol
            order_0.increment_count(symbol,2);
            // encode this symbol
            coder.encode(low_count,high_count,total_count);
            return;
        }

        // if we are here then the symbol does not appear in the order-0 context

        // since we have never seen the current symbol in this context
        // escape from order-0 context
        order_0.get_range(alphabet_size,low_count,high_count,total_count);
        coder.encode(low_count,high_count,total_count);
        // increment the count for the escape symbol
        order_0.increment_count(alphabet_size);

        // update the count for this symbol
        order_0.increment_count(symbol,2);

        // use order minus one context
        coder.encode(symbol,symbol+1,alphabet_size);

    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_ENTROPY_ENCODER_MODEL_KERNEl_1_


dlib C++ Library - entropy_encoder_model_kernel_2.h

// Copyright (C) 2004  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ENTROPY_ENCODER_MODEL_KERNEl_2_
#define DLIB_ENTROPY_ENCODER_MODEL_KERNEl_2_

#include "../algs.h"
#include "entropy_encoder_model_kernel_abstract.h"
#include "../assert.h"

namespace dlib
{

    template <
        unsigned long alphabet_size,
        typename entropy_encoder,
        typename cc,
        typename ccbig
        >
    class entropy_encoder_model_kernel_2
    {
        /*!
            REQUIREMENTS ON cc
                cc is an implementation of conditioning_class/conditioning_class_kernel_abstract.h
                cc::get_alphabet_size() == alphabet_size+1
                this will be used for the order-0 context

            REQUIREMENTS ON ccbig
                ccbig is an implementation of conditioning_class/conditioning_class_kernel_abstract.h
                ccbig::get_alphabet_size() == alphabet_size+1
                this will be used for the order-1 context

            INITIAL VALUE
                Initially this object's finite context model is empty
                previous_symbol == 0

            CONVENTION
                &get_entropy_encoder() == coder
                &order_0.get_global_state() == &gs
                &order_1[i]->get_global_state() == &gsbig

                This is an order-1-0 model. The last symbol in the order-0 and order-1
                context is an escape into the lower context.

                previous_symbol == the last symbol seen
        !*/

    public:

        typedef entropy_encoder entropy_encoder_type;

        entropy_encoder_model_kernel_2 (
            entropy_encoder& coder
        );

        virtual ~entropy_encoder_model_kernel_2 (
        );

        inline void clear(
        );

        inline void encode (
            unsigned long symbol
        );

        entropy_encoder& get_entropy_encoder (
        ) { return coder; }

        static unsigned long get_alphabet_size (
        ) { return alphabet_size; }

    private:

        entropy_encoder& coder;
        typename cc::global_state_type gs;
        typename ccbig::global_state_type gsbig;
        cc order_0;
        ccbig* order_1[alphabet_size];
        unsigned long previous_symbol;

        // restricted functions
        entropy_encoder_model_kernel_2(entropy_encoder_model_kernel_2<alphabet_size,entropy_encoder,cc,ccbig>&);        // copy constructor
        entropy_encoder_model_kernel_2<alphabet_size,entropy_encoder,cc,ccbig>& operator=(entropy_encoder_model_kernel_2<alphabet_size,entropy_encoder,cc,ccbig>&);    // assignment operator

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_encoder,
        typename cc,
        typename ccbig
        >
    entropy_encoder_model_kernel_2<alphabet_size,entropy_encoder,cc,ccbig>::
    entropy_encoder_model_kernel_2 (
        entropy_encoder& coder_
    ) :
        coder(coder_),
        order_0(gs),
        previous_symbol(0)
    {
        COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65535 );

        unsigned long i;
        try
        {
            for (i = 0; i < alphabet_size; ++i)
            {
                order_1[i] = new ccbig(gsbig);
            }
        }
        catch (...)
        {
            for (unsigned long j = 0; j < i; ++j)
            {
                delete order_1[j];
            }
            throw;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_encoder,
        typename cc,
        typename ccbig
        >
    entropy_encoder_model_kernel_2<alphabet_size,entropy_encoder,cc,ccbig>::
    ~entropy_encoder_model_kernel_2 (
    )
    {
        for (unsigned long i = 0; i < alphabet_size; ++i)
        {
            delete order_1[i];
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_encoder,
        typename cc,
        typename ccbig
        >
    void entropy_encoder_model_kernel_2<alphabet_size,entropy_encoder,cc,ccbig>::
    clear(
    )
    {
        previous_symbol = 0;
        order_0.clear();
        for (unsigned long i = 0; i < alphabet_size; ++i)
        {
            order_1[i]->clear();
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_encoder,
        typename cc,
        typename ccbig
        >
    void entropy_encoder_model_kernel_2<alphabet_size,entropy_encoder,cc,ccbig>::
    encode (
        unsigned long symbol
    )
    {
        unsigned long low_count = 0, high_count = 0, total_count = 0;

        ccbig& context = *order_1[previous_symbol];

        // if we have seen this symbol in the order-1 context
        if (context.get_range(symbol,low_count,high_count,total_count))
        {
            // update the count for this symbol
            context.increment_count(symbol,2);
            // encode this symbol
            coder.encode(low_count,high_count,total_count);
            previous_symbol = symbol;
            return;
        }

        // we didn't find the symbol in the order-1 context so we must escape to a
        // lower context.

        // escape to the order-0 context
        context.get_range(alphabet_size,low_count,high_count,total_count);
        coder.encode(low_count,high_count,total_count);

        // increment counts for the escape symbol and the current symbol
        context.increment_count(alphabet_size);
        context.increment_count(symbol,2);

        previous_symbol = symbol;

        // if we have seen this symbol in the order-0 context
        if (order_0.get_range(symbol,low_count,high_count,total_count))
        {
            // update the count for this symbol
            order_0.increment_count(symbol,2);
            // encode this symbol
            coder.encode(low_count,high_count,total_count);
            return;
        }

        // if we are here then the symbol does not appear in the order-0 context

        // since we have never seen the current symbol in this context
        // escape from order-0 context
        order_0.get_range(alphabet_size,low_count,high_count,total_count);
        coder.encode(low_count,high_count,total_count);
        // increment the count for the escape symbol
        order_0.increment_count(alphabet_size);

        // update the count for this symbol
        order_0.increment_count(symbol,2);

        // use order minus one context
        coder.encode(symbol,symbol+1,alphabet_size);

    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_ENTROPY_ENCODER_MODEL_KERNEl_2_


dlib C++ Library - entropy_encoder_model_kernel_3.h

// Copyright (C) 2004  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ENTROPY_ENCODER_MODEL_KERNEl_3_
#define DLIB_ENTROPY_ENCODER_MODEL_KERNEl_3_

#include "../algs.h"
#include "entropy_encoder_model_kernel_abstract.h"
#include "../assert.h"

namespace dlib
{

    template <
        unsigned long alphabet_size,
        typename entropy_encoder,
        typename cc,
        typename cc_high
        >
    class entropy_encoder_model_kernel_3
    {
        /*!
            REQUIREMENTS ON cc
                cc is an implementation of conditioning_class/conditioning_class_kernel_abstract.h
                cc::get_alphabet_size() == alphabet_size+1

            REQUIREMENTS ON cc_high
                cc_high is an implementation of conditioning_class/conditioning_class_kernel_abstract.h
                cc_high::get_alphabet_size() == alphabet_size+1

            INITIAL VALUE
                - Initially this object's finite context model is empty
                - previous_symbol == 0
                - previous_symbol2 == 0
                - order_1 == pointer to an array of alphabet_size elements
                - order_2 == pointer to an array of alphabet_size*alphabet_size elements
                - order_2[i] == 0

            CONVENTION
                &get_entropy_encoder() == coder
                &order_0.get_global_state() == &gs
                &order_1[i]->get_global_state() == &gs

                if (order_2[i] != 0) then
                    &order_2[i]->get_global_state() == &gs_high

                This is an order-2-1-0 model. The last symbol in the order-2, order-1 and
                order-0 contexts is an escape into the lower context.

                previous_symbol == the last symbol seen
                previous_symbol2 == the symbol we saw before previous_symbol
        !*/

    public:

        typedef entropy_encoder entropy_encoder_type;

        entropy_encoder_model_kernel_3 (
            entropy_encoder& coder
        );

        virtual ~entropy_encoder_model_kernel_3 (
        );

        inline void clear(
        );

        inline void encode (
            unsigned long symbol
        );

        entropy_encoder& get_entropy_encoder (
        ) { return coder; }

        static unsigned long get_alphabet_size (
        ) { return alphabet_size; }

    private:

        entropy_encoder& coder;
        typename cc::global_state_type gs;
        typename cc_high::global_state_type gs_high;
        cc order_0;
        cc** order_1;
        unsigned long previous_symbol;
        cc_high** order_2;
        unsigned long previous_symbol2;

        // restricted functions
        entropy_encoder_model_kernel_3(entropy_encoder_model_kernel_3&);        // copy constructor
        entropy_encoder_model_kernel_3& operator=(entropy_encoder_model_kernel_3&);    // assignment operator

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_encoder,
        typename cc,
        typename cc_high
        >
    entropy_encoder_model_kernel_3<alphabet_size,entropy_encoder,cc,cc_high>::
    entropy_encoder_model_kernel_3 (
        entropy_encoder& coder_
    ) :
        coder(coder_),
        order_0(gs),
        order_1(0),
        previous_symbol(0),
        order_2(0),
        previous_symbol2(0)
    {
        COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65535 );

        try
        {
            order_1 = new cc*[alphabet_size];
            order_2 = new cc_high*[alphabet_size*alphabet_size];
        }
        catch (...)
        {
            if (order_1) delete [] order_1;
            if (order_2) delete [] order_2;
            throw;
        }

        unsigned long i;

        for (i = 0; i < (alphabet_size*alphabet_size); ++i)
        {
            order_2[i] = 0;
        }

        try
        {
            for (i = 0; i < alphabet_size; ++i)
            {
                order_1[i] = new cc(gs);
            }
        }
        catch (...)
        {
            for (unsigned long j = 0; j < i; ++j)
            {
                delete order_1[j];
            }
            throw;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_encoder,
        typename cc,
        typename cc_high
        >
    entropy_encoder_model_kernel_3<alphabet_size,entropy_encoder,cc,cc_high>::
    ~entropy_encoder_model_kernel_3 (
    )
    {
        for (unsigned long i = 0; i < alphabet_size; ++i)
        {
            delete order_1[i];
        }

        for (unsigned long i = 0; i < alphabet_size*alphabet_size; ++i)
        {
            if (order_2[i] != 0)
                delete order_2[i];
        }
        delete [] order_1;
        delete [] order_2;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_encoder,
        typename cc,
        typename cc_high
        >
    void entropy_encoder_model_kernel_3<alphabet_size,entropy_encoder,cc,cc_high>::
    clear(
    )
    {
        previous_symbol = 0;
        previous_symbol2 = 0;
        order_0.clear();
        for (unsigned long i = 0; i < alphabet_size; ++i)
        {
            order_1[i]->clear();
        }

        for (unsigned long i = 0; i < alphabet_size*alphabet_size; ++i)
        {
            if (order_2[i] != 0)
            {
                delete order_2[i];
                order_2[i] = 0;
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_encoder,
        typename cc,
        typename cc_high
        >
    void entropy_encoder_model_kernel_3<alphabet_size,entropy_encoder,cc,cc_high>::
    encode (
        unsigned long symbol
    )
    {
        unsigned long low_count = 0, high_count = 0, total_count = 0;

        // order-2 context stuff
        {
            unsigned long temp = previous_symbol + (previous_symbol2 * alphabet_size);
            previous_symbol2 = previous_symbol;

            if (order_2[temp] != 0)
            {
                if (order_2[temp]->get_range(symbol,low_count,high_count,total_count))
                {
                    // there was an entry for this symbol in this context

                    // update the count for this symbol
                    order_2[temp]->increment_count(symbol,2);
                    // encode this symbol
                    coder.encode(low_count,high_count,total_count);
                    previous_symbol = symbol;
                    return;
                }

                // there was no entry for this symbol in this context so we must
                // escape to order-1

                // escape to the order-1 context
                order_2[temp]->get_range(alphabet_size,low_count,high_count,total_count);
                coder.encode(low_count,high_count,total_count);

                // increment the count for the escape symbol
                order_2[temp]->increment_count(alphabet_size);

            }
            else
            {
                order_2[temp] = new cc_high(gs_high);

                // in this case the decoder knows to escape to order-1 because
                // there was no conditioning_class object in this context yet.
                // so we don't need to actually write the escape symbol
            }

            // update the count for this symbol in this context
            order_2[temp]->increment_count(symbol,2);
        }

        // order-1 context stuff
        {
            cc& context = *order_1[previous_symbol];

            // if we have seen this symbol in the order-1 context
            if (context.get_range(symbol,low_count,high_count,total_count))
            {
                // update the count for this symbol
                context.increment_count(symbol,2);
                // encode this symbol
                coder.encode(low_count,high_count,total_count);
                previous_symbol = symbol;
                return;
            }

            // we didn't find the symbol in the order-1 context so we must escape to a
            // lower context.

            // escape to the order-0 context
            context.get_range(alphabet_size,low_count,high_count,total_count);
            coder.encode(low_count,high_count,total_count);

            // increment counts for the escape symbol and the current symbol
            context.increment_count(alphabet_size);
            context.increment_count(symbol,2);
        }

        previous_symbol = symbol;

        // if we have seen this symbol in the order-0 context
        if (order_0.get_range(symbol,low_count,high_count,total_count))
        {
            // update the count for this symbol
            order_0.increment_count(symbol,2);
            // encode this symbol
            coder.encode(low_count,high_count,total_count);
            return;
        }

        // if we are here then the symbol does not appear in the order-0 context

        // since we have never seen the current symbol in this context
        // escape from order-0 context
        order_0.get_range(alphabet_size,low_count,high_count,total_count);
        coder.encode(low_count,high_count,total_count);
        // increment the count for the escape symbol
        order_0.increment_count(alphabet_size);

        // update the count for this symbol
        order_0.increment_count(symbol,2);

        // use order minus one context
        coder.encode(symbol,symbol+1,alphabet_size);

    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_ENTROPY_ENCODER_MODEL_KERNEl_3_


dlib C++ Library - entropy_encoder_model_kernel_4.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ENTROPY_ENCODER_MODEL_KERNEl_4_
#define DLIB_ENTROPY_ENCODER_MODEL_KERNEl_4_

#include "../algs.h"
#include "entropy_encoder_model_kernel_abstract.h"
#include "../assert.h"

namespace dlib
{

    namespace eemk4
    {
        struct node
        {
            node* next;
            node* child_context;
            node* parent_context;

            unsigned short symbol;
            unsigned short count;
            unsigned short total;
            unsigned short escapes;
        };
    }

    template <
        unsigned long alphabet_size,
        typename entropy_encoder,
        unsigned long total_nodes,
        unsigned long order
        >
    class entropy_encoder_model_kernel_4
    {
        /*!
            REQUIREMENTS ON total_nodes
                - 4096 < total_nodes
                - this is the total number of nodes that we will use in the tree

            REQUIREMENTS ON order
                - 0 <= order
                - this is the maximum depth-1 the tree will be allowed to go (note
                  that the root level is depth 0).

            GENERAL NOTES
                This implementation follows more or less the implementation
                strategy laid out by Alistair Moffat in his paper
                Implementing the PPM data compression scheme.  Published in IEEE
                Transactions on Communications, 38(11):1917-1921, 1990.

                The escape method used will be method D.

            INITIAL VALUE
                - root == pointer to an array of total_nodes nodes
                - next_node == 1
                - cur == root
                - cur_order = 0
                - root->next == 0
                - root->parent_context == 0
                - root->child_context == 0
                - root->escapes == 0
                - root->total == 0

            CONVENTION
                - &get_entropy_encoder() == coder
                - root == pointer to an array of total_nodes nodes.
                  this is also the root of the tree.

                - if (next_node < total_nodes) then
                    - next_node == the next node in root that has not yet been allocated

                - root->next == 0
                - root->parent_context == 0

                - for every node in the tree:
                  {
                    - NOTATION:
                        - The "context" of a node is the string of symbols seen
                          when you go from the root of the tree down (down though
                          child context pointers) to the node, including the symbol at
                          the node itself.  (note that the context of the root node
                          is "" or the empty string)
                        - A set of nodes is in the same "context set" if all the node's
                          contexts are of length n and all the node's contexts share
                          the same prefix of length n-1.
                        - The "child context set" of a node is a set of nodes with
                          contexts that are one symbol longer and prefixed by the node's
                          context.  For example, if a node has a context "abc" then the
                          nodes for contexts "abca", "abcb", "abcc", etc. are all in
                          the child context set of the node.
                        - The "parent context" of a node is the context that is one
                          symbol shorter than the node's context and includes the
                          symbol in the node.  So the parent context of a node with
                          context "abcd" would be the context "bcd".

                    - if (next != 0) then
                        - next == pointer to the next node in the same context set
                    - if (child_context != 0) then
                        - child_context == pointer to the first node of the child
                          context set for this node.
                    - if (parent_context != 0) then
                        - parent_context == pointer to the parent context of this node.
                    - else
                        - this node is the root node of the tree

                    - if (this is not the root node) then
                        - symbol == the symbol represented with this node
                        - count == the number of times this symbol has been seen in its
                          parent context.
                    - else
                        - the root doesn't have a symbol.  i.e. the context for the
                          root node is "" or the empty string.

                    - total == The sum of the counts of all the nodes
                      in the child context set + escapes.
                    - escapes == the escape count for the context represented
                      by the node.
                }

                - cur_order < order
                - cur_order == the depth of the node cur in the tree.
                  (note that the root node has depth 0)
                - cur == pointer to the node in the tree who's context matches
                  the most recent symbols we have seen.

        !*/

        typedef eemk4::node node;

    public:

        typedef entropy_encoder entropy_encoder_type;

        entropy_encoder_model_kernel_4 (
            entropy_encoder& coder
        );

        virtual ~entropy_encoder_model_kernel_4 (
        );

        inline void clear(
        );

        inline void encode (
            unsigned long symbol
        );

        entropy_encoder& get_entropy_encoder (
        ) { return coder; }

        static unsigned long get_alphabet_size (
        ) { return alphabet_size; }

    private:

        inline eemk4::node* allocate_node (
        );
        /*!
            requires
                - space_left() == true
            ensures
                - returns a pointer to a new node
        !*/

        inline void destroy_tree (
        );
        /*!
            ensures
                - deallocates all nodes except the root
                - #root->child_context == 0
                - #root->escapes == 0
                - #root->total == 0
                - #cur == root
                - #cur_order == 0
        !*/

        inline bool space_left (
        ) const;
        /*!
            ensures
                - returns true if there is at least 1 free node left.
                - returns false otherwise
        !*/

        inline void scale_counts (
            node* n
        );
        /*!
            ensures
                - divides all the counts in the child context set of n by 2.
                - none of the nodes in the child context set will have a count of 0
        !*/

        unsigned long next_node;
        entropy_encoder& coder;
        node* root;
        node* cur;
        unsigned long cur_order;

        // restricted functions
        entropy_encoder_model_kernel_4(entropy_encoder_model_kernel_4<alphabet_size,entropy_encoder,total_nodes,order>&);        // copy constructor
        entropy_encoder_model_kernel_4<alphabet_size,entropy_encoder,total_nodes,order>& operator=(entropy_encoder_model_kernel_4<alphabet_size,entropy_encoder,total_nodes,order>&);    // assignment operator

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_encoder,
        unsigned long total_nodes,
        unsigned long order
        >
    entropy_encoder_model_kernel_4<alphabet_size,entropy_encoder,total_nodes,order>::
    entropy_encoder_model_kernel_4 (
        entropy_encoder& coder_
    ) :
        next_node(1),
        coder(coder_),
        cur_order(0)
    {
        COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65535 );
        COMPILE_TIME_ASSERT( 4096 < total_nodes );

        root = new node[total_nodes];
        cur = root;

        root->child_context = 0;
        root->escapes = 0;
        root->next = 0;
        root->parent_context = 0;
        root->total = 0;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_encoder,
        unsigned long total_nodes,
        unsigned long order
        >
    entropy_encoder_model_kernel_4<alphabet_size,entropy_encoder,total_nodes,order>::
    ~entropy_encoder_model_kernel_4 (
    )
    {
        delete [] root;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_encoder,
        unsigned long total_nodes,
        unsigned long order
        >
    void entropy_encoder_model_kernel_4<alphabet_size,entropy_encoder,total_nodes,order>::
    clear(
    )
    {
        destroy_tree();
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_encoder,
        unsigned long total_nodes,
        unsigned long order
        >
    void entropy_encoder_model_kernel_4<alphabet_size,entropy_encoder,total_nodes,order>::
    encode (
        unsigned long sym
    )
    {
        unsigned short symbol = static_cast<unsigned short>(sym);
        node* temp = cur;
        cur = 0;
        unsigned short low_count, high_count, total_count;
        node* new_node = 0;

        // local_order will track the level of temp in the tree
        unsigned long local_order = cur_order;

        while (true)
        {
            high_count = 0;
            if (space_left())
            {
                total_count = temp->total;

                if (total_count > 0)
                {
                    // check if we need to scale the counts
                    if (total_count > 10000)
                    {
                        scale_counts(temp);
                        total_count = temp->total;
                    }

                    // find either the symbol we are looking for or the
                    // end of the context set
                    node* n = temp->child_context;
                    node* last = 0;
                    while (true)
                    {
                        high_count += n->count;

                        if (n->symbol == symbol || n->next == 0)
                            break;
                        last = n;
                        n = n->next;
                    }

                    low_count = high_count - n->count;

                    // if we found the symbol
                    if (n->symbol == symbol)
                    {
                        if (new_node != 0)
                        {
                            new_node->parent_context = n;
                        }

                        coder.encode(low_count,high_count,total_count);
                        n->count += 8;
                        temp->total += 8;

                        // move this node to the front
                        if (last)
                        {
                            last->next = n->next;
                            n->next = temp->child_context;
                            temp->child_context = n;
                        }

                        if (cur == 0)
                        {
                            if (local_order < order)
                            {
                                cur_order = local_order+1;
                                cur = n;
                            }
                            else
                            {
                                cur = n->parent_context;
                                cur_order = local_order;
                            }
                        }

                        break;

                    }
                    // if we hit the end of the context set without finding the symbol
                    else
                    {
                        if (new_node != 0)
                        {
                            new_node->parent_context = allocate_node();
                            new_node = new_node->parent_context;
                        }
                        else
                        {
                            new_node = allocate_node();
                        }

                        n->next = new_node;

                        // write an escape to a lower context
                        coder.encode(high_count,total_count,total_count);
                    }

                }
                else // if (total_count == 0)
                {
                    // this means that temp->child_context == 0 so we should make
                    // a new node here.
                    if (new_node != 0)
                    {
                        new_node->parent_context = allocate_node();
                        new_node = new_node->parent_context;
                    }
                    else
                    {
                        new_node = allocate_node();
                    }

                    temp->child_context = new_node;
                }

                if (cur == 0 && local_order < order)
                {
                    cur = new_node;
                    cur_order = local_order+1;
                }

                // fill out the new node
                new_node->child_context = 0;
                new_node->count = 4;
                new_node->escapes = 0;
                new_node->next = 0;
                new_node->symbol = static_cast<unsigned short>(symbol);
                new_node->total = 0;
                temp->escapes += 4;
                temp->total += 8;

                if (temp != root)
                {
                    temp = temp->parent_context;
                    --local_order;
                    continue;
                }

                // since this is the root we are going to the order-(-1) context
                // so we can just take care of that here.
                new_node->parent_context = root;
                coder.encode(symbol,symbol+1,alphabet_size);

                if (cur == 0)
                {
                    cur = root;
                    cur_order = 0;
                }
                break;
            }
            else
            {
                // there isn't enough space so we should rebuild the tree
                destroy_tree();
                temp = cur;
                local_order = cur_order;
                cur = 0;
                new_node = 0;
            }
        } // while (true)

    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // private member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_encoder,
        unsigned long total_nodes,
        unsigned long order
        >
    eemk4::node* entropy_encoder_model_kernel_4<alphabet_size,entropy_encoder,total_nodes,order>::
    allocate_node (
    )
    {
        node* temp;
        temp = root + next_node;
        ++next_node;
        return temp;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_encoder,
        unsigned long total_nodes,
        unsigned long order
        >
    void entropy_encoder_model_kernel_4<alphabet_size,entropy_encoder,total_nodes,order>::
    destroy_tree (
    )
    {
        next_node = 1;
        root->child_context = 0;
        root->escapes = 0;
        root->total = 0;
        cur = root;
        cur_order = 0;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_encoder,
        unsigned long total_nodes,
        unsigned long order
        >
    bool entropy_encoder_model_kernel_4<alphabet_size,entropy_encoder,total_nodes,order>::
    space_left (
    ) const
    {
        return (next_node < total_nodes);
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_encoder,
        unsigned long total_nodes,
        unsigned long order
        >
    void entropy_encoder_model_kernel_4<alphabet_size,entropy_encoder,total_nodes,order>::
    scale_counts (
        node* temp
    )
    {
        if (temp->escapes > 1)
            temp->escapes >>= 1;
        temp->total = temp->escapes;

        node* n = temp->child_context;
        while (n != 0)
        {
            if (n->count > 1)
                n->count >>= 1;

            temp->total += n->count;
            n = n->next;
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_ENTROPY_ENCODER_MODEL_KERNEl_4_


dlib C++ Library - entropy_encoder_model_kernel_5.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ENTROPY_ENCODER_MODEL_KERNEl_5_
#define DLIB_ENTROPY_ENCODER_MODEL_KERNEl_5_

#include "../algs.h"
#include "entropy_encoder_model_kernel_abstract.h"
#include "../assert.h"

namespace dlib
{

    namespace eemk5
    {
        struct node
        {
            node* next;
            node* child_context;
            node* parent_context;

            unsigned short symbol;
            unsigned short count;
            unsigned short total;
            unsigned short escapes;
        };
    }

    template <
        unsigned long alphabet_size,
        typename entropy_encoder,
        unsigned long total_nodes,
        unsigned long order
        >
    class entropy_encoder_model_kernel_5
    {
        /*!
            REQUIREMENTS ON total_nodes
                - 4096 < total_nodes
                - this is the total number of nodes that we will use in the tree

            REQUIREMENTS ON order
                - 0 <= order
                - this is the maximum depth-1 the tree will be allowed to go (note
                  that the root level is depth 0).

            GENERAL NOTES
                This implementation follows more or less the implementation
                strategy laid out by Alistair Moffat in his paper
                Implementing the PPM data compression scheme.  Published in IEEE
                Transactions on Communications, 38(11):1917-1921, 1990.

                The escape method used will be method D.

                This also uses Dmitry Shkarin's Information Inheritance scheme.
                (described in "PPM: one step to practicality" and "Improving the
                Efficiency of the PPM Algorithm")

            INITIAL VALUE
                - root == pointer to an array of total_nodes nodes
                - next_node == 1
                - cur == root
                - cur_order = 0
                - root->next == 0
                - root->parent_context == 0
                - root->child_context == 0
                - root->escapes == 0
                - root->total == 0
                - stack_size == 0
                - exc_used == false
                - for all i: exc[i] == 0

            CONVENTION
                - pop() == stack[stack_size-1].n and stack[stack_size-1].nc
                - exc_used == something_is_excluded()
                - is_excluded(symbol) == bit symbol&0x1F from exc[symbol>>5]
                - &get_entropy_encoder() == coder
                - root == pointer to an array of total_nodes nodes.
                  this is also the root of the tree.
                - if (next_node < total_nodes) then
                    - next_node == the next node in root that has not yet been allocated

                - root->next == 0
                - root->parent_context == 0

                - for every node in the tree:
                  {
                    - NOTATION:
                        - The "context" of a node is the string of symbols seen
                          when you go from the root of the tree down (down though
                          child context pointers) to the node, including the symbol at
                          the node itself.  (note that the context of the root node
                          is "" or the empty string)
                        - A set of nodes is in the same "context set" if all the node's
                          contexts are of length n and all the node's contexts share
                          the same prefix of length n-1.
                        - The "child context set" of a node is a set of nodes with
                          contexts that are one symbol longer and prefixed by the node's
                          context.  For example, if a node has a context "abc" then the
                          nodes for contexts "abca", "abcb", "abcc", etc. are all in
                          the child context set of the node.
                        - The "parent context" of a node is the context that is one
                          symbol shorter than the node's context and includes the
                          symbol in the node.  So the parent context of a node with
                          context "abcd" would be the context "bcd".

                    - if (next != 0) then
                        - next == pointer to the next node in the same context set
                    - if (child_context != 0) then
                        - child_context == pointer to the first node of the child
                          context set for this node.
                        - escapes > 0
                    - if (parent_context != 0) then
                        - parent_context == pointer to the parent context of this node.
                    - else
                        - this node is the root node of the tree

                    - if (this is not the root node) then
                        - symbol == the symbol represented with this node
                        - count == the number of times this symbol has been seen in its
                          parent context.
                    - else
                        - the root doesn't have a symbol.  i.e. the context for the
                          root node is "" or the empty string.

                    - total == The sum of the counts of all the nodes
                      in the child context set + escapes.
                    - escapes == the escape count for the context represented
                      by the node.
                    - count > 0
                }

                - cur_order < order
                - cur_order == the depth of the node cur in the tree.
                  (note that the root node has depth 0)
                - cur == pointer to the node in the tree who's context matches
                  the most recent symbols we have seen.

        !*/

        typedef eemk5::node node;

    public:

        typedef entropy_encoder entropy_encoder_type;

        entropy_encoder_model_kernel_5 (
            entropy_encoder& coder
        );

        virtual ~entropy_encoder_model_kernel_5 (
        );

        inline void clear(
        );

        inline void encode (
            unsigned long symbol
        );

        entropy_encoder& get_entropy_encoder (
        ) { return coder; }

        static unsigned long get_alphabet_size (
        ) { return alphabet_size; }

    private:

        inline eemk5::node* allocate_node (
        );
        /*!
            requires
                - space_left() == true
            ensures
                - returns a pointer to a new node
        !*/

        inline bool space_left (
        ) const;
        /*!
            ensures
                - returns true if there is at least 1 free node left.
                - returns false otherwise
        !*/

        inline void exclude (
            unsigned short symbol
        );
        /*!
            ensures
                - #is_excluded(symbol) == true
                - #something_is_excluded() == true
        !*/

        inline bool something_is_excluded (
        );
        /*!
            ensures
                - returns true if some symbol has been excluded.
                  returns false otherwise
        !*/

        inline bool is_excluded (
            unsigned short symbol
        );
        /*!
            ensures
                - if (symbol has been excluded) then
                    - returns true
                - else
                    - returns false
        !*/

        inline void clear_exclusions (
        );
        /*!
            ensures
                - for all symbols #is_excluded(symbol) == false
                - #something_is_excluded() == true
        !*/

        inline void scale_counts (
            node* n
        );
        /*!
            ensures
                - divides all the counts in the child context set of n by 2.
                - none of the nodes in the child context set will have a count of 0
        !*/

        inline void push (
            node* n,
            node* nc
        );
        /*!
            requires
                - stack_size < order
            ensures
                - #pop(a,b): a == n && b == nc
        !*/

        inline void pop (
            node*& n,
            node*& nc
        );
        /*!
            requires
                - stack_size > 0
            ensures
                - returns the two nodes at the top of the stack
        !*/

        struct nodes
        {
            node* n;
            node* nc;
        };

        unsigned long next_node;
        entropy_encoder& coder;
        node* root;
        node* cur;
        unsigned long cur_order;
        unsigned long exc[alphabet_size/32+1];
        bool exc_used;
        nodes stack[order+1];
        unsigned long stack_size;

        // restricted functions
        entropy_encoder_model_kernel_5(entropy_encoder_model_kernel_5<alphabet_size,entropy_encoder,total_nodes,order>&);        // copy constructor
        entropy_encoder_model_kernel_5<alphabet_size,entropy_encoder,total_nodes,order>& operator=(entropy_encoder_model_kernel_5<alphabet_size,entropy_encoder,total_nodes,order>&);    // assignment operator

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_encoder,
        unsigned long total_nodes,
        unsigned long order
        >
    entropy_encoder_model_kernel_5<alphabet_size,entropy_encoder,total_nodes,order>::
    entropy_encoder_model_kernel_5 (
        entropy_encoder& coder_
    ) :
        next_node(1),
        coder(coder_),
        cur_order(0),
        stack_size(0)
    {
        COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65535 );
        COMPILE_TIME_ASSERT( 4096 < total_nodes );

        root = new node[total_nodes];
        cur = root;

        root->child_context = 0;
        root->escapes = 0;
        root->next = 0;
        root->parent_context = 0;
        root->total = 0;

        clear_exclusions();
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_encoder,
        unsigned long total_nodes,
        unsigned long order
        >
    entropy_encoder_model_kernel_5<alphabet_size,entropy_encoder,total_nodes,order>::
    ~entropy_encoder_model_kernel_5 (
    )
    {
        delete [] root;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_encoder,
        unsigned long total_nodes,
        unsigned long order
        >
    void entropy_encoder_model_kernel_5<alphabet_size,entropy_encoder,total_nodes,order>::
    clear(
    )
    {
        next_node = 1;
        root->child_context = 0;
        root->escapes = 0;
        root->total = 0;
        cur = root;
        cur_order = 0;
        stack_size = 0;

        clear_exclusions();
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_encoder,
        unsigned long total_nodes,
        unsigned long order
        >
    void entropy_encoder_model_kernel_5<alphabet_size,entropy_encoder,total_nodes,order>::
    encode (
        unsigned long sym
    )
    {
        unsigned short symbol = static_cast<unsigned short>(sym);
        node* temp = cur;
        cur = 0;
        unsigned short low_count, high_count, total_count;
        node* new_node = 0;

        // local_order will track the level of temp in the tree
        unsigned long local_order = cur_order;

        unsigned short c; // c == t(a|sk)
        unsigned short t; // t == T(sk)

        if (something_is_excluded())
            clear_exclusions();

        while (true)
        {
            low_count = 0;
            high_count = 0;
            if (space_left())
            {
                total_count = temp->total;

                if (total_count > 0)
                {
                    // check if we need to scale the counts
                    if (total_count > 10000)
                    {
                        scale_counts(temp);
                        total_count = temp->total;
                    }

                    // find the symbol we are looking for and put a pointer to it
                    // into found_symbol.  If it isn't found then found_symbol == 0.
                    // also, low_count and high_count will be correctly set.
                    node* n = temp->child_context;
                    node* found_symbol = 0;
                    node* last = 0;
                    if (something_is_excluded())
                    {
                        node* templast = 0;
                        while (true)
                        {
                            if (is_excluded(n->symbol) == false)
                            {
                                exclude(n->symbol);
                                if (found_symbol == 0)
                                {
                                    high_count += n->count;
                                    if (n->symbol == symbol)
                                    {
                                        found_symbol = n;
                                        last = templast;
                                        low_count = high_count - n->count;
                                    }
                                }
                            }
                            else
                            {
                                total_count -= n->count;
                            }

                            if (n->next == 0)
                                break;
                            templast = n;
                            n = n->next;
                        }
                    }
                    else
                    {
                        while (true)
                        {
                            high_count += n->count;
                            exclude(n->symbol);

                            if (n->symbol == symbol)
                            {
                                found_symbol = n;
                                low_count = high_count - n->count;
                                break;
                            }

                            if (n->next == 0)
                                break;
                            last = n;
                            n = n->next;
                        }
                    }

                    // if we found the symbol
                    if (found_symbol)
                    {
                        n = found_symbol;
                        if (new_node != 0)
                        {
                            new_node->parent_context = found_symbol;
                        }

                        coder.encode(low_count,high_count,total_count);
                        c = n->count += 8;
                        t = temp->total += 8;

                        // move this node to the front
                        if (last)
                        {
                            last->next = n->next;
                            n->next = temp->child_context;
                            temp->child_context = n;
                        }

                        if (cur == 0)
                        {
                            if (local_order >= order)
                            {
                                cur = n->parent_context;
                                cur_order = local_order;
                            }
                            else
                            {
                                cur_order = local_order+1;
                                cur = n;
                            }
                        }

                        break;

                    }
                    // if we hit the end of the context set without finding the symbol
                    else
                    {
                        // finish excluding all the symbols
                        while (n->next)
                        {
                            exclude(n->symbol);
                            n = n->next;
                        }

                        if (new_node != 0)
                        {
                            new_node->parent_context = allocate_node();
                            new_node = new_node->parent_context;
                        }
                        else
                        {
                            new_node = allocate_node();
                        }

                        n->next = new_node;

                        // write an escape to a lower context
                        coder.encode(high_count,total_count,total_count);
                    }

                }
                else // if (total_count == 0)
                {
                    // this means that temp->child_context == 0 so we should make
                    // a new node here.
                    if (new_node != 0)
                    {
                        new_node->parent_context = allocate_node();
                        new_node = new_node->parent_context;
                    }
                    else
                    {
                        new_node = allocate_node();
                    }

                    temp->child_context = new_node;
                }

                if (cur == 0 && local_order < order)
                {
                    cur = new_node;
                    cur_order = local_order+1;
                }

                // fill out the new node
                new_node->child_context = 0;
                new_node->escapes = 0;
                new_node->next = 0;
                new_node->total = 0;
                push(new_node,temp);

                if (temp != root)
                {
                    temp = temp->parent_context;
                    --local_order;
                    continue;
                }

                t = 2056;
                c = 8;

                // since this is the root we are going to the order-(-1) context
                // so we can just take care of that here.
                new_node->parent_context = root;
                coder.encode(symbol,symbol+1,alphabet_size);

                if (cur == 0)
                {
                    cur = root;
                    cur_order = 0;
                }
                break;
            }
            else
            {
                // there isn't enough space so we should throw away the tree
                clear();
                temp = cur;
                local_order = cur_order;
                cur = 0;
                new_node = 0;
            }
        } // while (true)

        // initialize the counts and symbol for any new nodes we have added
        // to the tree.
        node* n, *nc;
        while (stack_size > 0)
        {
            pop(n,nc);

            n->symbol = static_cast<unsigned short>(symbol);

            // if nc is not a determnistic context
            if (nc->total)
            {
                unsigned long temp2 = t-c+nc->total - nc->escapes - nc->escapes;
                unsigned long temp = nc->total;
                temp *= c;
                temp /= (temp2|1); // this oring by 1 is just to make sure that temp2 is never zero
                temp += 2;
                if (temp > 50000) temp = 50000;
                n->count = static_cast<unsigned short>(temp);

                nc->escapes += 4;
                nc->total += static_cast<unsigned short>(temp) + 4;
            }
            else
            {
                n->count = 3 + 5*(c)/(t-c);

                nc->escapes = 4;
                nc->total = n->count + 4;
            }

            while (nc->total > 10000)
            {
                scale_counts(nc);
            }
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // private member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_encoder,
        unsigned long total_nodes,
        unsigned long order
        >
    eemk5::node* entropy_encoder_model_kernel_5<alphabet_size,entropy_encoder,total_nodes,order>::
    allocate_node (
    )
    {
        node* temp;
        temp = root + next_node;
        ++next_node;
        return temp;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_encoder,
        unsigned long total_nodes,
        unsigned long order
        >
    bool entropy_encoder_model_kernel_5<alphabet_size,entropy_encoder,total_nodes,order>::
    space_left (
    ) const
    {
        return (next_node < total_nodes);
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_encoder,
        unsigned long total_nodes,
        unsigned long order
        >
    void entropy_encoder_model_kernel_5<alphabet_size,entropy_encoder,total_nodes,order>::
    exclude (
        unsigned short symbol
    )
    {
        exc_used = true;
        unsigned long temp = 1;
        temp <<= symbol&0x1F;
        exc[symbol>>5] |= temp;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_encoder,
        unsigned long total_nodes,
        unsigned long order
        >
    bool entropy_encoder_model_kernel_5<alphabet_size,entropy_encoder,total_nodes,order>::
    is_excluded (
        unsigned short symbol
    )
    {
        unsigned long temp = 1;
        temp <<= symbol&0x1F;
        return ((exc[symbol>>5]&temp) != 0);
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_encoder,
        unsigned long total_nodes,
        unsigned long order
        >
    void entropy_encoder_model_kernel_5<alphabet_size,entropy_encoder,total_nodes,order>::
    clear_exclusions (
    )
    {
        exc_used = false;
        for (unsigned long i = 0; i < alphabet_size/32+1; ++i)
        {
            exc[i] = 0;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_encoder,
        unsigned long total_nodes,
        unsigned long order
        >
    bool entropy_encoder_model_kernel_5<alphabet_size,entropy_encoder,total_nodes,order>::
    something_is_excluded (
    )
    {
        return exc_used;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_encoder,
        unsigned long total_nodes,
        unsigned long order
        >
    void entropy_encoder_model_kernel_5<alphabet_size,entropy_encoder,total_nodes,order>::
    push (
        node* n,
        node* nc
    )
    {
        stack[stack_size].n = n;
        stack[stack_size].nc = nc;
        ++stack_size;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_encoder,
        unsigned long total_nodes,
        unsigned long order
        >
    void entropy_encoder_model_kernel_5<alphabet_size,entropy_encoder,total_nodes,order>::
    pop (
        node*& n,
        node*& nc
    )
    {
        --stack_size;
        n = stack[stack_size].n;
        nc = stack[stack_size].nc;
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_encoder,
        unsigned long total_nodes,
        unsigned long order
        >
    void entropy_encoder_model_kernel_5<alphabet_size,entropy_encoder,total_nodes,order>::
    scale_counts (
        node* temp
    )
    {
        if (temp->escapes > 1)
            temp->escapes >>= 1;
        temp->total = temp->escapes;

        node* n = temp->child_context;
        while (n != 0)
        {
            if (n->count > 1)
                n->count >>= 1;

            temp->total += n->count;
            n = n->next;
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_ENTROPY_ENCODER_MODEL_KERNEl_5_


dlib C++ Library - entropy_encoder_model_kernel_6.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ENTROPY_ENCODER_MODEL_KERNEl_6_
#define DLIB_ENTROPY_ENCODER_MODEL_KERNEl_6_

#include "../algs.h"
#include "entropy_encoder_model_kernel_abstract.h"
#include "../assert.h"

namespace dlib
{

    template <
        unsigned long alphabet_size,
        typename entropy_encoder
        >
    class entropy_encoder_model_kernel_6
    {
        /*!
            INITIAL VALUE
                Initially this object's finite context model is empty

            CONVENTION
                &get_entropy_encoder() == coder

                This is an order-(-1) model.  So it doesn't really do anything.
                Every symbol has the same probability.
        !*/

    public:

        typedef entropy_encoder entropy_encoder_type;

        entropy_encoder_model_kernel_6 (
            entropy_encoder& coder
        );

        virtual ~entropy_encoder_model_kernel_6 (
        );

        inline void clear(
        );

        inline void encode (
            unsigned long symbol
        );

        entropy_encoder& get_entropy_encoder (
        ) { return coder; }

        static unsigned long get_alphabet_size (
        ) { return alphabet_size; }

    private:

        entropy_encoder& coder;

        // restricted functions
        entropy_encoder_model_kernel_6(entropy_encoder_model_kernel_6<alphabet_size,entropy_encoder>&);        // copy constructor
        entropy_encoder_model_kernel_6<alphabet_size,entropy_encoder>& operator=(entropy_encoder_model_kernel_6<alphabet_size,entropy_encoder>&);    // assignment operator

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_encoder
        >
    entropy_encoder_model_kernel_6<alphabet_size,entropy_encoder>::
    entropy_encoder_model_kernel_6 (
        entropy_encoder& coder_
    ) :
        coder(coder_)
    {
        COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65535 );
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_encoder
        >
    entropy_encoder_model_kernel_6<alphabet_size,entropy_encoder>::
    ~entropy_encoder_model_kernel_6 (
    )
    {
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_encoder
        >
    void entropy_encoder_model_kernel_6<alphabet_size,entropy_encoder>::
    clear(
    )
    {
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long alphabet_size,
        typename entropy_encoder
        >
    void entropy_encoder_model_kernel_6<alphabet_size,entropy_encoder>::
    encode (
        unsigned long symbol
    )
    {
        // use order minus one context
        coder.encode(symbol,symbol+1,alphabet_size);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_ENTROPY_ENCODER_MODEL_KERNEl_6_


dlib C++ Library - entropy_encoder_model_kernel_c.h

// Copyright (C) 2004  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ENTROPY_ENCODER_MODEL_KERNEl_C_
#define DLIB_ENTROPY_ENCODER_MODEL_KERNEl_C_

#include "entropy_encoder_model_kernel_abstract.h"
#include "../algs.h"
#include "../assert.h"
#include <iostream>

namespace dlib
{

    template <
        typename eem_base
        >
    class entropy_encoder_model_kernel_c : public eem_base
    {
        const unsigned long alphabet_size;
        typedef typename eem_base::entropy_encoder_type entropy_encoder;

        public:

            entropy_encoder_model_kernel_c (
                entropy_encoder& coder
            ) : eem_base(coder), alphabet_size(eem_base::get_alphabet_size()) {}

            void encode (
                unsigned long symbol
            );
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename eem_base
        >
    void entropy_encoder_model_kernel_c<eem_base>::
    encode (
        unsigned long symbol
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(symbol < alphabet_size,
            "\tvoid entropy_encoder_model::encode()"
            << "\n\tthe symbol must be in the range 0 to alphabet_size-1"
            << "\n\talphabet_size: " << alphabet_size
            << "\n\tsymbol:        " << symbol
            << "\n\tthis:          " << this
            );

        // call the real function
        eem_base::encode(symbol);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_ENTROPY_ENCODER_MODEL_KERNEl_C_


dlib C++ Library - count_bits.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_COUNT_BiTS_Hh_
#define DLIB_COUNT_BiTS_Hh_

#include "../algs.h"
#include <climits>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    T count_bits (
        T v
    )
    /*!
        requires
            - T is an unsigned integral type
        ensures
            - returns the number of bits in v which are set to 1.
    !*/
    {
        COMPILE_TIME_ASSERT(is_unsigned_type<T>::value && sizeof(T) <= 8);

        // This bit of bit trickery is from:
        // http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSet64

        v = v - ((v >> 1) & (T)~(T)0/3);
        v = (v & (T)~(T)0/15*3) + ((v >> 2) & (T)~(T)0/15*3);
        v = (v + (v >> 4)) & (T)~(T)0/255*15;
        return (T)(v * ((T)~(T)0/255)) >> (sizeof(T) - 1) * CHAR_BIT;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    T hamming_distance (
        const T& a,
        const T& b
    )
    /*!
        requires
            - T is an unsigned integral type
        ensures
            - returns the number of bits which differ between a and b.
    !*/
    {
        return count_bits(a^b);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_COUNT_BiTS_Hh_


dlib C++ Library - general_hash.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_GENERAL_HASh_
#define DLIB_GENERAL_HASh_

#include <string>
#include "hash.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------- provide a general hashing function object ----------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    class general_hash
    {
    public:
        inline unsigned long operator() (
            const T& item
        ) const;
    };
    /*!
        Note that the default behavior of general hash is to attempt to cast
        an object of type T to an unsigned long and use that as the hash.

        REQUIREMENTS ON general_hash
            - must have a default constructor
            - must be a function object which overloads operator() as follows:
              unsigned long operator()(const T& item)
            - must take item, compute a hash number and return it
            - must not throw
            - must define the hash in such a way that all equivalent objects have
              the same hash.  where equivalent means the following:
                  definition of equivalent:
                  a is equivalent to b if
                  a < b == false and
                  b < a == false
    !*/

// ---------------

    template <
        typename T
        >
    unsigned long general_hash<T>::
    operator() (
        const T& item
    ) const
    {
        // hash any types that have a conversion to uint64
        return hash(static_cast<uint64>(item));
    }

// ---------------

    // std::string hash
    template <>
    inline unsigned long general_hash<std::string>::
    operator() (
        const std::string& item
    ) const
    {
        return hash(item);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

}

#endif // DLIB_GENERAL_HASh_


dlib C++ Library - hash.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_HAsH_Hh_
#define DLIB_HAsH_Hh_

#include "hash_abstract.h"
#include <vector>
#include <string>
#include <map>
#include "murmur_hash3.h"
#include "../algs.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    inline uint32 hash (
        const std::string& item,
        uint32 seed = 0
    )
    {
        if (item.size() == 0)
            return 0;
        else
            return murmur_hash3(&item[0], sizeof(item[0])*item.size(), seed);
    }

// ----------------------------------------------------------------------------------------

    inline uint32 hash (
        const std::wstring& item,
        uint32 seed = 0
    )
    {
        if (item.size() == 0)
            return 0;
        else
            return murmur_hash3(&item[0], sizeof(item[0])*item.size(), seed);
    }

// ----------------------------------------------------------------------------------------

    template <typename T, typename alloc>
    uint32 hash (
        const std::vector<T,alloc>& item,
        uint32 seed = 0
    )
    {
        DLIB_ASSERT_HAS_STANDARD_LAYOUT(T);

        if (item.size() == 0)
            return 0;
        else
            return murmur_hash3(&item[0], sizeof(T)*item.size(), seed);
    }

// ----------------------------------------------------------------------------------------

    template <typename T, typename U, typename alloc>
    uint32 hash (
        const std::vector<std::pair<T,U>,alloc>& item,
        uint32 seed = 0
    )
    {
        DLIB_ASSERT_HAS_STANDARD_LAYOUT(T);
        DLIB_ASSERT_HAS_STANDARD_LAYOUT(U);

        if (item.size() == 0)
            return 0;
        else
            return murmur_hash3(&item[0], sizeof(item[0])*item.size(), seed);
    }

// ----------------------------------------------------------------------------------------

    template <typename T, typename U, typename comp, typename alloc>
    uint32 hash (
        const std::map<T,U,comp,alloc>& item,
        uint32 seed = 0
    )
    {
        return hash(std::vector<std::pair<T,U> >(item.begin(), item.end()), seed);
    }

// ----------------------------------------------------------------------------------------

    inline uint32 hash (
        uint32 val,
        uint32 seed = 0
    )
    {
        return murmur_hash3_2(val,seed);
    }

// ----------------------------------------------------------------------------------------

    inline uint32 hash (
        uint64 val,
        uint32 seed = 0
    )
    {
        return static_cast<uint32>(murmur_hash3_128bit_3(val,seed,0).first);
    }

// ----------------------------------------------------------------------------------------

    inline uint32 hash (
        const std::pair<uint64,uint64>& item,
        uint32 seed = 0
    )
    {
        return static_cast<uint32>(murmur_hash3_128bit_3(item.first,item.second,seed).first);
    }

// ----------------------------------------------------------------------------------------

    inline uint32 hash (
        const std::pair<uint32,uint32>& item,
        uint32 seed = 0
    )
    {
        return murmur_hash3_3(item.first,item.second,seed);
    }

// ----------------------------------------------------------------------------------------

    template <typename T, typename U>
    uint32 hash (
        const std::pair<T,U>& item,
        uint32 seed = 0
    )
    {
        return hash(item.first, seed) ^ hash(item.second, seed+1);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_HAsH_Hh_


dlib C++ Library - murmur_hash3.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MURMUR_HAsH_3_Hh_
#define DLIB_MURMUR_HAsH_3_Hh_

#include "murmur_hash3_abstract.h"
#include "../uintn.h"
#include <utility>
#include <string.h>

namespace dlib
{
    //-----------------------------------------------------------------------------
    // The original MurmurHash3 code was written by Austin Appleby, and is placed
    // in the public domain. The author hereby disclaims copyright to this source code.
    // The code in this particular file was modified by Davis E. King.  In
    // particular, endian-swapping was added along with some other minor code
    // changes like avoiding strict aliasing violations.

    //-----------------------------------------------------------------------------
    // Platform-specific functions and macros

    // Microsoft Visual Studio

#if defined(_MSC_VER)

#define DLIB_FORCE_INLINE	__forceinline

#include <stdlib.h>

#define DLIB_ROTL32(x,y)	_rotl(x,y)
#define DLIB_ROTL64(x,y)	_rotl64(x,y)

#define DLIB_BIG_CONSTANT(x) (x)

    // Other compilers

#else	// defined(_MSC_VER)

#define	DLIB_FORCE_INLINE __attribute__((always_inline)) inline

    inline uint32 murmur_rotl32 ( uint32 x, int8 r )
    {
        return (x << r) | (x >> (32 - r));
    }

    inline uint64 murmur_rotl64 ( uint64 x, int8 r )
    {
        return (x << r) | (x >> (64 - r));
    }

#define	DLIB_ROTL32(x,y)	dlib::murmur_rotl32(x,y)
#define DLIB_ROTL64(x,y)	dlib::murmur_rotl64(x,y)

#define DLIB_BIG_CONSTANT(x) (x##LLU)

#endif // !defined(_MSC_VER)

// ----------------------------------------------------------------------------------------
    // Block read - if your platform needs to do endian-swapping or can only
    // handle aligned reads, do the conversion here

    DLIB_FORCE_INLINE uint32 murmur_getblock ( const uint32 * p, int i )
    {
        // The reason we do a memcpy() here instead of simply returning p[i] is because
        // doing it this way avoids violations of the strict aliasing rule when all these
        // functions are inlined into the user's code.
        uint32 temp;
        memcpy(&temp, p+i, 4);
        return temp;
    }

    DLIB_FORCE_INLINE uint32 murmur_getblock_byte_swap ( const uint32 * p, int i )
    {
        union
        {
            uint8 bytes[4];
            uint32 val;
        } temp;

        const uint8* pp = reinterpret_cast<const uint8*>(p + i);
        temp.bytes[0] = pp[3];
        temp.bytes[1] = pp[2];
        temp.bytes[2] = pp[1];
        temp.bytes[3] = pp[0];

        return temp.val;
    }

    DLIB_FORCE_INLINE uint64 murmur_getblock ( const uint64 * p, int i )
    {
        // The reason we do a memcpy() here instead of simply returning p[i] is because
        // doing it this way avoids violations of the strict aliasing rule when all these
        // functions are inlined into the user's code.
        uint64 temp;
        memcpy(&temp, p+i, 8);
        return temp;
    }

    DLIB_FORCE_INLINE uint64 murmur_getblock_byte_swap ( const uint64 * p, int i )
    {
        union
        {
            uint8 bytes[8];
            uint64 val;
        } temp;

        const uint8* pp = reinterpret_cast<const uint8*>(p + i);
        temp.bytes[0] = pp[7];
        temp.bytes[1] = pp[6];
        temp.bytes[2] = pp[5];
        temp.bytes[3] = pp[4];
        temp.bytes[4] = pp[3];
        temp.bytes[5] = pp[2];
        temp.bytes[6] = pp[1];
        temp.bytes[7] = pp[0];

        return temp.val;
    }

// ----------------------------------------------------------------------------------------
    // Finalization mix - force all bits of a hash block to avalanche

    DLIB_FORCE_INLINE uint32 murmur_fmix ( uint32 h )
    {
        h ^= h >> 16;
        h *= 0x85ebca6b;
        h ^= h >> 13;
        h *= 0xc2b2ae35;
        h ^= h >> 16;

        return h;
    }

// ----------------------------------------------------------------------------------------

    DLIB_FORCE_INLINE uint64 murmur_fmix ( uint64 k )
    {
        k ^= k >> 33;
        k *= DLIB_BIG_CONSTANT(0xff51afd7ed558ccd);
        k ^= k >> 33;
        k *= DLIB_BIG_CONSTANT(0xc4ceb9fe1a85ec53);
        k ^= k >> 33;

        return k;
    }

// ----------------------------------------------------------------------------------------

    inline uint32 murmur_hash3 (
        const void * key,
        const int len,
        const uint32 seed = 0
    )
    {
        const uint8 * data = (const uint8*)key;
        const int nblocks = len / 4;

        uint32 h1 = seed;

        uint32 c1 = 0xcc9e2d51;
        uint32 c2 = 0x1b873593;

        //----------
        // body

        const uint32 * blocks = (const uint32 *)(data + nblocks*4);

        bool is_little_endian = true;
        uint32 endian_test = 1;
        if (*reinterpret_cast<unsigned char*>(&endian_test) != 1)
            is_little_endian = false;

        if (is_little_endian)
        {
            for(int i = -nblocks; i; i++)
            {
                uint32 k1 = murmur_getblock(blocks,i);

                k1 *= c1;
                k1 = DLIB_ROTL32(k1,15);
                k1 *= c2;

                h1 ^= k1;
                h1 = DLIB_ROTL32(h1,13);
                h1 = h1*5+0xe6546b64;
            }
        }
        else
        {
            for(int i = -nblocks; i; i++)
            {
                uint32 k1 = murmur_getblock_byte_swap(blocks,i);

                k1 *= c1;
                k1 = DLIB_ROTL32(k1,15);
                k1 *= c2;

                h1 ^= k1;
                h1 = DLIB_ROTL32(h1,13);
                h1 = h1*5+0xe6546b64;
            }
        }

        //----------
        // tail

        const uint8 * tail = (const uint8*)(data + nblocks*4);

        uint32 k1 = 0;

        switch(len & 3)
        {
            case 3: k1 ^= tail[2] << 16;
            case 2: k1 ^= tail[1] << 8;
            case 1: k1 ^= tail[0];
                    k1 *= c1; k1 = DLIB_ROTL32(k1,15); k1 *= c2; h1 ^= k1;
        };

        //----------
        // finalization

        h1 ^= len;

        h1 = murmur_fmix(h1);

        return h1;
    }

// ----------------------------------------------------------------------------------------

    inline uint32 murmur_hash3_2 (
        const uint32 v1,
        const uint32 v2
    )
    {
        uint32 h1 = v2;

        uint32 c1 = 0xcc9e2d51;
        uint32 c2 = 0x1b873593;

        //----------
        // body

        uint32 k1 = v1;

        k1 *= c1;
        k1 = DLIB_ROTL32(k1,15);
        k1 *= c2;

        h1 ^= k1;
        h1 = DLIB_ROTL32(h1,13);
        h1 = h1*5+0xe6546b64;

        //----------
        // finalization

        h1 ^= 4; // =^ by length in bytes

        h1 = murmur_fmix(h1);

        return h1;
    }

// ----------------------------------------------------------------------------------------

    inline uint32 murmur_hash3_3 (
        const uint32 v1,
        const uint32 v2,
        const uint32 v3
    )
    {

        uint32 h1 = v3;

        uint32 c1 = 0xcc9e2d51;
        uint32 c2 = 0x1b873593;

        //----------
        // body

        uint32 k1 = v1;

        k1 *= c1;
        k1 = DLIB_ROTL32(k1,15);
        k1 *= c2;

        h1 ^= k1;
        h1 = DLIB_ROTL32(h1,13);
        h1 = h1*5+0xe6546b64;

        k1 = v2;
        k1 *= c1;
        k1 = DLIB_ROTL32(k1,15);
        k1 *= c2;

        h1 ^= k1;
        h1 = DLIB_ROTL32(h1,13);
        h1 = h1*5+0xe6546b64;

        //----------
        // finalization

        h1 ^= 8; // =^ by length in bytes

        h1 = murmur_fmix(h1);

        return h1;
    }

// ----------------------------------------------------------------------------------------

    inline std::pair<uint64,uint64> murmur_hash3_128bit (
        const void* key,
        const int len,
        const uint32 seed = 0
    )
    {
        const uint8 * data = (const uint8*)key;
        const int nblocks = len / 16;

        uint64 h1 = seed;
        uint64 h2 = seed;

        uint64 c1 = DLIB_BIG_CONSTANT(0x87c37b91114253d5);
        uint64 c2 = DLIB_BIG_CONSTANT(0x4cf5ad432745937f);

        //----------
        // body

        const uint64 * blocks = (const uint64 *)(data);

        bool is_little_endian = true;
        uint32 endian_test = 1;
        if (*reinterpret_cast<unsigned char*>(&endian_test) != 1)
            is_little_endian = false;

        if (is_little_endian)
        {
            for(int i = 0; i < nblocks; i++)
            {
                uint64 k1 = murmur_getblock(blocks,i*2+0);
                uint64 k2 = murmur_getblock(blocks,i*2+1);

                k1 *= c1; k1  = DLIB_ROTL64(k1,31); k1 *= c2; h1 ^= k1;

                h1 = DLIB_ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729;

                k2 *= c2; k2  = DLIB_ROTL64(k2,33); k2 *= c1; h2 ^= k2;

                h2 = DLIB_ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5;
            }
        }
        else
        {
            for(int i = 0; i < nblocks; i++)
            {
                uint64 k1 = murmur_getblock_byte_swap(blocks,i*2+0);
                uint64 k2 = murmur_getblock_byte_swap(blocks,i*2+1);

                k1 *= c1; k1  = DLIB_ROTL64(k1,31); k1 *= c2; h1 ^= k1;

                h1 = DLIB_ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729;

                k2 *= c2; k2  = DLIB_ROTL64(k2,33); k2 *= c1; h2 ^= k2;

                h2 = DLIB_ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5;
            }
        }

        //----------
        // tail

        const uint8 * tail = (const uint8*)(data + nblocks*16);

        uint64 k1 = 0;
        uint64 k2 = 0;

        switch(len & 15)
        {
            case 15: k2 ^= uint64(tail[14]) << 48;
            case 14: k2 ^= uint64(tail[13]) << 40;
            case 13: k2 ^= uint64(tail[12]) << 32;
            case 12: k2 ^= uint64(tail[11]) << 24;
            case 11: k2 ^= uint64(tail[10]) << 16;
            case 10: k2 ^= uint64(tail[ 9]) << 8;
            case  9: k2 ^= uint64(tail[ 8]) << 0;
                     k2 *= c2; k2  = DLIB_ROTL64(k2,33); k2 *= c1; h2 ^= k2;

            case  8: k1 ^= uint64(tail[ 7]) << 56;
            case  7: k1 ^= uint64(tail[ 6]) << 48;
            case  6: k1 ^= uint64(tail[ 5]) << 40;
            case  5: k1 ^= uint64(tail[ 4]) << 32;
            case  4: k1 ^= uint64(tail[ 3]) << 24;
            case  3: k1 ^= uint64(tail[ 2]) << 16;
            case  2: k1 ^= uint64(tail[ 1]) << 8;
            case  1: k1 ^= uint64(tail[ 0]) << 0;
                     k1 *= c1; k1  = DLIB_ROTL64(k1,31); k1 *= c2; h1 ^= k1;
        };

        //----------
        // finalization

        h1 ^= len; h2 ^= len;

        h1 += h2;
        h2 += h1;

        h1 = murmur_fmix(h1);
        h2 = murmur_fmix(h2);

        h1 += h2;
        h2 += h1;

        return std::make_pair(h1,h2);
    }

// ----------------------------------------------------------------------------------------

    inline std::pair<uint64,uint64> murmur_hash3_128bit (
        const uint32& v1,
        const uint32& v2,
        const uint32& v3,
        const uint32& v4
    )
    {
        uint64 h1 = 0;
        uint64 h2 = 0;

        const uint64 c1 = DLIB_BIG_CONSTANT(0x87c37b91114253d5);
        const uint64 c2 = DLIB_BIG_CONSTANT(0x4cf5ad432745937f);

        //----------
        // body

        uint64 k1 = (static_cast<uint64>(v2)<<32)|v1;
        uint64 k2 = (static_cast<uint64>(v4)<<32)|v3;

        k1 *= c1; k1  = DLIB_ROTL64(k1,31); k1 *= c2;

        h1 = DLIB_ROTL64(k1,27); h1 = h1*5+0x52dce729;

        k2 *= c2; k2  = DLIB_ROTL64(k2,33); k2 *= c1;

        h2 = DLIB_ROTL64(k2,31); h2 += h1; h2 = h2*5+0x38495ab5;

        //----------
        // finalization

        h1 ^= 16; h2 ^= 16;

        h1 += h2;
        h2 += h1;

        h1 = murmur_fmix(h1);
        h2 = murmur_fmix(h2);

        h1 += h2;
        h2 += h1;

        return std::make_pair(h1,h2);
    }

// ----------------------------------------------------------------------------------------

    inline std::pair<uint64,uint64> murmur_hash3_128bit_3 (
        uint64 k1,
        uint64 k2,
        uint64 k3
    )
    {
        uint64 h1 = k3;
        uint64 h2 = k3;

        const uint64 c1 = DLIB_BIG_CONSTANT(0x87c37b91114253d5);
        const uint64 c2 = DLIB_BIG_CONSTANT(0x4cf5ad432745937f);

        //----------
        // body

        k1 *= c1; k1  = DLIB_ROTL64(k1,31); k1 *= c2; h1 ^= k1;

        h1 = DLIB_ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729;

        k2 *= c2; k2  = DLIB_ROTL64(k2,33); k2 *= c1; h2 ^= k2;

        h2 = DLIB_ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5;

        //----------
        // finalization

        h1 ^= 16; h2 ^= 16;

        h1 += h2;
        h2 += h1;

        h1 = murmur_fmix(h1);
        h2 = murmur_fmix(h2);

        h1 += h2;
        h2 += h1;

        return std::make_pair(h1,h2);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MURMUR_HAsH_3_Hh_


dlib C++ Library - random_hashing.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_RANDOM_HAsHING_Hh_
#define DLIB_RANDOM_HAsHING_Hh_

#include "random_hashing_abstract.h"
#include "murmur_hash3.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    inline double uniform_random_hash (
        const uint64& k1,
        const uint64& k2,
        const uint64& k3
    )
    {
        const std::pair<uint64,uint64> h = murmur_hash3_128bit_3(k1,k2,k3);
        const uint64 mask = DLIB_BIG_CONSTANT(0xFFFFFFFFFF);
        const double max = mask+1;
        return static_cast<double>(h.first&mask)/max;
    }

// ----------------------------------------------------------------------------------------

    inline double gaussian_random_hash (
        const uint64& k1,
        const uint64& k2,
        const uint64& k3
    )
    {
        const std::pair<uint64,uint64> h = murmur_hash3_128bit_3(k1,k2,k3);

        const static unsigned int max = 4096;

        const static double logvals[max] = {
        4.079, 3.905, 3.8, 3.723, 3.663, 3.613, 3.57, 3.532, 3.499, 3.468,
        3.441, 3.416, 3.392, 3.37, 3.35, 3.33, 3.312, 3.295, 3.278, 3.263,
        3.248, 3.233, 3.219, 3.206, 3.193, 3.181, 3.169, 3.158, 3.147, 3.136,
        3.125, 3.115, 3.105, 3.096, 3.086, 3.077, 3.068, 3.059, 3.051, 3.043,
        3.035, 3.027, 3.019, 3.011, 3.004, 2.996, 2.989, 2.982, 2.975, 2.968,
        2.962, 2.955, 2.949, 2.942, 2.936, 2.93, 2.924, 2.918, 2.912, 2.906,
        2.901, 2.895, 2.89, 2.884, 2.879, 2.873, 2.868, 2.863, 2.858, 2.853,
        2.848, 2.843, 2.838, 2.833, 2.829, 2.824, 2.819, 2.815, 2.81, 2.806,
        2.801, 2.797, 2.792, 2.788, 2.784, 2.78, 2.776, 2.771, 2.767, 2.763,
        2.759, 2.755, 2.751, 2.748, 2.744, 2.74, 2.736, 2.732, 2.729, 2.725,
        2.721, 2.718, 2.714, 2.71, 2.707, 2.703, 2.7, 2.697, 2.693, 2.69,
        2.686, 2.683, 2.68, 2.676, 2.673, 2.67, 2.667, 2.663, 2.66, 2.657,
        2.654, 2.651, 2.648, 2.645, 2.642, 2.639, 2.636, 2.633, 2.63, 2.627,
        2.624, 2.621, 2.618, 2.615, 2.612, 2.61, 2.607, 2.604, 2.601, 2.599,
        2.596, 2.593, 2.59, 2.588, 2.585, 2.582, 2.58, 2.577, 2.574, 2.572,
        2.569, 2.567, 2.564, 2.562, 2.559, 2.557, 2.554, 2.552, 2.549, 2.547,
        2.544, 2.542, 2.539, 2.537, 2.534, 2.532, 2.53, 2.527, 2.525, 2.523,
        2.52, 2.518, 2.516, 2.513, 2.511, 2.509, 2.507, 2.504, 2.502, 2.5,
        2.498, 2.495, 2.493, 2.491, 2.489, 2.487, 2.485, 2.482, 2.48, 2.478,
        2.476, 2.474, 2.472, 2.47, 2.468, 2.466, 2.464, 2.462, 2.459, 2.457,
        2.455, 2.453, 2.451, 2.449, 2.447, 2.445, 2.443, 2.441, 2.439, 2.437,
        2.436, 2.434, 2.432, 2.43, 2.428, 2.426, 2.424, 2.422, 2.42, 2.418,
        2.416, 2.415, 2.413, 2.411, 2.409, 2.407, 2.405, 2.404, 2.402, 2.4,
        2.398, 2.396, 2.394, 2.393, 2.391, 2.389, 2.387, 2.386, 2.384, 2.382,
        2.38, 2.379, 2.377, 2.375, 2.373, 2.372, 2.37, 2.368, 2.367, 2.365,
        2.363, 2.361, 2.36, 2.358, 2.356, 2.355, 2.353, 2.352, 2.35, 2.348,
        2.347, 2.345, 2.343, 2.342, 2.34, 2.338, 2.337, 2.335, 2.334, 2.332,
        2.331, 2.329, 2.327, 2.326, 2.324, 2.323, 2.321, 2.32, 2.318, 2.316,
        2.315, 2.313, 2.312, 2.31, 2.309, 2.307, 2.306, 2.304, 2.303, 2.301,
        2.3, 2.298, 2.297, 2.295, 2.294, 2.292, 2.291, 2.289, 2.288, 2.286,
        2.285, 2.284, 2.282, 2.281, 2.279, 2.278, 2.276, 2.275, 2.274, 2.272,
        2.271, 2.269, 2.268, 2.266, 2.265, 2.264, 2.262, 2.261, 2.259, 2.258,
        2.257, 2.255, 2.254, 2.253, 2.251, 2.25, 2.248, 2.247, 2.246, 2.244,
        2.243, 2.242, 2.24, 2.239, 2.238, 2.236, 2.235, 2.234, 2.232, 2.231,
        2.23, 2.228, 2.227, 2.226, 2.225, 2.223, 2.222, 2.221, 2.219, 2.218,
        2.217, 2.215, 2.214, 2.213, 2.212, 2.21, 2.209, 2.208, 2.207, 2.205,
        2.204, 2.203, 2.202, 2.2, 2.199, 2.198, 2.197, 2.195, 2.194, 2.193,
        2.192, 2.19, 2.189, 2.188, 2.187, 2.185, 2.184, 2.183, 2.182, 2.181,
        2.179, 2.178, 2.177, 2.176, 2.175, 2.173, 2.172, 2.171, 2.17, 2.169,
        2.168, 2.166, 2.165, 2.164, 2.163, 2.162, 2.16, 2.159, 2.158, 2.157,
        2.156, 2.155, 2.154, 2.152, 2.151, 2.15, 2.149, 2.148, 2.147, 2.146,
        2.144, 2.143, 2.142, 2.141, 2.14, 2.139, 2.138, 2.136, 2.135, 2.134,
        2.133, 2.132, 2.131, 2.13, 2.129, 2.128, 2.126, 2.125, 2.124, 2.123,
        2.122, 2.121, 2.12, 2.119, 2.118, 2.117, 2.116, 2.114, 2.113, 2.112,
        2.111, 2.11, 2.109, 2.108, 2.107, 2.106, 2.105, 2.104, 2.103, 2.102,
        2.101, 2.1, 2.099, 2.097, 2.096, 2.095, 2.094, 2.093, 2.092, 2.091,
        2.09, 2.089, 2.088, 2.087, 2.086, 2.085, 2.084, 2.083, 2.082, 2.081,
        2.08, 2.079, 2.078, 2.077, 2.076, 2.075, 2.074, 2.073, 2.072, 2.071,
        2.07, 2.069, 2.068, 2.067, 2.066, 2.065, 2.064, 2.063, 2.062, 2.061,
        2.06, 2.059, 2.058, 2.057, 2.056, 2.055, 2.054, 2.053, 2.052, 2.051,
        2.05, 2.049, 2.048, 2.047, 2.046, 2.045, 2.044, 2.043, 2.042, 2.041,
        2.04, 2.039, 2.038, 2.037, 2.036, 2.036, 2.035, 2.034, 2.033, 2.032,
        2.031, 2.03, 2.029, 2.028, 2.027, 2.026, 2.025, 2.024, 2.023, 2.022,
        2.021, 2.02, 2.02, 2.019, 2.018, 2.017, 2.016, 2.015, 2.014, 2.013,
        2.012, 2.011, 2.01, 2.009, 2.008, 2.008, 2.007, 2.006, 2.005, 2.004,
        2.003, 2.002, 2.001, 2, 1.999, 1.998, 1.998, 1.997, 1.996, 1.995,
        1.994, 1.993, 1.992, 1.991, 1.99, 1.99, 1.989, 1.988, 1.987, 1.986,
        1.985, 1.984, 1.983, 1.982, 1.982, 1.981, 1.98, 1.979, 1.978, 1.977,
        1.976, 1.975, 1.975, 1.974, 1.973, 1.972, 1.971, 1.97, 1.969, 1.969,
        1.968, 1.967, 1.966, 1.965, 1.964, 1.963, 1.963, 1.962, 1.961, 1.96,
        1.959, 1.958, 1.957, 1.957, 1.956, 1.955, 1.954, 1.953, 1.952, 1.952,
        1.951, 1.95, 1.949, 1.948, 1.947, 1.947, 1.946, 1.945, 1.944, 1.943,
        1.942, 1.942, 1.941, 1.94, 1.939, 1.938, 1.937, 1.937, 1.936, 1.935,
        1.934, 1.933, 1.933, 1.932, 1.931, 1.93, 1.929, 1.928, 1.928, 1.927,
        1.926, 1.925, 1.924, 1.924, 1.923, 1.922, 1.921, 1.92, 1.92, 1.919,
        1.918, 1.917, 1.916, 1.916, 1.915, 1.914, 1.913, 1.912, 1.912, 1.911,
        1.91, 1.909, 1.908, 1.908, 1.907, 1.906, 1.905, 1.904, 1.904, 1.903,
        1.902, 1.901, 1.901, 1.9, 1.899, 1.898, 1.897, 1.897, 1.896, 1.895,
        1.894, 1.894, 1.893, 1.892, 1.891, 1.89, 1.89, 1.889, 1.888, 1.887,
        1.887, 1.886, 1.885, 1.884, 1.884, 1.883, 1.882, 1.881, 1.88, 1.88,
        1.879, 1.878, 1.877, 1.877, 1.876, 1.875, 1.874, 1.874, 1.873, 1.872,
        1.871, 1.871, 1.87, 1.869, 1.868, 1.868, 1.867, 1.866, 1.865, 1.865,
        1.864, 1.863, 1.862, 1.862, 1.861, 1.86, 1.859, 1.859, 1.858, 1.857,
        1.857, 1.856, 1.855, 1.854, 1.854, 1.853, 1.852, 1.851, 1.851, 1.85,
        1.849, 1.848, 1.848, 1.847, 1.846, 1.846, 1.845, 1.844, 1.843, 1.843,
        1.842, 1.841, 1.84, 1.84, 1.839, 1.838, 1.838, 1.837, 1.836, 1.835,
        1.835, 1.834, 1.833, 1.833, 1.832, 1.831, 1.83, 1.83, 1.829, 1.828,
        1.828, 1.827, 1.826, 1.825, 1.825, 1.824, 1.823, 1.823, 1.822, 1.821,
        1.821, 1.82, 1.819, 1.818, 1.818, 1.817, 1.816, 1.816, 1.815, 1.814,
        1.814, 1.813, 1.812, 1.811, 1.811, 1.81, 1.809, 1.809, 1.808, 1.807,
        1.807, 1.806, 1.805, 1.805, 1.804, 1.803, 1.802, 1.802, 1.801, 1.8,
        1.8, 1.799, 1.798, 1.798, 1.797, 1.796, 1.796, 1.795, 1.794, 1.794,
        1.793, 1.792, 1.792, 1.791, 1.79, 1.79, 1.789, 1.788, 1.787, 1.787,
        1.786, 1.785, 1.785, 1.784, 1.783, 1.783, 1.782, 1.781, 1.781, 1.78,
        1.779, 1.779, 1.778, 1.777, 1.777, 1.776, 1.775, 1.775, 1.774, 1.773,
        1.773, 1.772, 1.771, 1.771, 1.77, 1.769, 1.769, 1.768, 1.767, 1.767,
        1.766, 1.766, 1.765, 1.764, 1.764, 1.763, 1.762, 1.762, 1.761, 1.76,
        1.76, 1.759, 1.758, 1.758, 1.757, 1.756, 1.756, 1.755, 1.754, 1.754,
        1.753, 1.752, 1.752, 1.751, 1.751, 1.75, 1.749, 1.749, 1.748, 1.747,
        1.747, 1.746, 1.745, 1.745, 1.744, 1.743, 1.743, 1.742, 1.742, 1.741,
        1.74, 1.74, 1.739, 1.738, 1.738, 1.737, 1.736, 1.736, 1.735, 1.735,
        1.734, 1.733, 1.733, 1.732, 1.731, 1.731, 1.73, 1.729, 1.729, 1.728,
        1.728, 1.727, 1.726, 1.726, 1.725, 1.724, 1.724, 1.723, 1.723, 1.722,
        1.721, 1.721, 1.72, 1.719, 1.719, 1.718, 1.718, 1.717, 1.716, 1.716,
        1.715, 1.715, 1.714, 1.713, 1.713, 1.712, 1.711, 1.711, 1.71, 1.71,
        1.709, 1.708, 1.708, 1.707, 1.706, 1.706, 1.705, 1.705, 1.704, 1.703,
        1.703, 1.702, 1.702, 1.701, 1.7, 1.7, 1.699, 1.699, 1.698, 1.697,
        1.697, 1.696, 1.696, 1.695, 1.694, 1.694, 1.693, 1.692, 1.692, 1.691,
        1.691, 1.69, 1.689, 1.689, 1.688, 1.688, 1.687, 1.686, 1.686, 1.685,
        1.685, 1.684, 1.683, 1.683, 1.682, 1.682, 1.681, 1.68, 1.68, 1.679,
        1.679, 1.678, 1.678, 1.677, 1.676, 1.676, 1.675, 1.675, 1.674, 1.673,
        1.673, 1.672, 1.672, 1.671, 1.67, 1.67, 1.669, 1.669, 1.668, 1.667,
        1.667, 1.666, 1.666, 1.665, 1.665, 1.664, 1.663, 1.663, 1.662, 1.662,
        1.661, 1.66, 1.66, 1.659, 1.659, 1.658, 1.658, 1.657, 1.656, 1.656,
        1.655, 1.655, 1.654, 1.653, 1.653, 1.652, 1.652, 1.651, 1.651, 1.65,
        1.649, 1.649, 1.648, 1.648, 1.647, 1.647, 1.646, 1.645, 1.645, 1.644,
        1.644, 1.643, 1.643, 1.642, 1.641, 1.641, 1.64, 1.64, 1.639, 1.639,
        1.638, 1.637, 1.637, 1.636, 1.636, 1.635, 1.635, 1.634, 1.633, 1.633,
        1.632, 1.632, 1.631, 1.631, 1.63, 1.629, 1.629, 1.628, 1.628, 1.627,
        1.627, 1.626, 1.625, 1.625, 1.624, 1.624, 1.623, 1.623, 1.622, 1.622,
        1.621, 1.62, 1.62, 1.619, 1.619, 1.618, 1.618, 1.617, 1.617, 1.616,
        1.615, 1.615, 1.614, 1.614, 1.613, 1.613, 1.612, 1.612, 1.611, 1.61,
        1.61, 1.609, 1.609, 1.608, 1.608, 1.607, 1.607, 1.606, 1.605, 1.605,
        1.604, 1.604, 1.603, 1.603, 1.602, 1.602, 1.601, 1.6, 1.6, 1.599,
        1.599, 1.598, 1.598, 1.597, 1.597, 1.596, 1.596, 1.595, 1.594, 1.594,
        1.593, 1.593, 1.592, 1.592, 1.591, 1.591, 1.59, 1.59, 1.589, 1.588,
        1.588, 1.587, 1.587, 1.586, 1.586, 1.585, 1.585, 1.584, 1.584, 1.583,
        1.582, 1.582, 1.581, 1.581, 1.58, 1.58, 1.579, 1.579, 1.578, 1.578,
        1.577, 1.577, 1.576, 1.576, 1.575, 1.574, 1.574, 1.573, 1.573, 1.572,
        1.572, 1.571, 1.571, 1.57, 1.57, 1.569, 1.569, 1.568, 1.567, 1.567,
        1.566, 1.566, 1.565, 1.565, 1.564, 1.564, 1.563, 1.563, 1.562, 1.562,
        1.561, 1.561, 1.56, 1.56, 1.559, 1.558, 1.558, 1.557, 1.557, 1.556,
        1.556, 1.555, 1.555, 1.554, 1.554, 1.553, 1.553, 1.552, 1.552, 1.551,
        1.551, 1.55, 1.55, 1.549, 1.549, 1.548, 1.547, 1.547, 1.546, 1.546,
        1.545, 1.545, 1.544, 1.544, 1.543, 1.543, 1.542, 1.542, 1.541, 1.541,
        1.54, 1.54, 1.539, 1.539, 1.538, 1.538, 1.537, 1.537, 1.536, 1.536,
        1.535, 1.534, 1.534, 1.533, 1.533, 1.532, 1.532, 1.531, 1.531, 1.53,
        1.53, 1.529, 1.529, 1.528, 1.528, 1.527, 1.527, 1.526, 1.526, 1.525,
        1.525, 1.524, 1.524, 1.523, 1.523, 1.522, 1.522, 1.521, 1.521, 1.52,
        1.52, 1.519, 1.519, 1.518, 1.518, 1.517, 1.517, 1.516, 1.516, 1.515,
        1.515, 1.514, 1.514, 1.513, 1.512, 1.512, 1.511, 1.511, 1.51, 1.51,
        1.509, 1.509, 1.508, 1.508, 1.507, 1.507, 1.506, 1.506, 1.505, 1.505,
        1.504, 1.504, 1.503, 1.503, 1.502, 1.502, 1.501, 1.501, 1.5, 1.5,
        1.499, 1.499, 1.498, 1.498, 1.497, 1.497, 1.496, 1.496, 1.495, 1.495,
        1.494, 1.494, 1.493, 1.493, 1.492, 1.492, 1.491, 1.491, 1.49, 1.49,
        1.489, 1.489, 1.488, 1.488, 1.487, 1.487, 1.486, 1.486, 1.485, 1.485,
        1.484, 1.484, 1.483, 1.483, 1.482, 1.482, 1.481, 1.481, 1.48, 1.48,
        1.48, 1.479, 1.479, 1.478, 1.478, 1.477, 1.477, 1.476, 1.476, 1.475,
        1.475, 1.474, 1.474, 1.473, 1.473, 1.472, 1.472, 1.471, 1.471, 1.47,
        1.47, 1.469, 1.469, 1.468, 1.468, 1.467, 1.467, 1.466, 1.466, 1.465,
        1.465, 1.464, 1.464, 1.463, 1.463, 1.462, 1.462, 1.461, 1.461, 1.46,
        1.46, 1.459, 1.459, 1.458, 1.458, 1.458, 1.457, 1.457, 1.456, 1.456,
        1.455, 1.455, 1.454, 1.454, 1.453, 1.453, 1.452, 1.452, 1.451, 1.451,
        1.45, 1.45, 1.449, 1.449, 1.448, 1.448, 1.447, 1.447, 1.446, 1.446,
        1.445, 1.445, 1.444, 1.444, 1.444, 1.443, 1.443, 1.442, 1.442, 1.441,
        1.441, 1.44, 1.44, 1.439, 1.439, 1.438, 1.438, 1.437, 1.437, 1.436,
        1.436, 1.435, 1.435, 1.434, 1.434, 1.434, 1.433, 1.433, 1.432, 1.432,
        1.431, 1.431, 1.43, 1.43, 1.429, 1.429, 1.428, 1.428, 1.427, 1.427,
        1.426, 1.426, 1.425, 1.425, 1.424, 1.424, 1.424, 1.423, 1.423, 1.422,
        1.422, 1.421, 1.421, 1.42, 1.42, 1.419, 1.419, 1.418, 1.418, 1.417,
        1.417, 1.416, 1.416, 1.416, 1.415, 1.415, 1.414, 1.414, 1.413, 1.413,
        1.412, 1.412, 1.411, 1.411, 1.41, 1.41, 1.409, 1.409, 1.409, 1.408,
        1.408, 1.407, 1.407, 1.406, 1.406, 1.405, 1.405, 1.404, 1.404, 1.403,
        1.403, 1.402, 1.402, 1.402, 1.401, 1.401, 1.4, 1.4, 1.399, 1.399,
        1.398, 1.398, 1.397, 1.397, 1.396, 1.396, 1.395, 1.395, 1.395, 1.394,
        1.394, 1.393, 1.393, 1.392, 1.392, 1.391, 1.391, 1.39, 1.39, 1.389,
        1.389, 1.389, 1.388, 1.388, 1.387, 1.387, 1.386, 1.386, 1.385, 1.385,
        1.384, 1.384, 1.383, 1.383, 1.383, 1.382, 1.382, 1.381, 1.381, 1.38,
        1.38, 1.379, 1.379, 1.378, 1.378, 1.378, 1.377, 1.377, 1.376, 1.376,
        1.375, 1.375, 1.374, 1.374, 1.373, 1.373, 1.373, 1.372, 1.372, 1.371,
        1.371, 1.37, 1.37, 1.369, 1.369, 1.368, 1.368, 1.367, 1.367, 1.367,
        1.366, 1.366, 1.365, 1.365, 1.364, 1.364, 1.363, 1.363, 1.362, 1.362,
        1.362, 1.361, 1.361, 1.36, 1.36, 1.359, 1.359, 1.358, 1.358, 1.358,
        1.357, 1.357, 1.356, 1.356, 1.355, 1.355, 1.354, 1.354, 1.353, 1.353,
        1.353, 1.352, 1.352, 1.351, 1.351, 1.35, 1.35, 1.349, 1.349, 1.349,
        1.348, 1.348, 1.347, 1.347, 1.346, 1.346, 1.345, 1.345, 1.344, 1.344,
        1.344, 1.343, 1.343, 1.342, 1.342, 1.341, 1.341, 1.34, 1.34, 1.34,
        1.339, 1.339, 1.338, 1.338, 1.337, 1.337, 1.336, 1.336, 1.336, 1.335,
        1.335, 1.334, 1.334, 1.333, 1.333, 1.332, 1.332, 1.332, 1.331, 1.331,
        1.33, 1.33, 1.329, 1.329, 1.328, 1.328, 1.328, 1.327, 1.327, 1.326,
        1.326, 1.325, 1.325, 1.324, 1.324, 1.324, 1.323, 1.323, 1.322, 1.322,
        1.321, 1.321, 1.32, 1.32, 1.32, 1.319, 1.319, 1.318, 1.318, 1.317,
        1.317, 1.316, 1.316, 1.316, 1.315, 1.315, 1.314, 1.314, 1.313, 1.313,
        1.312, 1.312, 1.312, 1.311, 1.311, 1.31, 1.31, 1.309, 1.309, 1.309,
        1.308, 1.308, 1.307, 1.307, 1.306, 1.306, 1.305, 1.305, 1.305, 1.304,
        1.304, 1.303, 1.303, 1.302, 1.302, 1.302, 1.301, 1.301, 1.3, 1.3,
        1.299, 1.299, 1.298, 1.298, 1.298, 1.297, 1.297, 1.296, 1.296, 1.295,
        1.295, 1.295, 1.294, 1.294, 1.293, 1.293, 1.292, 1.292, 1.291, 1.291,
        1.291, 1.29, 1.29, 1.289, 1.289, 1.288, 1.288, 1.288, 1.287, 1.287,
        1.286, 1.286, 1.285, 1.285, 1.285, 1.284, 1.284, 1.283, 1.283, 1.282,
        1.282, 1.281, 1.281, 1.281, 1.28, 1.28, 1.279, 1.279, 1.278, 1.278,
        1.278, 1.277, 1.277, 1.276, 1.276, 1.275, 1.275, 1.275, 1.274, 1.274,
        1.273, 1.273, 1.272, 1.272, 1.272, 1.271, 1.271, 1.27, 1.27, 1.269,
        1.269, 1.269, 1.268, 1.268, 1.267, 1.267, 1.266, 1.266, 1.266, 1.265,
        1.265, 1.264, 1.264, 1.263, 1.263, 1.263, 1.262, 1.262, 1.261, 1.261,
        1.26, 1.26, 1.26, 1.259, 1.259, 1.258, 1.258, 1.257, 1.257, 1.257,
        1.256, 1.256, 1.255, 1.255, 1.254, 1.254, 1.254, 1.253, 1.253, 1.252,
        1.252, 1.251, 1.251, 1.251, 1.25, 1.25, 1.249, 1.249, 1.248, 1.248,
        1.248, 1.247, 1.247, 1.246, 1.246, 1.245, 1.245, 1.245, 1.244, 1.244,
        1.243, 1.243, 1.242, 1.242, 1.242, 1.241, 1.241, 1.24, 1.24, 1.239,
        1.239, 1.239, 1.238, 1.238, 1.237, 1.237, 1.237, 1.236, 1.236, 1.235,
        1.235, 1.234, 1.234, 1.234, 1.233, 1.233, 1.232, 1.232, 1.231, 1.231,
        1.231, 1.23, 1.23, 1.229, 1.229, 1.228, 1.228, 1.228, 1.227, 1.227,
        1.226, 1.226, 1.226, 1.225, 1.225, 1.224, 1.224, 1.223, 1.223, 1.223,
        1.222, 1.222, 1.221, 1.221, 1.22, 1.22, 1.22, 1.219, 1.219, 1.218,
        1.218, 1.218, 1.217, 1.217, 1.216, 1.216, 1.215, 1.215, 1.215, 1.214,
        1.214, 1.213, 1.213, 1.212, 1.212, 1.212, 1.211, 1.211, 1.21, 1.21,
        1.21, 1.209, 1.209, 1.208, 1.208, 1.207, 1.207, 1.207, 1.206, 1.206,
        1.205, 1.205, 1.204, 1.204, 1.204, 1.203, 1.203, 1.202, 1.202, 1.202,
        1.201, 1.201, 1.2, 1.2, 1.199, 1.199, 1.199, 1.198, 1.198, 1.197,
        1.197, 1.197, 1.196, 1.196, 1.195, 1.195, 1.194, 1.194, 1.194, 1.193,
        1.193, 1.192, 1.192, 1.192, 1.191, 1.191, 1.19, 1.19, 1.189, 1.189,
        1.189, 1.188, 1.188, 1.187, 1.187, 1.187, 1.186, 1.186, 1.185, 1.185,
        1.184, 1.184, 1.184, 1.183, 1.183, 1.182, 1.182, 1.182, 1.181, 1.181,
        1.18, 1.18, 1.179, 1.179, 1.179, 1.178, 1.178, 1.177, 1.177, 1.177,
        1.176, 1.176, 1.175, 1.175, 1.175, 1.174, 1.174, 1.173, 1.173, 1.172,
        1.172, 1.172, 1.171, 1.171, 1.17, 1.17, 1.17, 1.169, 1.169, 1.168,
        1.168, 1.167, 1.167, 1.167, 1.166, 1.166, 1.165, 1.165, 1.165, 1.164,
        1.164, 1.163, 1.163, 1.163, 1.162, 1.162, 1.161, 1.161, 1.16, 1.16,
        1.16, 1.159, 1.159, 1.158, 1.158, 1.158, 1.157, 1.157, 1.156, 1.156,
        1.156, 1.155, 1.155, 1.154, 1.154, 1.153, 1.153, 1.153, 1.152, 1.152,
        1.151, 1.151, 1.151, 1.15, 1.15, 1.149, 1.149, 1.149, 1.148, 1.148,
        1.147, 1.147, 1.146, 1.146, 1.146, 1.145, 1.145, 1.144, 1.144, 1.144,
        1.143, 1.143, 1.142, 1.142, 1.142, 1.141, 1.141, 1.14, 1.14, 1.139,
        1.139, 1.139, 1.138, 1.138, 1.137, 1.137, 1.137, 1.136, 1.136, 1.135,
        1.135, 1.135, 1.134, 1.134, 1.133, 1.133, 1.133, 1.132, 1.132, 1.131,
        1.131, 1.13, 1.13, 1.13, 1.129, 1.129, 1.128, 1.128, 1.128, 1.127,
        1.127, 1.126, 1.126, 1.126, 1.125, 1.125, 1.124, 1.124, 1.124, 1.123,
        1.123, 1.122, 1.122, 1.121, 1.121, 1.121, 1.12, 1.12, 1.119, 1.119,
        1.119, 1.118, 1.118, 1.117, 1.117, 1.117, 1.116, 1.116, 1.115, 1.115,
        1.115, 1.114, 1.114, 1.113, 1.113, 1.113, 1.112, 1.112, 1.111, 1.111,
        1.11, 1.11, 1.11, 1.109, 1.109, 1.108, 1.108, 1.108, 1.107, 1.107,
        1.106, 1.106, 1.106, 1.105, 1.105, 1.104, 1.104, 1.104, 1.103, 1.103,
        1.102, 1.102, 1.102, 1.101, 1.101, 1.1, 1.1, 1.099, 1.099, 1.099,
        1.098, 1.098, 1.097, 1.097, 1.097, 1.096, 1.096, 1.095, 1.095, 1.095,
        1.094, 1.094, 1.093, 1.093, 1.093, 1.092, 1.092, 1.091, 1.091, 1.091,
        1.09, 1.09, 1.089, 1.089, 1.089, 1.088, 1.088, 1.087, 1.087, 1.086,
        1.086, 1.086, 1.085, 1.085, 1.084, 1.084, 1.084, 1.083, 1.083, 1.082,
        1.082, 1.082, 1.081, 1.081, 1.08, 1.08, 1.08, 1.079, 1.079, 1.078,
        1.078, 1.078, 1.077, 1.077, 1.076, 1.076, 1.076, 1.075, 1.075, 1.074,
        1.074, 1.074, 1.073, 1.073, 1.072, 1.072, 1.072, 1.071, 1.071, 1.07,
        1.07, 1.069, 1.069, 1.069, 1.068, 1.068, 1.067, 1.067, 1.067, 1.066,
        1.066, 1.065, 1.065, 1.065, 1.064, 1.064, 1.063, 1.063, 1.063, 1.062,
        1.062, 1.061, 1.061, 1.061, 1.06, 1.06, 1.059, 1.059, 1.059, 1.058,
        1.058, 1.057, 1.057, 1.057, 1.056, 1.056, 1.055, 1.055, 1.055, 1.054,
        1.054, 1.053, 1.053, 1.053, 1.052, 1.052, 1.051, 1.051, 1.05, 1.05,
        1.05, 1.049, 1.049, 1.048, 1.048, 1.048, 1.047, 1.047, 1.046, 1.046,
        1.046, 1.045, 1.045, 1.044, 1.044, 1.044, 1.043, 1.043, 1.042, 1.042,
        1.042, 1.041, 1.041, 1.04, 1.04, 1.04, 1.039, 1.039, 1.038, 1.038,
        1.038, 1.037, 1.037, 1.036, 1.036, 1.036, 1.035, 1.035, 1.034, 1.034,
        1.034, 1.033, 1.033, 1.032, 1.032, 1.032, 1.031, 1.031, 1.03, 1.03,
        1.03, 1.029, 1.029, 1.028, 1.028, 1.028, 1.027, 1.027, 1.026, 1.026,
        1.026, 1.025, 1.025, 1.024, 1.024, 1.023, 1.023, 1.023, 1.022, 1.022,
        1.021, 1.021, 1.021, 1.02, 1.02, 1.019, 1.019, 1.019, 1.018, 1.018,
        1.017, 1.017, 1.017, 1.016, 1.016, 1.015, 1.015, 1.015, 1.014, 1.014,
        1.013, 1.013, 1.013, 1.012, 1.012, 1.011, 1.011, 1.011, 1.01, 1.01,
        1.009, 1.009, 1.009, 1.008, 1.008, 1.007, 1.007, 1.007, 1.006, 1.006,
        1.005, 1.005, 1.005, 1.004, 1.004, 1.003, 1.003, 1.003, 1.002, 1.002,
        1.001, 1.001, 1.001, 1, 0.9997, 0.9993, 0.9989, 0.9985, 0.9981, 0.9977,
        0.9973, 0.9969, 0.9965, 0.9961, 0.9957, 0.9953, 0.9949, 0.9945, 0.9941, 0.9937,
        0.9933, 0.9929, 0.9925, 0.9921, 0.9917, 0.9913, 0.9909, 0.9905, 0.9901, 0.9897,
        0.9893, 0.9889, 0.9885, 0.9881, 0.9877, 0.9873, 0.9869, 0.9865, 0.9861, 0.9856,
        0.9852, 0.9848, 0.9844, 0.984, 0.9836, 0.9832, 0.9828, 0.9824, 0.982, 0.9816,
        0.9812, 0.9808, 0.9804, 0.98, 0.9796, 0.9792, 0.9788, 0.9784, 0.978, 0.9776,
        0.9772, 0.9768, 0.9764, 0.976, 0.9756, 0.9752, 0.9748, 0.9744, 0.974, 0.9736,
        0.9732, 0.9728, 0.9724, 0.972, 0.9716, 0.9712, 0.9707, 0.9703, 0.9699, 0.9695,
        0.9691, 0.9687, 0.9683, 0.9679, 0.9675, 0.9671, 0.9667, 0.9663, 0.9659, 0.9655,
        0.9651, 0.9647, 0.9643, 0.9639, 0.9635, 0.9631, 0.9627, 0.9623, 0.9619, 0.9615,
        0.9611, 0.9607, 0.9603, 0.9599, 0.9595, 0.9591, 0.9587, 0.9583, 0.9579, 0.9574,
        0.957, 0.9566, 0.9562, 0.9558, 0.9554, 0.955, 0.9546, 0.9542, 0.9538, 0.9534,
        0.953, 0.9526, 0.9522, 0.9518, 0.9514, 0.951, 0.9506, 0.9502, 0.9498, 0.9494,
        0.949, 0.9486, 0.9482, 0.9478, 0.9474, 0.947, 0.9466, 0.9462, 0.9457, 0.9453,
        0.9449, 0.9445, 0.9441, 0.9437, 0.9433, 0.9429, 0.9425, 0.9421, 0.9417, 0.9413,
        0.9409, 0.9405, 0.9401, 0.9397, 0.9393, 0.9389, 0.9385, 0.9381, 0.9377, 0.9373,
        0.9369, 0.9365, 0.9361, 0.9356, 0.9352, 0.9348, 0.9344, 0.934, 0.9336, 0.9332,
        0.9328, 0.9324, 0.932, 0.9316, 0.9312, 0.9308, 0.9304, 0.93, 0.9296, 0.9292,
        0.9288, 0.9284, 0.928, 0.9276, 0.9272, 0.9267, 0.9263, 0.9259, 0.9255, 0.9251,
        0.9247, 0.9243, 0.9239, 0.9235, 0.9231, 0.9227, 0.9223, 0.9219, 0.9215, 0.9211,
        0.9207, 0.9203, 0.9199, 0.9195, 0.9191, 0.9186, 0.9182, 0.9178, 0.9174, 0.917,
        0.9166, 0.9162, 0.9158, 0.9154, 0.915, 0.9146, 0.9142, 0.9138, 0.9134, 0.913,
        0.9126, 0.9122, 0.9118, 0.9113, 0.9109, 0.9105, 0.9101, 0.9097, 0.9093, 0.9089,
        0.9085, 0.9081, 0.9077, 0.9073, 0.9069, 0.9065, 0.9061, 0.9057, 0.9053, 0.9049,
        0.9044, 0.904, 0.9036, 0.9032, 0.9028, 0.9024, 0.902, 0.9016, 0.9012, 0.9008,
        0.9004, 0.9, 0.8996, 0.8992, 0.8988, 0.8983, 0.8979, 0.8975, 0.8971, 0.8967,
        0.8963, 0.8959, 0.8955, 0.8951, 0.8947, 0.8943, 0.8939, 0.8935, 0.8931, 0.8926,
        0.8922, 0.8918, 0.8914, 0.891, 0.8906, 0.8902, 0.8898, 0.8894, 0.889, 0.8886,
        0.8882, 0.8878, 0.8873, 0.8869, 0.8865, 0.8861, 0.8857, 0.8853, 0.8849, 0.8845,
        0.8841, 0.8837, 0.8833, 0.8829, 0.8825, 0.882, 0.8816, 0.8812, 0.8808, 0.8804,
        0.88, 0.8796, 0.8792, 0.8788, 0.8784, 0.878, 0.8775, 0.8771, 0.8767, 0.8763,
        0.8759, 0.8755, 0.8751, 0.8747, 0.8743, 0.8739, 0.8735, 0.873, 0.8726, 0.8722,
        0.8718, 0.8714, 0.871, 0.8706, 0.8702, 0.8698, 0.8694, 0.869, 0.8685, 0.8681,
        0.8677, 0.8673, 0.8669, 0.8665, 0.8661, 0.8657, 0.8653, 0.8649, 0.8644, 0.864,
        0.8636, 0.8632, 0.8628, 0.8624, 0.862, 0.8616, 0.8612, 0.8607, 0.8603, 0.8599,
        0.8595, 0.8591, 0.8587, 0.8583, 0.8579, 0.8575, 0.857, 0.8566, 0.8562, 0.8558,
        0.8554, 0.855, 0.8546, 0.8542, 0.8538, 0.8533, 0.8529, 0.8525, 0.8521, 0.8517,
        0.8513, 0.8509, 0.8505, 0.85, 0.8496, 0.8492, 0.8488, 0.8484, 0.848, 0.8476,
        0.8472, 0.8467, 0.8463, 0.8459, 0.8455, 0.8451, 0.8447, 0.8443, 0.8439, 0.8434,
        0.843, 0.8426, 0.8422, 0.8418, 0.8414, 0.841, 0.8406, 0.8401, 0.8397, 0.8393,
        0.8389, 0.8385, 0.8381, 0.8377, 0.8372, 0.8368, 0.8364, 0.836, 0.8356, 0.8352,
        0.8348, 0.8343, 0.8339, 0.8335, 0.8331, 0.8327, 0.8323, 0.8319, 0.8314, 0.831,
        0.8306, 0.8302, 0.8298, 0.8294, 0.8289, 0.8285, 0.8281, 0.8277, 0.8273, 0.8269,
        0.8265, 0.826, 0.8256, 0.8252, 0.8248, 0.8244, 0.824, 0.8235, 0.8231, 0.8227,
        0.8223, 0.8219, 0.8215, 0.821, 0.8206, 0.8202, 0.8198, 0.8194, 0.819, 0.8185,
        0.8181, 0.8177, 0.8173, 0.8169, 0.8165, 0.816, 0.8156, 0.8152, 0.8148, 0.8144,
        0.814, 0.8135, 0.8131, 0.8127, 0.8123, 0.8119, 0.8114, 0.811, 0.8106, 0.8102,
        0.8098, 0.8094, 0.8089, 0.8085, 0.8081, 0.8077, 0.8073, 0.8068, 0.8064, 0.806,
        0.8056, 0.8052, 0.8047, 0.8043, 0.8039, 0.8035, 0.8031, 0.8026, 0.8022, 0.8018,
        0.8014, 0.801, 0.8005, 0.8001, 0.7997, 0.7993, 0.7989, 0.7984, 0.798, 0.7976,
        0.7972, 0.7968, 0.7963, 0.7959, 0.7955, 0.7951, 0.7947, 0.7942, 0.7938, 0.7934,
        0.793, 0.7926, 0.7921, 0.7917, 0.7913, 0.7909, 0.7904, 0.79, 0.7896, 0.7892,
        0.7888, 0.7883, 0.7879, 0.7875, 0.7871, 0.7866, 0.7862, 0.7858, 0.7854, 0.7849,
        0.7845, 0.7841, 0.7837, 0.7833, 0.7828, 0.7824, 0.782, 0.7816, 0.7811, 0.7807,
        0.7803, 0.7799, 0.7794, 0.779, 0.7786, 0.7782, 0.7777, 0.7773, 0.7769, 0.7765,
        0.776, 0.7756, 0.7752, 0.7748, 0.7743, 0.7739, 0.7735, 0.7731, 0.7726, 0.7722,
        0.7718, 0.7714, 0.7709, 0.7705, 0.7701, 0.7697, 0.7692, 0.7688, 0.7684, 0.7679,
        0.7675, 0.7671, 0.7667, 0.7662, 0.7658, 0.7654, 0.765, 0.7645, 0.7641, 0.7637,
        0.7632, 0.7628, 0.7624, 0.762, 0.7615, 0.7611, 0.7607, 0.7602, 0.7598, 0.7594,
        0.759, 0.7585, 0.7581, 0.7577, 0.7572, 0.7568, 0.7564, 0.756, 0.7555, 0.7551,
        0.7547, 0.7542, 0.7538, 0.7534, 0.7529, 0.7525, 0.7521, 0.7516, 0.7512, 0.7508,
        0.7504, 0.7499, 0.7495, 0.7491, 0.7486, 0.7482, 0.7478, 0.7473, 0.7469, 0.7465,
        0.746, 0.7456, 0.7452, 0.7447, 0.7443, 0.7439, 0.7434, 0.743, 0.7426, 0.7421,
        0.7417, 0.7413, 0.7408, 0.7404, 0.74, 0.7395, 0.7391, 0.7387, 0.7382, 0.7378,
        0.7374, 0.7369, 0.7365, 0.7361, 0.7356, 0.7352, 0.7348, 0.7343, 0.7339, 0.7335,
        0.733, 0.7326, 0.7321, 0.7317, 0.7313, 0.7308, 0.7304, 0.73, 0.7295, 0.7291,
        0.7287, 0.7282, 0.7278, 0.7273, 0.7269, 0.7265, 0.726, 0.7256, 0.7252, 0.7247,
        0.7243, 0.7238, 0.7234, 0.723, 0.7225, 0.7221, 0.7216, 0.7212, 0.7208, 0.7203,
        0.7199, 0.7195, 0.719, 0.7186, 0.7181, 0.7177, 0.7173, 0.7168, 0.7164, 0.7159,
        0.7155, 0.7151, 0.7146, 0.7142, 0.7137, 0.7133, 0.7128, 0.7124, 0.712, 0.7115,
        0.7111, 0.7106, 0.7102, 0.7098, 0.7093, 0.7089, 0.7084, 0.708, 0.7075, 0.7071,
        0.7066, 0.7062, 0.7058, 0.7053, 0.7049, 0.7044, 0.704, 0.7035, 0.7031, 0.7027,
        0.7022, 0.7018, 0.7013, 0.7009, 0.7004, 0.7, 0.6995, 0.6991, 0.6986, 0.6982,
        0.6978, 0.6973, 0.6969, 0.6964, 0.696, 0.6955, 0.6951, 0.6946, 0.6942, 0.6937,
        0.6933, 0.6928, 0.6924, 0.6919, 0.6915, 0.691, 0.6906, 0.6901, 0.6897, 0.6892,
        0.6888, 0.6883, 0.6879, 0.6874, 0.687, 0.6865, 0.6861, 0.6856, 0.6852, 0.6847,
        0.6843, 0.6838, 0.6834, 0.6829, 0.6825, 0.682, 0.6816, 0.6811, 0.6807, 0.6802,
        0.6798, 0.6793, 0.6789, 0.6784, 0.678, 0.6775, 0.6771, 0.6766, 0.6762, 0.6757,
        0.6752, 0.6748, 0.6743, 0.6739, 0.6734, 0.673, 0.6725, 0.6721, 0.6716, 0.6711,
        0.6707, 0.6702, 0.6698, 0.6693, 0.6689, 0.6684, 0.668, 0.6675, 0.667, 0.6666,
        0.6661, 0.6657, 0.6652, 0.6648, 0.6643, 0.6638, 0.6634, 0.6629, 0.6625, 0.662,
        0.6615, 0.6611, 0.6606, 0.6602, 0.6597, 0.6592, 0.6588, 0.6583, 0.6579, 0.6574,
        0.6569, 0.6565, 0.656, 0.6556, 0.6551, 0.6546, 0.6542, 0.6537, 0.6532, 0.6528,
        0.6523, 0.6519, 0.6514, 0.6509, 0.6505, 0.65, 0.6495, 0.6491, 0.6486, 0.6481,
        0.6477, 0.6472, 0.6468, 0.6463, 0.6458, 0.6454, 0.6449, 0.6444, 0.644, 0.6435,
        0.643, 0.6426, 0.6421, 0.6416, 0.6412, 0.6407, 0.6402, 0.6397, 0.6393, 0.6388,
        0.6383, 0.6379, 0.6374, 0.6369, 0.6365, 0.636, 0.6355, 0.6351, 0.6346, 0.6341,
        0.6336, 0.6332, 0.6327, 0.6322, 0.6318, 0.6313, 0.6308, 0.6303, 0.6299, 0.6294,
        0.6289, 0.6285, 0.628, 0.6275, 0.627, 0.6266, 0.6261, 0.6256, 0.6251, 0.6247,
        0.6242, 0.6237, 0.6232, 0.6228, 0.6223, 0.6218, 0.6213, 0.6208, 0.6204, 0.6199,
        0.6194, 0.6189, 0.6185, 0.618, 0.6175, 0.617, 0.6165, 0.6161, 0.6156, 0.6151,
        0.6146, 0.6142, 0.6137, 0.6132, 0.6127, 0.6122, 0.6117, 0.6113, 0.6108, 0.6103,
        0.6098, 0.6093, 0.6089, 0.6084, 0.6079, 0.6074, 0.6069, 0.6064, 0.606, 0.6055,
        0.605, 0.6045, 0.604, 0.6035, 0.603, 0.6026, 0.6021, 0.6016, 0.6011, 0.6006,
        0.6001, 0.5996, 0.5992, 0.5987, 0.5982, 0.5977, 0.5972, 0.5967, 0.5962, 0.5957,
        0.5952, 0.5948, 0.5943, 0.5938, 0.5933, 0.5928, 0.5923, 0.5918, 0.5913, 0.5908,
        0.5903, 0.5898, 0.5894, 0.5889, 0.5884, 0.5879, 0.5874, 0.5869, 0.5864, 0.5859,
        0.5854, 0.5849, 0.5844, 0.5839, 0.5834, 0.5829, 0.5824, 0.5819, 0.5814, 0.5809,
        0.5804, 0.5799, 0.5794, 0.5789, 0.5784, 0.5779, 0.5774, 0.5769, 0.5764, 0.5759,
        0.5754, 0.5749, 0.5744, 0.5739, 0.5734, 0.5729, 0.5724, 0.5719, 0.5714, 0.5709,
        0.5704, 0.5699, 0.5694, 0.5689, 0.5684, 0.5679, 0.5674, 0.5669, 0.5664, 0.5659,
        0.5654, 0.5649, 0.5644, 0.5639, 0.5633, 0.5628, 0.5623, 0.5618, 0.5613, 0.5608,
        0.5603, 0.5598, 0.5593, 0.5588, 0.5582, 0.5577, 0.5572, 0.5567, 0.5562, 0.5557,
        0.5552, 0.5547, 0.5541, 0.5536, 0.5531, 0.5526, 0.5521, 0.5516, 0.5511, 0.5505,
        0.55, 0.5495, 0.549, 0.5485, 0.548, 0.5474, 0.5469, 0.5464, 0.5459, 0.5454,
        0.5448, 0.5443, 0.5438, 0.5433, 0.5428, 0.5422, 0.5417, 0.5412, 0.5407, 0.5402,
        0.5396, 0.5391, 0.5386, 0.5381, 0.5375, 0.537, 0.5365, 0.536, 0.5354, 0.5349,
        0.5344, 0.5339, 0.5333, 0.5328, 0.5323, 0.5317, 0.5312, 0.5307, 0.5302, 0.5296,
        0.5291, 0.5286, 0.528, 0.5275, 0.527, 0.5264, 0.5259, 0.5254, 0.5248, 0.5243,
        0.5238, 0.5232, 0.5227, 0.5222, 0.5216, 0.5211, 0.5206, 0.52, 0.5195, 0.5189,
        0.5184, 0.5179, 0.5173, 0.5168, 0.5162, 0.5157, 0.5152, 0.5146, 0.5141, 0.5135,
        0.513, 0.5124, 0.5119, 0.5114, 0.5108, 0.5103, 0.5097, 0.5092, 0.5086, 0.5081,
        0.5075, 0.507, 0.5064, 0.5059, 0.5053, 0.5048, 0.5043, 0.5037, 0.5032, 0.5026,
        0.502, 0.5015, 0.5009, 0.5004, 0.4998, 0.4993, 0.4987, 0.4982, 0.4976, 0.4971,
        0.4965, 0.496, 0.4954, 0.4948, 0.4943, 0.4937, 0.4932, 0.4926, 0.492, 0.4915,
        0.4909, 0.4904, 0.4898, 0.4892, 0.4887, 0.4881, 0.4875, 0.487, 0.4864, 0.4859,
        0.4853, 0.4847, 0.4842, 0.4836, 0.483, 0.4825, 0.4819, 0.4813, 0.4807, 0.4802,
        0.4796, 0.479, 0.4785, 0.4779, 0.4773, 0.4767, 0.4762, 0.4756, 0.475, 0.4744,
        0.4739, 0.4733, 0.4727, 0.4721, 0.4716, 0.471, 0.4704, 0.4698, 0.4692, 0.4687,
        0.4681, 0.4675, 0.4669, 0.4663, 0.4657, 0.4652, 0.4646, 0.464, 0.4634, 0.4628,
        0.4622, 0.4616, 0.461, 0.4605, 0.4599, 0.4593, 0.4587, 0.4581, 0.4575, 0.4569,
        0.4563, 0.4557, 0.4551, 0.4545, 0.4539, 0.4533, 0.4527, 0.4521, 0.4515, 0.451,
        0.4504, 0.4498, 0.4491, 0.4485, 0.4479, 0.4473, 0.4467, 0.4461, 0.4455, 0.4449,
        0.4443, 0.4437, 0.4431, 0.4425, 0.4419, 0.4413, 0.4407, 0.4401, 0.4394, 0.4388,
        0.4382, 0.4376, 0.437, 0.4364, 0.4358, 0.4351, 0.4345, 0.4339, 0.4333, 0.4327,
        0.4321, 0.4314, 0.4308, 0.4302, 0.4296, 0.4289, 0.4283, 0.4277, 0.4271, 0.4264,
        0.4258, 0.4252, 0.4246, 0.4239, 0.4233, 0.4227, 0.422, 0.4214, 0.4208, 0.4201,
        0.4195, 0.4189, 0.4182, 0.4176, 0.4169, 0.4163, 0.4157, 0.415, 0.4144, 0.4137,
        0.4131, 0.4125, 0.4118, 0.4112, 0.4105, 0.4099, 0.4092, 0.4086, 0.4079, 0.4073,
        0.4066, 0.406, 0.4053, 0.4047, 0.404, 0.4034, 0.4027, 0.402, 0.4014, 0.4007,
        0.4001, 0.3994, 0.3987, 0.3981, 0.3974, 0.3967, 0.3961, 0.3954, 0.3947, 0.3941,
        0.3934, 0.3927, 0.3921, 0.3914, 0.3907, 0.39, 0.3894, 0.3887, 0.388, 0.3873,
        0.3866, 0.386, 0.3853, 0.3846, 0.3839, 0.3832, 0.3825, 0.3819, 0.3812, 0.3805,
        0.3798, 0.3791, 0.3784, 0.3777, 0.377, 0.3763, 0.3756, 0.3749, 0.3742, 0.3735,
        0.3728, 0.3721, 0.3714, 0.3707, 0.37, 0.3693, 0.3686, 0.3679, 0.3672, 0.3665,
        0.3657, 0.365, 0.3643, 0.3636, 0.3629, 0.3622, 0.3614, 0.3607, 0.36, 0.3593,
        0.3585, 0.3578, 0.3571, 0.3564, 0.3556, 0.3549, 0.3542, 0.3534, 0.3527, 0.352,
        0.3512, 0.3505, 0.3497, 0.349, 0.3483, 0.3475, 0.3468, 0.346, 0.3453, 0.3445,
        0.3438, 0.343, 0.3422, 0.3415, 0.3407, 0.34, 0.3392, 0.3384, 0.3377, 0.3369,
        0.3361, 0.3354, 0.3346, 0.3338, 0.3331, 0.3323, 0.3315, 0.3307, 0.3299, 0.3292,
        0.3284, 0.3276, 0.3268, 0.326, 0.3252, 0.3244, 0.3236, 0.3228, 0.3221, 0.3213,
        0.3205, 0.3196, 0.3188, 0.318, 0.3172, 0.3164, 0.3156, 0.3148, 0.314, 0.3132,
        0.3123, 0.3115, 0.3107, 0.3099, 0.309, 0.3082, 0.3074, 0.3065, 0.3057, 0.3049,
        0.304, 0.3032, 0.3023, 0.3015, 0.3007, 0.2998, 0.2989, 0.2981, 0.2972, 0.2964,
        0.2955, 0.2946, 0.2938, 0.2929, 0.292, 0.2912, 0.2903, 0.2894, 0.2885, 0.2877,
        0.2868, 0.2859, 0.285, 0.2841, 0.2832, 0.2823, 0.2814, 0.2805, 0.2796, 0.2787,
        0.2778, 0.2768, 0.2759, 0.275, 0.2741, 0.2732, 0.2722, 0.2713, 0.2704, 0.2694,
        0.2685, 0.2675, 0.2666, 0.2656, 0.2647, 0.2637, 0.2628, 0.2618, 0.2608, 0.2599,
        0.2589, 0.2579, 0.2569, 0.256, 0.255, 0.254, 0.253, 0.252, 0.251, 0.25,
        0.249, 0.248, 0.2469, 0.2459, 0.2449, 0.2439, 0.2428, 0.2418, 0.2408, 0.2397,
        0.2387, 0.2376, 0.2365, 0.2355, 0.2344, 0.2333, 0.2323, 0.2312, 0.2301, 0.229,
        0.2279, 0.2268, 0.2257, 0.2246, 0.2235, 0.2223, 0.2212, 0.2201, 0.2189, 0.2178,
        0.2166, 0.2155, 0.2143, 0.2132, 0.212, 0.2108, 0.2096, 0.2084, 0.2072, 0.206,
        0.2048, 0.2036, 0.2023, 0.2011, 0.1999, 0.1986, 0.1974, 0.1961, 0.1948, 0.1935,
        0.1923, 0.191, 0.1896, 0.1883, 0.187, 0.1857, 0.1843, 0.183, 0.1816, 0.1802,
        0.1789, 0.1775, 0.1761, 0.1747, 0.1732, 0.1718, 0.1703, 0.1689, 0.1674, 0.1659,
        0.1644, 0.1629, 0.1614, 0.1599, 0.1583, 0.1567, 0.1551, 0.1535, 0.1519, 0.1503,
        0.1486, 0.147, 0.1453, 0.1436, 0.1418, 0.1401, 0.1383, 0.1365, 0.1347, 0.1329,
        0.131, 0.1291, 0.1272, 0.1252, 0.1233, 0.1213, 0.1192, 0.1171, 0.115, 0.1129,
        0.1107, 0.1084, 0.1061, 0.1038, 0.1014, 0.09894, 0.09643, 0.09385, 0.0912, 0.08847,
        0.08566, 0.08275, 0.07974, 0.0766, 0.07334, 0.06992, 0.06633, 0.06253, 0.05849, 0.05415,
        0.04943, 0.0442, 0.03828, 0.03125, 0.0221, -0};

        const static double cosvals[max] = {
        1, 1, 1, 1, 1, 1, 0.9999, 0.9999, 0.9999, 0.9999,
        0.9999, 0.9998, 0.9998, 0.9998, 0.9997, 0.9997, 0.9997, 0.9996, 0.9996, 0.9995,
        0.9995, 0.9994, 0.9994, 0.9993, 0.9993, 0.9992, 0.9991, 0.9991, 0.999, 0.9989,
        0.9989, 0.9988, 0.9987, 0.9986, 0.9986, 0.9985, 0.9984, 0.9983, 0.9982, 0.9981,
        0.998, 0.9979, 0.9978, 0.9977, 0.9976, 0.9975, 0.9974, 0.9973, 0.9972, 0.9971,
        0.9969, 0.9968, 0.9967, 0.9966, 0.9964, 0.9963, 0.9962, 0.996, 0.9959, 0.9958,
        0.9956, 0.9955, 0.9953, 0.9952, 0.995, 0.9949, 0.9947, 0.9946, 0.9944, 0.9942,
        0.9941, 0.9939, 0.9937, 0.9936, 0.9934, 0.9932, 0.993, 0.9929, 0.9927, 0.9925,
        0.9923, 0.9921, 0.9919, 0.9917, 0.9915, 0.9913, 0.9911, 0.9909, 0.9907, 0.9905,
        0.9903, 0.9901, 0.9898, 0.9896, 0.9894, 0.9892, 0.989, 0.9887, 0.9885, 0.9883,
        0.988, 0.9878, 0.9875, 0.9873, 0.9871, 0.9868, 0.9866, 0.9863, 0.9861, 0.9858,
        0.9855, 0.9853, 0.985, 0.9847, 0.9845, 0.9842, 0.9839, 0.9837, 0.9834, 0.9831,
        0.9828, 0.9825, 0.9823, 0.982, 0.9817, 0.9814, 0.9811, 0.9808, 0.9805, 0.9802,
        0.9799, 0.9796, 0.9793, 0.9789, 0.9786, 0.9783, 0.978, 0.9777, 0.9774, 0.977,
        0.9767, 0.9764, 0.976, 0.9757, 0.9754, 0.975, 0.9747, 0.9743, 0.974, 0.9736,
        0.9733, 0.9729, 0.9726, 0.9722, 0.9719, 0.9715, 0.9711, 0.9708, 0.9704, 0.97,
        0.9697, 0.9693, 0.9689, 0.9685, 0.9681, 0.9678, 0.9674, 0.967, 0.9666, 0.9662,
        0.9658, 0.9654, 0.965, 0.9646, 0.9642, 0.9638, 0.9634, 0.963, 0.9625, 0.9621,
        0.9617, 0.9613, 0.9609, 0.9604, 0.96, 0.9596, 0.9591, 0.9587, 0.9583, 0.9578,
        0.9574, 0.9569, 0.9565, 0.956, 0.9556, 0.9551, 0.9547, 0.9542, 0.9538, 0.9533,
        0.9528, 0.9524, 0.9519, 0.9514, 0.951, 0.9505, 0.95, 0.9495, 0.949, 0.9486,
        0.9481, 0.9476, 0.9471, 0.9466, 0.9461, 0.9456, 0.9451, 0.9446, 0.9441, 0.9436,
        0.9431, 0.9426, 0.9421, 0.9415, 0.941, 0.9405, 0.94, 0.9395, 0.9389, 0.9384,
        0.9379, 0.9373, 0.9368, 0.9363, 0.9357, 0.9352, 0.9346, 0.9341, 0.9335, 0.933,
        0.9324, 0.9319, 0.9313, 0.9308, 0.9302, 0.9296, 0.9291, 0.9285, 0.9279, 0.9274,
        0.9268, 0.9262, 0.9256, 0.925, 0.9245, 0.9239, 0.9233, 0.9227, 0.9221, 0.9215,
        0.9209, 0.9203, 0.9197, 0.9191, 0.9185, 0.9179, 0.9173, 0.9167, 0.9161, 0.9154,
        0.9148, 0.9142, 0.9136, 0.913, 0.9123, 0.9117, 0.9111, 0.9104, 0.9098, 0.9092,
        0.9085, 0.9079, 0.9072, 0.9066, 0.9059, 0.9053, 0.9046, 0.904, 0.9033, 0.9027,
        0.902, 0.9013, 0.9007, 0.9, 0.8993, 0.8987, 0.898, 0.8973, 0.8966, 0.896,
        0.8953, 0.8946, 0.8939, 0.8932, 0.8925, 0.8918, 0.8911, 0.8904, 0.8897, 0.889,
        0.8883, 0.8876, 0.8869, 0.8862, 0.8855, 0.8848, 0.8841, 0.8834, 0.8826, 0.8819,
        0.8812, 0.8805, 0.8797, 0.879, 0.8783, 0.8775, 0.8768, 0.8761, 0.8753, 0.8746,
        0.8738, 0.8731, 0.8723, 0.8716, 0.8708, 0.8701, 0.8693, 0.8686, 0.8678, 0.867,
        0.8663, 0.8655, 0.8647, 0.864, 0.8632, 0.8624, 0.8616, 0.8609, 0.8601, 0.8593,
        0.8585, 0.8577, 0.8569, 0.8561, 0.8554, 0.8546, 0.8538, 0.853, 0.8522, 0.8514,
        0.8505, 0.8497, 0.8489, 0.8481, 0.8473, 0.8465, 0.8457, 0.8449, 0.844, 0.8432,
        0.8424, 0.8416, 0.8407, 0.8399, 0.8391, 0.8382, 0.8374, 0.8365, 0.8357, 0.8349,
        0.834, 0.8332, 0.8323, 0.8315, 0.8306, 0.8298, 0.8289, 0.828, 0.8272, 0.8263,
        0.8255, 0.8246, 0.8237, 0.8228, 0.822, 0.8211, 0.8202, 0.8193, 0.8185, 0.8176,
        0.8167, 0.8158, 0.8149, 0.814, 0.8131, 0.8123, 0.8114, 0.8105, 0.8096, 0.8087,
        0.8078, 0.8068, 0.8059, 0.805, 0.8041, 0.8032, 0.8023, 0.8014, 0.8005, 0.7995,
        0.7986, 0.7977, 0.7968, 0.7958, 0.7949, 0.794, 0.793, 0.7921, 0.7912, 0.7902,
        0.7893, 0.7883, 0.7874, 0.7865, 0.7855, 0.7846, 0.7836, 0.7827, 0.7817, 0.7807,
        0.7798, 0.7788, 0.7779, 0.7769, 0.7759, 0.775, 0.774, 0.773, 0.772, 0.7711,
        0.7701, 0.7691, 0.7681, 0.7671, 0.7662, 0.7652, 0.7642, 0.7632, 0.7622, 0.7612,
        0.7602, 0.7592, 0.7582, 0.7572, 0.7562, 0.7552, 0.7542, 0.7532, 0.7522, 0.7512,
        0.7502, 0.7491, 0.7481, 0.7471, 0.7461, 0.7451, 0.744, 0.743, 0.742, 0.741,
        0.7399, 0.7389, 0.7379, 0.7368, 0.7358, 0.7347, 0.7337, 0.7327, 0.7316, 0.7306,
        0.7295, 0.7285, 0.7274, 0.7264, 0.7253, 0.7242, 0.7232, 0.7221, 0.7211, 0.72,
        0.7189, 0.7179, 0.7168, 0.7157, 0.7147, 0.7136, 0.7125, 0.7114, 0.7104, 0.7093,
        0.7082, 0.7071, 0.706, 0.7049, 0.7038, 0.7028, 0.7017, 0.7006, 0.6995, 0.6984,
        0.6973, 0.6962, 0.6951, 0.694, 0.6929, 0.6918, 0.6907, 0.6895, 0.6884, 0.6873,
        0.6862, 0.6851, 0.684, 0.6828, 0.6817, 0.6806, 0.6795, 0.6784, 0.6772, 0.6761,
        0.675, 0.6738, 0.6727, 0.6716, 0.6704, 0.6693, 0.6681, 0.667, 0.6659, 0.6647,
        0.6636, 0.6624, 0.6613, 0.6601, 0.659, 0.6578, 0.6567, 0.6555, 0.6543, 0.6532,
        0.652, 0.6508, 0.6497, 0.6485, 0.6473, 0.6462, 0.645, 0.6438, 0.6427, 0.6415,
        0.6403, 0.6391, 0.6379, 0.6368, 0.6356, 0.6344, 0.6332, 0.632, 0.6308, 0.6296,
        0.6284, 0.6273, 0.6261, 0.6249, 0.6237, 0.6225, 0.6213, 0.6201, 0.6189, 0.6176,
        0.6164, 0.6152, 0.614, 0.6128, 0.6116, 0.6104, 0.6092, 0.6079, 0.6067, 0.6055,
        0.6043, 0.6031, 0.6018, 0.6006, 0.5994, 0.5982, 0.5969, 0.5957, 0.5945, 0.5932,
        0.592, 0.5908, 0.5895, 0.5883, 0.587, 0.5858, 0.5846, 0.5833, 0.5821, 0.5808,
        0.5796, 0.5783, 0.5771, 0.5758, 0.5746, 0.5733, 0.572, 0.5708, 0.5695, 0.5683,
        0.567, 0.5657, 0.5645, 0.5632, 0.5619, 0.5607, 0.5594, 0.5581, 0.5568, 0.5556,
        0.5543, 0.553, 0.5517, 0.5505, 0.5492, 0.5479, 0.5466, 0.5453, 0.544, 0.5428,
        0.5415, 0.5402, 0.5389, 0.5376, 0.5363, 0.535, 0.5337, 0.5324, 0.5311, 0.5298,
        0.5285, 0.5272, 0.5259, 0.5246, 0.5233, 0.522, 0.5207, 0.5194, 0.518, 0.5167,
        0.5154, 0.5141, 0.5128, 0.5115, 0.5102, 0.5088, 0.5075, 0.5062, 0.5049, 0.5035,
        0.5022, 0.5009, 0.4996, 0.4982, 0.4969, 0.4956, 0.4942, 0.4929, 0.4916, 0.4902,
        0.4889, 0.4876, 0.4862, 0.4849, 0.4835, 0.4822, 0.4808, 0.4795, 0.4781, 0.4768,
        0.4755, 0.4741, 0.4727, 0.4714, 0.47, 0.4687, 0.4673, 0.466, 0.4646, 0.4633,
        0.4619, 0.4605, 0.4592, 0.4578, 0.4564, 0.4551, 0.4537, 0.4523, 0.451, 0.4496,
        0.4482, 0.4469, 0.4455, 0.4441, 0.4427, 0.4414, 0.44, 0.4386, 0.4372, 0.4359,
        0.4345, 0.4331, 0.4317, 0.4303, 0.4289, 0.4276, 0.4262, 0.4248, 0.4234, 0.422,
        0.4206, 0.4192, 0.4178, 0.4164, 0.415, 0.4136, 0.4122, 0.4108, 0.4094, 0.408,
        0.4066, 0.4052, 0.4038, 0.4024, 0.401, 0.3996, 0.3982, 0.3968, 0.3954, 0.394,
        0.3926, 0.3912, 0.3898, 0.3883, 0.3869, 0.3855, 0.3841, 0.3827, 0.3813, 0.3798,
        0.3784, 0.377, 0.3756, 0.3742, 0.3727, 0.3713, 0.3699, 0.3685, 0.367, 0.3656,
        0.3642, 0.3628, 0.3613, 0.3599, 0.3585, 0.357, 0.3556, 0.3542, 0.3527, 0.3513,
        0.3499, 0.3484, 0.347, 0.3455, 0.3441, 0.3427, 0.3412, 0.3398, 0.3383, 0.3369,
        0.3354, 0.334, 0.3326, 0.3311, 0.3297, 0.3282, 0.3268, 0.3253, 0.3239, 0.3224,
        0.321, 0.3195, 0.318, 0.3166, 0.3151, 0.3137, 0.3122, 0.3108, 0.3093, 0.3078,
        0.3064, 0.3049, 0.3035, 0.302, 0.3005, 0.2991, 0.2976, 0.2962, 0.2947, 0.2932,
        0.2918, 0.2903, 0.2888, 0.2873, 0.2859, 0.2844, 0.2829, 0.2815, 0.28, 0.2785,
        0.277, 0.2756, 0.2741, 0.2726, 0.2711, 0.2697, 0.2682, 0.2667, 0.2652, 0.2638,
        0.2623, 0.2608, 0.2593, 0.2578, 0.2563, 0.2549, 0.2534, 0.2519, 0.2504, 0.2489,
        0.2474, 0.246, 0.2445, 0.243, 0.2415, 0.24, 0.2385, 0.237, 0.2355, 0.234,
        0.2326, 0.2311, 0.2296, 0.2281, 0.2266, 0.2251, 0.2236, 0.2221, 0.2206, 0.2191,
        0.2176, 0.2161, 0.2146, 0.2131, 0.2116, 0.2101, 0.2086, 0.2071, 0.2056, 0.2041,
        0.2026, 0.2011, 0.1996, 0.1981, 0.1966, 0.1951, 0.1936, 0.1921, 0.1906, 0.1891,
        0.1876, 0.1861, 0.1845, 0.183, 0.1815, 0.18, 0.1785, 0.177, 0.1755, 0.174,
        0.1725, 0.171, 0.1695, 0.1679, 0.1664, 0.1649, 0.1634, 0.1619, 0.1604, 0.1589,
        0.1573, 0.1558, 0.1543, 0.1528, 0.1513, 0.1498, 0.1482, 0.1467, 0.1452, 0.1437,
        0.1422, 0.1407, 0.1391, 0.1376, 0.1361, 0.1346, 0.1331, 0.1315, 0.13, 0.1285,
        0.127, 0.1255, 0.1239, 0.1224, 0.1209, 0.1194, 0.1178, 0.1163, 0.1148, 0.1133,
        0.1117, 0.1102, 0.1087, 0.1072, 0.1056, 0.1041, 0.1026, 0.1011, 0.09954, 0.09802,
        0.09649, 0.09496, 0.09344, 0.09191, 0.09038, 0.08885, 0.08733, 0.0858, 0.08427, 0.08274,
        0.08121, 0.07968, 0.07815, 0.07662, 0.07509, 0.07356, 0.07203, 0.0705, 0.06897, 0.06744,
        0.06591, 0.06438, 0.06285, 0.06132, 0.05979, 0.05826, 0.05673, 0.0552, 0.05366, 0.05213,
        0.0506, 0.04907, 0.04754, 0.046, 0.04447, 0.04294, 0.04141, 0.03987, 0.03834, 0.03681,
        0.03527, 0.03374, 0.03221, 0.03067, 0.02914, 0.02761, 0.02607, 0.02454, 0.02301, 0.02147,
        0.01994, 0.01841, 0.01687, 0.01534, 0.01381, 0.01227, 0.01074, 0.009204, 0.00767, 0.006136,
        0.004602, 0.003068, 0.001534, 6.123e-17, -0.001534, -0.003068, -0.004602, -0.006136, -0.00767, -0.009204,
        -0.01074, -0.01227, -0.01381, -0.01534, -0.01687, -0.01841, -0.01994, -0.02147, -0.02301, -0.02454,
        -0.02607, -0.02761, -0.02914, -0.03067, -0.03221, -0.03374, -0.03527, -0.03681, -0.03834, -0.03987,
        -0.04141, -0.04294, -0.04447, -0.046, -0.04754, -0.04907, -0.0506, -0.05213, -0.05366, -0.0552,
        -0.05673, -0.05826, -0.05979, -0.06132, -0.06285, -0.06438, -0.06591, -0.06744, -0.06897, -0.0705,
        -0.07203, -0.07356, -0.07509, -0.07662, -0.07815, -0.07968, -0.08121, -0.08274, -0.08427, -0.0858,
        -0.08733, -0.08885, -0.09038, -0.09191, -0.09344, -0.09496, -0.09649, -0.09802, -0.09954, -0.1011,
        -0.1026, -0.1041, -0.1056, -0.1072, -0.1087, -0.1102, -0.1117, -0.1133, -0.1148, -0.1163,
        -0.1178, -0.1194, -0.1209, -0.1224, -0.1239, -0.1255, -0.127, -0.1285, -0.13, -0.1315,
        -0.1331, -0.1346, -0.1361, -0.1376, -0.1391, -0.1407, -0.1422, -0.1437, -0.1452, -0.1467,
        -0.1482, -0.1498, -0.1513, -0.1528, -0.1543, -0.1558, -0.1573, -0.1589, -0.1604, -0.1619,
        -0.1634, -0.1649, -0.1664, -0.1679, -0.1695, -0.171, -0.1725, -0.174, -0.1755, -0.177,
        -0.1785, -0.18, -0.1815, -0.183, -0.1845, -0.1861, -0.1876, -0.1891, -0.1906, -0.1921,
        -0.1936, -0.1951, -0.1966, -0.1981, -0.1996, -0.2011, -0.2026, -0.2041, -0.2056, -0.2071,
        -0.2086, -0.2101, -0.2116, -0.2131, -0.2146, -0.2161, -0.2176, -0.2191, -0.2206, -0.2221,
        -0.2236, -0.2251, -0.2266, -0.2281, -0.2296, -0.2311, -0.2326, -0.234, -0.2355, -0.237,
        -0.2385, -0.24, -0.2415, -0.243, -0.2445, -0.246, -0.2474, -0.2489, -0.2504, -0.2519,
        -0.2534, -0.2549, -0.2563, -0.2578, -0.2593, -0.2608, -0.2623, -0.2638, -0.2652, -0.2667,
        -0.2682, -0.2697, -0.2711, -0.2726, -0.2741, -0.2756, -0.277, -0.2785, -0.28, -0.2815,
        -0.2829, -0.2844, -0.2859, -0.2873, -0.2888, -0.2903, -0.2918, -0.2932, -0.2947, -0.2962,
        -0.2976, -0.2991, -0.3005, -0.302, -0.3035, -0.3049, -0.3064, -0.3078, -0.3093, -0.3108,
        -0.3122, -0.3137, -0.3151, -0.3166, -0.318, -0.3195, -0.321, -0.3224, -0.3239, -0.3253,
        -0.3268, -0.3282, -0.3297, -0.3311, -0.3326, -0.334, -0.3354, -0.3369, -0.3383, -0.3398,
        -0.3412, -0.3427, -0.3441, -0.3455, -0.347, -0.3484, -0.3499, -0.3513, -0.3527, -0.3542,
        -0.3556, -0.357, -0.3585, -0.3599, -0.3613, -0.3628, -0.3642, -0.3656, -0.367, -0.3685,
        -0.3699, -0.3713, -0.3727, -0.3742, -0.3756, -0.377, -0.3784, -0.3798, -0.3813, -0.3827,
        -0.3841, -0.3855, -0.3869, -0.3883, -0.3898, -0.3912, -0.3926, -0.394, -0.3954, -0.3968,
        -0.3982, -0.3996, -0.401, -0.4024, -0.4038, -0.4052, -0.4066, -0.408, -0.4094, -0.4108,
        -0.4122, -0.4136, -0.415, -0.4164, -0.4178, -0.4192, -0.4206, -0.422, -0.4234, -0.4248,
        -0.4262, -0.4276, -0.4289, -0.4303, -0.4317, -0.4331, -0.4345, -0.4359, -0.4372, -0.4386,
        -0.44, -0.4414, -0.4427, -0.4441, -0.4455, -0.4469, -0.4482, -0.4496, -0.451, -0.4523,
        -0.4537, -0.4551, -0.4564, -0.4578, -0.4592, -0.4605, -0.4619, -0.4633, -0.4646, -0.466,
        -0.4673, -0.4687, -0.47, -0.4714, -0.4727, -0.4741, -0.4755, -0.4768, -0.4781, -0.4795,
        -0.4808, -0.4822, -0.4835, -0.4849, -0.4862, -0.4876, -0.4889, -0.4902, -0.4916, -0.4929,
        -0.4942, -0.4956, -0.4969, -0.4982, -0.4996, -0.5009, -0.5022, -0.5035, -0.5049, -0.5062,
        -0.5075, -0.5088, -0.5102, -0.5115, -0.5128, -0.5141, -0.5154, -0.5167, -0.518, -0.5194,
        -0.5207, -0.522, -0.5233, -0.5246, -0.5259, -0.5272, -0.5285, -0.5298, -0.5311, -0.5324,
        -0.5337, -0.535, -0.5363, -0.5376, -0.5389, -0.5402, -0.5415, -0.5428, -0.544, -0.5453,
        -0.5466, -0.5479, -0.5492, -0.5505, -0.5517, -0.553, -0.5543, -0.5556, -0.5568, -0.5581,
        -0.5594, -0.5607, -0.5619, -0.5632, -0.5645, -0.5657, -0.567, -0.5683, -0.5695, -0.5708,
        -0.572, -0.5733, -0.5746, -0.5758, -0.5771, -0.5783, -0.5796, -0.5808, -0.5821, -0.5833,
        -0.5846, -0.5858, -0.587, -0.5883, -0.5895, -0.5908, -0.592, -0.5932, -0.5945, -0.5957,
        -0.5969, -0.5982, -0.5994, -0.6006, -0.6018, -0.6031, -0.6043, -0.6055, -0.6067, -0.6079,
        -0.6092, -0.6104, -0.6116, -0.6128, -0.614, -0.6152, -0.6164, -0.6176, -0.6189, -0.6201,
        -0.6213, -0.6225, -0.6237, -0.6249, -0.6261, -0.6273, -0.6284, -0.6296, -0.6308, -0.632,
        -0.6332, -0.6344, -0.6356, -0.6368, -0.6379, -0.6391, -0.6403, -0.6415, -0.6427, -0.6438,
        -0.645, -0.6462, -0.6473, -0.6485, -0.6497, -0.6508, -0.652, -0.6532, -0.6543, -0.6555,
        -0.6567, -0.6578, -0.659, -0.6601, -0.6613, -0.6624, -0.6636, -0.6647, -0.6659, -0.667,
        -0.6681, -0.6693, -0.6704, -0.6716, -0.6727, -0.6738, -0.675, -0.6761, -0.6772, -0.6784,
        -0.6795, -0.6806, -0.6817, -0.6828, -0.684, -0.6851, -0.6862, -0.6873, -0.6884, -0.6895,
        -0.6907, -0.6918, -0.6929, -0.694, -0.6951, -0.6962, -0.6973, -0.6984, -0.6995, -0.7006,
        -0.7017, -0.7028, -0.7038, -0.7049, -0.706, -0.7071, -0.7082, -0.7093, -0.7104, -0.7114,
        -0.7125, -0.7136, -0.7147, -0.7157, -0.7168, -0.7179, -0.7189, -0.72, -0.7211, -0.7221,
        -0.7232, -0.7242, -0.7253, -0.7264, -0.7274, -0.7285, -0.7295, -0.7306, -0.7316, -0.7327,
        -0.7337, -0.7347, -0.7358, -0.7368, -0.7379, -0.7389, -0.7399, -0.741, -0.742, -0.743,
        -0.744, -0.7451, -0.7461, -0.7471, -0.7481, -0.7491, -0.7502, -0.7512, -0.7522, -0.7532,
        -0.7542, -0.7552, -0.7562, -0.7572, -0.7582, -0.7592, -0.7602, -0.7612, -0.7622, -0.7632,
        -0.7642, -0.7652, -0.7662, -0.7671, -0.7681, -0.7691, -0.7701, -0.7711, -0.772, -0.773,
        -0.774, -0.775, -0.7759, -0.7769, -0.7779, -0.7788, -0.7798, -0.7807, -0.7817, -0.7827,
        -0.7836, -0.7846, -0.7855, -0.7865, -0.7874, -0.7883, -0.7893, -0.7902, -0.7912, -0.7921,
        -0.793, -0.794, -0.7949, -0.7958, -0.7968, -0.7977, -0.7986, -0.7995, -0.8005, -0.8014,
        -0.8023, -0.8032, -0.8041, -0.805, -0.8059, -0.8068, -0.8078, -0.8087, -0.8096, -0.8105,
        -0.8114, -0.8123, -0.8131, -0.814, -0.8149, -0.8158, -0.8167, -0.8176, -0.8185, -0.8193,
        -0.8202, -0.8211, -0.822, -0.8228, -0.8237, -0.8246, -0.8255, -0.8263, -0.8272, -0.828,
        -0.8289, -0.8298, -0.8306, -0.8315, -0.8323, -0.8332, -0.834, -0.8349, -0.8357, -0.8365,
        -0.8374, -0.8382, -0.8391, -0.8399, -0.8407, -0.8416, -0.8424, -0.8432, -0.844, -0.8449,
        -0.8457, -0.8465, -0.8473, -0.8481, -0.8489, -0.8497, -0.8505, -0.8514, -0.8522, -0.853,
        -0.8538, -0.8546, -0.8554, -0.8561, -0.8569, -0.8577, -0.8585, -0.8593, -0.8601, -0.8609,
        -0.8616, -0.8624, -0.8632, -0.864, -0.8647, -0.8655, -0.8663, -0.867, -0.8678, -0.8686,
        -0.8693, -0.8701, -0.8708, -0.8716, -0.8723, -0.8731, -0.8738, -0.8746, -0.8753, -0.8761,
        -0.8768, -0.8775, -0.8783, -0.879, -0.8797, -0.8805, -0.8812, -0.8819, -0.8826, -0.8834,
        -0.8841, -0.8848, -0.8855, -0.8862, -0.8869, -0.8876, -0.8883, -0.889, -0.8897, -0.8904,
        -0.8911, -0.8918, -0.8925, -0.8932, -0.8939, -0.8946, -0.8953, -0.896, -0.8966, -0.8973,
        -0.898, -0.8987, -0.8993, -0.9, -0.9007, -0.9013, -0.902, -0.9027, -0.9033, -0.904,
        -0.9046, -0.9053, -0.9059, -0.9066, -0.9072, -0.9079, -0.9085, -0.9092, -0.9098, -0.9104,
        -0.9111, -0.9117, -0.9123, -0.913, -0.9136, -0.9142, -0.9148, -0.9154, -0.9161, -0.9167,
        -0.9173, -0.9179, -0.9185, -0.9191, -0.9197, -0.9203, -0.9209, -0.9215, -0.9221, -0.9227,
        -0.9233, -0.9239, -0.9245, -0.925, -0.9256, -0.9262, -0.9268, -0.9274, -0.9279, -0.9285,
        -0.9291, -0.9296, -0.9302, -0.9308, -0.9313, -0.9319, -0.9324, -0.933, -0.9335, -0.9341,
        -0.9346, -0.9352, -0.9357, -0.9363, -0.9368, -0.9373, -0.9379, -0.9384, -0.9389, -0.9395,
        -0.94, -0.9405, -0.941, -0.9415, -0.9421, -0.9426, -0.9431, -0.9436, -0.9441, -0.9446,
        -0.9451, -0.9456, -0.9461, -0.9466, -0.9471, -0.9476, -0.9481, -0.9486, -0.949, -0.9495,
        -0.95, -0.9505, -0.951, -0.9514, -0.9519, -0.9524, -0.9528, -0.9533, -0.9538, -0.9542,
        -0.9547, -0.9551, -0.9556, -0.956, -0.9565, -0.9569, -0.9574, -0.9578, -0.9583, -0.9587,
        -0.9591, -0.9596, -0.96, -0.9604, -0.9609, -0.9613, -0.9617, -0.9621, -0.9625, -0.963,
        -0.9634, -0.9638, -0.9642, -0.9646, -0.965, -0.9654, -0.9658, -0.9662, -0.9666, -0.967,
        -0.9674, -0.9678, -0.9681, -0.9685, -0.9689, -0.9693, -0.9697, -0.97, -0.9704, -0.9708,
        -0.9711, -0.9715, -0.9719, -0.9722, -0.9726, -0.9729, -0.9733, -0.9736, -0.974, -0.9743,
        -0.9747, -0.975, -0.9754, -0.9757, -0.976, -0.9764, -0.9767, -0.977, -0.9774, -0.9777,
        -0.978, -0.9783, -0.9786, -0.9789, -0.9793, -0.9796, -0.9799, -0.9802, -0.9805, -0.9808,
        -0.9811, -0.9814, -0.9817, -0.982, -0.9823, -0.9825, -0.9828, -0.9831, -0.9834, -0.9837,
        -0.9839, -0.9842, -0.9845, -0.9847, -0.985, -0.9853, -0.9855, -0.9858, -0.9861, -0.9863,
        -0.9866, -0.9868, -0.9871, -0.9873, -0.9875, -0.9878, -0.988, -0.9883, -0.9885, -0.9887,
        -0.989, -0.9892, -0.9894, -0.9896, -0.9898, -0.9901, -0.9903, -0.9905, -0.9907, -0.9909,
        -0.9911, -0.9913, -0.9915, -0.9917, -0.9919, -0.9921, -0.9923, -0.9925, -0.9927, -0.9929,
        -0.993, -0.9932, -0.9934, -0.9936, -0.9937, -0.9939, -0.9941, -0.9942, -0.9944, -0.9946,
        -0.9947, -0.9949, -0.995, -0.9952, -0.9953, -0.9955, -0.9956, -0.9958, -0.9959, -0.996,
        -0.9962, -0.9963, -0.9964, -0.9966, -0.9967, -0.9968, -0.9969, -0.9971, -0.9972, -0.9973,
        -0.9974, -0.9975, -0.9976, -0.9977, -0.9978, -0.9979, -0.998, -0.9981, -0.9982, -0.9983,
        -0.9984, -0.9985, -0.9986, -0.9986, -0.9987, -0.9988, -0.9989, -0.9989, -0.999, -0.9991,
        -0.9991, -0.9992, -0.9993, -0.9993, -0.9994, -0.9994, -0.9995, -0.9995, -0.9996, -0.9996,
        -0.9997, -0.9997, -0.9997, -0.9998, -0.9998, -0.9998, -0.9999, -0.9999, -0.9999, -0.9999,
        -0.9999, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -0.9999, -0.9999, -0.9999, -0.9999, -0.9999, -0.9998,
        -0.9998, -0.9998, -0.9997, -0.9997, -0.9997, -0.9996, -0.9996, -0.9995, -0.9995, -0.9994,
        -0.9994, -0.9993, -0.9993, -0.9992, -0.9991, -0.9991, -0.999, -0.9989, -0.9989, -0.9988,
        -0.9987, -0.9986, -0.9986, -0.9985, -0.9984, -0.9983, -0.9982, -0.9981, -0.998, -0.9979,
        -0.9978, -0.9977, -0.9976, -0.9975, -0.9974, -0.9973, -0.9972, -0.9971, -0.9969, -0.9968,
        -0.9967, -0.9966, -0.9964, -0.9963, -0.9962, -0.996, -0.9959, -0.9958, -0.9956, -0.9955,
        -0.9953, -0.9952, -0.995, -0.9949, -0.9947, -0.9946, -0.9944, -0.9942, -0.9941, -0.9939,
        -0.9937, -0.9936, -0.9934, -0.9932, -0.993, -0.9929, -0.9927, -0.9925, -0.9923, -0.9921,
        -0.9919, -0.9917, -0.9915, -0.9913, -0.9911, -0.9909, -0.9907, -0.9905, -0.9903, -0.9901,
        -0.9898, -0.9896, -0.9894, -0.9892, -0.989, -0.9887, -0.9885, -0.9883, -0.988, -0.9878,
        -0.9875, -0.9873, -0.9871, -0.9868, -0.9866, -0.9863, -0.9861, -0.9858, -0.9855, -0.9853,
        -0.985, -0.9847, -0.9845, -0.9842, -0.9839, -0.9837, -0.9834, -0.9831, -0.9828, -0.9825,
        -0.9823, -0.982, -0.9817, -0.9814, -0.9811, -0.9808, -0.9805, -0.9802, -0.9799, -0.9796,
        -0.9793, -0.9789, -0.9786, -0.9783, -0.978, -0.9777, -0.9774, -0.977, -0.9767, -0.9764,
        -0.976, -0.9757, -0.9754, -0.975, -0.9747, -0.9743, -0.974, -0.9736, -0.9733, -0.9729,
        -0.9726, -0.9722, -0.9719, -0.9715, -0.9711, -0.9708, -0.9704, -0.97, -0.9697, -0.9693,
        -0.9689, -0.9685, -0.9681, -0.9678, -0.9674, -0.967, -0.9666, -0.9662, -0.9658, -0.9654,
        -0.965, -0.9646, -0.9642, -0.9638, -0.9634, -0.963, -0.9625, -0.9621, -0.9617, -0.9613,
        -0.9609, -0.9604, -0.96, -0.9596, -0.9591, -0.9587, -0.9583, -0.9578, -0.9574, -0.9569,
        -0.9565, -0.956, -0.9556, -0.9551, -0.9547, -0.9542, -0.9538, -0.9533, -0.9528, -0.9524,
        -0.9519, -0.9514, -0.951, -0.9505, -0.95, -0.9495, -0.949, -0.9486, -0.9481, -0.9476,
        -0.9471, -0.9466, -0.9461, -0.9456, -0.9451, -0.9446, -0.9441, -0.9436, -0.9431, -0.9426,
        -0.9421, -0.9415, -0.941, -0.9405, -0.94, -0.9395, -0.9389, -0.9384, -0.9379, -0.9373,
        -0.9368, -0.9363, -0.9357, -0.9352, -0.9346, -0.9341, -0.9335, -0.933, -0.9324, -0.9319,
        -0.9313, -0.9308, -0.9302, -0.9296, -0.9291, -0.9285, -0.9279, -0.9274, -0.9268, -0.9262,
        -0.9256, -0.925, -0.9245, -0.9239, -0.9233, -0.9227, -0.9221, -0.9215, -0.9209, -0.9203,
        -0.9197, -0.9191, -0.9185, -0.9179, -0.9173, -0.9167, -0.9161, -0.9154, -0.9148, -0.9142,
        -0.9136, -0.913, -0.9123, -0.9117, -0.9111, -0.9104, -0.9098, -0.9092, -0.9085, -0.9079,
        -0.9072, -0.9066, -0.9059, -0.9053, -0.9046, -0.904, -0.9033, -0.9027, -0.902, -0.9013,
        -0.9007, -0.9, -0.8993, -0.8987, -0.898, -0.8973, -0.8966, -0.896, -0.8953, -0.8946,
        -0.8939, -0.8932, -0.8925, -0.8918, -0.8911, -0.8904, -0.8897, -0.889, -0.8883, -0.8876,
        -0.8869, -0.8862, -0.8855, -0.8848, -0.8841, -0.8834, -0.8826, -0.8819, -0.8812, -0.8805,
        -0.8797, -0.879, -0.8783, -0.8775, -0.8768, -0.8761, -0.8753, -0.8746, -0.8738, -0.8731,
        -0.8723, -0.8716, -0.8708, -0.8701, -0.8693, -0.8686, -0.8678, -0.867, -0.8663, -0.8655,
        -0.8647, -0.864, -0.8632, -0.8624, -0.8616, -0.8609, -0.8601, -0.8593, -0.8585, -0.8577,
        -0.8569, -0.8561, -0.8554, -0.8546, -0.8538, -0.853, -0.8522, -0.8514, -0.8505, -0.8497,
        -0.8489, -0.8481, -0.8473, -0.8465, -0.8457, -0.8449, -0.844, -0.8432, -0.8424, -0.8416,
        -0.8407, -0.8399, -0.8391, -0.8382, -0.8374, -0.8365, -0.8357, -0.8349, -0.834, -0.8332,
        -0.8323, -0.8315, -0.8306, -0.8298, -0.8289, -0.828, -0.8272, -0.8263, -0.8255, -0.8246,
        -0.8237, -0.8228, -0.822, -0.8211, -0.8202, -0.8193, -0.8185, -0.8176, -0.8167, -0.8158,
        -0.8149, -0.814, -0.8131, -0.8123, -0.8114, -0.8105, -0.8096, -0.8087, -0.8078, -0.8068,
        -0.8059, -0.805, -0.8041, -0.8032, -0.8023, -0.8014, -0.8005, -0.7995, -0.7986, -0.7977,
        -0.7968, -0.7958, -0.7949, -0.794, -0.793, -0.7921, -0.7912, -0.7902, -0.7893, -0.7883,
        -0.7874, -0.7865, -0.7855, -0.7846, -0.7836, -0.7827, -0.7817, -0.7807, -0.7798, -0.7788,
        -0.7779, -0.7769, -0.7759, -0.775, -0.774, -0.773, -0.772, -0.7711, -0.7701, -0.7691,
        -0.7681, -0.7671, -0.7662, -0.7652, -0.7642, -0.7632, -0.7622, -0.7612, -0.7602, -0.7592,
        -0.7582, -0.7572, -0.7562, -0.7552, -0.7542, -0.7532, -0.7522, -0.7512, -0.7502, -0.7491,
        -0.7481, -0.7471, -0.7461, -0.7451, -0.744, -0.743, -0.742, -0.741, -0.7399, -0.7389,
        -0.7379, -0.7368, -0.7358, -0.7347, -0.7337, -0.7327, -0.7316, -0.7306, -0.7295, -0.7285,
        -0.7274, -0.7264, -0.7253, -0.7242, -0.7232, -0.7221, -0.7211, -0.72, -0.7189, -0.7179,
        -0.7168, -0.7157, -0.7147, -0.7136, -0.7125, -0.7114, -0.7104, -0.7093, -0.7082, -0.7071,
        -0.706, -0.7049, -0.7038, -0.7028, -0.7017, -0.7006, -0.6995, -0.6984, -0.6973, -0.6962,
        -0.6951, -0.694, -0.6929, -0.6918, -0.6907, -0.6895, -0.6884, -0.6873, -0.6862, -0.6851,
        -0.684, -0.6828, -0.6817, -0.6806, -0.6795, -0.6784, -0.6772, -0.6761, -0.675, -0.6738,
        -0.6727, -0.6716, -0.6704, -0.6693, -0.6681, -0.667, -0.6659, -0.6647, -0.6636, -0.6624,
        -0.6613, -0.6601, -0.659, -0.6578, -0.6567, -0.6555, -0.6543, -0.6532, -0.652, -0.6508,
        -0.6497, -0.6485, -0.6473, -0.6462, -0.645, -0.6438, -0.6427, -0.6415, -0.6403, -0.6391,
        -0.6379, -0.6368, -0.6356, -0.6344, -0.6332, -0.632, -0.6308, -0.6296, -0.6284, -0.6273,
        -0.6261, -0.6249, -0.6237, -0.6225, -0.6213, -0.6201, -0.6189, -0.6176, -0.6164, -0.6152,
        -0.614, -0.6128, -0.6116, -0.6104, -0.6092, -0.6079, -0.6067, -0.6055, -0.6043, -0.6031,
        -0.6018, -0.6006, -0.5994, -0.5982, -0.5969, -0.5957, -0.5945, -0.5932, -0.592, -0.5908,
        -0.5895, -0.5883, -0.587, -0.5858, -0.5846, -0.5833, -0.5821, -0.5808, -0.5796, -0.5783,
        -0.5771, -0.5758, -0.5746, -0.5733, -0.572, -0.5708, -0.5695, -0.5683, -0.567, -0.5657,
        -0.5645, -0.5632, -0.5619, -0.5607, -0.5594, -0.5581, -0.5568, -0.5556, -0.5543, -0.553,
        -0.5517, -0.5505, -0.5492, -0.5479, -0.5466, -0.5453, -0.544, -0.5428, -0.5415, -0.5402,
        -0.5389, -0.5376, -0.5363, -0.535, -0.5337, -0.5324, -0.5311, -0.5298, -0.5285, -0.5272,
        -0.5259, -0.5246, -0.5233, -0.522, -0.5207, -0.5194, -0.518, -0.5167, -0.5154, -0.5141,
        -0.5128, -0.5115, -0.5102, -0.5088, -0.5075, -0.5062, -0.5049, -0.5035, -0.5022, -0.5009,
        -0.4996, -0.4982, -0.4969, -0.4956, -0.4942, -0.4929, -0.4916, -0.4902, -0.4889, -0.4876,
        -0.4862, -0.4849, -0.4835, -0.4822, -0.4808, -0.4795, -0.4781, -0.4768, -0.4755, -0.4741,
        -0.4727, -0.4714, -0.47, -0.4687, -0.4673, -0.466, -0.4646, -0.4633, -0.4619, -0.4605,
        -0.4592, -0.4578, -0.4564, -0.4551, -0.4537, -0.4523, -0.451, -0.4496, -0.4482, -0.4469,
        -0.4455, -0.4441, -0.4427, -0.4414, -0.44, -0.4386, -0.4372, -0.4359, -0.4345, -0.4331,
        -0.4317, -0.4303, -0.4289, -0.4276, -0.4262, -0.4248, -0.4234, -0.422, -0.4206, -0.4192,
        -0.4178, -0.4164, -0.415, -0.4136, -0.4122, -0.4108, -0.4094, -0.408, -0.4066, -0.4052,
        -0.4038, -0.4024, -0.401, -0.3996, -0.3982, -0.3968, -0.3954, -0.394, -0.3926, -0.3912,
        -0.3898, -0.3883, -0.3869, -0.3855, -0.3841, -0.3827, -0.3813, -0.3798, -0.3784, -0.377,
        -0.3756, -0.3742, -0.3727, -0.3713, -0.3699, -0.3685, -0.367, -0.3656, -0.3642, -0.3628,
        -0.3613, -0.3599, -0.3585, -0.357, -0.3556, -0.3542, -0.3527, -0.3513, -0.3499, -0.3484,
        -0.347, -0.3455, -0.3441, -0.3427, -0.3412, -0.3398, -0.3383, -0.3369, -0.3354, -0.334,
        -0.3326, -0.3311, -0.3297, -0.3282, -0.3268, -0.3253, -0.3239, -0.3224, -0.321, -0.3195,
        -0.318, -0.3166, -0.3151, -0.3137, -0.3122, -0.3108, -0.3093, -0.3078, -0.3064, -0.3049,
        -0.3035, -0.302, -0.3005, -0.2991, -0.2976, -0.2962, -0.2947, -0.2932, -0.2918, -0.2903,
        -0.2888, -0.2873, -0.2859, -0.2844, -0.2829, -0.2815, -0.28, -0.2785, -0.277, -0.2756,
        -0.2741, -0.2726, -0.2711, -0.2697, -0.2682, -0.2667, -0.2652, -0.2638, -0.2623, -0.2608,
        -0.2593, -0.2578, -0.2563, -0.2549, -0.2534, -0.2519, -0.2504, -0.2489, -0.2474, -0.246,
        -0.2445, -0.243, -0.2415, -0.24, -0.2385, -0.237, -0.2355, -0.234, -0.2326, -0.2311,
        -0.2296, -0.2281, -0.2266, -0.2251, -0.2236, -0.2221, -0.2206, -0.2191, -0.2176, -0.2161,
        -0.2146, -0.2131, -0.2116, -0.2101, -0.2086, -0.2071, -0.2056, -0.2041, -0.2026, -0.2011,
        -0.1996, -0.1981, -0.1966, -0.1951, -0.1936, -0.1921, -0.1906, -0.1891, -0.1876, -0.1861,
        -0.1845, -0.183, -0.1815, -0.18, -0.1785, -0.177, -0.1755, -0.174, -0.1725, -0.171,
        -0.1695, -0.1679, -0.1664, -0.1649, -0.1634, -0.1619, -0.1604, -0.1589, -0.1573, -0.1558,
        -0.1543, -0.1528, -0.1513, -0.1498, -0.1482, -0.1467, -0.1452, -0.1437, -0.1422, -0.1407,
        -0.1391, -0.1376, -0.1361, -0.1346, -0.1331, -0.1315, -0.13, -0.1285, -0.127, -0.1255,
        -0.1239, -0.1224, -0.1209, -0.1194, -0.1178, -0.1163, -0.1148, -0.1133, -0.1117, -0.1102,
        -0.1087, -0.1072, -0.1056, -0.1041, -0.1026, -0.1011, -0.09954, -0.09802, -0.09649, -0.09496,
        -0.09344, -0.09191, -0.09038, -0.08885, -0.08733, -0.0858, -0.08427, -0.08274, -0.08121, -0.07968,
        -0.07815, -0.07662, -0.07509, -0.07356, -0.07203, -0.0705, -0.06897, -0.06744, -0.06591, -0.06438,
        -0.06285, -0.06132, -0.05979, -0.05826, -0.05673, -0.0552, -0.05366, -0.05213, -0.0506, -0.04907,
        -0.04754, -0.046, -0.04447, -0.04294, -0.04141, -0.03987, -0.03834, -0.03681, -0.03527, -0.03374,
        -0.03221, -0.03067, -0.02914, -0.02761, -0.02607, -0.02454, -0.02301, -0.02147, -0.01994, -0.01841,
        -0.01687, -0.01534, -0.01381, -0.01227, -0.01074, -0.009204, -0.00767, -0.006136, -0.004602, -0.003068,
        -0.001534, -1.837e-16, 0.001534, 0.003068, 0.004602, 0.006136, 0.00767, 0.009204, 0.01074, 0.01227,
        0.01381, 0.01534, 0.01687, 0.01841, 0.01994, 0.02147, 0.02301, 0.02454, 0.02607, 0.02761,
        0.02914, 0.03067, 0.03221, 0.03374, 0.03527, 0.03681, 0.03834, 0.03987, 0.04141, 0.04294,
        0.04447, 0.046, 0.04754, 0.04907, 0.0506, 0.05213, 0.05366, 0.0552, 0.05673, 0.05826,
        0.05979, 0.06132, 0.06285, 0.06438, 0.06591, 0.06744, 0.06897, 0.0705, 0.07203, 0.07356,
        0.07509, 0.07662, 0.07815, 0.07968, 0.08121, 0.08274, 0.08427, 0.0858, 0.08733, 0.08885,
        0.09038, 0.09191, 0.09344, 0.09496, 0.09649, 0.09802, 0.09954, 0.1011, 0.1026, 0.1041,
        0.1056, 0.1072, 0.1087, 0.1102, 0.1117, 0.1133, 0.1148, 0.1163, 0.1178, 0.1194,
        0.1209, 0.1224, 0.1239, 0.1255, 0.127, 0.1285, 0.13, 0.1315, 0.1331, 0.1346,
        0.1361, 0.1376, 0.1391, 0.1407, 0.1422, 0.1437, 0.1452, 0.1467, 0.1482, 0.1498,
        0.1513, 0.1528, 0.1543, 0.1558, 0.1573, 0.1589, 0.1604, 0.1619, 0.1634, 0.1649,
        0.1664, 0.1679, 0.1695, 0.171, 0.1725, 0.174, 0.1755, 0.177, 0.1785, 0.18,
        0.1815, 0.183, 0.1845, 0.1861, 0.1876, 0.1891, 0.1906, 0.1921, 0.1936, 0.1951,
        0.1966, 0.1981, 0.1996, 0.2011, 0.2026, 0.2041, 0.2056, 0.2071, 0.2086, 0.2101,
        0.2116, 0.2131, 0.2146, 0.2161, 0.2176, 0.2191, 0.2206, 0.2221, 0.2236, 0.2251,
        0.2266, 0.2281, 0.2296, 0.2311, 0.2326, 0.234, 0.2355, 0.237, 0.2385, 0.24,
        0.2415, 0.243, 0.2445, 0.246, 0.2474, 0.2489, 0.2504, 0.2519, 0.2534, 0.2549,
        0.2563, 0.2578, 0.2593, 0.2608, 0.2623, 0.2638, 0.2652, 0.2667, 0.2682, 0.2697,
        0.2711, 0.2726, 0.2741, 0.2756, 0.277, 0.2785, 0.28, 0.2815, 0.2829, 0.2844,
        0.2859, 0.2873, 0.2888, 0.2903, 0.2918, 0.2932, 0.2947, 0.2962, 0.2976, 0.2991,
        0.3005, 0.302, 0.3035, 0.3049, 0.3064, 0.3078, 0.3093, 0.3108, 0.3122, 0.3137,
        0.3151, 0.3166, 0.318, 0.3195, 0.321, 0.3224, 0.3239, 0.3253, 0.3268, 0.3282,
        0.3297, 0.3311, 0.3326, 0.334, 0.3354, 0.3369, 0.3383, 0.3398, 0.3412, 0.3427,
        0.3441, 0.3455, 0.347, 0.3484, 0.3499, 0.3513, 0.3527, 0.3542, 0.3556, 0.357,
        0.3585, 0.3599, 0.3613, 0.3628, 0.3642, 0.3656, 0.367, 0.3685, 0.3699, 0.3713,
        0.3727, 0.3742, 0.3756, 0.377, 0.3784, 0.3798, 0.3813, 0.3827, 0.3841, 0.3855,
        0.3869, 0.3883, 0.3898, 0.3912, 0.3926, 0.394, 0.3954, 0.3968, 0.3982, 0.3996,
        0.401, 0.4024, 0.4038, 0.4052, 0.4066, 0.408, 0.4094, 0.4108, 0.4122, 0.4136,
        0.415, 0.4164, 0.4178, 0.4192, 0.4206, 0.422, 0.4234, 0.4248, 0.4262, 0.4276,
        0.4289, 0.4303, 0.4317, 0.4331, 0.4345, 0.4359, 0.4372, 0.4386, 0.44, 0.4414,
        0.4427, 0.4441, 0.4455, 0.4469, 0.4482, 0.4496, 0.451, 0.4523, 0.4537, 0.4551,
        0.4564, 0.4578, 0.4592, 0.4605, 0.4619, 0.4633, 0.4646, 0.466, 0.4673, 0.4687,
        0.47, 0.4714, 0.4727, 0.4741, 0.4755, 0.4768, 0.4781, 0.4795, 0.4808, 0.4822,
        0.4835, 0.4849, 0.4862, 0.4876, 0.4889, 0.4902, 0.4916, 0.4929, 0.4942, 0.4956,
        0.4969, 0.4982, 0.4996, 0.5009, 0.5022, 0.5035, 0.5049, 0.5062, 0.5075, 0.5088,
        0.5102, 0.5115, 0.5128, 0.5141, 0.5154, 0.5167, 0.518, 0.5194, 0.5207, 0.522,
        0.5233, 0.5246, 0.5259, 0.5272, 0.5285, 0.5298, 0.5311, 0.5324, 0.5337, 0.535,
        0.5363, 0.5376, 0.5389, 0.5402, 0.5415, 0.5428, 0.544, 0.5453, 0.5466, 0.5479,
        0.5492, 0.5505, 0.5517, 0.553, 0.5543, 0.5556, 0.5568, 0.5581, 0.5594, 0.5607,
        0.5619, 0.5632, 0.5645, 0.5657, 0.567, 0.5683, 0.5695, 0.5708, 0.572, 0.5733,
        0.5746, 0.5758, 0.5771, 0.5783, 0.5796, 0.5808, 0.5821, 0.5833, 0.5846, 0.5858,
        0.587, 0.5883, 0.5895, 0.5908, 0.592, 0.5932, 0.5945, 0.5957, 0.5969, 0.5982,
        0.5994, 0.6006, 0.6018, 0.6031, 0.6043, 0.6055, 0.6067, 0.6079, 0.6092, 0.6104,
        0.6116, 0.6128, 0.614, 0.6152, 0.6164, 0.6176, 0.6189, 0.6201, 0.6213, 0.6225,
        0.6237, 0.6249, 0.6261, 0.6273, 0.6284, 0.6296, 0.6308, 0.632, 0.6332, 0.6344,
        0.6356, 0.6368, 0.6379, 0.6391, 0.6403, 0.6415, 0.6427, 0.6438, 0.645, 0.6462,
        0.6473, 0.6485, 0.6497, 0.6508, 0.652, 0.6532, 0.6543, 0.6555, 0.6567, 0.6578,
        0.659, 0.6601, 0.6613, 0.6624, 0.6636, 0.6647, 0.6659, 0.667, 0.6681, 0.6693,
        0.6704, 0.6716, 0.6727, 0.6738, 0.675, 0.6761, 0.6772, 0.6784, 0.6795, 0.6806,
        0.6817, 0.6828, 0.684, 0.6851, 0.6862, 0.6873, 0.6884, 0.6895, 0.6907, 0.6918,
        0.6929, 0.694, 0.6951, 0.6962, 0.6973, 0.6984, 0.6995, 0.7006, 0.7017, 0.7028,
        0.7038, 0.7049, 0.706, 0.7071, 0.7082, 0.7093, 0.7104, 0.7114, 0.7125, 0.7136,
        0.7147, 0.7157, 0.7168, 0.7179, 0.7189, 0.72, 0.7211, 0.7221, 0.7232, 0.7242,
        0.7253, 0.7264, 0.7274, 0.7285, 0.7295, 0.7306, 0.7316, 0.7327, 0.7337, 0.7347,
        0.7358, 0.7368, 0.7379, 0.7389, 0.7399, 0.741, 0.742, 0.743, 0.744, 0.7451,
        0.7461, 0.7471, 0.7481, 0.7491, 0.7502, 0.7512, 0.7522, 0.7532, 0.7542, 0.7552,
        0.7562, 0.7572, 0.7582, 0.7592, 0.7602, 0.7612, 0.7622, 0.7632, 0.7642, 0.7652,
        0.7662, 0.7671, 0.7681, 0.7691, 0.7701, 0.7711, 0.772, 0.773, 0.774, 0.775,
        0.7759, 0.7769, 0.7779, 0.7788, 0.7798, 0.7807, 0.7817, 0.7827, 0.7836, 0.7846,
        0.7855, 0.7865, 0.7874, 0.7883, 0.7893, 0.7902, 0.7912, 0.7921, 0.793, 0.794,
        0.7949, 0.7958, 0.7968, 0.7977, 0.7986, 0.7995, 0.8005, 0.8014, 0.8023, 0.8032,
        0.8041, 0.805, 0.8059, 0.8068, 0.8078, 0.8087, 0.8096, 0.8105, 0.8114, 0.8123,
        0.8131, 0.814, 0.8149, 0.8158, 0.8167, 0.8176, 0.8185, 0.8193, 0.8202, 0.8211,
        0.822, 0.8228, 0.8237, 0.8246, 0.8255, 0.8263, 0.8272, 0.828, 0.8289, 0.8298,
        0.8306, 0.8315, 0.8323, 0.8332, 0.834, 0.8349, 0.8357, 0.8365, 0.8374, 0.8382,
        0.8391, 0.8399, 0.8407, 0.8416, 0.8424, 0.8432, 0.844, 0.8449, 0.8457, 0.8465,
        0.8473, 0.8481, 0.8489, 0.8497, 0.8505, 0.8514, 0.8522, 0.853, 0.8538, 0.8546,
        0.8554, 0.8561, 0.8569, 0.8577, 0.8585, 0.8593, 0.8601, 0.8609, 0.8616, 0.8624,
        0.8632, 0.864, 0.8647, 0.8655, 0.8663, 0.867, 0.8678, 0.8686, 0.8693, 0.8701,
        0.8708, 0.8716, 0.8723, 0.8731, 0.8738, 0.8746, 0.8753, 0.8761, 0.8768, 0.8775,
        0.8783, 0.879, 0.8797, 0.8805, 0.8812, 0.8819, 0.8826, 0.8834, 0.8841, 0.8848,
        0.8855, 0.8862, 0.8869, 0.8876, 0.8883, 0.889, 0.8897, 0.8904, 0.8911, 0.8918,
        0.8925, 0.8932, 0.8939, 0.8946, 0.8953, 0.896, 0.8966, 0.8973, 0.898, 0.8987,
        0.8993, 0.9, 0.9007, 0.9013, 0.902, 0.9027, 0.9033, 0.904, 0.9046, 0.9053,
        0.9059, 0.9066, 0.9072, 0.9079, 0.9085, 0.9092, 0.9098, 0.9104, 0.9111, 0.9117,
        0.9123, 0.913, 0.9136, 0.9142, 0.9148, 0.9154, 0.9161, 0.9167, 0.9173, 0.9179,
        0.9185, 0.9191, 0.9197, 0.9203, 0.9209, 0.9215, 0.9221, 0.9227, 0.9233, 0.9239,
        0.9245, 0.925, 0.9256, 0.9262, 0.9268, 0.9274, 0.9279, 0.9285, 0.9291, 0.9296,
        0.9302, 0.9308, 0.9313, 0.9319, 0.9324, 0.933, 0.9335, 0.9341, 0.9346, 0.9352,
        0.9357, 0.9363, 0.9368, 0.9373, 0.9379, 0.9384, 0.9389, 0.9395, 0.94, 0.9405,
        0.941, 0.9415, 0.9421, 0.9426, 0.9431, 0.9436, 0.9441, 0.9446, 0.9451, 0.9456,
        0.9461, 0.9466, 0.9471, 0.9476, 0.9481, 0.9486, 0.949, 0.9495, 0.95, 0.9505,
        0.951, 0.9514, 0.9519, 0.9524, 0.9528, 0.9533, 0.9538, 0.9542, 0.9547, 0.9551,
        0.9556, 0.956, 0.9565, 0.9569, 0.9574, 0.9578, 0.9583, 0.9587, 0.9591, 0.9596,
        0.96, 0.9604, 0.9609, 0.9613, 0.9617, 0.9621, 0.9625, 0.963, 0.9634, 0.9638,
        0.9642, 0.9646, 0.965, 0.9654, 0.9658, 0.9662, 0.9666, 0.967, 0.9674, 0.9678,
        0.9681, 0.9685, 0.9689, 0.9693, 0.9697, 0.97, 0.9704, 0.9708, 0.9711, 0.9715,
        0.9719, 0.9722, 0.9726, 0.9729, 0.9733, 0.9736, 0.974, 0.9743, 0.9747, 0.975,
        0.9754, 0.9757, 0.976, 0.9764, 0.9767, 0.977, 0.9774, 0.9777, 0.978, 0.9783,
        0.9786, 0.9789, 0.9793, 0.9796, 0.9799, 0.9802, 0.9805, 0.9808, 0.9811, 0.9814,
        0.9817, 0.982, 0.9823, 0.9825, 0.9828, 0.9831, 0.9834, 0.9837, 0.9839, 0.9842,
        0.9845, 0.9847, 0.985, 0.9853, 0.9855, 0.9858, 0.9861, 0.9863, 0.9866, 0.9868,
        0.9871, 0.9873, 0.9875, 0.9878, 0.988, 0.9883, 0.9885, 0.9887, 0.989, 0.9892,
        0.9894, 0.9896, 0.9898, 0.9901, 0.9903, 0.9905, 0.9907, 0.9909, 0.9911, 0.9913,
        0.9915, 0.9917, 0.9919, 0.9921, 0.9923, 0.9925, 0.9927, 0.9929, 0.993, 0.9932,
        0.9934, 0.9936, 0.9937, 0.9939, 0.9941, 0.9942, 0.9944, 0.9946, 0.9947, 0.9949,
        0.995, 0.9952, 0.9953, 0.9955, 0.9956, 0.9958, 0.9959, 0.996, 0.9962, 0.9963,
        0.9964, 0.9966, 0.9967, 0.9968, 0.9969, 0.9971, 0.9972, 0.9973, 0.9974, 0.9975,
        0.9976, 0.9977, 0.9978, 0.9979, 0.998, 0.9981, 0.9982, 0.9983, 0.9984, 0.9985,
        0.9986, 0.9986, 0.9987, 0.9988, 0.9989, 0.9989, 0.999, 0.9991, 0.9991, 0.9992,
        0.9993, 0.9993, 0.9994, 0.9994, 0.9995, 0.9995, 0.9996, 0.9996, 0.9997, 0.9997,
        0.9997, 0.9998, 0.9998, 0.9998, 0.9999, 0.9999, 0.9999, 0.9999, 0.9999, 1,
        1, 1, 1, 1, 1, 1};

        const static uint64 mask = max-1;
        return logvals[h.first&mask]*cosvals[h.second&mask];

        // Note that we are just using the Box–Muller transform to compute the result.  In
        // particular, we are doing this (where u1 and u2 are uniform random variables in
        // the range [0,1]):
        //    return sqrt(-2*log(u1)) * cos(2*PI*u2);
        // It is just that we use table lookups to avoid calling sqrt(), log() and cos().
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_RANDOM_HAsHING_Hh_


dlib C++ Library - border_enumerator.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_BORDER_EnUMERATOR_H_
#define DLIB_BORDER_EnUMERATOR_H_

#include "border_enumerator_abstract.h"
#include "rectangle.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class border_enumerator
    {
    public:
        border_enumerator(
        )
        {
            reset();
        }

        border_enumerator(
            const rectangle& rect_,
            unsigned long border_size
        ) :
            rect(rect_),
            inner_rect(shrink_rect(rect_, border_size))
        {
            reset();
        }

        border_enumerator(
            const rectangle& rect_,
            const rectangle& non_border_region
        ) :
            rect(rect_),
            inner_rect(non_border_region.intersect(rect))
        {
            reset();
        }

        void reset (
        )
        {
            // make the four rectangles that surround inner_rect and intersect them
            // with rect.
            bleft   = rect.intersect(rectangle(std::numeric_limits<long>::min(),
                                               std::numeric_limits<long>::min(),
                                               inner_rect.left()-1,
                                               std::numeric_limits<long>::max()));

            bright  = rect.intersect(rectangle(inner_rect.right()+1,
                                               std::numeric_limits<long>::min(),
                                               std::numeric_limits<long>::max(),
                                               std::numeric_limits<long>::max()));

            btop    = rect.intersect(rectangle(inner_rect.left(),
                                               std::numeric_limits<long>::min(),
                                               inner_rect.right(),
                                               inner_rect.top()-1));

            bbottom = rect.intersect(rectangle(inner_rect.left(),
                                               inner_rect.bottom()+1,
                                               inner_rect.right(),
                                               std::numeric_limits<long>::max()));

            p = bleft.tl_corner();
            p.x() -= 1;

            mode = atleft;
        }

        bool at_start (
        ) const
        {
            point temp = bleft.tl_corner();
            temp.x() -=1;
            return temp == p;
        }

        bool current_element_valid(
        ) const
        {
            return rect.contains(p);
        }

        bool move_next()
        {
            if (mode == atleft)
            {
                if (advance_point(bleft, p))
                    return true;

                mode = attop;
                p = btop.tl_corner();
                p.x() -= 1;
            }
            if (mode == attop)
            {
                if (advance_point(btop, p))
                    return true;

                mode = atright;
                p = bright.tl_corner();
                p.x() -= 1;
            }
            if (mode == atright)
            {
                if (advance_point(bright, p))
                    return true;

                mode = atbottom;
                p = bbottom.tl_corner();
                p.x() -= 1;
            }

            if (advance_point(bbottom, p))
                return true;

            // put p outside rect since there are no more points to enumerate
            p = rect.br_corner();
            p.x() += 1;

            return false;
        }

        unsigned long size (
        ) const
        {
            return rect.area() - inner_rect.area();
        }

        const point& element (
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(current_element_valid(),
                "\t point border_enumerator::element()"
                << "\n\t This function can't be called unless the element is valid."
                << "\n\t this: " << this
                );

            return p;
        }

    private:

        bool advance_point (
            const rectangle& r,
            point& p
        ) const
        {
            p.x() += 1;
            if (p.x() > r.right())
            {
                p.x() = r.left();
                p.y() += 1;
            }

            return r.contains(p);
        }

        point p;
        rectangle rect;
        rectangle inner_rect;  // the non-border regions of rect

        enum emode
        {
            atleft,
            atright,
            atbottom,
            attop
        };

        emode mode;

        rectangle btop, bleft, bright, bbottom;
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_BORDER_EnUMERATOR_H_


dlib C++ Library - drectangle.h

// Copyright (C) 2015  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_DRECTANGLe_
#define DLIB_DRECTANGLe_

#include "drectangle_abstract.h"
#include "rectangle.h"

namespace dlib
{
    class drectangle;
    drectangle operator* (
        const drectangle& rect,
        const double& scale
    );

// ----------------------------------------------------------------------------------------

    class drectangle
    {
    public:

        drectangle (
        ) : l(0), t(0), r(-1), b(-1) {}

        drectangle (
            double l_,
            double t_,
            double r_,
            double b_
        ) :
            l(l_),
            t(t_),
            r(r_),
            b(b_)
        {}

        drectangle (
            const dlib::vector<double,2>& p
        ) :
            l(p.x()),
            t(p.y()),
            r(p.x()),
            b(p.y())
        {
        }

        template <typename T, typename U>
        drectangle (
            const vector<T,2>& p1,
            const vector<U,2>& p2
        )
        {
            *this = drectangle(p1) + drectangle(p2);
        }

        drectangle (
            const rectangle& rect
        ) : l(rect.left()),
            t(rect.top()),
            r(rect.right()),
            b(rect.bottom()) {}

        operator rectangle (
        ) const
        {
            return rectangle((long)std::floor(l+0.5),
                             (long)std::floor(t+0.5),
                             (long)std::floor(r+0.5),
                             (long)std::floor(b+0.5));
        }

        double left()   const { return l; }
        double top()    const { return t; }
        double right()  const { return r; }
        double bottom() const { return b; }

        double& left()   { return l; }
        double& top()    { return t; }
        double& right()  { return r; }
        double& bottom() { return b; }

        const dlib::vector<double,2> tl_corner (
        ) const { return dlib::vector<double,2>(left(), top()); }

        const dlib::vector<double,2> bl_corner (
        ) const { return dlib::vector<double,2>(left(), bottom()); }

        const dlib::vector<double,2> tr_corner (
        ) const { return dlib::vector<double,2>(right(), top()); }

        const dlib::vector<double,2> br_corner (
        ) const { return dlib::vector<double,2>(right(), bottom()); }

        double width (
        ) const
        {
            if (is_empty())
                return 0;
            else
                return r - l + 1;
        }

        double height (
        ) const
        {
            if (is_empty())
                return 0;
            else
                return b - t + 1;
        }

        double area (
        ) const
        {
            return width()*height();
        }

        bool is_empty (
        ) const { return (t > b || l > r); }

        drectangle operator + (
            const drectangle& rhs
        ) const
        {
            if (rhs.is_empty())
                return *this;
            else if (is_empty())
                return rhs;

            return drectangle (
                std::min(l,rhs.l),
                std::min(t,rhs.t),
                std::max(r,rhs.r),
                std::max(b,rhs.b)
                );
        }

        drectangle intersect (
            const drectangle& rhs
        ) const
        {
            return drectangle (
                std::max(l,rhs.l),
                std::max(t,rhs.t),
                std::min(r,rhs.r),
                std::min(b,rhs.b)
                );
        }

        bool contains (
            const dlib::vector<double,2>& p
        ) const
        {
            if (p.x() < l || p.x() > r || p.y() < t || p.y() > b)
                return false;
            return true;
        }

        bool contains (
            const drectangle& rect
        ) const
        {
            if (rect.is_empty())
                return true;
            if (l <= rect.left() &&
                r >= rect.right() &&
                t <= rect.top() &&
                b >= rect.bottom())
                return true;
            return false;
        }

        drectangle& operator *= (
            const double& scale
        )
        {
            *this = *this*scale;
            return *this;
        }

        drectangle& operator /= (
            const double& scale
        )
        {
            *this = *this*(1.0/scale);
            return *this;
        }

        drectangle& operator += (
            const dlib::vector<double,2>& p
        )
        {
            *this = *this + drectangle(p);
            return *this;
        }

    private:
        double l;
        double t;
        double r;
        double b;
    };

// ----------------------------------------------------------------------------------------

    inline void serialize (
        const drectangle& item,
        std::ostream& out
    )
    {
        try
        {
            serialize(item.left(),out);
            serialize(item.top(),out);
            serialize(item.right(),out);
            serialize(item.bottom(),out);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while serializing an object of type drectangle");
        }
    }

    inline void deserialize (
        drectangle& item,
        std::istream& in
    )
    {
        try
        {
            deserialize(item.left(),in);
            deserialize(item.top(),in);
            deserialize(item.right(),in);
            deserialize(item.bottom(),in);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while deserializing an object of type drectangle");
        }
    }

    inline std::ostream& operator<< (
        std::ostream& out,
        const drectangle& item
    )
    {
        out << "[(" << item.left() << ", " << item.top() << ") (" << item.right() << ", " << item.bottom() << ")]";
        return out;
    }

    inline std::istream& operator>>(
        std::istream& in,
        drectangle& item
    )
    {
        // ignore any whitespace
        while (in.peek() == ' ' || in.peek() == '\t' || in.peek() == '\r' || in.peek() == '\n')
            in.get();
        // now eat the leading '[' character
        if (in.get() != '[')
        {
            in.setstate(in.rdstate() | std::ios::failbit);
            return in;
        }

        dlib::vector<double,2> p1, p2;
        in >> p1;
        in >> p2;
        item = drectangle(p1) + drectangle(p2);

        // ignore any whitespace
        while (in.peek() == ' ' || in.peek() == '\t' || in.peek() == '\r' || in.peek() == '\n')
            in.get();
        // now eat the trailing ']' character
        if (in.get() != ']')
        {
            in.setstate(in.rdstate() | std::ios::failbit);
        }
        return in;
    }

// ----------------------------------------------------------------------------------------

    inline dlib::vector<double,2> center (
        const drectangle& rect
    )
    {
        dlib::vector<double,2> temp(rect.left() + rect.right(),
                                    rect.top() + rect.bottom());

        return temp/2.0;
    }

    inline dlib::vector<double,2> dcenter (
        const drectangle& rect
    )
    {
        return center(rect);
    }

    inline drectangle operator* (
        const drectangle& rect,
        const double& scale
    )
    {
        if (!rect.is_empty())
        {
            const double width = (rect.right()-rect.left())*scale;
            const double height = (rect.bottom()-rect.top())*scale;
            const dlib::vector<double,2> p = center(rect);
            return drectangle(p.x()-width/2, p.y()-height/2, p.x()+width/2, p.y()+height/2);
        }
        else
        {
            return rect;
        }
    }

    inline drectangle operator* (
        const double& scale,
        const drectangle& rect
    )
    {
        return rect*scale;
    }

    inline drectangle operator/ (
        const drectangle& rect,
        const double& scale
    )
    {
        return rect*(1.0/scale);
    }

    inline drectangle operator+ (
        const drectangle& r,
        const dlib::vector<double,2>& p
    )
    {
        return r + drectangle(p);
    }

    inline drectangle operator+ (
        const dlib::vector<double,2>& p,
        const drectangle& r
    )
    {
        return r + drectangle(p);
    }

    template <typename T>
    inline drectangle translate_rect (
        const drectangle& rect,
        const dlib::vector<T,2>& p
    )
    {
        drectangle result;
        result.top    () = rect.top()    + p.y();
        result.bottom () = rect.bottom() + p.y();
        result.left   () = rect.left()   + p.x();
        result.right  () = rect.right()  + p.x();
        return result;
    }

    inline drectangle intersect (
        const drectangle& a,
        const drectangle& b
    ) { return a.intersect(b); }

    inline double area (
        const drectangle& a
    ) { return a.area(); }

    inline drectangle centered_drect (
        const dlib::vector<double,2>& p,
        double width,
        double height
    )
    {
        width--;
        height--;

        return drectangle(p.x()-width/2, p.y()-height/2, p.x()+width/2, p.y()+height/2);
    }

    inline drectangle centered_drect (
        const drectangle& rect,
        double width,
        double height
    )
    {
        return centered_drect(dcenter(rect), width, height);
    }

    inline const drectangle shrink_rect (
        const drectangle& rect,
        double num
    )
    {
        return drectangle(rect.left()+num, rect.top()+num, rect.right()-num, rect.bottom()-num);
    }

    inline const drectangle grow_rect (
        const drectangle& rect,
        double num
    )
    {
        return shrink_rect(rect, -num);
    }

    inline const drectangle shrink_rect (
        const drectangle& rect,
        double width,
        double height
    )
    {
        return drectangle(rect.left()+width, rect.top()+height, rect.right()-width, rect.bottom()-height);
    }

    inline const drectangle grow_rect (
        const drectangle& rect,
        double width,
        double height
    )
    {
        return shrink_rect(rect, -width, -height);
    }

    inline drectangle set_aspect_ratio (
        const drectangle& rect,
        double ratio
    )
    {
        DLIB_ASSERT(ratio > 0,
            "\t drectangle set_aspect_ratio()"
            << "\n\t ratio: " << ratio
            );

        const double h = std::sqrt(rect.area()/ratio);
        const double w = h*ratio;
        return centered_drect(rect, w, h);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_DRECTANGLe_


dlib C++ Library - point_transforms.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_POINT_TrANSFORMS_H_
#define DLIB_POINT_TrANSFORMS_H_

#include "point_transforms_abstract.h"
#include "../algs.h"
#include "vector.h"
#include "../matrix.h"
#include "../matrix/matrix_la.h"
#include "../optimization/optimization.h"
#include <vector>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class point_rotator
    {
    public:
        point_rotator (
        )
        {
            sin_angle = 0;
            cos_angle = 1;
        }

        point_rotator (
            const double& angle
        )
        {
            sin_angle = std::sin(angle);
            cos_angle = std::cos(angle);
        }

        template <typename T>
        const dlib::vector<T,2> operator() (
            const dlib::vector<T,2>& p
        ) const
        {
            double x = cos_angle*p.x() - sin_angle*p.y();
            double y = sin_angle*p.x() + cos_angle*p.y();

            return dlib::vector<double,2>(x,y);
        }

        const matrix<double,2,2> get_m(
        ) const
        {
            matrix<double,2,2> temp;
            temp = cos_angle, -sin_angle,
                   sin_angle, cos_angle;
            return temp;
        }

        inline friend void serialize (const point_rotator& item, std::ostream& out)
        {
            serialize(item.sin_angle, out);
            serialize(item.cos_angle, out);
        }

        inline friend void deserialize (point_rotator& item, std::istream& in)
        {
            deserialize(item.sin_angle, in);
            deserialize(item.cos_angle, in);
        }

    private:
        double sin_angle;
        double cos_angle;
    };

// ----------------------------------------------------------------------------------------

    class point_transform
    {
    public:

        point_transform (
        )
        {
            sin_angle = 0;
            cos_angle = 1;
            translate.x() = 0;
            translate.y() = 0;
        }

        point_transform (
            const double& angle,
            const dlib::vector<double,2>& translate_
        )
        {
            sin_angle = std::sin(angle);
            cos_angle = std::cos(angle);
            translate = translate_;
        }

        template <typename T>
        const dlib::vector<T,2> operator() (
            const dlib::vector<T,2>& p
        ) const
        {
            double x = cos_angle*p.x() - sin_angle*p.y();
            double y = sin_angle*p.x() + cos_angle*p.y();

            return dlib::vector<double,2>(x,y) + translate;
        }

        const matrix<double,2,2> get_m(
        ) const
        {
            matrix<double,2,2> temp;
            temp = cos_angle, -sin_angle,
                   sin_angle, cos_angle;
            return temp;
        }

        const dlib::vector<double,2> get_b(
        ) const { return translate; }

        inline friend void serialize (const point_transform& item, std::ostream& out)
        {
            serialize(item.sin_angle, out);
            serialize(item.cos_angle, out);
            serialize(item.translate, out);
        }

        inline friend void deserialize (point_transform& item, std::istream& in)
        {
            deserialize(item.sin_angle, in);
            deserialize(item.cos_angle, in);
            deserialize(item.translate, in);
        }

    private:
        double sin_angle;
        double cos_angle;
        dlib::vector<double,2> translate;
    };

// ----------------------------------------------------------------------------------------

    class point_transform_affine
    {
    public:

        point_transform_affine (
        )
        {
            m = identity_matrix<double>(2);
            b.x() = 0;
            b.y() = 0;
        }

        point_transform_affine (
            const matrix<double,2,2>& m_,
            const dlib::vector<double,2>& b_
        ) :m(m_), b(b_)
        {
        }

        const dlib::vector<double,2> operator() (
            const dlib::vector<double,2>& p
        ) const
        {
            return m*p + b;
        }

        const matrix<double,2,2>& get_m(
        ) const { return m; }

        const dlib::vector<double,2>& get_b(
        ) const { return b; }

        inline friend void serialize (const point_transform_affine& item, std::ostream& out)
        {
            serialize(item.m, out);
            serialize(item.b, out);
        }

        inline friend void deserialize (point_transform_affine& item, std::istream& in)
        {
            deserialize(item.m, in);
            deserialize(item.b, in);
        }

    private:
        matrix<double,2,2> m;
        dlib::vector<double,2> b;
    };

// ----------------------------------------------------------------------------------------

    inline point_transform_affine operator* (
        const point_transform_affine& lhs,
        const point_transform_affine& rhs
    )
    {
        return point_transform_affine(lhs.get_m()*rhs.get_m(), lhs.get_m()*rhs.get_b()+lhs.get_b());
    }

// ----------------------------------------------------------------------------------------

    inline point_transform_affine inv (
        const point_transform_affine& trans
    )
    {
        matrix<double,2,2> im = inv(trans.get_m());
        return point_transform_affine(im, -im*trans.get_b());
    }

// ----------------------------------------------------------------------------------------

    template <typename T>
    point_transform_affine find_affine_transform (
        const std::vector<dlib::vector<T,2> >& from_points,
        const std::vector<dlib::vector<T,2> >& to_points
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(from_points.size() == to_points.size() &&
                    from_points.size() >= 3,
            "\t point_transform_affine find_affine_transform(from_points, to_points)"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t from_points.size(): " << from_points.size()
            << "\n\t to_points.size():   " << to_points.size()
            );

        matrix<double,3,0> P(3, from_points.size());
        matrix<double,2,0> Q(2, from_points.size());

        for (unsigned long i = 0; i < from_points.size(); ++i)
        {
            P(0,i) = from_points[i].x();
            P(1,i) = from_points[i].y();
            P(2,i) = 1;

            Q(0,i) = to_points[i].x();
            Q(1,i) = to_points[i].y();
        }

        const matrix<double,2,3> m = Q*pinv(P);
        return point_transform_affine(subm(m,0,0,2,2), colm(m,2));
    }

// ----------------------------------------------------------------------------------------

    template <typename T>
    point_transform_affine find_similarity_transform (
        const std::vector<dlib::vector<T,2> >& from_points,
        const std::vector<dlib::vector<T,2> >& to_points
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(from_points.size() == to_points.size() &&
                    from_points.size() >= 2,
            "\t point_transform_affine find_similarity_transform(from_points, to_points)"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t from_points.size(): " << from_points.size()
            << "\n\t to_points.size():   " << to_points.size()
            );

        // We use the formulas from the paper: Least-squares estimation of transformation
        // parameters between two point patterns by Umeyama.  They are equations 34 through
        // 43.

        dlib::vector<double,2> mean_from, mean_to;
        double sigma_from = 0, sigma_to = 0;
        matrix<double,2,2> cov;
        cov = 0;

        for (unsigned long i = 0; i < from_points.size(); ++i)
        {
            mean_from += from_points[i];
            mean_to += to_points[i];
        }
        mean_from /= from_points.size();
        mean_to   /= from_points.size();

        for (unsigned long i = 0; i < from_points.size(); ++i)
        {
            sigma_from += length_squared(from_points[i] - mean_from);
            sigma_to += length_squared(to_points[i] - mean_to);
            cov += (to_points[i] - mean_to)*trans(from_points[i] - mean_from);
        }

        sigma_from /= from_points.size();
        sigma_to   /= from_points.size();
        cov        /= from_points.size();

        matrix<double,2,2> u, v, s, d;
        svd(cov, u,d,v);
        s = identity_matrix(cov);
        if (det(cov) < 0 || (det(cov) == 0 && det(u)*det(v)<0))
        {
            if (d(1,1) < d(0,0))
                s(1,1) = -1;
            else
                s(0,0) = -1;
        }

        matrix<double,2,2> r = u*s*trans(v);
        double c = 1;
        if (sigma_from != 0)
            c = 1.0/sigma_from * trace(d*s);
        vector<double,2> t = mean_to - c*r*mean_from;

        return point_transform_affine(c*r, t);
    }

// ----------------------------------------------------------------------------------------

    class point_transform_projective
    {
    public:

        point_transform_projective (
        )
        {
            m = identity_matrix<double>(3);
        }

        point_transform_projective (
            const matrix<double,3,3>& m_
        ) :m(m_)
        {
        }

        point_transform_projective (
            const point_transform_affine& tran
        )
        {
            set_subm(m, 0,0, 2,2) = tran.get_m();
            set_subm(m, 0,2, 2,1) = tran.get_b();
            m(2,0) = 0;
            m(2,1) = 0;
            m(2,2) = 1;
        }

        const dlib::vector<double,2> operator() (
            const dlib::vector<double,2>& p
        ) const
        {
            dlib::vector<double,3> temp(p);
            temp.z() = 1;
            temp = m*temp;
            if (temp.z() != 0)
                temp = temp/temp.z();
            return temp;
        }

        const matrix<double,3,3>& get_m(
        ) const { return m; }

        inline friend void serialize (const point_transform_projective& item, std::ostream& out)
        {
            serialize(item.m, out);
        }

        inline friend void deserialize (point_transform_projective& item, std::istream& in)
        {
            deserialize(item.m, in);
        }

    private:
        matrix<double,3,3> m;
    };

// ----------------------------------------------------------------------------------------

    inline point_transform_projective operator* (
        const point_transform_projective& lhs,
        const point_transform_projective& rhs
    )
    {
        return point_transform_projective(lhs.get_m()*rhs.get_m());
    }

// ----------------------------------------------------------------------------------------

    inline point_transform_projective inv (
        const point_transform_projective& trans
    )
    {
        return point_transform_projective(inv(trans.get_m()));
    }

// ----------------------------------------------------------------------------------------

    namespace impl_proj
    {

        inline point_transform_projective find_projective_transform_basic (
            const std::vector<dlib::vector<double,2> >& from_points,
            const std::vector<dlib::vector<double,2> >& to_points
        )
        /*!
            ensures
                - Uses the system of equations approach to finding a projective transform.
                  This is "Method 3" from Estimating Projective Transformation Matrix by
                  Zhengyou Zhang.
                - It should be emphasized that the find_projective_transform_basic()
                  routine, which uses the most popular method for finding projective
                  transformations, doesn't really work well when the minimum error solution
                  doesn't have zero error.  In this case, it can deviate by a large amount
                  from the proper minimum mean squared error transformation.  Therefore,
                  our overall strategy will be to use the solution from
                  find_projective_transform_basic() as a starting point for a BFGS based
                  non-linear optimizer which will optimize the correct mean squared error
                  criterion.

                  A great essay on this subject is Homography Estimation by Elan Dubrofsky.
        !*/
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(from_points.size() == to_points.size() &&
                from_points.size() >= 4,
                "\t point_transform_projective find_projective_transform_basic(from_points, to_points)"
                << "\n\t Invalid inputs were given to this function."
                << "\n\t from_points.size(): " << from_points.size()
                << "\n\t to_points.size():   " << to_points.size()
            );

            matrix<double,9,9> accum, u, v;
            matrix<double,9,1> w;
            matrix<double,2,9> B;
            accum = 0;
            B = 0;
            for (unsigned long i = 0; i < from_points.size(); ++i)
            {
                dlib::vector<double,3> f = from_points[i];
                f.z() = 1;
                dlib::vector<double,3> t = to_points[i];
                t.z() = 1;

                set_subm(B,0,0,1,3) = t.y()*trans(f);
                set_subm(B,1,0,1,3) =       trans(f);

                set_subm(B,0,3,1,3) = -t.x()*trans(f);
                set_subm(B,1,6,1,3) = -t.x()*trans(f);

                accum += trans(B)*B;
            }

            svd2(true, false, accum, u, w, v);
            long j = index_of_min(w);

            return point_transform_projective(reshape(colm(u,j),3,3));
        }

    // ----------------------------------------------------------------------------------------

        struct obj
        {
            /*!
                WHAT THIS OBJECT REPRESENTS
                    This is the objective function we really want to minimize when looking
                    for a transformation matrix.  That is, we would like the transformed
                    points to be as close as possible to their "to" points.  Here,
                    closeness is measured using Euclidean distance.

            !*/
            obj(
                const std::vector<dlib::vector<double,2> >& from_points_,
                const std::vector<dlib::vector<double,2> >& to_points_
            ) :
                from_points(from_points_) ,
                to_points(to_points_)
            {}
            const std::vector<dlib::vector<double,2> >& from_points;
            const std::vector<dlib::vector<double,2> >& to_points;

            double operator() (
                const matrix<double,9,1>& p
            ) const
            {
                point_transform_projective tran(reshape(p,3,3));

                double sum = 0;
                for (unsigned long i = 0; i < from_points.size(); ++i)
                {
                    sum += length_squared(tran(from_points[i]) - to_points[i]);
                }
                return sum;
            }
        };

        struct obj_der
        {
            /*!
                WHAT THIS OBJECT REPRESENTS
                    This is the derivative of obj.
            !*/

            obj_der(
                const std::vector<dlib::vector<double,2> >& from_points_,
                const std::vector<dlib::vector<double,2> >& to_points_
            ) :
                from_points(from_points_) ,
                to_points(to_points_)
            {}
            const std::vector<dlib::vector<double,2> >& from_points;
            const std::vector<dlib::vector<double,2> >& to_points;

            matrix<double,9,1> operator() (
                const matrix<double,9,1>& p
            ) const
            {
                const matrix<double,3,3> H = reshape(p,3,3);

                matrix<double,3,3> grad;
                grad = 0;
                for (unsigned long i = 0; i < from_points.size(); ++i)
                {
                    dlib::vector<double,3> from, to;
                    from = from_points[i];
                    from.z() = 1;
                    to = to_points[i];
                    to.z() = 1;

                    matrix<double,3,1> w = H*from;
                    const double scale = (w(2) != 0) ? (1.0/w(2)) : (1);
                    w *= scale;
                    matrix<double,3,1> residual = (w-to)*2*scale;

                    grad(0,0) += from.x()*residual(0);
                    grad(0,1) += from.y()*residual(0);
                    grad(0,2) +=          residual(0);

                    grad(1,0) += from.x()*residual(1);
                    grad(1,1) += from.y()*residual(1);
                    grad(1,2) +=          residual(1);

                    grad(2,0) += -(from.x()*w(0)*residual(0) + from.x()*w(1)*residual(1));
                    grad(2,1) += -(from.y()*w(0)*residual(0) + from.y()*w(1)*residual(1));
                    grad(2,2) += -(         w(0)*residual(0) +          w(1)*residual(1));

                }
                return reshape_to_column_vector(grad);
            }
        };
    }

// ----------------------------------------------------------------------------------------

    inline point_transform_projective find_projective_transform (
        const std::vector<dlib::vector<double,2> >& from_points,
        const std::vector<dlib::vector<double,2> >& to_points
    )
    {
        using namespace impl_proj;
        // make sure requires clause is not broken
        DLIB_ASSERT(from_points.size() == to_points.size() &&
                    from_points.size() >= 4,
            "\t point_transform_projective find_projective_transform(from_points, to_points)"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t from_points.size(): " << from_points.size()
            << "\n\t to_points.size():   " << to_points.size()
            );

        // Find a candidate projective transformation.  Also, find the best affine
        // transform and then compare it with the projective transform estimated using the
        // direct SVD method.  Use whichever one works better as the starting point for a
        // BFGS based optimizer.  If the best solution has large mean squared error and is
        // also close to affine then find_projective_transform_basic() might give a very
        // bad initial guess.  So also checking for a good affine transformation can
        // produce a much better final result in many cases.
        point_transform_projective tran1 = find_projective_transform_basic(from_points, to_points);
        point_transform_affine tran2 = find_affine_transform(from_points, to_points);

        // check which is best
        double error1 = 0;
        double error2 = 0;
        for (unsigned long i = 0; i < from_points.size(); ++i)
        {
            error1 += length_squared(tran1(from_points[i])-to_points[i]);
            error2 += length_squared(tran2(from_points[i])-to_points[i]);
        }
        matrix<double,9,1> params;
        // Pick the minimum error solution among the two so far.
        if (error1 < error2)
            params = reshape_to_column_vector(tran1.get_m());
        else
            params = reshape_to_column_vector(point_transform_projective(tran2).get_m());

        // Now refine the transformation matrix so that we can be sure we have
        // at least a local minimizer.
        obj o(from_points, to_points);
        obj_der der(from_points, to_points);
        find_min(bfgs_search_strategy(),
                objective_delta_stop_strategy(1e-6,100),
                o,
                der,
                params,
                0);

        return point_transform_projective(reshape(params,3,3));
    }

// ----------------------------------------------------------------------------------------

    template <typename T>
    const dlib::vector<T,2> rotate_point (
        const dlib::vector<T,2>& center,
        const dlib::vector<T,2>& p,
        double angle
    )
    {
        point_rotator rot(angle);
        return rot(p-center)+center;
    }

// ----------------------------------------------------------------------------------------

    inline matrix<double,2,2> rotation_matrix (
         double angle
    )
    {
        const double ca = std::cos(angle);
        const double sa = std::sin(angle);

        matrix<double,2,2> m;
        m = ca, -sa,
            sa, ca;
        return m;
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class point_transform_affine3d
    {
    public:

        point_transform_affine3d (
        )
        {
            m = identity_matrix<double>(3);
            b.x() = 0;
            b.y() = 0;
        }

        point_transform_affine3d (
            const matrix<double,3,3>& m_,
            const dlib::vector<double,3>& b_
        ) :m(m_), b(b_)
        {
        }

        const dlib::vector<double,3> operator() (
            const dlib::vector<double,3>& p
        ) const
        {
            return m*p + b;
        }

        const matrix<double,3,3>& get_m(
        ) const { return m; }

        const dlib::vector<double,3>& get_b(
        ) const { return b; }

        inline friend void serialize (const point_transform_affine3d& item, std::ostream& out)
        {
            serialize(item.m, out);
            serialize(item.b, out);
        }

        inline friend void deserialize (point_transform_affine3d& item, std::istream& in)
        {
            deserialize(item.m, in);
            deserialize(item.b, in);
        }

    private:
        matrix<double,3,3> m;
        dlib::vector<double,3> b;
    };

// ----------------------------------------------------------------------------------------

    inline point_transform_affine3d operator* (
        const point_transform_affine3d& lhs,
        const point_transform_affine& rhs
    )
    {
        matrix<double,3,3> m;
        m = 0;
        set_subm(m, get_rect(rhs.get_m())) = rhs.get_m();
        vector<double,3> b = rhs.get_b();

        return point_transform_affine3d(lhs.get_m()*m, lhs.get_m()*b+lhs.get_b());
    }

// ----------------------------------------------------------------------------------------

    inline point_transform_affine3d operator* (
        const point_transform_affine3d& lhs,
        const point_transform_affine3d& rhs
    )
    {
        return point_transform_affine3d(lhs.get_m()*rhs.get_m(), lhs.get_m()*rhs.get_b()+lhs.get_b());
    }

// ----------------------------------------------------------------------------------------

    inline point_transform_affine3d inv (
        const point_transform_affine3d& trans
    )
    {
        matrix<double,3,3> im = inv(trans.get_m());
        return point_transform_affine3d(im, -im*trans.get_b());
    }

// ----------------------------------------------------------------------------------------

    inline point_transform_affine3d rotate_around_x (
        double angle
    )
    {
        const double ca = std::cos(angle);
        const double sa = std::sin(angle);

        matrix<double,3,3> m;
        m = 1,  0,  0,
            0, ca, -sa,
            0, sa, ca;

        vector<double,3> b;

        return point_transform_affine3d(m,b);
    }

// ----------------------------------------------------------------------------------------

    inline point_transform_affine3d rotate_around_y (
        double angle
    )
    {
        const double ca = std::cos(angle);
        const double sa = std::sin(angle);

        matrix<double,3,3> m;
        m = ca,  0, sa,
             0,  1, 0,
            -sa, 0, ca;

        vector<double,3> b;

        return point_transform_affine3d(m,b);
    }

// ----------------------------------------------------------------------------------------

    inline point_transform_affine3d rotate_around_z (
        double angle
    )
    {
        const double ca = std::cos(angle);
        const double sa = std::sin(angle);

        matrix<double,3,3> m;
        m = ca, -sa, 0,
            sa, ca,  0,
            0,   0,  1;

        vector<double,3> b;

        return point_transform_affine3d(m,b);
    }

// ----------------------------------------------------------------------------------------

    inline point_transform_affine3d translate_point (
        const vector<double,3>& delta
    )
    {
        return point_transform_affine3d(identity_matrix<double>(3),delta);
    }

    inline point_transform_affine3d translate_point (
        double x,
        double y,
        double z
    )
    {
        return translate_point(vector<double>(x,y,z));
    }

// ----------------------------------------------------------------------------------------

    class camera_transform
    {

    public:

        camera_transform  (
        )
        {
            *this = camera_transform(vector<double>(1,1,1),
                                     vector<double>(0,0,0),
                                     vector<double>(0,0,1),
                                     90,
                                     1);
        }

        camera_transform (
            const vector<double>& camera_pos_,
            const vector<double>& camera_looking_at_,
            const vector<double>& camera_up_direction_,
            const double camera_field_of_view_,
            const unsigned long num_pixels_
        )
        {
            // make sure requires clause is not broken
            DLIB_CASSERT(0 < camera_field_of_view_ && camera_field_of_view_ < 180,
                "\t camera_transform::camera_transform()"
                << "\n\t Invalid inputs were given to this function."
                << "\n\t camera_field_of_view_: " << camera_field_of_view_
                );

            camera_pos = camera_pos_;
            camera_looking_at = camera_looking_at_;
            camera_up_direction = camera_up_direction_;
            camera_field_of_view = camera_field_of_view_;
            num_pixels = num_pixels_;

            dlib::vector<double> X,Y,Z;
            Z = (camera_looking_at - camera_pos).normalize();
            Y = camera_up_direction - dot(camera_up_direction,Z)*Z;
            Y = Y.normalize();
            X = Z.cross(Y);

            set_rowm(proj,0) = trans(X);
            // Minus because images have y axis going down but we want the 3d projection to appear using a normal coordinate system with y going up.
            set_rowm(proj,1) = -trans(Y);
            set_rowm(proj,2) = trans(Z);

            width = num_pixels/2.0;
            dist_scale = width/std::tan(pi/180*camera_field_of_view/2);
        }

        vector<double> get_camera_pos()         const { return camera_pos; }
        vector<double> get_camera_looking_at()  const { return camera_looking_at; }
        vector<double> get_camera_up_direction()const { return camera_up_direction; }
        double get_camera_field_of_view()       const { return camera_field_of_view; }
        unsigned long get_num_pixels()                   const { return num_pixels; }

        inline dpoint operator() (
            const vector<double>& p,
            double& scale,
            double& distance
        ) const
        {
            vector<double> temp = p-camera_pos;
            temp = proj*temp;
            distance = temp.z();
            scale = dist_scale/(temp.z()>0 ? temp.z() : 1e-9);
            temp.x() = temp.x()*scale + width;
            temp.y() = temp.y()*scale + width;
            return temp;
        }

        dpoint operator() (
            const vector<double>& p
        ) const
        {
            double scale, distance;
            return (*this)(p,scale,distance);
        }

        inline friend void serialize (const camera_transform& item, std::ostream& out)
        {
            serialize(item.camera_pos, out);
            serialize(item.camera_looking_at, out);
            serialize(item.camera_up_direction, out);
            serialize(item.camera_field_of_view, out);
            serialize(item.num_pixels, out);
            serialize(item.proj, out);
            serialize(item.dist_scale, out);
            serialize(item.width, out);
        }

        inline friend void deserialize (camera_transform& item, std::istream& in)
        {
            deserialize(item.camera_pos, in);
            deserialize(item.camera_looking_at, in);
            deserialize(item.camera_up_direction, in);
            deserialize(item.camera_field_of_view, in);
            deserialize(item.num_pixels, in);
            deserialize(item.proj, in);
            deserialize(item.dist_scale, in);
            deserialize(item.width, in);
        }

    private:

        vector<double> camera_pos;
        vector<double> camera_looking_at;
        vector<double> camera_up_direction;
        double camera_field_of_view;
        unsigned long num_pixels;
        matrix<double,3,3> proj;
        double dist_scale;
        double width;

    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_POINT_TrANSFORMS_H_


dlib C++ Library - rectangle.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_RECTANGLe_
#define DLIB_RECTANGLe_

#include "rectangle_abstract.h"
#include "../algs.h"
#include <algorithm>
#include <iostream>
#include "../serialize.h"
#include "vector.h"
#include "../image_processing/generic_image.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class rectangle
    {
        /*!
            INITIAL VALUE
                The initial value of this object is defined by its constructor.

            CONVENTION
                left() == l
                top() == t
                right() == r
                bottom() == b
        !*/

    public:

        rectangle (
            long l_,
            long t_,
            long r_,
            long b_
        ) :
            l(l_),
            t(t_),
            r(r_),
            b(b_)
        {}

        rectangle (
            unsigned long w,
            unsigned long h
        ) :
            l(0),
            t(0),
            r(static_cast<long>(w)-1),
            b(static_cast<long>(h)-1)
        {
            DLIB_ASSERT((w > 0 && h > 0) || (w == 0 && h == 0),
                "\trectangle(width,height)"
                << "\n\twidth and height must be > 0 or both == 0"
                << "\n\twidth:  " << w
                << "\n\theight: " << h
                << "\n\tthis: " << this
                );
        }

        rectangle (
            const point& p
        ) :
            l(p.x()),
            t(p.y()),
            r(p.x()),
            b(p.y())
        {
        }

        rectangle (
            const point& p1,
            const point& p2
        )
        {
            *this = rectangle(p1) + rectangle(p2);
        }

        template <typename T>
        rectangle (
            const vector<T,2>& p1,
            const vector<T,2>& p2
        )
        {
            *this = rectangle(p1) + rectangle(p2);
        }

        rectangle (
        ) :
            l(0),
            t(0),
            r(-1),
            b(-1)
        {}

        long top (
        ) const { return t; }

        long& top (
        ) { return t; }

        void set_top (
            long top_
        ) { t = top_; }

        long left (
        ) const { return l; }

        long& left (
        ) { return l; }

        void set_left (
            long left_
        ) { l = left_; }

        long right (
        ) const { return r; }

        long& right (
        ) { return r; }

        void set_right (
            long right_
        ) { r = right_; }

        long bottom (
        ) const { return b; }

        long& bottom (
        ) { return b; }

        void set_bottom (
            long bottom_
        ) { b = bottom_; }

        const point tl_corner (
        ) const { return point(left(), top()); }

        const point bl_corner (
        ) const { return point(left(), bottom()); }

        const point tr_corner (
        ) const { return point(right(), top()); }

        const point br_corner (
        ) const { return point(right(), bottom()); }

        unsigned long width (
        ) const
        {
            if (is_empty())
                return 0;
            else
                return r - l + 1;
        }

        unsigned long height (
        ) const
        {
            if (is_empty())
                return 0;
            else
                return b - t + 1;
        }

        unsigned long area (
        ) const
        {
            return width()*height();
        }

        bool is_empty (
        ) const { return (t > b || l > r); }

        rectangle operator + (
            const rectangle& rhs
        ) const
        {
            if (rhs.is_empty())
                return *this;
            else if (is_empty())
                return rhs;

            return rectangle (
                std::min(l,rhs.l),
                std::min(t,rhs.t),
                std::max(r,rhs.r),
                std::max(b,rhs.b)
                );
        }

        rectangle intersect (
            const rectangle& rhs
        ) const
        {
            return rectangle (
                std::max(l,rhs.l),
                std::max(t,rhs.t),
                std::min(r,rhs.r),
                std::min(b,rhs.b)
                );
        }

        bool contains (
            const point& p
        ) const
        {
            if (p.x() < l || p.x() > r || p.y() < t || p.y() > b)
                return false;
            return true;
        }

        bool contains (
            long x,
            long y
        ) const
        {
            if (x < l || x > r || y < t || y > b)
                return false;
            return true;
        }

        bool contains (
            const rectangle& rect
        ) const
        {
            return (rect + *this == *this);
        }

        rectangle& operator+= (
            const point& p
        )
        {
            *this = *this + rectangle(p);
            return *this;
        }

        rectangle& operator+= (
            const rectangle& rect
        )
        {
            *this = *this + rect;
            return *this;
        }

        bool operator== (
            const rectangle& rect
        ) const
        {
            return (l == rect.l) && (t == rect.t) && (r == rect.r) && (b == rect.b);
        }

        bool operator!= (
            const rectangle& rect
        ) const
        {
            return !(*this == rect);
        }

    private:
        long l;
        long t;
        long r;
        long b;
    };

// ----------------------------------------------------------------------------------------

    inline void serialize (
        const rectangle& item,
        std::ostream& out
    )
    {
        try
        {
            serialize(item.left(),out);
            serialize(item.top(),out);
            serialize(item.right(),out);
            serialize(item.bottom(),out);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while serializing an object of type rectangle");
        }
    }

    inline void deserialize (
        rectangle& item,
        std::istream& in
    )
    {
        try
        {
            deserialize(item.left(),in);
            deserialize(item.top(),in);
            deserialize(item.right(),in);
            deserialize(item.bottom(),in);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while deserializing an object of type rectangle");
        }
    }

    inline std::ostream& operator<< (
        std::ostream& out,
        const rectangle& item
    )
    {
        out << "[(" << item.left() << ", " << item.top() << ") (" << item.right() << ", " << item.bottom() << ")]";
        return out;
    }

    inline std::istream& operator>>(
        std::istream& in,
        rectangle& item
    )
    {
        // ignore any whitespace
        while (in.peek() == ' ' || in.peek() == '\t' || in.peek() == '\r' || in.peek() == '\n')
            in.get();
        // now eat the leading '[' character
        if (in.get() != '[')
        {
            in.setstate(in.rdstate() | std::ios::failbit);
            return in;
        }

        point p1, p2;
        in >> p1;
        in >> p2;
        item = rectangle(p1) + rectangle(p2);

        // ignore any whitespace
        while (in.peek() == ' ' || in.peek() == '\t' || in.peek() == '\r' || in.peek() == '\n')
            in.get();
        // now eat the trailing ']' character
        if (in.get() != ']')
        {
            in.setstate(in.rdstate() | std::ios::failbit);
        }
        return in;
    }

// ----------------------------------------------------------------------------------------

    inline const rectangle centered_rect (
        long x,
        long y,
        unsigned long width,
        unsigned long height
    )
    {
        rectangle result;
        result.set_left ( x - static_cast<long>(width) / 2 );
        result.set_top ( y - static_cast<long>(height) / 2 );
        result.set_right ( result.left() + width - 1 );
        result.set_bottom ( result.top() + height - 1 );
        return result;
    }

// ----------------------------------------------------------------------------------------

    inline rectangle intersect (
        const rectangle& a,
        const rectangle& b
    ) { return a.intersect(b); }

// ----------------------------------------------------------------------------------------

    inline unsigned long area (
        const rectangle& a
    ) { return a.area(); }

// ----------------------------------------------------------------------------------------

    inline point center (
        const dlib::rectangle& rect
    )
    {
        point temp(rect.left() + rect.right() + 1,
                   rect.top() + rect.bottom() + 1);

        if (temp.x() < 0)
            temp.x() -= 1;

        if (temp.y() < 0)
            temp.y() -= 1;

        return temp/2;
    }

// ----------------------------------------------------------------------------------------

    inline dlib::vector<double,2> dcenter (
        const dlib::rectangle& rect
    )
    {
        dlib::vector<double,2> temp(rect.left() + rect.right(),
                                    rect.top() + rect.bottom());

        return temp/2.0;
    }

// ----------------------------------------------------------------------------------------

    inline long distance_to_rect_edge (
        const rectangle& rect,
        const point& p
    )
    {
        using std::max;
        using std::min;
        using std::abs;

        const long dist_x = min(abs(p.x()-rect.left()), abs(p.x()-rect.right()));
        const long dist_y = min(abs(p.y()-rect.top()),  abs(p.y()-rect.bottom()));

        if (rect.contains(p))
            return min(dist_x,dist_y);
        else if (rect.left() <= p.x() && p.x() <= rect.right())
            return dist_y;
        else if (rect.top() <= p.y() && p.y() <= rect.bottom())
            return dist_x;
        else
            return dist_x + dist_y;
    }

// ----------------------------------------------------------------------------------------

    inline const point nearest_point (
        const rectangle& rect,
        const point& p
    )
    {
        point temp(p);
        if (temp.x() < rect.left())
            temp.x() = rect.left();
        else if (temp.x() > rect.right())
            temp.x() = rect.right();

        if (temp.y() < rect.top())
            temp.y() = rect.top();
        else if (temp.y() > rect.bottom())
            temp.y() = rect.bottom();

        return temp;
    }

// ----------------------------------------------------------------------------------------

    template <typename T, typename U>
    double distance_to_line (
        const std::pair<vector<T,2>,vector<T,2> >& line,
        const vector<U,2>& p
    )
    {
        const vector<double,2> delta = p-line.second;
        const double along_dist = (line.first-line.second).normalize().dot(delta);
        return std::sqrt(std::max(0.0,delta.length_squared() - along_dist*along_dist));
    }

// ----------------------------------------------------------------------------------------

    inline void clip_line_to_rectangle (
        const rectangle& box,
        point& p1,
        point& p2
    )
    {
        // Now clip the line segment so it is contained inside box.
        if (p1.x() == p2.x())
        {
            if (!box.contains(p1))
                p1.y() = box.top();
            if (!box.contains(p2))
                p2.y() = box.bottom();
        }
        else if (p1.y() == p2.y())
        {
            if (!box.contains(p1))
                p1.x() = box.left();
            if (!box.contains(p2))
                p2.x() = box.right();
        }
        else
        {
            // We use these relations to find alpha values.  These values tell us
            // how to generate points intersecting the rectangle boundaries.  We then
            // test the resulting points for ones that are inside the rectangle and output
            // those.
            //box.left()  == alpha1*(p1.x()-p2.x()) + p2.x();
            //box.right() == alpha2*(p1.x()-p2.x()) + p2.x();

            const point d = p1-p2;
            double alpha1 = (box.left()  -p2.x())/(double)d.x();
            double alpha2 = (box.right() -p2.x())/(double)d.x();
            double alpha3 = (box.top()   -p2.y())/(double)d.y();
            double alpha4 = (box.bottom()-p2.y())/(double)d.y();

            const point c1 = alpha1*d + p2;
            const point c2 = alpha2*d + p2;
            const point c3 = alpha3*d + p2;
            const point c4 = alpha4*d + p2;

            if (!box.contains(p1))
                p1 = c1;
            if (!box.contains(p2))
                p2 = c2;
            if (box.contains(c3))
            {
                if (!box.contains(p2))
                    p2 = c3;
                else if (!box.contains(p1))
                    p1 = c3;
            }
            if (box.contains(c4))
            {
                if (!box.contains(p2))
                    p2 = c4;
                else if (!box.contains(p1))
                    p1 = c4;
            }
        }

        p1 = nearest_point(box, p1);
        p2 = nearest_point(box, p2);
    }

// ----------------------------------------------------------------------------------------

    inline const rectangle centered_rect (
        const point& p,
        unsigned long width,
        unsigned long height
    )
    {
        return centered_rect(p.x(),p.y(),width,height);
    }

// ----------------------------------------------------------------------------------------

    inline const rectangle centered_rect (
        const rectangle& rect,
        unsigned long width,
        unsigned long height
    )
    {
        return centered_rect((rect.left()+rect.right())/2,  (rect.top()+rect.bottom())/2, width, height);
    }

// ----------------------------------------------------------------------------------------

    inline const rectangle shrink_rect (
        const rectangle& rect,
        long num
    )
    {
        return rectangle(rect.left()+num, rect.top()+num, rect.right()-num, rect.bottom()-num);
    }

// ----------------------------------------------------------------------------------------

    inline const rectangle grow_rect (
        const rectangle& rect,
        long num
    )
    {
        return shrink_rect(rect, -num);
    }

// ----------------------------------------------------------------------------------------

    inline const rectangle shrink_rect (
        const rectangle& rect,
        long width,
        long height
    )
    {
        return rectangle(rect.left()+width, rect.top()+height, rect.right()-width, rect.bottom()-height);
    }

// ----------------------------------------------------------------------------------------

    inline const rectangle grow_rect (
        const rectangle& rect,
        long width,
        long height
    )
    {
        return shrink_rect(rect, -width, -height);
    }

// ----------------------------------------------------------------------------------------

    inline const rectangle translate_rect (
        const rectangle& rect,
        const point& p
    )
    {
        rectangle result;
        result.set_top ( rect.top() + p.y() );
        result.set_bottom ( rect.bottom() + p.y() );
        result.set_left ( rect.left() + p.x() );
        result.set_right ( rect.right() + p.x() );
        return result;
    }

// ----------------------------------------------------------------------------------------

    inline const rectangle translate_rect (
        const rectangle& rect,
        long x,
        long y
    )
    {
        rectangle result;
        result.set_top ( rect.top() + y );
        result.set_bottom ( rect.bottom() + y );
        result.set_left ( rect.left() + x );
        result.set_right ( rect.right() + x );
        return result;
    }

// ----------------------------------------------------------------------------------------

    inline const rectangle resize_rect (
        const rectangle& rect,
        unsigned long width,
        unsigned long height
    )
    {
        return rectangle(rect.left(),rect.top(),
                         rect.left()+width-1,
                         rect.top()+height-1);
    }

// ----------------------------------------------------------------------------------------

    inline const rectangle resize_rect_width (
        const rectangle& rect,
        unsigned long width
    )
    {
        return rectangle(rect.left(),rect.top(),
                         rect.left()+width-1,
                         rect.bottom());
    }

// ----------------------------------------------------------------------------------------

    inline const rectangle resize_rect_height (
        const rectangle& rect,
        unsigned long height
    )
    {
        return rectangle(rect.left(),rect.top(),
                         rect.right(),
                         rect.top()+height-1);
    }

// ----------------------------------------------------------------------------------------

    inline const rectangle move_rect (
        const rectangle& rect,
        const point& p
    )
    {
        return rectangle(p.x(), p.y(), p.x()+rect.width()-1, p.y()+rect.height()-1);
    }

// ----------------------------------------------------------------------------------------

    inline const rectangle move_rect (
        const rectangle& rect,
        long x,
        long y
    )
    {
        return rectangle(x, y, x+rect.width()-1, y+rect.height()-1);
    }

// ----------------------------------------------------------------------------------------

    inline rectangle set_aspect_ratio (
        const rectangle& rect,
        double ratio
    )
    {
        DLIB_ASSERT(ratio > 0,
            "\t rectangle set_aspect_ratio()"
            << "\n\t ratio: " << ratio
            );

        // aspect ratio is w/h

        // we need to find the rectangle that is nearest to rect in area but
        // with an aspect ratio of ratio.

        // w/h == ratio
        // w*h == rect.area()

        if (ratio >= 1)
        {
            const long h = static_cast<long>(std::sqrt(rect.area()/ratio) + 0.5);
            const long w = static_cast<long>(h*ratio + 0.5);
            return centered_rect(rect, w, h);
        }
        else
        {
            const long w = static_cast<long>(std::sqrt(rect.area()*ratio) + 0.5);
            const long h = static_cast<long>(w/ratio + 0.5);
            return centered_rect(rect, w, h);
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    inline const rectangle get_rect (
        const T& m
    )
    {
        return rectangle(0, 0, num_columns(m)-1, num_rows(m)-1);
    }

// ----------------------------------------------------------------------------------------

    inline rectangle operator+ (
        const rectangle& r,
        const point& p
    )
    {
        return r + rectangle(p);
    }

// ----------------------------------------------------------------------------------------

    inline rectangle operator+ (
        const point& p,
        const rectangle& r
    )
    {
        return r + rectangle(p);
    }

// ----------------------------------------------------------------------------------------

}

namespace std
{
    /*!
        Define std::less<rectangle> so that you can use rectangles in the associative containers.
    !*/
    template<>
    struct less<dlib::rectangle> : public binary_function<dlib::rectangle ,dlib::rectangle,bool>
    {
        inline bool operator() (const dlib::rectangle& a, const dlib::rectangle& b) const
        {
            if      (a.left() < b.left()) return true;
            else if (a.left() > b.left()) return false;
            else if (a.top() < b.top()) return true;
            else if (a.top() > b.top()) return false;
            else if (a.right() < b.right()) return true;
            else if (a.right() > b.right()) return false;
            else if (a.bottom() < b.bottom()) return true;
            else if (a.bottom() > b.bottom()) return false;
            else                    return false;
        }
    };
}

#endif // DLIB_RECTANGLe_


dlib C++ Library - vector.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_VECTOr_H_
#define DLIB_VECTOr_H_

#include <cmath>
#include "vector_abstract.h"
#include "../algs.h"
#include "../serialize.h"
#include <functional>
#include <iostream>
#include "../matrix/matrix.h"
#include <limits>

#if defined(_MSC_VER) && _MSC_VER < 1400
// Despite my efforts to disabuse visual studio of its usual nonsense I can't find a
// way to make this warning go away without just disabling it.   This is the warning:
//   dlib\geometry\vector.h(129) : warning C4805: '==' : unsafe mix of type 'std::numeric_limits<_Ty>::is_integer' and type 'bool' in operation
//
#pragma warning(disable:4805)
#endif

namespace dlib
{

    template <
        typename T,
        long NR = 3
        >
    class vector;

// ----------------------------------------------------------------------------------------

    template <typename T, typename U, typename enabled = void>
    struct vect_promote;

    template <typename T, typename U, bool res = (sizeof(T) <= sizeof(U))>
    struct largest_type
    {
        typedef T type;
    };
    template <typename T, typename U>
    struct largest_type<T,U,true>
    {
        typedef U type;
    };

    template <typename T, typename U>
    struct vect_promote<T,U, typename enable_if_c<std::numeric_limits<T>::is_integer == std::numeric_limits<U>::is_integer>::type>
    {
        // If both T and U are both either integral or non-integral then just
        // use the biggest one
        typedef typename largest_type<T,U>::type type;
    };

    template <typename T, typename U>
    struct vect_promote<T,U, typename enable_if_c<std::numeric_limits<T>::is_integer != std::numeric_limits<U>::is_integer>::type>
    {
        typedef double type;
    };

// ----------------------------------------------------------------------------------------

    // This insanity here is to work around a bug in visual studio 8.   These two rebind
    // structures are actually declared at a few points in this file because just having the
    // one declaration here isn't enough for visual studio.  It takes the three spread around
    // to avoid all its bugs.
    template <typename T, long N>
    struct vc_rebind
    {
        typedef vector<T,N> type;
    };
    template <typename T, typename U, long N>
    struct vc_rebind_promote
    {
        typedef vector<typename vect_promote<T,U>::type,N> type;
    };

// ----------------------------------------------------------------------------------------

    template <typename T, typename U, typename enabled = void>
    struct vector_assign_helper
    {
        template <long NR>
        static void assign (
            vector<T,2>& dest,
            const vector<U,NR>& src
        )
        {
            dest.x() = static_cast<T>(src.x());
            dest.y() = static_cast<T>(src.y());
        }

        template <long NR>
        static void assign (
            vector<T,3>& dest,
            const vector<U,NR>& src
        )
        {
            dest.x() = static_cast<T>(src.x());
            dest.y() = static_cast<T>(src.y());
            dest.z() = static_cast<T>(src.z());
        }

        template <typename EXP>
        static void assign (
            vector<T,2>& dest,
            const matrix_exp<EXP>& m
        )
        {
            T x = static_cast<T>(m(0));
            T y = static_cast<T>(m(1));
            dest.x() = x;
            dest.y() = y;
        }

        template <typename EXP>
        static void assign (
            vector<T,3>& dest,
            const matrix_exp<EXP>& m
        )
        {
            T x = static_cast<T>(m(0));
            T y = static_cast<T>(m(1));
            T z = static_cast<T>(m(2));

            dest.x() = x;
            dest.y() = y;
            dest.z() = z;
        }
    };

    // This is an overload for the case where you are converting from a floating point
    // type to an integral type.  These overloads make sure values are rounded to
    // the nearest integral value.
    template <typename T, typename U>
    struct vector_assign_helper<T,U, typename enable_if_c<std::numeric_limits<T>::is_integer == true &&
                                                          std::numeric_limits<U>::is_integer == false>::type>
    {
        template <long NR>
        static void assign (
            vector<T,2>& dest,
            const vector<U,NR>& src
        )
        {
            dest.x() = static_cast<T>(std::floor(src.x() + 0.5));
            dest.y() = static_cast<T>(std::floor(src.y() + 0.5));
        }

        template <long NR>
        static void assign (
            vector<T,3>& dest,
            const vector<U,NR>& src
        )
        {
            dest.x() = static_cast<T>(std::floor(src.x() + 0.5));
            dest.y() = static_cast<T>(std::floor(src.y() + 0.5));
            dest.z() = static_cast<T>(std::floor(src.z() + 0.5));
        }

        template <typename EXP>
        static void assign (
            vector<T,3>& dest,
            const matrix_exp<EXP>& m
        )
        {
            dest.x() = static_cast<T>(std::floor(m(0) + 0.5));
            dest.y() = static_cast<T>(std::floor(m(1) + 0.5));
            dest.z() = static_cast<T>(std::floor(m(2) + 0.5));
        }

        template <typename EXP>
        static void assign (
            vector<T,2>& dest,
            const matrix_exp<EXP>& m
        )
        {
            dest.x() = static_cast<T>(std::floor(m(0) + 0.5));
            dest.y() = static_cast<T>(std::floor(m(1) + 0.5));
        }

    };

// ----------------------------------------------------------------------------------------

    template <typename T>
    class vector<T,3> : public matrix<T,3,1>
    {
        /*!
            INITIAL VALUE
                - x() == 0
                - y() == 0
                - z() == 0

            CONVENTION
                - (*this)(0) == x()
                - (*this)(1) == y()
                - (*this)(2) == z()

        !*/

        // This insanity here is to work around a bug in visual studio 8.
        template <typename V, long N>
        struct vc_rebind
        {
            typedef vector<V,N> type;
        };
            template <typename V, typename U, long N>
        struct vc_rebind_promote
        {
            typedef vector<typename vect_promote<V,U>::type,N> type;
        };

    public:

        typedef T type;

        vector (
        )
        {
            x() = 0;
            y() = 0;
            z() = 0;
        }

        // ---------------------------------------

        vector (
            const T _x,
            const T _y,
            const T _z
        )
        {
            x() = _x;
            y() = _y;
            z() = _z;
        }

        // ---------------------------------------

        vector (
            const vector& item
        ) : matrix<T,3,1>(item)
        {
        }

        // ---------------------------------------

        template <typename U>
        vector (
            const vector<U,2>& item
        )
        {
            // Do this so that we get the appropriate rounding depending on the relative
            // type of T and U.
            vector<T,2> temp(item);
            x() = temp.x();
            y() = temp.y();
            z() = 0;
        }

        // ---------------------------------------

        vector (
            const vector<T,2>& item
        )
        {
            x() = item.x();
            y() = item.y();
            z() = 0;
        }

        // ---------------------------------------

        template <typename U>
        vector (
            const vector<U,3>& item
        )
        {
            (*this) = item;
        }

        // ---------------------------------------

        template <typename EXP>
        vector ( const matrix_exp<EXP>& m)
        {
            (*this) = m;
        }

        // ---------------------------------------

        template <typename EXP>
        vector& operator = (
            const matrix_exp<EXP>& m
        )
        {
            // you can only assign vectors with 3 elements to a dlib::vector<T,3> object
            COMPILE_TIME_ASSERT(EXP::NR*EXP::NC == 3 || EXP::NR*EXP::NC == 0);

            // make sure requires clause is not broken
            DLIB_ASSERT((m.nr() == 1 || m.nc() == 1) && (m.size() == 3),
                "\t vector(const matrix_exp& m)"
                << "\n\t the given matrix is of the wrong size"
                << "\n\t m.nr():   " << m.nr()
                << "\n\t m.nc():   " << m.nc()
                << "\n\t m.size(): " << m.size()
                << "\n\t this: " << this
                );

            vector_assign_helper<T, typename EXP::type>::assign(*this, m);
            return *this;
        }

        // ---------------------------------------

        template <typename U, long N>
        vector& operator = (
            const vector<U,N>& item
        )
        {
            vector_assign_helper<T,U>::assign(*this, item);
            return *this;
        }

        // ---------------------------------------

        vector& operator= (
            const vector& item
        )
        {
            x() = item.x();
            y() = item.y();
            z() = item.z();
            return *this;
        }

        // ---------------------------------------

        double length(
        ) const
        {
            return std::sqrt((double)(x()*x() + y()*y() + z()*z()));
        }

        // ---------------------------------------

        double length_squared(
        ) const
        {
            return (double)(x()*x() + y()*y() + z()*z());
        }

        // ---------------------------------------

        typename vc_rebind<double,3>::type normalize (
        ) const
        {
            const double tmp = std::sqrt((double)(x()*x() + y()*y() + z()*z()));
            return vector<double,3> ( x()/tmp,
                                      y()/tmp,
                                      z()/tmp
            );
        }

        // ---------------------------------------

        T& x (
        )
        {
            return (*this)(0);
        }

        // ---------------------------------------

        T& y (
        )
        {
            return (*this)(1);
        }

        // ---------------------------------------

        T& z (
        )
        {
            return (*this)(2);
        }

        // ---------------------------------------

        const T& x (
        ) const
        {
            return (*this)(0);
        }

        // ---------------------------------------

        const T& y (
        ) const
        {
            return (*this)(1);
        }

        // ---------------------------------------

        const T& z (
        ) const
        {
            return (*this)(2);
        }

        // ---------------------------------------

        T dot (
            const vector& rhs
        ) const
        {
            return x()*rhs.x() + y()*rhs.y() + z()*rhs.z();
        }

        // ---------------------------------------

        template <typename U, long N>
        typename vect_promote<T,U>::type dot (
            const vector<U,N>& rhs
        ) const
        {
            return x()*rhs.x() + y()*rhs.y() + z()*rhs.z();
        }

        // ---------------------------------------

        template <typename U, long N>
        typename vc_rebind_promote<T,U,3>::type cross (
            const vector<U,N>& rhs
        ) const
        {
            typedef vector<typename vect_promote<T,U>::type,3> ret_type;

            return ret_type (
                y()*rhs.z() - z()*rhs.y(),
                z()*rhs.x() - x()*rhs.z(),
                x()*rhs.y() - y()*rhs.x()
                );
        }

        // ---------------------------------------

        vector& operator += (
            const vector& rhs
        )
        {
            x() += rhs.x();
            y() += rhs.y();
            z() += rhs.z();
            return *this;
        }

        // ---------------------------------------

        vector& operator -= (
            const vector& rhs
        )
        {
            x() -= rhs.x();
            y() -= rhs.y();
            z() -= rhs.z();
            return *this;
        }

        // ---------------------------------------

        vector& operator /= (
            const T& rhs
        )
        {
            x() /= rhs;
            y() /= rhs;
            z() /= rhs;
            return *this;
        }

        // ---------------------------------------

        vector& operator *= (
            const T& rhs
        )
        {
            x() *= rhs;
            y() *= rhs;
            z() *= rhs;
            return *this;
        }

        // ---------------------------------------

        vector operator - (
        ) const
        {
            return vector(-x(), -y(), -z());
        }

        // ---------------------------------------

        template <typename U>
        typename vc_rebind_promote<T,U,3>::type operator / (
            const U& val
        ) const
        {
            typedef vector<typename vect_promote<T,U>::type,3> ret_type;
            return ret_type(x()/val, y()/val, z()/val);
        }

        // ---------------------------------------

        template <typename U, long NR2>
        bool operator== (
            const vector<U,NR2>& rhs
        ) const
        {
            return x()==rhs.x() && y()==rhs.y() && z()==rhs.z();
        }

        // ---------------------------------------

        template <typename U, long NR2>
        bool operator!= (
            const vector<U,NR2>& rhs
        ) const
        {
            return !(*this == rhs);
        }

        // ---------------------------------------

        void swap (
            vector& item
        )
        {
            dlib::exchange(x(), item.x());
            dlib::exchange(y(), item.y());
            dlib::exchange(z(), item.z());
        }

        // ---------------------------------------

    };

// ----------------------------------------------------------------------------------------

    template <typename T>
    class vector<T,2> : public matrix<T,2,1>
    {
        /*!
            INITIAL VALUE
                - x() == 0
                - y() == 0

            CONVENTION
                - (*this)(0) == x()
                - (*this)(1) == y()
                - z() == 0
        !*/

        // This insanity here is to work around a bug in visual studio 8.
        template <typename V, long N>
        struct vc_rebind
        {
            typedef vector<V,N> type;
        };
            template <typename V, typename U, long N>
        struct vc_rebind_promote
        {
            typedef vector<typename vect_promote<V,U>::type,N> type;
        };

    public:

        typedef T type;

        vector (
        )
        {
            x() = 0;
            y() = 0;
        }

        // ---------------------------------------

        vector (
            const T _x,
            const T _y
        )
        {
            x() = _x;
            y() = _y;
        }

        // ---------------------------------------

        template <typename U>
        vector (
            const vector<U,3>& item
        )
        {
            // Do this so that we get the appropriate rounding depending on the relative
            // type of T and U.
            vector<T,3> temp(item);
            x() = temp.x();
            y() = temp.y();
        }

        // ---------------------------------------

        vector (
            const vector& item
        ) : matrix<T,2,1>(item)
        {
        }

        // ---------------------------------------

        vector (
            const vector<T,3>& item
        )
        {
            x() = item.x();
            y() = item.y();
        }

        // ---------------------------------------

        template <typename U>
        vector (
            const vector<U,2>& item
        )
        {
            (*this) = item;
        }

        // ---------------------------------------

        template <typename EXP>
        vector ( const matrix_exp<EXP>& m)
        {
            (*this) = m;
        }

        // ---------------------------------------

        template <typename EXP>
        vector& operator = (
            const matrix_exp<EXP>& m
        )
        {
            // you can only assign vectors with 2 elements to a dlib::vector<T,2> object
            COMPILE_TIME_ASSERT(EXP::NR*EXP::NC == 2 || EXP::NR*EXP::NC == 0);

            // make sure requires clause is not broken
            DLIB_ASSERT((m.nr() == 1 || m.nc() == 1) && (m.size() == 2),
                "\t vector(const matrix_exp& m)"
                << "\n\t the given matrix is of the wrong size"
                << "\n\t m.nr():   " << m.nr()
                << "\n\t m.nc():   " << m.nc()
                << "\n\t m.size(): " << m.size()
                << "\n\t this: " << this
                );

            vector_assign_helper<T, typename EXP::type>::assign(*this, m);
            return *this;
        }

        // ---------------------------------------

        template <typename U, long N>
        vector& operator = (
            const vector<U,N>& item
        )
        {
            vector_assign_helper<T,U>::assign(*this, item);
            return *this;
        }

        // ---------------------------------------

        vector& operator= (
            const vector& item
        )
        {
            x() = item.x();
            y() = item.y();
            return *this;
        }

        // ---------------------------------------

        double length(
        ) const
        {
            return std::sqrt((double)(x()*x() + y()*y()));
        }

        // ---------------------------------------

        double length_squared(
        ) const
        {
            return (double)(x()*x() + y()*y());
        }

        // ---------------------------------------

        typename vc_rebind<double,2>::type normalize (
        ) const
        {
            const double tmp = std::sqrt((double)(x()*x() + y()*y()));
            return vector<double,2> ( x()/tmp,
                         y()/tmp
            );
        }

        // ---------------------------------------

        T& x (
        )
        {
            return (*this)(0);
        }

        // ---------------------------------------

        T& y (
        )
        {
            return (*this)(1);
        }

        // ---------------------------------------

        const T& x (
        ) const
        {
            return (*this)(0);
        }

        // ---------------------------------------

        const T& y (
        ) const
        {
            return (*this)(1);
        }

        // ---------------------------------------

        const T z (
        ) const
        {
            return 0;
        }

        // ---------------------------------------

        T dot (
            const vector& rhs
        ) const
        {
            return x()*rhs.x() + y()*rhs.y();
        }

        // ---------------------------------------

        template <typename U, long N>
        typename vect_promote<T,U>::type dot (
            const vector<U,N>& rhs
        ) const
        {
            return x()*rhs.x() + y()*rhs.y() + z()*rhs.z();
        }

        // ---------------------------------------

        vector& operator += (
            const vector& rhs
        )
        {
            x() += rhs.x();
            y() += rhs.y();
            return *this;
        }

        // ---------------------------------------

        vector& operator -= (
            const vector& rhs
        )
        {
            x() -= rhs.x();
            y() -= rhs.y();
            return *this;
        }

        // ---------------------------------------

        vector& operator /= (
            const T& rhs
        )
        {
            x() /= rhs;
            y() /= rhs;
            return *this;
        }

        // ---------------------------------------

        vector& operator *= (
            const T& rhs
        )
        {
            x() *= rhs;
            y() *= rhs;
            return *this;
        }

        // ---------------------------------------

        vector operator - (
        ) const
        {
            return vector(-x(), -y());
        }

        // ---------------------------------------

        template <typename U>
        typename vc_rebind_promote<T,U,2>::type operator / (
            const U& val
        ) const
        {
            typedef vector<typename vect_promote<T,U>::type,2> ret_type;
            return ret_type(x()/val, y()/val);
        }

        // ---------------------------------------

        template <typename U, long NR2>
        bool operator== (
            const vector<U,NR2>& rhs
        ) const
        {
            return x()==rhs.x() && y()==rhs.y() && z()==rhs.z();
        }

        // ---------------------------------------

        bool operator== (
            const vector& rhs
        ) const
        {
            return x()==rhs.x() && y()==rhs.y();
        }

        // ---------------------------------------

        template <typename U, long NR2>
        bool operator!= (
            const vector<U,NR2>& rhs
        ) const
        {
            return !(*this == rhs);
        }

        // ---------------------------------------

        bool operator!= (
            const vector& rhs
        ) const
        {
            return !(*this == rhs);
        }

        // ---------------------------------------

        void swap (
            vector& item
        )
        {
            dlib::exchange(x(), item.x());
            dlib::exchange(y(), item.y());
        }

        // ---------------------------------------

        template <typename U, long N>
        typename vc_rebind_promote<T,U,3>::type cross (
            const vector<U,N>& rhs
        ) const
        {
            typedef vector<typename vect_promote<T,U>::type,3> ret_type;
            return ret_type (
                y()*rhs.z(),
                - x()*rhs.z(),
                x()*rhs.y() - y()*rhs.x()
                );
        }

        // ---------------------------------------

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <typename T, typename U>
    inline const typename vc_rebind_promote<T,U,2>::type operator+ (
        const vector<T,2>& lhs,
        const vector<U,2>& rhs
    )
    {
        typedef typename vc_rebind_promote<T,U,2>::type ret_type;
        return ret_type(lhs.x()+rhs.x(), lhs.y()+rhs.y());
    }

// ----------------------------------------------------------------------------------------

    template <typename T, typename U>
    inline const typename vc_rebind_promote<T,U,3>::type operator+ (
        const vector<T,3>& lhs,
        const vector<U,3>& rhs
    )
    {
        typedef typename vc_rebind_promote<T,U,3>::type ret_type;
        return ret_type(lhs.x()+rhs.x(), lhs.y()+rhs.y(), lhs.z()+rhs.z());
    }

// ----------------------------------------------------------------------------------------

    template <typename T, typename U>
    inline const typename vc_rebind_promote<T,U,3>::type operator+ (
        const vector<T,2>& lhs,
        const vector<U,3>& rhs
    )
    {
        typedef typename vc_rebind_promote<T,U,3>::type ret_type;
        return ret_type(lhs.x()+rhs.x(), lhs.y()+rhs.y(), rhs.z());
    }

// ----------------------------------------------------------------------------------------

    template <typename T, typename U>
    inline const typename vc_rebind_promote<T,U,3>::type operator+ (
        const vector<T,3>& lhs,
        const vector<U,2>& rhs
    )
    {
        typedef typename vc_rebind_promote<T,U,3>::type ret_type;
        return ret_type(lhs.x()+rhs.x(), lhs.y()+rhs.y(), lhs.z());
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <typename T, typename U>
    inline const typename vc_rebind_promote<T,U,2>::type operator- (
        const vector<T,2>& lhs,
        const vector<U,2>& rhs
    )
    {
        typedef typename vc_rebind_promote<T,U,2>::type ret_type;
        return ret_type(lhs.x()-rhs.x(), lhs.y()-rhs.y());
    }

// ----------------------------------------------------------------------------------------

    template <typename T, typename U>
    inline const typename vc_rebind_promote<T,U,3>::type operator- (
        const vector<T,3>& lhs,
        const vector<U,3>& rhs
    )
    {
        typedef typename vc_rebind_promote<T,U,3>::type ret_type;
        return ret_type(lhs.x()-rhs.x(), lhs.y()-rhs.y(), lhs.z()-rhs.z());
    }

// ----------------------------------------------------------------------------------------

    template <typename T, typename U>
    inline const typename vc_rebind_promote<T,U,3>::type operator- (
        const vector<T,2>& lhs,
        const vector<U,3>& rhs
    )
    {
        typedef typename vc_rebind_promote<T,U,3>::type ret_type;
        return ret_type(lhs.x()-rhs.x(), lhs.y()-rhs.y(), -rhs.z());
    }

// ----------------------------------------------------------------------------------------

    template <typename T, typename U>
    inline const typename vc_rebind_promote<T,U,3>::type operator- (
        const vector<T,3>& lhs,
        const vector<U,2>& rhs
    )
    {
        typedef typename vc_rebind_promote<T,U,3>::type ret_type;
        return ret_type(lhs.x()-rhs.x(), lhs.y()-rhs.y(), lhs.z());
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <typename T, typename U>
    inline typename disable_if<is_matrix<U>, const typename vc_rebind_promote<T,U,2>::type >::type operator* (
        const vector<T,2>& v,
        const U& s
    )
    {
        typedef typename vc_rebind_promote<T,U,2>::type ret_type;
        return ret_type(v.x()*s, v.y()*s);
    }

// ----------------------------------------------------------------------------------------

    template <typename T, typename U>
    inline typename disable_if<is_matrix<U>, const typename vc_rebind_promote<T,U,2>::type >::type operator* (
        const U& s,
        const vector<T,2>& v
    )
    {
        typedef typename vc_rebind_promote<T,U,2>::type ret_type;
        return ret_type(v.x()*s, v.y()*s);
    }

// ----------------------------------------------------------------------------------------

    template <typename T, typename U>
    inline typename disable_if<is_matrix<U>, const typename vc_rebind_promote<T,U,3>::type >::type operator* (
        const vector<T,3>& v,
        const U& s
    )
    {
        typedef typename vc_rebind_promote<T,U,3>::type ret_type;
        return ret_type(v.x()*s, v.y()*s, v.z()*s);
    }

// ----------------------------------------------------------------------------------------

    template <typename T, typename U>
    inline typename disable_if<is_matrix<U>, const typename vc_rebind_promote<T,U,3>::type >::type operator* (
        const U& s,
        const vector<T,3>& v
    )
    {
        typedef typename vc_rebind_promote<T,U,3>::type ret_type;
        return ret_type(v.x()*s, v.y()*s, v.z()*s);
    }

// ----------------------------------------------------------------------------------------

    template<typename T, long NR>
    inline void swap (
        vector<T,NR> & a,
        vector<T,NR> & b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------

    template<typename T>
    inline void serialize (
        const vector<T,3>& item,
        std::ostream& out
    )
    {
        try
        {
            serialize(item.x(),out);
            serialize(item.y(),out);
            serialize(item.z(),out);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while serializing object of type vector");
        }
    }

    template<typename T>
    inline void deserialize (
        vector<T,3>& item,
        std::istream& in
    )
    {
        try
        {
            deserialize(item.x(),in);
            deserialize(item.y(),in);
            deserialize(item.z(),in);
        }
        catch (serialization_error& e)
        {
            item.x() = 0;
            item.y() = 0;
            item.z() = 0;
            throw serialization_error(e.info + "\n   while deserializing object of type vector");
        }
    }

// ----------------------------------------------------------------------------------------

    template<typename T>
    inline void serialize (
        const vector<T,2>& item,
        std::ostream& out
    )
    {
        try
        {
            serialize(item.x(),out);
            serialize(item.y(),out);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while serializing object of type vector");
        }
    }

    template<typename T>
    inline void deserialize (
        vector<T,2>& item,
        std::istream& in
    )
    {
        try
        {
            deserialize(item.x(),in);
            deserialize(item.y(),in);
        }
        catch (serialization_error& e)
        {
            item.x() = 0;
            item.y() = 0;
            throw serialization_error(e.info + "\n   while deserializing object of type vector");
        }
    }

// ----------------------------------------------------------------------------------------

    template<typename T>
    std::ostream& operator<< (
        std::ostream& out,
        const vector<T,3>& item
    )
    {
        out << "(" << item.x() << ", " << item.y() << ", " << item.z() << ")";
        return out;
    }

    template<typename T>
    std::istream& operator>>(
        std::istream& in,
        vector<T,3>& item
    )
    {

        // eat all the crap up to the '('
        while (in.peek() == ' ' || in.peek() == '\t' || in.peek() == '\r' || in.peek() == '\n')
            in.get();

        // there should be a '(' if not then this is an error
        if (in.get() != '(')
        {
            in.setstate(in.rdstate() | std::ios::failbit);
            return in;
        }

        // eat all the crap up to the first number
        while (in.peek() == ' ' || in.peek() == '\t')
            in.get();
        in >> item.x();

        if (!in.good())
            return in;

        // eat all the crap up to the next number
        while (in.peek() == ' ' || in.peek() == '\t' || in.peek() == ',')
            in.get();
        in >> item.y();

        if (!in.good())
            return in;

        // eat all the crap up to the next number
        while (in.peek() == ' ' || in.peek() == '\t' || in.peek() == ',')
            in.get();
        in >> item.z();

        if (!in.good())
            return in;

        // eat all the crap up to the ')'
        while (in.peek() == ' ' || in.peek() == '\t')
            in.get();

        // there should be a ')' if not then this is an error
        if (in.get() != ')')
            in.setstate(in.rdstate() | std::ios::failbit);
        return in;
    }

// ----------------------------------------------------------------------------------------

    template<typename T>
    std::ostream& operator<< (
        std::ostream& out,
        const vector<T,2>& item
    )
    {
        out << "(" << item.x() << ", " << item.y() << ")";
        return out;
    }

    template<typename T>
    std::istream& operator>>(
        std::istream& in,
        vector<T,2>& item
    )
    {

        // eat all the crap up to the '('
        while (in.peek() == ' ' || in.peek() == '\t' || in.peek() == '\r' || in.peek() == '\n')
            in.get();

        // there should be a '(' if not then this is an error
        if (in.get() != '(')
        {
            in.setstate(in.rdstate() | std::ios::failbit);
            return in;
        }

        // eat all the crap up to the first number
        while (in.peek() == ' ' || in.peek() == '\t')
            in.get();
        in >> item.x();

        if (!in.good())
            return in;

        // eat all the crap up to the next number
        while (in.peek() == ' ' || in.peek() == '\t' || in.peek() == ',')
            in.get();
        in >> item.y();

        if (!in.good())
            return in;

        // eat all the crap up to the ')'
        while (in.peek() == ' ' || in.peek() == '\t')
            in.get();

        // there should be a ')' if not then this is an error
        if (in.get() != ')')
            in.setstate(in.rdstate() | std::ios::failbit);
        return in;
    }

// ----------------------------------------------------------------------------------------

    typedef vector<long,2> point;
    typedef vector<double,2> dpoint;

// ----------------------------------------------------------------------------------------

}

namespace std
{
    /*!
        Define std::less<vector<T,3> > so that you can use vectors in the associative containers.
    !*/
    template<typename T>
    struct less<dlib::vector<T,3> > : public binary_function<dlib::vector<T,3> ,dlib::vector<T,3> ,bool>
    {
        inline bool operator() (const dlib::vector<T,3> & a, const dlib::vector<T,3> & b) const
        {
            if      (a.x() < b.x()) return true;
            else if (a.x() > b.x()) return false;
            else if (a.y() < b.y()) return true;
            else if (a.y() > b.y()) return false;
            else if (a.z() < b.z()) return true;
            else if (a.z() > b.z()) return false;
            else                    return false;
        }
    };

    /*!
        Define std::less<vector<T,2> > so that you can use vector<T,2>s in the associative containers.
    !*/
    template<typename T>
    struct less<dlib::vector<T,2> > : public binary_function<dlib::vector<T,2> ,dlib::vector<T,2> ,bool>
    {
        inline bool operator() (const dlib::vector<T,2> & a, const dlib::vector<T,2> & b) const
        {
            if      (a.x() < b.x()) return true;
            else if (a.x() > b.x()) return false;
            else if (a.y() < b.y()) return true;
            else if (a.y() > b.y()) return false;
            else                    return false;
        }
    };
}

#if defined(_MSC_VER) && _MSC_VER < 1400
// turn this warning back on
#pragma warning(default:4805)
#endif

#endif // DLIB_VECTOr_H_


dlib C++ Library - graph_kernel_1.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_GRAPH_KERNEl_1_
#define DLIB_GRAPH_KERNEl_1_

#include "../serialize.h"
#include "../noncopyable.h"
#include "../std_allocator.h"
#include "../smart_pointers.h"
#include "../algs.h"
#include <vector>
#include "graph_kernel_abstract.h"
#include "../is_kind.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <typename node_type, typename graph, bool is_checked>
    struct graph_checker_helper
    {
        /*!
            This object is used to check preconditions based on the value of is_checked
        !*/

        static void check_neighbor (
            unsigned long edge_index,
            const node_type& self
        )
        {
            // make sure requires clause is not broken
            DLIB_CASSERT(edge_index < self.number_of_neighbors(),
                         "\tnode_type& graph::node_type::neighbor(edge_index)"
                         << "\n\tYou have specified an invalid index"
                         << "\n\tedge_index:            " << edge_index
                         << "\n\tnumber_of_neighbors(): " << self.number_of_neighbors()
                         << "\n\tthis:                  " << &self
            );
        }

        static void check_edge (
            unsigned long edge_index,
            const node_type& self
        )
        {
            // make sure requires clause is not broken
            DLIB_CASSERT(edge_index < self.number_of_neighbors(),
                         "\tE& graph::node_type::edge(edge_index)"
                         << "\n\tYou have specified an invalid index"
                         << "\n\tedge_index:            " << edge_index
                         << "\n\tnumber_of_neighbors(): " << self.number_of_neighbors()
                         << "\n\tthis:                  " << &self
            );
        }

        static void check_node (
            unsigned long index,
            const graph& self
        )
        {
            // make sure requires clause is not broken
            DLIB_CASSERT(index < self.number_of_nodes(),
                         "\tnode_type& graph::node(index)"
                         << "\n\tYou have specified an invalid index"
                         << "\n\tindex:             " << index
                         << "\n\tnumber_of_nodes(): " << self.number_of_nodes()
                         << "\n\tthis:              " << &self
            );
        }

        static void check_has_edge (
            unsigned long node_index1,
            unsigned long node_index2,
            const graph& self
        )
        {
            // make sure requires clause is not broken
            DLIB_CASSERT(node_index1 < self.number_of_nodes() &&
                         node_index2 < self.number_of_nodes(),
                         "\tvoid graph::has_edge(node_index1, node_index2)"
                         << "\n\tYou have specified an invalid index"
                         << "\n\tnode_index1:       " << node_index1
                         << "\n\tnode_index2:       " << node_index2
                         << "\n\tnumber_of_nodes(): " << self.number_of_nodes()
                         << "\n\tthis:              " << &self
            );
        }

        static void check_add_edge (
            unsigned long node_index1,
            unsigned long node_index2,
            const graph& self
        )
        {
            DLIB_CASSERT(node_index1 < self.number_of_nodes() &&
                         node_index2 < self.number_of_nodes(),
                         "\tvoid graph::add_edge(node_index1, node_index2)"
                         << "\n\tYou have specified an invalid index"
                         << "\n\tnode_index1:       " << node_index1
                         << "\n\tnode_index2:       " << node_index2
                         << "\n\tnumber_of_nodes(): " << self.number_of_nodes()
                         << "\n\tthis:              " << &self
            );

            DLIB_CASSERT( self.has_edge(node_index1, node_index2) == false,
                          "\tvoid graph::add_edge(node_index1, node_index2)"
                          << "\n\tYou can't add an edge if it already exists in the graph"
                          << "\n\tnode_index1:       " << node_index1
                          << "\n\tnode_index2:       " << node_index2
                          << "\n\tnumber_of_nodes(): " << self.number_of_nodes()
                          << "\n\tthis:              " << &self
            );

        }

        static void check_remove_edge (
            unsigned long node_index1,
            unsigned long node_index2,
            const graph& self
        )
        {
            DLIB_CASSERT(node_index1 < self.number_of_nodes() &&
                         node_index2 < self.number_of_nodes(),
                         "\tvoid graph::remove_edge(node_index1, node_index2)"
                         << "\n\tYou have specified an invalid index"
                         << "\n\tnode_index1:       " << node_index1
                         << "\n\tnode_index2:       " << node_index2
                         << "\n\tnumber_of_nodes(): " << self.number_of_nodes()
                         << "\n\tthis:              " << &self
            );

            DLIB_CASSERT( self.has_edge(node_index1, node_index2) == true,
                          "\tvoid graph::remove_edge(node_index1, node_index2)"
                          << "\n\tYou can't remove an edge if it isn't in the graph"
                          << "\n\tnode_index1:       " << node_index1
                          << "\n\tnode_index2:       " << node_index2
                          << "\n\tnumber_of_nodes(): " << self.number_of_nodes()
                          << "\n\tthis:              " << &self
            );

        }

        static void check_remove_node (
            unsigned long index,
            const graph& self
        )
        {
            // make sure requires clause is not broken
            DLIB_CASSERT(index < self.number_of_nodes(),
                         "\tvoid graph::remove_node(index)"
                         << "\n\tYou have specified an invalid index"
                         << "\n\tindex:             " << index
                         << "\n\tnumber_of_nodes(): " << self.number_of_nodes()
                         << "\n\tthis:              " << &self
            );
        }
    };

    template <typename node_type, typename graph>
    struct graph_checker_helper <node_type, graph, false>
    {
        static inline void check_edge ( unsigned long , const node_type& ) { }
        static inline void check_neighbor ( unsigned long , const node_type& ) { }
        static inline void check_node ( unsigned long , const graph& ) { }
        static inline void check_has_edge ( unsigned long , unsigned long , const graph& ) { }
        static inline void check_add_edge ( unsigned long , unsigned long , const graph& ) { }
        static inline void check_remove_edge ( unsigned long , unsigned long , const graph& ) { }
        static inline void check_remove_node ( unsigned long , const graph& ) { }
    };

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename E = char,
        typename mem_manager = default_memory_manager,
        bool is_checked = true
        >
    class graph_kernel_1 : noncopyable
    {

        /*!
            INITIAL VALUE
                - nodes.size() == 0

            CONVENTION
                - nodes.size() == number_of_nodes()
                - for all valid i:
                    - *nodes[i] == node(i)
                    - nodes[i]->neighbors.size() == nodes[i]->number_of_neighbors(i)
                    - nodes[i]->idx == i == nodes[i]->index()
                    - for all valid n:
                        - nodes[i]->neighbors[n] == pointer to the n'th parent node of i
                        - *nodes[i]->neighbors[n] == node(i).neighbor(n)
                        - *nodes[i]->edges[n] == node(i).edge(n)
        !*/

    public:
        struct node_type;

    private:
        typedef graph_checker_helper<node_type, graph_kernel_1, is_checked> checker;

    public:

        typedef T type;
        typedef E edge_type;
        typedef mem_manager mem_manager_type;

        graph_kernel_1(
        ) {}

        virtual ~graph_kernel_1(
        ) {}

        void clear(
        ) { nodes.clear(); }

        void set_number_of_nodes (
            unsigned long new_size
        );

        unsigned long number_of_nodes (
        ) const { return nodes.size(); }

        node_type& node (
            unsigned long index
        ) { checker::check_node(index,*this); return *nodes[index]; }

        const node_type& node (
            unsigned long index
        ) const { checker::check_node(index,*this); return *nodes[index]; }

        bool has_edge (
            unsigned long node_index1,
            unsigned long node_index2
        ) const;

        void add_edge (
            unsigned long node_index1,
            unsigned long node_index2
        );

        void remove_edge (
            unsigned long node_index1,
            unsigned long node_index2
        );

        unsigned long add_node (
        );

        void remove_node (
            unsigned long index
        );

        void swap (
            graph_kernel_1& item
        ) { nodes.swap(item.nodes); }

    public:

        struct node_type
        {
            T data;
            typedef graph_kernel_1 graph_type;

            unsigned long index(
            ) const { return idx; }

            unsigned long number_of_neighbors (
            ) const { return neighbors.size(); }

            const node_type& neighbor (
                unsigned long edge_index
            ) const { checker::check_neighbor(edge_index,*this);  return *neighbors[edge_index]; }

            node_type& neighbor (
                unsigned long edge_index
            ) { checker::check_neighbor(edge_index,*this);  return *neighbors[edge_index]; }

            const E& edge (
                unsigned long edge_index
            ) const { checker::check_edge(edge_index,*this);  return *edges[edge_index]; }

            E& edge (
                unsigned long edge_index
            ) { checker::check_edge(edge_index,*this);  return *edges[edge_index]; }

        private:
            friend class graph_kernel_1;
            typedef std_allocator<node_type*,mem_manager> alloc_type;
            typedef std_allocator<shared_ptr<E>,mem_manager> alloc_edge_type;
            std::vector<node_type*,alloc_type> neighbors;
            std::vector<shared_ptr<E>,alloc_edge_type> edges;
            unsigned long idx;
        };

    private:

        typedef std_allocator<shared_ptr<node_type>,mem_manager> alloc_type;
        typedef std::vector<shared_ptr<node_type>, alloc_type> vector_type;
        vector_type nodes;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename E,
        typename mem_manager,
        bool is_checked
        >
    inline void swap (
        graph_kernel_1<T,E,mem_manager,is_checked>& a,
        graph_kernel_1<T,E,mem_manager,is_checked>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename E,
        typename mem_manager,
        bool is_checked
        >
    struct is_graph<graph_kernel_1<T,E,mem_manager, is_checked> >
    {
        static const bool value = true;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename E,
        typename mem_manager,
        bool is_checked
        >
    void serialize (
        const graph_kernel_1<T,E,mem_manager,is_checked>& item,
        std::ostream& out
    )
    {
        try
        {
            serialize(item.number_of_nodes(), out);

            // serialize each node
            for (unsigned long i = 0; i < item.number_of_nodes(); ++i)
            {
                serialize(item.node(i).data, out);

                // serialize all the edges
                for (unsigned long n = 0; n < item.node(i).number_of_neighbors(); ++n)
                {
                    // only serialize edges that we haven't already serialized
                    if (item.node(i).neighbor(n).index() >= i)
                    {
                        serialize(item.node(i).neighbor(n).index(), out);
                        serialize(item.node(i).edge(n), out);
                    }
                }
                const unsigned long stop_mark = 0xFFFFFFFF;
                serialize(stop_mark, out);
            }
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while serializing object of type graph_kernel_1");
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename E,
        typename mem_manager,
        bool is_checked
        >
    void deserialize (
        graph_kernel_1<T,E,mem_manager,is_checked>& item,
        std::istream& in
    )
    {
        try
        {
            unsigned long size;
            deserialize(size, in);

            item.clear();
            item.set_number_of_nodes(size);

            // deserialize each node
            for (unsigned long i = 0; i < item.number_of_nodes(); ++i)
            {
                deserialize(item.node(i).data, in);

                const unsigned long stop_mark = 0xFFFFFFFF;
                // Add all the edges going to this node's neighbors
                unsigned long index;
                deserialize(index, in);
                while (index != stop_mark)
                {
                    item.add_edge(i, index);
                    // find the edge
                    unsigned long j = 0;
                    for (j = 0; j < item.node(i).number_of_neighbors(); ++j)
                        if (item.node(i).neighbor(j).index() == index)
                            break;

                    deserialize(item.node(i).edge(j), in);
                    deserialize(index, in);
                }

            }
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while deserializing object of type graph_kernel_1");
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                             member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename E,
        typename mem_manager,
        bool is_checked
        >
    void graph_kernel_1<T,E,mem_manager,is_checked>::
    set_number_of_nodes (
        unsigned long new_size
    )
    {
        try
        {
            nodes.resize(new_size);
            for (unsigned long i = 0; i < nodes.size(); ++i)
            {
                nodes[i].reset(new node_type);
                nodes[i]->idx = i;
            }
        }
        catch (...)
        {
            clear();
            throw;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename E,
        typename mem_manager,
        bool is_checked
        >
    bool graph_kernel_1<T,E,mem_manager,is_checked>::
    has_edge (
        unsigned long node_index1,
        unsigned long node_index2
    ) const
    {
        checker::check_has_edge(node_index1, node_index2, *this);

        node_type& n = *nodes[node_index1];

        // search all the child nodes to see if there is a link to the right node
        for (unsigned long i = 0; i < n.neighbors.size(); ++i)
        {
            if (n.neighbors[i]->idx == node_index2)
                return true;
        }

        return false;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename E,
        typename mem_manager,
        bool is_checked
        >
    void graph_kernel_1<T,E,mem_manager,is_checked>::
    add_edge (
        unsigned long node_index1,
        unsigned long node_index2
    )
    {
        checker::check_add_edge(node_index1, node_index2, *this);
        try
        {
            node_type& n1 = *nodes[node_index1];
            node_type& n2 = *nodes[node_index2];

            n1.neighbors.push_back(&n2);

            shared_ptr<E> e(new E);
            n1.edges.push_back(e);

            // don't add this twice if this is an edge from node_index1 back to itself
            if (node_index1 != node_index2)
            {
                n2.neighbors.push_back(&n1);
                n2.edges.push_back(e);
            }
        }
        catch (...)
        {
            clear();
            throw;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename E,
        typename mem_manager,
        bool is_checked
        >
    void graph_kernel_1<T,E,mem_manager,is_checked>::
    remove_edge (
        unsigned long node_index1,
        unsigned long node_index2
    )
    {
        checker::check_remove_edge(node_index1, node_index2, *this);

        node_type& n1 = *nodes[node_index1];
        node_type& n2 = *nodes[node_index2];

        // remove the record of the link from n1
        unsigned long pos = static_cast<unsigned long>(find(n1.neighbors.begin(), n1.neighbors.end(), &n2) - n1.neighbors.begin());
        n1.neighbors.erase(n1.neighbors.begin() + pos);
        n1.edges.erase(n1.edges.begin() + pos);

        // check if this is an edge that goes from node_index1 back to itself
        if (node_index1 != node_index2)
        {
            // remove the record of the link from n2
            unsigned long pos = static_cast<unsigned long>(find(n2.neighbors.begin(), n2.neighbors.end(), &n1) - n2.neighbors.begin());
            n2.neighbors.erase(n2.neighbors.begin() + pos);
            n2.edges.erase(n2.edges.begin() + pos);
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename E,
        typename mem_manager,
        bool is_checked
        >
    unsigned long graph_kernel_1<T,E,mem_manager,is_checked>::
    add_node (
    )
    {
        try
        {
            shared_ptr<node_type> n(new node_type);
            n->idx = nodes.size();
            nodes.push_back(n);
            return n->idx;
        }
        catch (...)
        {
            clear();
            throw;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename E,
        typename mem_manager,
        bool is_checked
        >
    void graph_kernel_1<T,E,mem_manager,is_checked>::
    remove_node (
        unsigned long index
    )
    {
        checker::check_remove_node(index,*this);

        node_type& n = *nodes[index];

        // remove all edges pointing to this node from its neighbors
        for (unsigned long i = 0; i < n.neighbors.size(); ++i)
        {
            // remove the edge from this specific parent
            unsigned long pos = static_cast<unsigned long>(find(n.neighbors[i]->neighbors.begin(), n.neighbors[i]->neighbors.end(), &n) -
                                n.neighbors[i]->neighbors.begin());
            n.neighbors[i]->neighbors.erase(n.neighbors[i]->neighbors.begin() + pos);
            n.neighbors[i]->edges.erase(n.neighbors[i]->edges.begin() + pos);
        }

        // now remove this node by replacing it with the last node in the nodes vector
        nodes[index] = nodes[nodes.size()-1];

        // update the index for the node we just moved
        nodes[index]->idx = index;

        // now remove the duplicated node at the end of the vector
        nodes.pop_back();
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_GRAPH_KERNEl_1_


dlib C++ Library - edge_list_graphs.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_EDGE_LIST_GrAPHS_Hh_
#define DLIB_EDGE_LIST_GrAPHS_Hh_

#include "edge_list_graphs_abstract.h"
#include <limits>
#include <vector>
#include "../string.h"
#include "../rand.h"
#include <algorithm>
#include "sample_pair.h"
#include "ordered_sample_pair.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type
        >
    void remove_duplicate_edges (
        vector_type& pairs
    )
    {
        typedef typename vector_type::value_type T;
        if (pairs.size() > 0)
        {
            // sort pairs so that we can avoid duplicates in the loop below
            std::sort(pairs.begin(), pairs.end(), &order_by_index<T>);

            // now put edges into temp while avoiding duplicates
            vector_type temp;
            temp.reserve(pairs.size());
            temp.push_back(pairs[0]);
            for (unsigned long i = 1; i < pairs.size(); ++i)
            {
                if (pairs[i] != pairs[i-1])
                {
                    temp.push_back(pairs[i]);
                }
            }

            temp.swap(pairs);
        }
    }

// ----------------------------------------------------------------------------------------

    namespace impl
    {
        template <typename iterator>
        iterator iterator_of_worst (
            iterator begin,
            const iterator& end
        )
        /*!
            ensures
                - returns an iterator that points to the element in the given range
                  that has the biggest distance
        !*/
        {
            double dist = begin->distance();
            iterator worst = begin;
            for (; begin != end; ++begin)
            {
                if (begin->distance() > dist)
                {
                    dist = begin->distance();
                    worst = begin;
                }
            }

            return worst;
        }

    }

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type,
        typename distance_function_type,
        typename alloc,
        typename T
        >
    void find_percent_shortest_edges_randomly (
        const vector_type& samples,
        const distance_function_type& dist_funct,
        const double percent,
        const unsigned long num,
        const T& random_seed,
        std::vector<sample_pair, alloc>& out
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( 0 < percent && percent <= 1 &&
                    num > 0,
            "\t void find_percent_shortest_edges_randomly()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t samples.size(): " << samples.size()
            << "\n\t percent:        " << percent
            << "\n\t num:            " << num
            );

        out.clear();

        if (samples.size() <= 1)
        {
            return;
        }

        std::vector<sample_pair, alloc> edges;
        edges.reserve(num);

        dlib::rand rnd;
        rnd.set_seed(cast_to_string(random_seed));

        // randomly sample a bunch of edges
        for (unsigned long i = 0; i < num; ++i)
        {
            const unsigned long idx1 = rnd.get_random_32bit_number()%samples.size();
            const unsigned long idx2 = rnd.get_random_32bit_number()%samples.size();
            if (idx1 != idx2)
            {
                const double dist = dist_funct(samples[idx1], samples[idx2]);
                if (dist < std::numeric_limits<double>::infinity())
                {
                    edges.push_back(sample_pair(idx1, idx2, dist));
                }
            }
        }

        // now put edges into out while avoiding duplicates
        if (edges.size() > 0)
        {
            remove_duplicate_edges(edges);

            // now sort all the edges by distance and take the percent with the smallest distance
            std::sort(edges.begin(), edges.end(), &order_by_distance<sample_pair>);

            const unsigned long out_size = std::min<unsigned long>((unsigned long)(num*percent), edges.size());
            out.assign(edges.begin(), edges.begin() + out_size);
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type,
        typename distance_function_type,
        typename alloc,
        typename T
        >
    void find_approximate_k_nearest_neighbors (
        const vector_type& samples,
        const distance_function_type& dist_funct,
        const unsigned long k,
        unsigned long num,
        const T& random_seed,
        std::vector<sample_pair, alloc>& out
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( num > 0 && k > 0,
            "\t void find_approximate_k_nearest_neighbors()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t samples.size(): " << samples.size()
            << "\n\t k:              " << k
            << "\n\t num:            " << num
            );

        out.clear();

        if (samples.size() <= 1)
        {
            return;
        }

        // we add each edge twice in the following loop.  So multiply num by 2 to account for that.
        num *= 2;

        std::vector<ordered_sample_pair> edges;
        edges.reserve(num);
        std::vector<sample_pair, alloc> temp;
        temp.reserve(num);

        dlib::rand rnd;
        rnd.set_seed(cast_to_string(random_seed));

        // randomly sample a bunch of edges
        for (unsigned long i = 0; i < num; ++i)
        {
            const unsigned long idx1 = rnd.get_random_32bit_number()%samples.size();
            const unsigned long idx2 = rnd.get_random_32bit_number()%samples.size();
            if (idx1 != idx2)
            {
                const double dist = dist_funct(samples[idx1], samples[idx2]);
                if (dist < std::numeric_limits<double>::infinity())
                {
                    edges.push_back(ordered_sample_pair(idx1, idx2, dist));
                    edges.push_back(ordered_sample_pair(idx2, idx1, dist));
                }
            }
        }

        std::sort(edges.begin(), edges.end(), &order_by_index<ordered_sample_pair>);

        std::vector<ordered_sample_pair>::iterator beg, itr;
        // now copy edges into temp when they aren't duplicates and also only move in the k shortest for
        // each index.
        itr = edges.begin();
        while (itr != edges.end())
        {
            // first find the bounding range for all the edges connected to node itr->index1()
            beg = itr;
            while (itr != edges.end() && itr->index1() == beg->index1())
                ++itr;

            // If the node has more than k edges then sort them by distance so that
            // we will end up with the k best.
            if (static_cast<unsigned long>(itr - beg) > k)
            {
                std::sort(beg, itr, &order_by_distance_and_index<ordered_sample_pair>);
            }

            // take the k best unique edges from the range [beg,itr)
            temp.push_back(sample_pair(beg->index1(), beg->index2(), beg->distance()));
            unsigned long prev_index2 = beg->index2();
            ++beg;
            unsigned long count = 1;
            for (; beg != itr && count < k; ++beg)
            {
                if (beg->index2() != prev_index2)
                {
                    temp.push_back(sample_pair(beg->index1(), beg->index2(), beg->distance()));
                    ++count;
                }
                prev_index2 = beg->index2();
            }
        }

        remove_duplicate_edges(temp);
        temp.swap(out);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type,
        typename distance_function_type,
        typename alloc
        >
    void find_k_nearest_neighbors (
        const vector_type& samples,
        const distance_function_type& dist_funct,
        const unsigned long k,
        std::vector<sample_pair, alloc>& out
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(k > 0,
            "\t void find_k_nearest_neighbors()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t samples.size(): " << samples.size()
            << "\n\t k:              " << k
            );

        out.clear();

        if (samples.size() <= 1)
        {
            return;
        }

        using namespace impl;
        std::vector<sample_pair> edges;

        // Initialize all the edges to an edge with an invalid index
        edges.resize(samples.size()*k,
                     sample_pair(samples.size(),samples.size(),std::numeric_limits<double>::infinity()));

        // Hold the length for the longest edge for each node.  Initially they are all infinity.
        std::vector<double> worst_dists(samples.size(), std::numeric_limits<double>::infinity());

        std::vector<sample_pair>::iterator begin_i, end_i, begin_j, end_j, itr;
        begin_i = edges.begin();
        end_i = begin_i + k;

        // Loop over all combinations of samples.   We will maintain the iterator ranges so that
        // within the inner for loop we have:
        //   [begin_i, end_i) == the range in edges that contains neighbors of samples[i]
        //   [begin_j, end_j) == the range in edges that contains neighbors of samples[j]
        for (unsigned long i = 0; i+1 < samples.size(); ++i)
        {
            begin_j = begin_i;
            end_j = end_i;

            for (unsigned long j = i+1; j < samples.size(); ++j)
            {
                begin_j += k;
                end_j += k;

                const double dist = dist_funct(samples[i], samples[j]);

                if (dist < worst_dists[i])
                {
                    *iterator_of_worst(begin_i, end_i) = sample_pair(i, j, dist);
                    worst_dists[i] = iterator_of_worst(begin_i, end_i)->distance();
                }

                if (dist < worst_dists[j])
                {
                    *iterator_of_worst(begin_j, end_j) = sample_pair(i, j, dist);
                    worst_dists[j] = iterator_of_worst(begin_j, end_j)->distance();
                }
            }

            begin_i += k;
            end_i += k;
        }

        // sort the edges so that duplicate edges will be adjacent
        std::sort(edges.begin(), edges.end(), &order_by_index<sample_pair>);

        // if the first edge is valid
        if (edges[0].index1() < samples.size())
        {
            // now put edges into out while avoiding duplicates and any remaining invalid edges.
            out.reserve(edges.size());
            out.push_back(edges[0]);
            for (unsigned long i = 1; i < edges.size(); ++i)
            {
                // if we hit an invalid edge then we can stop
                if (edges[i].index1() >= samples.size())
                    break;

                // if this isn't a duplicate edge
                if (edges[i] != edges[i-1])
                {
                    out.push_back(edges[i]);
                }
            }
        }

    }

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type
        >
    bool contains_duplicate_pairs (
        const vector_type& pairs
    )
    {
        typedef typename vector_type::value_type T;
        vector_type temp(pairs);
        std::sort(temp.begin(), temp.end(), &order_by_index<T>);

        for (unsigned long i = 1; i < temp.size(); ++i)
        {
            // if we found a duplicate
            if (temp[i-1] == temp[i])
                return true;
        }

        return false;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type
        >
    typename enable_if_c<(is_same_type<sample_pair, typename vector_type::value_type>::value ||
                          is_same_type<ordered_sample_pair, typename vector_type::value_type>::value),
                          unsigned long>::type
    max_index_plus_one (
        const vector_type& pairs
    )
    {
        if (pairs.size() == 0)
        {
            return 0;
        }
        else
        {
            unsigned long max_idx = 0;
            for (unsigned long i = 0; i < pairs.size(); ++i)
            {
                if (pairs[i].index1() > max_idx)
                    max_idx = pairs[i].index1();
                if (pairs[i].index2() > max_idx)
                    max_idx = pairs[i].index2();
            }

            return max_idx + 1;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type
        >
    void remove_long_edges (
        vector_type& pairs,
        double distance_threshold
    )
    {
        vector_type temp;
        temp.reserve(pairs.size());

        // add all the pairs shorter than the given threshold into temp
        for (unsigned long i = 0; i < pairs.size(); ++i)
        {
            if (pairs[i].distance() <= distance_threshold)
                temp.push_back(pairs[i]);
        }

        // move temp into the output vector
        temp.swap(pairs);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type
        >
    void remove_short_edges (
        vector_type& pairs,
        double distance_threshold
    )
    {
        vector_type temp;
        temp.reserve(pairs.size());

        // add all the pairs longer than the given threshold into temp
        for (unsigned long i = 0; i < pairs.size(); ++i)
        {
            if (pairs[i].distance() >= distance_threshold)
                temp.push_back(pairs[i]);
        }

        // move temp into the output vector
        temp.swap(pairs);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type
        >
    void remove_percent_longest_edges (
        vector_type& pairs,
        double percent
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( 0 <= percent && percent < 1,
            "\t void remove_percent_longest_edges()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t percent:        " << percent
            );

        typedef typename vector_type::value_type T;
        std::sort(pairs.begin(), pairs.end(), &order_by_distance<T>);

        const unsigned long num = static_cast<unsigned long>((1.0-percent)*pairs.size());

        // pick out the num shortest pairs
        vector_type temp(pairs.begin(), pairs.begin() + num);

        // move temp into the output vector
        temp.swap(pairs);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type
        >
    void remove_percent_shortest_edges (
        vector_type& pairs,
        double percent
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( 0 <= percent && percent < 1,
            "\t void remove_percent_shortest_edges()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t percent:        " << percent
            );

        typedef typename vector_type::value_type T;
        std::sort(pairs.rbegin(), pairs.rend(), &order_by_distance<T>);

        const unsigned long num = static_cast<unsigned long>((1.0-percent)*pairs.size());

        // pick out the num shortest pairs
        vector_type temp(pairs.begin(), pairs.begin() + num);

        // move temp into the output vector
        temp.swap(pairs);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type
        >
    bool is_ordered_by_index (
        const vector_type& edges
    )
    {
        for (unsigned long i = 1; i < edges.size(); ++i)
        {
            if (order_by_index(edges[i], edges[i-1]))
                return false;
        }
        return true;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename alloc1,
        typename alloc2
        >
    void find_neighbor_ranges (
        const std::vector<ordered_sample_pair,alloc1>& edges,
        std::vector<std::pair<unsigned long, unsigned long>,alloc2>& neighbors
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(is_ordered_by_index(edges),
                    "\t void find_neighbor_ranges()"
                    << "\n\t Invalid inputs were given to this function"
        );

        // setup neighbors so that [neighbors[i].first, neighbors[i].second) is the range
        // within edges that contains all node i's edges.
        const unsigned long num_nodes = max_index_plus_one(edges);
        neighbors.assign(num_nodes, std::make_pair(0,0));
        unsigned long cur_node = 0;
        unsigned long start_idx = 0;
        for (unsigned long i = 0; i < edges.size(); ++i)
        {
            if (edges[i].index1() != cur_node)
            {
                neighbors[cur_node] = std::make_pair(start_idx, i);
                start_idx = i;
                cur_node = edges[i].index1();
            }
        }
        if (neighbors.size() != 0)
            neighbors[cur_node] = std::make_pair(start_idx, (unsigned long)edges.size());
    }

// ----------------------------------------------------------------------------------------

    template <
        typename alloc1,
        typename alloc2
        >
    void convert_unordered_to_ordered (
        const std::vector<sample_pair,alloc1>& edges,
        std::vector<ordered_sample_pair,alloc2>& out_edges
    )
    {
        out_edges.clear();
        out_edges.reserve(edges.size()*2);
        for (unsigned long i = 0; i < edges.size(); ++i)
        {
            out_edges.push_back(ordered_sample_pair(edges[i].index1(), edges[i].index2(), edges[i].distance()));
            if (edges[i].index1() != edges[i].index2())
                out_edges.push_back(ordered_sample_pair(edges[i].index2(), edges[i].index1(), edges[i].distance()));
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_EDGE_LIST_GrAPHS_Hh_


dlib C++ Library - function_objects.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MR_FUNCTION_ObJECTS_Hh_
#define DLIB_MR_FUNCTION_ObJECTS_Hh_

#include "function_objects_abstract.h"
#include "../matrix.h"
#include "../svm/sparse_vector.h"
#include <cmath>
#include <limits>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    struct squared_euclidean_distance
    {
        squared_euclidean_distance (
        ) :
            lower(0),
            upper(std::numeric_limits<double>::infinity())
        {}

        squared_euclidean_distance (
            const double l,
            const double u
        ) :
            lower(l),
            upper(u)
        {}

        const double lower;
        const double upper;

        template <typename sample_type>
        double operator() (
            const sample_type& a,
            const sample_type& b
        ) const
        {
            const double len = length_squared(a-b);
            if (lower <= len && len <= upper)
                return len;
            else
                return std::numeric_limits<double>::infinity();
        }
    };

// ----------------------------------------------------------------------------------------

    struct cosine_distance
    {
        template <typename sample_type>
        double operator() (
            const sample_type& a,
            const sample_type& b
        ) const
        {
            const double temp = length(a)*length(b);
            if (temp == 0)
                return 0;
            else
                return 1-dot(a,b)/temp;
        }
    };

// ----------------------------------------------------------------------------------------

    struct negative_dot_product_distance
    {
        template <typename sample_type>
        double operator() (
            const sample_type& a,
            const sample_type& b
        ) const
        {
            return -dot(a,b);
        }
    };

// ----------------------------------------------------------------------------------------

    struct use_weights_of_one
    {
        template <typename edge_type>
        double operator() (
            const edge_type&
        ) const
        {
            return 1;
        }
    };

// ----------------------------------------------------------------------------------------

    struct use_gaussian_weights
    {
        use_gaussian_weights (
        )
        {
            gamma = 0.1;
        }

        use_gaussian_weights (
            double g
        )
        {
            gamma = g;
        }

        double gamma;

        template <typename edge_type>
        double operator() (
            const edge_type& e
        ) const
        {
            return std::exp(-gamma*e.distance());
        }
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MR_FUNCTION_ObJECTS_Hh_


dlib C++ Library - graph_utils.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_GRAPH_UTILs_
#define DLIB_GRAPH_UTILs_

#include "../algs.h"
#include <vector>
#include "graph_utils_abstract.h"
#include "../is_kind.h"
#include "../enable_if.h"
#include <algorithm>
#include "../set.h"
#include "../memory_manager.h"
#include "../set_utils.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <typename T>
    typename enable_if<is_graph<T>,typename T::edge_type>::type& edge(
        T& g,
        unsigned long idx_i,
        unsigned long idx_j
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(g.has_edge(idx_i,idx_j) == true,
            "\tT::edge_type& edge(g, idx_i, idx_j)"
            << "\n\t you have requested an invalid edge"
            << "\n\t idx_i: " << idx_i
            << "\n\t idx_j: " << idx_j
            );

        for (unsigned long i = 0; i < g.node(idx_i).number_of_neighbors(); ++i)
        {
            if (g.node(idx_i).neighbor(i).index() == idx_j)
                return g.node(idx_i).edge(i);
        }

        // put this here just so compilers don't complain about a lack of
        // a return here
        DLIB_CASSERT(false,
            "\tT::edge_type& edge(g, idx_i, idx_j)"
            << "\n\t you have requested an invalid edge"
            << "\n\t idx_i: " << idx_i
            << "\n\t idx_j: " << idx_j
            );
    }

    template <typename T>
    const typename enable_if<is_graph<T>,typename T::edge_type>::type& edge(
        const T& g,
        unsigned long idx_i,
        unsigned long idx_j
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(g.has_edge(idx_i,idx_j) == true,
            "\tT::edge_type& edge(g, idx_i, idx_j)"
            << "\n\t you have requested an invalid edge"
            << "\n\t idx_i: " << idx_i
            << "\n\t idx_j: " << idx_j
            );

        for (unsigned long i = 0; i < g.node(idx_i).number_of_neighbors(); ++i)
        {
            if (g.node(idx_i).neighbor(i).index() == idx_j)
                return g.node(idx_i).edge(i);
        }

        // put this here just so compilers don't complain about a lack of
        // a return here
        DLIB_CASSERT(false,
            "\tT::edge_type& edge(g, idx_i, idx_j)"
            << "\n\t you have requested an invalid edge"
            << "\n\t idx_i: " << idx_i
            << "\n\t idx_j: " << idx_j
            );
    }

// ----------------------------------------------------------------------------------------

    template <typename T>
    typename enable_if<is_directed_graph<T>,typename T::edge_type>::type& edge(
        T& g,
        unsigned long parent_idx,
        unsigned long child_idx
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(g.has_edge(parent_idx,child_idx) == true,
            "\t T::edge_type& edge(g, parent_idx, child_idx)"
            << "\n\t you have requested an invalid edge"
            << "\n\t parent_idx: " << parent_idx
            << "\n\t child_idx: " << child_idx
            );

        for (unsigned long i = 0; i < g.node(parent_idx).number_of_children(); ++i)
        {
            if (g.node(parent_idx).child(i).index() == child_idx)
                return g.node(parent_idx).child_edge(i);
        }

        // put this here just so compilers don't complain about a lack of
        // a return here
        DLIB_CASSERT(false,
            "\t T::edge_type& edge(g, parent_idx, child_idx)"
            << "\n\t you have requested an invalid edge"
            << "\n\t parent_idx: " << parent_idx
            << "\n\t child_idx: " << child_idx
            );
    }

    template <typename T>
    const typename enable_if<is_directed_graph<T>,typename T::edge_type>::type& edge(
        const T& g,
        unsigned long parent_idx,
        unsigned long child_idx
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(g.has_edge(parent_idx,child_idx) == true,
            "\t T::edge_type& edge(g, parent_idx, child_idx)"
            << "\n\t you have requested an invalid edge"
            << "\n\t parent_idx: " << parent_idx
            << "\n\t child_idx: " << child_idx
            );

        for (unsigned long i = 0; i < g.node(parent_idx).number_of_children(); ++i)
        {
            if (g.node(parent_idx).child(i).index() == child_idx)
                return g.node(parent_idx).child_edge(i);
        }

        // put this here just so compilers don't complain about a lack of
        // a return here
        DLIB_ASSERT(false,
            "\t T::edge_type& edge(g, parent_idx, child_idx)"
            << "\n\t you have requested an invalid edge"
            << "\n\t parent_idx: " << parent_idx
            << "\n\t child_idx: " << child_idx
            );
    }

// ----------------------------------------------------------------------------------------

    namespace graph_helpers
    {
        template <typename T, typename U>
        inline bool is_same_object (
            const T& a,
            const U& b
        )
        {
            if (is_same_type<const T,const U>::value == false)
                return false;
            if ((void*)&a == (void*)&b)
                return true;
            else
                return false;
        }

        template <
            typename T
            >
        bool search_for_directed_cycles (
            const T& node,
            std::vector<bool>& visited,
            std::vector<bool>& temp
        )
        /*!
            requires
                - visited.size() >= number of nodes in the graph that contains the given node
                - temp.size() >= number of nodes in the graph that contains the given node
                - for all i in temp:
                    - temp[i] == false
            ensures
                - checks the connected subgraph containing the given node for directed cycles
                  and returns true if any are found and false otherwise.
                - for all nodes N in the connected subgraph containing the given node:
                    - #visited[N.index()] == true
                - for all i in temp:
                    - #temp[i] == false
        !*/
        {
            if (temp[node.index()] == true)
                return true;

            visited[node.index()] = true;
            temp[node.index()] = true;

            for (unsigned long i = 0; i < node.number_of_children(); ++i)
            {
                if (search_for_directed_cycles(node.child(i), visited, temp))
                    return true;
            }

            temp[node.index()] = false;

            return false;
        }

    // ------------------------------------------------------------------------------------

        template <
            typename T
            >
        typename enable_if<is_directed_graph<typename T::graph_type>,bool>::type search_for_undirected_cycles (
            const T& node,
            std::vector<bool>& visited,
            unsigned long prev = std::numeric_limits<unsigned long>::max()
        )
        /*!
            requires
                - visited.size() >= number of nodes in the graph that contains the given node
                - for all nodes N in the connected subgraph containing the given node:
                    - visited[N.index] == false
            ensures
                - checks the connected subgraph containing the given node for directed cycles
                  and returns true if any are found and false otherwise.
                - for all nodes N in the connected subgraph containing the given node:
                    - #visited[N.index()] == true
        !*/
        {
            using namespace std;
            if (visited[node.index()] == true)
                return true;

            visited[node.index()] = true;

            for (unsigned long i = 0; i < node.number_of_children(); ++i)
            {
                if (node.child(i).index() != prev &&
                    search_for_undirected_cycles(node.child(i), visited, node.index()))
                    return true;
            }

            for (unsigned long i = 0; i < node.number_of_parents(); ++i)
            {
                if (node.parent(i).index() != prev &&
                    search_for_undirected_cycles(node.parent(i), visited, node.index()))
                    return true;
            }

            return false;
        }

    // ------------------------------------------------------------------------------------

        template <
            typename T
            >
        typename enable_if<is_graph<typename T::graph_type>,bool>::type search_for_undirected_cycles (
            const T& node,
            std::vector<bool>& visited,
            unsigned long prev = std::numeric_limits<unsigned long>::max()
        )
        /*!
            requires
                - visited.size() >= number of nodes in the graph that contains the given node
                - for all nodes N in the connected subgraph containing the given node:
                    - visited[N.index] == false
            ensures
                - checks the connected subgraph containing the given node for directed cycles
                  and returns true if any are found and false otherwise.
                - for all nodes N in the connected subgraph containing the given node:
                    - #visited[N.index()] == true
        !*/
        {
            using namespace std;
            if (visited[node.index()] == true)
                return true;

            visited[node.index()] = true;

            for (unsigned long i = 0; i < node.number_of_neighbors(); ++i)
            {
                if (node.neighbor(i).index() != prev &&
                    search_for_undirected_cycles(node.neighbor(i), visited, node.index()))
                    return true;
            }

            return false;
        }

    }

// ------------------------------------------------------------------------------------

    template <
        typename graph_type1,
        typename graph_type2
        >
    typename enable_if<is_graph<graph_type1> >::type copy_graph_structure (
        const graph_type1& src,
        graph_type2& dest
    )
    {
        COMPILE_TIME_ASSERT(is_graph<graph_type1>::value);
        COMPILE_TIME_ASSERT(is_graph<graph_type2>::value);
        if (graph_helpers::is_same_object(src,dest))
            return;

        dest.clear();
        dest.set_number_of_nodes(src.number_of_nodes());

        // copy all the edges from src into dest
        for (unsigned long i = 0; i < src.number_of_nodes(); ++i)
        {
            for (unsigned long j = 0; j < src.node(i).number_of_neighbors(); ++j)
            {
                const unsigned long nidx = src.node(i).neighbor(j).index();
                if (nidx >= i)
                {
                    dest.add_edge(i,nidx);
                }
            }
        }
    }

    template <
        typename graph_type1,
        typename graph_type2
        >
    typename enable_if<is_directed_graph<graph_type1> >::type copy_graph_structure (
        const graph_type1& src,
        graph_type2& dest
    )
    {
        COMPILE_TIME_ASSERT(is_directed_graph<graph_type1>::value);
        COMPILE_TIME_ASSERT(is_directed_graph<graph_type2>::value || is_graph<graph_type2>::value );
        if (graph_helpers::is_same_object(src,dest))
            return;

        dest.clear();
        dest.set_number_of_nodes(src.number_of_nodes());

        // copy all the edges from src into dest
        for (unsigned long i = 0; i < src.number_of_nodes(); ++i)
        {
            for (unsigned long j = 0; j < src.node(i).number_of_children(); ++j)
            {
                const unsigned long nidx = src.node(i).child(j).index();
                if (dest.has_edge(i,nidx) == false)
                {
                    dest.add_edge(i,nidx);
                }
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename graph_type1,
        typename graph_type2
        >
    typename enable_if<is_graph<graph_type1> >::type copy_graph (
        const graph_type1& src,
        graph_type2& dest
    )
    {
        COMPILE_TIME_ASSERT(is_graph<graph_type1>::value);
        COMPILE_TIME_ASSERT(is_graph<graph_type2>::value);
        if (graph_helpers::is_same_object(src,dest))
            return;

        copy_graph_structure(src,dest);

        // copy all the node and edge content
        for (unsigned long i = 0; i < src.number_of_nodes(); ++i)
        {
            dest.node(i).data = src.node(i).data;

            for (unsigned long j = 0; j < src.node(i).number_of_neighbors(); ++j)
            {
                const unsigned long nidx = src.node(i).neighbor(j).index();
                if (nidx >= i)
                {
                    dest.node(i).edge(j) = src.node(i).edge(j);
                }
            }
        }
    }

    template <
        typename graph_type1,
        typename graph_type2
        >
    typename enable_if<is_directed_graph<graph_type1> >::type copy_graph (
        const graph_type1& src,
        graph_type2& dest
    )
    {
        COMPILE_TIME_ASSERT(is_directed_graph<graph_type1>::value);
        COMPILE_TIME_ASSERT(is_directed_graph<graph_type2>::value);
        if (graph_helpers::is_same_object(src,dest))
            return;

        copy_graph_structure(src,dest);

        // copy all the node and edge content
        for (unsigned long i = 0; i < src.number_of_nodes(); ++i)
        {
            dest.node(i).data = src.node(i).data;
            for (unsigned long j = 0; j < src.node(i).number_of_children(); ++j)
            {
                dest.node(i).child_edge(j) = src.node(i).child_edge(j);
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename S
        >
    typename enable_if<is_graph<typename T::graph_type> >::type find_connected_nodes (
    const T& n,
    S& visited
    )
    {
        if (visited.is_member(n.index()) == false)
        {
            unsigned long temp = n.index();
            visited.add(temp);

            for (unsigned long i = 0; i < n.number_of_neighbors(); ++i)
                find_connected_nodes(n.neighbor(i), visited);
        }
    }

    template <
        typename T,
        typename S
        >
    typename enable_if<is_directed_graph<typename T::graph_type> >::type find_connected_nodes (
    const T& n,
    S& visited
    )
    {
        if (visited.is_member(n.index()) == false)
        {
            unsigned long temp = n.index();
            visited.add(temp);

            for (unsigned long i = 0; i < n.number_of_parents(); ++i)
                find_connected_nodes(n.parent(i), visited);
            for (unsigned long i = 0; i < n.number_of_children(); ++i)
                find_connected_nodes(n.child(i), visited);
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    bool graph_is_connected (
        const T& g
    )
    {
        if (g.number_of_nodes() == 0)
            return true;

        set<unsigned long>::kernel_1b_c visited;
        find_connected_nodes(g.node(0), visited);
        return (visited.size() == g.number_of_nodes());
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    bool graph_has_symmetric_edges (
        const T& graph
    )
    {
        for (unsigned long i = 0; i < graph.number_of_nodes(); ++i)
        {
            for (unsigned long j = 0; j < graph.node(i).number_of_children(); ++j)
            {
                const unsigned long jj = graph.node(i).child(j).index();
                // make sure every edge from a parent to a child has an edge linking back
                if (graph.has_edge(jj,i) == false)
                    return false;
            }

            for (unsigned long j = 0; j < graph.node(i).number_of_parents(); ++j)
            {
                const unsigned long jj = graph.node(i).parent(j).index();
                // make sure every edge from a child to a parent has an edge linking back
                if (graph.has_edge(i,jj) == false)
                    return false;
            }
        }

        return true;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    bool graph_contains_directed_cycle (
        const T& graph
    )
    {
        using namespace std;
        using namespace graph_helpers;
        std::vector<bool> visited(graph.number_of_nodes(), false);
        std::vector<bool> temp(graph.number_of_nodes(), false);

        while (true)
        {
            // find the first node that hasn't been visited yet
            unsigned long i;
            for (i = 0; i < visited.size(); ++i)
            {
                if (visited[i] == false)
                    break;
            }

            // if we didn't find any non-visited nodes then we are done
            if (i == visited.size())
                return false;

            if (search_for_directed_cycles(graph.node(i), visited, temp))
                return true;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    bool graph_contains_undirected_cycle (
        const T& graph
    )
    {
        using namespace std;
        using namespace graph_helpers;
        std::vector<bool> visited(graph.number_of_nodes(), false);

        while (true)
        {
            // find the first node that hasn't been visited yet
            unsigned long i;
            for (i = 0; i < visited.size(); ++i)
            {
                if (visited[i] == false)
                    break;
            }

            // if we didn't find any non-visited nodes then we are done
            if (i == visited.size())
                return false;

            if (search_for_undirected_cycles(graph.node(i), visited))
                return true;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename directed_graph_type,
        typename graph_type
        >
    void create_moral_graph (
        const directed_graph_type& g,
        graph_type& moral_graph
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(graph_contains_directed_cycle(g) == false,
            "\tvoid create_moral_graph(g, moral_graph)"
            << "\n\tYou can only make moral graphs if g doesn't have directed cycles"
            );
        COMPILE_TIME_ASSERT(is_graph<graph_type>::value);
        COMPILE_TIME_ASSERT(is_directed_graph<directed_graph_type>::value);

        copy_graph_structure(g, moral_graph);

        // now marry all the parents (i.e. add edges between parent nodes)
        for (unsigned long i = 0; i < g.number_of_nodes(); ++i)
        {
            // loop over all combinations of parents of g.node(i)
            for (unsigned long j = 0; j < g.node(i).number_of_parents(); ++j)
            {
                for (unsigned long k = 0; k < g.node(i).number_of_parents(); ++k)
                {
                    const unsigned long p1 = g.node(i).parent(j).index();
                    const unsigned long p2 = g.node(i).parent(k).index();
                    if (p1 == p2)
                        continue;

                    if (moral_graph.has_edge(p1,p2) == false)
                        moral_graph.add_edge(p1,p2);
                }
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename graph_type,
        typename sets_of_int
        >
    bool is_clique (
        const graph_type& g,
        const sets_of_int& clique
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(graph_contains_length_one_cycle(g) == false,
            "\tvoid is_clique(g, clique)"
            << "\n\tinvalid graph"
            );
#ifdef ENABLE_ASSERTS
        clique.reset();
        while (clique.move_next())
        {
            const unsigned long x = clique.element();
            DLIB_ASSERT( x < g.number_of_nodes(),
                "\tvoid is_clique(g, clique)"
                << "\n\tthe clique set contained an invalid node index"
                << "\n\tx:                   " << x
                << "\n\tg.number_of_nodes(): " << g.number_of_nodes()
                );
        }
#endif

        COMPILE_TIME_ASSERT(is_graph<graph_type>::value);

        std::vector<unsigned long> v;
        v.reserve(clique.size());
        clique.reset();
        while (clique.move_next())
        {
            v.push_back(clique.element());
        }

        for (unsigned long i = 0; i < v.size(); ++i)
        {
            for (unsigned long j = 0; j < v.size(); ++j)
            {
                if (v[i] == v[j])
                    continue;
                if (g.has_edge(v[i], v[j]) == false)
                    return false;
            }
        }

        return true;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename graph_type,
        typename sets_of_int
        >
    bool is_maximal_clique (
        const graph_type& g,
        const sets_of_int& clique
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(graph_contains_length_one_cycle(g) == false,
            "\tvoid is_maximal_clique(g, clique)"
            << "\n\tinvalid graph"
            );
        DLIB_ASSERT(is_clique(g,clique) == true,
            "\tvoid is_maximal_clique(g, clique)"
            << "\n\tinvalid graph"
            );
#ifdef ENABLE_ASSERTS
        clique.reset();
        while (clique.move_next())
        {
            const unsigned long x = clique.element();
            DLIB_ASSERT( x < g.number_of_nodes(),
                "\tvoid is_maximal_clique(g, clique)"
                << "\n\tthe clique set contained an invalid node index"
                << "\n\tx:                   " << x
                << "\n\tg.number_of_nodes(): " << g.number_of_nodes()
                );
        }
#endif

        COMPILE_TIME_ASSERT(is_graph<graph_type>::value);

        if (clique.size() == 0)
            return true;

        // get an element in the clique and make sure that
        // none of its neighbors that aren't in the clique are connected
        // to all the elements of the clique.
        clique.reset();
        clique.move_next();
        const unsigned long idx = clique.element();

        for (unsigned long i = 0; i < g.node(idx).number_of_neighbors(); ++i)
        {
            const unsigned long n = g.node(idx).neighbor(i).index();
            if (clique.is_member(n))
                continue;

            // now loop over all the clique members and make sure they don't all
            // share an edge with node n
            bool all_share_edge = true;
            clique.reset();
            while (clique.move_next())
            {
                if (g.has_edge(clique.element(), n) == false)
                {
                    all_share_edge = false;
                    break;
                }
            }

            if (all_share_edge == true)
                return false;
        }

        return true;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    typename enable_if<is_directed_graph<T>,bool>::type graph_contains_length_one_cycle (
        const T& graph
    )
    {
        for (unsigned long i = 0; i < graph.number_of_nodes(); ++i)
        {
            // make sure none of this guys children are actually itself
            for (unsigned long n = 0; n < graph.node(i).number_of_children(); ++n)
            {
                if (graph.node(i).child(n).index() == i)
                    return true;
            }
        }

        return false;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    typename enable_if<is_graph<T>,bool>::type graph_contains_length_one_cycle (
        const T& graph
    )
    {
        for (unsigned long i = 0; i < graph.number_of_nodes(); ++i)
        {
            // make sure none of this guys neighbors are actually itself
            for (unsigned long n = 0; n < graph.node(i).number_of_neighbors(); ++n)
            {
                if (graph.node(i).neighbor(n).index() == i)
                    return true;
            }
        }

        return false;
    }

// ----------------------------------------------------------------------------------------

    namespace graph_helpers
    {
        struct pair
        {
            unsigned long index;
            unsigned long num_neighbors;

            bool operator< (const pair& p) const { return num_neighbors < p.num_neighbors; }
        };

        template <
            typename T,
            typename S,
            typename V
            >
        void search_graph_for_triangulate (
            const T& n,
            S& visited,
            V& order_visited
        )
        {
            // base case of recursion.  stop when we hit a node we have
            // already visited.
            if (visited.is_member(n.index()))
                return;

            // record that we have visited this node
            order_visited.push_back(n.index());
            unsigned long temp = n.index();
            visited.add(temp);

            // we want to visit all the neighbors of this node but do
            // so by visiting the nodes with the most neighbors first.  So
            // lets make a vector that lists the nodes in the order we
            // want to visit them
            std::vector<pair> neighbors;
            for (unsigned long i = 0; i < n.number_of_neighbors(); ++i)
            {
                pair p;
                p.index = i;
                p.num_neighbors = n.neighbor(i).number_of_neighbors();
                neighbors.push_back(p);
            }

            // now sort the neighbors array so that the neighbors with the
            // most neighbors come first.
            std::sort(neighbors.rbegin(), neighbors.rend());

            // now visit all the nodes
            for (unsigned long i = 0; i < neighbors.size(); ++i)
            {
                search_graph_for_triangulate(n.neighbor(neighbors[i].index), visited, order_visited);
            }
        }
    } // end namespace graph_helpers

    template <
        typename graph_type,
        typename set_of_sets_of_int
        >
    void triangulate_graph_and_find_cliques (
        graph_type& g,
        set_of_sets_of_int& cliques
    )
    {

        // make sure requires clause is not broken
        DLIB_ASSERT(graph_contains_length_one_cycle(g) == false,
            "\tvoid triangulate_graph_and_find_cliques(g, cliques)"
            << "\n\tInvalid graph"
            );
        DLIB_ASSERT(graph_is_connected(g) == true,
            "\tvoid triangulate_graph_and_find_cliques(g, cliques)"
            << "\n\tInvalid graph"
            );

        COMPILE_TIME_ASSERT(is_graph<graph_type>::value);

        using namespace graph_helpers;
        using namespace std;
        typedef typename set_of_sets_of_int::type set_of_int;

        cliques.clear();

        // first we find the node with the most neighbors
        unsigned long max_index = 0;
        unsigned long num_neighbors = 0;
        for (unsigned long i = 0; i < g.number_of_nodes(); ++i)
        {
            if (g.node(i).number_of_neighbors() > num_neighbors)
            {
                max_index = i;
                num_neighbors = g.node(i).number_of_neighbors();
            }
        }

        // now we do a depth first search of the entire graph starting
        // with the node we just found.  We record the order in which
        // we visit each node in the vector order_visited.
        std::vector<unsigned long> order_visited;
        set_of_int visited;
        search_graph_for_triangulate(g.node(max_index), visited, order_visited);

        set_of_int clique;

        // now add edges to the graph to make it triangulated
        while (visited.size() > 0)
        {
            // we are going to enumerate over the nodes in the reverse of the
            // order in which they were visited.  So get the last node out.
            const unsigned long idx = order_visited.back();
            order_visited.pop_back();
            visited.destroy(idx);

            // as a start add this node to our current clique
            unsigned long temp = idx;
            clique.clear();
            clique.add(temp);

            // now we want to make a clique that contains node g.node(idx) and
            // all of its neighbors that are still recorded in the visited set
            // (except for neighbors that have only one edge).
            for (unsigned long i = 0; i < g.node(idx).number_of_neighbors(); ++i)
            {
                // get the index of the i'th neighbor
                unsigned long nidx = g.node(idx).neighbor(i).index();

                // add it to the clique if it is still in visited and it isn't
                // a node with only one neighbor
                if (visited.is_member(nidx) == true &&
                    g.node(nidx).number_of_neighbors() != 1)
                {
                    // add edges between this new node and all the nodes
                    // that are already in the clique
                    clique.reset();
                    while (clique.move_next())
                    {
                        if (g.has_edge(nidx, clique.element()) == false)
                            g.add_edge(nidx, clique.element());
                    }

                    // now also record that we added this node to the clique
                    clique.add(nidx);
                }
            }

            if (cliques.is_member(clique) == false && is_maximal_clique(g,clique) )
            {
                cliques.add(clique);
            }

            // now it is possible that we are missing some cliques of size 2 since
            // above we didn't add nodes with only one edge to any of our cliques.
            // Now lets make sure all these nodes are accounted for
            for (unsigned long i = 0; i < g.number_of_nodes(); ++i)
            {
                clique.clear();
                if (g.node(i).number_of_neighbors() == 1)
                {
                    unsigned long temp = i;
                    clique.add(temp);
                    temp = g.node(i).neighbor(0).index();
                    clique.add(temp);

                    if (cliques.is_member(clique) == false)
                        cliques.add(clique);
                }
            }
        }

    }

// ----------------------------------------------------------------------------------------

    template <
        typename graph_type,
        typename join_tree_type
        >
    void create_join_tree (
        const graph_type& g,
        join_tree_type& join_tree
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(graph_contains_length_one_cycle(g) == false,
            "\tvoid create_join_tree(g, join_tree)"
            << "\n\tInvalid graph"
            );
        DLIB_ASSERT(graph_is_connected(g) == true,
            "\tvoid create_join_tree(g, join_tree)"
            << "\n\tInvalid graph"
            );

        COMPILE_TIME_ASSERT(is_graph<graph_type>::value);
        COMPILE_TIME_ASSERT(is_graph<join_tree_type>::value);

        typedef typename join_tree_type::type set_of_int;
        typedef typename join_tree_type::edge_type set_of_int_edge;
        typedef typename set<set_of_int>::kernel_1b_c set_of_sets_of_int;

        copy_graph_structure(g, join_tree);

        // don't even bother in this case
        if (g.number_of_nodes() == 0)
            return;

        set_of_sets_of_int cliques;
        set_of_int s;

        triangulate_graph_and_find_cliques(join_tree, cliques);

        join_tree.set_number_of_nodes(cliques.size());

        // copy the cliques into each of the nodes of tree
        for (unsigned long i = 0; i < join_tree.number_of_nodes(); ++i)
        {
            cliques.remove_any(s);
            s.swap(join_tree.node(i).data);
        }

        set_of_int_edge e;

        // add all possible edges to the join_tree
        for (unsigned long i = 0; i < join_tree.number_of_nodes(); ++i)
        {
            for (unsigned long j = i+1; j < join_tree.number_of_nodes(); ++j)
            {
                set_intersection(
                    join_tree.node(i).data,
                    join_tree.node(j).data,
                    e);

                if (e.size() > 0)
                {
                    join_tree.add_edge(i,j);
                    edge(join_tree,i,j).swap(e);
                }
            }
        }

        // now we just need to remove the unnecessary edges so that we get a
        // proper join tree
        s.clear();
        set_of_int& good = s; // rename s to something slightly more meaningful
        // good will contain nodes that have been "approved"
        unsigned long n = 0;
        good.add(n);

        std::vector<unsigned long> vtemp;

        while (good.size() < join_tree.number_of_nodes())
        {
            // figure out which of the neighbors of nodes in good has the best edge
            unsigned long best_bad_idx = 0;
            unsigned long best_good_idx = 0;
            unsigned long best_overlap = 0;
            good.reset();
            while (good.move_next())
            {
                // loop over all the neighbors of the current node in good
                for (unsigned long i = 0; i < join_tree.node(good.element()).number_of_neighbors(); ++i)
                {
                    const unsigned long idx = join_tree.node(good.element()).neighbor(i).index();
                    if (!good.is_member(idx))
                    {
                        const unsigned long overlap = join_tree.node(good.element()).edge(i).size();

                        if (overlap > best_overlap)
                        {
                            best_overlap = overlap;
                            best_bad_idx = idx;
                            best_good_idx = good.element();
                        }
                    }
                }
            }

            // now remove all the edges from best_bad_idx to the nodes in good except for the
            // edge to best_good_idx.
            for (unsigned long i = 0; i < join_tree.node(best_bad_idx).number_of_neighbors(); ++i)
            {
                const unsigned long idx = join_tree.node(best_bad_idx).neighbor(i).index();
                if (idx != best_good_idx && good.is_member(idx))
                {
                    vtemp.push_back(idx);
                }
            }

            for (unsigned long i = 0; i < vtemp.size(); ++i)
                join_tree.remove_edge(vtemp[i], best_bad_idx);

            vtemp.clear();

            // and finally add this bad index into the good set
            good.add(best_bad_idx);
        }
    }

// ----------------------------------------------------------------------------------------

    namespace graph_helpers
    {
        template <
            typename T,
            typename U
            >
        bool validate_join_tree (
            const T& n,
            U& deads,
            unsigned long parent = 0xffffffff
        )
        /*!
            this function makes sure that a join tree satisfies the following criterion for paths starting at the given node:
                - for all valid i and j such that i and j are both < #join_tree.number_of_nodes()
                    - let X be the set of numbers that is contained in both #join_tree.node(i).data
                      and #join_tree.node(j).data
                    - It is the case that all nodes on the unique path between #join_tree.node(i)
                      and #join_tree.node(j) contain the numbers from X in their sets.

            returns true if validation passed and false if there is a problem with the tree
        !*/
        {
            n.data.reset();
            while (n.data.move_next())
            {
                if (deads.is_member(n.data.element()))
                    return false;
            }

            for (unsigned long i = 0; i < n.number_of_neighbors(); ++i)
            {
                if (n.neighbor(i).index() == parent)
                    continue;

                // add anything to dead stuff
                n.data.reset();
                while (n.data.move_next())
                {
                    if (n.neighbor(i).data.is_member(n.data.element()) == false)
                    {
                        unsigned long temp = n.data.element();
                        deads.add(temp);
                    }
                }

                if (validate_join_tree(n.neighbor(i), deads, n.index()) == false)
                    return false;

                // remove this nodes stuff from dead stuff
                n.data.reset();
                while (n.data.move_next())
                {
                    if (n.neighbor(i).data.is_member(n.data.element()) == false)
                    {
                        unsigned long temp = n.data.element();
                        deads.destroy(temp);
                    }
                }
            }

            return true;
        }
    }

    template <
        typename graph_type,
        typename join_tree_type
        >
    bool is_join_tree (
        const graph_type& g,
        const join_tree_type& join_tree
    )
    {

        // make sure requires clause is not broken
        DLIB_ASSERT(graph_contains_length_one_cycle(g) == false,
            "\tvoid create_join_tree(g, join_tree)"
            << "\n\tInvalid graph"
            );
        DLIB_ASSERT(graph_is_connected(g) == true,
            "\tvoid create_join_tree(g, join_tree)"
            << "\n\tInvalid graph"
            );

        COMPILE_TIME_ASSERT(is_graph<graph_type>::value || is_directed_graph<graph_type>::value);
        COMPILE_TIME_ASSERT(is_graph<join_tree_type>::value);

        if (graph_contains_undirected_cycle(join_tree))
            return false;

        if (graph_is_connected(join_tree) == false)
            return false;

        // verify that the path condition of the join tree is valid
        for (unsigned long i = 0; i < join_tree.number_of_nodes(); ++i)
        {
            typename join_tree_type::type deads;
            if (graph_helpers::validate_join_tree(join_tree.node(i), deads) == false)
                return false;
        }

        typename join_tree_type::edge_type e;
        typename join_tree_type::edge_type all;
        // now make sure that the edges contain correct intersections
        for (unsigned long i = 0; i < join_tree.number_of_nodes(); ++i)
        {
            set_union(all,join_tree.node(i).data, all);
            for (unsigned long j = 0; j < join_tree.node(i).number_of_neighbors(); ++j)
            {
                set_intersection(join_tree.node(i).data,
                                 join_tree.node(i).neighbor(j).data,
                                 e);

                if (!(e == join_tree.node(i).edge(j)))
                    return false;
            }
        }

        // and finally check that all the nodes in g show up in the join tree
        if (all.size() != g.number_of_nodes())
            return false;
        all.reset();
        while (all.move_next())
        {
            if (all.element() >= g.number_of_nodes())
                return false;
        }

        return true;
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_GRAPH_UTILs_


dlib C++ Library - ordered_sample_pair.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ORDERED_SAMPLE_PaIR_Hh_
#define DLIB_ORDERED_SAMPLE_PaIR_Hh_

#include "ordered_sample_pair_abstract.h"
#include <limits>
#include "../serialize.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class ordered_sample_pair
    {
    public:
        ordered_sample_pair(
        ) :
            _index1(0),
            _index2(0)
        {
            _distance = 1;
        }

        ordered_sample_pair (
            const unsigned long idx1,
            const unsigned long idx2
        )
        {
            _distance = 1;
            _index1 = idx1;
            _index2 = idx2;
        }

        ordered_sample_pair (
            const unsigned long idx1,
            const unsigned long idx2,
            const double dist
        )
        {
            _distance = dist;
            _index1 = idx1;
            _index2 = idx2;
        }

        const unsigned long& index1 (
        ) const { return _index1; }

        const unsigned long& index2 (
        ) const { return _index2; }

        const double& distance (
        ) const { return _distance; }

    private:
        unsigned long _index1;
        unsigned long _index2;
        double _distance;
    };

// ----------------------------------------------------------------------------------------

    inline bool operator == (
        const ordered_sample_pair& a,
        const ordered_sample_pair& b
    )
    {
        return a.index1() == b.index1() && a.index2() == b.index2();
    }

    inline bool operator != (
        const ordered_sample_pair& a,
        const ordered_sample_pair& b
    )
    {
        return !(a == b);
    }

// ----------------------------------------------------------------------------------------

    inline void serialize (
        const ordered_sample_pair& item,
        std::ostream& out
    )
    {
        try
        {
            serialize(item.index1(),out);
            serialize(item.index2(),out);
            serialize(item.distance(),out);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while serializing object of type ordered_sample_pair");
        }
    }

    inline void deserialize (
        ordered_sample_pair& item,
        std::istream& in
    )
    {
        try
        {
            unsigned long idx1, idx2;
            double dist;

            deserialize(idx1,in);
            deserialize(idx2,in);
            deserialize(dist,in);
            item = ordered_sample_pair(idx1, idx2, dist);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while deserializing object of type ordered_sample_pair");
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_ORDERED_SAMPLE_PaIR_Hh_


dlib C++ Library - sample_pair.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SAMPLE_PaIR_Hh_
#define DLIB_SAMPLE_PaIR_Hh_

#include "sample_pair_abstract.h"
#include <limits>
#include "../serialize.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class sample_pair
    {
    public:
        sample_pair(
        ) :
            _index1(0),
            _index2(0)
        {
            _distance = 1;
        }

        sample_pair (
            const unsigned long idx1,
            const unsigned long idx2
        )
        {
            _distance = 1;
            if (idx1 < idx2)
            {
                _index1 = idx1;
                _index2 = idx2;
            }
            else
            {
                _index1 = idx2;
                _index2 = idx1;
            }
        }

        sample_pair (
            const unsigned long idx1,
            const unsigned long idx2,
            const double dist
        )
        {
            _distance = dist;
            if (idx1 < idx2)
            {
                _index1 = idx1;
                _index2 = idx2;
            }
            else
            {
                _index1 = idx2;
                _index2 = idx1;
            }
        }

        const unsigned long& index1 (
        ) const { return _index1; }

        const unsigned long& index2 (
        ) const { return _index2; }

        const double& distance (
        ) const { return _distance; }

    private:
        unsigned long _index1;
        unsigned long _index2;
        double _distance;
    };

// ----------------------------------------------------------------------------------------

    template <typename T>
    inline bool order_by_index (
        const T& a,
        const T& b
    )
    {
        return a.index1() < b.index1() || (a.index1() == b.index1() && a.index2() < b.index2());
    }

    template <typename T>
    inline bool order_by_distance (
        const T& a,
        const T& b
    )
    {
        return a.distance() < b.distance();
    }

    template <typename T>
    inline bool order_by_descending_distance (
        const T& a,
        const T& b
    )
    {
        return a.distance() > b.distance();
    }

    template <typename T>
    bool order_by_distance_and_index (
        const T& a,
        const T& b
    )
    {
        return a.distance() < b.distance() || (a.distance() == b.distance() && order_by_index(a,b));
    }

// ----------------------------------------------------------------------------------------

    inline bool operator == (
        const sample_pair& a,
        const sample_pair& b
    )
    {
        return a.index1() == b.index1() && a.index2() == b.index2();
    }

    inline bool operator != (
        const sample_pair& a,
        const sample_pair& b
    )
    {
        return !(a == b);
    }

// ----------------------------------------------------------------------------------------

    inline void serialize (
        const sample_pair& item,
        std::ostream& out
    )
    {
        try
        {
            serialize(item.index1(),out);
            serialize(item.index2(),out);
            serialize(item.distance(),out);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while serializing object of type sample_pair");
        }
    }

    inline void deserialize (
        sample_pair& item,
        std::istream& in
    )
    {
        try
        {
            unsigned long idx1, idx2;
            double dist;

            deserialize(idx1,in);
            deserialize(idx2,in);
            deserialize(dist,in);
            item = sample_pair(idx1, idx2, dist);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while deserializing object of type sample_pair");
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SAMPLE_PaIR_Hh_


dlib C++ Library - gui_core_kernel_1.cpp

// Copyright (C) 2005  Davis E. King (davis@dlib.net), Keita Mochizuki
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_GUI_CORE_KERNEL_1_CPp_
#define DLIB_GUI_CORE_KERNEL_1_CPp_
#include "../platform.h"

#ifdef WIN32

#include "gui_core_kernel_1.h"

// tell visual studio to link to the libraries we need if we are
// in fact using visual studio
#ifdef _MSC_VER
#pragma comment (lib, "gdi32.lib")
#pragma comment (lib, "comctl32.lib")
#pragma comment (lib, "user32.lib")
#pragma comment (lib, "imm32.lib")
#endif

#include <sstream>
#include "../threads.h"
#include "../assert.h"
#include "../queue.h"
#include "../sync_extension.h"
#include "../queue.h"
#include "../logger.h"
#include <cmath>
#include <vector>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    namespace gui_core_kernel_1_globals
    {

        struct user_event_type
        {
            HWND w;
            void* p;
            int i;
        };

        typedef sync_extension<binary_search_tree<HWND,base_window*>::kernel_1a>::kernel_1a window_table_type;
        typedef sync_extension<queue<user_event_type,memory_manager<char>::kernel_1b>::kernel_2a_c>::kernel_1a queue_of_user_events;

        enum USER_OFFSETS
        {
            CREATE_WINDOW,
            DESTROY_WINDOW,
            SET_ACTIVE_WINDOW,
            QUIT_EVENT_HANDLER_THREAD,
            USER_EVENTS_READY,
            CALL_MOVE_WINDOW,
            SHOW_WINDOW_SHOW,
            SHOW_WINDOW_HIDE,
            CALL_SET_WINDOW_TITLE
        };

    // ----------------------------------------------------------------------------------------

        const shared_ptr_thread_safe<dlib::mutex>& global_mutex()
        {
            static shared_ptr_thread_safe<dlib::mutex> m(new dlib::mutex);
            return m;
        }

        class event_handler_thread : public threaded_object
        {
        public:

            enum et_state
            {
                uninitialized,
                initialized,
                failure_to_init
            };

            et_state status;

            queue_of_user_events user_events;
            queue_of_user_events user_events_temp;
            logger dlog;

            HINSTANCE hInstance;
            HWND helper_window;
            const TCHAR* window_class_name;

            bool quit_windows_loop;
            bool set_window_title_done;
            std::wstring window_title;
            bool move_window_done;
            HWND move_window_hwnd;
            int move_window_width;
            int move_window_height;
            int move_window_x;
            int move_window_y;
            bool request_new_window;
            DWORD dwStyle;
            HWND new_window;
            bool in_ime_composition;
            bool event_thread_started;
            // the window_table.get_mutex() mutex locks the above 11 variables

            // this variable holds a mapping from window handles to the base_window
            // objects which represent them.  Note that this objects mutex is always locked
            // when inside the event loop.
            window_table_type window_table;
            rsignaler window_close_signaler;
            rsignaler et_signaler;

            // note that this is the thread that will perform all the event
            // processing.
            thread_id_type event_thread_id;

            shared_ptr_thread_safe<dlib::mutex> reference_to_global_mutex;

            event_handler_thread(
            ) :
                dlog("dlib.gui_core"),
                hInstance(0),
                helper_window(0),
                window_class_name(TEXT ("w3049u6qc2d94thw9m34f4we0gvwa3-tgkser0-b9gm 05")),
                quit_windows_loop(false),
                set_window_title_done(true),
                move_window_done(true),
                move_window_hwnd(0),
                move_window_width(0),
                move_window_height(0),
                move_window_x(0),
                move_window_y(0),
                request_new_window(false),
                dwStyle(0),
                new_window(0),
                in_ime_composition(false),
                event_thread_started(false),
                window_close_signaler(window_table.get_mutex()),
                et_signaler(window_table.get_mutex()),
                reference_to_global_mutex(global_mutex())
            {
                status = uninitialized;
            }

            void start_event_thread (
            )
            /*!
                we can't call this function from this objects constructor because
                starting the event thread in windows involves sending messages to the
                WndProc() and that requires this object to be fully constructed.
            !*/
            {

                if (event_thread_started == false)
                {
                    auto_mutex M(window_table.get_mutex());
                    if (event_thread_started == false)
                    {
                        event_thread_started = true;
                        // start up the event handler thread
                        start();

                        // wait for the event thread to get up and running
                        while (status == uninitialized)
                            et_signaler.wait();

                        if (status == failure_to_init)
                            throw gui_error("Failed to start event thread");
                    }
                }
            }

            ~event_handler_thread ()
            {
                using namespace gui_core_kernel_1_globals;

                if (is_alive())
                {
                    if (PostMessage(helper_window,WM_USER+QUIT_EVENT_HANDLER_THREAD,0,0)==0)
                    {
                        dlog << LWARN << "Unable to schedule function for execution in event handling thread.";
                        // No point calling wait() here since the thread isn't going to
                        // terminate gracefully in this case.  So we just let the program
                        // end as it will and hope for the best.
                    }
                    else
                    {
                        // wait for the event handler thread to terminate.
                        wait();
                    }
                }

            }

        private:

            void thread (
            )
            {
                event_thread_id = get_thread_id();

                hInstance = GetModuleHandle(NULL);
                if (hInstance == NULL)
                {
                    dlog << LFATAL << "Error gathering needed resources";

                    // signal that an error has occurred
                    window_table.get_mutex().lock();
                    status = failure_to_init;
                    et_signaler.broadcast();
                    window_table.get_mutex().unlock();
                    return;
                }

                // register the main window class
                WNDCLASS     wndclass ;

                wndclass.style         = CS_DBLCLKS;
                wndclass.lpfnWndProc   = dlib::gui_core_kernel_1_globals::WndProc ;
                wndclass.cbClsExtra    = 0 ;
                wndclass.cbWndExtra    = 0 ;
                wndclass.hInstance     = hInstance ;
                wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
                wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
                wndclass.hbrBackground = 0;
                wndclass.lpszMenuName  = NULL ;
                wndclass.lpszClassName = window_class_name ;

                if (!RegisterClass (&wndclass))
                {
                    dlog << LFATAL << "Error registering window class";

                    // signal that an error has occurred
                    window_table.get_mutex().lock();
                    status = failure_to_init;
                    et_signaler.broadcast();
                    window_table.get_mutex().unlock();
                    return;
                }

                // make the helper window that is used to trigger events in the
                // event handler loop from other threads
                TCHAR nothing[] = TEXT("");
                helper_window = CreateWindow(window_class_name,nothing,WS_DISABLED,0,0,0,0,HWND_MESSAGE,NULL,hInstance,NULL);
                if (helper_window == NULL)
                {
                    dlog << LFATAL << "Error gathering needed resources";

                    // signal that an error has occurred
                    window_table.get_mutex().lock();
                    status = failure_to_init;
                    et_signaler.broadcast();
                    window_table.get_mutex().unlock();
                    return;
                }

                // signal that the event thread is now up and running
                window_table.get_mutex().lock();
                status = initialized;
                et_signaler.broadcast();
                window_table.get_mutex().unlock();

                // start the event handler loop.
                /*
                    A note about this quit_windows_loop thing.  If the user is holding
                    the mouse button down on the title bar of a window it will cause
                    the PostQuitMessage() function to be ignored!!  This extra bool
                    is a work around to prevent that from happening.
                */
                MSG msg;
                while (GetMessage (&msg, NULL, 0, 0) &&
                       quit_windows_loop == false)
                {
                    TranslateMessage (&msg) ;
                    DispatchMessage (&msg) ;
                }
            }
        };

        // Do all this just to make sure global_mutex() is initialized at program start
        // and thus hopefully before any threads have the chance to startup and call
        // global_data() concurrently.
        struct call_global_mutex { call_global_mutex() { global_mutex(); } };
        static call_global_mutex call_global_mutex_instance;

        const shared_ptr_thread_safe<event_handler_thread>& global_data()
        {
            auto_mutex M(*global_mutex());
            static shared_ptr_thread_safe<event_handler_thread> p;
            if (p.get() == 0)
            {
                p.reset(new event_handler_thread());
                M.unlock();
                p->start_event_thread();
            }
            return p;
        }

    // ----------------------------------------------------------------------------------------

        struct ebh_param
        {
            std::string text;
            std::string title;
        };

        static void error_box_helper(void* param)
        {
            ebh_param& p = *static_cast<ebh_param*>(param);
#ifdef UNICODE
            MessageBox (NULL,  convert_mbstring_to_wstring(p.text).c_str(),
                        convert_mbstring_to_wstring(p.title).c_str(), MB_OK|MB_ICONERROR|MB_SYSTEMMODAL
                        );
#else
            MessageBox (NULL,  p.text.c_str(),
                        p.title.c_str(), MB_OK|MB_ICONERROR|MB_SYSTEMMODAL
                        );
#endif
            delete &p;
        }

        static void error_box (
            const char* title,
            const char* text,
            bool nonblocking = false
        )
        {
            try
            {
                if (nonblocking)
                {
                    ebh_param* param = new ebh_param;
                    param->text = text;
                    param->title = title;
                    dlib::create_new_thread(error_box_helper,param);
                }
                else
                {
#ifdef UNICODE
                    MessageBox (NULL, convert_mbstring_to_wstring(text).c_str(),
                                convert_mbstring_to_wstring(title).c_str(),
                                MB_OK|MB_ICONERROR|MB_SYSTEMMODAL
                                );
#else
                    MessageBox (NULL,  text,
                                title, MB_OK|MB_ICONERROR|MB_SYSTEMMODAL
                                );
#endif
                }
            }
            catch (...)
            {
                // we are totally screwed if this happens so just quit
                exit(0);
            }
        }

    // ----------------------------------------------------------------------------------------

        static bool map_keys (
            unsigned long keycode,
            bool shift,
            bool caps,
            unsigned long& result,
            bool& is_printable
        )
        /*!
            requires
                - if (shift was down for this key) then
                    - shift == true
                - if (caps lock was on for this key) then
                    - caps == true
                - keycode == the keycode from windows that we are to process
                - keycode < keyboard_keys_size
            ensures
                - if (this key should be ignored) then
                    - returns false
                - else
                    - returns true
                    - #is_printable == true if result is a printable ascii character
                    - #result == the keycode converted into the proper number to tbe
                      returned by the event handler.
        !*/
        {
            is_printable = true;

            if (keycode <= '9' && keycode >= '0')
            {
                result = keycode;
                if (shift)
                {
                    switch (result)
                    {
                    case '0': result = ')'; break;
                    case '1': result = '!'; break;
                    case '2': result = '@'; break;
                    case '3': result = '#'; break;
                    case '4': result = '$'; break;
                    case '5': result = '%'; break;
                    case '6': result = '^'; break;
                    case '7': result = '&'; break;
                    case '8': result = '*'; break;
                    case '9': result = '('; break;
                    }
                }
            }
            else if (keycode <= 'Z' && keycode >= 'A')
            {
                result = keycode;

                // make the result lower case if we need to.
                if ((shift && caps) || (!caps && !shift))
                    result = result - 'A' + 'a';
            }
            else
            {
                switch (keycode)
                {
                case VK_BACK:
                    is_printable = false;
                    result = base_window::KEY_BACKSPACE;
                    break;

                case VK_SHIFT:
                    is_printable = false;
                    result = base_window::KEY_SHIFT;
                    break;

                case VK_CONTROL:
                    is_printable = false;
                    result = base_window::KEY_CTRL;
                    break;

                case VK_MENU:
                    is_printable = false;
                    result = base_window::KEY_ALT;
                    break;

                case VK_PAUSE:
                    is_printable = false;
                    result = base_window::KEY_PAUSE;
                    break;

                case VK_CAPITAL:
                    is_printable = false;
                    result = base_window::KEY_CAPS_LOCK;
                    break;

                case VK_ESCAPE:
                    is_printable = false;
                    result = base_window::KEY_ESC;
                    break;

                case VK_PRIOR:
                    is_printable = false;
                    result = base_window::KEY_PAGE_UP;
                    break;

                case VK_NEXT:
                    is_printable = false;
                    result = base_window::KEY_PAGE_DOWN;
                    break;

                case VK_END:
                    is_printable = false;
                    result = base_window::KEY_END;
                    break;

                case VK_HOME:
                    is_printable = false;
                    result = base_window::KEY_HOME;
                    break;

                case VK_LEFT:
                    is_printable = false;
                    result = base_window::KEY_LEFT;
                    break;

                case VK_RIGHT:
                    is_printable = false;
                    result = base_window::KEY_RIGHT;
                    break;

                case VK_UP:
                    is_printable = false;
                    result = base_window::KEY_UP;
                    break;

                case VK_DOWN:
                    is_printable = false;
                    result = base_window::KEY_DOWN;
                    break;

                case VK_INSERT:
                    is_printable = false;
                    result = base_window::KEY_INSERT;
                    break;

                case VK_DELETE:
                    is_printable = false;
                    result = base_window::KEY_DELETE;
                    break;

                case 0x91:
                    is_printable = false;
                    result = base_window::KEY_SCROLL_LOCK;
                    break;

                case VK_F1:
                    is_printable = false;
                    result = base_window::KEY_F1;
                    break;

                case VK_F2:
                    is_printable = false;
                    result = base_window::KEY_F2;
                    break;

                case VK_F3:
                    is_printable = false;
                    result = base_window::KEY_F3;
                    break;

                case VK_F4:
                    is_printable = false;
                    result = base_window::KEY_F4;
                    break;

                case VK_F5:
                    is_printable = false;
                    result = base_window::KEY_F5;
                    break;

                case VK_F6:
                    is_printable = false;
                    result = base_window::KEY_F6;
                    break;

                case VK_F7:
                    is_printable = false;
                    result = base_window::KEY_F7;
                    break;

                case VK_F8:
                    is_printable = false;
                    result = base_window::KEY_F8;
                    break;

                case VK_F9:
                    is_printable = false;
                    result = base_window::KEY_F9;
                    break;

                case VK_F10:
                    is_printable = false;
                    result = base_window::KEY_F10;
                    break;

                case VK_F11:
                    is_printable = false;
                    result = base_window::KEY_F11;
                    break;

                case VK_F12:
                    is_printable = false;
                    result = base_window::KEY_F12;
                    break;

                case VK_SPACE:  result = ' ';  break;
                case VK_TAB:    result = '\t'; break;
                case VK_RETURN: result = '\n'; break;
                case VK_NUMPAD0:  result = '0';  break;
                case VK_NUMPAD1:  result = '1';  break;
                case VK_NUMPAD2:  result = '2';  break;
                case VK_NUMPAD3:  result = '3';  break;
                case VK_NUMPAD4:  result = '4';  break;
                case VK_NUMPAD5:  result = '5';  break;
                case VK_NUMPAD6:  result = '6';  break;
                case VK_NUMPAD7:  result = '7';  break;
                case VK_NUMPAD8:  result = '8';  break;
                case VK_NUMPAD9:  result = '9';  break;

                case VK_MULTIPLY:   result = '*';  break;
                case VK_ADD:        result = '+';  break;
                case VK_SUBTRACT:   result = '-';  break;
                case VK_DECIMAL:    result = '.';  break;
                case VK_DIVIDE:     result = '/';  break;

                case VK_OEM_1:
                    if (shift)  result = ':';
                    else        result = ';';
                    break;

                case VK_OEM_PLUS:
                    if (shift)  result = '+';
                    else        result = '=';
                    break;

                case VK_OEM_COMMA:
                    if (shift)  result = '<';
                    else        result = ',';
                    break;

                case VK_OEM_MINUS:
                    if (shift)  result = '_';
                    else        result = '-';
                    break;

                case VK_OEM_PERIOD:
                    if (shift)  result = '>';
                    else        result = '.';
                    break;

                case VK_OEM_2:
                    if (shift)  result = '?';
                    else        result = '/';
                    break;

                case VK_OEM_3:
                    if (shift)  result = '~';
                    else        result = '`';
                    break;

                case VK_OEM_4:
                    if (shift)  result = '{';
                    else        result = '[';
                    break;

                case VK_OEM_5:
                    if (shift)  result = '|';
                    else        result = '\\';
                    break;

                case VK_OEM_6:
                    if (shift)  result = '}';
                    else        result = ']';
                    break;

                case VK_OEM_7:
                    if (shift)  result = '"';
                    else        result = '\'';
                    break;

                default:
                    return false;
                }
            }

            return true;
        }

    // ------------------------------------------------------------------------------------

        LRESULT CALLBACK WndProc (
            HWND hwnd,
            UINT message,
            WPARAM wParam,
            LPARAM lParam
        )
        {
            using namespace gui_core_kernel_1_globals;
            // Make the event processing thread have a priority slightly above normal.
            // This makes the GUI smother if you do heavy processing in other threads.
            HANDLE hand = OpenThread(THREAD_ALL_ACCESS,FALSE,GetCurrentThreadId());
            SetThreadPriority(hand,THREAD_PRIORITY_ABOVE_NORMAL);
            CloseHandle(hand);

            shared_ptr_thread_safe<event_handler_thread> globals(global_data());

            window_table_type& window_table = globals->window_table;
            HWND& helper_window = globals->helper_window;

            auto_mutex M(window_table.get_mutex());

            try
            {
                std::vector<unsigned char> bitmap_buffer;

                bool is_double = false;
                unsigned long btn = base_window::NONE;

                switch (message)
                {
                    case WM_USER+QUIT_EVENT_HANDLER_THREAD:
                        if (hwnd == helper_window)
                        {
                            globals->quit_windows_loop = true;
                            PostQuitMessage(0);
                        }
                        return 0;

                    case WM_USER+DESTROY_WINDOW:
                        if (hwnd == helper_window)
                        {
                            DestroyWindow((HWND)wParam);
                        }
                        return 0;

                    case WM_USER+CALL_MOVE_WINDOW:
                        if (hwnd == helper_window)
                        {
                            MoveWindow(
                                globals->move_window_hwnd,
                                globals->move_window_x,
                                globals->move_window_y,
                                globals->move_window_width,
                                globals->move_window_height,
                                TRUE);
                            globals->move_window_done = true;
                            globals->et_signaler.broadcast();
                        }
                        return 0;

                    case WM_USER+USER_EVENTS_READY:
                        if (hwnd == helper_window)
                        {
                            // this is the signal to look in the user_events queue
                            globals->user_events.lock();
                            globals->user_events.swap(globals->user_events_temp);
                            globals->user_events.unlock();
                            globals->user_events_temp.reset();
                            // now dispatch all these user events
                            while (globals->user_events_temp.move_next())
                            {
                                base_window** win_ = window_table[globals->user_events_temp.element().w];
                                base_window* win;
                                // if this window exists in the window table then dispatch
                                // its event.
                                if (win_)
                                {
                                    win = *win_;
                                    win->on_user_event(
                                        globals->user_events_temp.element().p,
                                        globals->user_events_temp.element().i
                                    );
                                }
                            }
                            globals->user_events_temp.clear();
                        }
                        return 0;

                    case WM_USER+SET_ACTIVE_WINDOW:
                        if (hwnd == helper_window)
                        {
                            SetActiveWindow((HWND)wParam);
                        }
                        return 0;

                    case WM_USER+SHOW_WINDOW_SHOW:
                        if (hwnd == helper_window)
                        {
                            ShowWindow((HWND)wParam,SW_SHOW);
                            BringWindowToTop((HWND)wParam);
                        }
                        return 0;

                    case WM_USER+SHOW_WINDOW_HIDE:
                        if (hwnd == helper_window)
                        {
                            ShowWindow((HWND)wParam,SW_HIDE);
                        }
                        return 0;

                    case WM_USER+CALL_SET_WINDOW_TITLE:
                        if (hwnd == helper_window)
                        {
                            SetWindowTextW((HWND)wParam,globals->window_title.c_str());
                            globals->set_window_title_done = true;
                            globals->et_signaler.broadcast();
                        }
                        return 0;

                    case WM_USER+CREATE_WINDOW:
                        if (hwnd == helper_window)
                        {

                            // if this is stupposed to be a popup window then do the popup window thing
                            if (globals->dwStyle == WS_CHILD)
                            {
                                TCHAR nothing[] = TEXT("");
                                globals->new_window = CreateWindowEx (WS_EX_TOOLWINDOW,globals->window_class_name, nothing,
                                    globals->dwStyle,
                                    CW_USEDEFAULT, CW_USEDEFAULT,
                                    CW_USEDEFAULT, CW_USEDEFAULT,
                                    helper_window, NULL, globals->hInstance, NULL);
                                SetParent(globals->new_window,NULL);
                            }
                            else
                            {
                                TCHAR nothing[] = TEXT("");
                                globals->new_window = CreateWindow (globals->window_class_name, nothing,
                                    globals->dwStyle,
                                    CW_USEDEFAULT, CW_USEDEFAULT,
                                    CW_USEDEFAULT, CW_USEDEFAULT,
                                    NULL, NULL, globals->hInstance, NULL);
                            }
                            // use the helper_window to indicate that CreateWindow failed
                            if (globals->new_window == NULL)
                                globals->new_window = helper_window;
                            globals->et_signaler.broadcast();
                        }
                        return 0;

                    case WM_SYSKEYDOWN:
                    case WM_KEYDOWN:
                        {
                            if (globals->in_ime_composition) break;

                            base_window** win_ = window_table[hwnd];
                            base_window* win;
                            if (win_)
                                win = *win_;
                            else
                                break;

                            unsigned long state = 0;

                            bool shift = ((GetKeyState(VK_SHIFT)&0x8000)!=0);
                            bool ctrl = ((GetKeyState(VK_CONTROL)&0x8000)!=0);
                            bool caps = ((GetKeyState(VK_CAPITAL)&0x0001)!=0);
                            if(shift)
                                state = base_window::KBD_MOD_SHIFT;
                            if(ctrl)
                                state |= base_window::KBD_MOD_CONTROL;
                            if(caps)
                                state |= base_window::KBD_MOD_CAPS_LOCK;
                            if((GetKeyState(VK_MENU)&0x8000)!=0)
                                state |= base_window::KBD_MOD_ALT;
                            if((GetKeyState(VK_NUMLOCK)&0x0001)!=0)
                                state |= base_window::KBD_MOD_NUM_LOCK;
                            if((GetKeyState(VK_SCROLL)&0x0001)!=0)
                                state |= base_window::KBD_MOD_SCROLL_LOCK;

                            bool is_printable;
                            unsigned long result;

                            if (map_keys(wParam,shift,caps,result,is_printable))
                            {
                                // signal the keyboard event
                                win->on_keydown(result,is_printable,state);
                            }

                        }
                        break;

                        // treat the user releasing the mouse button on the non client area (e.g. the title bar)
                        // like focus being lost since that is what X11 does
                    case WM_NCLBUTTONUP:
                    case WM_NCMBUTTONUP:
                    case WM_NCRBUTTONUP:
                    case WM_SETFOCUS:
                        {
                            base_window** win_ = window_table[hwnd];
                            base_window* win;
                            if (win_)
                                win = *win_;
                            else
                                break;

                            // signal that the window is gaining focus
                            win->on_focus_gained();
                        }
                        break;

                        // treat the user clicking on the non client area (e.g. the title bar)
                        // like focus being lost since that is what X11 does
                    case WM_NCLBUTTONDBLCLK:
                    case WM_NCMBUTTONDBLCLK:
                    case WM_NCRBUTTONDBLCLK:
                    case WM_NCLBUTTONDOWN:
                    case WM_NCMBUTTONDOWN:
                    case WM_NCRBUTTONDOWN:
                    case WM_KILLFOCUS:
                        {
                            base_window** win_ = window_table[hwnd];
                            base_window* win;
                            if (win_)
                                win = *win_;
                            else
                                break;

                            // signal that the window is gaining focus
                            win->on_focus_lost();
                        }
                        break;

                    case WM_SIZE:
                        {
                            base_window** win_ = window_table[hwnd];
                            base_window* win;
                            if (win_)
                                win = *win_;
                            else
                                break;

                            // signal that the window has been resized
                            win->on_window_resized();

                        }
                        return 0;

                    case WM_MOVE:
                        {
                            base_window** win_ = window_table[hwnd];
                            base_window* win;
                            if (win_)
                                win = *win_;
                            else
                                break;

                            // signal that the window has moved
                            win->on_window_moved();

                        }
                        return 0;

                    case WM_MOUSELEAVE:
                        {
                            base_window** win_ = window_table[hwnd];
                            base_window* win;
                            if (win_)
                                win = *win_;
                            else
                                break;

                            // signal that the mouse has left the window
                            if (win->mouse_in)
                            {
                                win->on_mouse_leave();
                                win->mouse_in = false;
                            }

                        }
                        return 0;

                    case WM_MOUSEWHEEL:
                        {
                            base_window** win_ = window_table[hwnd];
                            base_window* win;
                            if (win_)
                                win = *win_;
                            else
                                break;

                            unsigned long state = 0;
                            if (wParam & MK_CONTROL)
                                state |= base_window::CONTROL;
                            if (wParam & MK_LBUTTON)
                                state |= base_window::LEFT;
                            if (wParam & MK_MBUTTON)
                                state |= base_window::MIDDLE;
                            if (wParam & MK_RBUTTON)
                                state |= base_window::RIGHT;
                            if (wParam & MK_SHIFT)
                                state |= base_window::SHIFT;

                            // signal the mouse wheel event
                            if (GET_WHEEL_DELTA_WPARAM(wParam) > 0)
                            {
                                win->on_wheel_up(state);
                            }
                            else
                            {
                                win->on_wheel_down(state);
                            }

                        }
                        return 0;

                    case WM_LBUTTONUP:
                        btn = base_window::LEFT;
                    case WM_MBUTTONUP:
                        if (btn == base_window::NONE)
                            btn = base_window::MIDDLE;
                    case WM_RBUTTONUP:
                        if (btn == base_window::NONE)
                            btn = base_window::RIGHT;
                        {
                            // release the mouse capture if the user isn't holding any
                            // other mouse buttons
                            if (!((wParam & MK_LBUTTON) | (wParam & MK_MBUTTON) | (wParam & MK_RBUTTON)))
                                ReleaseCapture();

                            base_window** win_ = window_table[hwnd];
                            base_window* win;
                            if (win_)
                                win = *win_;
                            else
                                break;

                            unsigned long state = 0;
                            if (wParam & MK_CONTROL)
                                state |= base_window::CONTROL;
                            if (wParam & MK_LBUTTON)
                                state |= base_window::LEFT;
                            if (wParam & MK_MBUTTON)
                                state |= base_window::MIDDLE;
                            if (wParam & MK_RBUTTON)
                                state |= base_window::RIGHT;
                            if (wParam & MK_SHIFT)
                                state |= base_window::SHIFT;

                            // remove the clicked button from the state
                            state &= (~btn);

                            // signal the mouse click
                            win->on_mouse_up(btn,state,GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam));

                        }
                        return 0;

                    case WM_LBUTTONDBLCLK:
                        if (btn == base_window::NONE)
                            btn = base_window::LEFT;
                    case WM_MBUTTONDBLCLK:
                        if (btn == base_window::NONE)
                            btn = base_window::MIDDLE;
                    case WM_RBUTTONDBLCLK:
                        if (btn == base_window::NONE)
                            btn = base_window::RIGHT;
                        is_double = true;
                    case WM_LBUTTONDOWN:
                        if (btn == base_window::NONE)
                            btn = base_window::LEFT;
                    case WM_MBUTTONDOWN:
                        if (btn == base_window::NONE)
                            btn = base_window::MIDDLE;
                    case WM_RBUTTONDOWN:
                        if (btn == base_window::NONE)
                            btn = base_window::RIGHT;
                        {
                            SetCapture(hwnd);

                            base_window** win_ = window_table[hwnd];
                            base_window* win;
                            if (win_)
                                win = *win_;
                            else
                                break;

                            unsigned long state = 0;
                            if (wParam & MK_CONTROL)
                                state |= base_window::CONTROL;
                            if (wParam & MK_LBUTTON)
                                state |= base_window::LEFT;
                            if (wParam & MK_MBUTTON)
                                state |= base_window::MIDDLE;
                            if (wParam & MK_RBUTTON)
                                state |= base_window::RIGHT;
                            if (wParam & MK_SHIFT)
                                state |= base_window::SHIFT;

                            // remove the clicked button from the state
                            state &= (~btn);

                            // signal the mouse click
                            win->on_mouse_down(btn,state,GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam),is_double);

                        }
                        return 0;

                    case WM_MOUSEMOVE:
                        {
                            base_window** win_ = window_table[hwnd];
                            base_window* win;
                            if (win_)
                                win = *win_;
                            else
                                break;

                            unsigned long state = 0;
                            bool mouse_button_down = false;
                            if (wParam & MK_CONTROL)
                                state |= base_window::CONTROL;
                            if (wParam & MK_LBUTTON)
                            {
                                state |= base_window::LEFT;
                                mouse_button_down = true;
                            }
                            if (wParam & MK_MBUTTON)
                            {
                                mouse_button_down = true;
                                state |= base_window::MIDDLE;
                            }
                            if (wParam & MK_RBUTTON)
                            {
                                state |= base_window::RIGHT;
                                mouse_button_down = true;
                            }
                            if (wParam & MK_SHIFT)
                                state |= base_window::SHIFT;

                            // signal the mouse movement if this mouse event isn't identical to the
                            // last one we got
                            if ( GET_X_LPARAM(lParam) != win->prevx ||
                                 GET_Y_LPARAM(lParam) != win->prevy ||
                                 state != win->prev_state)
                            {
                                win->on_mouse_move(state,GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam));
                            }

                            // save the event data into the prev* member variables
                            win->prevx = GET_X_LPARAM(lParam);
                            win->prevy = GET_Y_LPARAM(lParam);
                            win->prev_state = state;

                            // The following block of code checks if the mouse is moving
                            // into or out of the window.
                            if (mouse_button_down == false)
                            {
                                // if there isn't any mouse button down then the fact that
                                // we are getting a mouse move message means it is in the
                                // window
                                if (win->mouse_in == false)
                                {
                                    win->on_mouse_enter();
                                    win->mouse_in = true;

                                    // set the tracker for the mouse
                                    TRACKMOUSEEVENT tm;
                                    tm.hwndTrack = hwnd;
                                    tm.cbSize = sizeof(tm);
                                    tm.dwFlags = TME_LEAVE;
                                    _TrackMouseEvent(&tm);
                                }
                            }
                            else if (win->mouse_in)
                            {
                                // check if the mouse is currently outside the window
                                const long mouse_x = GET_X_LPARAM(lParam);
                                const long mouse_y = GET_Y_LPARAM(lParam);
                                if (mouse_x < 0 || mouse_y < 0)
                                {
                                    // the mouse is not in the window
                                    win->mouse_in = false;
                                    win->on_mouse_leave();
                                }
                                else
                                {
                                    unsigned long width, height;
                                    win->get_size(width,height);
                                    if (mouse_x >= static_cast<long>(width) ||
                                        mouse_y >= static_cast<long>(height))
                                    {
                                        // the mouse is not in the window
                                        win->mouse_in = false;
                                        win->on_mouse_leave();
                                    }
                                }
                            }
                            else if (win->mouse_in == false)
                            {
                                // at this point we know that the mouse is moving around
                                // with some of its buttons down.  So it might be outside the window.
                                // get the window size and see if the mouse is outside
                                // it.
                                const long mouse_x = GET_X_LPARAM(lParam);
                                const long mouse_y = GET_Y_LPARAM(lParam);
                                unsigned long width, height;
                                win->get_size(width,height);
                                if (mouse_x < static_cast<long>(width) &&
                                    mouse_y < static_cast<long>(height) &&
                                    mouse_x >= 0 &&
                                    mouse_y >= 0)
                                {
                                    // The mouse has gone inside the window
                                    win->mouse_in = true;
                                    win->on_mouse_enter();

                                    // set the tracker for the mouse
                                    TRACKMOUSEEVENT tm;
                                    tm.hwndTrack = hwnd;
                                    tm.cbSize = sizeof(tm);
                                    tm.dwFlags = TME_LEAVE;
                                    _TrackMouseEvent(&tm);
                                }

                            }

                        }
                        return 0;

                    case WM_PAINT :
                        {

                            PAINTSTRUCT ps;
                            HDC   hdc = NULL;

                            hdc = BeginPaint (hwnd, &ps) ;

                            try
                            {
                                base_window** win_ = window_table[hwnd];
                                base_window* win;
                                if (win_)
                                    win = *win_;
                                else
                                    break;

                                LONG x = ps.rcPaint.left;
                                LONG y = ps.rcPaint.top;
                                LONG width = ps.rcPaint.right - x;
                                LONG height = ps.rcPaint.bottom - y;

                                if (width != 0 && height != 0)
                                {

                                    BITMAPINFO bmap_info;
                                    bmap_info.bmiColors[0].rgbBlue = 0;
                                    bmap_info.bmiColors[0].rgbGreen = 0;
                                    bmap_info.bmiColors[0].rgbRed = 0;
                                    bmap_info.bmiColors[0].rgbReserved = 0;
                                    bmap_info.bmiHeader.biSize = sizeof(bmap_info.bmiHeader);
                                    bmap_info.bmiHeader.biWidth = width;
                                    bmap_info.bmiHeader.biHeight = -1*height;
                                    bmap_info.bmiHeader.biPlanes = 1;
                                    bmap_info.bmiHeader.biBitCount = 24;
                                    bmap_info.bmiHeader.biCompression = BI_RGB;
                                    bmap_info.bmiHeader.biSizeImage = 0;
                                    bmap_info.bmiHeader.biXPelsPerMeter = 0;
                                    bmap_info.bmiHeader.biYPelsPerMeter = 0;
                                    bmap_info.bmiHeader.biClrUsed = 0;
                                    bmap_info.bmiHeader.biClrImportant = 0;

                                    unsigned char* bitmap ;
                                    unsigned long size;
                                    unsigned long padding = 0;
                                    if ((width*3)%sizeof(LONG) != 0)
                                    {
                                        padding = sizeof(LONG) - (width*3)%sizeof(LONG);
                                        size = (width*3+padding)*height;
                                    }
                                    else
                                    {
                                        size = width*height*3;
                                    }

                                    if (bitmap_buffer.size() < size)
                                        bitmap_buffer.resize(size);
                                    bitmap = &bitmap_buffer[0];

                                    canvas bits(bitmap,padding,x,y,x+width-1,y+height-1);

                                    win->paint(bits);

                                    SetDIBitsToDevice (
                                        hdc,
                                        ps.rcPaint.left,
                                        ps.rcPaint.top,
                                        width,
                                        height,
                                        0,
                                        0,
                                        0,
                                        height,
                                        bitmap,
                                        &bmap_info,
                                        DIB_RGB_COLORS
                                        );
                                }

                                EndPaint (hwnd, &ps) ;

                            }
                            catch (...)
                            {
                                // make sure EndPaint is called even if an exception
                                // is thrown.
                                if (hdc != NULL)
                                    EndPaint (hwnd, &ps);
                                throw;
                            }
                        }
                        return 0 ;

                    case  WM_ERASEBKGND:
                        return 1;

                    case WM_CLOSE:
                        {
                            base_window** win_ = window_table[hwnd];
                            base_window* win;
                            if (win_)
                                win = *win_;
                            else
                                break;

                            // signal that the window is being closed
                            if (win->on_window_close() == base_window::DO_NOT_CLOSE_WINDOW)
                            {
                                DLIB_ASSERT(win->has_been_destroyed == false,
                                    "\tYou called close_window() inside the on_window_close() event but"
                                    << "\n\tthen returned DO_NOT_CLOSE_WINDOW.  You can do one or the other but not both."
                                    << "\n\tthis:     " << win
                                    );
                                // this happens if the on_window_close() callback
                                // tells us to ignore the close event.
                                return 0;
                            }
                            else
                            {
                                if (window_table[hwnd])
                                {
                                    window_table.destroy(hwnd);
                                    win->has_been_destroyed = true;
                                    win->hwnd = 0;
                                    globals->window_close_signaler.broadcast();
                                }
                                else
                                {
                                    // in this case the window must have self destructed by
                                    // calling delete this;
                                    return 0;
                                }
                            }

                        }
                        return DefWindowProc (hwnd, message, wParam, lParam);

                    case WM_IME_STARTCOMPOSITION:
                        globals->in_ime_composition = true;
                        break;

                    case WM_IME_COMPOSITION:
                        {
                        globals->in_ime_composition = false;
                        base_window** win_ = window_table[hwnd];
                        base_window* win;
                        if (win_)
                            win = *win_;
                        else
                            break;
                        HIMC hImc = ImmGetContext(hwnd);
                        if (lParam & GCS_RESULTSTR){
                            WCHAR wc;
                            LONG bufbyte = ImmGetCompositionStringW(hImc, GCS_RESULTSTR, &wc, 0);
                            if (bufbyte != IMM_ERROR_NODATA && bufbyte != IMM_ERROR_GENERAL){
                                bufbyte += sizeof(WCHAR);

                                WCHAR *buf = new WCHAR[bufbyte / sizeof(WCHAR)];
                                ImmGetCompositionStringW(hImc, GCS_RESULTSTR, buf, bufbyte);
                                buf[bufbyte / sizeof(WCHAR) - 1] = L'\0';

                                // signal the putstring event
                                win->on_string_put(std::wstring(buf));
                                delete [] buf;
                            }
                        }
                        ImmReleaseContext(hwnd, hImc);
                        }
                        break;

                    default:
                        break;

                } // switch (message)

            }
            catch (std::exception& e)
            {
                error_box("Exception thrown in event handler",e.what());
                globals->quit_windows_loop = true;
            }
            catch (...)
            {
                error_box("Exception thrown in event handler","Unknown Exception type.");
                globals->quit_windows_loop = true;
            }

            return DefWindowProc (hwnd, message, wParam, lParam) ;

        }

    // ----------------------------------------------------------------------------------------

        void show_window (
            HWND hwnd
        )
        {
            using namespace gui_core_kernel_1_globals;
            PostMessage(global_data()->helper_window,WM_USER+SHOW_WINDOW_SHOW,(WPARAM)hwnd,0);
        }

    // ----------------------------------------------------------------------------------------

        void hide_window (
            HWND hwnd
        )
        {
            using namespace gui_core_kernel_1_globals;
            PostMessage(global_data()->helper_window,WM_USER+SHOW_WINDOW_HIDE,(WPARAM)hwnd,0);
        }

    // ----------------------------------------------------------------------------------------

        void give_window_focus (
            HWND hwnd
        )
        /*!
            ensures
                - calls SetActiveWindow(hwnd) from the event handling thread.
        !*/
        {
            using namespace gui_core_kernel_1_globals;
            PostMessage(global_data()->helper_window,WM_USER+SET_ACTIVE_WINDOW,(WPARAM)hwnd,0);
        }

    // ----------------------------------------------------------------------------------------

        void destroy_window (
            HWND hwnd
        )
        /*!
            ensures
                - calls DestroyWindow(hwnd) from the event handling thread.
        !*/
        {
            using namespace gui_core_kernel_1_globals;
            PostMessage(global_data()->helper_window,WM_USER+DESTROY_WINDOW,(WPARAM)hwnd,0);
        }

    // ----------------------------------------------------------------------------------------

        HWND make_window (
            DWORD dwStyle_
        )
        /*!
            ensures
                - creates a window by calling CreateWindow and passes on the
                  dwStyle argument.
                - returns the HWND that is returned by CreateWindow
                - ensures that CreateWindow is called from the event handler thread
                - if (it was unable to create a window) then
                    - returns NULL or helper_window
        !*/
        {
            using namespace gui_core_kernel_1_globals;
            shared_ptr_thread_safe<event_handler_thread> globals(global_data());
            // if we are running in the event handling thread then just call
            // CreateWindow directly
            if (get_thread_id() == globals->event_thread_id)
            {
                // if this is stupposed to be a popup window then do the popup window thing
                if (dwStyle_ == WS_CHILD)
                {
                    TCHAR nothing[] = TEXT("");
                    HWND tmp = CreateWindowEx (WS_EX_TOOLWINDOW|WS_EX_TOPMOST, globals->window_class_name, nothing,
                            dwStyle_,
                            CW_USEDEFAULT, CW_USEDEFAULT,
                            CW_USEDEFAULT, CW_USEDEFAULT,
                            globals->helper_window, NULL, globals->hInstance, NULL);
                    SetParent(tmp,NULL);
                    return tmp;
                }
                else
                {
                    TCHAR nothing[] = TEXT("");
                    return CreateWindow (globals->window_class_name, nothing,
                            dwStyle_,
                            CW_USEDEFAULT, CW_USEDEFAULT,
                            CW_USEDEFAULT, CW_USEDEFAULT,
                            NULL, NULL, globals->hInstance, NULL);
                }
            }
            else
            {
                auto_mutex M(globals->window_table.get_mutex());
                // wait for our chance to make a new window request
                while (globals->request_new_window)
                    globals->et_signaler.wait();

                globals->dwStyle = dwStyle_;
                if (PostMessage(globals->helper_window,WM_USER+CREATE_WINDOW,0,0)==0)
                {
                    throw gui_error("Unable to schedule function for execution in event handling thread.");
                }

                // wait for our request to be serviced
                while (globals->new_window == NULL)
                    globals->et_signaler.wait();

                HWND temp = globals->new_window;
                globals->new_window = NULL;
                globals->request_new_window = false;
                globals->et_signaler.broadcast();

                // if make_window() returns the helper_window then it means it failed
                // to make a new window
                if (temp == globals->helper_window)
                    temp = NULL;

                return temp;
            }
        }

    // ------------------------------------------------------------------------------------

    } // end namespace gui_core_kernel_1_globals

// ----------------------------------------------------------------------------------------

    void canvas::
    fill (
        unsigned char red_,
        unsigned char green_,
        unsigned char blue_
    ) const
    {
        const unsigned long red = red_;
        const unsigned long green = green_;
        const unsigned long blue = blue_;

        const LONG block1 = (blue<<24) | (red<<16) | (green<<8) | blue;
        const LONG block2 = (green<<24) | (blue<<16) | (red<<8) | green;
        const LONG block3 = (red<<24) | (green<<16) | (blue<<8) | red;

        // remember that row_width is a multiple of 4 because windows
        // requires that all bitmaps have row widths that are multiples of 4.
        unsigned long size = row_width/4;
        for (unsigned long i = 0; i < height_; ++i)
        {
            unsigned long padding = size%3;
            LONG* start = reinterpret_cast<LONG*>(bits+row_width*i);
            LONG* end = reinterpret_cast<LONG*>(start) + size - padding;
            while (start != end)
            {
                *start = block1;
                ++start;
                *start = block2;
                ++start;
                *start = block3;
                ++start;
            }
            if (padding)
            {
                *start = block1;
                ++start;
                --padding;
            }
            if (padding)
            {
                *start = block2;
            }
        }
    }

// ----------------------------------------------------------------------------------------

    void base_window::
    trigger_user_event (
        void* p,
        int i
    )
    {
        using namespace gui_core_kernel_1_globals;

        user_event_type e;
        e.w = hwnd;
        e.p = p;
        e.i = i;
        {
            auto_mutex M(globals->user_events.get_mutex());
            globals->user_events.enqueue(e);
        }

        if (PostMessage(globals->helper_window,WM_USER+USER_EVENTS_READY,0,0)==0)
        {
            throw gui_error("Unable to schedule function for execution in event handling thread.");
        }
    }

// ----------------------------------------------------------------------------------------

    base_window::
    base_window (
        bool resizable,
        bool undecorated
    ) :
        globals(gui_core_kernel_1_globals::global_data()),
        has_been_destroyed(false),
        prevx(-1),
        prevy(-1),
        prev_state(0),
        wm(globals->window_table.get_mutex())
    {
        using namespace gui_core_kernel_1_globals;
        DLIB_ASSERT(!(undecorated == true && resizable == true),
            "\tbase_window::base_window()"
            << "\n\tThere is no such thing as an undecorated window that is resizable by the user."
            << "\n\tthis:     " << this
            );

        if (resizable)
            style = WS_OVERLAPPEDWINDOW;
        else if (undecorated)
            style = WS_CHILD;
        else
            style = WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME ^ WS_MAXIMIZEBOX;

        hwnd = gui_core_kernel_1_globals::make_window(style);

        if (hwnd == NULL)
            throw gui_error("unable to create base_window");

        auto_mutex M(wm);

        mouse_in = false;

        HWND temp = hwnd;
        base_window* ttemp = this;
        globals->window_table.add(temp,ttemp);
    }

// ----------------------------------------------------------------------------------------

    base_window::
    ~base_window (
    )
    {
        using namespace gui_core_kernel_1_globals;
        close_window();
    }

// ----------------------------------------------------------------------------------------

    void base_window::
    close_window (
    )
    {
        using namespace gui_core_kernel_1_globals;
        auto_mutex M(wm);
        if (has_been_destroyed == false)
        {
            // do this just to make sure no one tries to call this window's
            // calbacks.
            globals->window_table.destroy(hwnd);
            gui_core_kernel_1_globals::destroy_window(hwnd);
            hwnd = 0;
            has_been_destroyed = true;
            globals->window_close_signaler.broadcast();
        }
    }

// ----------------------------------------------------------------------------------------

    void base_window::
    wait_until_closed (
    ) const
    {
        using namespace gui_core_kernel_1_globals;
        auto_mutex M(wm);
        while (has_been_destroyed == false)
            globals->window_close_signaler.wait();
    }

// ----------------------------------------------------------------------------------------

    bool base_window::
    is_closed (
    ) const
    {
        auto_mutex M(wm);
        return has_been_destroyed;
    }

// ----------------------------------------------------------------------------------------

    void base_window::
    set_title (
        const std::string &title
    )
    {
        set_title(convert_mbstring_to_wstring(title));
    }

    void base_window::
    set_title (
        const ustring &title
    )
    {
        set_title(convert_utf32_to_wstring(title));
    }

    void base_window::
    set_title (
        const std::wstring& title
    )
    {
        using namespace gui_core_kernel_1_globals;

        auto_mutex M(wm);
        if (has_been_destroyed == true)
            return;

        // call the SetWindowText function with our arguments but make sure it is from
        // the event thread.  We have to do this because the SetWindowText() apparently blocks
        // until something happens in the event thread so we have to
        // do this to avoid possible deadlocks.
        if (get_thread_id() == globals->event_thread_id)
        {
            SetWindowTextW(hwnd,title.c_str());
        }
        else
        {
            globals->window_title = title;
            globals->set_window_title_done = false;

            if (PostMessage(globals->helper_window,WM_USER+CALL_SET_WINDOW_TITLE,(WPARAM)hwnd,0)==0)
            {
                throw gui_error("Unable to schedule SetWindowText function for execution in event handling thread.");
            }

            // wait for any SetWindowText() calls to finish
            while (globals->set_window_title_done == false)
                globals->et_signaler.wait();
        }
    }

// ----------------------------------------------------------------------------------------

    void base_window::
    show (
    )
    {
        using namespace gui_core_kernel_1_globals;
        auto_mutex M(wm);
        if (has_been_destroyed == true)
            return;

        show_window(hwnd);
        if (style != WS_CHILD)
            give_window_focus(hwnd);
    }

// ----------------------------------------------------------------------------------------

    void base_window::
    hide(
    )
    {
        using namespace gui_core_kernel_1_globals;
        auto_mutex M(wm);
        if (has_been_destroyed == true)
            return;

        hide_window(hwnd);
    }

// ----------------------------------------------------------------------------------------

    void base_window::
    set_size (
        int width_,
        int height_
    )
    {
        using namespace gui_core_kernel_1_globals;
        auto_mutex M(wm);
        if (has_been_destroyed == true)
            return;

        if (get_thread_id() == globals->event_thread_id)
        {
            RECT info;
            GetWindowRect(hwnd,&info);

            int x = info.left;
            int y = info.top;
            int width;
            int height;

            RECT rect;
            rect.top = 0;
            rect.left = 0;
            rect.bottom = height_;
            rect.right = width_;
            AdjustWindowRectEx(&rect,style,FALSE,0);

            width = std::abs(rect.right - rect.left);
            height = std::abs(rect.bottom - rect.top);

            MoveWindow(
                hwnd,
                x,
                y,
                width,
                height,
                TRUE);
        }
        else
        {
            RECT info;
            GetWindowRect(hwnd,&info);

            int x = info.left;
            int y = info.top;
            int width;
            int height;

            RECT rect;
            rect.top = 0;
            rect.left = 0;
            rect.bottom = height_;
            rect.right = width_;
            AdjustWindowRectEx(&rect,style,FALSE,0);

            width = std::abs(rect.right - rect.left);
            height = std::abs(rect.bottom - rect.top);

            // call the MoveWindow function with our arguments.  We
            // have to do this because the MoveWindow() apparently blocks
            // until something happens in the event thread so we have to
            // do this to avoid possible deadlocks.
            globals->move_window_hwnd = hwnd;
            globals->move_window_x = x;
            globals->move_window_y = y;
            globals->move_window_width = width;
            globals->move_window_height = height;
            globals->move_window_done = false;

            if (PostMessage(globals->helper_window,WM_USER+CALL_MOVE_WINDOW,0,0)==0)
            {
                throw gui_error("Unable to schedule MoveWindow function for execution in event handling thread.");
            }

            // wait for any MoveWindow calls to finish
            while (globals->move_window_done == false)
                globals->et_signaler.wait();
        }

    }

// ----------------------------------------------------------------------------------------

    void base_window::
    set_pos (
        long x_,
        long y_
    )
    {
        using namespace gui_core_kernel_1_globals;
        auto_mutex M(wm);
        if (has_been_destroyed == true)
            return;

        if (get_thread_id() == globals->event_thread_id)
        {
            RECT info;
            GetWindowRect(hwnd,&info);
            int width = info.right - info.left;
            int height = info.bottom - info.top;

            MoveWindow(
                hwnd,
                x_,
                y_,
                width,
                height,
                TRUE);

        }
        else
        {
            RECT info;
            GetWindowRect(hwnd,&info);
            int width = info.right - info.left;
            int height = info.bottom - info.top;

            // call the MoveWindow function with our arguments.  We
            // have to do this because the MoveWindow() apparently blocks
            // until something happens in the event thread so we have to
            // do this to avoid possible deadlocks.
            globals->move_window_hwnd = hwnd;
            globals->move_window_x = x_;
            globals->move_window_y = y_;
            globals->move_window_width = width;
            globals->move_window_height = height;
            globals->move_window_done = false;

            if (PostMessage(globals->helper_window,WM_USER+CALL_MOVE_WINDOW,0,0)==0)
            {
                throw gui_error("Unable to schedule MoveWindow function for execution in event handling thread.");
            }

            // wait for any MoveWindow calls to finish
            while (globals->move_window_done == false)
                globals->et_signaler.wait();
        }
    }

// ----------------------------------------------------------------------------------------

    void base_window::
    get_pos (
        long& x_,
        long& y_
    )
    {
        auto_mutex M(wm);
        x_ = 0;
        y_ = 0;
        if (has_been_destroyed == true)
            return;

        POINT p;
        p.x = 0;
        p.y = 0;
        ClientToScreen(hwnd,&p);

        x_ = p.x;
        y_ = p.y;
    }

// ----------------------------------------------------------------------------------------

    void base_window::
    get_display_size (
        unsigned long& width,
        unsigned long& height
    ) const
    {
        auto_mutex M(wm);
        width = 0;
        height = 0;
        if (has_been_destroyed == true)
            return;

        RECT rc;
        GetWindowRect(hwnd, &rc);

        HMONITOR hMonitor;
        MONITORINFO mi;
        //
        // get the nearest monitor to the passed rect.
        //
        hMonitor = MonitorFromRect(&rc, MONITOR_DEFAULTTONEAREST);

        //
        // get the work area or entire monitor rect.
        //
        mi.cbSize = sizeof(mi);
        GetMonitorInfo(hMonitor, &mi);

        rc = mi.rcMonitor;

        width = static_cast<unsigned long>(rc.right - rc.left);
        height = static_cast<unsigned long>(rc.bottom - rc.top);

    }

// ----------------------------------------------------------------------------------------

    void base_window::
    get_size (
        unsigned long& width,
        unsigned long& height
    ) const
    {
        auto_mutex M(wm);
        width = 0;
        height = 0;
        if (has_been_destroyed == true)
            return;

        RECT r;
        GetClientRect(hwnd,&r);

        width = r.right - r.left;
        height = r.bottom - r.top;
    }

// ----------------------------------------------------------------------------------------

    void base_window::
    invalidate_rectangle (
        const rectangle& rect
    )
    {
        auto_mutex M(wm);
        if (rect.is_empty() == false && !has_been_destroyed)
        {
            RECT info;
            info.top = rect.top();
            info.left = rect.left();
            info.right = rect.right()+1;
            info.bottom = rect.bottom()+1;

            InvalidateRect(hwnd,&info,FALSE);
        }
    }

// ----------------------------------------------------------------------------------------

    void base_window::
    set_im_pos (
        long x,
        long y
    )
    {
        auto_mutex M(wm);
        if (has_been_destroyed == true)
            return;

        HIMC hImc = ImmGetContext(hwnd);

        COMPOSITIONFORM cf;
        cf.dwStyle = CFS_POINT;
        cf.ptCurrentPos.x = x;
        cf.ptCurrentPos.y = y;
        ImmSetCompositionWindow(hImc, &cf);
        ImmReleaseContext(hwnd, hImc);
    }

// ----------------------------------------------------------------------------------------

    void put_on_clipboard (
        const std::string& str
    )
    {
        put_on_clipboard(convert_mbstring_to_wstring(str));
    }

    void put_on_clipboard (
        const dlib::ustring& str
    )
    {
        put_on_clipboard(convert_utf32_to_wstring(str));
    }

    void put_on_clipboard (
        const std::wstring& str
    )
    {
        using namespace gui_core_kernel_1_globals;
        using namespace std;

        shared_ptr_thread_safe<event_handler_thread> globals(global_data());

        if (OpenClipboard(globals->helper_window))
        {
            EmptyClipboard();
            auto_mutex M(globals->window_table.get_mutex());

            const unsigned long newlines = count(str.begin(),str.end(),L'\n');

            HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE,(str.size()+newlines+1)*sizeof(wchar_t));
            if (mem != NULL)
            {
                wchar_t* buf = reinterpret_cast<wchar_t*>(GlobalLock(mem));

                if (buf != NULL)
                {
                    // copy str into buf while also replacing all the \n with \r\n
                    for (wstring::size_type i = 0; i < str.size(); ++i)
                    {
                        if (str[i] != L'\n')
                        {
                            *buf = str[i];
                            ++buf;
                        }
                        else
                        {
                            *buf = L'\r';
                            ++buf;
                            *buf = L'\n';
                            ++buf;
                        }
                    }
                    *buf = L'\0';
                    GlobalUnlock(mem);
                    SetClipboardData(CF_UNICODETEXT,mem);
                }
            }
            CloseClipboard();
        }
    }

// ----------------------------------------------------------------------------------------

    void get_from_clipboard (
        std::string& str
    )
    {
        std::wstring wstr;
        get_from_clipboard(wstr);
        str = convert_wstring_to_mbstring(wstr);
    }

    void get_from_clipboard (
        dlib::ustring& str
    )
    {
        std::wstring wstr;
        get_from_clipboard(wstr);
        str = convert_wstring_to_utf32(wstr);
    }

    void get_from_clipboard (
        std::wstring& str
    )
    {
        using namespace gui_core_kernel_1_globals;
        using namespace std;
        shared_ptr_thread_safe<event_handler_thread> globals(global_data());

        auto_mutex M(globals->window_table.get_mutex());
        if (OpenClipboard(globals->helper_window))
        {

            HANDLE data = GetClipboardData(CF_UNICODETEXT);
            if (data != NULL)
            {
                wchar_t* buf = reinterpret_cast<wchar_t*>(GlobalLock(data));
                if (buf != 0)
                {
                    str.clear();

                    // copy the data from buf into str while also removing any '\r'
                    // characters.
                    while (*buf != L'\0')
                    {
                        if (*buf != L'\r')
                            str += *buf;
                        ++buf;
                    }

                    GlobalUnlock(data);
                }
                else
                {
                    Beep(500,500);
                }
            }

            CloseClipboard();
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // WIN32

#endif // DLIB_GUI_CORE_KERNEL_1_CPp_


dlib C++ Library - gui_core_kernel_1.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net), Keita Mochizuki
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_GUI_CORE_KERNEl_1_
#define DLIB_GUI_CORE_KERNEl_1_

#ifdef DLIB_ISO_CPP_ONLY
#error "DLIB_ISO_CPP_ONLY is defined so you can't use this OS dependent code.  Turn DLIB_ISO_CPP_ONLY off if you want to use it."
#endif

#ifdef DLIB_NO_GUI_SUPPORT
#error "DLIB_NO_GUI_SUPPORT is defined so you can't use the GUI code.  Turn DLIB_NO_GUI_SUPPORT off if you want to use it."
#endif

#include <string>
#include "../windows_magic.h"

#include <windows.h>
#include <winuser.h>
#include <windowsx.h>
#include <commctrl.h>

#include "gui_core_kernel_abstract.h"

#ifdef _MSC_VER
// Disable the following warnings for Visual Studio
//
// These two warnings have to do with converting points to and from the LONG
// type.  But both these types are 32 bits in windows so it is fine.
#pragma warning(disable: 4244; disable: 4312)
#endif

#include "../algs.h"
#include "../sync_extension.h"
#include "../binary_search_tree.h"
#include "../threads.h"
#include "../geometry/rectangle.h"
#include "../assert.h"
#include "../queue.h"
#include "../pixel.h"
#include "../unicode.h"
#include "../smart_pointers_thread_safe.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class base_window;
    namespace gui_core_kernel_1_globals
    {

        LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
        class event_handler_thread;

    }

// ----------------------------------------------------------------------------------------

    class canvas : public rectangle
    {
    public:
        struct pixel
        {
            unsigned char blue;
            unsigned char green;
            unsigned char red;
        };

        ~canvas() { }

        inline pixel* operator[] (
            unsigned long row
        ) const
        {
            DLIB_ASSERT(row < height(),
                "\tpixel* canvas::operator[]"
                << "\n\tyou have to give a row that is less than the height()"
                << "\n\tthis:     " << this
                << "\n\trow:      " << row
                << "\n\theight(): " << height()
                );
            unsigned char* temp = bits + row_width*row;
            return reinterpret_cast<pixel*>(temp);
        }

        void fill (
            unsigned char red_,
            unsigned char green_,
            unsigned char blue_
        ) const;

    private:

        friend LRESULT CALLBACK gui_core_kernel_1_globals::WndProc (HWND, UINT, WPARAM, LPARAM);

        canvas (
            unsigned char* bits_,
            unsigned long padding_,
            unsigned long left_,
            unsigned long top_,
            unsigned long right_,
            unsigned long bottom_
        ) :
            rectangle(left_,top_,right_,bottom_),
            bits(bits_),
            width_(width()),
            height_(height()),
            row_width(width_*3+padding_)
        {}

        // restricted functions
        canvas();        // normal constructor
        canvas(canvas&);        // copy constructor
        canvas& operator=(canvas&);    // assignment operator

        unsigned char* const bits;
        const unsigned long width_;
        const unsigned long height_;
        const unsigned long row_width;
    };

    template <>
    struct pixel_traits<canvas::pixel>
    {
        const static bool rgb  = true;
        const static bool rgb_alpha  = false;
        const static bool grayscale = false;
        const static bool hsi = false;
        const static long num = 3;
        typedef unsigned char basic_pixel_type;
        static basic_pixel_type min() { return 0;}
        static basic_pixel_type max() { return 255;}
        const static bool is_unsigned = true;
        const static bool has_alpha = false;
    };

// ----------------------------------------------------------------------------------------

    void put_on_clipboard (
        const std::string& str
    );

    void put_on_clipboard (
        const std::wstring& str
    );

    void put_on_clipboard (
        const dlib::ustring& str
    );

// ----------------------------------------------------------------------------------------

    void get_from_clipboard (
        std::string& str
    );

    void get_from_clipboard (
        std::wstring& str
    );

    void get_from_clipboard (
        dlib::ustring& str
    );

// ----------------------------------------------------------------------------------------

    class base_window
    {
        friend LRESULT CALLBACK gui_core_kernel_1_globals::WndProc (HWND, UINT, WPARAM, LPARAM);
        shared_ptr_thread_safe<gui_core_kernel_1_globals::event_handler_thread> globals;

        HWND hwnd;
        DWORD style;
        bool has_been_destroyed;

        // This is true if the mouse is in this window.  false otherwise.
        // also note that this variable is only accessed from the event handling thread
        // (except for being initialized below in the constructor, but that is inside
        // the window_table mutex so it doesn't matter).
        bool mouse_in;

        // this is a copy of the last inputs we sent to the on_mouse_move() event.
        long prevx;
        long prevy;
        unsigned long prev_state;

    protected:
        const rmutex& wm;

    public:

        base_window (
            bool resizable = true,
            bool undecorated = false
        );

        virtual ~base_window (
        );

        void close_window (
        );

        bool is_closed (
        ) const;

        void set_title (
            const std::string& title
        );

        void set_title (
            const std::wstring& title
        );

        void set_title (
            const ustring& title
        );

        virtual void show (
        );

        virtual void hide(
        );

        void set_size (
            int width_,
            int height_
        );

        void set_pos (
            long x_,
            long y_
        );

        void get_pos (
            long& x_,
            long& y_
        );

        void get_size (
            unsigned long& width,
            unsigned long& height
        ) const;

        void get_display_size (
            unsigned long& width,
            unsigned long& height
        ) const;

        void invalidate_rectangle (
            const rectangle& rect
        );

        void trigger_user_event (
            void* p,
            int i
        );

        void wait_until_closed (
        ) const;

        void set_im_pos (
            long x_,
            long y_
        );

        enum on_close_return_code
        {
            DO_NOT_CLOSE_WINDOW,
            CLOSE_WINDOW
        };

        enum mouse_state_masks
        {
            NONE = 0,
            LEFT = 1,
            RIGHT = 2,
            MIDDLE = 4,
            SHIFT = 8,
            CONTROL = 16
        };

        enum keyboard_state_masks
        {
            KBD_MOD_NONE = 0,
            KBD_MOD_SHIFT = 1,
            KBD_MOD_CONTROL = 2,
            KBD_MOD_ALT = 4,
            KBD_MOD_META = 8,
            KBD_MOD_CAPS_LOCK = 16,
            KBD_MOD_NUM_LOCK = 32,
            KBD_MOD_SCROLL_LOCK = 64
        };

        enum non_printable_keyboard_keys
        {
            KEY_BACKSPACE,
            KEY_SHIFT,
            KEY_CTRL,
            KEY_ALT,
            KEY_PAUSE,
            KEY_CAPS_LOCK,
            KEY_ESC,
            KEY_PAGE_UP,
            KEY_PAGE_DOWN,
            KEY_END,
            KEY_HOME,
            KEY_LEFT,           // This is the left arrow key
            KEY_RIGHT,          // This is the right arrow key
            KEY_UP,             // This is the up arrow key
            KEY_DOWN,           // This is the down arrow key
            KEY_INSERT,
            KEY_DELETE,
            KEY_SCROLL_LOCK,

            // Function Keys
            KEY_F1,
            KEY_F2,
            KEY_F3,
            KEY_F4,
            KEY_F5,
            KEY_F6,
            KEY_F7,
            KEY_F8,
            KEY_F9,
            KEY_F10,
            KEY_F11,
            KEY_F12
        };

    protected:

        virtual on_close_return_code on_window_close(
        ){return CLOSE_WINDOW;}

        virtual void on_user_event (
            void* ,
            int
        ){}

        virtual void on_window_resized(
        ){}

        virtual void on_window_moved(
        ){}

        virtual void on_mouse_down (
            unsigned long ,
            unsigned long ,
            long ,
            long ,
            bool
        ){}

        virtual void on_mouse_up (
            unsigned long ,
            unsigned long ,
            long ,
            long
        ){}

        virtual void on_mouse_move (
            unsigned long ,
            long ,
            long
        ){}

        virtual void on_mouse_leave (
        ){}

        virtual void on_mouse_enter (
        ){}

        virtual void on_wheel_up (
            unsigned long
        ){}

        virtual void on_wheel_down (
            unsigned long
        ){}

        virtual void on_focus_gained (
        ){}

        virtual void on_focus_lost (
        ){}

        virtual void on_keydown (
            unsigned long ,
            bool ,
            unsigned long
        ){}

        virtual void on_string_put (
            const std::wstring&
        ){}

    private:

        virtual void paint (
            const canvas&
        ) =0;

        base_window(base_window&);        // copy constructor
        base_window& operator=(base_window&);    // assignment operator

    };

// ----------------------------------------------------------------------------------------

}

#ifdef NO_MAKEFILE
#include "gui_core_kernel_1.cpp"
#endif

#endif // DLIB_GUI_CORE_KERNEl_1_


dlib C++ Library - gui_core_kernel_2.cpp

// Copyright (C) 2005  Davis E. King (davis@dlib.net), Keita Mochizuki
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_GUI_CORE_KERNEL_2_CPp_
#define DLIB_GUI_CORE_KERNEL_2_CPp_
#include "../platform.h"

#ifdef POSIX

#include "gui_core_kernel_2.h"

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include <X11/Xlocale.h>
#include <X11/XKBlib.h>
#include <poll.h>
#include <iostream>
#include "../assert.h"
#include "../queue.h"
#include <cstring>
#include <cmath>
#include <X11/Xatom.h>
#include "../sync_extension.h"
#include "../logger.h"
#include <vector>
#include <set>
#include "../smart_pointers_thread_safe.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    namespace gui_core_kernel_2_globals
    {
        void init_keyboard_mod_masks();
        struct user_event_type
        {
            Window w;
            void* p;
            int i;
        };

        typedef sync_extension<queue<user_event_type,memory_manager<char>::kernel_1b>::kernel_2a_c>::kernel_1a queue_of_user_events;

        typedef sync_extension<binary_search_tree<Window,base_window*>::kernel_1a>::kernel_1a
            window_table_type;

    // ----------------------------------------------------------------------------------------

        const shared_ptr_thread_safe<dlib::mutex>& global_mutex()
        {
            static shared_ptr_thread_safe<dlib::mutex> m(new dlib::mutex);
            return m;
        }

        class event_handler_thread : public threaded_object
        {
        public:

            enum et_state
            {
                uninitialized,
                initialized,
                failure_to_init
            };

            et_state status;
            logger dlog;

            int depth;
            Display* disp;
            XIM xim;
            XIMStyle xim_style;
            Screen* screen;

            Atom delete_window;
            Window exit_window;
            std::wstring clipboard;

            int alt_mask;
            int meta_mask;
            int num_lock_mask;
            int scroll_lock_mask;

            // the mutex in this object is the global mutex used to protect everything
            // in the gui_core and gui_widgets components.
            window_table_type window_table;

            rsignaler window_close_signaler;
            rsignaler et_signaler;

            queue_of_user_events user_events;
            queue_of_user_events user_events_temp;

            shared_ptr_thread_safe<dlib::mutex> reference_to_global_mutex;

            event_handler_thread(
            ) :
                dlog("dlib.gui_core"),
                depth(0),
                disp(0),
                xim(0),
                screen(0),
                alt_mask(0),
                meta_mask(0),
                num_lock_mask(0),
                scroll_lock_mask(0),
                window_close_signaler(window_table.get_mutex()),
                et_signaler(window_table.get_mutex()),
                reference_to_global_mutex(global_mutex())
            {
                auto_mutex M(window_table.get_mutex());

                status = uninitialized;

                // start up the event handler thread
                start();

                // wait for the event thread to get up and running
                while (status == uninitialized)
                    et_signaler.wait();

                if (status == failure_to_init)
                    throw gui_error("Failed to initialize X11 resources");

                init_keyboard_mod_masks();
            }

            ~event_handler_thread ()
            {

                if (is_alive())
                {

                    if (status != failure_to_init)
                    {
                        XConfigureEvent event;
                        event.type = ConfigureNotify;
                        event.send_event = True;
                        event.display = disp;
                        event.window = exit_window;
                        event.x = 1;
                        XFlush(disp);
                        XPutBackEvent(disp,reinterpret_cast<XEvent*>(&event));
                        XFlush(disp);

                        // This should cause XNextEvent() to unblock so that it will see
                        // this ConfigureNotify event we are putting onto the event queue.
                        XSendEvent(disp,exit_window,False,0,reinterpret_cast<XEvent*>(&event));
                        XFlush(disp);

                        wait();

                        if (xim != NULL)
                        {
                            XCloseIM(xim);
                        }

                        XCloseDisplay(disp);

                    }
                    else
                    {

                        wait();
                    }
                }

            }

        private:

            void thread (
            )
            {
                using namespace std;
                using namespace dlib;
                try
                {

                    // You are supposed to call this if using XLib in a threaded program.  Note
                    // however that at one point I noticed that calling this causes a dead-lock
                    // when using XIM.  But I can't reproduce that anymore and not calling it
                    // sometimes causes XCloseDisplay() to hang.
                    if (XInitThreads() == 0)
                    {
                        dlog << LFATAL << "Unable to initialize threading support.";
                        // signal that an error has occurred
                        window_table.get_mutex().lock();
                        status = failure_to_init;
                        et_signaler.broadcast();
                        window_table.get_mutex().unlock();
                        return;
                    }

                    window_table.get_mutex().lock();
                    disp = XOpenDisplay(NULL);
                    window_table.get_mutex().unlock();
                    if (disp == 0)
                    {
                        window_table.get_mutex().lock();
                        disp = XOpenDisplay(":0.0");
                        window_table.get_mutex().unlock();
                        if (disp == 0)
                        {
                            dlog << LFATAL << "Unable to connect to the X display.";
                            // signal that an error has occurred
                            window_table.get_mutex().lock();
                            status = failure_to_init;
                            et_signaler.broadcast();
                            window_table.get_mutex().unlock();
                            return;
                        }
                    }

                    window_table.get_mutex().lock();
                    screen = DefaultScreenOfDisplay(disp);
                    depth = DefaultDepthOfScreen(screen);
                    delete_window = XInternAtom(disp,"WM_DELETE_WINDOW",1);
                    window_table.get_mutex().unlock();

                    xim = NULL;
                    // I'm disabling XIM usage all together because calling XSetICValues()
                    // in set_im_pos() randomly hangs the application (on Ubuntu 13.10 at
                    // least).
                    /*
                    window_table.get_mutex().lock();
                    std::string saved_locale(setlocale (LC_CTYPE, NULL));
                    if (setlocale( LC_CTYPE, "" ) && XSupportsLocale() && XSetLocaleModifiers(""))
                        xim = XOpenIM(disp, NULL, NULL, NULL);
                    else
                        setlocale( LC_CTYPE, saved_locale.c_str() );
                    window_table.get_mutex().unlock();
                    */
                    if (xim)
                    {
                        const static XIMStyle preedit_styles[] =
                            {XIMPreeditPosition, XIMPreeditNothing, XIMPreeditNone, 0};
                        const static XIMStyle status_styles[] =
                            {XIMStatusNothing, XIMStatusNone, 0};
                        xim_style = 0;

                        XIMStyles *xim_styles;
                        window_table.get_mutex().lock();

                        XGetIMValues (xim, XNQueryInputStyle, &xim_styles, (const void*)NULL);
                        window_table.get_mutex().unlock();
                        std::set<XIMStyle> xims;
                        for (int i = 0; i < xim_styles->count_styles; ++i){
                            xims.insert(xim_styles->supported_styles[i]);
                        }
                        for (int j = 0; status_styles[j]; ++j){
                            for (int i = 0; preedit_styles[i]; ++i){
                                xim_style = (status_styles[j] | preedit_styles[i]);
                                if (xims.count(xim_style)) break;
                            }
                            if (xim_style) break;
                        }
                        XFree(xim_styles);
                    }

                    // make this window just so we can send messages to it and trigger
                    // events in the event thread
                    XSetWindowAttributes attr;
                    window_table.get_mutex().lock();
                    exit_window = XCreateWindow(
                        disp,
                        DefaultRootWindow(disp),
                        0,
                        0,
                        10,  // this is the default width of a window
                        10,  // this is the default width of a window
                        0,
                        depth,
                        InputOutput,
                        CopyFromParent,
                        0,
                        &attr
                    );
                    window_table.get_mutex().unlock();

                    // signal that the event thread is now up and running
                    window_table.get_mutex().lock();
                    status = initialized;
                    et_signaler.broadcast();
                    window_table.get_mutex().unlock();

                    // start the event handler
                    event_handler();
                }
                catch (std::exception& e)
                {
                    cout << "\nEXCEPTION THROWN: \n" << e.what() << endl;
                    abort();
                }
                catch (...)
                {
                    cout << "UNKNOWN EXCEPTION THROWN.\n" << endl;
                    abort();
                }
            }

            void event_handler();
            void init_keyboard_mod_masks();
        };

        struct x11_base_windowstuff
        {
            Window hwnd;
            Time last_click_time;
            XIC xic;
            XFontSet fs;
            shared_ptr_thread_safe<event_handler_thread> globals;
        };

        // Do all this just to make sure global_mutex() is initialized at program start
        // and thus hopefully before any threads have the chance to startup and call
        // global_data() concurrently.
        struct call_global_mutex { call_global_mutex() { global_mutex(); } };
        static call_global_mutex call_global_mutex_instance;

        const shared_ptr_thread_safe<event_handler_thread>& global_data()
        {
            auto_mutex M(*global_mutex());
            static shared_ptr_thread_safe<event_handler_thread> p;
            if (p.get() == 0)
                p.reset(new event_handler_thread());
            return p;
        }

    // ----------------------------------------------------------------------------------------

        Bool XCheckIfEventPredicate (
            Display* ,
            XEvent* event,
            XPointer arg
        )
        /*!
            ensures
                - if (event is an Expose event for the window pointed to by arg) then
                    - returns true
                - else
                    - returns false
        !*/
        {
            if (event->type == Expose)
            {
                XExposeEvent* e = reinterpret_cast<XExposeEvent*>(event);
                Window* win= reinterpret_cast<Window*>(arg);
                if (e->window == *win)
                {
                    return 1;
                }
            }
            return 0;
        }

    // ----------------------------------------------------------------------------------------

        static bool map_keys (
            KeySym keycode,
            bool ,
            bool ,
            unsigned long& result,
            bool& is_printable
        )
        /*!
            requires
                - if (shift was down for this key) then
                    - shift == true
                - if (caps lock was on for this key) then
                    - caps == true
                - keycode == the keycode from windows that we are to process
                - keycode < keyboard_keys_size
            ensures
                - if (this key should be ignored) then
                    - returns false
                - else
                    - returns true
                    - #is_printable == true if result is a printable ascii character
                    - #result == the keycode converted into the proper number to tbe
                      returned by the event handler.
        !*/
        {
            is_printable = true;
            if ((keycode <= 'z' && keycode >= 'a') ||
                (keycode <= 'Z' && keycode >= 'A') ||
                (keycode <= '9' && keycode >= '0'))
            {
                result = keycode;
            }
            else
            {
                is_printable = false;
                switch (keycode)
                {
                case XK_Home:   result = base_window::KEY_HOME; break;
                case XK_Left:   result = base_window::KEY_LEFT; break;
                case XK_Right:  result = base_window::KEY_RIGHT; break;
                case XK_Down:   result = base_window::KEY_DOWN; break;
                case XK_Up:     result = base_window::KEY_UP; break;
                case XK_Prior:  result = base_window::KEY_PAGE_UP; break;
                case XK_Next:   result = base_window::KEY_PAGE_DOWN;     break;
                case XK_End:    result = base_window::KEY_END; break;
                case XK_Escape:    result = base_window::KEY_ESC; break;

                case XK_KP_Delete:    result = base_window::KEY_DELETE; break;
                case XK_KP_Prior:    result = base_window::KEY_PAGE_UP; break;
                case XK_KP_Next:    result = base_window::KEY_PAGE_DOWN; break;

                case XK_F1:    result = base_window::KEY_F1; break;
                case XK_F2:    result = base_window::KEY_F2; break;
                case XK_F3:    result = base_window::KEY_F3; break;
                case XK_F4:    result = base_window::KEY_F4; break;
                case XK_F5:    result = base_window::KEY_F5; break;
                case XK_F6:    result = base_window::KEY_F6; break;
                case XK_F7:    result = base_window::KEY_F7; break;
                case XK_F8:    result = base_window::KEY_F8; break;
                case XK_F9:    result = base_window::KEY_F9; break;
                case XK_F10:    result = base_window::KEY_F10; break;
                case XK_F11:    result = base_window::KEY_F11; break;
                case XK_F12:    result = base_window::KEY_F12; break;

                case XK_Shift_L:    result = base_window::KEY_SHIFT; break;
                case XK_Shift_R:    result = base_window::KEY_SHIFT; break;
                case XK_Control_L:    result = base_window::KEY_CTRL; break;
                case XK_Control_R:    result = base_window::KEY_CTRL; break;
                case XK_Caps_Lock:    result = base_window::KEY_CAPS_LOCK; break;
                case XK_Alt_L:    result = base_window::KEY_ALT; break;
                case XK_Alt_R:    result = base_window::KEY_ALT; break;

                case XK_BackSpace:    result = base_window::KEY_BACKSPACE; break;
                case XK_Delete:    result = base_window::KEY_DELETE; break;
                case XK_Scroll_Lock:    result = base_window::KEY_SCROLL_LOCK; break;
                case XK_Pause:    result = base_window::KEY_PAUSE; break;
                case XK_Insert:    result = base_window::KEY_INSERT; break;
                case XK_KP_Insert:    result = base_window::KEY_INSERT; break;

                case XK_exclam:
                    is_printable = true;
                    result = '!'; break;
                case XK_quotedbl:
                    is_printable = true;
                    result = '"'; break;
                case XK_numbersign:
                    is_printable = true;
                    result = '#'; break;
                case XK_dollar:
                    is_printable = true;
                    result = '$'; break;
                case XK_percent:
                    is_printable = true;
                    result = '%'; break;
                case XK_ampersand:
                    is_printable = true;
                    result = '&'; break;
                case XK_apostrophe:
                    is_printable = true;
                    result = '\''; break;
                case XK_parenleft:
                    is_printable = true;
                    result = '('; break;
                case XK_parenright:
                    is_printable = true;
                    result = ')'; break;
                case XK_asterisk:
                    is_printable = true;
                    result = '*'; break;
                case XK_plus:
                    is_printable = true;
                    result = '+'; break;
                case XK_comma:
                    is_printable = true;
                    result = ','; break;
                case XK_minus:
                    is_printable = true;
                    result = '-'; break;
                case XK_period:
                    is_printable = true;
                    result = '.'; break;
                case XK_slash:
                    is_printable = true;
                    result = '/'; break;
                case XK_colon:
                    is_printable = true;
                    result = ':'; break;
                case XK_semicolon:
                    is_printable = true;
                    result = ';'; break;
                case XK_less:
                    is_printable = true;
                    result = '<'; break;
                case XK_equal:
                    is_printable = true;
                    result = '='; break;
                case XK_greater:
                    is_printable = true;
                    result = '>'; break;
                case XK_question:
                    is_printable = true;
                    result = '?'; break;
                case XK_at:
                    is_printable = true;
                    result = '@'; break;
                case XK_grave:
                    is_printable = true;
                    result = '`'; break;
                case XK_underscore:
                    is_printable = true;
                    result = '_'; break;
                case XK_asciicircum:
                    is_printable = true;
                    result = '^'; break;
                case XK_bracketleft:
                    is_printable = true;
                    result = '['; break;
                case XK_backslash:
                    is_printable = true;
                    result = '\\'; break;
                case XK_bracketright:
                    is_printable = true;
                    result = ']'; break;
                case XK_asciitilde:
                    is_printable = true;
                    result = '~'; break;
                case XK_braceleft:
                    is_printable = true;
                    result = '{'; break;
                case XK_bar:
                    is_printable = true;
                    result = '|'; break;
                case XK_braceright:
                    is_printable = true;
                    result = '}'; break;

                case XK_space:
                    is_printable = true;
                    result = ' '; break;
                case XK_Return:
                    is_printable = true;
                    result = '\n'; break;
                case XK_Tab:
                    is_printable = true;
                    result = '\t'; break;
                case XK_KP_Divide:
                    is_printable = true;
                    result = '/'; break;
                case XK_KP_Decimal:
                    is_printable = true;
                    result = '.'; break;
                case XK_KP_Subtract:
                    is_printable = true;
                    result = '-'; break;
                case XK_KP_Add:
                    is_printable = true;
                    result = '+'; break;
                case XK_KP_Multiply:
                    is_printable = true;
                    result = '*'; break;
                case XK_KP_Equal:
                    is_printable = true;
                    result = '='; break;

                case XK_KP_0:
                    is_printable = true;
                    result = '0'; break;
                case XK_KP_1:
                    is_printable = true;
                    result = '1'; break;
                case XK_KP_2:
                    is_printable = true;
                    result = '2'; break;
                case XK_KP_3:
                    is_printable = true;
                    result = '3'; break;
                case XK_KP_4:
                    is_printable = true;
                    result = '4'; break;
                case XK_KP_5:
                    is_printable = true;
                    result = '5'; break;
                case XK_KP_6:
                    is_printable = true;
                    result = '6'; break;
                case XK_KP_7:
                    is_printable = true;
                    result = '7'; break;
                case XK_KP_8:
                    is_printable = true;
                    result = '8'; break;
                case XK_KP_9:
                    is_printable = true;
                    result = '9'; break;

                default:
                    return false;
                }
            }

            return true;
        }

    // ----------------------------------------------------------------------------------------

        void event_handler_thread::
        event_handler (
        )
        /*!
            ensures
                - will handle all events and event dispatching
        !*/
        {
            try
            {
                std::vector<unsigned char> bitmap_buffer;
                bool quit_event_loop = false;
                while (quit_event_loop == false)
                {
                    // get a lock on the window_table's mutex
                    auto_mutex window_table_locker(window_table.get_mutex());

                    XEvent ev;
                    memset(&ev, 0, sizeof(ev));
                    while (XPending(disp) == 0){
                        window_table.get_mutex().unlock();
                        // wait until receiving X11 next event
                        struct pollfd pfd;
                        pfd.fd = ConnectionNumber(disp);
                        pfd.events = POLLIN | POLLPRI;
                        poll(&pfd, 1, -1);

                        window_table.get_mutex().lock();
                    }
                    XNextEvent(disp,&ev);

                    // pass events to input method.
                    // if this event is needed by input method, XFilterEvent returns True
                    if (XFilterEvent(&ev, None) == True){
                        continue;
                    }

                    // if this event is for one of the windows in the window_table
                    // then get that window out of the table and put it into win.
                    XAnyEvent* _ae = reinterpret_cast<XAnyEvent*>(&ev);
                    base_window** win_ = window_table[_ae->window];
                    base_window* win = 0;
                    if (win_)
                        win = *win_;

                    // ignore messages for unmapped windows
                    if (ev.type != MapNotify && win != 0)
                    {
                        if (win->is_mapped == false)
                           continue;
                    }

                    switch (ev.type)
                    {

                    case SelectionRequest:
                        {
                            Atom a_ct = XInternAtom(disp, "COMPOUND_TEXT", False);
                            XSelectionRequestEvent* req = reinterpret_cast<XSelectionRequestEvent*>(&ev.xselectionrequest);
                            XEvent respond;

                            if (req->target == XA_STRING)
                            {
                                XChangeProperty (disp,
                                                 req->requestor,
                                                 req->property,
                                                 XA_STRING,
                                                 8,
                                                 PropModeReplace,
                                                 reinterpret_cast<const unsigned char*>(convert_wstring_to_mbstring(clipboard).c_str()),
                                                 clipboard.size()+1);
                                respond.xselection.property=req->property;
                            }
                            else if (req->target == a_ct)
                            {
                                XChangeProperty (disp,
                                                 req->requestor,
                                                 req->property,
                                                 a_ct,
                                                 sizeof(wchar_t)*8,
                                                 PropModeReplace,
                                                 reinterpret_cast<const unsigned char*>(clipboard.c_str()),
                                                 clipboard.size()+1);
                                respond.xselection.property=req->property;
                            }
                            else
                            {
                                respond.xselection.property= None;
                            }
                            respond.xselection.type= SelectionNotify;
                            respond.xselection.display= req->display;
                            respond.xselection.requestor= req->requestor;
                            respond.xselection.selection=req->selection;
                            respond.xselection.target= req->target;
                            respond.xselection.time = req->time;
                            XSendEvent (disp, req->requestor,0,0,&respond);
                            XFlush (disp);

                        } break;

                    case MapNotify:
                        {
                            if (win == 0)
                                break;

                            win->is_mapped = true;

                            if (win->resizable == false)
                            {
                                XSizeHints* hints = XAllocSizeHints();
                                hints->flags = PMinSize|PMaxSize;
                                hints->min_width = win->width;
                                hints->max_width = win->width;
                                hints->max_height = win->height;
                                hints->min_height = win->height;
                                XSetNormalHints(disp,win->x11_stuff.hwnd,hints);
                                XFree(hints);
                            }

                            if (win->has_been_resized)
                            {
                                XResizeWindow(disp,win->x11_stuff.hwnd,win->width,win->height);
                                win->has_been_resized = false;
                                win->on_window_resized();
                            }

                            if (win->has_been_moved)
                            {
                                XMoveWindow(disp,win->x11_stuff.hwnd,win->x,win->y);
                                win->has_been_moved = false;
                                win->on_window_moved();
                            }
                            XFlush(disp);

                        } break;

                    case KeyPress:
                        {
                            XKeyPressedEvent* e = reinterpret_cast<XKeyPressedEvent*>(&ev);

                            if (win == 0)
                                break;

                            unsigned long state = 0;
                            bool shift = ((e->state & ShiftMask)!=0);
                            bool ctrl = ((e->state & ControlMask)!=0);
                            bool caps = ((e->state & LockMask)!=0);
                            if(shift)
                                state |= base_window::KBD_MOD_SHIFT;
                            if(ctrl)
                                state |= base_window::KBD_MOD_CONTROL;
                            if(caps)
                                state |= base_window::KBD_MOD_CAPS_LOCK;
                            if((e->state & alt_mask)!=0)
                                state |= base_window::KBD_MOD_ALT;
                            if((e->state & meta_mask)!=0)
                                state |= base_window::KBD_MOD_META;
                            if((e->state & num_lock_mask)!=0)
                                state |= base_window::KBD_MOD_NUM_LOCK;
                            if((e->state & scroll_lock_mask)!=0)
                                state |= base_window::KBD_MOD_SCROLL_LOCK;

                            KeySym key;
                            Status status;

                            if (win->x11_stuff.xic) {
                                std::wstring wstr;
                                wstr.resize(2);
                                int len = XwcLookupString(win->x11_stuff.xic,e,&wstr[0],wstr.size(),&key,&status);
                                if (status == XBufferOverflow){
                                    wstr.resize(len);
                                    len = XwcLookupString(win->x11_stuff.xic,e,&wstr[0],wstr.size(),&key,&status);
                                }
                                if (status == XLookupChars){
                                    win->on_string_put(wstr);
                                }
                            } else {
                                char buffer[2];
                                XLookupString(e, buffer, sizeof(buffer), &key, NULL);
                                status = XLookupKeySym;
                            }

                            if (status == XLookupKeySym || status == XLookupBoth){

                                bool is_printable;
                                unsigned long result;

                                if (map_keys(key,shift,caps,result,is_printable))
                                {
                                    // signal the keyboard event
                                    win->on_keydown(result,is_printable,state);
                                }
                            }

                        } break;

                    case FocusIn:
                        {
                            if (win == 0)
                                break;

                            // signal the focus event
                            win->on_focus_gained();
                        } break;

                    case FocusOut:
                        {
                            if (win == 0)
                                break;

                            // signal the focus event
                            win->on_focus_lost();
                        } break;

                    case ButtonPress:
                    case ButtonRelease:
                        {
                            XButtonEvent* e = reinterpret_cast<XButtonEvent*>(&ev);

                            if (win == 0)
                                break;

                            unsigned long btn = base_window::NONE;
                            if (e->button == Button1)
                                btn = base_window::LEFT;
                            else if (e->button == Button3)
                                btn = base_window::RIGHT;
                            else if (e->button == Button2)
                                btn = base_window::MIDDLE;

                            unsigned long state = 0;
                            if (e->state & ControlMask)
                                state |= base_window::CONTROL;
                            if (e->state & Button1Mask)
                                state |= base_window::LEFT;
                            if (e->state & Button2Mask)
                                state |= base_window::MIDDLE;
                            if (e->state & Button3Mask)
                                state |= base_window::RIGHT;
                            if (e->state & ShiftMask)
                                state |= base_window::SHIFT;

                            // only send the event if this is a button we support
                            if (btn != (unsigned long)base_window::NONE)
                            {

                                if (ev.type == ButtonPress)
                                {
                                    bool is_double_click = false;
                                    if (win->last_click_button == btn &&
                                        std::abs((long)win->last_click_x - (long)e->x) < 5 &&
                                        std::abs((long)win->last_click_y - (long)e->y) < 5 &&
                                        e->time - win->x11_stuff.last_click_time <= 400)
                                    {
                                        // this is a double click
                                        is_double_click = true;
                                        // set this to make sure the next click can't be
                                        // interpreted as a double click
                                        win->last_click_button = base_window::NONE;
                                    }
                                    else
                                    {
                                        win->last_click_button = btn;
                                        win->last_click_x = e->x;
                                        win->last_click_y = e->y;
                                        win->x11_stuff.last_click_time = e->time;
                                    }

                                    // remove the clicked button from the state
                                    state &= (~btn);
                                    win->on_mouse_down(btn,state,e->x,e->y,is_double_click);

                                }
                                else
                                {
                                    // remove the clicked button from the state
                                    state &= (~btn);
                                    win->on_mouse_up(btn,state,e->x,e->y);
                                }
                            }
                            else if (e->button == Button4 && ev.type == ButtonPress)
                            {
                                win->on_wheel_up(state);
                            }
                            else if (e->button == Button5 && ev.type == ButtonPress)
                            {
                                win->on_wheel_down(state);
                            }

                        } break;

                    case LeaveNotify:
                        {
                            if (win == 0)
                                break;

                            win->on_mouse_leave();

                        } break;

                    case EnterNotify:
                        {
                            if (win == 0)
                                break;

                            win->on_mouse_enter();
                        } break;

                    case MotionNotify:
                        {
                            XMotionEvent* e = reinterpret_cast<XMotionEvent*>(&ev);

                            if (win == 0)
                                break;

                            unsigned long state = 0;
                            if (e->state & ControlMask)
                                state |= base_window::CONTROL;
                            if (e->state & Button1Mask)
                                state |= base_window::LEFT;
                            if (e->state & Button2Mask)
                                state |= base_window::MIDDLE;
                            if (e->state & Button3Mask)
                                state |= base_window::RIGHT;
                            if (e->state & ShiftMask)
                                state |= base_window::SHIFT;

                            win->on_mouse_move(state,e->x,e->y);

                        } break;

                    case ConfigureNotify:
                        {
                            XConfigureEvent* e = reinterpret_cast<XConfigureEvent*>(&ev);
                            if (e->window == exit_window)
                            {
                                // this is the signal to quit the event handler
                                quit_event_loop = true;
                                break;
                            }

                            if (win == 0)
                                break;

                            if (win->width != e->width ||
                                win->height != e->height ||
                                win->has_been_resized)
                            {
                                win->has_been_resized = false;
                                // this is a resize
                                win->width = e->width;
                                win->height = e->height;
                                win->on_window_resized();
                            }
                            if (win->x != e->x ||
                                win->y != e->y ||
                                win->has_been_moved)
                            {
                                win->has_been_moved = false;
                                // this is a move
                                win->x = e->x;
                                win->y = e->y;
                                win->on_window_moved();
                            }

                        } break;

                    case ClientMessage:
                        {
                            XClientMessageEvent* e = reinterpret_cast<XClientMessageEvent*>(&ev);
                            if ((Atom)e->data.l[0] == delete_window)
                            {
                                if (win == 0)
                                    break;

                                if (win->on_window_close() == base_window::DO_NOT_CLOSE_WINDOW)
                                {
                                    DLIB_ASSERT(win->has_been_destroyed == false,
                                        "\tYou called close_window() inside the on_window_close() event but"
                                        << "\n\tthen returned DO_NOT_CLOSE_WINDOW.  You can do one or the other but not both."
                                        << "\n\tthis:     " << win
                                        );
                                    // the client has decided not to close the window
                                    // after all
                                }
                                else
                                {
                                    if (window_table[e->window])
                                    {
                                        window_table.destroy(e->window);
                                        XDestroyWindow(disp,e->window);
                                        win->has_been_destroyed = true;
                                        window_close_signaler.broadcast();
                                    }
                                    else
                                    {
                                        // in this case the window must have self destructed by
                                        // calling delete this;  so we don't have to do anything.
                                    }
                                }
                            }
                        } break;

                    case Expose:
                        {
                            XExposeEvent* e = reinterpret_cast<XExposeEvent*>(&ev);

                            if (win == 0)
                                break;

                            // take all the expose events for this window out
                            XEvent etemp;
                            int x = e->x;
                            int y = e->y;
                            int width = e->width;
                            int height = e->height;

                            // What we are doing here with this loop is we are combining
                            // all of the Expose events for this window that are
                            // currently in the queue.
                            while (XCheckIfEvent(disp,&etemp,XCheckIfEventPredicate,reinterpret_cast<XPointer>(&(e->window))))
                            {
                                XExposeEvent* e2 = reinterpret_cast<XExposeEvent*>(&etemp);
                                if (e2->x < x)
                                {
                                    width += x - e2->x;
                                    x = e2->x;
                                }
                                if (e2->y < y)
                                {
                                    height += y - e2->y;
                                    y = e2->y;
                                }
                                if (e2->width + e2->x > width + x)
                                {
                                    width = e2->width + e2->x - x;
                                }
                                if (e2->height + e2->y > height + y)
                                {
                                    height = e2->height + e2->y - y;
                                }
                            }

                            // I'm not sure if this sort of thing can happen but
                            // if it does then just ignore this entire event.
                            if (width == 0 || height == 0)
                            {
                                break;
                            }

                            if (bitmap_buffer.size() < static_cast<unsigned long>(width*height*4))
                                bitmap_buffer.resize(width*height*4);

                            unsigned char* const bitmap = &bitmap_buffer[0];
                            unsigned char* const end = bitmap + width*height*4;

                            unsigned char* temp;
                            canvas c(bitmap,x,y,x+width-1,y+height-1);

                            win->paint(c);

                            // the user might have called win->close_window() and if they did
                            // then just stop right here.  We don't want to paint the window.
                            if (win->has_been_destroyed)
                                break;

                            // if the color depth we are working with isn't 24bits then we need
                            // to transform our image into whatever it is supposed to be.
                            if (depth != 24)
                            {
                                // convert this image into an 8 bit image
                                unsigned int red_bits = 0;
                                unsigned int green_bits = 0;
                                unsigned int blue_bits = 0;
                                if (depth != 16)
                                {
                                    unsigned int bits = depth/3;
                                    unsigned int extra = depth%3;
                                    red_bits = bits;
                                    green_bits = bits;
                                    blue_bits = bits;
                                    if (extra)
                                    {
                                        ++red_bits;
                                        --extra;
                                    }
                                    if (extra)
                                    {
                                        ++green_bits;
                                    }
                                }
                                else if (depth == 16)
                                {
                                    red_bits = 5;
                                    green_bits = 6;
                                    blue_bits = 5;
                                }

                                if (depth == 16)
                                {
                                    temp = bitmap;
                                    unsigned char *red, *green, *blue;
                                    while (temp != end)
                                    {
                                        blue = temp;
                                        ++temp;
                                        green = temp;
                                        ++temp;
                                        red = temp;
                                        ++temp;
                                        ++temp;

                                        const unsigned long r = static_cast<unsigned long>(*red)>>(8-red_bits);
                                        const unsigned long g = static_cast<unsigned long>(*green)>>(8-green_bits);
                                        const unsigned long b = static_cast<unsigned long>(*blue)>>(8-blue_bits);

                                        unsigned long color = (r<<(depth-red_bits))| (g<<(depth-red_bits-green_bits))| b;

                                        *blue  = (color>>0)&0xFF;
                                        *green = (color>>8)&0xFF;
                                    }
                                }
                                else if (depth < 24)
                                {
                                    temp = bitmap;
                                    unsigned char *red, *green, *blue;
                                    while (temp != end)
                                    {
                                        blue = temp;
                                        ++temp;
                                        green = temp;
                                        ++temp;
                                        red = temp;
                                        ++temp;
                                        ++temp;

                                        const unsigned long r = static_cast<unsigned long>(*red)>>(8-red_bits);
                                        const unsigned long g = static_cast<unsigned long>(*green)>>(8-green_bits);
                                        const unsigned long b = static_cast<unsigned long>(*blue)>>(8-blue_bits);

                                        unsigned long color = (b<<(depth-blue_bits))| (g<<(depth-blue_bits-green_bits))| r;

                                        *blue  = (color>>0)&0xFF;
                                        *green = (color>>8)&0xFF;
                                        *red   = (color>>16)&0xFF;
                                    }
                                }
                                else if (depth > 24)
                                {
                                    temp = bitmap;
                                    unsigned char *red, *green, *blue, *four;
                                    while (temp != end)
                                    {
                                        blue = temp;
                                        ++temp;
                                        green = temp;
                                        ++temp;
                                        red = temp;
                                        ++temp;
                                        four = temp;
                                        ++temp;

                                        const unsigned long r = static_cast<unsigned long>(*red)<<(red_bits-8);
                                        const unsigned long g = static_cast<unsigned long>(*green)<<(green_bits-8);
                                        const unsigned long b = static_cast<unsigned long>(*blue)<<(blue_bits-8);

                                        unsigned long color = (b<<(depth-blue_bits))| (g<<(depth-blue_bits-green_bits))| r;

                                        *blue  = (color>>0)&0xFF;
                                        *green = (color>>8)&0xFF;
                                        *red   = (color>>16)&0xFF;
                                        *four  = (color>>24)&0xFF;
                                    }
                                }
                            } // if (depth != 24)

                            XImage img;
                            memset(&img,0,sizeof(img));
                            img.width = width;
                            img.height = height;
                            img.depth = depth;
                            img.data = reinterpret_cast<char*>(bitmap);
                            img.bitmap_bit_order = LSBFirst;
                            img.byte_order = LSBFirst;
                            img.format = ZPixmap;
                            img.bitmap_pad = 32;
                            img.bitmap_unit = 32;
                            img.bits_per_pixel = 32;

                            XInitImage(&img);

                            GC gc = XCreateGC(disp, e->window, 0, NULL);

                            XPutImage(disp,e->window,gc,&img,0,0,x,y,width,height);

                            XFreeGC(disp,gc);
                        } break;
                    } // switch (ev.type)
                }
            }
            catch (std::exception& e)
            {
                dlog << LFATAL << "Exception thrown in event handler: " << e.what();
            }
            catch (...)
            {
                dlog << LFATAL << "Unknown exception thrown in event handler.";
            }
        }

    // ----------------------------------------------------------------------------------------

        int index_to_modmask(unsigned long n)
        {
            switch ( n )
            {
                case 0:
                    return Mod1Mask;
                case 1:
                    return Mod2Mask;
                case 2:
                    return Mod3Mask;
                case 3:
                    return Mod4Mask;
            }
            return Mod5Mask;
        }

        void event_handler_thread::
        init_keyboard_mod_masks()
        {
            XModifierKeymap* map = XGetModifierMapping( disp );
            KeyCode* codes = map->modifiermap + map->max_keypermod * Mod1MapIndex;
            for (int n = 0; n < 5 * map->max_keypermod; n++ )
            {
                if ( codes[n] == 0 )
                    continue;
                switch(XkbKeycodeToKeysym( disp, codes[n], 0, 0 ))
                {
                    case XK_Alt_L:
                        alt_mask = index_to_modmask(n / map->max_keypermod);
                        continue;
                    case XK_Alt_R:
                        if(alt_mask == 0)
                            alt_mask = index_to_modmask(n / map->max_keypermod);
                        continue;
                    case XK_Meta_L:
                    case XK_Meta_R:
                        meta_mask = index_to_modmask(n / map->max_keypermod);
                        continue;
                    case XK_Scroll_Lock:
                        scroll_lock_mask = index_to_modmask(n / map->max_keypermod);
                        continue;
                    case XK_Num_Lock:
                        num_lock_mask = index_to_modmask(n / map->max_keypermod);
                    default:
                        continue;
                }
            }
            XFreeModifiermap( map );
            if ( alt_mask == 0 )
            {
                dlog << LWARN << "Search for Alt-key faild.";
                if ( meta_mask != 0 )
                    alt_mask = meta_mask;
                else
                    alt_mask = Mod1Mask; // resort to guessing
            }
        }

    // ----------------------------------------------------------------------------------------

    } // namespace gui_core_kernel_2_globals

// ----------------------------------------------------------------------------------------

    void canvas::
    fill (
        unsigned char red_,
        unsigned char green_,
        unsigned char blue_
    ) const
    {
        pixel pixel_value;
        pixel_value.red = red_;
        pixel_value.green = green_;
        pixel_value.blue = blue_;
        pixel_value._padding = 0;

        pixel* start = reinterpret_cast<pixel*>(bits);
        pixel* end = start + width_*height_;

        while (start != end)
        {
            *start = pixel_value;
            ++start;
        }
    }

// ----------------------------------------------------------------------------------------

    void put_on_clipboard (
        const std::string& str
    )
    {
        put_on_clipboard(convert_mbstring_to_wstring(str));
    }

    void put_on_clipboard (
        const dlib::ustring& str
    )
    {
        put_on_clipboard(convert_utf32_to_wstring(str));
    }

    void put_on_clipboard (
        const std::wstring& str
    )
    {
        using namespace gui_core_kernel_2_globals;

        shared_ptr_thread_safe<event_handler_thread> globals(global_data());

        auto_mutex M(globals->window_table.get_mutex());
        globals->clipboard = str.c_str();

        XSetSelectionOwner(globals->disp,XA_PRIMARY,globals->exit_window,CurrentTime);
    }

// ----------------------------------------------------------------------------------------

    Bool clip_peek_helper (
        Display*,
        XEvent* event,
        XPointer
    )
    {
        if ( event->type == SelectionNotify)
        {
            return True;
        }
        else
        {
            return False;
        }
    }

    void get_from_clipboard (
        std::string& str
    )
    {
        std::wstring wstr;
        get_from_clipboard(wstr);
        str = convert_wstring_to_mbstring(wstr);
    }

    void get_from_clipboard (
        dlib::ustring& str
    )
    {
        std::wstring wstr;
        get_from_clipboard(wstr);
        str = convert_wstring_to_utf32(wstr);
    }

    void get_from_clipboard (
        std::wstring& str
    )
    {
        using namespace gui_core_kernel_2_globals;
        shared_ptr_thread_safe<event_handler_thread> globals(global_data());

        auto_mutex M(globals->window_table.get_mutex());
        str.clear();
        unsigned char *data = 0;
        wchar_t **plist = 0;
        Window sown;
        Atom  type;
        int format, result;
        unsigned long len, bytes_left, dummy;
        XEvent e;

        try
        {
            Atom atom_ct = XInternAtom(globals->disp, "COMPOUND_TEXT", False);
            sown = XGetSelectionOwner (globals->disp, XA_PRIMARY);
            if (sown == globals->exit_window)
            {
                // if we are copying from ourselfs then don't fool with the Xwindows junk.
                str = globals->clipboard.c_str();
            }
            else if (sown != None)
            {
                // request that the selection be copied into the XA_PRIMARY property
                // of the exit_window.  It doesn't matter what window we put it in
                // so long as it is one under the control of this process and exit_window
                // is easy to use here so that is what I'm using.
                XConvertSelection (globals->disp, XA_PRIMARY, atom_ct, XA_PRIMARY,
                                   globals->exit_window, CurrentTime);

                // This will wait until we get a SelectionNotify event which should happen
                // really soon.
                XPeekIfEvent(globals->disp,&e,clip_peek_helper,0);

                // See how much data we got
                XGetWindowProperty (globals->disp, globals->exit_window,
                                    XA_PRIMARY,    // Tricky..
                                    0, 0,         // offset - len
                                    0,        // Delete 0==FALSE
                                    AnyPropertyType,  //flag
                                    &type,        // return type
                                    &format,      // return format
                                    &len, &bytes_left,  //that
                                    &data);
                if (data)
                {
                    XFree(data);
                    data = 0;
                }
                if (bytes_left > 0 && type == atom_ct)
                {
                    XTextProperty p;
                    result = XGetWindowProperty (globals->disp, globals->exit_window,
                                                 XA_PRIMARY, 0,bytes_left,0,
                                                 AnyPropertyType, &p.encoding,&p.format,
                                                 &p.nitems, &dummy, &p.value);
                    if (result == Success && p.encoding == atom_ct)
                    {
                        int n;
                        XwcTextPropertyToTextList(globals->disp, &p, &plist, &n);
                        str = plist[0];
                    }
                    if (plist)
                    {
                        XwcFreeStringList(plist);
                        plist = 0;
                    }
                }
            }
        }
        catch (...)
        {
            if (data)
                XFree(data);
            if (plist)
            {
                XwcFreeStringList(plist);
                plist = 0;
            }
        }
    }

// ----------------------------------------------------------------------------------------

    namespace gui_core_kernel_2_globals
    {
        void trigger_user_event_threadproc (
            void*
        )
        {
            shared_ptr_thread_safe<event_handler_thread> globals(global_data());
            auto_mutex M(globals->window_table.get_mutex());

            globals->user_events.lock();
            globals->user_events.swap(globals->user_events_temp);
            globals->user_events.unlock();

            globals->user_events_temp.reset();
            // now dispatch all these user events
            while (globals->user_events_temp.move_next())
            {
                base_window** win_ = globals->window_table[globals->user_events_temp.element().w];
                base_window* win;
                // if this window exists in the window table then dispatch
                // its event.
                if (win_)
                {
                    win = *win_;
                    win->on_user_event(
                        globals->user_events_temp.element().p,
                        globals->user_events_temp.element().i
                    );
                }
            }
            globals->user_events_temp.clear();
        }
    }

    void base_window::
    trigger_user_event (
        void* p,
        int i
    )
    {
        using namespace gui_core_kernel_2_globals;
        user_event_type e;
        e.w = x11_stuff.hwnd;
        e.p = p;
        e.i = i;
        {
            shared_ptr_thread_safe<event_handler_thread> globals(global_data());
            auto_mutex M(globals->user_events.get_mutex());
            globals->user_events.enqueue(e);

            // we only need to start a thread to deal with this if there isn't already
            // one out working on the queue
            if (globals->user_events.size() == 1)
                create_new_thread (trigger_user_event_threadproc,0);
        }
    }

// ----------------------------------------------------------------------------------------

    base_window::
    base_window (
        bool resizable_,
        bool undecorated
    ) :
        x11_stuff(*(new gui_core_kernel_2_globals::x11_base_windowstuff)),
        is_mapped(false),
        resizable(resizable_),
        has_been_destroyed(false),
        has_been_resized(false),
        has_been_moved(false),
        wm(gui_core_kernel_2_globals::global_data()->window_table.get_mutex())
    {
        DLIB_ASSERT(!(undecorated == true && resizable_ == true),
            "\tbase_window::base_window()"
            << "\n\tThere is no such thing as an undecorated window that is resizable by the user."
            << "\n\tthis:     " << this
            );
        using namespace gui_core_kernel_2_globals;

        auto_mutex M(wm);

        x11_stuff.globals = global_data();

        x11_stuff.last_click_time = 0;
        last_click_x = 0;
        last_click_y = 0;
        last_click_button = NONE;

        XSetWindowAttributes attr;
        memset(&attr,'\0',sizeof(attr));

        unsigned long valuemask = 0;
        if (undecorated)
        {
            attr.override_redirect = True;
            valuemask = CWOverrideRedirect;
        }

        x11_stuff.hwnd = XCreateWindow(
                        x11_stuff.globals->disp,
                        DefaultRootWindow(x11_stuff.globals->disp),
                        0,
                        0,
                        10,  // this is the default width of a window
                        10,  // this is the default width of a window
                        0,
                        x11_stuff.globals->depth,
                        InputOutput,
                        CopyFromParent,
                        valuemask,
                        &attr
                        );

        x11_stuff.xic = NULL;
        if (x11_stuff.globals->xim)
        {
            XVaNestedList   xva_nlist;
            XPoint          xpoint;

            char **mlist;
            int mcount;
            char *def_str;
            char fontset[256];
            const long native_font_height = 12;
            sprintf(fontset, "-*-*-medium-r-normal--%lu-*-*-*-", native_font_height);
            x11_stuff.fs = XCreateFontSet(x11_stuff.globals->disp, fontset, &mlist, &mcount, &def_str);
            xpoint.x = 0;
            xpoint.y = 0;
            xva_nlist = XVaCreateNestedList(0, XNSpotLocation, &xpoint, XNFontSet, x11_stuff.fs, (const void*)NULL);
            x11_stuff.xic = XCreateIC(
                x11_stuff.globals->xim,
                XNInputStyle, x11_stuff.globals->xim_style,
                XNClientWindow, x11_stuff.hwnd,
                XNPreeditAttributes, xva_nlist,
                (const void*)NULL
                );
            XFree(xva_nlist);
            XFreeStringList(mlist);
        }

        Window temp = x11_stuff.hwnd;
        base_window* ttemp = this;
        x11_stuff.globals->window_table.add(temp,ttemp);

        // query event mask required by input method
        unsigned long event_xim = 0;
        if (x11_stuff.xic)
             XGetICValues( x11_stuff.xic, XNFilterEvents, &event_xim, (const void*)NULL );

        XSelectInput(
            x11_stuff.globals->disp,
            x11_stuff.hwnd,
            StructureNotifyMask|ExposureMask|ButtonPressMask|ButtonReleaseMask|
            PointerMotionMask|LeaveWindowMask|EnterWindowMask|KeyPressMask|
            KeyReleaseMask| FocusChangeMask | event_xim
            );

        XSetWMProtocols(
            x11_stuff.globals->disp,
            x11_stuff.hwnd,
            &x11_stuff.globals->delete_window,
            1
            );

        // these are just default values
        x = 0;
        y = 0;
        width = 10;
        height = 10;

        if (resizable == false)
        {
            XSizeHints* hints = XAllocSizeHints();
            hints->flags = PMinSize|PMaxSize;
            hints->min_width = width;
            hints->max_width = width;
            hints->max_height = height;
            hints->min_height = height;
            XSetNormalHints(x11_stuff.globals->disp,x11_stuff.hwnd,hints);
            XFree(hints);
        }
    }

// ----------------------------------------------------------------------------------------

    base_window::
    ~base_window (
    )
    {
        using namespace gui_core_kernel_2_globals;
        close_window();

        if (x11_stuff.globals->xim != NULL)
        {
            XDestroyIC(x11_stuff.xic);
            x11_stuff.xic = 0;
            XFreeFontSet(x11_stuff.globals->disp,x11_stuff.fs);
        }

        delete &x11_stuff;
    }

// ----------------------------------------------------------------------------------------

    void base_window::
    close_window (
    )
    {
        using namespace gui_core_kernel_2_globals;
        auto_mutex M(wm);
        if (has_been_destroyed == false)
        {
            has_been_destroyed = true;

            x11_stuff.globals->window_table.destroy(x11_stuff.hwnd);

            XDestroyWindow(x11_stuff.globals->disp,x11_stuff.hwnd);
            x11_stuff.hwnd = 0;
            x11_stuff.globals->window_close_signaler.broadcast();
        }
    }

// ----------------------------------------------------------------------------------------

    bool base_window::
    is_closed (
    ) const
    {
        auto_mutex M(wm);
        return has_been_destroyed;
    }

// ----------------------------------------------------------------------------------------

    void base_window::
    set_title (
        const std::string& title_
    )
    {
        set_title(convert_mbstring_to_wstring(title_));
    }

    void base_window::
    set_title (
        const ustring& title_
    )
    {
        set_title(convert_utf32_to_wstring(title_));
    }

    void base_window::
    set_title (
        const std::wstring& title_
    )
    {
        using namespace gui_core_kernel_2_globals;
        auto_mutex M(wm);
        if (has_been_destroyed == true)
            return;

        // I'm pretty sure the pointer won't be modified even though
        // it isn't const anymore.
        wchar_t *title = const_cast<wchar_t *>(title_.c_str());
        XTextProperty property;
        XwcTextListToTextProperty(x11_stuff.globals->disp,&title,1,XStdICCTextStyle, &property);
        XSetWMName(x11_stuff.globals->disp,x11_stuff.hwnd,&property);
        XFree(property.value);
        XFlush(x11_stuff.globals->disp);
    }

// ----------------------------------------------------------------------------------------

    void base_window::
    show (
    )
    {
        using namespace gui_core_kernel_2_globals;
        auto_mutex M(wm);
        if (has_been_destroyed == true)
            return;

        XMapRaised(x11_stuff.globals->disp,x11_stuff.hwnd);
        XFlush(x11_stuff.globals->disp);
    }

// ----------------------------------------------------------------------------------------

    void base_window::
    wait_until_closed (
    ) const
    {
        using namespace gui_core_kernel_2_globals;
        auto_mutex M(wm);
        while (has_been_destroyed == false)
            x11_stuff.globals->window_close_signaler.wait();
    }

// ----------------------------------------------------------------------------------------

    void base_window::
    hide (
    )
    {
        using namespace gui_core_kernel_2_globals;
        auto_mutex M(wm);
        if (has_been_destroyed == true)
            return;

        XUnmapWindow(x11_stuff.globals->disp,x11_stuff.hwnd);
        XFlush(x11_stuff.globals->disp);
    }

// ----------------------------------------------------------------------------------------

    void base_window::
    set_size (
        int width_,
        int height_
    )
    {
        using namespace gui_core_kernel_2_globals;
        auto_mutex a(wm);
        if (has_been_destroyed == true)
            return;

        // do some sanity checking on these values
        if (width_ < 1)
            width_ = 1;
        if (height_ < 1)
            height_ = 1;

        width = width_;
        height = height_;
        has_been_resized = true;

        if (resizable == false)
        {
            XSizeHints* hints = XAllocSizeHints();
            hints->flags = PMinSize|PMaxSize;
            hints->min_width = width;
            hints->max_width = width;
            hints->max_height = height;
            hints->min_height = height;
            XSetNormalHints(x11_stuff.globals->disp,x11_stuff.hwnd,hints);
            XFree(hints);
        }

        XResizeWindow(x11_stuff.globals->disp,x11_stuff.hwnd,width,height);

        XFlush(x11_stuff.globals->disp);
    }

// ----------------------------------------------------------------------------------------

    void base_window::
    set_pos (
        long x_,
        long y_
    )
    {
        using namespace gui_core_kernel_2_globals;
        auto_mutex a(wm);
        if (has_been_destroyed == true)
            return;

        x = x_;
        y = y_;

        has_been_moved = true;

        XMoveWindow(x11_stuff.globals->disp,x11_stuff.hwnd,x,y);
        XFlush(x11_stuff.globals->disp);
    }

// ----------------------------------------------------------------------------------------

    void base_window::
    get_pos (
        long& x_,
        long& y_
    )
    {
        using namespace gui_core_kernel_2_globals;
        auto_mutex a(wm);
        x_ = 0;
        y_ = 0;
        if (has_been_destroyed == true)
            return;

        // we can't really trust the values we have for x and y because some window managers
        // will have reported bogus values back in the ConfigureNotify event.  So just to be
        // on the safe side we will use XTranslateCoordinates()
        int rx, ry;
        Window desktop_window = DefaultRootWindow(x11_stuff.globals->disp);
        Window junk;
        XTranslateCoordinates(x11_stuff.globals->disp,x11_stuff.hwnd,desktop_window,0,0,&rx, &ry, &junk);
        x_ = rx;
        y_ = ry;
        x = rx;
        y = ry;
    }

// ----------------------------------------------------------------------------------------

    void base_window::
    get_size (
        unsigned long& width_,
        unsigned long& height_
    ) const
    {
        auto_mutex M(wm);
        width_ = 0;
        height_ = 0;
        if (has_been_destroyed == true)
            return;

        width_ = width;
        height_ = height;
    }

// ----------------------------------------------------------------------------------------

    void base_window::
    get_display_size (
        unsigned long& width_,
        unsigned long& height_
    ) const
    {
        using namespace gui_core_kernel_2_globals;
        auto_mutex M(wm);
        width_ = 0;
        height_ = 0;
        if (has_been_destroyed == true)
            return;

        int screen_number = XScreenNumberOfScreen(x11_stuff.globals->screen);
        width_ = DisplayWidth(x11_stuff.globals->disp, screen_number);
        height_ = DisplayHeight(x11_stuff.globals->disp, screen_number);
    }

// ----------------------------------------------------------------------------------------

    void base_window::
    invalidate_rectangle (
        const rectangle& rect
    )
    {
        using namespace gui_core_kernel_2_globals;
        auto_mutex a(wm);
        if (is_mapped == false)
            return;

        if (rect.is_empty() == false && !has_been_destroyed)
        {
            const long x = rect.left();
            const long y = rect.top();
            const unsigned long width = rect.width();
            const unsigned long height = rect.height();

            XClearArea(x11_stuff.globals->disp,x11_stuff.hwnd,x,y,width,height,1);
            XFlush(x11_stuff.globals->disp);
        }
    }

// ----------------------------------------------------------------------------------------

    void base_window::
    set_im_pos (
        long x,
        long y
    )
    {
        using namespace gui_core_kernel_2_globals;
        auto_mutex a(wm);
        if (has_been_destroyed == true)
            return;

        if (!x11_stuff.xic || !(x11_stuff.globals->xim_style & XIMPreeditPosition)) return;

        XVaNestedList   xva_nlist;
        XPoint          xpoint;

        xpoint.x = x;
        xpoint.y = y;

        xva_nlist = XVaCreateNestedList(0, XNSpotLocation, &xpoint, (const void*)NULL);
        XSetICValues(x11_stuff.xic, XNPreeditAttributes, xva_nlist, (const void*)NULL);
        XFree(xva_nlist);
    }

}

// ----------------------------------------------------------------------------------------

#endif // POSIX

#endif // DLIB_GUI_CORE_KERNEL_2_CPp_


dlib C++ Library - gui_core_kernel_2.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net), Keita Mochizuki
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_GUI_CORE_KERNEl_2_
#define DLIB_GUI_CORE_KERNEl_2_

#ifdef DLIB_ISO_CPP_ONLY
#error "DLIB_ISO_CPP_ONLY is defined so you can't use this OS dependent code.  Turn DLIB_ISO_CPP_ONLY off if you want to use it."
#endif

#ifdef DLIB_NO_GUI_SUPPORT
#error "DLIB_NO_GUI_SUPPORT is defined so you can't use the GUI code.  Turn DLIB_NO_GUI_SUPPORT off if you want to use it."
#error "Also make sure you have libx11-dev installed on your system"
#endif

#include <string>

#include "gui_core_kernel_abstract.h"
#include "../algs.h"
#include "../threads.h"
#include "../geometry/rectangle.h"
#include "../binary_search_tree.h"
#include <string.h>
#include "../pixel.h"
#include "../unicode.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    namespace gui_core_kernel_2_globals
    {
        class event_handler_thread;
        void trigger_user_event_threadproc (void*);

        // This is a forward declaration for a struct that contains any
        // X11 variables.  This allows me to avoid having any dlib header files
        // include the X11 headers.  Which in turn speeds build times and simplifies
        // build setups.
        struct x11_base_windowstuff;
    }

// ----------------------------------------------------------------------------------------

    void put_on_clipboard (
        const std::string& str
    );

    void put_on_clipboard (
        const std::wstring& str
    );

    void put_on_clipboard (
        const dlib::ustring& str
    );

// ----------------------------------------------------------------------------------------

    void get_from_clipboard (
        std::string& str
    );

    void get_from_clipboard (
        std::wstring& str
    );

    void get_from_clipboard (
        dlib::ustring& str
    );

// ----------------------------------------------------------------------------------------

    class canvas : public rectangle
    {
    public:
        struct pixel
        {
            unsigned char blue;
            unsigned char green;
            unsigned char red;
        private:
            friend class canvas;
            unsigned char _padding;
        };

        ~canvas() {}

        inline pixel* operator[] (
            unsigned long row
        ) const
        {
            DLIB_ASSERT(row < height(),
                "\tpixel* canvas::operator[]"
                << "\n\tyou have to give a row that is less than the height()"
                << "\n\tthis:     " << this
                << "\n\trow:      " << row
                << "\n\theight(): " << height()
                );
            unsigned char* temp = bits + row_width*row;
            return reinterpret_cast<pixel*>(temp);
        }

        void fill (
            unsigned char red_,
            unsigned char green_,
            unsigned char blue_
        ) const;

    private:

        friend class gui_core_kernel_2_globals::event_handler_thread;

        canvas (
            unsigned char* bits_,
            unsigned long left_,
            unsigned long top_,
            unsigned long right_,
            unsigned long bottom_
        ) :
            rectangle(left_,top_,right_,bottom_),
            bits(bits_),
            width_(width()),
            height_(height()),
            row_width(width_*4)
        {}

        // restricted functions
        canvas();        // normal constructor
        canvas(canvas&);        // copy constructor
        canvas& operator=(canvas&);    // assignment operator

        unsigned char* const bits;
        const unsigned long width_;
        const unsigned long height_;
        const unsigned long row_width;
    };

    template <>
    struct pixel_traits<canvas::pixel>
    {
        const static bool rgb  = true;
        const static bool rgb_alpha  = false;
        const static bool grayscale = false;
        const static bool hsi = false;
        const static long num = 3;
        typedef unsigned char basic_pixel_type;
        static basic_pixel_type min() { return 0;}
        static basic_pixel_type max() { return 255;}
        const static bool is_unsigned = true;
        const static bool has_alpha = false;
    };

// -----------------

    class base_window
    {
        friend class gui_core_kernel_2_globals::event_handler_thread;
        friend void gui_core_kernel_2_globals::trigger_user_event_threadproc (void*);

    public:

        enum  mouse_state_masks
        {
            NONE = 0,
            LEFT = 1,
            RIGHT = 2,
            MIDDLE = 4,
            SHIFT = 8,
            CONTROL = 16
        };

        enum keyboard_state_masks
        {
            KBD_MOD_NONE = 0,
            KBD_MOD_SHIFT = 1,
            KBD_MOD_CONTROL = 2,
            KBD_MOD_ALT = 4,
            KBD_MOD_META = 8,
            KBD_MOD_CAPS_LOCK = 16,
            KBD_MOD_NUM_LOCK = 32,
            KBD_MOD_SCROLL_LOCK = 64
        };

        enum on_close_return_code
        {
            DO_NOT_CLOSE_WINDOW,
            CLOSE_WINDOW
        };

        enum non_printable_keyboard_keys
        {
            KEY_BACKSPACE,
            KEY_SHIFT,
            KEY_CTRL,
            KEY_ALT,
            KEY_PAUSE,
            KEY_CAPS_LOCK,
            KEY_ESC,
            KEY_PAGE_UP,
            KEY_PAGE_DOWN,
            KEY_END,
            KEY_HOME,
            KEY_LEFT,           // This is the left arrow key
            KEY_RIGHT,          // This is the right arrow key
            KEY_UP,             // This is the up arrow key
            KEY_DOWN,           // This is the down arrow key
            KEY_INSERT,
            KEY_DELETE,
            KEY_SCROLL_LOCK,

            // Function Keys
            KEY_F1,
            KEY_F2,
            KEY_F3,
            KEY_F4,
            KEY_F5,
            KEY_F6,
            KEY_F7,
            KEY_F8,
            KEY_F9,
            KEY_F10,
            KEY_F11,
            KEY_F12
        };

    private:

        gui_core_kernel_2_globals::x11_base_windowstuff& x11_stuff;

        int x, y, width, height;
        bool is_mapped;

        const bool resizable;
        bool has_been_destroyed;
        bool has_been_resized;  // true if someone called set_size() and the on_window_resized() event
                                // hasn't yet occurred.
        bool has_been_moved;    // true if someone called set_pos() and the on_window_moved() event
                                // hasn't yet occurred.

        // The following 3 variables (and x11_stuff.last_click_time) are only accessed from the
        // event handling loop (except for being initialized below). They record the last
        // mouse click event details.
        long last_click_x, last_click_y;
        unsigned long last_click_button;

    protected:
        const rmutex& wm;

    public:

        base_window (
            bool resizable_ = true,
            bool undecorated = false
        );

        virtual ~base_window (
        );

        void close_window (
        );

        void wait_until_closed (
        ) const;

        void set_im_pos (
            long x_,
            long y_
        );

        bool is_closed (
        ) const;

        void set_title (
            const std::string& title_
        );

        void set_title (
            const std::wstring& title_
        );

        void set_title (
            const dlib::ustring& title_
        );

        virtual void show (
        );

        virtual void hide(
        );

        void set_size (
            int width_,
            int height_
        );

        void set_pos (
            long x_,
            long y_
        );

        void get_pos (
            long& x_,
            long& y_
        );

        void get_size (
            unsigned long& width_,
            unsigned long& height_
        ) const;

        void get_display_size (
            unsigned long& width,
            unsigned long& height
        ) const;

        void invalidate_rectangle (
            const rectangle& rect
        );

        void trigger_user_event (
            void* p,
            int i
        );

    protected:

        virtual on_close_return_code on_window_close(
        ){return CLOSE_WINDOW;}

        virtual void on_window_resized(
        ){}

        virtual void on_window_moved(
        ){}
        virtual void on_user_event (
            void* ,
            int
        ){}

        virtual void on_mouse_down (
            unsigned long ,
            unsigned long ,
            long ,
            long ,
            bool
        ){}

        virtual void on_mouse_up (
            unsigned long ,
            unsigned long ,
            long ,
            long
        ){}

        virtual void on_mouse_move (
            unsigned long ,
            long ,
            long
        ){}

        virtual void on_mouse_leave (
        ){}

        virtual void on_mouse_enter (
        ){}

        virtual void on_wheel_up (
            unsigned long
        ){}

        virtual void on_wheel_down (
            unsigned long
        ){}

        virtual void on_focus_gained (
        ){}

        virtual void on_focus_lost (
        ){}

        virtual void on_keydown (
            unsigned long ,
            bool ,
            unsigned long
        ){}

        virtual void on_string_put (
            const std::wstring&
        ){}

    private:

        virtual void paint (
            const canvas& c
        ) =0;

        base_window(base_window&);        // copy constructor
        base_window& operator=(base_window&);    // assignment operator

    };

// ----------------------------------------------------------------------------------------

}

#ifdef NO_MAKEFILE
#include "gui_core_kernel_2.cpp"
#endif

#endif // DLIB_GUI_CORE_KERNEl_2_


dlib C++ Library - windows.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_GUI_CORE_KERNEl_2_
#include "gui_core_kernel_1.h"
#endif


dlib C++ Library - xlib.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_GUI_CORE_KERNEl_1_
#include "gui_core_kernel_2.h"
#endif


dlib C++ Library - base_widgets.cpp

// Copyright (C) 2005  Davis E. King (davis@dlib.net), Keita Mochizuki
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_BASE_WIDGETs_CPP_
#define DLIB_BASE_WIDGETs_CPP_

#include "base_widgets.h"
#include "../assert.h"
#include <iostream>

namespace dlib
{

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // button object methods
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    void button::
    set_size (
        unsigned long width,
        unsigned long height
    )
    {
        auto_mutex M(m);
        rectangle min_rect = style->get_min_size(name_,*mfont);
        // only change the size if it isn't going to be too small to fit the name
        if (height >= min_rect.height() &&
            width >= min_rect.width())
        {
            rectangle old(rect);
            rect = resize_rect(rect,width,height);
            parent.invalidate_rectangle(style->get_invalidation_rect(rect+old));
            btn_tooltip.set_size(width,height);
        }
    }

// ----------------------------------------------------------------------------------------

    void button::
    show (
    )
    {
        button_action::show();
        btn_tooltip.show();
    }

// ----------------------------------------------------------------------------------------

    void button::
    hide (
    )
    {
        button_action::hide();
        btn_tooltip.hide();
    }

// ----------------------------------------------------------------------------------------

    void button::
    enable (
    )
    {
        button_action::enable();
        btn_tooltip.enable();
    }

// ----------------------------------------------------------------------------------------

    void button::
    disable (
    )
    {
        button_action::disable();
        btn_tooltip.disable();
    }

// ----------------------------------------------------------------------------------------

    void button::
    set_tooltip_text (
        const std::string& text
    )
    {
        btn_tooltip.set_text(text);
    }

// ----------------------------------------------------------------------------------------

    void button::
    set_tooltip_text (
        const std::wstring& text
    )
    {
        btn_tooltip.set_text(text);
    }

// ----------------------------------------------------------------------------------------

    void button::
    set_tooltip_text (
        const ustring& text
    )
    {
        btn_tooltip.set_text(text);
    }

// ----------------------------------------------------------------------------------------

    const std::string button::
    tooltip_text (
    ) const
    {
        return btn_tooltip.text();
    }

    const std::wstring button::
    tooltip_wtext (
    ) const
    {
        return btn_tooltip.wtext();
    }

    const dlib::ustring button::
    tooltip_utext (
    ) const
    {
        return btn_tooltip.utext();
    }

// ----------------------------------------------------------------------------------------

    void button::
    set_main_font (
        const shared_ptr_thread_safe<font>& f
    )
    {
        auto_mutex M(m);
        mfont = f;
        set_name(name_);
    }

// ----------------------------------------------------------------------------------------

    void button::
    set_pos (
        long x,
        long y
    )
    {
        auto_mutex M(m);
        button_action::set_pos(x,y);
        btn_tooltip.set_pos(x,y);
    }

// ----------------------------------------------------------------------------------------

    void button::
    set_name (
        const std::string& name
    )
    {
        set_name(convert_mbstring_to_wstring(name));
    }

    void button::
    set_name (
        const std::wstring& name
    )
    {
        set_name(convert_wstring_to_utf32(name));
    }

    void button::
    set_name (
        const ustring& name
    )
    {
        auto_mutex M(m);
        name_ = name;
        // do this to get rid of any reference counting that may be present in
        // the std::string implementation.
        name_[0] = name_[0];

        rectangle old(rect);
        rect = move_rect(style->get_min_size(name,*mfont),rect.left(),rect.top());
        btn_tooltip.set_size(rect.width(),rect.height());

        parent.invalidate_rectangle(style->get_invalidation_rect(rect+old));
    }

// ----------------------------------------------------------------------------------------

    const std::string button::
    name (
    ) const
    {
        auto_mutex M(m);
        std::string temp = convert_wstring_to_mbstring(wname());
        // do this to get rid of any reference counting that may be present in
        // the std::string implementation.
        char c = temp[0];
        temp[0] = c;
        return temp;
    }

    const std::wstring button::
    wname (
    ) const
    {
        auto_mutex M(m);
        std::wstring temp = convert_utf32_to_wstring(uname());
        // do this to get rid of any reference counting that may be present in
        // the std::wstring implementation.
        wchar_t w = temp[0];
        temp[0] = w;
        return temp;
    }

    const dlib::ustring button::
    uname (
    ) const
    {
        auto_mutex M(m);
        dlib::ustring temp = name_;
        // do this to get rid of any reference counting that may be present in
        // the dlib::ustring implementation.
        temp[0] = name_[0];
        return temp;
    }

// ----------------------------------------------------------------------------------------

    void button::
    on_button_up (
        bool mouse_over
    )
    {
        if (mouse_over)
        {
            // this is a valid button click
            if (event_handler.is_set())
                event_handler();
            if (event_handler_self.is_set())
                event_handler_self(*this);
        }
        if (button_up_handler.is_set())
            button_up_handler(mouse_over);
        if (button_up_handler_self.is_set())
            button_up_handler_self(mouse_over,*this);
    }

// ----------------------------------------------------------------------------------------

    void button::
    on_button_down (
    )
    {
        if (button_down_handler.is_set())
            button_down_handler();
        if (button_down_handler_self.is_set())
            button_down_handler_self(*this);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // draggable object methods
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    draggable::~draggable() {}

// ----------------------------------------------------------------------------------------

    void draggable::
    on_mouse_move (
        unsigned long state,
        long x,
        long y
    )
    {
        if (drag && (state & base_window::LEFT) && enabled && !hidden)
        {
            // the user is trying to drag this object.  we should calculate the new
            // x and y positions for the upper left corner of this object's rectangle

            long new_x = x - this->x;
            long new_y = y - this->y;

            // make sure these points are inside the draggable area.
            if (new_x < area.left())
                new_x = area.left();
            if (new_x + static_cast<long>(rect.width()) - 1 > area.right())
                new_x = area.right() - rect.width() + 1;

            if (new_y + static_cast<long>(rect.height()) - 1 > area.bottom())
                new_y = area.bottom() - rect.height() + 1;
            if (new_y < area.top())
                new_y = area.top();

            // now make the new rectangle for this object
            rectangle new_rect(
                new_x,
                new_y,
                new_x + rect.width() - 1,
                new_y + rect.height() - 1
            );

            // only do anything if this is a new rectangle and it is inside area
            if (new_rect != rect && area.intersect(new_rect) == new_rect)
            {
                parent.invalidate_rectangle(new_rect + rect);
                rect = new_rect;

                // call the on_drag() event handler
                on_drag();
            }
        }
        else
        {
            drag = false;
            on_drag_stop();
        }
    }

// ----------------------------------------------------------------------------------------

    void draggable::
    on_mouse_up (
        unsigned long ,
        unsigned long state,
        long ,
        long
    )
    {
        if (drag && (state & base_window::LEFT) == 0)
        {
            drag = false;
            on_drag_stop();
        }
    }

// ----------------------------------------------------------------------------------------

    void draggable::
    on_mouse_down (
        unsigned long btn,
        unsigned long ,
        long x,
        long y,
        bool
    )
    {
        if (enabled && !hidden && rect.contains(x,y) && btn == base_window::LEFT)
        {
            drag = true;
            this->x = x - rect.left();
            this->y = y - rect.top();
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // mouse_over_event object methods
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    mouse_over_event::~mouse_over_event() {}

// ----------------------------------------------------------------------------------------

    void mouse_over_event::
    on_mouse_leave (
    )
    {
        if (is_mouse_over_)
        {
            is_mouse_over_ = false;
            on_mouse_not_over();
        }
    }

// ----------------------------------------------------------------------------------------

    void mouse_over_event::
    on_mouse_move (
        unsigned long ,
        long x,
        long y
    )
    {
        if (rect.contains(x,y) == false)
        {
            if (is_mouse_over_)
            {
                is_mouse_over_ = false;
                on_mouse_not_over();
            }
        }
        else if (is_mouse_over_ == false)
        {
            is_mouse_over_ = true;
            if (enabled && !hidden)
                on_mouse_over();
        }
    }

// ----------------------------------------------------------------------------------------

    bool mouse_over_event::
    is_mouse_over (
    ) const
    {
        // check if the mouse is still really over this button
        if (is_mouse_over_ && rect.contains(lastx,lasty) == false)
        {
            // trigger a user event to call on_mouse_not_over() and repaint this object.
            // we must do this in another event because someone might call is_mouse_over()
            // from draw() and you don't want this function to end up calling
            // parent.invalidate_rectangle().  It would lead to draw() being called over
            // and over.
            parent.trigger_user_event((void*)this,drawable::next_free_user_event_number());
            return false;
        }

        return is_mouse_over_;
    }

// ----------------------------------------------------------------------------------------

    void mouse_over_event::
    on_user_event (
        int num
    )
    {
        if (is_mouse_over_ && num == drawable::next_free_user_event_number())
        {
            is_mouse_over_ = false;
            on_mouse_not_over();
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // button_action object methods
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    button_action::~button_action() {}

// ----------------------------------------------------------------------------------------

    void button_action::
    on_mouse_down (
        unsigned long btn,
        unsigned long ,
        long x,
        long y,
        bool
    )
    {
        if (enabled && !hidden && btn == base_window::LEFT && rect.contains(x,y))
        {
            is_depressed_ = true;
            seen_click = true;
            parent.invalidate_rectangle(rect);
            on_button_down();
        }
    }

// ----------------------------------------------------------------------------------------

    void button_action::
    on_mouse_not_over (
    )
    {
        if (is_depressed_)
        {
            is_depressed_ = false;
            parent.invalidate_rectangle(rect);
            on_button_up(false);
        }
    }

// ----------------------------------------------------------------------------------------

    void button_action::
    on_mouse_move (
        unsigned long state,
        long x,
        long y
    )
    {
        // forward event to the parent class so it can do it's thing as well as us
        mouse_over_event::on_mouse_move(state,x,y);

        if (enabled == false || hidden == true)
            return;

        if ((state & base_window::LEFT) == 0)
        {
            seen_click = false;
            if (is_depressed_)
            {
                is_depressed_ = false;
                parent.invalidate_rectangle(rect);
                on_button_up(false);
            }

            // the left button isn't down so we don't care about anything else
            return;
        }

        if (rect.contains(x,y) == false)
        {
            if (is_depressed_)
            {
                is_depressed_ = false;
                parent.invalidate_rectangle(rect);
                on_button_up(false);
            }
        }
        else if (is_depressed_ == false && seen_click)
        {
            is_depressed_ = true;
            parent.invalidate_rectangle(rect);
            on_button_down();
        }
    }

// ----------------------------------------------------------------------------------------

    void button_action::
    on_mouse_up (
        unsigned long btn,
        unsigned long,
        long x,
        long y
    )
    {
        if (enabled && !hidden && btn == base_window::LEFT)
        {
            if (is_depressed_)
            {
                is_depressed_ = false;
                parent.invalidate_rectangle(rect);

                if (rect.contains(x,y))
                {
                    on_button_up(true);
                }
                else
                {
                    on_button_up(false);
                }
            }
            else if (seen_click && rect.contains(x,y))
            {
                // this case here covers the unlikly event that you click on a button,
                // move the mouse off the button and then move it back very quickly and
                // release the mouse button.   It is possible that this mouse up event
                // will occurr before any mouse move event so you might not have set
                // that the button is depressed yet.

                // So we should say that this triggers an on_button_down() event and
                // then an on_button_up(true) event.

                parent.invalidate_rectangle(rect);

                on_button_down();
                on_button_up(true);
            }

            seen_click = false;
        }
    }

// ----------------------------------------------------------------------------------------

    bool button_action::
    is_depressed (
    ) const
    {
        // check if the mouse is still really over this button
        if (enabled && !hidden && is_depressed_ && rect.contains(lastx,lasty) == false)
        {
            // trigger a user event to call on_button_up() and repaint this object.
            // we must do this in another event because someone might call is_depressed()
            // from draw() and you don't want this function to end up calling
            // parent.invalidate_rectangle().  It would lead to draw() being called over
            // and over.
            parent.trigger_user_event((void*)this,mouse_over_event::next_free_user_event_number());
            return false;
        }

        return is_depressed_;
    }

// ----------------------------------------------------------------------------------------

    void button_action::
    on_user_event (
        int num
    )
    {
        // forward event to the parent class so it can do it's thing as well as us
        mouse_over_event::on_user_event(num);

        if (is_depressed_ && num == mouse_over_event::next_free_user_event_number())
        {
            is_depressed_ = false;
            parent.invalidate_rectangle(rect);
            on_button_up(false);
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // scroll_bar object methods
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    scroll_bar::
    scroll_bar(
        drawable_window& w,
        bar_orientation orientation
    ) :
        drawable(w),
        b1(w),
        b2(w),
        slider(w,*this,&scroll_bar::on_slider_drag),
        ori(orientation),
        top_filler(w,*this,&scroll_bar::top_filler_down,&scroll_bar::top_filler_up),
        bottom_filler(w,*this,&scroll_bar::bottom_filler_down,&scroll_bar::bottom_filler_up),
        pos(0),
        max_pos(0),
        js(10),
        b1_timer(*this,&scroll_bar::b1_down_t),
        b2_timer(*this,&scroll_bar::b2_down_t),
        top_filler_timer(*this,&scroll_bar::top_filler_down_t),
        bottom_filler_timer(*this,&scroll_bar::bottom_filler_down_t)
    {
        set_style(scroll_bar_style_default());

        // don't show the slider when there is no place it can move.
        slider.hide();

        set_length(100);

        b1.set_button_down_handler(*this,&scroll_bar::b1_down);
        b2.set_button_down_handler(*this,&scroll_bar::b2_down);

        b1.set_button_up_handler(*this,&scroll_bar::b1_up);
        b2.set_button_up_handler(*this,&scroll_bar::b2_up);
        b1.disable();
        b2.disable();
        enable_events();
    }

// ----------------------------------------------------------------------------------------

    scroll_bar::
    ~scroll_bar(
    )
    {
        disable_events();
        parent.invalidate_rectangle(rect);
        // wait for all the timers to be stopped
        b1_timer.stop_and_wait();
        b2_timer.stop_and_wait();
        top_filler_timer.stop_and_wait();
        bottom_filler_timer.stop_and_wait();
    }

// ----------------------------------------------------------------------------------------

    scroll_bar::bar_orientation scroll_bar::
    orientation (
    ) const
    {
        auto_mutex M(m);
        return ori;
    }

// ----------------------------------------------------------------------------------------

    void scroll_bar::
    set_length (
        unsigned long length
    )
    {
        auto_mutex M(m);
        // make the min length be at least 1
        if (length == 0)
        {
            length = 1;
        }

        parent.invalidate_rectangle(rect);

        if (ori == HORIZONTAL)
        {
            rect.set_right(rect.left() + length - 1);
            rect.set_bottom(rect.top() + style->get_width() - 1);

            const long btn_size = style->get_button_length(rect.width(), max_pos);

            b1.set_size(btn_size,style->get_width());
            b2.set_size(btn_size,style->get_width());

            slider.set_size(get_slider_size(),style->get_width());
        }
        else
        {
            rect.set_right(rect.left() + style->get_width() - 1);
            rect.set_bottom(rect.top() + length - 1);

            const long btn_size = style->get_button_length(rect.height(), max_pos);

            b1.set_size(style->get_width(),btn_size);
            b2.set_size(style->get_width(),btn_size);

            slider.set_size(style->get_width(),get_slider_size());
        }

        // call this to put everything is in the right spot.
        set_pos (rect.left(),rect.top());

        if ((b2.get_rect().top() - b1.get_rect().bottom() - 1 <= 8 && ori == VERTICAL) ||
            (b2.get_rect().left() - b1.get_rect().right() - 1 <= 8 && ori == HORIZONTAL) ||
            max_pos == 0)
        {
            hide_slider();
        }
        else if (enabled && !hidden)
        {
            show_slider();
        }
    }

// ----------------------------------------------------------------------------------------

    void scroll_bar::
    set_pos (
        long x,
        long y
    )
    {
        auto_mutex M(m);
        drawable::set_pos(x,y);

        b1.set_pos(rect.left(),rect.top());
        if (ori == HORIZONTAL)
        {
            // make the b2 button appear at the end of the scroll_bar
            b2.set_pos(rect.right()-b2.get_rect().width() + 1,rect.top());

            if (max_pos != 0)
            {
                double range = b2.get_rect().left() - b1.get_rect().right() - slider.get_rect().width() - 1;
                double slider_pos = pos;
                slider_pos /= max_pos;
                slider_pos *= range;
                slider.set_pos(
                    static_cast<long>(slider_pos)+rect.left() + b1.get_rect().width(),
                    rect.top()
                    );

                // move the draggable area for the slider to the new location
                rectangle area = rect;
                area.set_left(area.left() + style->get_width());
                area.set_right(area.right() - style->get_width());
                slider.set_draggable_area(area);

            }

        }
        else
        {
            // make the b2 button appear at the end of the scroll_bar
            b2.set_pos(rect.left(), rect.bottom() - b2.get_rect().height() + 1);

            if (max_pos != 0)
            {
                double range = b2.get_rect().top() - b1.get_rect().bottom() - slider.get_rect().height() - 1;
                double slider_pos = pos;
                slider_pos /= max_pos;
                slider_pos *= range;
                slider.set_pos(
                    rect.left(),
                    static_cast<long>(slider_pos) + rect.top() + b1.get_rect().height()
                    );

                // move the draggable area for the slider to the new location
                rectangle area = rect;
                area.set_top(area.top() + style->get_width());
                area.set_bottom(area.bottom() - style->get_width());
                slider.set_draggable_area(area);
            }
        }

        adjust_fillers();
    }

// ----------------------------------------------------------------------------------------

    unsigned long scroll_bar::
    get_slider_size (
    ) const
    {
        if (ori == HORIZONTAL)
            return style->get_slider_length(rect.width(),max_pos);
        else
            return style->get_slider_length(rect.height(),max_pos);
    }

// ----------------------------------------------------------------------------------------

    void scroll_bar::
    adjust_fillers (
    )
    {
        rectangle top(rect), bottom(rect);

        if (ori == HORIZONTAL)
        {
            if (slider.is_hidden())
            {
                top.set_left(b1.get_rect().right()+1);
                top.set_right(b2.get_rect().left()-1);
                bottom.set_left(1);
                bottom.set_right(-1);
            }
            else
            {
                top.set_left(b1.get_rect().right()+1);
                top.set_right(slider.get_rect().left()-1);
                bottom.set_left(slider.get_rect().right()+1);
                bottom.set_right(b2.get_rect().left()-1);
            }
        }
        else
        {
            if (slider.is_hidden())
            {
                top.set_top(b1.get_rect().bottom()+1);
                top.set_bottom(b2.get_rect().top()-1);
                bottom.set_top(1);
                bottom.set_bottom(-1);
            }
            else
            {
                top.set_top(b1.get_rect().bottom()+1);
                top.set_bottom(slider.get_rect().top()-1);
                bottom.set_top(slider.get_rect().bottom()+1);
                bottom.set_bottom(b2.get_rect().top()-1);
            }
        }

        top_filler.rect = top;
        bottom_filler.rect = bottom;
    }

// ----------------------------------------------------------------------------------------

    void scroll_bar::
    hide_slider (
    )
    {
        rectangle top(rect), bottom(rect);
        slider.hide();
        top_filler.disable();
        bottom_filler.disable();
        bottom_filler.hide();
        if (ori == HORIZONTAL)
        {
            top.set_left(b1.get_rect().right()+1);
            top.set_right(b2.get_rect().left()-1);
        }
        else
        {
            top.set_top(b1.get_rect().bottom()+1);
            top.set_bottom(b2.get_rect().top()-1);
        }
        top_filler.rect = top;
        bottom_filler.rect = bottom;
    }

// ----------------------------------------------------------------------------------------

    void scroll_bar::
    show_slider (
    )
    {
        if ((b2.get_rect().top() - b1.get_rect().bottom() - 1 <= 8 && ori == VERTICAL) ||
            (b2.get_rect().left() - b1.get_rect().right() - 1 <= 8 && ori == HORIZONTAL) ||
            max_pos == 0)
            return;

        rectangle top(rect), bottom(rect);
        slider.show();
        top_filler.enable();
        bottom_filler.enable();
        bottom_filler.show();
        if (ori == HORIZONTAL)
        {
            top.set_left(b1.get_rect().right()+1);
            top.set_right(slider.get_rect().left()-1);
            bottom.set_left(slider.get_rect().right()+1);
            bottom.set_right(b2.get_rect().left()-1);
        }
        else
        {
            top.set_top(b1.get_rect().bottom()+1);
            top.set_bottom(slider.get_rect().top()-1);
            bottom.set_top(slider.get_rect().bottom()+1);
            bottom.set_bottom(b2.get_rect().top()-1);
        }
        top_filler.rect = top;
        bottom_filler.rect = bottom;
    }

// ----------------------------------------------------------------------------------------

    long scroll_bar::
    max_slider_pos (
    ) const
    {
        auto_mutex M(m);
        return max_pos;
    }

// ----------------------------------------------------------------------------------------

    void scroll_bar::
    set_max_slider_pos (
        long mpos
    )
    {
        auto_mutex M(m);
        max_pos = mpos;
        if (pos > mpos)
            pos = mpos;

        if (ori == HORIZONTAL)
            set_length(rect.width());
        else
            set_length(rect.height());

        if (mpos != 0 && enabled)
        {
            b1.enable();
            b2.enable();
        }
        else
        {
            b1.disable();
            b2.disable();
        }

    }

// ----------------------------------------------------------------------------------------

    void scroll_bar::
    set_slider_pos (
        long pos
    )
    {
        auto_mutex M(m);
        if (pos < 0)
            pos = 0;
        if (pos > max_pos)
            pos = max_pos;

        this->pos = pos;

        // move the slider object to its new position
        set_pos(rect.left(),rect.top());
    }

// ----------------------------------------------------------------------------------------

    long scroll_bar::
    slider_pos (
    ) const
    {
        auto_mutex M(m);
        return pos;
    }

// ----------------------------------------------------------------------------------------

    void scroll_bar::
    on_slider_drag (
    )
    {
        if (ori == HORIZONTAL)
        {
            double slider_pos = slider.get_rect().left() - b1.get_rect().right() - 1;
            double range = b2.get_rect().left() - b1.get_rect().right() - slider.get_rect().width() - 1;
            slider_pos /= range;
            slider_pos *= max_pos;
            pos = static_cast<unsigned long>(slider_pos);
        }
        else
        {
            double slider_pos = slider.get_rect().top() - b1.get_rect().bottom() - 1;
            double range = b2.get_rect().top() - b1.get_rect().bottom() - slider.get_rect().height() - 1;
            slider_pos /= range;
            slider_pos *= max_pos;
            pos = static_cast<unsigned long>(slider_pos);
        }

        adjust_fillers();

        if (scroll_handler.is_set())
            scroll_handler();
    }

// ----------------------------------------------------------------------------------------

    void scroll_bar::
    draw (
        const canvas&
    ) const
    {
    }

// ----------------------------------------------------------------------------------------

    void scroll_bar::
    b1_down (
    )
    {
        if (pos != 0)
        {
            set_slider_pos(pos-1);
            if (scroll_handler.is_set())
                scroll_handler();

            if (b1_timer.delay_time() == 1000)
                b1_timer.set_delay_time(500);
            else
                b1_timer.set_delay_time(50);
            b1_timer.start();
        }
    }

// ----------------------------------------------------------------------------------------

    void scroll_bar::
    b1_up (
        bool
    )
    {
        b1_timer.stop();
        b1_timer.set_delay_time(1000);
    }

// ----------------------------------------------------------------------------------------

    void scroll_bar::
    b2_down (
    )
    {
        if (pos != max_pos)
        {
            set_slider_pos(pos+1);
            if (scroll_handler.is_set())
                scroll_handler();

            if (b2_timer.delay_time() == 1000)
                b2_timer.set_delay_time(500);
            else
                b2_timer.set_delay_time(50);
            b2_timer.start();
        }
    }

// ----------------------------------------------------------------------------------------

    void scroll_bar::
    b2_up (
        bool
    )
    {
        b2_timer.stop();
        b2_timer.set_delay_time(1000);
    }

// ----------------------------------------------------------------------------------------

    void scroll_bar::
    top_filler_down (
    )
    {
        // ignore this if the mouse is now outside this object.  This could happen
        // since the timers are also calling this function.
        if (top_filler.rect.contains(lastx,lasty) == false)
        {
            top_filler_up(false);
            return;
        }

        if (pos != 0)
        {
            if (pos < js)
            {
                // if there is less than jump_size() space left then jump the remaining
                // amount.
                delayed_set_slider_pos(0);
            }
            else
            {
                delayed_set_slider_pos(pos-js);
            }

            if (top_filler_timer.delay_time() == 1000)
                top_filler_timer.set_delay_time(500);
            else
                top_filler_timer.set_delay_time(50);
            top_filler_timer.start();
        }
    }

// ----------------------------------------------------------------------------------------

    void scroll_bar::
    top_filler_up (
        bool
    )
    {
        top_filler_timer.stop();
        top_filler_timer.set_delay_time(1000);
    }

// ----------------------------------------------------------------------------------------

    void scroll_bar::
    bottom_filler_down (
    )
    {
        // ignore this if the mouse is now outside this object.  This could happen
        // since the timers are also calling this function.
        if (bottom_filler.rect.contains(lastx,lasty) == false)
        {
            bottom_filler_up(false);
            return;
        }

        if (pos != max_pos)
        {
            if (max_pos - pos < js)
            {
                // if there is less than jump_size() space left then jump the remaining
                // amount.
                delayed_set_slider_pos(max_pos);
            }
            else
            {
                delayed_set_slider_pos(pos+js);
            }

            if (bottom_filler_timer.delay_time() == 1000)
                bottom_filler_timer.set_delay_time(500);
            else
                bottom_filler_timer.set_delay_time(50);
            bottom_filler_timer.start();
        }
    }

// ----------------------------------------------------------------------------------------

    void scroll_bar::
    bottom_filler_up (
        bool
    )
    {
        bottom_filler_timer.stop();
        bottom_filler_timer.set_delay_time(1000);
    }

// ----------------------------------------------------------------------------------------

    void scroll_bar::
    set_jump_size (
        long js_
    )
    {
        auto_mutex M(m);
        if (js_ < 1)
            js = 1;
        else
            js = js_;
    }

// ----------------------------------------------------------------------------------------

    long scroll_bar::
    jump_size (
    ) const
    {
        auto_mutex M(m);
        return js;
    }

// ----------------------------------------------------------------------------------------

    void scroll_bar::
    on_user_event (
        int i
    )
    {
        switch (i)
        {
            case 0:
                b1_down();
                break;
            case 1:
                b2_down();
                break;
            case 2:
                top_filler_down();
                break;
            case 3:
                bottom_filler_down();
                break;
            case 4:
                // if the position we are supposed to switch the slider too isn't
                // already set
                if (delayed_pos != pos)
                {
                    set_slider_pos(delayed_pos);
                    if (scroll_handler.is_set())
                        scroll_handler();
                }
                break;
            default:
                break;
        }
    }

// ----------------------------------------------------------------------------------------

    void scroll_bar::
    delayed_set_slider_pos (
        unsigned long dpos
    )
    {
        delayed_pos = dpos;
        parent.trigger_user_event(this,4);
    }

// ----------------------------------------------------------------------------------------

    void scroll_bar::
    b1_down_t (
    )
    {
        parent.trigger_user_event(this,0);
    }

// ----------------------------------------------------------------------------------------

    void scroll_bar::
    b2_down_t (
    )
    {
        parent.trigger_user_event(this,1);
    }

// ----------------------------------------------------------------------------------------

    void scroll_bar::
    top_filler_down_t (
    )
    {
        parent.trigger_user_event(this,2);
    }

// ----------------------------------------------------------------------------------------

    void scroll_bar::
    bottom_filler_down_t (
    )
    {
        parent.trigger_user_event(this,3);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                  widget_group object methods
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    void widget_group::
    empty (
    )
    {
        auto_mutex M(m);
        widgets.clear();
        wg_widgets.clear();
    }

// ----------------------------------------------------------------------------------------

    void widget_group::
    add (
        drawable& widget,
        unsigned long x,
        unsigned long y
    )
    {
        auto_mutex M(m);
        drawable* w = &widget;
        relpos rp;
        rp.x = x;
        rp.y = y;
        if (widgets.is_in_domain(w))
        {
            widgets[w].x = x;
            widgets[w].y = y;
        }
        else
        {
            widgets.add(w,rp);
        }
        if (is_hidden())
            widget.hide();
        else
            widget.show();

        if (is_enabled())
            widget.enable();
        else
            widget.disable();

        widget.set_z_order(z_order());
        widget.set_pos(x+rect.left(),y+rect.top());
    }

// ----------------------------------------------------------------------------------------

    void widget_group::
    add (
        widget_group& widget,
        unsigned long x,
        unsigned long y
    )
    {
        auto_mutex M(m);
        drawable& w = widget;
        add(w, x, y);

        widget_group* wg = &widget;
        wg_widgets.add(wg);
    }

// ----------------------------------------------------------------------------------------

    bool widget_group::
    is_member (
        const drawable& widget
    ) const
    {
        auto_mutex M(m);
        drawable* w = const_cast<drawable*>(&widget);
        return widgets.is_in_domain(w);
    }

// ----------------------------------------------------------------------------------------

    void widget_group::
    remove (
        const drawable& widget
    )
    {
        auto_mutex M(m);
        drawable* w = const_cast<drawable*>(&widget);
        if (widgets.is_in_domain(w))
        {
            widgets.destroy(w);

            // check if we also have an entry in the wg_widgets set and if
            // so then remove that too
            widget_group* wg = reinterpret_cast<widget_group*>(w);
            if (wg_widgets.is_member(wg))
            {
                wg_widgets.destroy(wg);
            }
        }
    }

// ----------------------------------------------------------------------------------------

    unsigned long widget_group::
    size (
    ) const
    {
        auto_mutex M(m);
        return widgets.size();
    }

// ----------------------------------------------------------------------------------------

    void widget_group::
    set_pos (
        long x,
        long y
    )
    {
        auto_mutex M(m);
        widgets.reset();
        while (widgets.move_next())
        {
            const unsigned long rx = widgets.element().value().x;
            const unsigned long ry = widgets.element().value().y;
            widgets.element().key()->set_pos(x+rx,y+ry);
        }
        drawable::set_pos(x,y);
    }

// ----------------------------------------------------------------------------------------

    void widget_group::
    set_z_order (
        long order
    )
    {
        auto_mutex M(m);
        widgets.reset();
        while (widgets.move_next())
            widgets.element().key()->set_z_order(order);
        drawable::set_z_order(order);
    }

// ----------------------------------------------------------------------------------------

    void widget_group::
    show (
    )
    {
        auto_mutex M(m);
        widgets.reset();
        while (widgets.move_next())
            widgets.element().key()->show();
        drawable::show();
    }

// ----------------------------------------------------------------------------------------

    void widget_group::
    hide (
    )
    {
        auto_mutex M(m);
        widgets.reset();
        while (widgets.move_next())
            widgets.element().key()->hide();
        drawable::hide();
    }

// ----------------------------------------------------------------------------------------

    void widget_group::
    enable (
    )
    {
        auto_mutex M(m);
        widgets.reset();
        while (widgets.move_next())
            widgets.element().key()->enable();
        drawable::enable();
    }

// ----------------------------------------------------------------------------------------

    void widget_group::
    disable ()
    {
        auto_mutex M(m);
        widgets.reset();
        while (widgets.move_next())
            widgets.element().key()->disable();
        drawable::disable();
    }

// ----------------------------------------------------------------------------------------

    void widget_group::
    fit_to_contents (
    )
    {
        auto_mutex M(m);

        // call fit_to_contents on all the widget_groups we contain
        wg_widgets.reset();
        while (wg_widgets.move_next())
            wg_widgets.element()->fit_to_contents();

        // now accumulate a rectangle that contains everything in this widget_group
        rectangle r;
        widgets.reset();
        while (widgets.move_next())
            r = r + widgets.element().key()->get_rect();

        if (r.is_empty())
        {
            // make sure it is still empty after we set it at the correct position
            r.set_right(rect.left()-1);
            r.set_bottom(rect.top()-1);
        }

        r.set_left(rect.left());
        r.set_top(rect.top());
        rect = r;
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                class popup_menu
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    popup_menu::
    popup_menu (
    ) :
        base_window(false,true),
        pad(2),
        item_pad(3),
        cur_rect(pad,pad,pad-1,pad-1),
        left_width(0),
        middle_width(0),
        selected_item(0),
        submenu_open(false)
    {
    }

// ----------------------------------------------------------------------------------------

    void popup_menu::
    enable_menu_item (
        unsigned long idx
    )
    {
        DLIB_ASSERT ( idx < size() ,
                      "\tvoid popup_menu::enable_menu_item()"
                      << "\n\tidx:    " << idx
                      << "\n\tsize(): " << size()
        );
        auto_mutex M(wm);
        item_enabled[idx] = true;
        invalidate_rectangle(cur_rect);
    }

// ----------------------------------------------------------------------------------------

    void popup_menu::
    disable_menu_item (
        unsigned long idx
    )
    {
        DLIB_ASSERT ( idx < size() ,
                      "\tvoid popup_menu::enable_menu_item()"
                      << "\n\tidx:    " << idx
                      << "\n\tsize(): " << size()
        );
        auto_mutex M(wm);
        item_enabled[idx] = false;
        invalidate_rectangle(cur_rect);
    }

// ----------------------------------------------------------------------------------------

    unsigned long popup_menu::
    size (
    ) const
    {
        auto_mutex M(wm);
        return items.size();
    }

// ----------------------------------------------------------------------------------------

    void popup_menu::
    clear (
    )
    {
        auto_mutex M(wm);
        hide();
        cur_rect = rectangle(pad,pad,pad-1,pad-1);
        win_rect = rectangle();
        left_width = 0;
        middle_width = 0;
        items.clear();
        item_enabled.clear();
        left_rects.clear();
        middle_rects.clear();
        right_rects.clear();
        line_rects.clear();
        submenus.clear();
        selected_item = 0;
        submenu_open = false;
    }

// ----------------------------------------------------------------------------------------

    void popup_menu::
    show (
    )
    {
        auto_mutex M(wm);
        selected_item = submenus.size();
        base_window::show();
    }

// ----------------------------------------------------------------------------------------

    void popup_menu::
    hide (
    )
    {
        auto_mutex M(wm);
        // hide ourselves
        close_submenu();
        selected_item = submenus.size();
        base_window::hide();
    }

// ----------------------------------------------------------------------------------------

    void popup_menu::
    select_first_item (
    )
    {
        auto_mutex M(wm);
        close_submenu();
        selected_item = items.size();
        for (unsigned long i = 0; i < items.size(); ++i)
        {
            if ((items[i]->has_click_event() || submenus[i]) && item_enabled[i])
            {
                selected_item = i;
                break;
            }
        }
        invalidate_rectangle(cur_rect);
    }

// ----------------------------------------------------------------------------------------

    bool popup_menu::
    forwarded_on_keydown (
        unsigned long key,
        bool is_printable,
        unsigned long state
    )
    {
        auto_mutex M(wm);
        // do nothing if this popup menu is empty
        if (items.size() == 0)
            return false;

        // check if the selected item is a submenu
        if (selected_item != submenus.size() && submenus[selected_item] != 0 && submenu_open)
        {
            // send the key to the submenu and return if that menu used the key
            if (submenus[selected_item]->forwarded_on_keydown(key,is_printable,state) == true)
                return true;
        }

        if (key == KEY_UP)
        {
            for (unsigned long i = 0; i < items.size(); ++i)
            {
                selected_item = (selected_item + items.size() - 1)%items.size();
                // only stop looking if this one is enabled and has a click event or is a submenu
                if (item_enabled[selected_item] && (items[selected_item]->has_click_event() || submenus[selected_item]) )
                    break;
            }
            invalidate_rectangle(cur_rect);
            return true;
        }
        else if (key == KEY_DOWN)
        {
            for (unsigned long i = 0; i < items.size(); ++i)
            {
                selected_item = (selected_item + 1)%items.size();
                // only stop looking if this one is enabled and has a click event or is a submenu
                if (item_enabled[selected_item] && (items[selected_item]->has_click_event() || submenus[selected_item]))
                    break;
            }
            invalidate_rectangle(cur_rect);
            return true;
        }
        else if (key == KEY_RIGHT && submenu_open == false && display_selected_submenu())
        {
            submenus[selected_item]->select_first_item();
            return true;
        }
        else if (key == KEY_LEFT && selected_item != submenus.size() &&
                 submenus[selected_item] != 0 && submenu_open)
        {
            close_submenu();
            return true;
        }
        else if (key == '\n')
        {
            if (selected_item != submenus.size() && (items[selected_item]->has_click_event() || submenus[selected_item]))
            {
                const long idx = selected_item;
                // only hide this popup window if this isn't a submenu
                if (submenus[idx] == 0)
                {
                    hide();
                    hide_handlers.reset();
                    while (hide_handlers.move_next())
                        hide_handlers.element()();
                }
                else
                {
                    display_selected_submenu();
                    submenus[idx]->select_first_item();
                }
                items[idx]->on_click();
                return true;
            }
        }
        else if (is_printable)
        {
            // check if there is a hotkey for this key
            for (unsigned long i = 0; i < items.size(); ++i)
            {
                if (std::tolower(key) == std::tolower(items[i]->get_hot_key()) &&
                    (items[i]->has_click_event() || submenus[i]) && item_enabled[i] )
                {
                    // only hide this popup window if this isn't a submenu
                    if (submenus[i] == 0)
                    {
                        hide();
                        hide_handlers.reset();
                        while (hide_handlers.move_next())
                            hide_handlers.element()();
                    }
                    else
                    {
                        if (selected_item != items.size())
                            invalidate_rectangle(line_rects[selected_item]);

                        selected_item = i;
                        display_selected_submenu();
                        invalidate_rectangle(line_rects[i]);
                        submenus[i]->select_first_item();
                    }
                    items[i]->on_click();
                }
            }

            // always say we use a printable key for hotkeys
            return true;
        }

        return false;
    }

// ----------------------------------------------------------------------------------------

    void popup_menu::
    on_submenu_hide (
    )
    {
        hide();
        hide_handlers.reset();
        while (hide_handlers.move_next())
            hide_handlers.element()();
    }

// ----------------------------------------------------------------------------------------

    void popup_menu::
    on_window_resized(
    )
    {
        invalidate_rectangle(win_rect);
    }

// ----------------------------------------------------------------------------------------

    void popup_menu::
    on_mouse_up (
        unsigned long btn,
        unsigned long,
        long x,
        long y
    )
    {
        if (cur_rect.contains(x,y) && btn == LEFT)
        {
            // figure out which item this was on
            for (unsigned long i = 0; i < items.size(); ++i)
            {
                if (line_rects[i].contains(x,y) && item_enabled[i] && items[i]->has_click_event())
                {
                    // only hide this popup window if this isn't a submenu
                    if (submenus[i] == 0)
                    {
                        hide();
                        hide_handlers.reset();
                        while (hide_handlers.move_next())
                            hide_handlers.element()();
                    }
                    items[i]->on_click();
                    break;
                }
            }
        }
    }

// ----------------------------------------------------------------------------------------

    void popup_menu::
    on_mouse_move (
        unsigned long ,
        long x,
        long y
    )
    {
        if (cur_rect.contains(x,y))
        {
            // check if the mouse is still in the same rect it was in last time
            rectangle last_rect;
            if (selected_item != submenus.size())
            {
                last_rect = line_rects[selected_item];
            }

            // if the mouse isn't in the same rectangle any more
            if (last_rect.contains(x,y) == false)
            {
                if (selected_item != submenus.size())
                {
                    invalidate_rectangle(last_rect);
                    close_submenu();
                    selected_item = submenus.size();
                }

                // figure out if we should redraw any menu items
                for (unsigned long i = 0; i < items.size(); ++i)
                {
                    if (items[i]->has_click_event() || submenus[i])
                    {
                        if (line_rects[i].contains(x,y))
                        {
                            selected_item = i;
                            break;
                        }
                    }
                }

                // if we found a rectangle that contains the mouse then
                // tell it to redraw itself
                if (selected_item != submenus.size())
                {
                    display_selected_submenu();
                    invalidate_rectangle(line_rects[selected_item]);
                }
            }
        }
    }

// ----------------------------------------------------------------------------------------

    void popup_menu::
    close_submenu (
    )
    {
        if (selected_item != submenus.size() && submenus[selected_item] && submenu_open)
        {
            submenus[selected_item]->hide();
            submenu_open = false;
        }
    }

// ----------------------------------------------------------------------------------------

    bool popup_menu::
    display_selected_submenu (
    )
    {
        // show the submenu if one exists
        if (selected_item != submenus.size() && submenus[selected_item])
        {
            long wx, wy;
            get_pos(wx,wy);
            wx += line_rects[selected_item].right();
            wy += line_rects[selected_item].top();
            submenus[selected_item]->set_pos(wx+1,wy-2);
            submenus[selected_item]->show();
            submenu_open = true;
            return true;
        }
        return false;
    }

// ----------------------------------------------------------------------------------------

    void popup_menu::
    on_mouse_leave (
    )
    {
        if (selected_item != submenus.size())
        {
            // only unhighlight a menu item if it isn't a submenu item
            if (submenus[selected_item] == 0)
            {
                invalidate_rectangle(line_rects[selected_item]);
                selected_item = submenus.size();
            }
        }
    }

// ----------------------------------------------------------------------------------------

    void popup_menu::
    paint (
        const canvas& c
    )
    {
        c.fill(200,200,200);
        draw_rectangle(c, win_rect);
        for (unsigned long i = 0; i < items.size(); ++i)
        {
            bool is_selected = false;
            if (selected_item != submenus.size() && i == selected_item &&
                item_enabled[i])
                is_selected = true;

            items[i]->draw_background(c,line_rects[i], item_enabled[i], is_selected);
            items[i]->draw_left(c,left_rects[i], item_enabled[i], is_selected);
            items[i]->draw_middle(c,middle_rects[i], item_enabled[i], is_selected);
            items[i]->draw_right(c,right_rects[i], item_enabled[i], is_selected);
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//              class zoomable_region
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    zoomable_region::
    zoomable_region (
        drawable_window& w,
        unsigned long events
    ) :
        drawable(w,MOUSE_CLICK | MOUSE_WHEEL | MOUSE_MOVE | events),
        min_scale(0.15),
        max_scale(1.0),
        zoom_increment_(0.90),
        vsb(w, scroll_bar::VERTICAL),
        hsb(w, scroll_bar::HORIZONTAL)
    {
        scale = 1;
        mouse_drag_screen = false;
        style.reset(new scrollable_region_style_default());

        hsb.set_scroll_handler(*this,&zoomable_region::on_h_scroll);
        vsb.set_scroll_handler(*this,&zoomable_region::on_v_scroll);
    }

// ----------------------------------------------------------------------------------------

    zoomable_region::
    ~zoomable_region()
    {
    }

// ----------------------------------------------------------------------------------------

    void zoomable_region::
    set_pos (
        long x,
        long y
    )
    {
        auto_mutex M(m);
        drawable::set_pos(x,y);
        const long border_size = style->get_border_size();
        vsb.set_pos(rect.right()-border_size+1-vsb.width(),rect.top()+border_size);
        hsb.set_pos(rect.left()+border_size,rect.bottom()-border_size+1-hsb.height());

        display_rect_ = rectangle(rect.left()+border_size,
                                  rect.top()+border_size,
                                  rect.right()-border_size-vsb.width(),
                                  rect.bottom()-border_size-hsb.height());

    }

// ----------------------------------------------------------------------------------------

    void zoomable_region::
    set_zoom_increment (
        double zi
    )
    {
        DLIB_ASSERT(0.0 < zi && zi < 1.0,
                    "\tvoid zoomable_region::set_zoom_increment(zi)"
                    << "\n\t the zoom increment must be between 0 and 1"
                    << "\n\t zi:   " << zi
                    << "\n\t this: " << this
        );

        auto_mutex M(m);
        zoom_increment_ = zi;
    }

// ----------------------------------------------------------------------------------------

    double zoomable_region::
    zoom_increment (
    ) const
    {
        auto_mutex M(m);
        return zoom_increment_;
    }

// ----------------------------------------------------------------------------------------

    void zoomable_region::
    set_max_zoom_scale (
        double ms
    )
    {
        DLIB_ASSERT(ms > 0,
                    "\tvoid zoomable_region::set_max_zoom_scale(ms)"
                    << "\n\t the max zoom scale must be greater than 0"
                    << "\n\t ms:   " << ms
                    << "\n\t this: " << this
        );

        auto_mutex M(m);
        max_scale = ms;
        if (scale > ms)
        {
            scale = max_scale;
            lr_point = gui_to_graph_space(point(display_rect_.right(),display_rect_.bottom()));
            redraw_graph();
        }
    }

// ----------------------------------------------------------------------------------------

    void zoomable_region::
    set_min_zoom_scale (
        double ms
    )
    {
        DLIB_ASSERT(ms > 0,
                    "\tvoid zoomable_region::set_min_zoom_scale(ms)"
                    << "\n\t the min zoom scale must be greater than 0"
                    << "\n\t ms:   " << ms
                    << "\n\t this: " << this
        );

        auto_mutex M(m);
        min_scale = ms;

        if (scale < ms)
        {
            scale = min_scale;
        }

        // just call set_size so that everything gets redrawn right
        set_size(rect.width(), rect.height());
    }

// ----------------------------------------------------------------------------------------

    double zoomable_region::
    min_zoom_scale (
    ) const
    {
        auto_mutex M(m);
        return min_scale;
    }

// ----------------------------------------------------------------------------------------

    double zoomable_region::
    max_zoom_scale (
    ) const
    {
        auto_mutex M(m);
        return max_scale;
    }

// ----------------------------------------------------------------------------------------

    void zoomable_region::
    set_size (
        unsigned long width,
        unsigned long height
    )
    {
        auto_mutex M(m);
        rectangle old(rect);
        const long border_size = style->get_border_size();
        rect = resize_rect(rect,width,height);
        vsb.set_pos(rect.right()-border_size+1-vsb.width(),  rect.top()+border_size);
        hsb.set_pos(rect.left()+border_size,  rect.bottom()-border_size+1-hsb.height());

        display_rect_ = rectangle(rect.left()+border_size,
                                  rect.top()+border_size,
                                  rect.right()-border_size-vsb.width(),
                                  rect.bottom()-border_size-hsb.height());
        vsb.set_length(display_rect_.height());
        hsb.set_length(display_rect_.width());
        parent.invalidate_rectangle(rect+old);

        const double old_scale = scale;
        const vector<double,2> old_gr_orig(gr_orig);
        scale = min_scale;
        gr_orig = vector<double,2>(0,0);
        lr_point = gui_to_graph_space(point(display_rect_.right(),display_rect_.bottom()));
        scale = old_scale;

        // call adjust_origin() so that the scroll bars get their max slider positions
        // setup right
        const point rect_corner(display_rect_.left(), display_rect_.top());
        adjust_origin(rect_corner, old_gr_orig);
    }

// ----------------------------------------------------------------------------------------

    void zoomable_region::
    show (
    )
    {
        auto_mutex M(m);
        drawable::show();
        hsb.show();
        vsb.show();
    }

// ----------------------------------------------------------------------------------------

    void zoomable_region::
    hide (
    )
    {
        auto_mutex M(m);
        drawable::hide();
        hsb.hide();
        vsb.hide();
    }

// ----------------------------------------------------------------------------------------

    void zoomable_region::
    enable (
    )
    {
        auto_mutex M(m);
        drawable::enable();
        hsb.enable();
        vsb.enable();
    }

// ----------------------------------------------------------------------------------------

    void zoomable_region::
    disable (
    )
    {
        auto_mutex M(m);
        drawable::disable();
        hsb.disable();
        vsb.disable();
    }

// ----------------------------------------------------------------------------------------

    void zoomable_region::
    set_z_order (
        long order
    )
    {
        auto_mutex M(m);
        drawable::set_z_order(order);
        hsb.set_z_order(order);
        vsb.set_z_order(order);
    }

// ----------------------------------------------------------------------------------------

    point zoomable_region::
    graph_to_gui_space (
        const vector<double,2>& p
    ) const
    {
        const point rect_corner(display_rect_.left(), display_rect_.top());
        return (p - gr_orig)*scale + rect_corner;
    }

// ----------------------------------------------------------------------------------------

    vector<double,2> zoomable_region::
    gui_to_graph_space (
        const point& p
    ) const
    {
        const point rect_corner(display_rect_.left(), display_rect_.top());
        return (p - rect_corner)/scale + gr_orig;
    }

// ----------------------------------------------------------------------------------------

    point zoomable_region::
    max_graph_point (
    ) const
    {
        return lr_point;
    }

// ----------------------------------------------------------------------------------------

    rectangle zoomable_region::
    display_rect (
    ) const
    {
        return display_rect_;
    }

// ----------------------------------------------------------------------------------------

    double zoomable_region::
    zoom_scale (
    ) const
    {
        return scale;
    }

// ----------------------------------------------------------------------------------------

    void zoomable_region::
    set_zoom_scale (
        double new_scale
    )
    {
        // if new_scale isn't in the right range then put it back in range before we do the
        // rest of this function
        if (!(min_scale <= new_scale && new_scale <= max_scale))
        {
            if (new_scale > max_scale)
                new_scale = max_scale;
            else
                new_scale = min_scale;
        }

        // find the point in the center of the graph area
        point center((display_rect_.left()+display_rect_.right())/2,  (display_rect_.top()+display_rect_.bottom())/2);
        point graph_p(gui_to_graph_space(center));
        scale = new_scale;
        adjust_origin(center, graph_p);
        redraw_graph();
    }

// ----------------------------------------------------------------------------------------

    void zoomable_region::
    center_display_at_graph_point (
        const vector<double,2>& p
    )
    {
        // find the point in the center of the graph area
        point center((display_rect_.left()+display_rect_.right())/2,  (display_rect_.top()+display_rect_.bottom())/2);
        adjust_origin(center, p);
        redraw_graph();
    }

// ----------------------------------------------------------------------------------------

    void zoomable_region::
    on_wheel_down (
        unsigned long
    )
    {
        // zoom out
        if (enabled && !hidden && scale > min_scale && display_rect_.contains(lastx,lasty))
        {
            point gui_p(lastx,lasty);
            point graph_p(gui_to_graph_space(gui_p));
            const double old_scale = scale;
            scale *= zoom_increment_;
            if (scale < min_scale)
                scale = min_scale;
            redraw_graph();
            adjust_origin(gui_p, graph_p);

            if (scale != old_scale)
                on_view_changed();
        }
    }

// ----------------------------------------------------------------------------------------

    void zoomable_region::
    on_wheel_up (
        unsigned long
    )
    {
        // zoom in
        if (enabled && !hidden && scale < max_scale  && display_rect_.contains(lastx,lasty))
        {
            point gui_p(lastx,lasty);
            point graph_p(gui_to_graph_space(gui_p));
            const double old_scale = scale;
            scale /= zoom_increment_;
            if (scale > max_scale)
                scale = max_scale;
            redraw_graph();
            adjust_origin(gui_p, graph_p);

            if (scale != old_scale)
                on_view_changed();
        }
    }

// ----------------------------------------------------------------------------------------

    void zoomable_region::
    on_mouse_move (
        unsigned long state,
        long x,
        long y
    )
    {
        if (enabled && !hidden && mouse_drag_screen)
        {
            adjust_origin(point(x,y), drag_screen_point);
            redraw_graph();
            on_view_changed();
        }

        // check if the mouse isn't being dragged anymore
        if ((state & base_window::LEFT) == 0)
        {
            mouse_drag_screen = false;
        }
    }

// ----------------------------------------------------------------------------------------

    void zoomable_region::
    on_mouse_up (
        unsigned long ,
        unsigned long ,
        long ,
        long
    )
    {
        mouse_drag_screen = false;
    }

// ----------------------------------------------------------------------------------------

    void zoomable_region::
    on_mouse_down (
        unsigned long btn,
        unsigned long ,
        long x,
        long y,
        bool
    )
    {
        if (enabled && !hidden && display_rect_.contains(x,y) && btn == base_window::LEFT)
        {
            mouse_drag_screen = true;
            drag_screen_point = gui_to_graph_space(point(x,y));
        }
    }

// ----------------------------------------------------------------------------------------

    void zoomable_region::
    draw (
        const canvas& c
    ) const
    {
        style->draw_scrollable_region_border(c, rect, enabled);
    }

// ----------------------------------------------------------------------------------------

    void zoomable_region::
    on_h_scroll (
    )
    {
        gr_orig.x() = hsb.slider_pos();
        redraw_graph();

        on_view_changed();
    }

// ----------------------------------------------------------------------------------------

    void zoomable_region::
    on_v_scroll (
    )
    {
        gr_orig.y() = vsb.slider_pos();
        redraw_graph();

        on_view_changed();
    }

// ----------------------------------------------------------------------------------------

    void zoomable_region::
    redraw_graph (
    )
    {
        parent.invalidate_rectangle(display_rect_);
    }

// ----------------------------------------------------------------------------------------

    void zoomable_region::
    adjust_origin (
        const point& gui_p,
        const vector<double,2>& graph_p
    )
    {
        const point rect_corner(display_rect_.left(), display_rect_.top());
        const dlib::vector<double,2> v(gui_p - rect_corner);
        gr_orig = graph_p - v/scale;

        // make sure the origin isn't outside the point (0,0)
        if (gr_orig.x() < 0)
            gr_orig.x() = 0;
        if (gr_orig.y() < 0)
            gr_orig.y() = 0;

        // make sure the lower right corner of the display_rect_ doesn't map to a point beyond lr_point
        point lr_rect_corner(display_rect_.right(), display_rect_.bottom());
        point p = graph_to_gui_space(lr_point);
        vector<double,2> lr_rect_corner_graph_space(gui_to_graph_space(lr_rect_corner));
        vector<double,2> delta(lr_point - lr_rect_corner_graph_space);
        if (lr_rect_corner.x() > p.x())
        {
            gr_orig.x() += delta.x();
        }

        if (lr_rect_corner.y() > p.y())
        {
            gr_orig.y() += delta.y();
        }

        const vector<double,2> ul_rect_corner_graph_space(gui_to_graph_space(rect_corner));
        lr_rect_corner_graph_space = gui_to_graph_space(lr_rect_corner);
        // now adjust the scroll bars

        hsb.set_max_slider_pos((unsigned long)std::max(lr_point.x()-(lr_rect_corner_graph_space.x()-ul_rect_corner_graph_space.x()),0.0));
        vsb.set_max_slider_pos((unsigned long)std::max(lr_point.y()-(lr_rect_corner_graph_space.y()-ul_rect_corner_graph_space.y()),0.0));
        // adjust slider position now.
        hsb.set_slider_pos(static_cast<long>(ul_rect_corner_graph_space.x()));
        vsb.set_slider_pos(static_cast<long>(ul_rect_corner_graph_space.y()));

    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//              class scrollable_region
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    scrollable_region::
    scrollable_region (
        drawable_window& w,
        unsigned long events
    ) :
        drawable(w, MOUSE_WHEEL|events|MOUSE_CLICK|MOUSE_MOVE),
        hsb(w,scroll_bar::HORIZONTAL),
        vsb(w,scroll_bar::VERTICAL),
        hscroll_bar_inc(1),
        vscroll_bar_inc(1),
        h_wheel_scroll_bar_inc(1),
        v_wheel_scroll_bar_inc(1),
        mouse_drag_enabled_(false),
        user_is_dragging_mouse(false)
    {
        style.reset(new scrollable_region_style_default());

        hsb.set_scroll_handler(*this,&scrollable_region::on_h_scroll);
        vsb.set_scroll_handler(*this,&scrollable_region::on_v_scroll);
    }

// ----------------------------------------------------------------------------------------

    scrollable_region::
    ~scrollable_region (
    )
    {
    }

// ----------------------------------------------------------------------------------------

    void scrollable_region::
    show (
    )
    {
        auto_mutex M(m);
        drawable::show();
        if (need_h_scroll())
            hsb.show();
        if (need_v_scroll())
            vsb.show();
    }

// ----------------------------------------------------------------------------------------

    void scrollable_region::
    hide (
    )
    {
        auto_mutex M(m);
        drawable::hide();
        hsb.hide();
        vsb.hide();
    }

// ----------------------------------------------------------------------------------------

    void scrollable_region::
    enable (
    )
    {
        auto_mutex M(m);
        drawable::enable();
        hsb.enable();
        vsb.enable();
    }

// ----------------------------------------------------------------------------------------

    void scrollable_region::
    disable (
    )
    {
        auto_mutex M(m);
        drawable::disable();
        hsb.disable();
        vsb.disable();
    }

// ----------------------------------------------------------------------------------------

    void scrollable_region::
    set_z_order (
        long order
    )
    {
        auto_mutex M(m);
        drawable::set_z_order(order);
        hsb.set_z_order(order);
        vsb.set_z_order(order);
    }

// ----------------------------------------------------------------------------------------

    void scrollable_region::
    set_size (
        unsigned long width,
        unsigned long height
    )
    {
        auto_mutex M(m);
        rectangle old(rect);
        rect = resize_rect(rect,width,height);
        vsb.set_pos(rect.right()-style->get_border_size()-vsb.width()+1, rect.top()+style->get_border_size());
        hsb.set_pos(rect.left()+style->get_border_size(), rect.bottom()-style->get_border_size()-hsb.height()+1);

        // adjust the display_rect_
        if (need_h_scroll() && need_v_scroll())
        {
            // both scroll bars aren't hidden
            if (!hidden)
            {
                vsb.show();
                hsb.show();
            }
            display_rect_ = rectangle( rect.left()+style->get_border_size(),
                                       rect.top()+style->get_border_size(),
                                       rect.right()-style->get_border_size()-vsb.width(),
                                       rect.bottom()-style->get_border_size()-hsb.height());

            // figure out how many scroll bar positions there should be
            unsigned long hdelta = total_rect_.width()-display_rect_.width();
            unsigned long vdelta = total_rect_.height()-display_rect_.height();
            hdelta = (hdelta+hscroll_bar_inc-1)/hscroll_bar_inc;
            vdelta = (vdelta+vscroll_bar_inc-1)/vscroll_bar_inc;

            hsb.set_max_slider_pos(hdelta);
            vsb.set_max_slider_pos(vdelta);

            vsb.set_jump_size((display_rect_.height()+vscroll_bar_inc-1)/vscroll_bar_inc/2+1);
            hsb.set_jump_size((display_rect_.width()+hscroll_bar_inc-1)/hscroll_bar_inc/2+1);
        }
        else if (need_h_scroll())
        {
            // only hsb is hidden
            if (!hidden)
            {
                hsb.show();
                vsb.hide();
            }
            display_rect_ = rectangle( rect.left()+style->get_border_size(),
                                       rect.top()+style->get_border_size(),
                                       rect.right()-style->get_border_size(),
                                       rect.bottom()-style->get_border_size()-hsb.height());

            // figure out how many scroll bar positions there should be
            unsigned long hdelta = total_rect_.width()-display_rect_.width();
            hdelta = (hdelta+hscroll_bar_inc-1)/hscroll_bar_inc;

            hsb.set_max_slider_pos(hdelta);
            vsb.set_max_slider_pos(0);

            hsb.set_jump_size((display_rect_.width()+hscroll_bar_inc-1)/hscroll_bar_inc/2+1);
        }
        else if (need_v_scroll())
        {
            // only vsb is hidden
            if (!hidden)
            {
                hsb.hide();
                vsb.show();
            }
            display_rect_ = rectangle( rect.left()+style->get_border_size(),
                                       rect.top()+style->get_border_size(),
                                       rect.right()-style->get_border_size()-vsb.width(),
                                       rect.bottom()-style->get_border_size());

            unsigned long vdelta = total_rect_.height()-display_rect_.height();
            vdelta = (vdelta+vscroll_bar_inc-1)/vscroll_bar_inc;

            hsb.set_max_slider_pos(0);
            vsb.set_max_slider_pos(vdelta);

            vsb.set_jump_size((display_rect_.height()+vscroll_bar_inc-1)/vscroll_bar_inc/2+1);
        }
        else
        {
            // both are hidden
            if (!hidden)
            {
                hsb.hide();
                vsb.hide();
            }
            display_rect_ = rectangle( rect.left()+style->get_border_size(),
                                       rect.top()+style->get_border_size(),
                                       rect.right()-style->get_border_size(),
                                       rect.bottom()-style->get_border_size());

            hsb.set_max_slider_pos(0);
            vsb.set_max_slider_pos(0);
        }

        vsb.set_length(display_rect_.height());
        hsb.set_length(display_rect_.width());

        // adjust the total_rect_ position by trigging the scroll events
        on_h_scroll();
        on_v_scroll();

        parent.invalidate_rectangle(rect+old);
    }

// ----------------------------------------------------------------------------------------

    unsigned long scrollable_region::
    horizontal_mouse_wheel_scroll_increment (
    ) const
    {
        auto_mutex M(m);
        return h_wheel_scroll_bar_inc;
    }

// ----------------------------------------------------------------------------------------

    unsigned long scrollable_region::
    vertical_mouse_wheel_scroll_increment (
    ) const
    {
        auto_mutex M(m);
        return v_wheel_scroll_bar_inc;
    }

// ----------------------------------------------------------------------------------------

    void scrollable_region::
    set_horizontal_mouse_wheel_scroll_increment (
        unsigned long inc
    )
    {
        auto_mutex M(m);
        h_wheel_scroll_bar_inc = inc;
    }

// ----------------------------------------------------------------------------------------

    void scrollable_region::
    set_vertical_mouse_wheel_scroll_increment (
        unsigned long inc
    )
    {
        auto_mutex M(m);
        v_wheel_scroll_bar_inc = inc;
    }

// ----------------------------------------------------------------------------------------

    unsigned long scrollable_region::
    horizontal_scroll_increment (
    ) const
    {
        auto_mutex M(m);
        return hscroll_bar_inc;
    }

// ----------------------------------------------------------------------------------------

    unsigned long scrollable_region::
    vertical_scroll_increment (
    ) const
    {
        auto_mutex M(m);
        return vscroll_bar_inc;
    }

// ----------------------------------------------------------------------------------------

    void scrollable_region::
    set_horizontal_scroll_increment (
        unsigned long inc
    )
    {
        auto_mutex M(m);
        hscroll_bar_inc = inc;
        // call set_size to reset the scroll bars
        set_size(rect.width(),rect.height());
    }

// ----------------------------------------------------------------------------------------

    void scrollable_region::
    set_vertical_scroll_increment (
        unsigned long inc
    )
    {
        auto_mutex M(m);
        vscroll_bar_inc = inc;
        // call set_size to reset the scroll bars
        set_size(rect.width(),rect.height());
    }

// ----------------------------------------------------------------------------------------

    long scrollable_region::
    horizontal_scroll_pos (
    ) const
    {
        auto_mutex M(m);
        return hsb.slider_pos();
    }

// ----------------------------------------------------------------------------------------

    long scrollable_region::
    vertical_scroll_pos (
    ) const
    {
        auto_mutex M(m);
        return vsb.slider_pos();
    }

// ----------------------------------------------------------------------------------------

    void scrollable_region::
    set_horizontal_scroll_pos (
        long pos
    )
    {
        auto_mutex M(m);

        hsb.set_slider_pos(pos);
        on_h_scroll();
    }

// ----------------------------------------------------------------------------------------

    void scrollable_region::
    set_vertical_scroll_pos (
        long pos
    )
    {
        auto_mutex M(m);

        vsb.set_slider_pos(pos);
        on_v_scroll();
    }

// ----------------------------------------------------------------------------------------

    void scrollable_region::
    set_pos (
        long x,
        long y
    )
    {
        auto_mutex M(m);
        drawable::set_pos(x,y);
        vsb.set_pos(rect.right()-style->get_border_size()-vsb.width()+1, rect.top()+style->get_border_size());
        hsb.set_pos(rect.left()+style->get_border_size(), rect.bottom()-style->get_border_size()-hsb.height()+1);

        const long delta_x = total_rect_.left() - display_rect_.left();
        const long delta_y = total_rect_.top() - display_rect_.top();

        display_rect_ = move_rect(display_rect_, rect.left()+style->get_border_size(), rect.top()+style->get_border_size());

        total_rect_ = move_rect(total_rect_, display_rect_.left()+delta_x, display_rect_.top()+delta_y);
    }

// ----------------------------------------------------------------------------------------

    bool scrollable_region::
    mouse_drag_enabled (
    ) const
    {
        auto_mutex M(m);
        return mouse_drag_enabled_;
    }

// ----------------------------------------------------------------------------------------

    void scrollable_region::
    enable_mouse_drag (
    )
    {
        auto_mutex M(m);
        mouse_drag_enabled_ = true;
    }

// ----------------------------------------------------------------------------------------

    void scrollable_region::
    disable_mouse_drag (
    )
    {
        auto_mutex M(m);
        mouse_drag_enabled_ = false;
    }

// ----------------------------------------------------------------------------------------

    const rectangle& scrollable_region::
    display_rect (
    ) const
    {
        return display_rect_;
    }

// ----------------------------------------------------------------------------------------

    void scrollable_region::
    set_total_rect_size (
        unsigned long width,
        unsigned long height
    )
    {
        DLIB_ASSERT((width > 0 && height > 0) || (width == 0 && height == 0),
                    "\tvoid scrollable_region::set_total_rect_size(width,height)"
                    << "\n\twidth and height must be > 0 or both == 0"
                    << "\n\twidth:  " << width
                    << "\n\theight: " << height
                    << "\n\tthis: " << this
        );

        total_rect_ = move_rect(rectangle(width,height),
                                display_rect_.left()-static_cast<long>(hsb.slider_pos()),
                                display_rect_.top()-static_cast<long>(vsb.slider_pos()));

        // call this just to reconfigure the scroll bars
        set_size(rect.width(),rect.height());
    }

// ----------------------------------------------------------------------------------------

    const rectangle& scrollable_region::
    total_rect (
    ) const
    {
        return total_rect_;
    }

// ----------------------------------------------------------------------------------------

    void scrollable_region::
    scroll_to_rect (
        const rectangle& r_
    )
    {
        const rectangle r(total_rect_.intersect(r_));
        const rectangle old(total_rect_);
        // adjust the horizontal scroll bar so that r fits as best as possible
        if (r.left() < display_rect_.left())
        {
            long distance = (r.left()-total_rect_.left())/hscroll_bar_inc;
            hsb.set_slider_pos(distance);
        }
        else if (r.right() > display_rect_.right())
        {
            long distance = (r.right()-total_rect_.left()-display_rect_.width()+hscroll_bar_inc)/hscroll_bar_inc;
            hsb.set_slider_pos(distance);
        }

        // adjust the vertical scroll bar so that r fits as best as possible
        if (r.top() < display_rect_.top())
        {
            long distance = (r.top()-total_rect_.top())/vscroll_bar_inc;
            vsb.set_slider_pos(distance);
        }
        else if (r.bottom() > display_rect_.bottom())
        {
            long distance = (r.bottom()-total_rect_.top()-display_rect_.height()+vscroll_bar_inc)/vscroll_bar_inc;
            vsb.set_slider_pos(distance);
        }

        // adjust total_rect_ so that it matches where the scroll bars are now
        total_rect_ = move_rect(total_rect_,
                                display_rect_.left()-hscroll_bar_inc*hsb.slider_pos(),
                                display_rect_.top()-vscroll_bar_inc*vsb.slider_pos());

        // only redraw if we actually changed something
        if (total_rect_ != old)
        {
            parent.invalidate_rectangle(display_rect_);
        }
    }

// ----------------------------------------------------------------------------------------

    void scrollable_region::
    on_wheel_down (
        unsigned long
    )
    {
        if (rect.contains(lastx,lasty) && enabled && !hidden)
        {
            if (need_v_scroll())
            {
                long pos = vsb.slider_pos();
                vsb.set_slider_pos(pos+(long)v_wheel_scroll_bar_inc);
                on_v_scroll();
            }
            else if (need_h_scroll())
            {
                long pos = hsb.slider_pos();
                hsb.set_slider_pos(pos+(long)h_wheel_scroll_bar_inc);
                on_h_scroll();
            }
        }
    }

// ----------------------------------------------------------------------------------------

    void scrollable_region::
    on_mouse_move (
        unsigned long state,
        long x,
        long y
    )
    {
        if (enabled && !hidden && user_is_dragging_mouse && state==base_window::LEFT)
        {
            point current_delta = point(x,y) - point(total_rect().left(), total_rect().top());
            rectangle new_rect(translate_rect(display_rect(), drag_origin - current_delta));
            new_rect = centered_rect(new_rect, new_rect.width()-hscroll_bar_inc, new_rect.height()-vscroll_bar_inc);
            scroll_to_rect(new_rect);
            on_view_changed();
        }
        else
        {
            user_is_dragging_mouse = false;
        }
    }

// ----------------------------------------------------------------------------------------

    void scrollable_region::
    on_mouse_down (
        unsigned long btn,
        unsigned long ,
        long x,
        long y,
        bool
    )
    {
        if (mouse_drag_enabled_ && enabled && !hidden && display_rect().contains(x,y) && (btn==base_window::LEFT))
        {
            drag_origin = point(x,y) - point(total_rect().left(), total_rect().top());
            user_is_dragging_mouse = true;
        }
        else
        {
            user_is_dragging_mouse = false;
        }
    }

// ----------------------------------------------------------------------------------------

    void scrollable_region::
    on_mouse_up   (
        unsigned long ,
        unsigned long ,
        long ,
        long
    )
    {
        user_is_dragging_mouse = false;
    }

// ----------------------------------------------------------------------------------------

    void scrollable_region::
    on_wheel_up (
        unsigned long
    )
    {
        if (rect.contains(lastx,lasty) && enabled && !hidden)
        {
            if (need_v_scroll())
            {
                long pos = vsb.slider_pos();
                vsb.set_slider_pos(pos-(long)v_wheel_scroll_bar_inc);
                on_v_scroll();
            }
            else if (need_h_scroll())
            {
                long pos = hsb.slider_pos();
                hsb.set_slider_pos(pos-(long)h_wheel_scroll_bar_inc);
                on_h_scroll();
            }
        }
    }

// ----------------------------------------------------------------------------------------

    void scrollable_region::
    draw (
        const canvas& c
    ) const
    {
        style->draw_scrollable_region_border(c, rect, enabled);
    }

// ----------------------------------------------------------------------------------------

    bool scrollable_region::
    need_h_scroll (
    ) const
    {
        if (total_rect_.width() > rect.width()-style->get_border_size()*2)
        {
            return true;
        }
        else
        {
            // check if we would need a vertical scroll bar and if adding one would make us need
            // a horizontal one
            if (total_rect_.height() > rect.height()-style->get_border_size()*2 &&
                total_rect_.width() > rect.width()-style->get_border_size()*2-vsb.width())
                return true;
            else
                return false;
        }
    }

// ----------------------------------------------------------------------------------------

    bool scrollable_region::
    need_v_scroll (
    ) const
    {
        if (total_rect_.height() > rect.height()-style->get_border_size()*2)
        {
            return true;
        }
        else
        {
            // check if we would need a horizontal scroll bar and if adding one would make us need
            // a vertical_scroll_pos one
            if (total_rect_.width() > rect.width()-style->get_border_size()*2 &&
                total_rect_.height() > rect.height()-style->get_border_size()*2-hsb.height())
                return true;
            else
                return false;
        }
    }

// ----------------------------------------------------------------------------------------

    void scrollable_region::
    on_h_scroll (
    )
    {
        total_rect_ = move_rect(total_rect_, display_rect_.left()-hscroll_bar_inc*hsb.slider_pos(), total_rect_.top());
        parent.invalidate_rectangle(display_rect_);
        if (events_are_enabled())
            on_view_changed();
    }

// ----------------------------------------------------------------------------------------

    void scrollable_region::
    on_v_scroll (
    )
    {
        total_rect_ = move_rect(total_rect_, total_rect_.left(), display_rect_.top()-vscroll_bar_inc*vsb.slider_pos());
        parent.invalidate_rectangle(display_rect_);
        if (events_are_enabled())
            on_view_changed();
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// class popup_menu_region
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    popup_menu_region::
    popup_menu_region(
        drawable_window& w
    ) :
        drawable(w,MOUSE_CLICK | KEYBOARD_EVENTS | FOCUS_EVENTS | WINDOW_MOVED),
        popup_menu_shown(false)
    {

        menu_.set_on_hide_handler(*this,&popup_menu_region::on_menu_becomes_hidden);
        enable_events();
    }

// ----------------------------------------------------------------------------------------

    popup_menu_region::
    ~popup_menu_region(
    )
    {
        disable_events();
    }

// ----------------------------------------------------------------------------------------

    void popup_menu_region::
    set_size (
        unsigned long width,
        unsigned long height
    )
    {
        auto_mutex M(m);
        rect = resize_rect(rect,width,height);
    }

// ----------------------------------------------------------------------------------------

    void popup_menu_region::
    set_rect (
        const rectangle& new_rect
    )
    {
        auto_mutex M(m);
        rect = new_rect;
    }

// ----------------------------------------------------------------------------------------

    popup_menu& popup_menu_region::
    menu (
    )
    {
        return menu_;
    }

// ----------------------------------------------------------------------------------------

    void popup_menu_region::
    hide (
    )
    {
        auto_mutex M(m);
        drawable::hide();
        menu_.hide();
        popup_menu_shown = false;
    }

// ----------------------------------------------------------------------------------------

    void popup_menu_region::
    disable (
    )
    {
        auto_mutex M(m);
        drawable::disable();
        menu_.hide();
        popup_menu_shown = false;
    }

// ----------------------------------------------------------------------------------------

    void popup_menu_region::
    on_keydown (
        unsigned long key,
        bool is_printable,
        unsigned long state
    )
    {
        if (enabled && !hidden && popup_menu_shown)
        {
            menu_.forwarded_on_keydown(key, is_printable, state);
        }
        else if (popup_menu_shown)
        {
            menu_.hide();
            popup_menu_shown = false;
        }

        if (key == (unsigned long)base_window::KEY_ESC)
        {
            menu_.hide();
            popup_menu_shown = false;
        }
    }

// ----------------------------------------------------------------------------------------

    void popup_menu_region::
    on_menu_becomes_hidden (
    )
    {
        popup_menu_shown = false;
    }

// ----------------------------------------------------------------------------------------

    void popup_menu_region::
    on_focus_lost (
    )
    {
        if (popup_menu_shown)
        {
            menu_.hide();
            popup_menu_shown = false;
        }
    }

// ----------------------------------------------------------------------------------------

    void popup_menu_region::
    on_focus_gained (
    )
    {
        if (popup_menu_shown)
        {
            menu_.hide();
            popup_menu_shown = false;
        }
    }

// ----------------------------------------------------------------------------------------

    void popup_menu_region::
    on_window_moved(
    )
    {
        if (popup_menu_shown)
        {
            menu_.hide();
            popup_menu_shown = false;
        }
    }

// ----------------------------------------------------------------------------------------

    void popup_menu_region::
    on_mouse_down (
        unsigned long btn,
        unsigned long ,
        long x,
        long y,
        bool
    )
    {
        if (enabled && !hidden && rect.contains(x,y) && btn == base_window::RIGHT)
        {
            long orig_x, orig_y;
            parent.get_pos(orig_x, orig_y);
            menu_.set_pos(orig_x+x, orig_y+y);
            menu_.show();
            popup_menu_shown = true;
        }
        else if (popup_menu_shown)
        {
            menu_.hide();
            popup_menu_shown = false;
        }
    }

// ----------------------------------------------------------------------------------------

    void popup_menu_region::
    draw (
        const canvas&
    ) const
    {
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_BASE_WIDGETs_CPP_


dlib C++ Library - base_widgets.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net), Keita Mochizuki
// License: Boost Software License   See LICENSE.txt for the full license.

#ifndef DLIB_BASE_WIDGETs_
#define DLIB_BASE_WIDGETs_

#include "base_widgets_abstract.h"
#include "drawable.h"
#include "../gui_core.h"
#include "../algs.h"
#include "../member_function_pointer.h"
#include "../timer.h"
#include "../map.h"
#include "../set.h"
#include "../array2d.h"
#include "../pixel.h"
#include "../image_transforms/assign_image.h"
#include "../array.h"
#include "style.h"
#include "../smart_pointers.h"
#include "../unicode.h"
#include <cctype>
#include "../any.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class draggable
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class draggable : public drawable
    {
        /*!
            INITIAL VALUE
                - drag == false

            CONVENTION
                - if (the user is holding the left button down over this object) then
                    - drag == true
                    - x == the x position of the mouse relative to the upper left corner
                      of this object.
                    - y == the y position of the mouse relative to the upper left corner
                      of this object.
                - else
                    - drag == false
        !*/

    public:

        draggable(
            drawable_window& w,
            unsigned long events = 0
        ) :
            drawable(w,events | MOUSE_MOVE | MOUSE_CLICK),
            drag(false)
        {}

        virtual ~draggable(
        ) = 0;

        rectangle draggable_area (
        ) const { auto_mutex M(m); return area; }

        void set_draggable_area (
            const rectangle& area_
        ) { auto_mutex M(m); area = area_; }

    protected:

        bool is_being_dragged (
        ) const { return drag; }

        virtual void on_drag (
        ){}

        virtual void on_drag_stop (
        ){}

        void on_mouse_move (
            unsigned long state,
            long x,
            long y
        );

        void on_mouse_down (
            unsigned long btn,
            unsigned long ,
            long x,
            long y,
            bool
        );

        void on_mouse_up (
            unsigned long btn,
            unsigned long state,
            long x,
            long y
        );

    private:

        rectangle area;
        bool drag;
        long x, y;

        // restricted functions
        draggable(draggable&);        // copy constructor
        draggable& operator=(draggable&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class mouse_over_event
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class mouse_over_event : public drawable
    {
        /*!
            INITIAL VALUE
                - is_mouse_over_ == false

            CONVENTION
                - is_mouse_over_ == is_mouse_over()
        !*/

    public:

        mouse_over_event(
            drawable_window& w,
            unsigned long events = 0
        ) :
            drawable(w,events | MOUSE_MOVE),
            is_mouse_over_(false)
        {}

        virtual ~mouse_over_event(
        ) = 0;

        int next_free_user_event_number() const
        {
            return drawable::next_free_user_event_number()+1;
        }

    protected:

        bool is_mouse_over (
        ) const;

        virtual void on_mouse_over (
        ){}

        virtual void on_mouse_not_over (
        ){}

        void on_mouse_leave (
        );

        void on_mouse_move (
            unsigned long state,
            long x,
            long y
        );

        void on_user_event (
            int num
        );

    private:
        mutable bool is_mouse_over_;

        // restricted functions
        mouse_over_event(mouse_over_event&);        // copy constructor
        mouse_over_event& operator=(mouse_over_event&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class button_action
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class button_action : public mouse_over_event
    {
        /*!
            INITIAL VALUE
                - is_depressed_ == false
                - seen_click == false

            CONVENTION
                - is_depressed_ == is_depressed()
                - if (the user has clicked the button but hasn't yet released the
                      left mouse button) then
                    - seen_click == true
                - else
                    - seen_click == false
        !*/

    public:

        button_action(
            drawable_window& w,
            unsigned long events = 0
        ) :
            mouse_over_event(w,events | MOUSE_MOVE | MOUSE_CLICK),
            is_depressed_(false),
            seen_click(false)
        {}

        virtual ~button_action(
        ) = 0;

        int next_free_user_event_number() const
        {
            return mouse_over_event::next_free_user_event_number()+1;
        }

    protected:

        bool is_depressed (
        ) const;

        virtual void on_button_down (
        ){}

        virtual void on_button_up (
            bool
        ){}

        void on_mouse_not_over (
        );

        void on_mouse_down (
            unsigned long btn,
            unsigned long ,
            long x,
            long y,
            bool
        );

        void on_mouse_move (
            unsigned long state,
            long x,
            long y
        );

        void on_mouse_up (
            unsigned long btn,
            unsigned long,
            long x,
            long y
        );

    private:
        mutable bool is_depressed_;
        bool seen_click;

        void on_user_event (
            int num
        );

        // restricted functions
        button_action(button_action&);        // copy constructor
        button_action& operator=(button_action&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class widget_group
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class widget_group : public drawable
    {
        /*!
            INITIAL VALUE
                widgets.size() == 0

            CONVENTION
                - widgets contains all the drawable objects and their relative positions
                  that are in *this.
                - wg_widgets contains pointers to just the widgets that happen
                  to be widget_group objects.
        !*/

        struct relpos
        {
            unsigned long x;
            unsigned long y;
        };

    public:
        widget_group(
            drawable_window& w
        ) : drawable(w) { rect = rectangle(0,0,-1,-1); enable_events();}

        virtual ~widget_group(
        ){ disable_events(); }

        void empty (
        );

        void add (
            drawable& widget,
            unsigned long x,
            unsigned long y
        );

        void add (
            widget_group& widget,
            unsigned long x,
            unsigned long y
        );

        bool is_member (
            const drawable& widget
        ) const;

        void remove (
            const drawable& widget
        );

        unsigned long size (
        ) const;

        void set_pos (
            long x,
            long y
        );

        void set_z_order (
            long order
        );

        void show (
        );

        void hide (
        );

        void enable (
        );

        void disable (
        );

        void fit_to_contents (
        );

    protected:

        // this object doesn't draw anything but also isn't abstract
        void draw (
            const canvas&
        ) const {}

    private:

        map<drawable*,relpos>::kernel_1a_c widgets;
        set<widget_group*>::kernel_1a_c wg_widgets;

        // restricted functions
        widget_group(widget_group&);        // copy constructor
        widget_group& operator=(widget_group&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------

    class image_widget : public draggable
    {
        /*!
            INITIAL VALUE
                - img.size() == 0

            CONVENTION
                - img == the image this object displays
        !*/

    public:

        image_widget(
            drawable_window& w
        ): draggable(w)  { enable_events(); }

        ~image_widget(
        )
        {
            disable_events();
            parent.invalidate_rectangle(rect);
        }

        template <
            typename image_type
            >
        void set_image (
            const image_type& new_img
        )
        {
            auto_mutex M(m);
            assign_image_scaled(img,new_img);
            rectangle old(rect);
            rect.set_right(rect.left()+img.nc()-1);
            rect.set_bottom(rect.top()+img.nr()-1);
            parent.invalidate_rectangle(rect+old);
        }

    private:

        void draw (
            const canvas& c
        ) const
        {
            rectangle area = rect.intersect(c);
            if (area.is_empty())
                return;

            draw_image(c, point(rect.left(),rect.top()), img);
        }

        array2d<rgb_alpha_pixel> img;

        // restricted functions
        image_widget(image_widget&);        // copy constructor
        image_widget& operator=(image_widget&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class tooltip
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class tooltip : public mouse_over_event
    {
        /*!
            INITIAL VALUE
                - stuff.get() == 0
                - events_are_enabled() == false

            CONVENTION
                - if (events_are_enabled() == true) then
                    - stuff.get() != 0
        !*/

    public:

        tooltip(
            drawable_window& w
        ) :
            mouse_over_event(w,MOUSE_CLICK)
        {}

        ~tooltip(
        ){ disable_events();}

        void set_size (
            unsigned long width,
            unsigned long height
        )
        {
            auto_mutex M(m);
            rect = resize_rect(rect,width,height);
        }

        void set_text (
            const std::string& str
        )
        {
            set_text(convert_mbstring_to_wstring(str));
        }

        void set_text (
            const std::wstring& str
        )
        {
            set_text(convert_wstring_to_utf32(str));
        }

        void set_text (
            const ustring& str
        )
        {
            auto_mutex M(m);
            if (!stuff)
            {
                stuff.reset(new data(*this));
                enable_events();
            }

            stuff->win.set_text(str);
        }

        const std::string text (
        ) const
        {
            return convert_wstring_to_mbstring(wtext());
        }

        const std::wstring wtext (
        ) const
        {
            return convert_utf32_to_wstring(utext());
        }

        const dlib::ustring utext (
        ) const
        {
            auto_mutex M(m);
            dlib::ustring temp;
            if (stuff)
            {
                temp = stuff->win.text;
            }
            return temp.c_str();
        }

        void hide (
        )
        {
            auto_mutex M(m);
            mouse_over_event::hide();
            if (stuff)
            {
                stuff->tt_timer.stop();
                stuff->win.hide();
            }
        }

        void disable (
        )
        {
            auto_mutex M(m);
            mouse_over_event::disable();
            if (stuff)
            {
                stuff->tt_timer.stop();
                stuff->win.hide();
            }
        }

    protected:

        void on_mouse_over()
        {
            stuff->x = lastx;
            stuff->y = lasty;
            stuff->tt_timer.start();
        }

        void on_mouse_not_over ()
        {
            stuff->tt_timer.stop();
            stuff->win.hide();
        }

        void on_mouse_down (
            unsigned long btn,
            unsigned long state,
            long x,
            long y,
            bool is_double_click
        )
        {
            mouse_over_event::on_mouse_down(btn,state,x,y,is_double_click);
            stuff->tt_timer.stop();
            stuff->win.hide();
        }

        void draw (
            const canvas&
        ) const{}

    private:

        class tooltip_window : public base_window
        {
        public:
            tooltip_window (const shared_ptr_thread_safe<font>& f) : base_window(false,true), pad(3), mfont(f)
            {
            }

            ustring text;
            rectangle rect_all;
            rectangle rect_text;
            const unsigned long pad;
            const shared_ptr_thread_safe<font> mfont;

            void set_text (
                const std::string& str
            )
            {
                set_text(convert_mbstring_to_wstring(str));
            }

            void set_text (
                const std::wstring& str
            )
            {
                set_text(convert_wstring_to_utf32(str));
            }

            void set_text (
                const dlib::ustring& str
            )
            {
                text = str.c_str();

                unsigned long width, height;
                mfont->compute_size(text,width,height);

                set_size(width+pad*2, height+pad*2);
                rect_all.set_left(0);
                rect_all.set_top(0);
                rect_all.set_right(width+pad*2-1);
                rect_all.set_bottom(height+pad*2-1);

                rect_text = move_rect(rectangle(width,height),pad,pad);
            }

            void paint(const canvas& c)
            {
                c.fill(255,255,150);
                draw_rectangle(c, rect_all);
                mfont->draw_string(c,rect_text,text);
            }
        };

        void show_tooltip (
        )
        {
            auto_mutex M(m);
            long x, y;
            // if the mouse has moved since we started the timer then
            // keep waiting until the user stops moving it
            if (lastx != stuff->x || lasty != stuff->y)
            {
                stuff->x = lastx;
                stuff->y = lasty;
                return;
            }

            unsigned long display_width, display_height;
            // stop the timer
            stuff->tt_timer.stop();
            parent.get_pos(x,y);
            x += lastx+15;
            y += lasty+15;

            // make sure the tooltip isn't going to be off the screen
            parent.get_display_size(display_width, display_height);
            rectangle wrect(move_rect(stuff->win.rect_all,x,y));
            rectangle srect(display_width, display_height);
            if (srect.contains(wrect) == false)
            {
                rectangle temp(srect.intersect(wrect));
                x -= wrect.width()-temp.width();
                y -= wrect.height()-temp.height();
            }

            stuff->win.set_pos(x,y);
            stuff->win.show();
        }

        // put all this stuff in data so we can arrange to only
        // construct it when someone is actually using the tooltip widget
        // rather than just instantiating it.
        struct data
        {
            data(
                tooltip& self
            ) :
                x(-1),
                y(-1),
                win(self.mfont),
                tt_timer(self,&tooltip::show_tooltip)
            {
                tt_timer.set_delay_time(400);
            }

            long x, y;
            tooltip_window win;
            timer<tooltip> tt_timer;

        };
        friend struct data;
        scoped_ptr<data> stuff;

        // restricted functions
        tooltip(tooltip&);        // copy constructor
        tooltip& operator=(tooltip&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class button
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class button : public button_action
    {
    public:
        button(
            drawable_window& w
        ) :
            button_action(w),
            btn_tooltip(w)
        {
            style.reset(new button_style_default());
            enable_events();
        }

        ~button() { disable_events(); parent.invalidate_rectangle(style->get_invalidation_rect(rect)); }

        void set_size (
            unsigned long width,
            unsigned long height
        );

        void set_name (
            const std::string& name_
        );

        void set_name (
            const std::wstring& name_
        );

        void set_name (
            const dlib::ustring& name_
        );

        const std::string name (
        ) const;

        const std::wstring wname (
        ) const;

        const dlib::ustring uname (
        ) const;

        void set_tooltip_text (
            const std::string& text
        );

        void set_tooltip_text (
            const std::wstring& text
        );

        void set_tooltip_text (
            const dlib::ustring& text
        );

        void set_pos(
            long x,
            long y
        );

        const std::string tooltip_text (
        ) const;

        const std::wstring tooltip_wtext (
        ) const;

        const dlib::ustring tooltip_utext (
        ) const;

        void set_main_font (
            const shared_ptr_thread_safe<font>& f
        );

        void show (
        );

        void hide (
        );

        void enable (
        );

        void disable (
        );

        template <
            typename style_type
            >
        void set_style (
            const style_type& style_
        )
        {
            auto_mutex M(m);
            style.reset(new style_type(style_));
            rect = move_rect(style->get_min_size(name_,*mfont), rect.left(), rect.top());
            parent.invalidate_rectangle(style->get_invalidation_rect(rect));
        }

        template <
            typename T
            >
        void set_click_handler (
            T& object,
            void (T::*event_handler_)()
        )
        {
            auto_mutex M(m);
            event_handler = make_mfp(object,event_handler_);
            event_handler_self.clear();
        }

        void set_click_handler (
            const any_function<void()>& event_handler_
        )
        {
            auto_mutex M(m);
            event_handler = event_handler_;
            event_handler_self.clear();
        }

        template <
            typename T
            >
        void set_click_handler (
            T& object,
            void (T::*event_handler_)(button&)
        )
        {
            auto_mutex M(m);
            event_handler_self = make_mfp(object,event_handler_);
            event_handler.clear();
        }

        void set_sourced_click_handler (
            const any_function<void(button&)>& event_handler_
        )
        {
            auto_mutex M(m);
            event_handler_self = event_handler_;
            event_handler.clear();
        }

        bool is_depressed (
        ) const
        {
            auto_mutex M(m);
            return button_action::is_depressed();
        }

        template <
            typename T
            >
        void set_button_down_handler (
            T& object,
            void (T::*event_handler)()
        )
        {
            auto_mutex M(m);
            button_down_handler = make_mfp(object,event_handler);
        }

        void set_button_down_handler (
            const any_function<void()>& event_handler
        )
        {
            auto_mutex M(m);
            button_down_handler = event_handler;
        }

        template <
            typename T
            >
        void set_button_up_handler (
            T& object,
            void (T::*event_handler)(bool mouse_over)
        )
        {
            auto_mutex M(m);
            button_up_handler = make_mfp(object,event_handler);
        }

        void set_button_up_handler (
            const any_function<void(bool)>& event_handler
        )
        {
            auto_mutex M(m);
            button_up_handler = event_handler;
        }

        template <
            typename T
            >
        void set_button_down_handler (
            T& object,
            void (T::*event_handler)(button&)
        )
        {
            auto_mutex M(m);
            button_down_handler_self = make_mfp(object,event_handler);
        }

        void set_sourced_button_down_handler (
            const any_function<void(button&)>& event_handler
        )
        {
            auto_mutex M(m);
            button_down_handler_self = event_handler;
        }

        template <
            typename T
            >
        void set_button_up_handler (
            T& object,
            void (T::*event_handler)(bool mouse_over, button&)
        )
        {
            auto_mutex M(m);
            button_up_handler_self = make_mfp(object,event_handler);
        }

        void set_sourced_button_up_handler (
            const any_function<void(bool,button&)>& event_handler
        )
        {
            auto_mutex M(m);
            button_up_handler_self = event_handler;
        }

    private:

        // restricted functions
        button(button&);        // copy constructor
        button& operator=(button&);    // assignment operator

        dlib::ustring name_;
        tooltip btn_tooltip;

        any_function<void()> event_handler;
        any_function<void(button&)> event_handler_self;
        any_function<void()> button_down_handler;
        any_function<void(bool)> button_up_handler;
        any_function<void(button&)> button_down_handler_self;
        any_function<void(bool,button&)> button_up_handler_self;

        scoped_ptr<button_style> style;

    protected:

        void draw (
            const canvas& c
        ) const { style->draw_button(c,rect,enabled,*mfont,lastx,lasty,name_,is_depressed()); }

        void on_button_up (
            bool mouse_over
        );

        void on_button_down (
        );

        void on_mouse_over (
        ){ if (style->redraw_on_mouse_over()) parent.invalidate_rectangle(style->get_invalidation_rect(rect)); }

        void on_mouse_not_over (
        ){ if (style->redraw_on_mouse_over()) parent.invalidate_rectangle(style->get_invalidation_rect(rect)); }
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class scroll_bar
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class scroll_bar : public drawable
    {
        /*!
            INITIAL VALUE
                - ori == a value given by the constructor
                - style == a scroll_bar_style_default object
                - pos == 0
                - max_pos == 0
                - js == 10

            CONVENTION
                - ori == orientation()
                - b1 == the button that is near the 0 end of the scroll bar
                - b2 == the button that is near the max_pos() end of the scroll bar

                - max_pos == max_slider_pos()
                - pos == slider_pos()
                - js == jump_size()
        !*/

    public:
        enum bar_orientation
        {
            HORIZONTAL,
            VERTICAL
        };

        scroll_bar(
            drawable_window& w,
            bar_orientation orientation_
        );

        virtual ~scroll_bar(
        );

        bar_orientation orientation (
        ) const;

        void set_length (
            unsigned long length
        );

        long max_slider_pos (
        ) const;

        void set_max_slider_pos (
            long mpos
        );

        void set_slider_pos (
            long pos
        );

        long slider_pos (
        ) const;

        template <
            typename T
            >
        void set_scroll_handler (
            T& object,
            void (T::*eh)()
        ) { auto_mutex M(m); scroll_handler = make_mfp(object,eh); }

        void set_scroll_handler (
            const any_function<void()>& eh
        ) { auto_mutex M(m); scroll_handler = eh; }

        void set_pos (
            long x,
            long y
        );

        void enable (
        )
        {
            auto_mutex M(m);
            if (!hidden)
                show_slider();
            if (max_pos != 0)
            {
                b1.enable();
                b2.enable();
            }
            drawable::enable();
        }

        void disable (
        )
        {
            auto_mutex M(m);
            hide_slider();
            b1.disable();
            b2.disable();
            drawable::disable();
        }

        void hide (
        )
        {
            auto_mutex M(m);
            hide_slider();
            top_filler.hide();
            bottom_filler.hide();
            b1.hide();
            b2.hide();
            drawable::hide();
        }

        void show (
        )
        {
            auto_mutex M(m);
            b1.show();
            b2.show();
            drawable::show();
            top_filler.show();
            if (enabled)
                show_slider();
        }

        void set_z_order (
            long order
        )
        {
            auto_mutex M(m);
            slider.set_z_order(order);
            top_filler.set_z_order(order);
            bottom_filler.set_z_order(order);
            b1.set_z_order(order);
            b2.set_z_order(order);
            drawable::set_z_order(order);
        }

        void set_jump_size (
            long js
        );

        long jump_size (
        ) const;

        template <
            typename style_type
            >
        void set_style (
            const style_type& style_
        )
        {
            auto_mutex M(m);
            style.reset(new style_type(style_));

            if (ori == HORIZONTAL)
            {
                b1.set_style(style_.get_left_button_style());
                b2.set_style(style_.get_right_button_style());
                set_length(rect.width());
            }
            else
            {
                b1.set_style(style_.get_up_button_style());
                b2.set_style(style_.get_down_button_style());
                set_length(rect.height());
            }

        }

    private:

        void hide_slider (
        );
        /*!
            ensures
                - hides the slider and makes any other changes needed so that the
                  scroll_bar still looks right.
        !*/

        void show_slider (
        );
        /*!
            ensures
                - shows the slider and makes any other changes needed so that the
                  scroll_bar still looks right.
        !*/

        void on_slider_drag (
        );
        /*!
            requires
                - is called whenever the user drags the slider
        !*/

        void draw (
            const canvas& c
        ) const;

        void b1_down (
        );

        void b1_up (
            bool mouse_over
        );

        void b2_down (
        );

        void b2_up (
            bool mouse_over
        );

        void top_filler_down (
        );

        void top_filler_up (
            bool mouse_over
        );

        void bottom_filler_down (
        );

        void bottom_filler_up (
            bool mouse_over
        );

        void on_user_event (
            int i
        );

        void delayed_set_slider_pos (
            unsigned long dpos
        );

        void b1_down_t (
        );

        void b2_down_t (
        );

        void top_filler_down_t (
        );

        void bottom_filler_down_t (
        );

        friend class filler;
        class filler : public button_action
        {
            friend class scroll_bar;
        public:
            filler (
                drawable_window& w,
                scroll_bar& object,
                void (scroll_bar::*down)(),
                void (scroll_bar::*up)(bool)
            ):
                button_action(w),
                my_scroll_bar(object)
            {
                bup = make_mfp(object,up);
                bdown = make_mfp(object,down);

                enable_events();
            }

            ~filler (
            )
            {
               disable_events();
            }

            void set_size (
                unsigned long width,
                unsigned long height
            )
            {
                rectangle old(rect);
                const unsigned long x = rect.left();
                const unsigned long y = rect.top();
                rect.set_right(x+width-1);
                rect.set_bottom(y+height-1);

                parent.invalidate_rectangle(rect+old);
            }

        private:

            void draw (
                const canvas& c
            ) const
            {
                my_scroll_bar.style->draw_scroll_bar_background(c,rect,enabled,lastx,lasty,is_depressed());
            }

            void on_button_down (
            ) { bdown(); }

            void on_button_up (
                bool mouse_over
            ) { bup(mouse_over); }

            scroll_bar& my_scroll_bar;
            any_function<void()> bdown;
            any_function<void(bool)> bup;
        };

        friend class slider_class;
        class slider_class : public draggable
        {
            friend class scroll_bar;
        public:
            slider_class (
                drawable_window& w,
                scroll_bar& object,
                void (scroll_bar::*handler)()
            ) :
                draggable(w, MOUSE_MOVE),
                mouse_in_widget(false),
                my_scroll_bar(object)
            {
                callback = make_mfp(object,handler);
                enable_events();
            }

            ~slider_class (
            )
            {
               disable_events();
            }

            void set_size (
                unsigned long width,
                unsigned long height
            )
            {
                rectangle old(rect);
                const unsigned long x = rect.left();
                const unsigned long y = rect.top();
                rect.set_right(x+width-1);
                rect.set_bottom(y+height-1);

                parent.invalidate_rectangle(rect+old);
            }

        private:
            virtual void on_mouse_move (
                unsigned long state,
                long x,
                long y
            )
            {
                draggable::on_mouse_move(state,x,y);
                if (!hidden && my_scroll_bar.style->redraw_on_mouse_over_slider())
                {
                    if (rect.contains(x,y) && !mouse_in_widget)
                    {
                        mouse_in_widget = true;
                        parent.invalidate_rectangle(rect);
                    }
                    else if (rect.contains(x,y) == false && mouse_in_widget)
                    {
                        mouse_in_widget = false;
                        parent.invalidate_rectangle(rect);
                    }
                }
            }

            void on_mouse_leave (
            )
            {
                if (mouse_in_widget && my_scroll_bar.style->redraw_on_mouse_over_slider())
                {
                    mouse_in_widget = false;
                    parent.invalidate_rectangle(rect);
                }
            }

            void on_drag_stop (
            )
            {
                if (my_scroll_bar.style->redraw_on_mouse_over_slider())
                    parent.invalidate_rectangle(rect);
            }

            void on_drag (
            )
            {
                callback();
            }

            void draw (
                const canvas& c
            ) const
            {
                my_scroll_bar.style->draw_scroll_bar_slider(c,rect,enabled,lastx,lasty, is_being_dragged());
            }

            bool mouse_in_widget;
            scroll_bar& my_scroll_bar;
            any_function<void()> callback;
        };

        void adjust_fillers (
        );
        /*!
            ensures
                - top_filler and bottom_filler appear in their correct positions
                  relative to the current positions of the slider and the b1 and
                  b2 buttons
        !*/

        unsigned long get_slider_size (
        ) const;
        /*!
            ensures
                - returns the length in pixels the slider should have based on the current
                  state of this scroll bar
        !*/

        button b1, b2;
        slider_class slider;
        bar_orientation ori;
        filler top_filler, bottom_filler;
        any_function<void()> scroll_handler;

        long pos;
        long max_pos;
        long js;

        timer<scroll_bar> b1_timer;
        timer<scroll_bar> b2_timer;
        timer<scroll_bar> top_filler_timer;
        timer<scroll_bar> bottom_filler_timer;
        long delayed_pos;
        scoped_ptr<scroll_bar_style> style;

        // restricted functions
        scroll_bar(scroll_bar&);        // copy constructor
        scroll_bar& operator=(scroll_bar&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class popup_menu
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class menu_item
    {
    public:
        virtual ~menu_item() {}

        virtual rectangle get_left_size (
        ) const { return rectangle(); }
        virtual rectangle get_middle_size (
        ) const = 0;
        virtual rectangle get_right_size (
        ) const { return rectangle(); }

        virtual unichar get_hot_key (
        ) const { return 0; }

        virtual void draw_background (
            const canvas& ,
            const rectangle& ,
            const bool ,
            const bool
        ) const {}

        virtual void draw_left (
            const canvas& ,
            const rectangle& ,
            const bool ,
            const bool
        ) const {}

        virtual void draw_middle (
            const canvas& ,
            const rectangle& ,
            const bool ,
            const bool
        ) const = 0;

        virtual void draw_right (
            const canvas& ,
            const rectangle& ,
            const bool ,
            const bool
        ) const {}

        virtual void on_click (
        ) const {}

        virtual bool has_click_event (
        ) const { return false; }

    };

// ----------------------------------------------------------------------------------------

    class menu_item_submenu : public menu_item
    {
        void initialize (
            unichar hk
        )
        {
            const dlib::ustring &str = text;
            if (hk != 0)
            {
                std::string::size_type pos = str.find_first_of(hk);
                if (pos != std::string::npos)
                {
                    // now compute the location of the underline bar
                    rectangle r1 = f->compute_cursor_rect( rectangle(100000,100000), str, pos);
                    rectangle r2 = f->compute_cursor_rect( rectangle(100000,100000), str, pos+1);

                    underline_p1.x() = r1.left()+1;
                    underline_p2.x() = r2.left()-1;
                    underline_p1.y() = r1.bottom()-f->height()+f->ascender()+2;
                    underline_p2.y() = r2.bottom()-f->height()+f->ascender()+2;
                }
            }
        }
    public:
        menu_item_submenu (
            const std::string& str,
            unichar hk = 0
        ) :
            text(convert_wstring_to_utf32(convert_mbstring_to_wstring(str))),
            f(default_font::get_font()),
            hotkey(hk)
        {
            initialize(hk);
        }

        menu_item_submenu (
            const std::wstring& str,
            unichar hk = 0
        ) :
            text(convert_wstring_to_utf32(str)),
            f(default_font::get_font()),
            hotkey(hk)
        {
            initialize(hk);
        }

        menu_item_submenu (
            const dlib::ustring& str,
            unichar hk = 0
        ) :
            text(str),
            f(default_font::get_font()),
            hotkey(hk)
        {
            initialize(hk);
        }

        virtual unichar get_hot_key (
        ) const { return hotkey; }

        virtual rectangle get_middle_size (
        ) const
        {
            unsigned long width, height;
            f->compute_size(text,width,height);
            return rectangle(width+30,height);
        }

        virtual rectangle get_right_size (
        ) const
        {
            return rectangle(15, 5);
        }

        virtual void draw_background (
            const canvas& c,
            const rectangle& rect,
            const bool enabled,
            const bool is_selected
        ) const
        {
            if (c.intersect(rect).is_empty())
                return;

            if (enabled && is_selected)
            {
                fill_rect_with_vertical_gradient(c, rect,rgb_alpha_pixel(0,200,0,100), rgb_alpha_pixel(0,0,0,100));
                draw_rectangle(c, rect,rgb_alpha_pixel(0,0,0,100));
            }
        }

        virtual void draw_right (
            const canvas& c,
            const rectangle& rect,
            const bool enabled,
            const bool
        ) const
        {
            if (c.intersect(rect).is_empty())
                return;

            unsigned char color = 0;

            if (enabled == false)
                color = 128;

            long x, y;
            x = rect.right() - 7;
            y = rect.top() + rect.height()/2;

            for ( unsigned long i = 0; i < 5; ++i)
                draw_line (c, point(x - i, y + i), point(x - i, y - i), color);
        }

        virtual void draw_middle (
            const canvas& c,
            const rectangle& rect,
            const bool enabled,
            const bool
        ) const
        {
            if (c.intersect(rect).is_empty())
                return;

            if (enabled)
            {
                f->draw_string(c,rect,text);
            }
            else
            {
                f->draw_string(c,rect,text,128);
            }

            if (underline_p1 != underline_p2)
            {
                point base(rect.left(),rect.top());
                draw_line(c, base+underline_p1, base+underline_p2);
            }
        }

    private:
        dlib::ustring text;
        const shared_ptr_thread_safe<font> f;
        any_function<void()> action;
        unichar hotkey;
        point underline_p1;
        point underline_p2;
    };

// ----------------------------------------------------------------------------------------

    class menu_item_text : public menu_item
    {
        void initialize (
            const any_function<void()>& event_handler_,
            unichar hk
        )
        {
            dlib::ustring &str = text;
            action = event_handler_;

            if (hk != 0)
            {
                std::string::size_type pos = str.find_first_of(hk);
                if (pos != std::string::npos)
                {
                    // now compute the location of the underline bar
                    rectangle r1 = f->compute_cursor_rect( rectangle(100000,100000), str, pos);
                    rectangle r2 = f->compute_cursor_rect( rectangle(100000,100000), str, pos+1);

                    underline_p1.x() = r1.left()+1;
                    underline_p2.x() = r2.left()-1;
                    underline_p1.y() = r1.bottom()-f->height()+f->ascender()+2;
                    underline_p2.y() = r2.bottom()-f->height()+f->ascender()+2;
                }
            }
        }

    public:
        template <typename T>
        menu_item_text (
            const std::string& str,
            T& object,
            void (T::*event_handler_)(),
            unichar hk = 0
        ) :
            text(convert_wstring_to_utf32(convert_mbstring_to_wstring(str))),
            f(default_font::get_font()),
            hotkey(hk)
        {
            initialize(make_mfp(object, event_handler_), hk);
        }

        menu_item_text (
            const std::string& str,
            const any_function<void()>& event_handler_,
            unichar hk = 0
        ) :
            text(convert_wstring_to_utf32(convert_mbstring_to_wstring(str))),
            f(default_font::get_font()),
            hotkey(hk)
        {
            initialize(event_handler_, hk);
        }

        template <typename T>
        menu_item_text (
            const std::wstring& str,
            T& object,
            void (T::*event_handler_)(),
            unichar hk = 0
        ) :
            text(convert_wstring_to_utf32(str)),
            f(default_font::get_font()),
            hotkey(hk)
        {
            initialize(make_mfp(object, event_handler_), hk);
        }

        menu_item_text (
            const std::wstring& str,
            const any_function<void()>& event_handler_,
            unichar hk = 0
        ) :
            text(convert_wstring_to_utf32(str)),
            f(default_font::get_font()),
            hotkey(hk)
        {
            initialize(event_handler_, hk);
        }

        template <typename T>
        menu_item_text (
            const dlib::ustring& str,
            T& object,
            void (T::*event_handler_)(),
            unichar hk = 0
        ) :
            text(str),
            f(default_font::get_font()),
            hotkey(hk)
        {
            initialize(make_mfp(object, event_handler_), hk);
        }

        menu_item_text (
            const dlib::ustring& str,
            const any_function<void()>& event_handler_,
            unichar hk = 0
        ) :
            text(str),
            f(default_font::get_font()),
            hotkey(hk)
        {
            initialize(event_handler_, hk);
        }

        virtual unichar get_hot_key (
        ) const { return hotkey; }

        virtual rectangle get_middle_size (
        ) const
        {
            unsigned long width, height;
            f->compute_size(text,width,height);
            return rectangle(width,height);
        }

        virtual void draw_background (
            const canvas& c,
            const rectangle& rect,
            const bool enabled,
            const bool is_selected
        ) const
        {
            if (c.intersect(rect).is_empty())
                return;

            if (enabled && is_selected)
            {
                fill_rect_with_vertical_gradient(c, rect,rgb_alpha_pixel(0,200,0,100), rgb_alpha_pixel(0,0,0,100));
                draw_rectangle(c, rect,rgb_alpha_pixel(0,0,0,100));
            }
        }

        virtual void draw_middle (
            const canvas& c,
            const rectangle& rect,
            const bool enabled,
            const bool
        ) const
        {
            if (c.intersect(rect).is_empty())
                return;

            unsigned char color = 0;

            if (enabled == false)
                color = 128;

            f->draw_string(c,rect,text,color);

            if (underline_p1 != underline_p2)
            {
                point base(rect.left(),rect.top());
                draw_line(c, base+underline_p1, base+underline_p2, color);
            }
        }

        virtual void on_click (
        ) const
        {
            action();
        }

        virtual bool has_click_event (
        ) const { return true; }

    private:
        dlib::ustring text;
        const shared_ptr_thread_safe<font> f;
        any_function<void()> action;
        unichar hotkey;
        point underline_p1;
        point underline_p2;
    };

// ----------------------------------------------------------------------------------------

    class menu_item_separator : public menu_item
    {
    public:
        virtual rectangle get_middle_size (
        ) const
        {
            return rectangle(10,4);
        }

        virtual void draw_background (
            const canvas& c,
            const rectangle& rect,
            const bool ,
            const bool
        ) const
        {
            if (c.intersect(rect).is_empty())
                return;

            point p1(rect.left(),rect.top()+rect.height()/2-1);
            point p2(rect.right(),rect.top()+rect.height()/2-1);

            point p3(rect.left(),rect.top()+rect.height()/2);
            point p4(rect.right(),rect.top()+rect.height()/2);
            draw_line(c, p1,p2,128);
            draw_line(c, p3,p4,255);
        }

        virtual void draw_middle (
            const canvas& ,
            const rectangle& ,
            const bool ,
            const bool
        ) const
        {
        }
    };

// ----------------------------------------------------------------------------------------

    class popup_menu : public base_window
    {
        /*!
            INITIAL VALUE
                - pad == 2
                - item_pad == 3
                - cur_rect == rectangle(pad,pad,pad-1,pad-1)
                - left_width == 0
                - middle_width == 0
                - selected_item == 0
                - submenu_open == false
                - items.size() == 0
                - item_enabled.size() == 0
                - left_rects.size() == 0
                - middle_rects.size() == 0
                - right_rects.size() == 0
                - line_rects.size() == 0
                - submenus.size() == 0
                - hide_handlers.size() == 0

            CONVENTION
                - pad = 2
                - item_pad = 3
                - all of the following arrays have the same size:
                    - items.size()
                    - item_enabled.size()
                    - left_rects.size()
                    - middle_rects.size()
                    - right_rects.size()
                    - line_rects.size()
                    - submenus.size()

                - win_rect == a rectangle that is the exact size of this window and with
                  its upper left corner at (0,0)
                - cur_rect == the rect inside which all the menu items are drawn

                - if (a menu_item is supposed to be selected) then
                    - selected_item == the index in menus of the menu_item
                - else
                    - selected_item == submenus.size()

                - if (there is a selected submenu and it is currently open) then
                    - submenu_open == true
                - else
                    - submenu_open == false

                - for all valid i:
                    - items[i] == a pointer to the ith menu_item
                    - item_enabled[i] == true if the ith menu_item is enabled, false otherwise
                    - left_rects[i] == the left rectangle for the ith menu item
                    - middle_rects[i] == the middle rectangle for the ith menu item
                    - right_rects[i] == the right rectangle for the ith menu item
                    - line_rects[i] == the rectangle for the entire line on which the ith menu
                      item appears.
                    - if (submenus[i] != 0) then
                        - the ith menu item has a submenu and it is pointed to by submenus[i]

                - hide_handlers == an array of all the on_hide events registered for
                  this popup_menu
        !*/

    public:

        popup_menu (
        );

        template <
            typename menu_item_type
            >
        unsigned long add_menu_item (
            const menu_item_type& new_item
        )
        {
            auto_mutex M(wm);
            bool t = true;
            scoped_ptr<menu_item> item(new menu_item_type(new_item));
            items.push_back(item);
            item_enabled.push_back(t);

            // figure out how big the window should be now and what not
            rectangle left = new_item.get_left_size();
            rectangle middle = new_item.get_middle_size();
            rectangle right = new_item.get_right_size();

            bool recalc_rect_positions = false;
            const rectangle all = left+middle+right;

            // make sure left_width contains the max of all the left rectangles
            if (left.width() > left_width)
            {
                left_width = left.width();
                recalc_rect_positions = true;
            }
            // make sure middle_width contains the max of all the middle rectangles
            if (middle.width() > middle_width)
            {
                middle_width = middle.width();
                recalc_rect_positions = true;
            }

            // make the current rectangle wider if necessary
            if (cur_rect.width() < left_width + middle_width + right.width() + 2*item_pad)
            {
                cur_rect = resize_rect_width(cur_rect, left_width + middle_width + right.width() + 2*item_pad);
                recalc_rect_positions = true;
            }

            const long y = cur_rect.bottom()+1 + item_pad;
            const long x = cur_rect.left() + item_pad;

            // make the current rectangle taller to account for this new menu item
            cur_rect.set_bottom(cur_rect.bottom()+all.height() + 2*item_pad);

            // adjust all the saved rectangles since the width of the window changed
            // or left_width changed
            if (recalc_rect_positions)
            {
                long y = cur_rect.top() + item_pad;
                for (unsigned long i = 0; i < left_rects.size(); ++i)
                {
                    middle_rects[i] = move_rect(middle_rects[i], x+left_width, y);
                    right_rects[i] = move_rect(right_rects[i], x+cur_rect.width()-right_rects[i].width()-item_pad, y);
                    line_rects[i] = resize_rect_width(line_rects[i], cur_rect.width());

                    y += line_rects[i].height();
                }
            }

            // save the rectangles for later use.  Also position them at the
            // right spots
            left = move_rect(left,x,y);
            middle = move_rect(middle,x+left_width,y);
            right = move_rect(right,x+cur_rect.width()-right.width()-item_pad,y);
            rectangle line(move_rect(rectangle(cur_rect.width(),all.height()+2*item_pad), x-item_pad, y-item_pad));

            // make sure the left, middle, and right rectangles are centered in the
            // line.
            if (left.height() < all.height())
                left = translate_rect(left,0, (all.height()-left.height())/2);
            if (middle.height() < all.height())
                middle = translate_rect(middle,0, (all.height()-middle.height())/2);
            if (right.height() < all.height())
                right = translate_rect(right,0, (all.height()-right.height())/2);

            left_rects.push_back(left);
            middle_rects.push_back(middle);
            right_rects.push_back(right);
            line_rects.push_back(line);

            popup_menu* junk = 0;
            submenus.push_back(junk);

            win_rect.set_right(cur_rect.right()+pad);
            win_rect.set_bottom(cur_rect.bottom()+pad);
            set_size(win_rect.width(),win_rect.height());

            // make it so that nothing is selected
            selected_item = submenus.size();

            return items.size()-1;
        }

        template <
            typename menu_item_type
            >
        unsigned long add_submenu (
            const menu_item_type& new_item,
            popup_menu& submenu
        )
        {
            auto_mutex M(wm);

            submenus[add_menu_item(new_item)] = &submenu;

            submenu.set_on_hide_handler(*this,&popup_menu::on_submenu_hide);

            return items.size()-1;
        }

        void enable_menu_item (
            unsigned long idx
        );

        void disable_menu_item (
            unsigned long idx
        );

        unsigned long size (
        ) const;

        void clear (
        );

        void show (
        );

        void hide (
        );

        template <typename T>
        void set_on_hide_handler (
            T& object,
            void (T::*event_handler)()
        )
        {
            auto_mutex M(wm);

            member_function_pointer<> temp;
            temp.set(object,event_handler);

            // if this handler isn't already registered then add it
            bool found_handler = false;
            for (unsigned long i = 0; i < hide_handlers.size(); ++i)
            {
                if (hide_handlers[i] == temp)
                {
                    found_handler = true;
                    break;
                }
            }

            if (found_handler == false)
            {
                hide_handlers.push_back(temp);
            }
        }

        void select_first_item (
        );

        bool forwarded_on_keydown (
            unsigned long key,
            bool is_printable,
            unsigned long state
        );

    private:

        void on_submenu_hide (
        );

        void on_window_resized(
        );

        void on_mouse_up (
            unsigned long btn,
            unsigned long,
            long x,
            long y
        );

        void on_mouse_move (
            unsigned long state,
            long x,
            long y
        );

        void close_submenu (
        );

        bool display_selected_submenu (
        );
        /*!
            ensures
                - if (submenus[selected_item] isn't null) then
                    - displays the selected submenu
                    - returns true
                - else
                    - returns false
        !*/

        void on_mouse_leave (
        );

        void paint (
            const canvas& c
        );

        const long pad;
        const long item_pad;
        rectangle cur_rect;
        rectangle win_rect;
        unsigned long left_width;
        unsigned long middle_width;
        array<scoped_ptr<menu_item> > items;
        array<bool> item_enabled;
        array<rectangle> left_rects;
        array<rectangle> middle_rects;
        array<rectangle> right_rects;
        array<rectangle> line_rects;
        array<popup_menu*> submenus;
        unsigned long selected_item;
        bool submenu_open;
        array<member_function_pointer<> > hide_handlers;

        // restricted functions
        popup_menu(popup_menu&);        // copy constructor
        popup_menu& operator=(popup_menu&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------

    class zoomable_region : public drawable
    {
        /*!
            INITIAL VALUE
                - min_scale == 0.15
                - max_scale == 1.0
                - zoom_increment_ == 0.02
                - scale == 1.0
                - mouse_drag_screen == false

            CONVENTION
                - zoom_increment() == zoom_increment_
                - min_zoom_scale() == min_scale
                - max_zoom_scale() == max_scale
                - zoom_scale() == scale
                - if (the user is currently dragging the graph around via the mouse) then
                    - mouse_drag_screen == true
                - else
                    - mouse_drag_screen == false

                - max_graph_point() == lr_point
                - display_rect() == display_rect_
                - gui_to_graph_space(point(display_rect.left(),display_rect.top())) == gr_orig
        !*/

    public:

        zoomable_region (
            drawable_window& w,
            unsigned long events = 0
        );

        virtual ~zoomable_region (
        )= 0;

        virtual void set_pos (
            long x,
            long y
        );

        template <
            typename style_type
            >
        void set_style (
            const style_type& style_
        )
        {
            auto_mutex M(m);
            style.reset(new style_type(style_));
            hsb.set_style(style_.get_horizontal_scroll_bar_style());
            vsb.set_style(style_.get_vertical_scroll_bar_style());

            // do this just so that everything gets redrawn right
            set_size(rect.width(), rect.height());
        }

        void set_zoom_increment (
            double zi
        );

        double zoom_increment (
        ) const;

        void set_max_zoom_scale (
            double ms
        );

        void set_min_zoom_scale (
            double ms
        );

        double min_zoom_scale (
        ) const;

        double max_zoom_scale (
        ) const;

        virtual void set_size (
            unsigned long width,
            unsigned long height
        );

        void show (
        );

        void hide (
        );

        void enable (
        );

        void disable (
        );

        void set_z_order (
            long order
        );

    protected:

        virtual void on_view_changed () {}

        point graph_to_gui_space (
            const vector<double,2>& p
        ) const;

        vector<double,2> gui_to_graph_space (
            const point& p
        ) const;

        point max_graph_point (
        ) const;

        rectangle display_rect (
        ) const;

        double zoom_scale (
        ) const;

        void set_zoom_scale (
            double new_scale
        );

        void center_display_at_graph_point (
            const vector<double,2>& p
        );

    // ----------- event handlers ---------------

        void on_wheel_down (
            unsigned long state
        );

        void on_wheel_up (
            unsigned long state
        );

        void on_mouse_move (
            unsigned long state,
            long x,
            long y
        );

        void on_mouse_up (
            unsigned long btn,
            unsigned long state,
            long x,
            long y
        );

        void on_mouse_down (
            unsigned long btn,
            unsigned long state,
            long x,
            long y,
            bool is_double_click
        );

        void draw (
            const canvas& c
        ) const;

    private:

        void on_h_scroll (
        );

        void on_v_scroll (
        );

        void redraw_graph (
        );

        void adjust_origin (
            const point& gui_p,
            const vector<double,2>& graph_p
        );
        /*!
            ensures
                - adjusts gr_orig so that we are as close to the following as possible:
                    - graph_to_gui_space(graph_p) == gui_p
                    - gui_to_graph_space(gui_p) == graph_p
        !*/

        vector<double,2> gr_orig; // point in graph space such that it's gui space point is the upper left of display_rect_
        vector<double,2> lr_point; // point in graph space such that it is at the lower right corner of the screen at max zoom

        mutable std::ostringstream sout;

        double scale; // 0 < scale <= 1
        double min_scale;
        double max_scale;
        double zoom_increment_;
        rectangle display_rect_;

        bool mouse_drag_screen;  // true if the user is dragging the white background area
        vector<double,2> drag_screen_point; // the starting point the mouse was at in graph space for the background area drag

        scroll_bar vsb;
        scroll_bar hsb;

        scoped_ptr<scrollable_region_style> style;

        // restricted functions
        zoomable_region(zoomable_region&);        // copy constructor
        zoomable_region& operator=(zoomable_region&);    // assignment operator

    };

// ----------------------------------------------------------------------------------------

    class scrollable_region : public drawable
    {
        /*!
            INITIAL VALUE
                - hscroll_bar_inc == 1
                - vscroll_bar_inc == 1
                - h_wheel_scroll_bar_inc == 1
                - v_wheel_scroll_bar_inc == 1
                - mouse_drag_enabled_ == false
                - user_is_dragging_mouse == false

            CONVENTION
                - mouse_drag_enabled() == mouse_drag_enabled_
                - horizontal_scroll_increment() == hscroll_bar_inc
                - vertical_scroll_increment() == vscroll_bar_inc
                - horizontal_mouse_wheel_scroll_increment() == h_wheel_scroll_bar_inc
                - vertical_mouse_wheel_scroll_increment() == v_wheel_scroll_bar_inc
                - vertical_scroll_pos() == vsb.slider_pos()
                - horizontal_scroll_pos() == hsb.slider_pos()
                - total_rect() == total_rect_
                - display_rect() == display_rect_

                - if (the user is currently dragging the total_rect around with a mouse drag) then
                    - user_is_dragging_mouse == true
                    - drag_origin == the point the mouse was at, with respect to total_rect,
                      when the dragging started
                - else
                    - user_is_dragging_mouse == false
        !*/

    public:

        scrollable_region (
            drawable_window& w,
            unsigned long events = 0
        );

        virtual ~scrollable_region (
        ) = 0;

        template <
            typename style_type
            >
        void set_style (
            const style_type& style_
        )
        {
            auto_mutex M(m);
            style.reset(new style_type(style_));
            hsb.set_style(style_.get_horizontal_scroll_bar_style());
            vsb.set_style(style_.get_vertical_scroll_bar_style());

            // do this just so that everything gets redrawn right
            set_size(rect.width(), rect.height());
        }

        void show (
        );

        void hide (
        );

        void enable (
        );

        void disable (
        );

        void set_z_order (
            long order
        );

        virtual void set_size (
            unsigned long width,
            unsigned long height
        );

        unsigned long horizontal_mouse_wheel_scroll_increment (
        ) const;

        unsigned long vertical_mouse_wheel_scroll_increment (
        ) const;

        void set_horizontal_mouse_wheel_scroll_increment (
            unsigned long inc
        );

        void set_vertical_mouse_wheel_scroll_increment (
            unsigned long inc
        );

        unsigned long horizontal_scroll_increment (
        ) const;

        unsigned long vertical_scroll_increment (
        ) const;

        void set_horizontal_scroll_increment (
            unsigned long inc
        );

        void set_vertical_scroll_increment (
            unsigned long inc
        );

        long horizontal_scroll_pos (
        ) const;

        long vertical_scroll_pos (
        ) const;

        void set_horizontal_scroll_pos (
            long pos
        );

        void set_vertical_scroll_pos (
            long pos
        );

        virtual void set_pos (
            long x,
            long y
        );

        bool mouse_drag_enabled (
        ) const;

        void enable_mouse_drag (
        );

        void disable_mouse_drag (
        );

    protected:

        virtual void on_view_changed () {}

        const rectangle& display_rect (
        ) const;

        void set_total_rect_size (
            unsigned long width,
            unsigned long height
        );

        const rectangle& total_rect (
        ) const;

        void scroll_to_rect (
            const rectangle& r_
        );

        void on_wheel_down (
            unsigned long state
        );

        void on_mouse_move (
            unsigned long state,
            long x,
            long y
        );

        void on_mouse_down (
            unsigned long btn,
            unsigned long state,
            long x,
            long y,
            bool is_double_click
        );

        void on_mouse_up   (
            unsigned long btn,
            unsigned long state,
            long x,
            long y
        );

        void on_wheel_up (
            unsigned long state
        );

        void draw (
            const canvas& c
        ) const;

    private:

        bool need_h_scroll (
        ) const;

        bool need_v_scroll (
        ) const;

        void on_h_scroll (
        );

        void on_v_scroll (
        );

        rectangle total_rect_;
        rectangle display_rect_;
        scroll_bar hsb;
        scroll_bar vsb;
        unsigned long hscroll_bar_inc;
        unsigned long vscroll_bar_inc;
        unsigned long h_wheel_scroll_bar_inc;
        unsigned long v_wheel_scroll_bar_inc;
        bool mouse_drag_enabled_;
        bool user_is_dragging_mouse;
        point drag_origin;
        scoped_ptr<scrollable_region_style> style;

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class popup_menu_region
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class popup_menu_region : public drawable
    {
        /*!
            CONVENTION
                popup_menu_visible() == popup_menu_shown
        !*/

    public:

        popup_menu_region(
            drawable_window& w
        );

        virtual ~popup_menu_region(
        );

        void set_size (
            unsigned long width,
            unsigned long height
        );

        void set_rect (
            const rectangle& new_rect
        );

        popup_menu& menu (
        );

        void hide (
        );

        void disable (
        );

        bool popup_menu_visible (
        ) const { auto_mutex M(m); return popup_menu_shown; }

    protected:

        void on_keydown (
            unsigned long key,
            bool is_printable,
            unsigned long state
        );

        void on_focus_lost (
        );

        void on_focus_gained (
        );

        void on_window_moved(
        );

        void on_mouse_down (
            unsigned long btn,
            unsigned long state,
            long x,
            long y,
            bool is_double_click
        );

        void on_menu_becomes_hidden (
        );

        void draw (
            const canvas&
        ) const;

    private:

        popup_menu menu_;
        bool popup_menu_shown;

        // restricted functions
        popup_menu_region(popup_menu_region&);        // copy constructor
        popup_menu_region& operator=(popup_menu_region&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------

}

#ifdef NO_MAKEFILE
#include "base_widgets.cpp"
#endif

#endif // DLIB_BASE_WIDGETs_


dlib C++ Library - canvas_drawing.cpp

// Copyright (C) 2005  Davis E. King (davis@dlib.net), and Nils Labugt
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_CANVAS_DRAWINg_CPP_
#define DLIB_CANVAS_DRAWINg_CPP_

#include "canvas_drawing.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    void draw_sunken_rectangle (
        const canvas& c,
        const rectangle& border,
        unsigned char alpha
    )
    {
        rectangle area = border.intersect(c);
        if (area.is_empty() == false)
        {
            const rgb_alpha_pixel dark_gray(64,64,64,alpha);
            const rgb_alpha_pixel gray(128,128,128,alpha);
            const rgb_alpha_pixel white(255,255,255,alpha);
            const rgb_alpha_pixel background(212,208,200,alpha);

            draw_line(c,point(border.left(),border.top()),point(border.right()-1,border.top()),gray);

            draw_line(c,point(border.left(),border.bottom()),point(border.right(),border.bottom()),white);
            draw_line(c,point(border.left()+1,border.bottom()-1),point(border.right()-1,border.bottom()-1),background);

            draw_line(c,point(border.left(),border.top()+1),point(border.left(),border.bottom()-1),gray);

            draw_line(c,point(border.right(),border.top()),point(border.right(),border.bottom()-1),white);
            draw_line(c,point(border.right()-1,border.top()+1),point(border.right()-1,border.bottom()-2),background);

            draw_line(c,point(border.left()+1,border.top()+1),point(border.left()+1,border.bottom()-2),dark_gray);
            draw_line(c,point(border.left()+1,border.top()+1),point(border.right()-2,border.top()+1),dark_gray);
        }
    }

// ----------------------------------------------------------------------------------------

    void draw_button_down (
        const canvas& c,
        const rectangle& btn,
        unsigned char alpha
    )
    {
        rectangle area = btn.intersect(c);
        if (area.is_empty() == false)
        {
            const rgb_alpha_pixel dark_gray(64,64,64,alpha);
            const rgb_alpha_pixel gray(128,128,128,alpha);
            const rgb_alpha_pixel black(0,0,0,alpha);

            draw_line(c,point(btn.left(),btn.top()),point(btn.right(),btn.top()),black);

            draw_line(c,point(btn.left()+1,btn.bottom()),point(btn.right(),btn.bottom()),dark_gray);
            draw_line(c,point(btn.left()+1,btn.top()+1),point(btn.right()-1,btn.top()+1),gray);

            draw_line(c,point(btn.left(),btn.top()+1),point(btn.left(),btn.bottom()),black);

            draw_line(c,point(btn.right(),btn.top()+1),point(btn.right(),btn.bottom()-1),dark_gray);
            draw_line(c,point(btn.left()+1,btn.top()+1),point(btn.left()+1,btn.bottom()-1),gray);
        }
    }

// ----------------------------------------------------------------------------------------

    void draw_button_up (
        const canvas& c,
        const rectangle& btn,
        unsigned char alpha
    )
    {
        rectangle area = btn.intersect(c);
        if (area.is_empty() == false)
        {
            const rgb_alpha_pixel dark_gray(64,64,64,alpha);
            const rgb_alpha_pixel gray(128,128,128,alpha);
            const rgb_alpha_pixel white(255,255,255,alpha);

            draw_line(c,point(btn.left(),btn.top()),point(btn.right()-1,btn.top()),white);

            draw_line(c,point(btn.left(),btn.bottom()),point(btn.right(),btn.bottom()),dark_gray);
            draw_line(c,point(btn.left()+1,btn.bottom()-1),point(btn.right()-1,btn.bottom()-1),gray);

            draw_line(c,point(btn.left(),btn.top()+1),point(btn.left(),btn.bottom()-1),white);

            draw_line(c,point(btn.right(),btn.top()),point(btn.right(),btn.bottom()-1),dark_gray);
            draw_line(c,point(btn.right()-1,btn.top()+1),point(btn.right()-1,btn.bottom()-2),gray);
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_CANVAS_DRAWINg_CPP_


dlib C++ Library - canvas_drawing.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net), and Nils Labugt
// License: Boost Software License   See LICENSE.txt for the full license.

#ifndef DLIB_GUI_CANVAS_DRAWINg_
#define DLIB_GUI_CANVAS_DRAWINg_

#include "canvas_drawing_abstract.h"
#include "../gui_core.h"
#include "../algs.h"
#include "../array2d.h"
#include "../pixel.h"
#include "../image_transforms/assign_image.h"
#include "../geometry.h"
#include <cmath>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <typename pixel_type>
    void draw_line (
        const canvas& c,
        const point& p1,
        const point& p2,
        const pixel_type& pixel,
        const rectangle& area = rectangle(std::numeric_limits<long>::min(), std::numeric_limits<long>::min(),
                                          std::numeric_limits<long>::max(), std::numeric_limits<long>::max())
    )
    {
        rectangle valid_area(c.intersect(area));
        long x1 = p1.x();
        long y1 = p1.y();
        long x2 = p2.x();
        long y2 = p2.y();
        if (x1 == x2)
        {
            // if the x coordinate is inside the canvas's area
            if (x1 <= valid_area.right() && x1 >= valid_area.left())
            {
                // make sure y1 comes before y2
                if (y1 > y2)
                    swap(y1,y2);

                y1 = std::max(y1,valid_area.top());
                y2 = std::min(y2,valid_area.bottom());
                // this is a vertical line
                for (long y = y1; y <= y2; ++y)
                {
                    assign_pixel(c[y-c.top()][x1-c.left()], pixel);
                }
            }
        }
        else if (y1 == y2)
        {
            // if the y coordinate is inside the canvas's area
            if (y1 <= valid_area.bottom() && y1 >= valid_area.top())
            {
                // make sure x1 comes before x2
                if (x1 > x2)
                    swap(x1,x2);

                x1 = std::max(x1,valid_area.left());
                x2 = std::min(x2,valid_area.right());
                // this is a horizontal line
                for (long x = x1; x <= x2; ++x)
                {
                    assign_pixel(c[y1-c.top()][x-c.left()], pixel);
                }
            }
        }
        else
        {
            rgb_alpha_pixel alpha_pixel;
            assign_pixel(alpha_pixel, pixel);
            const unsigned char max_alpha = alpha_pixel.alpha;

            const long rise = (((long)y2) - ((long)y1));
            const long run = (((long)x2) - ((long)x1));
            if (std::abs(rise) < std::abs(run))
            {
                const double slope = ((double)rise)/run;

                double first, last;

                if (x1 > x2)
                {
                    first = std::max(x2,valid_area.left());
                    last = std::min(x1,valid_area.right());
                }
                else
                {
                    first = std::max(x1,valid_area.left());
                    last = std::min(x2,valid_area.right());
                }

                long y;
                long x;
                const double x1f = x1;
                const double y1f = y1;
                for (double i = first; i <= last; ++i)
                {
                    const double dy = slope*(i-x1f) + y1f;
                    const double dx = i;

                    y = static_cast<long>(dy);
                    x = static_cast<long>(dx);

                    if (y >= valid_area.top() && y <= valid_area.bottom())
                    {
                        alpha_pixel.alpha = static_cast<unsigned char>((1.0-(dy-y))*max_alpha);
                        assign_pixel(c[y-c.top()][x-c.left()], alpha_pixel);
                    }
                    if (y+1 >= valid_area.top() && y+1 <= valid_area.bottom())
                    {
                        alpha_pixel.alpha = static_cast<unsigned char>((dy-y)*max_alpha);
                        assign_pixel(c[y+1-c.top()][x-c.left()], alpha_pixel);
                    }
                }
            }
            else
            {
                const double slope = ((double)run)/rise;

                double first, last;

                if (y1 > y2)
                {
                    first = std::max(y2,valid_area.top());
                    last = std::min(y1,valid_area.bottom());
                }
                else
                {
                    first = std::max(y1,valid_area.top());
                    last = std::min(y2,valid_area.bottom());
                }

                long x;
                long y;
                const double x1f = x1;
                const double y1f = y1;
                for (double i = first; i <= last; ++i)
                {
                    const double dx = slope*(i-y1f) + x1f;
                    const double dy = i;

                    y = static_cast<long>(dy);
                    x = static_cast<long>(dx);

                    if (x >= valid_area.left() && x <= valid_area.right())
                    {
                        alpha_pixel.alpha = static_cast<unsigned char>((1.0-(dx-x))*max_alpha);
                        assign_pixel(c[y-c.top()][x-c.left()], alpha_pixel);
                    }
                    if (x+1 >= valid_area.left() && x+1 <= valid_area.right())
                    {
                        alpha_pixel.alpha = static_cast<unsigned char>((dx-x)*max_alpha);
                        assign_pixel(c[y-c.top()][x+1-c.left()], alpha_pixel);
                    }
                }
            }
        }

    }
    inline void draw_line (
        const canvas& c,
        const point& p1,
        const point& p2
    ){ draw_line(c,p1,p2,0); }

// ----------------------------------------------------------------------------------------

    void draw_sunken_rectangle (
        const canvas& c,
        const rectangle& border,
        unsigned char alpha = 255
    );

// ----------------------------------------------------------------------------------------

    template <typename pixel_type>
    inline void draw_pixel (
        const canvas& c,
        const point& p,
        const pixel_type& pixel
    )
    {
        if (c.contains(p))
        {
            assign_pixel(c[p.y()-c.top()][p.x()-c.left()],pixel);
        }
    }

// ----------------------------------------------------------------------------------------

    template <typename pixel_type>
    void draw_checkered (
        const canvas& c,
        const rectangle& a,
        const pixel_type& pixel1,
        const pixel_type& pixel2
    )
    {
        rectangle area = a.intersect(c);
        if (area.is_empty())
            return;

        for (long i = area.left(); i <= area.right(); ++i)
        {
            for (long j = area.top(); j <= area.bottom(); ++j)
            {
                canvas::pixel& p = c[j - c.top()][i - c.left()];
                if ((j&0x1) ^ (i&0x1))
                {
                    assign_pixel(p,pixel1);
                }
                else
                {
                    assign_pixel(p,pixel2);
                }
            }
        }
    }

// ----------------------------------------------------------------------------------------

    void draw_button_down (
        const canvas& c,
        const rectangle& btn,
        unsigned char alpha = 255
    );

// ----------------------------------------------------------------------------------------

    void draw_button_up (
        const canvas& c,
        const rectangle& btn,
        unsigned char alpha = 255
    );

// ----------------------------------------------------------------------------------------

    template <typename pixel_type>
    void draw_circle (
        const canvas& c,
        const point& center_point,
        double radius,
        const pixel_type& pixel,
        const rectangle& area = rectangle(std::numeric_limits<long>::min(), std::numeric_limits<long>::min(),
                                          std::numeric_limits<long>::max(), std::numeric_limits<long>::max())
    )
    {
        using std::sqrt;
        rectangle valid_area(c.intersect(area));
        const long x = center_point.x();
        const long y = center_point.y();
        if (radius > 1)
        {
            long first_x = static_cast<long>(x - radius + 0.5);
            long last_x = static_cast<long>(x + radius + 0.5);
            const double rs = radius*radius;

            // ensure that we only loop over the part of the x dimension that this
            // canvas contains.
            if (first_x < valid_area.left())
                first_x = valid_area.left();
            if (last_x > valid_area.right())
                last_x = valid_area.right();

            long top, bottom;

            top = static_cast<long>(sqrt(std::max(rs - (first_x-x-0.5)*(first_x-x-0.5),0.0))+0.5);
            top += y;
            long last = top;

            // draw the left half of the circle
            long middle = std::min(x-1,last_x);
            for (long i = first_x; i <= middle; ++i)
            {
                double a = i - x + 0.5;
                // find the top of the arc
                top = static_cast<long>(sqrt(std::max(rs - a*a,0.0))+0.5);
                top += y;
                long temp = top;

                while(top >= last)
                {
                    bottom = y - top + y;
                    if (top >= valid_area.top() && top <= valid_area.bottom() )
                    {
                        assign_pixel(c[top-c.top()][i-c.left()],pixel);
                    }

                    if (bottom >= valid_area.top() && bottom <= valid_area.bottom() )
                    {
                        assign_pixel(c[bottom-c.top()][i-c.left()],pixel);
                    }
                    --top;
                }

                last = temp;
            }

            middle = std::max(x,first_x);
            top = static_cast<long>(sqrt(std::max(rs - (last_x-x+0.5)*(last_x-x+0.5),0.0))+0.5);
            top += y;
            last = top;
            // draw the right half of the circle
            for (long i = last_x; i >= middle; --i)
            {
                double a = i - x - 0.5;
                // find the top of the arc
                top = static_cast<long>(sqrt(std::max(rs - a*a,0.0))+0.5);
                top += y;
                long temp = top;

                while(top >= last)
                {
                    bottom = y - top + y;
                    if (top >= valid_area.top() && top <= valid_area.bottom() )
                    {
                        assign_pixel(c[top-c.top()][i-c.left()],pixel);
                    }

                    if (bottom >= valid_area.top() && bottom <= valid_area.bottom() )
                    {
                        assign_pixel(c[bottom-c.top()][i-c.left()],pixel);
                    }
                    --top;
                }

                last = temp;
            }
        }
        else if (radius == 1 &&
                 x >= valid_area.left() && x <= valid_area.right() &&
                 y >= valid_area.top() && y <= valid_area.bottom() )
        {
            assign_pixel(c[y-c.top()][x-c.left()], pixel);
        }
    }
    inline void draw_circle (
        const canvas& c,
        const point& center_point,
        double radius
    ){ draw_circle(c, center_point, radius, 0); }

// ----------------------------------------------------------------------------------------

    template <typename pixel_type>
    void draw_solid_circle (
        const canvas& c,
        const point& center_point,
        double radius,
        const pixel_type& pixel,
        const rectangle& area = rectangle(std::numeric_limits<long>::min(), std::numeric_limits<long>::min(),
                                          std::numeric_limits<long>::max(), std::numeric_limits<long>::max())
    )
    {
        using std::sqrt;
        rectangle valid_area(c.intersect(area));
        const long x = center_point.x();
        const long y = center_point.y();
        if (radius > 1)
        {
            long first_x = static_cast<long>(x - radius + 0.5);
            long last_x = static_cast<long>(x + radius + 0.5);
            const double rs = radius*radius;

            // ensure that we only loop over the part of the x dimension that this
            // canvas contains.
            if (first_x < valid_area.left())
                first_x = valid_area.left();
            if (last_x > valid_area.right())
                last_x = valid_area.right();

            long top, bottom;

            top = static_cast<long>(sqrt(std::max(rs - (first_x-x-0.5)*(first_x-x-0.5),0.0))+0.5);
            top += y;
            long last = top;

            // draw the left half of the circle
            long middle = std::min(x-1,last_x);
            for (long i = first_x; i <= middle; ++i)
            {
                double a = i - x + 0.5;
                // find the top of the arc
                top = static_cast<long>(sqrt(std::max(rs - a*a,0.0))+0.5);
                top += y;
                long temp = top;

                while(top >= last)
                {
                    bottom = y - top + y;
                    draw_line(c, point(i,top),point(i,bottom),pixel,area);
                    --top;
                }

                last = temp;
            }

            middle = std::max(x,first_x);
            top = static_cast<long>(sqrt(std::max(rs - (last_x-x+0.5)*(last_x-x+0.5),0.0))+0.5);
            top += y;
            last = top;
            // draw the right half of the circle
            for (long i = last_x; i >= middle; --i)
            {
                double a = i - x - 0.5;
                // find the top of the arc
                top = static_cast<long>(sqrt(std::max(rs - a*a,0.0))+0.5);
                top += y;
                long temp = top;

                while(top >= last)
                {
                    bottom = y - top + y;
                    draw_line(c, point(i,top),point(i,bottom),pixel,area);
                    --top;
                }

                last = temp;
            }
        }
        else if (radius == 1 &&
                 x >= valid_area.left() && x <= valid_area.right() &&
                 y >= valid_area.top() && y <= valid_area.bottom() )
        {
            assign_pixel(c[y-c.top()][x-c.left()], pixel);
        }
    }
    inline void draw_solid_circle (
        const canvas& c,
        const point& center_point,
        double radius
    ) { draw_solid_circle(c, center_point, radius, 0); }

// ----------------------------------------------------------------------------------------

    namespace impl
    {

        template <typename alloc>
        void get_convex_polygon_shape (
            const std::vector<point>& points,
            const long top,
            const long bottom,
            std::vector<double,alloc>& left_boundary,
            std::vector<double,alloc>& right_boundary
        )
        /*!
            requires
                - 0 <= top <= bottom
            ensures
                - interprets points as the coordinates defining a convex polygon.  In
                  particular, we interpret points as a list of the vertices of the polygon
                  and assume they are ordered in clockwise order.
                - #left_boundary.size() == bottom-top+1
                - #right_boundary.size() == bottom-top+1
                - for all top <= y <= bottom:
                    - #left_boundary[y-top] == the x coordinate for the left most side of
                      the polygon at coordinate y.
                    - #right_boundary[y-top] == the x coordinate for the right most side of
                      the polygon at coordinate y.
        !*/
        {
            using std::min;
            using std::max;

            left_boundary.assign(bottom-top+1, std::numeric_limits<double>::infinity());
            right_boundary.assign(bottom-top+1, -std::numeric_limits<double>::infinity());

            // trace out the points along the edge of the polynomial and record them
            for (unsigned long i = 0; i < points.size(); ++i)
            {
                const point p1 = points[i];
                const point p2 = points[(i+1)%points.size()];

                if (p1.y() == p2.y())
                {
                    if (top <= p1.y() && p1.y() <= bottom)
                    {
                        const long y = p1.y() - top;
                        const double xmin = min(p1.x(), p2.x());
                        const double xmax = min(p1.x(), p2.x());
                        left_boundary[y]  = min(left_boundary[y], xmin);
                        right_boundary[y] = max(right_boundary[y], xmax);
                    }
                }
                else
                {
                    // Here we trace out the line from p1 to p2 and record where it hits.

                    // x = m*y + b
                    const double m = (p2.x() - p1.x())/(double)(p2.y()-p1.y());
                    const double b = p1.x() - m*p1.y(); // because: x1 = m*y1 + b

                    const long ymin = max(top,min(p1.y(), p2.y()));
                    const long ymax = min(bottom,max(p1.y(), p2.y()));
                    for (long y = ymin; y <= ymax; ++y)
                    {
                        const double x = m*y + b;
                        const unsigned long idx = y-top;
                        left_boundary[idx]  = min(left_boundary[idx], x);
                        right_boundary[idx] = max(right_boundary[idx], x);
                    }
                }
            }
        }

    // ------------------------------------------------------------------------------------

    }

    template <typename pixel_type>
    void draw_solid_convex_polygon (
        const canvas& c,
        const std::vector<point>& polygon,
        const pixel_type& pixel,
        const rectangle& area = rectangle(std::numeric_limits<long>::min(), std::numeric_limits<long>::min(),
                                          std::numeric_limits<long>::max(), std::numeric_limits<long>::max())
    )
    {
        using std::max;
        using std::min;
        const rectangle valid_area(c.intersect(area));

        rectangle bounding_box;
        for (unsigned long i = 0; i < polygon.size(); ++i)
            bounding_box += polygon[i];

        // Don't do anything if the polygon is totally outside the area we can draw in
        // right now.
        if (bounding_box.intersect(valid_area).is_empty())
            return;

        rgb_alpha_pixel alpha_pixel;
        assign_pixel(alpha_pixel, pixel);
        const unsigned char max_alpha = alpha_pixel.alpha;

        // we will only want to loop over the part of left_boundary that is part of the
        // valid_area.
        long top = max(valid_area.top(),bounding_box.top());
        long bottom = min(valid_area.bottom(),bounding_box.bottom());

        // Since we look at the adjacent rows of boundary information when doing the alpha
        // blending, we want to make sure we always have some boundary information unless
        // we are at the absolute edge of the polygon.
        const long top_offset = (top == bounding_box.top()) ? 0 : 1;
        const long bottom_offset = (bottom == bounding_box.bottom()) ? 0 : 1;
        if (top != bounding_box.top())
            top -= 1;
        if (bottom != bounding_box.bottom())
            bottom += 1;

        std::vector<double> left_boundary;
        std::vector<double> right_boundary;
        impl::get_convex_polygon_shape(polygon, top, bottom, left_boundary, right_boundary);

        // draw the polygon row by row
        for (unsigned long i = top_offset; i < left_boundary.size(); ++i)
        {
            long left_x = static_cast<long>(std::ceil(left_boundary[i]));
            long right_x = static_cast<long>(std::floor(right_boundary[i]));

            left_x = max(left_x, valid_area.left());
            right_x = min(right_x, valid_area.right());

            if (i < left_boundary.size()-bottom_offset)
            {
                // draw the main body of the polygon
                for (long x = left_x; x <= right_x; ++x)
                {
                    const long y = i+top;
                    assign_pixel(c[y-c.top()][x-c.left()], pixel);
                }
            }

            if (i == 0)
                continue;

            // Now draw anti-aliased edges so they don't look all pixely.

            // Alpha blend the edges on the left side.
            double delta = left_boundary[i-1] - left_boundary[i];
            if (std::abs(delta) <= 1)
            {
                if (std::floor(left_boundary[i]) != left_x)
                {
                    const point p(static_cast<long>(std::floor(left_boundary[i])), i+top);
                    rgb_alpha_pixel temp = alpha_pixel;
                    temp.alpha = max_alpha-static_cast<unsigned char>((left_boundary[i]-p.x())*max_alpha);
                    if (valid_area.contains(p))
                        assign_pixel(c[p.y()-c.top()][p.x()-c.left()],temp);
                }
            }
            else if (delta < 0)  // on the bottom side
            {
                for (long x = static_cast<long>(std::ceil(left_boundary[i-1])); x < left_x; ++x)
                {
                    const point p(x, i+top);
                    rgb_alpha_pixel temp = alpha_pixel;
                    temp.alpha = static_cast<unsigned char>((x-left_boundary[i-1])/std::abs(delta)*max_alpha);
                    if (valid_area.contains(p))
                        assign_pixel(c[p.y()-c.top()][p.x()-c.left()],temp);
                }
            }
            else // on the top side
            {
                const long old_left_x = static_cast<long>(std::ceil(left_boundary[i-1]));
                for (long x = left_x; x < old_left_x; ++x)
                {
                    const point p(x, i+top-1);
                    rgb_alpha_pixel temp = alpha_pixel;
                    temp.alpha = static_cast<unsigned char>((x-left_boundary[i])/delta*max_alpha);
                    if (valid_area.contains(p))
                        assign_pixel(c[p.y()-c.top()][p.x()-c.left()],temp);
                }
            }

            // Alpha blend the edges on the right side
            delta = right_boundary[i-1] - right_boundary[i];
            if (std::abs(delta) <= 1)
            {
                if (std::ceil(right_boundary[i]) != right_x)
                {
                    const point p(static_cast<long>(std::ceil(right_boundary[i])), i+top);
                    rgb_alpha_pixel temp = alpha_pixel;
                    temp.alpha = max_alpha-static_cast<unsigned char>((p.x()-right_boundary[i])*max_alpha);
                    if (valid_area.contains(p))
                        assign_pixel(c[p.y()-c.top()][p.x()-c.left()],temp);
                }
            }
            else if (delta < 0) // on the top side
            {
                for (long x = static_cast<long>(std::floor(right_boundary[i-1]))+1; x <= right_x; ++x)
                {
                    const point p(x, i+top-1);
                    rgb_alpha_pixel temp = alpha_pixel;
                    temp.alpha = static_cast<unsigned char>((right_boundary[i]-x)/std::abs(delta)*max_alpha);
                    if (valid_area.contains(p))
                        assign_pixel(c[p.y()-c.top()][p.x()-c.left()],temp);
                }
            }
            else // on the bottom side
            {
                const long old_right_x = static_cast<long>(std::floor(right_boundary[i-1]));
                for (long x = right_x+1; x <= old_right_x; ++x)
                {
                    const point p(x, i+top);
                    rgb_alpha_pixel temp = alpha_pixel;
                    temp.alpha = static_cast<unsigned char>((right_boundary[i-1]-x)/delta*max_alpha);
                    if (valid_area.contains(p))
                        assign_pixel(c[p.y()-c.top()][p.x()-c.left()],temp);
                }
            }
        }
    }
    inline void draw_solid_convex_polygon (
        const canvas& c,
        const std::vector<point>& polygon
    ) { draw_solid_convex_polygon(c, polygon, 0); }

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    void draw_image (
        const canvas& c,
        const point& p,
        const image_type& img,
        const rectangle& area_ = rectangle(std::numeric_limits<long>::min(), std::numeric_limits<long>::min(),
                                          std::numeric_limits<long>::max(), std::numeric_limits<long>::max())
    )
    {
        const long x = p.x();
        const long y = p.y();
        rectangle rect(x,y,img.nc()+x-1,img.nr()+y-1);
        rectangle area = c.intersect(rect).intersect(area_);
        if (area.is_empty())
            return;

        for (long row = area.top(); row <= area.bottom(); ++row)
        {
            for (long col = area.left(); col <= area.right(); ++col)
            {
                assign_pixel(c[row-c.top()][col-c.left()], img[row-rect.top()][col-rect.left()]);
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    void draw_image (
        const canvas& c,
        const rectangle& rect,
        const image_type& img,
        const rectangle& area_ = rectangle(std::numeric_limits<long>::min(), std::numeric_limits<long>::min(),
                                          std::numeric_limits<long>::max(), std::numeric_limits<long>::max())
    )
    {
        const rectangle area = c.intersect(rect).intersect(area_);
        if (area.is_empty() || img.size() == 0)
            return;

        const matrix<long,1> x = matrix_cast<long>(round(linspace(0, img.nc()-1, rect.width())));
        const matrix<long,1> y = matrix_cast<long>(round(linspace(0, img.nr()-1, rect.height())));

        for (long row = area.top(); row <= area.bottom(); ++row)
        {
            const long r = y(row-rect.top());
            long cc = area.left() - rect.left();
            for (long col = area.left(); col <= area.right(); ++col)
            {
                assign_pixel(c[row-c.top()][col-c.left()], img[r][x(cc++)]);
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <typename pixel_type>
    void draw_rounded_rectangle (
        const canvas& c,
        const rectangle& rect,
        unsigned radius,
        const pixel_type& color,
        const rectangle& area_ = rectangle(std::numeric_limits<long>::min(), std::numeric_limits<long>::min(),
                                          std::numeric_limits<long>::max(), std::numeric_limits<long>::max())
    )
    {
        if ( rect.intersect ( c ).is_empty() )
            return;

        draw_line ( c, point(rect.left() + radius + 1, rect.bottom()),
                    point(rect.right() - radius - 1, rect.bottom()), color,area_ );

        draw_line ( c, point(rect.left() + radius + 1, rect.top()),
                    point(rect.right() - radius - 1, rect.top()), color,area_ );

        draw_line ( c, point(rect.left(), rect.top() + radius + 1),
                    point(rect.left(), rect.bottom() - radius - 1), color,area_ );

        draw_line ( c, point(rect.right(), rect.top() + radius + 1),
                    point(rect.right(), rect.bottom() - radius - 1), color,area_ );

        unsigned x = radius, y = 0, old_x = x;

        point p;
        while ( x > y )
        {
            p = point(rect.left() + radius - y, rect.top() + radius - x);
            if (area_.contains(p)) draw_pixel (c, p , color );
            p = point(rect.right() - radius + y, rect.top() + radius - x);
            if (area_.contains(p)) draw_pixel (c, p , color );
            p = point(rect.right() - radius + y, rect.bottom() - radius + x);
            if (area_.contains(p)) draw_pixel (c, p , color );
            p = point(rect.left() + radius - y, rect.bottom() - radius + x);
            if (area_.contains(p)) draw_pixel (c, p , color );
            p = point(rect.left() + radius - x, rect.top() + radius - y);
            if (area_.contains(p)) draw_pixel (c, p , color );
            p = point(rect.right() - radius + x, rect.top() + radius - y);
            if (area_.contains(p)) draw_pixel (c, p , color );
            p = point(rect.right() - radius + x, rect.bottom() - radius + y);
            if (area_.contains(p)) draw_pixel (c, p , color );
            p = point(rect.left() + radius - x, rect.bottom() - radius + y);
            if (area_.contains(p)) draw_pixel (c, p , color );
            y++;
            old_x = x;
            x = square_root ( ( radius * radius - y * y ) * 4 ) / 2;
        }

        if ( x == y && old_x != x )
        {
            p = point(rect.left() + radius - y, rect.top() + radius - x);
            if (area_.contains(p)) draw_pixel (c, p , color );
            p = point(rect.right() - radius + y, rect.top() + radius - x);
            if (area_.contains(p)) draw_pixel (c, p , color );
            p = point(rect.right() - radius + y, rect.bottom() - radius + x);
            if (area_.contains(p)) draw_pixel (c, p , color );
            p = point(rect.left() + radius - y, rect.bottom() - radius + x);
            if (area_.contains(p)) draw_pixel (c, p , color );
        }
    }

// ----------------------------------------------------------------------------------------

    template <typename pixel_type>
    void fill_gradient_rounded (
        const canvas& c,
        const rectangle& rect,
        unsigned long radius,
        const pixel_type& top_color,
        const pixel_type& bottom_color,
        const rectangle& area = rectangle(std::numeric_limits<long>::min(), std::numeric_limits<long>::min(),
                                          std::numeric_limits<long>::max(), std::numeric_limits<long>::max())

    )
    {
        rectangle valid_area(c.intersect(area.intersect(rect)));
        if ( valid_area.is_empty() )
            return;

        unsigned long m_prev = 0, m = radius, c_div = valid_area.height() - 1;

        const long c_top = valid_area.top();
        const long c_bottom = valid_area.bottom();

        for ( long y = c_top; y <= c_bottom;y++ )
        {

            unsigned long c_s = y - c_top;

            unsigned long c_t = c_bottom - y;

            if ( c_div == 0 )
            {
                // only a single round, just take the average color
                c_div = 2;
                c_s = c_t = 1;
            }

            rgb_alpha_pixel color;
            vector_to_pixel(color,
                            ((pixel_to_vector<unsigned long>(top_color)*c_t + pixel_to_vector<unsigned long>(bottom_color)*c_s)/c_div));

            unsigned long s = y - rect.top();

            unsigned long t = rect.bottom() - y;

            if ( s < radius )
            {
                m = radius - square_root ( ( radius * radius - ( radius - s ) * ( radius - s ) ) * 4 ) / 2;

                if ( s == m && m + 1 < m_prev )  // these are hacks to remove distracting artefacts at small radii
                    m++;
            }
            else if ( t < radius )
            {
                m = radius - square_root ( ( radius * radius - ( radius - t ) * ( radius - t ) ) * 4 ) / 2;

                if ( t == m && m == m_prev )
                    m++;
            }
            else
            {
                m = 0;
            }

            m_prev = m;

            draw_line ( c, point(rect.left() + m, y),
                        point(rect.right() - m, y), color, valid_area );
        }
    }

// ----------------------------------------------------------------------------------------

    template <typename pixel_type>
    void draw_rectangle (
        const canvas& c,
        rectangle rect,
        const pixel_type& pixel,
        const rectangle& area = rectangle(std::numeric_limits<long>::min(), std::numeric_limits<long>::min(),
                                          std::numeric_limits<long>::max(), std::numeric_limits<long>::max())
    )
    {
        // top line
        draw_line(c, point(rect.left(),rect.top()),
                  point(rect.right(),rect.top()),
                  pixel, area);

        // bottom line
        draw_line(c, point(rect.left(),rect.bottom()),
                  point(rect.right(),rect.bottom()),
                  pixel, area);

        // left line
        draw_line(c, point(rect.left(),rect.top()),
                  point(rect.left(),rect.bottom()),
                  pixel, area);

        // right line
        draw_line(c, point(rect.right(),rect.top()),
                  point(rect.right(),rect.bottom()),
                  pixel, area);
    }
    inline void draw_rectangle (
        const canvas& c,
        rectangle rect
    ){ draw_rectangle(c, rect, 0); }

// ----------------------------------------------------------------------------------------

    template <typename pixel_type>
    void fill_rect (
        const canvas& c,
        const rectangle& rect,
        const pixel_type& pixel
    )
    {
        rectangle area = rect.intersect(c);
        for (long y = area.top(); y <= area.bottom(); ++y)
        {
            for (long x = area.left(); x <= area.right(); ++x)
            {
                assign_pixel(c[y-c.top()][x-c.left()], pixel);
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <typename pixel_type>
    void fill_rect_with_vertical_gradient (
        const canvas& c,
        const rectangle& rect,
        const pixel_type& pixel_top,
        const pixel_type& pixel_bottom,
        const rectangle& area_ = rectangle(std::numeric_limits<long>::min(), std::numeric_limits<long>::min(),
                                          std::numeric_limits<long>::max(), std::numeric_limits<long>::max())
    )
    {
        rectangle area = rect.intersect(c).intersect(area_);
        pixel_type pixel;

        const long s = rect.bottom()-rect.top();

        for (long y = area.top(); y <= area.bottom(); ++y)
        {
            const long t = rect.bottom()-y;
            const long b = y-rect.top();
            vector_to_pixel(pixel,
                    ((pixel_to_vector<long>(pixel_top)*t +
                      pixel_to_vector<long>(pixel_bottom)*b)/s));

            for (long x = area.left(); x <= area.right(); ++x)
            {
                assign_pixel(c[y-c.top()][x-c.left()], pixel);
            }
        }
    }

// ----------------------------------------------------------------------------------------

}

#ifdef NO_MAKEFILE
#include "canvas_drawing.cpp"
#endif

#endif // DLIB_GUI_CANVAS_DRAWINg_


dlib C++ Library - drawable.cpp

// Copyright (C) 2005  Davis E. King (davis@dlib.net), Keita Mochizuki
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_DRAWABLe_CPP_
#define DLIB_DRAWABLe_CPP_

#include "drawable.h"

#include <algorithm>
#include <iostream>

namespace dlib
{

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// -----------  drawable_window object  ------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    rgb_pixel drawable_window::
    background_color (
    ) const
    {
        auto_mutex M(wm);
        return bg_color;
    }

// ----------------------------------------------------------------------------------------

    void drawable_window::
    set_background_color (
        unsigned long red_,
        unsigned long green_,
        unsigned long blue_
    )
    {
        wm.lock();
        bg_color.red = red_;
        bg_color.green = green_;
        bg_color.blue = blue_;
        wm.unlock();
        // now repaint the window
        unsigned long width,height;
        get_size(width,height);
        rectangle rect(0,0,width-1,height-1);
        invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    void drawable_window::
    paint (
        const canvas& c
    )
    {
        ++event_id;
        c.fill(bg_color.red,bg_color.green,bg_color.blue);

        widgets.reset();
        while (widgets.move_next())
        {
            widgets.element().value().reset();
            while (widgets.element().value().move_next())
            {
                // only dispatch a draw() call if this widget isn't hidden
                if (widgets.element().value().element()->hidden == false &&
                    widgets.element().value().element()->event_id != event_id)
                {
                    widgets.element().value().element()->event_id = event_id;
                    widgets.element().value().element()->draw(c);
                }
            }
        }
    }

// ----------------------------------------------------------------------------------------

    void drawable_window::
    on_user_event (
        void* p,
        int i
    )
    {
        drawable* d = static_cast<drawable*>(p);
        if (widget_set.is_member(d))
        {
            d->on_user_event(i);
        }
    }

// ----------------------------------------------------------------------------------------

    void drawable_window::
    on_window_moved(
    )
    {
        ++event_id;
        window_moved.reset();
        while (window_moved.move_next())
        {
            if (window_moved.element()->event_id != event_id)
            {
                window_moved.element()->event_id = event_id;
                window_moved.element()->on_window_moved();
            }
        }
    }

// ----------------------------------------------------------------------------------------

    void drawable_window::
    on_window_resized(
    )
    {
        ++event_id;
        window_resized.reset();
        while (window_resized.move_next())
        {
            if (window_resized.element()->event_id != event_id)
            {
                window_resized.element()->event_id = event_id;
                window_resized.element()->on_window_resized();
            }
        }
    }

// ----------------------------------------------------------------------------------------

    void drawable_window::
    on_keydown (
        unsigned long key,
        bool is_printable,
        unsigned long state
    )
    {
        ++event_id;
        keyboard.reset();
        while (keyboard.move_next())
        {
            if (keyboard.element()->event_id != event_id)
            {
                keyboard.element()->event_id = event_id;
                keyboard.element()->on_keydown(key,is_printable,state);
            }
        }
    }

// ----------------------------------------------------------------------------------------

    void drawable_window::
    on_focus_gained (
    )
    {
        ++event_id;
        focus.reset();
        while (focus.move_next())
        {
            if (focus.element()->event_id != event_id)
            {
                focus.element()->event_id = event_id;
                focus.element()->on_focus_gained();
            }
        }
    }

// ----------------------------------------------------------------------------------------

    void drawable_window::
    on_focus_lost (
    )
    {
        ++event_id;
        focus.reset();
        while (focus.move_next())
        {
            if (focus.element()->event_id != event_id)
            {
                focus.element()->event_id = event_id;
                focus.element()->on_focus_lost();
            }
        }
    }

// ----------------------------------------------------------------------------------------

    void drawable_window::
    on_mouse_down (
        unsigned long btn,
        unsigned long state,
        long x,
        long y,
        bool is_double_click
    )
    {
        lastx = x;
        lasty = y;

        ++event_id;
        mouse_click.reset();
        while (mouse_click.move_next())
        {
            if (mouse_click.element()->event_id != event_id)
            {
                mouse_click.element()->event_id = event_id;
                mouse_click.element()->on_mouse_down(btn,state,x,y,is_double_click);
            }
        }
    }

// ----------------------------------------------------------------------------------------

    void drawable_window::
    on_mouse_up (
        unsigned long btn,
        unsigned long state,
        long x,
        long y
    )
    {
        lastx = x;
        lasty = y;

        ++event_id;
        mouse_click.reset();
        while (mouse_click.move_next())
        {
            if (mouse_click.element()->event_id != event_id)
            {
                mouse_click.element()->event_id = event_id;
                mouse_click.element()->on_mouse_up(btn,state,x,y);
            }
        }
    }

// ----------------------------------------------------------------------------------------

    void drawable_window::
    on_mouse_move (
        unsigned long state,
        long x,
        long y
    )
    {
        lastx = x;
        lasty = y;

        ++event_id;
        mouse_move.reset();
        while (mouse_move.move_next())
        {
            if (mouse_move.element()->event_id != event_id)
            {
                mouse_move.element()->event_id = event_id;
                mouse_move.element()->on_mouse_move(state,x,y);
            }
        }
    }

// ----------------------------------------------------------------------------------------

    void drawable_window::
    on_mouse_leave (
    )
    {
        lastx = -1;
        lasty = -1;

        ++event_id;
        mouse_move.reset();
        while (mouse_move.move_next())
        {
            if (mouse_move.element()->event_id != event_id)
            {
                mouse_move.element()->event_id = event_id;
                mouse_move.element()->on_mouse_leave();
            }
        }
    }

// ----------------------------------------------------------------------------------------

    void drawable_window::
    on_mouse_enter (
    )
    {
        ++event_id;
        mouse_move.reset();
        while (mouse_move.move_next())
        {
            if (mouse_move.element()->event_id != event_id)
            {
                mouse_move.element()->event_id = event_id;
                mouse_move.element()->on_mouse_enter();
            }
        }
    }

// ----------------------------------------------------------------------------------------

    void drawable_window::
    on_wheel_up (
        unsigned long state
    )
    {
        ++event_id;
        mouse_wheel.reset();
        while (mouse_wheel.move_next())
        {
            if (mouse_wheel.element()->event_id != event_id)
            {
                mouse_wheel.element()->event_id = event_id;
                mouse_wheel.element()->on_wheel_up(state);
            }
        }
    }

// ----------------------------------------------------------------------------------------

    void drawable_window::
    on_wheel_down (
        unsigned long state
    )
    {
        ++event_id;
        mouse_wheel.reset();
        while (mouse_wheel.move_next())
        {
            if (mouse_wheel.element()->event_id != event_id)
            {
                mouse_wheel.element()->event_id = event_id;
                mouse_wheel.element()->on_wheel_down(state);
            }
        }
    }

// ----------------------------------------------------------------------------------------

    void drawable_window::
    on_string_put (
        const std::wstring &str
    )
    {
        ++event_id;
        string_put.reset();
        while (string_put.move_next())
        {
            if (string_put.element()->event_id != event_id)
            {
                string_put.element()->event_id = event_id;
                string_put.element()->on_string_put(str);
            }
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// -----------  drawable object  ----------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    void drawable::
    enable_events (
    )
    {
        auto_mutex M(m);
        if (enabled_events == false)
        {
            enabled_events = true;
            drawable* temp = this;
            long zo = z_order_value;

            drawable_window::set_of_drawables* sod = parent.widgets[zo];
            if (sod == 0)
            {
                // this drawable is the first widget at this z order so we need
                // to make its containing set
                drawable_window::set_of_drawables s;
                s.add(temp);
                parent.widgets.add(zo,s);
            }
            else
            {
                sod->add(temp);
            }

            temp = this;
            parent.widget_set.add(temp);

            if (events & MOUSE_MOVE)
            {
                temp = this;
                parent.mouse_move.add(temp);
            }
            if (events & MOUSE_CLICK)
            {
                temp = this;
                parent.mouse_click.add(temp);
            }
            if (events & MOUSE_WHEEL)
            {
                temp = this;
                parent.mouse_wheel.add(temp);
            }
            if (events & WINDOW_RESIZED)
            {
                temp = this;
                parent.window_resized.add(temp);
            }
            if (events & KEYBOARD_EVENTS)
            {
                temp = this;
                parent.keyboard.add(temp);
            }
            if (events & FOCUS_EVENTS)
            {
                temp = this;
                parent.focus.add(temp);
            }
            if (events & WINDOW_MOVED)
            {
                temp = this;
                parent.window_moved.add(temp);
            }
            if (events & STRING_PUT)
            {
                temp = this;
                parent.string_put.add(temp);
            }
            parent.invalidate_rectangle(rect);
        }
    }

// ----------------------------------------------------------------------------------------

    void drawable::
    set_z_order (
        long order
    )
    {
        auto_mutex M(m);
        if (order != z_order_value && enabled_events)
        {
            // first remove this drawable from widgets
            drawable_window::set_of_drawables* sod = parent.widgets[z_order_value];
            drawable* junk;
            sod->remove(this,junk);

            // if there are no more drawables at this z order then destroy the
            // set for this order
            if (sod->size() == 0)
                parent.widgets.destroy(z_order_value);

            // now add this drawable to its new z order
            sod = parent.widgets[order];
            if (sod == 0)
            {
                // this drawable is the first widget at this z order so we need
                // to make its containing set
                drawable_window::set_of_drawables s, x;
                s.add(junk);
                long temp_order = order;
                parent.widgets.add(temp_order,s);
            }
            else
            {
                sod->add(junk);
            }
            parent.invalidate_rectangle(rect);

        }
        z_order_value = order;
    }

// ----------------------------------------------------------------------------------------

    void drawable::
    disable_events (
    )
    {
        auto_mutex M(m);
        if (enabled_events)
        {
            enabled_events = false;
            // first remove this drawable from widgets
            drawable_window::set_of_drawables* sod = parent.widgets[z_order_value];
            drawable* junk;
            sod->remove(this,junk);

            // if there are no more drawables at this z order then destroy the
            // set for this order
            if (sod->size() == 0)
                parent.widgets.destroy(z_order_value);

            parent.widget_set.remove(this,junk);

            // now unregister this drawable from all the events it has registered for.
            if (events & MOUSE_MOVE)
                parent.mouse_move.remove(this,junk);
            if (events & MOUSE_CLICK)
                parent.mouse_click.remove(this,junk);
            if (events & MOUSE_WHEEL)
                parent.mouse_wheel.remove(this,junk);
            if (events & WINDOW_RESIZED)
                parent.window_resized.remove(this,junk);
            if (events & KEYBOARD_EVENTS)
                parent.keyboard.remove(this,junk);
            if (events & FOCUS_EVENTS)
                parent.focus.remove(this,junk);
            if (events & WINDOW_MOVED)
                parent.window_moved.remove(this,junk);
            if (events & STRING_PUT)
                parent.string_put.remove(this,junk);
        }
    }

// ----------------------------------------------------------------------------------------

    drawable::
    ~drawable (
    )
    {
        try
        {
            DLIB_ASSERT(events_are_enabled() == false,
                "\tdrawable::~drawable()"
                << "\n\tYou must disable events for drawable objects in their destructor by calling disable_events()."
                << "\n\tthis:     " << this
                );
        }
        catch (std::exception& e)
        {
            std::cerr << e.what() << std::endl;
            assert(false);
            abort();
        }
        disable_events();
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_DRAWABLe_CPP_


dlib C++ Library - drawable.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net), Keita Mochizuki
// License: Boost Software License   See LICENSE.txt for the full license.

#ifndef DLIB_DRAWABLe_
#define DLIB_DRAWABLe_

#include "drawable_abstract.h"
#include "../gui_core.h"
#include "../set.h"
#include "../binary_search_tree.h"
#include "../algs.h"
#include "../pixel.h"
#include "fonts.h"
#include "../matrix.h"
#include "canvas_drawing.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class drawable_window
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class drawable;
    class drawable_window : public base_window
    {
        /*!
            INITIAL VALUE
                - lastx == -1
                - lasty == -1
                - event_id == 1

            CONVENTION
                - bg_color == background_color()

                - widgets == this binary search tree contains every drawable that is in
                  this window.  It is a mapping of each drawable's z-order to a pointer
                  to said drawable.
                - widget_set == a set that contains all the widgets in this window and
                  want to receive events.

                - mouse_move == this is a set of drawables that are in this window and
                  want to receive the mouse movement events.
                - mouse_wheel == this is a set of drawables that are in this window and
                  want to receive the mouse wheel events.
                - mouse_click == this is a set of drawables that are in this window and
                  want to receive the mouse click events.
                - window_resized == this is a set of drawables that are in this window and
                  want to receive the window_resized event.
                - keyboard == this is a set of drawables that are in this window and
                  want to receive keyboard events.
                - focus == this is a set of drawables that are in this window and
                  want to receive focus events.
                - window_moved == this is a set of drawables that are in this window and
                  want to receive window move events.

                - lastx == the x coordinate that we last saw the mouse at or -1 if the
                  mouse is outside this window.
                - lasty == the y coordinate that we last saw the mouse at or -1 if the
                  mouse is outside this window.

                - event_id == a number we use to tag events so we don't end up sending
                  an event to a drawable more than once.  This could happen if one of the
                  event handlers does something to reset the enumerator while we are
                  dispatching events (e.g. creating a new widget).
        !*/
    public:

        drawable_window(
            bool resizable = true,
            bool undecorated = false
        ) :
            base_window(resizable,undecorated),
            bg_color(rgb_pixel(212,208,200)),
            lastx(-1),
            lasty(-1),
            event_id(1)
        {}

        void set_background_color (
            unsigned long red,
            unsigned long green,
            unsigned long blue
        );

        rgb_pixel background_color (
        ) const;

        virtual inline ~drawable_window()=0;

    private:

        void paint (
            const canvas& c
        );

    protected:

        void on_window_resized(
        );

        void on_window_moved(
        );

        void on_mouse_down (
            unsigned long btn,
            unsigned long state,
            long x,
            long y,
            bool is_double_click
        );

        void on_mouse_up (
            unsigned long btn,
            unsigned long state,
            long x,
            long y
        );

        void on_mouse_move (
            unsigned long state,
            long x,
            long y
        );

        void on_mouse_leave (
        );

        void on_mouse_enter (
        );

        void on_wheel_up (
            unsigned long state
        );

        void on_wheel_down (
            unsigned long state
        );

        void on_focus_gained (
        );

        void on_focus_lost (
        );

        void on_keydown (
            unsigned long key,
            bool is_printable,
            unsigned long state
        );

        void on_string_put (
            const std::wstring &str
        );

        void on_user_event (
            void* p,
            int i
        );

    private:

        friend class drawable;

        rgb_pixel bg_color;

        typedef set<drawable*>::kernel_1a_c set_of_drawables;

        binary_search_tree<long,set_of_drawables>::kernel_1a_c widgets;

        set_of_drawables widget_set;
        set_of_drawables mouse_move;
        set_of_drawables mouse_wheel;
        set_of_drawables mouse_click;
        set_of_drawables window_resized;
        set_of_drawables keyboard;
        set_of_drawables focus;
        set_of_drawables window_moved;
        set_of_drawables string_put;

        long lastx, lasty;
        unsigned long event_id;

        // restricted functions
        drawable_window(drawable_window&);        // copy constructor
        drawable_window& operator=(drawable_window&);    // assignment operator

    };

    drawable_window::~drawable_window(){ close_window();}

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class drawable
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    enum
    {
        MOUSE_MOVE = 1,
        MOUSE_CLICK = 2,
        MOUSE_WHEEL = 4,
        WINDOW_RESIZED = 8,
        KEYBOARD_EVENTS = 16,
        FOCUS_EVENTS = 32,
        WINDOW_MOVED = 64,
        STRING_PUT = 128
    };

    class drawable
    {

        /*!
            INITIAL VALUE
                - enabled_events == false
                - event_id == 0

            CONVENTION
                - events == a bitset specifying what events this drawable is to receive.

                - z_order_value == z_order()

                - if (this drawable has been added to the parent window's sets and
                  binary search tree) then
                    - enabled_events == true
                - else
                    - enabled_events == false

                - event_id == the id of the last event we got from our parent window
        !*/

    public:

        friend class drawable_window;

        drawable (
            drawable_window& w,
            unsigned long events_ = 0
        ) :
            m(w.wm),
            parent(w),
            hidden(false),
            enabled(true),
            lastx(w.lastx),
            lasty(w.lasty),
            mfont(default_font::get_font()),
            z_order_value(0),
            events(events_),
            enabled_events(false),
            event_id(0)
        {}

        virtual ~drawable (
        );

        long z_order (
        ) const
        {
            m.lock();
            long temp = z_order_value;
            m.unlock();
            return temp;
        }

        virtual void set_z_order (
            long order
        );

        const rectangle get_rect (
        ) const
        {
            auto_mutex M(m);
            return rect;
        }

        long bottom (
        ) const
        {
            auto_mutex M(m);
            return rect.bottom();
        }

        long top (
        ) const
        {
            auto_mutex M(m);
            return rect.top();
        }

        long left (
        ) const
        {
            auto_mutex M(m);
            return rect.left();
        }

        long right (
        ) const
        {
            auto_mutex M(m);
            return rect.right();
        }

        long width (
        ) const
        {
            auto_mutex M(m);
            return rect.width();
        }

        long height (
        ) const
        {
            auto_mutex M(m);
            return rect.height();
        }

        bool is_enabled (
        ) const
        {
            auto_mutex M(m);
            return enabled;
        }

        virtual void enable (
        )
        {
            auto_mutex M(m);
            enabled = true;
            parent.invalidate_rectangle(rect);
        }

        virtual void disable (
        )
        {
            auto_mutex M(m);
            enabled = false;
            parent.invalidate_rectangle(rect);
        }

        virtual void set_main_font (
            const shared_ptr_thread_safe<font>& f
        )
        {
            auto_mutex M(m);
            mfont = f;
            parent.invalidate_rectangle(rect);
        }

        const shared_ptr_thread_safe<font> main_font (
        ) const
        {
            auto_mutex M(m);
            return mfont;
        }

        bool is_hidden (
        ) const
        {
            auto_mutex M(m);
            return hidden;
        }

        virtual void set_pos (
            long x,
            long y
        )
        {
            m.lock();
            rectangle old(rect);

            const unsigned long width = rect.width();
            const unsigned long height = rect.height();
            rect.set_top(y);
            rect.set_left(x);
            rect.set_right(static_cast<long>(x+width)-1);
            rect.set_bottom(static_cast<long>(y+height)-1);

            parent.invalidate_rectangle(rect+old);
            m.unlock();
        }

        virtual void show (
        )
        {
            m.lock();
            hidden = false;
            parent.invalidate_rectangle(rect);
            m.unlock();
        }

        virtual void hide (
        )
        {
            m.lock();
            hidden = true;
            parent.invalidate_rectangle(rect);
            m.unlock();
        }

        base_window& parent_window (
        ) { return parent; }

        const base_window& parent_window (
        ) const { return parent; }

        virtual int next_free_user_event_number (
        )const { return 0; }

    protected:
        rectangle rect;
        const rmutex& m;
        drawable_window& parent;
        bool hidden;
        bool enabled;
        const long& lastx;
        const long& lasty;
        shared_ptr_thread_safe<font> mfont;

        void enable_events (
        );

        bool events_are_enabled (
        ) const { auto_mutex M(m); return enabled_events; }

        void disable_events (
        );

    private:

        long z_order_value;
        const unsigned long events;
        bool enabled_events;
        unsigned long event_id;

        // restricted functions
        drawable(drawable&);        // copy constructor
        drawable& operator=(drawable&);    // assignment operator

    protected:

        virtual void draw (
            const canvas& c
        ) const=0;

        virtual void on_user_event (
            int
        ){}

        virtual void on_window_resized(
        ){}

        virtual void on_window_moved(
        ){}

        virtual void on_mouse_down (
            unsigned long ,
            unsigned long ,
            long ,
            long ,
            bool
        ){}

        virtual void on_mouse_up (
            unsigned long ,
            unsigned long ,
            long ,
            long
        ){}

        virtual void on_mouse_move (
            unsigned long ,
            long ,
            long
        ){}

        virtual void on_mouse_leave (
        ){}

        virtual void on_mouse_enter (
        ){}

        virtual void on_wheel_up (
            unsigned long
        ){}

        virtual void on_wheel_down (
            unsigned long
        ){}

        virtual void on_focus_gained (
        ){}

        virtual void on_focus_lost (
        ){}

        virtual void on_keydown (
            unsigned long ,
            bool ,
            unsigned long
        ){}

        virtual void on_string_put (
            const std::wstring&
        ){}
    };

// ----------------------------------------------------------------------------------------

}

#ifdef NO_MAKEFILE
#include "drawable.cpp"
#endif

#endif // DLIB_DRAWABLe_


dlib C++ Library - fonts.cpp

// Copyright (C) 2005  Davis E. King (davis@dlib.net), and Nils Labugt, Keita Mochizuki
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_FONTs_CPP_
#define DLIB_FONTs_CPP_

#include "fonts.h"

#include "../serialize.h"
#include <sstream>
#include "../base64.h"
#include "../compress_stream.h"
#include <fstream>
#include "../tokenizer.h"
#include "nativefont.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    const std::string get_decoded_string_with_default_font_data()
    {
        dlib::base64::kernel_1a base64_coder;
        dlib::compress_stream::kernel_1ea compressor;
        std::ostringstream sout;
        std::istringstream sin;

        /*
            SOURCE BDF FILE (helvR12.bdf) COMMENTS
            COMMENT $XConsortium: helvR12.bdf,v 1.15 95/01/26 18:02:58 gildea Exp $
            COMMENT $Id: helvR12.bdf,v 1.26 2004-11-28 20:08:46+00 mgk25 Rel $
            COMMENT
            COMMENT +
            COMMENT  Copyright 1984-1989, 1994 Adobe Systems Incorporated.
            COMMENT  Copyright 1988, 1994 Digital Equipment Corporation.
            COMMENT
            COMMENT  Adobe is a trademark of Adobe Systems Incorporated which may be
            COMMENT  registered in certain jurisdictions.
            COMMENT  Permission to use these trademarks is hereby granted only in
            COMMENT  association with the images described in this file.
            COMMENT
            COMMENT  Permission to use, copy, modify, distribute and sell this software
            COMMENT  and its documentation for any purpose and without fee is hereby
            COMMENT  granted, provided that the above copyright notices appear in all
            COMMENT  copies and that both those copyright notices and this permission
            COMMENT  notice appear in supporting documentation, and that the names of
            COMMENT  Adobe Systems and Digital Equipment Corporation not be used in
            COMMENT  advertising or publicity pertaining to distribution of the software
            COMMENT  without specific, written prior permission.  Adobe Systems and
            COMMENT  Digital Equipment Corporation make no representations about the
            COMMENT  suitability of this software for any purpose.  It is provided "as
            COMMENT  is" without express or implied warranty.
            COMMENT -
        */

        // The base64 encoded data we want to decode and return.
        sout << "AXF+zOQzCgGitrKiOCGEL4hlIv1ZenWJyjMQ4rJ6f/oPMeHqsZn+8XnpehwFQTz3dtUGlZRAUoOa";
        sout << "uVo8UiplcFxuK69A+94rpMCMAyEeeOwZ/tRzkX4eKuU3L4xtsJDknMiYUNKaMrYimb1QJ0E+SRqQ";
        sout << "wATrMTecYNZvJJm02WibiwE4cJ5scvkHNl4KJT5QfdwRdGopTyUVdZvRvtbTLLjsJP0fQEQLqemf";
        sout << "qPE4kDD79ehrBIwLO1Y6TzxtrrIoQR57zlwTUyLenqRtSN3VLtjWYd82cehRIlTLtuxBg2s+zZVq";
        sout << "jNlNnYTSM+Swy06qnQgg+Dt0lhtlB9shR1OAlcfCtTW6HKoBk/FGeDmjTGW4bNCGv7RjgM6TlLDg";
        sout << "ZYSSA6ZCCAKBgE++U32gLHCCiVkPTkkp9P6ioR+e3SSKRNm9p5MHf+ZQ3LJkW8KFJ/K9gKT1yvyv";
        sout << "F99pAvOOq16tHRFvzBs+xZj/mUpH0lGIS7kLWr9oP2KuccVrz25aJn3kDruwTYoD+CYlOqtPO0Mv";
        sout << "dEI0LUR0Ykp1M2rWo76fJ/fpzHjV7737hjkNPJ13nO72RMDr4R5V3uG7Dw7Ng+vGX3WgJZ4wh1JX";
        sout << "pl2VMqC5JXccctzvnQvnuvBvRm7THgwQUgMKKT3WK6afUUVlJy8DHKuU4k1ibfVMxAmrwKdTUX2w";
        sout << "cje3A05Qji3aop65qEdwgI5O17HIVoRQOG/na+XRMowOfUvI4H8Z4+JGACfRrQctgYDAM9eJzm8i";
        sout << "PibyutmJfZBGg0a3oC75S5R9lTxEjPocnEyJRYNnmVnVAmKKbTbTsznuaD+D1XhPdr2t3A4bRTsp";
        sout << "toKKtlFnd9YGwLWwONDwLnoQ/IXwyF7txrRHNSVToh772U0Aih/yn5vnmcMF750eiMzRAgXu5sbR";
        sout << "VXEOVCiLgVevN5umkvjZt1eGTSSzDMrIvnv4nyOfaFsD+I76wQfgLqd71rheozGtjNc0AOTx4Ggc";
        sout << "eUSFHTDAVfTExBzckurtyuIAqF986a0JLHCtsDpBa2wWNuiQYOH3/LX1zkdU2hdamhBW774bpEwr";
        sout << "dguMxxOeDGOBgIlM5gxXGYXSf5IN3fUAEPfOPRxB7T+tpjFnWd7cg+JMabci3zhJ9ANaYT7HGeTX";
        sout << "bulKnGHjYrR1BxdK3YeliogQRU4ytmxlyL5zlNFU/759mA8XSfIPMEZn9Vxkb00q1htF7REiDcr3";
        sout << "kW1rtPAc7VQNEhT54vK/YF6rMvjO7kBZ/vLYo7E8e8hDKEnY8ucrC3KGmeo31Gei74BBcEbvJBd3";
        sout << "/YAaIKgXWwU2wSUw9wLq2RwGwyguvKBx0J/gn27tjcVAHorRBwxzPpk8r+YPyN+SifSzEL7LEy1G";
        sout << "lPHxmXTrcqnH9qraeAqXJUJvU8SJJpf/tmsAE+XSKD/kpVBnT5qXsJ1SRFS7MtfPjE1j/NYbaQBI";
        sout << "bOrh81zaYCEJR0IKHWCIsu/MC3zKXfkxFgQ9XpYAuWjSSK64YpgkxSMe8VG8yYvigOw2ODg/z4FU";
        sout << "+HpnEKF/M/mKfLKK1i/8BV7xcYVHrhEww1QznoFklJs/pEg3Kd5PE1lRii6hvTn6McVAkw+YbH9q";
        sout << "/sg4gFIAvai64hMcZ1oIZYppj3ZN6KMdyhK5s4++ZS/YOV2nNhW73ovivyi2Tjg7lxjJJtsYrLKb";
        sout << "zIN1slOICKYwBq42TFBcFXaZ6rf0Czd09tL+q6A1Ztgr3BNuhCenjhWN5ji0LccGYZo6bLTggRG/";
        sout << "Uz6K3CBBU/byLs79c5qCohrr7rlpDSdbuR+aJgNiWoU6T0i2Tvua6h51LcWEHy5P2n146/Ae2di4";
        sout << "eh20WQvclrsgm1oFTGD0Oe85GKOTA7vvwKmLBc1wwA0foTuxzVgj0TMTFBiYLTLG4ujUyBYy1N6e";
        sout << "H8EKi8H+ZAlqezrjABO3BQr33ewdZL5IeJ4w7gdGUDA6+P+7cODcBW50X9++6YTnKctuEw6aXBpy";
        sout << "GgcMfPE61G8YKBbFGFic3TVvGCLvre1iURv+F+hU4/ee6ILuPnpYnSXX2iCIK/kmkBse8805d4Qe";
        sout << "DG/8rBW9ojvAgc0jX7CatPEMHGkcz+KIZoKMI7XXK4PJpGQUdq6EdIhJC4koXEynjwwXMeC+jJqH";
        sout << "agwrlDNssq/8AA==";

        // 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();
    }

    default_font::
    default_font (
    )
    {
        using namespace std;
        l = new letter[256];

        try
        {
            istringstream sin(get_decoded_string_with_default_font_data());

            for (int i = 0; i < 256; ++i)
            {
                deserialize(l[i],sin);
            }

        }
        catch (...)
        {
            delete [] l;
            throw;
        }
    }

// ----------------------------------------------------------------------------------------

    void serialize (
        const letter& item,
        std::ostream& out
    )
    {
        try
        {
            serialize(item.w,out);
            serialize(item.count,out);

            for (unsigned long i = 0; i < item.count; ++i)
            {
                serialize(item.points[i].x,out);
                serialize(item.points[i].y,out);
            }
        }
        catch (serialization_error e)
        {
            throw serialization_error(e.info + "\n   while serializing object of type letter");
        }
    }

    void deserialize (
        letter& item,
        std::istream& in
    )
    {
        try
        {
            if (item.points)
                delete [] item.points;

            deserialize(item.w,in);
            deserialize(item.count,in);

            if (item.count > 0)
                item.points = new letter::point[item.count];
            else
                item.points = 0;

            for (unsigned long i = 0; i < item.count; ++i)
            {
                deserialize(item.points[i].x,in);
                deserialize(item.points[i].y,in);
            }
        }
        catch (serialization_error e)
        {
            item.w = 0;
            item.count = 0;
            item.points = 0;
            throw serialization_error(e.info + "\n   while deserializing object of type letter");
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    namespace bdf_font_helpers
    {
        class bdf_parser
        {
        public:
            bdf_parser( std::istream& in ) : in_( in )
            {
                std::string str_tmp;
                int int_tmp;

                str_tmp = "STARTFONT";      int_tmp = STARTFONT;        keyword_map.add( str_tmp, int_tmp );
                str_tmp = "FONTBOUNDINGBOX";int_tmp = FONTBOUNDINGBOX;  keyword_map.add( str_tmp, int_tmp );
                str_tmp = "DWIDTH";         int_tmp = DWIDTH;           keyword_map.add( str_tmp, int_tmp );
                str_tmp = "CHARS";          int_tmp = CHARS;            keyword_map.add( str_tmp, int_tmp );
                str_tmp = "STARTCHAR";      int_tmp = STARTCHAR;        keyword_map.add( str_tmp, int_tmp );
                str_tmp = "ENCODING";       int_tmp = ENCODING;         keyword_map.add( str_tmp, int_tmp );
                str_tmp = "BBX";            int_tmp = BBX;              keyword_map.add( str_tmp, int_tmp );
                str_tmp = "BITMAP";         int_tmp = BITMAP;           keyword_map.add( str_tmp, int_tmp );
                str_tmp = "ENDCHAR";        int_tmp = ENDCHAR;          keyword_map.add( str_tmp, int_tmp );
                str_tmp = "ENDFONT";        int_tmp = ENDFONT;          keyword_map.add( str_tmp, int_tmp );
                str_tmp = "DEFAULT_CHAR";   int_tmp = DEFAULT_CHAR;     keyword_map.add( str_tmp, int_tmp );

                tokzr.set_identifier_token( tokzr.uppercase_letters(), tokzr.uppercase_letters() + "_" );
                tokzr.set_stream( in );

            }

            enum bdf_enums
            {
                NO_KEYWORD = 0,
                STARTFONT = 1,
                FONTBOUNDINGBOX = 2,
                DWIDTH = 4,
                DEFAULT_CHAR = 8,
                CHARS = 16,
                STARTCHAR = 32,
                ENCODING = 64,
                BBX = 128,
                BITMAP = 256,
                ENDCHAR = 512,
                ENDFONT = 1024

            };
            struct header_info
            {
                int FBBx, FBBy, Xoff, Yoff;
                int dwx0, dwy0;
                bool has_global_dw;
                long default_char;
            };
            struct char_info
            {
                int dwx0, dwy0;
                int BBw, BBh, BBxoff0x, BByoff0y;
                array2d<char> bitmap;
                bool has_dw;
            };
            bool parse_header( header_info& info )
            {
                if ( required_keyword( STARTFONT ) == false )
                    return false;    // parse_error: required keyword missing
                info.has_global_dw = false;
                int find = FONTBOUNDINGBOX | DWIDTH | DEFAULT_CHAR;
                int stop = CHARS | STARTCHAR | ENCODING | BBX | BITMAP | ENDCHAR | ENDFONT;
                int res;
                while ( 1 )
                {
                    res = find_keywords( find | stop );
                    if ( res & FONTBOUNDINGBOX )
                    {
                        in_ >> info.FBBx >> info.FBBy >> info.Xoff >> info.Yoff;
                        if ( in_.fail() )
                            return false;    // parse_error
                        find &= ~FONTBOUNDINGBOX;
                        continue;
                    }
                    if ( res & DWIDTH )
                    {
                        in_ >> info.dwx0 >> info.dwy0;
                        if ( in_.fail() )
                            return false;    // parse_error
                        find &= ~DWIDTH;
                        info.has_global_dw = true;
                        continue;
                    }
                    if ( res & DEFAULT_CHAR )
                    {
                        in_ >> info.default_char;
                        if ( in_.fail() )
                            return false;    // parse_error
                        find &= ~DEFAULT_CHAR;
                        continue;
                    }
                    if ( res & NO_KEYWORD )
                        return false;    // parse_error: unexpected EOF
                    break;
                }
                if ( res != CHARS || ( find & FONTBOUNDINGBOX ) )
                    return false;    // parse_error: required keyword missing or unexpeced keyword
                return true;
            }
            int parse_glyph( char_info& info, unichar& enc )
            {
                info.has_dw = false;
                int e;
                int res;
                while ( 1 )
                {
                    res = find_keywords( ENCODING );
                    if ( res != ENCODING )
                        return 0; // no more glyphs
                    in_ >> e;
                    if ( in_.fail() )
                        return -1;    // parse_error
                    if ( e >= static_cast<int>(enc) )
                        break;
                }
                int find = BBX | DWIDTH;
                int stop = STARTCHAR | ENCODING | BITMAP | ENDCHAR | ENDFONT;
                while ( 1 )
                {
                    res = find_keywords( find | stop );
                    if ( res & BBX )
                    {
                        in_ >> info.BBw >> info.BBh >> info.BBxoff0x >> info.BByoff0y;
                        if ( in_.fail() )
                            return -1;    // parse_error
                        find &= ~BBX;
                        continue;
                    }
                    if ( res & DWIDTH )
                    {
                        in_ >> info.dwx0 >> info.dwy0;
                        if ( in_.fail() )
                            return -1;    // parse_error
                        find &= ~DWIDTH;
                        info.has_dw = true;
                        continue;
                    }
                    if ( res & NO_KEYWORD )
                        return -1;    // parse_error: unexpected EOF
                    break;
                }
                if ( res != BITMAP || ( find != NO_KEYWORD ) )
                    return -1;     // parse_error: required keyword missing or unexpeced keyword
                unsigned h = info.BBh;
                unsigned w = ( info.BBw + 7 ) / 8 * 2;
                info.bitmap.set_size( h, w );
                for ( unsigned r = 0;r < h;r++ )
                {
                    trim();
                    std::string str = "";
                    extract_hex(str);
                    if(str.size() < w)
                        return -1;    // parse_error
                    for ( unsigned c = 0;c < w;c++ )
                        info.bitmap[r][c] = str[c];
                }
                if ( in_.fail() )
                    return -1;      // parse_error
                if ( required_keyword( ENDCHAR ) == false )
                    return -1;      // parse_error: required keyword missing
                enc = e;
                return 1;
            }
        private:
            map<std::string, int>::kernel_1a_c keyword_map;
            tokenizer::kernel_1a_c tokzr;
            std::istream& in_;
            void extract_hex(std::string& str)
            {
                int type;
                std::string token;
                while ( 1 )
                {
                    type = tokzr.peek_type();
                    if ( type == tokenizer::kernel_1a_c::IDENTIFIER || type == tokenizer::kernel_1a_c::NUMBER )
                    {
                        tokzr.get_token( type, token );
                        str += token;
                        continue;
                    }
                    break;
                }
            }
            void trim()
            {
                int type;
                std::string token;
                while ( 1 )
                {
                    type = tokzr.peek_type();
                    if ( type == tokenizer::kernel_1a_c::WHITE_SPACE || type == tokenizer::kernel_1a_c::END_OF_LINE )
                    {
                        tokzr.get_token( type, token );
                        continue;
                    }
                    break;
                }
            }
            bool required_keyword( int kw )
            {
                int type;
                std::string token;
                while ( 1 )
                {
                    tokzr.get_token( type, token );
                    if ( type == tokenizer::kernel_1a_c::WHITE_SPACE || type == tokenizer::kernel_1a_c::END_OF_LINE )
                        continue;
                    if ( type != tokenizer::kernel_1a_c::IDENTIFIER || keyword_map.is_in_domain( token ) == false || ( keyword_map[token] & kw ) == 0 )
                        return false;
                    break;
                }
                return true;
            }
            int find_keywords( int find )
            {
                int type;
                std::string token;
                while ( 1 )
                {
                    tokzr.get_token( type, token );
                    if ( type == tokenizer::kernel_1a_c::END_OF_FILE )
                        return NO_KEYWORD;
                    if ( type == tokenizer::kernel_1a_c::IDENTIFIER && keyword_map.is_in_domain( token ) == true )
                    {
                        int kw = keyword_map[token];
                        if ( kw & find )
                            return kw;
                    }
                }
                return true;
            }

        };

    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                    bdf_font functions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    bdf_font::bdf_font(
        long default_char_
    ) :
        default_char(0),
        is_initialized( false ),
        right_overflow_( 0 ),
        has_global_width( false ),
        specified_default_char( default_char_ )
    {
        // make sure gl contains at least one letter
        gl.resize(1);
    }

// ----------------------------------------------------------------------------------------

    void bdf_font::adjust_metrics(
    )
    {
        if ( is_initialized == false )
            return;
        // set starting values for fbb
        if ( gl[default_char].num_of_points() > 0 )
        {
            letter& g =  gl[default_char];
            fbb.set_top( g[0].y );
            fbb.set_bottom( g[0].y );
            fbb.set_left( g[0].x );
            fbb.set_right( g[0].x );
        }
        else
        {
            // ok, the default char was a space
            // let's just choose some safe arbitrary values then...
            fbb.set_top( 10000 );
            fbb.set_bottom( -10000 );
            fbb.set_left( 10000 );
            fbb.set_right( -10000 );
        }
        right_overflow_ = 0;
        for ( unichar n = 0; n < gl.size(); n++ )
        {
            letter& g = gl[n];
            unsigned short nr_pts = g.num_of_points();
            for ( unsigned short k = 0;k < nr_pts;k++ )
            {
                fbb.set_top( std::min( fbb.top(), (long)g[k].y ) );
                fbb.set_left( std::min( fbb.left(), (long)g[k].x ) );
                fbb.set_bottom( std::max( fbb.bottom(), (long)g[k].y ) );
                fbb.set_right( std::max( fbb.right(), (long)g[k].x ) );
                right_overflow_ = std::max( right_overflow_, (unsigned long)(g[k].x - g.width()) );  // superfluous?
            }
        }
    }

// ----------------------------------------------------------------------------------------

    long bdf_font::
    read_bdf_file(
        std::istream& in,
        unichar max_enc,
        unichar min_enc
    )
    {
        using namespace bdf_font_helpers;

        bdf_parser parser( in );
        bdf_parser::header_info hinfo;
        bdf_parser::char_info cinfo;

        gl.resize(max_enc+1);
        hinfo.default_char =  - 1;
        if ( is_initialized == false || static_cast<std::streamoff>(in.tellg()) == std::ios::beg )
        {
            if ( parser.parse_header( hinfo ) == false )
                return 0;   // parse_error: invalid or missing header
        }
        else
        {
            // not start of file, so use values from previous read.
            hinfo.has_global_dw = has_global_width;
            hinfo.dwx0 = global_width;
        }
        int res;
        unichar nr_letters_added = 0;
        unsigned width;
        for ( unichar n = min_enc; n <= max_enc; n++ )
        {
            if ( in.eof() )
                break;
            long pos = in.tellg();
            res = parser.parse_glyph( cinfo, n );
            if ( res < 0 )
                return 0;  // parse_error
            if ( res == 0 )
                continue;
            if ( n > max_enc )
            {
                in.seekg( pos );
                break;
            }

            if ( cinfo.has_dw == false )
            {
                if ( hinfo.has_global_dw == false )
                    return 0;    // neither width info for the glyph, nor for the font as a whole (monospace).
                width = hinfo.dwx0;
            }
            else
                width = cinfo.dwx0;

            if ( bitmap_to_letter( cinfo.bitmap, n, width, cinfo.BBxoff0x, cinfo.BByoff0y ) == false )
                return 0;
            nr_letters_added++;

            if ( is_initialized == false )
            {
                // Bonding rectangle for the font.
                fbb.set_top( -( hinfo.Yoff + hinfo.FBBy - 1 ) );
                fbb.set_bottom( -hinfo.Yoff );
                fbb.set_left( hinfo.Xoff );
                fbb.set_right( hinfo.Xoff + hinfo.FBBx - 1 );
                // We need to compute this after all the glyphs are loaded.
                right_overflow_ = 0;
                // set this to something valid now, just in case.
                default_char = n;
                // Save any global width in case we later read from the same file.
                has_global_width = hinfo.has_global_dw;
                if ( has_global_width )
                    global_width = hinfo.dwx0;
                // dont override value specified in the constructor with value specified in the file
                if ( specified_default_char < 0 && hinfo.default_char >= 0 )
                    specified_default_char = hinfo.default_char;

                is_initialized = true;
            }
        }
        if ( is_initialized == false )
            return 0;   // Not a single glyph was found within the specified range.

        if ( specified_default_char >= 0 )
            default_char = specified_default_char;
        // no default char specified, try find something sane.
        else
            default_char = 0;

        return nr_letters_added;
    }

// ----------------------------------------------------------------------------------------

    bool bdf_font::
    bitmap_to_letter(
        array2d<char>& bitmap,
        unichar enc,
        unsigned long width,
        int x_offset,
        int y_offset
    )
    {
        unsigned nr_points = 0;
        bitmap.reset();
        while ( bitmap.move_next() )
        {
            unsigned char ch = bitmap.element();
            if ( ch > '9' )
                ch -= 'A' - '9' - 1;
            ch -= '0';
            if ( ch > 0xF )
                return false;   // parse error: invalid hex digit
            bitmap.element() = ch;
            if ( ch & 8 )
                nr_points++;
            if ( ch & 4 )
                nr_points++;
            if ( ch & 2 )
                nr_points++;
            if ( ch & 1 )
                nr_points++;
        }

        letter( width, nr_points ).swap(gl[enc]);

        unsigned index = 0;
        for ( int r = 0;r < bitmap.nr();r++ )
        {
            for ( int c = 0;c < bitmap.nc();c++ )
            {
                int x = x_offset + c * 4;
                int y = -( y_offset + bitmap.nr() - r - 1 );
                char ch = bitmap[r][c];
                letter& glyph =  gl[enc];
                if ( ch & 8 )
                {
                    glyph[index] = letter::point( x, y );
                    right_overflow_ = std::max( right_overflow_, x - width );
                    index++;
                }
                if ( ch & 4 )
                {
                    glyph[index] = letter::point( x + 1, y );
                    right_overflow_ = std::max( right_overflow_, x + 1 - width );
                    index++;
                }
                if ( ch & 2 )
                {
                    glyph[index] = letter::point( x + 2, y );
                    right_overflow_ = std::max( right_overflow_, x + 2 - width );
                    index++;
                }
                if ( ch & 1 )
                {
                    glyph[index] = letter::point( x + 3, y );
                    right_overflow_ = std::max( right_overflow_, x + 3 - width );
                    index++;
                }
            }
        }
        return true;
    }

// ----------------------------------------------------------------------------------------

    const shared_ptr_thread_safe<font> get_native_font (
    )
    {
        return nativefont::native_font::get_font();
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_FONTs_CPP_


dlib C++ Library - fonts.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net), and Nils Labugt, Keita Mochizuki
// License: Boost Software License   See LICENSE.txt for the full license.

#ifndef DLIB_FONTs_
#define DLIB_FONTs_

#include "fonts_abstract.h"
#include "../gui_core.h"
#include <string>
#include "../algs.h"
#include "../serialize.h"
#include "../unicode.h"
#include "../array.h"
#include "../array2d.h"
#include "../threads.h"
#include "../smart_pointers_thread_safe.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class letter
    {
        /*!
            INITIAL VALUE
                - defined by constructor

            CONVENTION
                - if (points != 0) then
                    - points == an array of count point structs
                - w == width()
                - count == num_of_points()
        !*/
    public:
        struct point
        {
            point (){}

            point (
                signed char x_,
                signed char y_
            ) :
                x(x_),
                y(y_)
            {}

            signed char x;
            signed char y;
        };

        letter (
        ) :
            points(0),
            w(0),
            count(0)
        {}

        letter (
            unsigned short width_,
            unsigned short point_count
        ) :
            points(new point[point_count]),
            w(width_),
            count(point_count)
        {}

        ~letter(
        )
        {
            if (points)
                delete [] points;
        }

        unsigned short width (
        ) const { return w; }

        unsigned short num_of_points (
        ) const { return count;}

        point& operator[] (
            unsigned short i
        )
        {
            DLIB_ASSERT (i < num_of_points(),
                    "\tvoid letter::operator[]()"
                    << "\n\ti:               " << i
                    << "\n\tnum_of_points(): " << num_of_points() );
            return points[i];
        }

        const point& operator[] (
            unsigned short i
        ) const
        {
            DLIB_ASSERT (i < num_of_points(),
                    "\tvoid letter::operator[]()"
                    << "\n\ti:               " << i
                    << "\n\tnum_of_points(): " << num_of_points() );
            return points[i];
        }

        friend void serialize (
            const letter& item,
            std::ostream& out
        );

        friend void deserialize (
            letter& item,
            std::istream& in
        );

        void swap (
            letter& item
        )
        {
            exchange(points, item.points);
            exchange(w, item.w);
            exchange(count, item.count);
        }

    private:
        // restricted functions
        letter(letter&);        // copy constructor
        letter& operator=(letter&);    // assignment operator

        point* points;
        unsigned short w;
        unsigned short count;
    };

    inline void swap (
        letter& a,
        letter& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------

    class font
    {
    public:
        virtual ~font() {}

        virtual bool has_character (
            unichar ch
        )const=0;
        bool has_character(char ch) const    { return this->has_character(zero_extend_cast<unichar>(ch)); }
        bool has_character(wchar_t ch) const { return this->has_character(zero_extend_cast<unichar>(ch)); }

        const letter& operator[] (char ch)   const { return (*this)[zero_extend_cast<unichar>(ch)]; };
        const letter& operator[] (wchar_t ch)const { return (*this)[zero_extend_cast<unichar>(ch)]; };

        virtual const letter& operator[] (
            unichar ch
        )const=0;

        virtual unsigned long height (
        ) const = 0;

        virtual unsigned long ascender (
        ) const = 0;

        virtual unsigned long left_overflow (
        ) const = 0;

        virtual unsigned long right_overflow (
        ) const = 0;

    // ------------------------------------------------------------------------------------

        template <typename T, typename traits, typename alloc>
        void compute_size (
            const std::basic_string<T,traits,alloc>& str,
            unsigned long& width,
            unsigned long& height,
            typename std::basic_string<T,traits,alloc>::size_type first = 0,
            typename std::basic_string<T,traits,alloc>::size_type last = (std::basic_string<T,traits,alloc>::npos)
        ) const
        {
            typedef std::basic_string<T,traits,alloc> string;
            DLIB_ASSERT ( (last == string::npos) || (first <= last && last < str.size())  ,
                          "\tvoid font::compute_size()"
                          << "\n\tlast == string::npos: " << ((last == string::npos)?"true":"false")
                          << "\n\tfirst: " << (unsigned long)first
                          << "\n\tlast:  " << (unsigned long)last
                          << "\n\tstr.size():  " << (unsigned long)str.size() );

            unsigned long line_width = 0;
            unsigned long newlines = 0;
            width = 0;
            height = 0;

            if (str.size())
            {
                if (last == string::npos)
                    last = str.size()-1;
                const font& f = *this;

                for (typename string::size_type i = first; i <= last; ++i)
                {
                    // ignore '\r' characters
                    if (str[i] == '\r')
                        continue;

                    if (str[i] == '\n')
                    {
                        ++newlines;
                        width = std::max(width,line_width);
                        line_width = 0;
                    }
                    else
                    {
                        if (is_combining_char(str[i]) == false)
                            line_width += f[str[i]].width();
                    }
                }
                width = std::max(width,line_width);

                height = (newlines+1)*f.height();
                width += f.left_overflow() + f.right_overflow();
            }
        }

    // ------------------------------------------------------------------------------------

        template <typename T, typename traits, typename alloc, typename pixel_type>
        void draw_string (
            const canvas& c,
            const rectangle& rect,
            const std::basic_string<T,traits,alloc>& str,
            const pixel_type& color,
            typename std::basic_string<T,traits,alloc>::size_type first = 0,
            typename std::basic_string<T,traits,alloc>::size_type last = (std::basic_string<T,traits,alloc>::npos),
            const rectangle area_ = rectangle(std::numeric_limits<long>::min(), std::numeric_limits<long>::min(),
                                            std::numeric_limits<long>::max(), std::numeric_limits<long>::max())
        ) const
        {
            typedef std::basic_string<T,traits,alloc> string;
            DLIB_ASSERT ( (last == string::npos) || (first <= last && last < str.size())  ,
                          "\tvoid font::draw_string()"
                          << "\n\tlast == string::npos: " << ((last == string::npos)?"true":"false")
                          << "\n\tfirst: " << (unsigned long)first
                          << "\n\tlast:  " << (unsigned long)last
                          << "\n\tstr.size():  " << (unsigned long)str.size() );

            rectangle area = rect.intersect(c).intersect(area_);
            if (area.is_empty() || str.size() == 0)
                return;

            if (last == string::npos)
                last = str.size()-1;

            const font& f = *this;

            long y_offset = rect.top() + f.ascender() - 1;

            long pos = rect.left()+f.left_overflow();
            for (typename string::size_type i = first; i <= last; ++i)
            {
                // ignore the '\r' character
                if (str[i] == '\r')
                    continue;

                // A combining character should be applied to the previous character, and we
                // therefore make one step back. If a combining comes right after a newline,
                // then there must be some kind of error in the string, and we don't combine.
                if(is_combining_char(str[i]) &&
                   pos > rect.left() + static_cast<long>(f.left_overflow()))
                {
                    pos -= f[str[i]].width();
                }

                if (str[i] == '\n')
                {
                    y_offset += f.height();
                    pos = rect.left()+f.left_overflow();
                    continue;
                }

                // only look at letters in the intersection area
                if (area.bottom() + static_cast<long>(f.height()) < y_offset)
                {
                    // the string is now below our rectangle so we are done
                    break;
                }
                else if (area.left() > pos - static_cast<long>(f.left_overflow()) &&
                    pos + static_cast<long>(f[str[i]].width() + f.right_overflow()) < area.left() )
                {
                    pos += f[str[i]].width();
                    continue;
                }
                else if (area.right() + static_cast<long>(f.right_overflow()) < pos)
                {
                    // keep looking because there might be a '\n' in the string that
                    // will wrap us around and put us back into our rectangle.
                    continue;
                }

                // at this point in the loop we know that f[str[i]] overlaps
                // horizontally with the intersection rectangle area.

                const letter& l = f[str[i]];
                for (unsigned short i = 0; i < l.num_of_points(); ++i)
                {
                    const long x = l[i].x + pos;
                    const long y = l[i].y + y_offset;
                    // draw each pixel of the letter if it is inside the intersection
                    // rectangle
                    if (area.contains(x,y))
                    {
                        assign_pixel(c[y-c.top()][x-c.left()], color);
                    }
                }

                pos += l.width();
            }
        }
        template <typename T, typename traits, typename alloc>
        void draw_string (
            const canvas& c,
            const rectangle& rect,
            const std::basic_string<T,traits,alloc>& str
        ) const
        {
            draw_string(c,rect, str, 0, 0, (std::basic_string<T,traits,alloc>::npos),
                        rectangle(std::numeric_limits<long>::min(), std::numeric_limits<long>::min(),
                                  std::numeric_limits<long>::max(), std::numeric_limits<long>::max()));
        }

    // ------------------------------------------------------------------------------------

        template <typename T, typename traits, typename alloc>
        const rectangle compute_cursor_rect (
            const rectangle& rect,
            const std::basic_string<T,traits,alloc>& str,
            unsigned long index,
            typename std::basic_string<T,traits,alloc>::size_type first = 0,
            typename std::basic_string<T,traits,alloc>::size_type last = (std::basic_string<T,traits,alloc>::npos)
        ) const
        {
            typedef std::basic_string<T,traits,alloc> string;
            DLIB_ASSERT ( (last == string::npos) || (first <= last && last < str.size())  ,
                          "\trectangle font::compute_cursor_rect()"
                          << "\n\tlast == string::npos: " << ((last == string::npos)?"true":"false")
                          << "\n\tfirst: " << (unsigned long)first
                          << "\n\tlast:  " << (unsigned long)last
                          << "\n\tindex:  " << index
                          << "\n\tstr.size():  " << (unsigned long)str.size() );

            const font& f = *this;

            if (last == string::npos)
                last = str.size()-1;

            long x = f.left_overflow();
            long y = 0;
            int count = 0;

            if (str.size() != 0)
            {
                for (typename string::size_type i = first; i <= last && i < index; ++i)
                {
                    ++count;
                    if (str[i] == '\n')
                    {
                        x = f.left_overflow();
                        y += f.height();
                        count = 0;
                    }
                    else if (is_combining_char(str[i]) == false &&
                             str[i] != '\r')
                    {
                        x += f[str[i]].width();
                    }
                }
            }

            x += rect.left();
            y += rect.top();

            // if the cursor is at the start of a line then back it up one pixel
            if (count == 0)
                --x;

            return rectangle(x,y,x,y+f.height()-1);
        }

    // ------------------------------------------------------------------------------------

        template <typename T, typename traits, typename alloc>
        unsigned long compute_cursor_pos (
            const rectangle& rect,
            const std::basic_string<T,traits,alloc>& str,
            long x,
            long y,
            typename std::basic_string<T,traits,alloc>::size_type first = 0,
            typename std::basic_string<T,traits,alloc>::size_type last = (std::basic_string<T,traits,alloc>::npos)
        ) const
        {
            typedef std::basic_string<T,traits,alloc> string;
            DLIB_ASSERT ( (last == string::npos) || (first <= last && last < str.size())  ,
                          "\tunsigned long font::compute_cursor_pos()"
                          << "\n\tlast == string::npos: " << ((last == string::npos)?"true":"false")
                          << "\n\tfirst: " << (unsigned long)first
                          << "\n\tlast:  " << (unsigned long)last
                          << "\n\tx:  " << x
                          << "\n\ty:  " << y
                          << "\n\tstr.size():  " << (unsigned long)str.size() );
            const font& f = *this;

            if (str.size() == 0)
                return 0;
            else if (first >= str.size())
                return static_cast<unsigned long>(str.size());

            y -= rect.top();
            x -= rect.left();
            if (y < 0)
                y = 0;
            if (x < 0)
                x = 0;

            if (last == string::npos)
                last = str.size()-1;

            // first figure out what line we are on
            typename string::size_type pos = first;
            long line = 0;
            while (static_cast<unsigned long>(y) >= f.height())
            {
                ++line;
                y -= f.height();
            }

            // find the start of the given line
            for (typename string::size_type i = first; i <= last && line != 0; ++i)
            {
                if (str[i] == '\n')
                {
                    --line;
                    pos = i + 1;
                }
            }

            // now str[pos] == the first character of the start of the line
            // that contains the cursor.
            const typename string::size_type start_of_line = pos;

            long cur_x = f.left_overflow();
            // set the current cursor position to where the mouse clicked
            while (pos <= last)
            {
                if (x <= cur_x || str[pos] == '\n')
                    break;

                if (is_combining_char(str[pos]) == false &&
                    str[pos] != '\r')
                {
                    cur_x += f[str[pos]].width();
                }
                ++pos;
            }

            if (x <= cur_x)
            {
                if (pos != start_of_line)
                {
                    // we might actually be closer to the previous character
                    // so check for that and if so then jump us back one.
                    const long width = f[str[pos-1]].width();
                    if (x < cur_x - width/2)
                        --pos;
                }
            }
            return static_cast<unsigned long>(pos);
        }

    };

// ----------------------------------------------------------------------------------------

    const shared_ptr_thread_safe<font> get_native_font ();

// ----------------------------------------------------------------------------------------

    class default_font : public font
    {
        letter* l;

        default_font(
        );
        default_font(default_font&);        // copy constructor
        default_font& operator=(default_font&);    // assignment operator

    public:
        static const shared_ptr_thread_safe<font>& get_font (
        )
        {
            static mutex m;
            static shared_ptr_thread_safe<font> f;
            auto_mutex M(m);
            if (f.get() == 0)
                f.reset(new default_font);

            return f;
        }

        ~default_font(
        )
        {
            delete [] l;
        }

        unsigned long height (
        ) const { return 16; }

        unsigned long ascender (
        ) const { return 12; }

        unsigned long left_overflow (
        ) const { return 1; }

        unsigned long right_overflow (
        ) const { return 2; }

        bool has_character (
            unichar ch
        )const
        {
            if (ch < 256 && (l[ch].width() != 0 || l[ch].num_of_points() != 0))
                return true;
            else
                return false;
        }

        const letter& operator[] (
            unichar ch
        ) const
        {
            if(ch < 256)
                return l[ch];
            return l[0]; // just return one of the empty characters in this case
        }
    };

// ----------------------------------------------------------------------------------------

    class bdf_font : public font
    {

    public:
        bdf_font( long default_char_ = -1 );

        long read_bdf_file( std::istream& in, unichar max_enc, unichar min_enc = 0 );
        unsigned long height() const
        {
            return fbb.height();
        }
        unsigned long ascender() const
        {
            return std::max( 0L, 1 - fbb.top() );
        }
        unsigned long left_overflow() const
        {
            return std::max( 0L, -fbb.left() );
        }
        unsigned long right_overflow() const
        {
            return right_overflow_;
        }
        const letter& operator[] ( unichar uch ) const
        {
            if ( !has_character(uch) )
            {
                return gl[default_char];
            }
            return gl[uch];
        }

        bool has_character (
            unichar ch
        )const
        {
            if (ch < gl.size() && (gl[ch].width() != 0 || gl[ch].num_of_points() != 0))
                return true;
            else
                return false;
        }

        void adjust_metrics();
    private:

        bool bitmap_to_letter( array2d<char>& bitmap, unichar enc, unsigned long width, int x_offset, int y_offset );

        array<letter> gl;
        unichar default_char; // if (is_intialized == true), then this MUST be an actual glyph
        bool is_initialized;
        rectangle fbb;
        unsigned long right_overflow_;

        unsigned global_width;
        bool has_global_width;
        long specified_default_char;

        bdf_font( bdf_font& );      // copy constructor
        bdf_font& operator=( bdf_font& );  // assignment operator

    };

// ----------------------------------------------------------------------------------------

}

#ifdef NO_MAKEFILE
#include "fonts.cpp"
#endif

#endif // DLIB_FONTs_


dlib C++ Library - nativefont.h

// Copyright (C) 2006 Keita Mochizuki
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_IGG_FONT_RENDERER_H_
#define DLIB_IGG_FONT_RENDERER_H_
#include "../platform.h"

#include "../gui_widgets.h"
#include "../unicode.h"
#include "../smart_pointers_thread_safe.h"
#include "../uintn.h"

#include <map>

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <locale.h>

#if defined(WIN32)
#include <windows.h>
#include <mbstring.h>
#elif defined(POSIX)
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xlocale.h>
#endif

namespace nativefont
{
// ----------------------------------------------------------------------------------------

    namespace font_renderer
    {
        typedef dlib::uint8 byte;

#ifdef WIN32
        template <typename T> struct input2native_trait{
        };
        template <> struct input2native_trait<char>{
            typedef char type_t;
        };
        template <> struct input2native_trait<wchar_t>{
            typedef wchar_t type_t;
        };
        template <> struct input2native_trait<dlib::unichar>{
            typedef wchar_t type_t;
        };
#endif
        // T : N : sizeof_source_type
        template <int N> struct size2inner_trait{
        };
        template <> struct size2inner_trait<1>{
            typedef char type_t;
        };
        template <> struct size2inner_trait<2>{
            typedef dlib::uint16 type_t;
        };
        template <> struct size2inner_trait<4>{
            typedef dlib::unichar type_t;
        };

// ----------------------------------------------------------------------------------------

        template <int N> struct create_helper{ };
        template <> struct create_helper<1>{
            typedef char type_t;
            type_t *istr;
            int len;
            create_helper(char *str){
                len = (int)strlen(str);
                istr = str;
            }
            ~create_helper(){}
        };
        template <> struct create_helper<2>{
            typedef wchar_t type_t;
            type_t *istr;
            bool allocated;
            int len;
            create_helper(wchar_t *str){
                allocated = false;
                len = (int)wcslen(str);
                istr = str;
            }
            create_helper(dlib::unichar *str){
                allocated = true;
                len = 0;
                int unicount = 0;
                dlib::unichar *p = str;
                while(*p){
                    if (*p > 0xffff){
                        len += 2;
                    }else{
                        len++;
                    }
                    unicount++;
                    p++;
                }
                istr = new wchar_t[len+1];
                for (int i = 0, wi = 0; i < unicount; ++i){
                    dlib::unichar high, low;
                    if (str[i] > 0xffff){
                        dlib::unichar_to_surrogate_pair(str[i], high, low);
                        istr[wi] = (wchar_t)high, istr[wi+1] = (wchar_t)low;
                        wi += 2;
                    }else{
                        istr[wi] = (wchar_t)str[i];
                        wi += 1;
                    }
                }
                istr[len] = L'\0';
            }

            ~create_helper(){
                if (allocated) delete[] istr;
            }
        };
        template <> struct create_helper<4>{
            typedef wchar_t type_t;
            type_t *istr;
            int len;
            create_helper(dlib::unichar *str){
                len = (int)wcslen((wchar_t *)str);
                istr = (type_t *)str;
            }
            ~create_helper(){}
        };

// ----------------------------------------------------------------------------------------

        class font_renderer{
        public:

            struct rgb_type{
                byte r, g, b;
                rgb_type() : r(0), g(0), b(0){};
                rgb_type(byte r_, byte g_, byte b_) : r(r_), g(g_), b(b_){};
            };
        private:

            byte *image;
            int width, height;
            void destroy(){
                width = height = 0;
                delete image;
                image = 0;
            }
            struct vals_internal{
                int width, height;
#ifdef WIN32
                COLORREF rgb2RGB(rgb_type &rgb){
                    return RGB(rgb.r, rgb.g, rgb.b);
                }
                HBITMAP hBmp, hBmpOld;
                HDC hDCBmp;
                BYTE *pixelint;
                HFONT hFont, hFontOld;
                HBRUSH hBrush;
                int pix_width_prev, pix_height_prev;
                bool first;
                int ascender, descender;
                int height_prev;
                char attribute_prev;

                template <typename T> void create(T *str, int height_want, bool italic, bool bold, bool fixed, rgb_type &background, rgb_type &foreground){
                    struct inner{
                        inline static BOOL GetTextExtentPoint32(HDC hDC, LPCSTR str, int len, LPSIZE lpsize){
                            return ::GetTextExtentPoint32A(hDC, str, len, lpsize);
                        }
                        inline static BOOL GetTextExtentPoint32(HDC hDC, LPCWSTR str, int len, LPSIZE lpsize){
                            return ::GetTextExtentPoint32W(hDC, str, len, lpsize);
                        }
                        inline static BOOL TextOut(HDC hDC, int nxstart, int nystart, LPCSTR str, int cbstr){
                            return ::TextOutA(hDC, nxstart, nystart, str, cbstr);
                        }
                        inline static BOOL TextOut(HDC hDC, int nxstart, int nystart, LPCWSTR str, int cbstr){
                            return ::TextOutW(hDC, nxstart, nystart, str, cbstr);
                        }
                    };

                    create_helper<sizeof(typename input2native_trait<T>::type_t)> ch(str);

                    if (hDCBmp == NULL){
                        HWND hWnd = GetDesktopWindow();
                        HDC hDC = GetDC(hWnd);
                        hDCBmp = CreateCompatibleDC(hDC);
                        ReleaseDC(hWnd, hDC);
                    }
                    SetTextColor(hDCBmp, rgb2RGB(foreground));
                    SetBkColor(hDCBmp, rgb2RGB(background));

                    char attribute = (italic ? 1 : 0) | (bold ? 2 : 0) | (fixed ? 4 : 0);
                    if (!hFont || height_prev != height || attribute != attribute_prev){
                        attribute_prev = attribute;
                        height_prev = height_want;
                        if (hFont){
                            SelectObject(hDCBmp, hFontOld);
                            DeleteObject(hFont);
                        }
                        hFont = CreateFont(height_want, 0, 0, 0, bold ? FW_BOLD : FW_DONTCARE, italic ? TRUE : FALSE,
                                           FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
                                           fixed ? (FIXED_PITCH | FF_DONTCARE) : (VARIABLE_PITCH | FF_DONTCARE), NULL);
                        hFontOld = (HFONT)SelectObject(hDCBmp, hFont);
                    }

                    {
                        SIZE sz;
                        inner::GetTextExtentPoint32(hDCBmp, ch.istr, ch.len, &sz);
                        width = ((sz.cx + 3) / 4) * 4;
                        height = sz.cy;
                    }

                    if (pix_width_prev < width || pix_height_prev < height){
                        if (hBmp){
                            SelectObject(hDCBmp, hBmpOld);
                            DeleteObject(hBmp);
                        }
                        pix_width_prev = width * 2;
                        pix_height_prev = height * 2;
                        BITMAPINFO bi;
                        ZeroMemory(&bi, sizeof(bi));
                        bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
                        bi.bmiHeader.biBitCount = 24;
                        bi.bmiHeader.biPlanes = 1;
                        bi.bmiHeader.biWidth = pix_width_prev;
                        bi.bmiHeader.biHeight = -pix_height_prev;
                        hBmp = CreateDIBSection(NULL, &bi, DIB_RGB_COLORS, (void **)&pixelint, NULL, 0);
                        hBmpOld = (HBITMAP)SelectObject(hDCBmp, hBmp);
                    }

                    {
                        HBRUSH hBrush = CreateSolidBrush(rgb2RGB(background));
                        RECT rc;
                        rc.left = rc.top = 0;
                        rc.right = pix_width_prev;
                        rc.bottom = pix_height_prev;
                        FillRect(hDCBmp, &rc, hBrush);
                    }

                    inner::TextOut(hDCBmp, 0, 0, ch.istr, ch.len);
                    TEXTMETRICW tm;
                    GetTextMetricsW(hDCBmp,&tm);
                    ascender = tm.tmAscent;
                    descender = tm.tmDescent;
                }

                template <typename T> vals_internal(T *str, int height_want, bool italic = false,
                    bool bold = false, bool fixed = false, rgb_type background = rgb_type(), rgb_type foreground = rgb_type()){
                    first = true;
                    hFont = NULL;
                    hDCBmp = 0;
                    hBmpOld = 0;
                    hBmp = 0;
                    hDCBmp = 0;
                    pixelint = 0;
                    pix_width_prev = pix_height_prev = 0;
                    height_prev = -1;
                    attribute_prev = 0;
                    create(str, height_want, italic, bold, fixed, background, foreground);
                    first = false;
                }

                inline int get_ascender(){
                    return ascender;
                }

                inline int get_descender(){
                    return descender;
                }

                inline void get_pixel(int x, int y, byte &r, byte &g, byte &b){
                    byte *p = pixelint + (y * pix_width_prev + x) * 3;
                    r = *(p+2), g = *(p+1), b = *p;
                }

                void destroy(){
                    SelectObject(hDCBmp, hBmpOld);
                    DeleteObject(hBmp);
                    SelectObject(hDCBmp, hFontOld);
                    DeleteObject(hFont);
                    DeleteDC(hDCBmp);
                    hFont = NULL;
                    hDCBmp = 0;
                    hBmpOld = 0;
                    hBmp = 0;
                    hDCBmp = 0;
                    pixelint = 0;
                }
                ~vals_internal(){
                    destroy();
                }
#elif defined(POSIX)
                XImage *ximg;
                Display *d;
                GC gc;
                XFontSet fs;
                Pixmap pix;
                Colormap cmap;
                int ascender, descender;
                int pix_width_prev, pix_height_prev;
                char fontset_prev[256];
                unsigned long rgb2color(rgb_type col, Display *d, Colormap &cmap){
                    XColor xcol;
                    xcol.red = col.r * 257;
                    xcol.green = col.g * 257;
                    xcol.blue = col.b * 257;
                    XAllocColor(d, cmap, &xcol);
                    return xcol.pixel;
                }
                template <typename T> void create(T *str, int height_want, bool italic, bool bold, bool fixed, rgb_type background, rgb_type foreground){
                    struct inner{
                        inline static int XTextExtents (XFontSet fs, char *str, int len, XRectangle *ink, XRectangle *logical){
                            return XmbTextExtents(fs, str, len, ink, logical);
                        }
                        inline static int XTextExtents (XFontSet fs, wchar_t *str, int len, XRectangle *ink, XRectangle *logical){
                            return XwcTextExtents(fs, str, len, ink, logical);
                        }
                        inline static void XDrawString(Display *d, Window w, XFontSet fs, GC gc, int x, int y, char *str, int num_bytes){
                            XmbDrawString(d, w, fs, gc, x, y, str, num_bytes);
                        }
                        inline static void XDrawString(Display *d, Window w, XFontSet fs, GC gc, int x, int y, wchar_t *str, int num_bytes){
                            XwcDrawString(d, w, fs, gc, x, y, str, num_bytes);
                        }
                    };
                    create_helper<sizeof(T)> ch((typename size2inner_trait<sizeof(T)>::type_t *)str);
                    setlocale(LC_CTYPE, "");
                    if (d == NULL){
                        d = XOpenDisplay(NULL);
                        if (d == 0)
                        {
                            d = XOpenDisplay(":0.0");
                            if (d == 0)
                            {
                                throw dlib::gui_error("Unable to connect to the X display.");
                            }
                        }

                        cmap = DefaultColormap(d, DefaultScreen(d));
                    }
                    char fontset[256];
                    {
                        char *p = fontset;
                        p += sprintf(fontset, "-*-*-%s-%c-normal--%d-*-*-*-%c",
                                     bold ? "bold" : "medium", italic ? 'i' : 'r', height_want, fixed ? 'c' : 'p');
                        if (fixed){
                            sprintf(p, ",-*-*-%s-%c-normal--%d-*-*-*-m",
                                    bold ? "bold" : "medium", italic ? 'i' : 'r', height_want);
                        }
                    }
                    bool equal_font;
                    if (strcmp(fontset, fontset_prev) == 0){
                        equal_font = true;
                    }else{
                        equal_font = false;
                        strcpy(fontset_prev, fontset);
                    }

                    char **mlist;
                    int mcount;
                    char *def_str;
                    if (!equal_font){
                        if (fs){
                            XFreeFontSet(d, fs);
                        }
                        fs = XCreateFontSet(d, fontset, &mlist, &mcount, &def_str);
                        if (fs == NULL)
                           throw dlib::gui_error("gui_error: XCreateFontSet() failure");

                        XFontSetExtents *extent;
                        extent = XExtentsOfFontSet(fs);
                        ascender = -extent->max_logical_extent.y;
                        descender = extent->max_logical_extent.height - ascender;
                        XFreeStringList(mlist);
                    }
                    XRectangle ink, logical;
                    inner::XTextExtents (fs, ch.istr, ch.len, &ink, &logical);
                    width = logical.width;
                    height = height_want;

                    if (pix == None || pix_width_prev < width || pix_height_prev < height){
                        if (pix != None){
                            XFreeGC(d, gc);
                            XFreePixmap(d, pix);
                        }
                        pix_width_prev = width * 2;
                        pix_height_prev = height * 2;
                        pix = XCreatePixmap(d, DefaultRootWindow(d), pix_width_prev, pix_height_prev, XDefaultDepth(d, DefaultScreen(d)));
                        gc = XCreateGC(d, pix, 0, NULL);
                    }

                    unsigned long backcolor = rgb2color(background, d, cmap);
                    XSetForeground(d, gc, backcolor);
                    XSetBackground(d, gc, backcolor);
                    XFillRectangle(d, pix, gc, 0, 0, width, height);
                    XSetForeground(d, gc, rgb2color(foreground, d, cmap));
                    inner::XDrawString(d, pix, fs, gc, 0, ascender, ch.istr, ch.len);

                    if (ximg) XDestroyImage(ximg);
                    ximg = XGetImage(d, pix, 0, 0, width, height, AllPlanes, ZPixmap );
                }

                template <typename T> vals_internal(T *str, int height_want, bool italic = false,
                    bool bold = false, bool fixed = false, rgb_type background = rgb_type(), rgb_type foreground = rgb_type()){
                    fontset_prev[0] = '\0';
                    ximg = NULL;
                    d = NULL;
                    pix = None;
                    fs = NULL;
                    ascender = descender = -1;
                    pix_width_prev = pix_height_prev = -1;
                    create(str, height_want, italic, bold, fixed, background, foreground);
                }

                inline int get_ascender(){
                    return ascender;
                }

                inline int get_descender(){
                    return descender;
                }

                std::map<unsigned long,rgb_type> col2rgb;
                rgb_type color2rgb(unsigned long color, Display *d, Colormap &cmap){
                    if (col2rgb.count(color)){
                        return col2rgb[color];
                    }else{
                        XColor xcol;
                        xcol.pixel = color;
                        XQueryColor(d, cmap, &xcol);
                        rgb_type rgb_((byte)(xcol.red/257), (byte)(xcol.green/257), (byte)(xcol.blue/257));
                        col2rgb[color] = rgb_;
                        return rgb_;
                    }
                }
                inline void get_pixel(int x, int y, byte &r, byte &g, byte &b){
                    rgb_type c = color2rgb(XGetPixel(ximg,x,y), d, cmap);
                    r = c.r, g = c.g, b = c.b;
                }

                ~vals_internal(){
                    XDestroyImage(ximg);

                    XFreeGC(d, gc);
                    XFreeFontSet(d, fs);
                    XFreePixmap(d, pix);
                    XCloseDisplay(d);
                }
#endif
            };

            struct image_size_setter{
                void operator()(int&, int&){
                }
            };

            int ascender, descender;
            vals_internal *vi;
        public:
            font_renderer() : image(0), width(0), height(0){
                ascender = descender = 0;
                vi = NULL;
            }

            template<typename T> font_renderer(T *str, int height_want, bool italic = false, bool bold = false, bool fixed = false,         rgb_type background = rgb_type(0,0,0), rgb_type foreground = rgb_type(255,255,255)){
                render(str, height_want, italic, bold, fixed, background, foreground);
            }

            template<typename T> void render(T *str, int height_want,
                                             bool italic = false, bool bold = false, bool fixed = false,
                                             rgb_type background = rgb_type(0,0,0), rgb_type foreground = rgb_type(255,255,255)){
                if (vi == NULL){
                    vi = new vals_internal(str, height_want, italic, bold, fixed, background, foreground);
                }else{
                    vi->create(str, height_want, italic, bold, fixed, background, foreground);
                }
                width = vi->width, height = vi->height;
                image = new byte[width * height * 3];
                ascender = vi->get_ascender();
                descender = vi->get_descender();

                int h = height, w = width;
                for (int j = 0, i3 = 0; j < h; ++j){
                    for (int i = 0; i < w; ++i, i3 += 3){
                        vi->get_pixel(i, j, image[i3], image[i3+1], image[i3+2]);
                    }
                }
            }

            ~font_renderer(){
                if (vi) delete vi;
                destroy();
            }
            int get_width(){
                return width;
            }
            int get_height(){
                return height;
            }
            inline int get_ascender(){
                return ascender;
            }
            inline int get_descender(){
                return descender;
            }

            const byte *get_image(){
                return image;
            }
        };
    }

// ----------------------------------------------------------------------------------------

    class native_font : public dlib::font
    {
        unsigned long ascender_;
        native_font(){
            setlocale(LC_CTYPE, "");
            ascender_ = 0;
            get_letter((int)('x'));
        }
        typedef std::map<int,dlib::letter *> letters_map_type;
        letters_map_type letters;
        font_renderer::font_renderer fl;
    public:

        virtual ~native_font()
        {
            // delete all the letter objects we have in our letters map
            letters_map_type::iterator i;
            for (i = letters.begin(); i != letters.end(); ++i)
            {
                delete i->second;
            }
        }

        virtual bool has_character (
            dlib::unichar ch
        )const{
            return (*this)[ch].width() > 0;
        }

        static const dlib::shared_ptr_thread_safe<font>& get_font (
        )
        {
            static dlib::shared_ptr_thread_safe<font> f(new native_font);
            return f;
        }

        virtual const dlib::letter& operator[] (dlib::unichar ch) const{
            return (const_cast<native_font *>(this))->get_letter(ch);
        }

        dlib::letter& get_letter (
            dlib::unichar ch
        ){
            if (letters.count(ch)){
                dlib::letter *l = letters.find(ch)->second;
                return *l;
            }

            dlib::unichar c[2];
            c[0] = ch;
            c[1] = 0;

            fl.render(c, height(),false,false,true);
            if (ascender_ == 0){
                ascender_ = fl.get_ascender();
            }
            std::vector<dlib::letter::point> v;
            const font_renderer::byte *bp = fl.get_image();
            for (int j = 0; j < fl.get_height(); ++j){
                for (int i = 0; i < fl.get_width(); ++i, bp += 3){
                    if (*bp){
                        v.push_back(dlib::letter::point(i,j-ascender()+1));
                    }
                }
            }
            dlib::letter *l = new dlib::letter(fl.get_width(), (unsigned long)v.size());

            letters.insert(std::make_pair(ch,l));
            for (int i = 0; i < (int)v.size(); ++i){
                (*l)[i] = v.at(i);
            }
            return *l;
        }

        virtual unsigned long height (
        ) const { return 12; }

        virtual unsigned long ascender (
        ) const { return ascender_; }

        virtual unsigned long left_overflow (
        ) const { return 1; }

        virtual unsigned long right_overflow (
        ) const { return 2; }
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_IGG_FONT_RENDERER_H_


dlib C++ Library - style.cpp

// Copyright (C) 2008  Davis E. King (davis@dlib.net), and Nils Labugt
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_WIDGETs_STYLE_CPP_
#define DLIB_WIDGETs_STYLE_CPP_

#include "style.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // button style stuff
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    void button_style_default::draw_button (
        const canvas& c,
        const rectangle& rect,
        const bool enabled,
        const font& mfont,
        const long ,
        const long ,
        const ustring& name,
        const bool is_depressed
    ) const
    {
        rectangle area = rect.intersect(c);
        if (area.is_empty())
            return;

        fill_rect(c,rect,rgb_pixel(212,208,200));

        unsigned char red, green, blue;
        if (enabled)
        {
            red = 0;
            green = 0;
            blue = 0;
        }
        else
        {
            red = 128;
            green = 128;
            blue = 128;
        }

        // compute the name length if it hasn't already been computed
        if (name_width == 0)
        {
            unsigned long height;
            mfont.compute_size(name,name_width,height);
        }

        // figure out where the name string should appear
        rectangle name_rect;
        const unsigned long width = name_width;
        const unsigned long height = mfont.height();
        name_rect.set_left((rect.right() + rect.left() - width)/2);
        name_rect.set_top((rect.bottom() + rect.top() - height)/2 + 1);
        name_rect.set_right(name_rect.left()+width-1);
        name_rect.set_bottom(name_rect.top()+height);

        if (is_depressed)
        {
            name_rect.set_left(name_rect.left()+1);
            name_rect.set_right(name_rect.right()+1);
            name_rect.set_top(name_rect.top()+1);
            name_rect.set_bottom(name_rect.bottom()+1);

            mfont.draw_string(c,name_rect,name,rgb_pixel(red,green,blue));

            draw_button_down(c,rect);
        }
        else
        {
            mfont.draw_string(c,name_rect,name,rgb_pixel(red,green,blue));

            // now draw the edge of the button
            draw_button_up(c,rect);
        }
    }

// ----------------------------------------------------------------------------------------

    rectangle button_style_default::
    get_min_size (
        const ustring& name,
        const font& mfont
    ) const
    {

        unsigned long width;
        unsigned long height;
        mfont.compute_size(name,width,height);
        name_width = width;

        return rectangle(width+2*padding, height+2*padding);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    void button_style_toolbar1::draw_button (
        const canvas& c,
        const rectangle& rect,
        const bool enabled,
        const font& mfont,
        const long lastx,
        const long lasty,
        const ustring& name,
        const bool is_depressed
    ) const
    {
        rectangle area = rect.intersect(c);
        if (area.is_empty())
            return;

        const long radius = 4;

        unsigned char red, green, blue;
        if (enabled)
        {
            red = 0;
            green = 0;
            blue = 0;

            long d = 0;
            if (rect.contains(lastx,lasty))
                d = -70;

            if (is_depressed)
                d = 20;

            if (d != 0)
            {
                rectangle temp(rect);
                temp.left()--; temp.top()--; temp.right()++; temp.bottom()++;
                draw_rounded_rectangle(c, temp, radius, rgb_alpha_pixel(255,255,0,120));
                temp.left()--; temp.top()--; temp.right()++; temp.bottom()++;
                draw_rounded_rectangle(c, temp, radius, rgb_alpha_pixel(255,255,0,40));
            }

            fill_gradient_rounded(c,rect,radius,rgb_alpha_pixel(255, 255, 255,120-d),
                                  rgb_alpha_pixel(255, 255, 255,0));
            draw_rounded_rectangle(c,rect,radius, rgb_alpha_pixel(30,30,30,200));
        }
        else
        {
            red = 128;
            green = 128;
            blue = 128;
            draw_rounded_rectangle(c,rect,radius, rgb_alpha_pixel(red,green,blue,210));
        }

        // compute the name length if it hasn't already been computed
        if (name_width == 0)
        {
            unsigned long height;
            mfont.compute_size(name,name_width,height);
        }

        // figure out where the name string should appear
        rectangle name_rect;
        const unsigned long width = name_width;
        const unsigned long height = mfont.height();
        name_rect.set_left((rect.right() + rect.left() - width)/2);
        name_rect.set_top((rect.bottom() + rect.top() - height)/2 + 1);
        name_rect.set_right(name_rect.left()+width-1);
        name_rect.set_bottom(name_rect.top()+height);

        if (is_depressed)
        {
            name_rect.set_left(name_rect.left()+1);
            name_rect.set_right(name_rect.right()+1);
            name_rect.set_top(name_rect.top()+1);
            name_rect.set_bottom(name_rect.bottom()+1);

            mfont.draw_string(c,name_rect,name,rgb_pixel(red,green,blue));

        }
        else
        {
            mfont.draw_string(c,name_rect,name,rgb_pixel(red,green,blue));
        }
    }

// ----------------------------------------------------------------------------------------

    rectangle button_style_toolbar1::
    get_min_size (
        const ustring& name,
        const font& mfont
    ) const
    {

        unsigned long width;
        unsigned long height;
        mfont.compute_size(name,width,height);
        name_width = width;

        return rectangle(width+2*padding, height+2*padding);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    void button_style_toolbar_icon1::draw_button (
        const canvas& c,
        const rectangle& rect,
        const bool enabled,
        const font& ,
        const long lastx,
        const long lasty,
        const ustring& ,
        const bool is_depressed
    ) const
    {
        rectangle area = rect.intersect(c);
        if (area.is_empty())
            return;

        const long radius = padding;

        if (enabled)
        {
            if (rect.contains(lastx,lasty))
            {
                if (is_depressed)
                {
                    fill_gradient_rounded(c,rect,radius,rgb_alpha_pixel(100,100,200,150),
                                                        rgb_alpha_pixel(50,50,100,100));
                    draw_rounded_rectangle(c,rect,radius, rgb_alpha_pixel(150,150,30,200));
                }
                else
                {
                    fill_gradient_rounded(c,rect,radius,rgb_alpha_pixel(150,150,250,130),
                                                        rgb_alpha_pixel(100,100,150,90));
                    draw_rounded_rectangle(c,rect,radius, rgb_alpha_pixel(150,150,30,200));
                }
            }

            if (is_depressed)
            {
                rectangle img_rect(translate_rect(centered_rect(rect,img_mouseover.nc(),img_mouseover.nr()),1,1));
                point p(img_rect.left(),img_rect.top());
                draw_image(c,p,img_mouseover);
            }
            else
            {
                rectangle img_rect(centered_rect(rect,img_normal.nc(),img_normal.nr()));
                point p(img_rect.left(),img_rect.top());
                if (rect.contains(lastx,lasty))
                    draw_image(c,p,img_mouseover);
                else
                    draw_image(c,p,img_normal);
            }

        }
        else
        {
            rectangle img_rect(centered_rect(rect,img_normal.nc(),img_normal.nr()));
            point p(img_rect.left(),img_rect.top());
            draw_image(c,p,img_disabled);
        }
    }

// ----------------------------------------------------------------------------------------

    rectangle button_style_toolbar_icon1::
    get_min_size (
        const ustring& ,
        const font&
    ) const
    {
        return rectangle(img_normal.nc()+2*padding, img_normal.nr()+2*padding);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    void button_style_arrow::
    draw_button (
        const canvas& c,
        const rectangle& rect,
        const bool enabled,
        const font& ,
        const long ,
        const long ,
        const ustring& ,
        const bool is_depressed
    ) const
    {
        rectangle area = rect.intersect(c);
        if (area.is_empty())
            return;

        fill_rect(c,rect,rgb_pixel(212,208,200));

        const long height = rect.height();
        const long width = rect.width();

        const long smallest = (width < height) ? width : height;

        const long rows = (smallest+3)/4;
        const long start = rows + rows/2-1;
        long dep;

        long tip_x = 0;
        long tip_y = 0;
        long wy = 0;
        long hy = 0;
        long wx = 0;
        long hx = 0;

        if (is_depressed)
        {
            dep = 0;

            // draw the button's border
            draw_button_down(c,rect);
        }
        else
        {
            dep = -1;

            // draw the button's border
            draw_button_up(c,rect);
        }

        switch (dir)
        {
            case UP:
                tip_x = width/2 + rect.left() + dep;
                tip_y = (height - start)/2 + rect.top() + dep + 1;
                wy = 0;
                hy = 1;
                wx = 1;
                hx = 0;
                break;

            case DOWN:
                tip_x = width/2 + rect.left() + dep;
                tip_y = rect.bottom() - (height - start)/2 + dep;
                wy = 0;
                hy = -1;
                wx = 1;
                hx = 0;
                break;

            case LEFT:
                tip_x = rect.left() + (width - start)/2 + dep + 1;
                tip_y = height/2 + rect.top() + dep;
                wy = 1;
                hy = 0;
                wx = 0;
                hx = 1;
                break;

            case RIGHT:
                tip_x = rect.right() - (width - start)/2 + dep;
                tip_y = height/2 + rect.top() + dep;
                wy = 1;
                hy = 0;
                wx = 0;
                hx = -1;
                break;
        }

        rgb_pixel color;
        if (enabled)
        {
            color.red = 0;
            color.green = 0;
            color.blue = 0;
        }
        else
        {
            color.red = 128;
            color.green = 128;
            color.blue = 128;
        }

        for (long i = 0; i < rows; ++i)
        {
            draw_line(c,point(tip_x + wx*i + hx*i, tip_y + wy*i + hy*i),
                      point(tip_x + wx*i*-1 + hx*i, tip_y + wy*i*-1 + hy*i),
                      color);
        }

    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // toggle button style stuff
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    void toggle_button_style_default::draw_toggle_button (
        const canvas& c,
        const rectangle& rect,
        const bool enabled,
        const font& mfont,
        const long ,
        const long ,
        const ustring& name,
        const bool is_depressed,
        const bool is_checked
    ) const
    {
        rectangle area = rect.intersect(c);
        if (area.is_empty())
            return;

        fill_rect(c,rect,rgb_pixel(212,208,200));

        unsigned char red, green, blue;
        if (enabled)
        {
            red = 0;
            green = 0;
            blue = 0;
        }
        else
        {
            red = 128;
            green = 128;
            blue = 128;
        }

        // compute the name length if it hasn't already been computed
        if (name_width == 0)
        {
            unsigned long height;
            mfont.compute_size(name,name_width,height);
        }

        // figure out where the name string should appear
        rectangle name_rect;
        const unsigned long width = name_width;
        const unsigned long height = mfont.height();
        name_rect.set_left((rect.right() + rect.left() - width)/2);
        name_rect.set_top((rect.bottom() + rect.top() - height)/2 + 1);
        name_rect.set_right(name_rect.left()+width-1);
        name_rect.set_bottom(name_rect.top()+height);

        long d = 0;
        if (is_checked)
            d = 1;

        if (is_depressed)
            d = 2;

        name_rect.set_left(name_rect.left()+d);
        name_rect.set_right(name_rect.right()+d);
        name_rect.set_top(name_rect.top()+d);
        name_rect.set_bottom(name_rect.bottom()+d);

        mfont.draw_string(c,name_rect,name,rgb_pixel(red,green,blue));

        // now draw the edge of the button
        if (is_checked || is_depressed)
            draw_button_down(c,rect);
        else
            draw_button_up(c,rect);
    }

// ----------------------------------------------------------------------------------------

    rectangle toggle_button_style_default::
    get_min_size (
        const ustring& name,
        const font& mfont
    ) const
    {

        unsigned long width;
        unsigned long height;
        mfont.compute_size(name,width,height);
        name_width = width;

        return rectangle(width+2*padding, height+2*padding);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    void toggle_button_style_check_box::draw_toggle_button (
        const canvas& c,
        const rectangle& rect,
        const bool enabled,
        const font& mfont,
        const long ,
        const long ,
        const ustring& name,
        const bool is_depressed,
        const bool is_checked
    ) const
    {
        rectangle area = rect.intersect(c);
        if (area.is_empty())
            return;

        rgb_pixel color;
        if (enabled)
        {
            color.red = 0;
            color.green = 0;
            color.blue = 0;
        }
        else
        {
            color.red = 128;
            color.green = 128;
            color.blue = 128;
        }

        // figure out where the name string should appear
        rectangle name_rect, box_rect;
        unsigned long padding = 0;
        if (mfont.height() < 13)
            padding = (rect.height() - mfont.height())/2;

        name_rect = rect;
        name_rect.set_left(rect.left() + 17-1);
        name_rect.set_top(rect.top() + padding);
        name_rect.set_bottom(rect.bottom() - padding);

        box_rect = rect;
        box_rect.set_right(rect.left() + 12);
        box_rect.set_bottom(rect.top() + 12);

        mfont.draw_string(c,name_rect,name,color);

        if (enabled && is_depressed == false)
            fill_rect(c, box_rect,rgb_pixel(255,255,255));
        else
            fill_rect(c, box_rect,rgb_pixel(212,208,200));

        draw_sunken_rectangle(c, box_rect);

        if (is_checked)
        {
            const long x = box_rect.left();
            const long y = box_rect.top();
            draw_line(c,point(3+x,5+y),point(6+x,8+y),color);
            draw_line(c,point(3+x,6+y),point(5+x,8+y),color);
            draw_line(c,point(3+x,7+y),point(5+x,9+y),color);
            draw_line(c,point(6+x,6+y),point(9+x,3+y),color);
            draw_line(c,point(6+x,7+y),point(9+x,4+y),color);
            draw_line(c,point(6+x,8+y),point(9+x,5+y),color);
        }
    }

// ----------------------------------------------------------------------------------------

    rectangle toggle_button_style_check_box::
    get_min_size (
        const ustring& name,
        const font& mfont
    ) const
    {
        unsigned long width;
        unsigned long height;
        mfont.compute_size(name,width,height);

        if (height < 13)
            height = 13;

        return rectangle(width + 17 -1, height -1);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    void toggle_button_style_radio_button::draw_toggle_button (
        const canvas& c,
        const rectangle& rect,
        const bool enabled,
        const font& mfont,
        const long ,
        const long ,
        const ustring& name,
        const bool is_depressed,
        const bool is_checked
    ) const
    {
        rectangle area = rect.intersect(c);
        if (area.is_empty())
            return;

        rgb_pixel color;

        // figure out where the name string should appear
        rectangle name_rect, box_rect;
        unsigned long padding = 0;
        if (mfont.height() < 13)
            padding = (rect.height() - mfont.height())/2;

        name_rect = rect;
        name_rect.set_left(rect.left() + 17-1);
        name_rect.set_top(rect.top() + padding);
        name_rect.set_bottom(rect.bottom() - padding);

        box_rect = rect;
        box_rect.set_right(rect.left() + 12);
        box_rect.set_bottom(rect.top() + 12);

        const long x = box_rect.left();
        const long y = box_rect.top();

        if (enabled && is_depressed == false)
            draw_solid_circle(c,point(rect.left()+5,rect.top()+5),4.5,rgb_pixel(255,255,255));
        else
            draw_solid_circle(c,point(rect.left()+5,rect.top()+5),4.5,rgb_pixel(212,208,200));

        color = rgb_pixel(128,128,128);
        draw_line(c,point(0+x,4+y),point(0+x,7+y),color);
        draw_line(c,point(1+x,2+y),point(1+x,9+y),color);
        draw_line(c,point(2+x,1+y),point(9+x,1+y),color);
        draw_line(c,point(4+x,0+y),point(7+x,0+y),color);

        color = rgb_pixel(255,255,255);
        draw_line(c,point(4+x,11+y),point(7+x,11+y),color);
        draw_line(c,point(2+x,10+y),point(9+x,10+y),color);
        draw_line(c,point(10+x,2+y),point(10+x,9+y),color);
        draw_line(c,point(11+x,4+y),point(11+x,7+y),color);

        color = rgb_pixel(64,64,64);
        draw_line(c,point(1+x,4+y),point(1+x,7+y),color);
        draw_line(c,point(4+x,1+y),point(7+x,1+y),color);
        draw_pixel(c,point(2+x,3+y),color);
        draw_pixel(c,point(3+x,2+y),color);
        draw_pixel(c,point(2+x,2+y),color);
        draw_pixel(c,point(2+x,8+y),color);
        draw_pixel(c,point(8+x,2+y),color);
        draw_pixel(c,point(9+x,2+y),color);

        color = rgb_pixel(212,208,200);
        draw_line(c,point(4+x,10+y),point(7+x,10+y),color);
        draw_line(c,point(10+x,4+y),point(10+x,7+y),color);
        draw_pixel(c,point(3+x,9+y),color);
        draw_pixel(c,point(9+x,3+y),color);

        if (enabled)
        {
            color.red = 0;
            color.green = 0;
            color.blue = 0;
        }
        else
        {
            color.red = 128;
            color.green = 128;
            color.blue = 128;
        }

        mfont.draw_string(c,name_rect,name,color);

        if (is_checked)
        {
            draw_line(c,point(5+x,4+y),point(6+x,4+y),color);
            draw_line(c,point(4+x,5+y),point(7+x,5+y),color);
            draw_line(c,point(4+x,6+y),point(7+x,6+y),color);
            draw_line(c,point(5+x,7+y),point(6+x,7+y),color);
        }

    }

// ----------------------------------------------------------------------------------------

    rectangle toggle_button_style_radio_button::
    get_min_size (
        const ustring& name,
        const font& mfont
    ) const
    {
        unsigned long width;
        unsigned long height;
        mfont.compute_size(name,width,height);

        if (height < 13)
            height = 13;

        return rectangle(width + 17 -1, height -1);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // scroll bar style stuff
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    long scroll_bar_style_default::
    get_slider_length (
        long total_length,
        long max_pos
    ) const
    {
        // if the length is too small then we have to smash up the arrow buttons
        // and hide the slider.
        if (total_length <= get_width()*2)
        {
            return 0;
        }
        else
        {
            double range = total_length - get_button_length(total_length, max_pos)*2;

            double scale_factor = 30.0/(max_pos + 30.0);

            if (scale_factor < 0.1)
                scale_factor = 0.1;

            double fraction = range/(max_pos + range)*scale_factor;
            double result = fraction * range;
            long res = static_cast<long>(result);
            if (res < 8)
                res = 8;
            return res;
        }
    }

// ----------------------------------------------------------------------------------------

    long scroll_bar_style_default::
    get_button_length (
        long total_length,
        long
    ) const
    {
        // if the length is too small then we have to smash up the arrow buttons
        // and hide the slider.
        if (total_length <= get_width()*2)
        {
            return total_length/2;
        }
        else
        {
            return get_width();
        }
    }

// ----------------------------------------------------------------------------------------

    void scroll_bar_style_default::
    draw_scroll_bar_background (
        const canvas& c,
        const rectangle& rect,
        const bool ,
        const long ,
        const long ,
        const bool is_depressed
    ) const
    {
        if (is_depressed)
            draw_checkered(c, rect,rgb_pixel(0,0,0),rgb_pixel(43,47,55));
        else
            draw_checkered(c, rect,rgb_pixel(255,255,255),rgb_pixel(212,208,200));
    }

// ----------------------------------------------------------------------------------------

    void scroll_bar_style_default::
    draw_scroll_bar_slider (
        const canvas& c,
        const rectangle& rect,
        const bool ,
        const long ,
        const long ,
        const bool
    ) const
    {
        fill_rect(c, rect, rgb_pixel(212,208,200));
        draw_button_up(c, rect);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // text_field styles
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    unsigned long text_field_style_default::
    get_padding (
        const font& mfont
    ) const
    {
        return mfont.height()-mfont.ascender();
    }

// ----------------------------------------------------------------------------------------

    void text_field_style_default::
    draw_text_field (
        const canvas& c,
        const rectangle& rect,
        const rectangle& text_rect,
        const bool enabled,
        const font& mfont,
        const ustring& text,
        const unsigned long cursor_x,
        const unsigned long text_pos,
        const rgb_pixel& text_color,
        const rgb_pixel& bg_color,
        const bool has_focus,
        const bool cursor_visible,
        const long highlight_start,
        const long highlight_end
    ) const
    {
        rectangle area = rect.intersect(c);

        if (enabled)
        {
            // first fill our area with the bg_color
            fill_rect(c, area,bg_color);
        }
        else
        {
            // first fill our area with gray
            fill_rect(c, area,rgb_pixel(212,208,200));
        }

        if (enabled)
            mfont.draw_string(c,text_rect,text,text_color,text_pos);
        else
            mfont.draw_string(c,text_rect,text,rgb_pixel(128,128,128),text_pos);

        // now draw the edge of the text_field
        draw_sunken_rectangle(c, rect);

        if (highlight_start <= highlight_end && enabled)
        {
            rectangle highlight_rect = text_rect;
            unsigned long left_pad = 0, right_pad = mfont.left_overflow();

            long i;
            for (i = text_pos; i <= highlight_end; ++i)
            {
                if (i == highlight_start)
                    left_pad = right_pad;

                right_pad += mfont[text[i]].width();
            }

            highlight_rect.set_left(text_rect.left()+left_pad);
            highlight_rect.set_right(text_rect.left()+right_pad);

            // highlight the highlight_rect area
            highlight_rect = highlight_rect.intersect(c);
            for (long row = highlight_rect.top(); row <= highlight_rect.bottom(); ++row)
            {
                for (long col = highlight_rect.left(); col <= highlight_rect.right(); ++col)
                {
                    canvas::pixel& pixel = c[row-c.top()][col-c.left()];
                    if (pixel.red == 255 && pixel.green == 255 && pixel.blue == 255)
                    {
                        // this is a background (and white) pixel so set it to a dark
                        // blueish color.
                        pixel.red = 10;
                        pixel.green = 36;
                        pixel.blue = 106;
                    }
                    else
                    {
                        // this should be a pixel that is part of a letter so set it to white
                        pixel.red = 255;
                        pixel.green = 255;
                        pixel.blue = 255;
                    }
                }
            }
        }

        // now draw the cursor if we need to
        if (cursor_visible && has_focus && enabled)
        {
            const unsigned long top = rect.top()+3;
            const unsigned long bottom = rect.bottom()-3;
            draw_line(c, point(rect.left()+cursor_x,top),point(rect.left()+cursor_x,bottom));
        }

    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // text_box styles
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    void text_box_style_default::
    draw_text_box (
        const canvas& c,
        const rectangle& display_rect,
        const rectangle& text_rect,
        const bool enabled,
        const font& mfont,
        const ustring& text,
        const rectangle& cursor_rect,
        const rgb_pixel& text_color,
        const rgb_pixel& bg_color,
        const bool has_focus,
        const bool cursor_visible,
        const long highlight_start,
        const long highlight_end
    ) const
    {
        rectangle area = display_rect.intersect(c);

        if (enabled)
        {
            // first fill our area with the bg_color
            fill_rect(c, area,bg_color);
        }
        else
        {
            // first fill our area with gray
            fill_rect(c, area,rgb_pixel(212,208,200));
        }

        if (enabled)
            mfont.draw_string(c,text_rect,text,text_color, 0, ustring::npos, area);
        else
            mfont.draw_string(c,text_rect,text,rgb_pixel(128,128,128), 0, ustring::npos, area);

        // now draw the highlight if there is any
        if (highlight_start <= highlight_end && enabled)
        {
            const rectangle first_pos = mfont.compute_cursor_rect(text_rect, text, highlight_start);
            const rectangle last_pos = mfont.compute_cursor_rect(text_rect, text, highlight_end+1);

            const rgb_alpha_pixel color(10, 30, 106, 90);

            // if the highlighted text is all on one line
            if (first_pos.top() == last_pos.top())
            {
                fill_rect(c, (first_pos + last_pos).intersect(display_rect), color);
            }
            else
            {
                const rectangle min_boundary(display_rect.left()+4, display_rect.top()+4,
                                             display_rect.right()-4, display_rect.bottom()-4);
                const rectangle boundary( display_rect.intersect(text_rect) + min_boundary);

                rectangle first_row, last_row, middle_rows;
                first_row += first_pos;
                first_row += point(boundary.right(), first_pos.top());
                last_row += last_pos;
                last_row += point(boundary.left(), last_pos.bottom());

                middle_rows.left() = boundary.left();
                middle_rows.right() = boundary.right();
                middle_rows.top() = first_row.bottom()+1;
                middle_rows.bottom() = last_row.top()-1;

                fill_rect(c, first_row.intersect(display_rect), color);
                fill_rect(c, middle_rows, color);
                fill_rect(c, last_row.intersect(display_rect), color);
            }
        }

        // now draw the cursor if we need to
        if (cursor_visible && has_focus && enabled)
        {
            draw_line(c, point(cursor_rect.left(), cursor_rect.top()),point(cursor_rect.left(), cursor_rect.bottom()), 0, area);
        }

    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_WIDGETs_STYLE_CPP_


dlib C++ Library - style.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net), and Nils Labugt
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_WIDGETs_STYLE_
#define DLIB_WIDGETs_STYLE_

#include "../algs.h"
#include "style_abstract.h"
#include "../gui_core.h"
#include "canvas_drawing.h"
#include <string>
#include <sstream>
#include "../unicode.h"
#include "../array2d.h"
#include "../pixel.h"
#include "fonts.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // button styles
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class button_style
    {
    public:

        button_style()
        {
        }

        virtual ~button_style()
        {}

        virtual bool redraw_on_mouse_over (
        ) const { return false; }

        virtual rectangle get_invalidation_rect (
            const rectangle& rect
        ) const { return rect; }

        virtual rectangle get_min_size (
            const ustring& name,
            const font& mfont
        ) const = 0;

        virtual void draw_button (
            const canvas& c,
            const rectangle& rect,
            const bool enabled,
            const font& mfont,
            const long lastx,
            const long lasty,
            const ustring& name,
            const bool is_depressed
        ) const = 0;
    };

// ----------------------------------------------------------------------------------------

    class button_style_default : public button_style
    {
    public:
        button_style_default () : padding(4), name_width(0) {}

        virtual void draw_button (
            const canvas& c,
            const rectangle& rect,
            const bool enabled,
            const font& mfont,
            const long lastx,
            const long lasty,
            const ustring& name,
            const bool is_depressed
        ) const;

        virtual rectangle get_min_size (
            const ustring& name,
            const font& mfont
        ) const;

    private:

        // this is the minimum amount of padding that can separate the name from the
        // edge of the button
        const unsigned long padding;
        // this is the width of the name string
        mutable unsigned long name_width;

    };

// ----------------------------------------------------------------------------------------

    class button_style_toolbar1 : public button_style
    {
    public:
        button_style_toolbar1 () : padding(4), name_width(0) {}

        virtual void draw_button (
            const canvas& c,
            const rectangle& rect,
            const bool enabled,
            const font& mfont,
            const long lastx,
            const long lasty,
            const ustring& name,
            const bool is_depressed
        ) const;

        virtual rectangle get_invalidation_rect (
            const rectangle& rect
        ) const
        {
            rectangle temp(rect);
            temp.left() -= 2;
            temp.top() -= 2;
            temp.right() += 2;
            temp.bottom() += 2;
            return temp;
        }

        virtual bool redraw_on_mouse_over (
        ) const { return true; }

        virtual rectangle get_min_size (
            const ustring& name,
            const font& mfont
        ) const;

    private:

        // this is the minimum amount of padding that can separate the name from the
        // edge of the button
        const unsigned long padding;
        // this is the width of the name string
        mutable unsigned long name_width;

    };

// ----------------------------------------------------------------------------------------

    class button_style_toolbar_icon1 : public button_style
    {
    public:
        template <typename image_type>
        button_style_toolbar_icon1 (const image_type& img_, unsigned long pad = 6) : padding(pad)
        {
            assign_image(img_mouseover,img_);
            make_images();
        }

        button_style_toolbar_icon1( const button_style_toolbar_icon1& item): button_style(item), padding(item.padding)
        {
            assign_image(img_mouseover, item.img_mouseover);
            assign_image(img_normal, item.img_normal);
            assign_image(img_disabled, item.img_disabled);
        }

        virtual void draw_button (
            const canvas& c,
            const rectangle& rect,
            const bool enabled,
            const font& mfont,
            const long lastx,
            const long lasty,
            const ustring& name,
            const bool is_depressed
        ) const;

        virtual bool redraw_on_mouse_over (
        ) const { return true; }

        virtual rectangle get_min_size (
            const ustring& name,
            const font& mfont
        ) const;

    private:

        void make_images (
        )
        {
            // make the disabled image grayscale and make both non-mouseover images have weaker alpha channels
            img_disabled.set_size(img_mouseover.nr(), img_mouseover.nc());
            img_normal.set_size(img_mouseover.nr(), img_mouseover.nc());

            for (long r = 0; r < img_mouseover.nr(); ++r)
            {
                for (long c = 0; c < img_mouseover.nc(); ++c)
                {
                    rgb_alpha_pixel p = img_mouseover[r][c];
                    long avg = p.red;
                    avg += p.green;
                    avg += p.blue;
                    avg /= 3;

                    if (p.alpha > 40)
                        p.alpha -= 40;
                    else
                        p.alpha = 0;

                    img_normal[r][c] = p;

                    if (p.alpha > 80)
                        p.alpha -= 80;
                    else
                        p.alpha = 0;

                    p.red = avg;
                    p.green = avg;
                    p.blue = avg;
                    img_disabled[r][c] = p;
                }
            }
        }

        array2d<rgb_alpha_pixel> img_mouseover;
        array2d<rgb_alpha_pixel> img_normal;
        array2d<rgb_alpha_pixel> img_disabled;

        // this is the minimum amount of padding that can separate the name from the
        // edge of the button
        const unsigned long padding;

    };

// ----------------------------------------------------------------------------------------

    class button_style_arrow : public button_style
    {

    public:

        enum arrow_direction
        {
            UP,
            DOWN,
            LEFT,
            RIGHT
        };

        button_style_arrow (
            arrow_direction dir_
        ) : dir(dir_) {}

        virtual void draw_button (
            const canvas& c,
            const rectangle& rect,
            const bool enabled,
            const font& mfont,
            const long lastx,
            const long lasty,
            const ustring& name,
            const bool is_depressed
        ) const;

        virtual rectangle get_min_size (
            const ustring& ,
            const font&
        ) const { return rectangle(); }

    private:
        arrow_direction dir;
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // toggle button styles
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class toggle_button_style
    {
    public:

        toggle_button_style()
        {
        }

        virtual ~toggle_button_style()
        {}

        virtual bool redraw_on_mouse_over (
        ) const { return false; }

        virtual rectangle get_min_size (
            const ustring& name,
            const font& mfont
        ) const = 0;

        virtual void draw_toggle_button (
            const canvas& c,
            const rectangle& rect,
            const bool enabled,
            const font& mfont,
            const long lastx,
            const long lasty,
            const ustring& name,
            const bool is_depressed,
            const bool is_checked
        ) const = 0;
    };

// ----------------------------------------------------------------------------------------

    class toggle_button_style_default : public toggle_button_style
    {
    public:
        toggle_button_style_default () : padding(4), name_width(0) {}

        virtual void draw_toggle_button (
            const canvas& c,
            const rectangle& rect,
            const bool enabled,
            const font& mfont,
            const long lastx,
            const long lasty,
            const ustring& name,
            const bool is_depressed,
            const bool is_checked
        ) const;

        virtual rectangle get_min_size (
            const ustring& name,
            const font& mfont
        ) const;

    private:

        // this is the minimum amount of padding that can separate the name from the
        // edge of the button
        const unsigned long padding;
        // this is the width of the name string
        mutable unsigned long name_width;

    };

// ----------------------------------------------------------------------------------------

    class toggle_button_style_check_box : public toggle_button_style
    {
    public:
        virtual void draw_toggle_button (
            const canvas& c,
            const rectangle& rect,
            const bool enabled,
            const font& mfont,
            const long lastx,
            const long lasty,
            const ustring& name,
            const bool is_depressed,
            const bool is_checked
        ) const;

        virtual rectangle get_min_size (
            const ustring& name,
            const font& mfont
        ) const;

    };

// ----------------------------------------------------------------------------------------

    class toggle_button_style_radio_button : public toggle_button_style
    {
    public:
        virtual void draw_toggle_button (
            const canvas& c,
            const rectangle& rect,
            const bool enabled,
            const font& mfont,
            const long lastx,
            const long lasty,
            const ustring& name,
            const bool is_depressed,
            const bool is_checked
        ) const;

        virtual rectangle get_min_size (
            const ustring& name,
            const font& mfont
        ) const;

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // scroll_bar styles
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class scroll_bar_style
    {
    public:

        virtual ~scroll_bar_style() {}

        virtual bool redraw_on_mouse_over_slider (
        ) const { return false; }

        virtual long get_width (
        ) const = 0;

        virtual long get_slider_length (
            long total_length,
            long max_pos
        ) const = 0;

        virtual long get_button_length (
            long total_length,
            long max_pos
        ) const = 0;

        virtual void draw_scroll_bar_background (
            const canvas& c,
            const rectangle& rect,
            const bool enabled,
            const long lastx,
            const long lasty,
            const bool is_depressed
        ) const = 0;

        virtual void draw_scroll_bar_slider (
            const canvas& c,
            const rectangle& rect,
            const bool enabled,
            const long lastx,
            const long lasty,
            const bool is_being_dragged
        ) const = 0;

    };

// ----------------------------------------------------------------------------------------

    class scroll_bar_style_default : public scroll_bar_style
    {
    public:
        button_style_arrow get_up_button_style (
        ) const { return button_style_arrow(button_style_arrow::UP); }

        button_style_arrow get_down_button_style (
        ) const { return button_style_arrow(button_style_arrow::DOWN); }

        button_style_arrow get_left_button_style (
        ) const { return button_style_arrow(button_style_arrow::LEFT); }

        button_style_arrow get_right_button_style (
        ) const { return button_style_arrow(button_style_arrow::RIGHT); }

        virtual long get_width (
        ) const  { return 16; }

        virtual long get_slider_length (
            long total_length,
            long max_pos
        ) const;

        virtual long get_button_length (
            long total_length,
            long max_pos
        ) const;

        virtual void draw_scroll_bar_background (
            const canvas& c,
            const rectangle& rect,
            const bool enabled,
            const long lastx,
            const long lasty,
            const bool is_depressed
        ) const;

        virtual void draw_scroll_bar_slider (
            const canvas& c,
            const rectangle& rect,
            const bool enabled,
            const long lastx,
            const long lasty,
            const bool is_being_dragged
        ) const;
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // scrollable_region styles
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class scrollable_region_style
    {
    public:

        virtual ~scrollable_region_style() {}

        virtual long get_border_size (
        ) const = 0;

        virtual void draw_scrollable_region_border (
            const canvas& c,
            const rectangle& rect,
            const bool enabled
        ) const = 0;

    };

// ----------------------------------------------------------------------------------------

    class scrollable_region_style_default : public scrollable_region_style
    {
    public:
        scroll_bar_style_default get_horizontal_scroll_bar_style (
        ) const { return scroll_bar_style_default(); }

        scroll_bar_style_default get_vertical_scroll_bar_style (
        ) const { return scroll_bar_style_default(); }

        virtual long get_border_size (
        ) const { return 2; }

        virtual void draw_scrollable_region_border (
            const canvas& c,
            const rectangle& rect,
            const bool
        ) const  { draw_sunken_rectangle(c,rect); }

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // list_box styles
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class list_box_style
    {
    public:

        virtual ~list_box_style() {}

        virtual void draw_list_box_background (
            const canvas& c,
            const rectangle& display_rect,
            const bool enabled
        ) const = 0;

        virtual void draw_list_box_item (
            const canvas& c,
            const rectangle& rect,
            const rectangle& display_rect,
            const bool enabled,
            const font& mfont,
            const std::string& text,
            const bool is_selected
        ) const = 0;

        virtual void draw_list_box_item (
            const canvas& c,
            const rectangle& rect,
            const rectangle& display_rect,
            const bool enabled,
            const font& mfont,
            const std::wstring& text,
            const bool is_selected
        ) const = 0;

        virtual void draw_list_box_item (
            const canvas& c,
            const rectangle& rect,
            const rectangle& display_rect,
            const bool enabled,
            const font& mfont,
            const ustring& text,
            const bool is_selected
        ) const = 0;

    };

// ----------------------------------------------------------------------------------------

    class list_box_style_default : public list_box_style
    {
    public:
        scrollable_region_style_default get_scrollable_region_style (
        ) const { return scrollable_region_style_default(); }

        virtual void draw_list_box_item (
            const canvas& c,
            const rectangle& rect,
            const rectangle& display_rect,
            const bool enabled,
            const font& mfont,
            const std::string& text,
            const bool is_selected
        ) const { draw_list_box_item_template(c,rect,display_rect, enabled, mfont, text, is_selected); }

        virtual void draw_list_box_item (
            const canvas& c,
            const rectangle& rect,
            const rectangle& display_rect,
            const bool enabled,
            const font& mfont,
            const std::wstring& text,
            const bool is_selected
        ) const { draw_list_box_item_template(c,rect,display_rect, enabled, mfont, text, is_selected); }

        virtual void draw_list_box_item (
            const canvas& c,
            const rectangle& rect,
            const rectangle& display_rect,
            const bool enabled,
            const font& mfont,
            const ustring& text,
            const bool is_selected
        ) const { draw_list_box_item_template(c,rect,display_rect, enabled, mfont, text, is_selected); }

        template <typename string_type>
        void draw_list_box_item_template (
            const canvas& c,
            const rectangle& rect,
            const rectangle& display_rect,
            const bool enabled,
            const font& mfont,
            const string_type& text,
            const bool is_selected
        ) const
        {
            if (is_selected)
            {
                if (enabled)
                    fill_rect_with_vertical_gradient(c,rect,rgb_pixel(110,160,255),  rgb_pixel(100,130,250),display_rect);
                else
                    fill_rect_with_vertical_gradient(c,rect,rgb_pixel(140,190,255),  rgb_pixel(130,160,250),display_rect);
            }

            if (enabled)
                mfont.draw_string(c,rect,text,rgb_pixel(0,0,0),0,std::string::npos,display_rect);
            else
                mfont.draw_string(c,rect,text,rgb_pixel(128,128,128),0,std::string::npos,display_rect);
        }

        virtual void draw_list_box_background (
            const canvas& c,
            const rectangle& display_rect,
            const bool enabled
        ) const
        {
            if (enabled)
            {
                // first fill our area with white
                fill_rect(c, display_rect,rgb_pixel(255,255,255));
            }
            else
            {
                // first fill our area with gray
                fill_rect(c, display_rect,rgb_pixel(212,208,200));
            }
        }

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // text_box styles
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class text_box_style
    {
    public:

        text_box_style()
        {
        }

        virtual ~text_box_style()
        {}

        virtual unsigned long get_padding (
            const font& mfont
        ) const = 0;

        virtual void draw_text_box (
            const canvas& c,
            const rectangle& display_rect,
            const rectangle& text_rect,
            const bool enabled,
            const font& mfont,
            const ustring& text,
            const rectangle& cursor_rect,
            const rgb_pixel& text_color,
            const rgb_pixel& bg_color,
            const bool has_focus,
            const bool cursor_visible,
            const long highlight_start,
            const long highlight_end
        ) const = 0;
    };

// ----------------------------------------------------------------------------------------

    class text_box_style_default : public text_box_style
    {
    public:

        text_box_style_default()
        {
        }

        scrollable_region_style_default get_scrollable_region_style (
        ) const { return scrollable_region_style_default(); }

        virtual ~text_box_style_default()
        {}

        virtual unsigned long get_padding (
            const font&
        ) const { return 1; }

        virtual void draw_text_box (
            const canvas& c,
            const rectangle& display_rect,
            const rectangle& text_rect,
            const bool enabled,
            const font& mfont,
            const ustring& text,
            const rectangle& cursor_rect,
            const rgb_pixel& text_color,
            const rgb_pixel& bg_color,
            const bool has_focus,
            const bool cursor_visible,
            const long highlight_start,
            const long highlight_end
        ) const;

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // text_field styles
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class text_field_style
    {
    public:

        text_field_style()
        {
        }

        virtual ~text_field_style()
        {}

        virtual unsigned long get_padding (
            const font& mfont
        ) const = 0;

        virtual void draw_text_field (
            const canvas& c,
            const rectangle& rect,
            const rectangle& text_rect,
            const bool enabled,
            const font& mfont,
            const ustring& text,
            const unsigned long cursor_x,
            const unsigned long text_pos,
            const rgb_pixel& text_color,
            const rgb_pixel& bg_color,
            const bool has_focus,
            const bool cursor_visible,
            const long highlight_start,
            const long highlight_end
        ) const = 0;
    };

// ----------------------------------------------------------------------------------------

    class text_field_style_default : public text_field_style
    {
    public:

        text_field_style_default()
        {
        }

        virtual ~text_field_style_default()
        {}

        virtual unsigned long get_padding (
            const font& mfont
        ) const;

        virtual void draw_text_field (
            const canvas& c,
            const rectangle& rect,
            const rectangle& text_rect,
            const bool enabled,
            const font& mfont,
            const ustring& text,
            const unsigned long cursor_x,
            const unsigned long text_pos,
            const rgb_pixel& text_color,
            const rgb_pixel& bg_color,
            const bool has_focus,
            const bool cursor_visible,
            const long highlight_start,
            const long highlight_end
        ) const;

    };

// ----------------------------------------------------------------------------------------

}

#ifdef NO_MAKEFILE
#include "style.cpp"
#endif

#endif // DLIB_WIDGETs_STYLE_


dlib C++ Library - widgets.cpp

// Copyright (C) 2005  Davis E. King (davis@dlib.net), Keita Mochizuki
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_WIDGETs_CPP_
#define DLIB_WIDGETs_CPP_

#include "widgets.h"
#include <algorithm>
#include "../string.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // toggle_button object methods
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    void toggle_button::
    set_size (
        unsigned long width,
        unsigned long height
    )
    {
        auto_mutex M(m);
        rectangle min_rect = style->get_min_size(name_,*mfont);
        // only change the size if it isn't going to be too small to fit the name
        if (height >= min_rect.height() &&
            width >= min_rect.width())
        {
            rectangle old(rect);
            rect = resize_rect(rect,width,height);
            parent.invalidate_rectangle(rect+old);
            btn_tooltip.set_size(width,height);
        }
    }

// ----------------------------------------------------------------------------------------

    void toggle_button::
    set_checked (
    )
    {
        auto_mutex M(m);
        checked = true;
        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    void toggle_button::
    set_unchecked (
    )
    {
        auto_mutex M(m);
        checked = false;
        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    bool toggle_button::
    is_checked (
    ) const
    {
        auto_mutex M(m);
        return checked;
    }

// ----------------------------------------------------------------------------------------

    void toggle_button::
    show (
    )
    {
        button_action::show();
        btn_tooltip.show();
    }

// ----------------------------------------------------------------------------------------

    void toggle_button::
    hide (
    )
    {
        button_action::hide();
        btn_tooltip.hide();
    }

// ----------------------------------------------------------------------------------------

    void toggle_button::
    enable (
    )
    {
        button_action::enable();
        btn_tooltip.enable();
    }

// ----------------------------------------------------------------------------------------

    void toggle_button::
    disable (
    )
    {
        button_action::disable();
        btn_tooltip.disable();
    }

// ----------------------------------------------------------------------------------------

    void toggle_button::
    set_tooltip_text (
        const std::string& text
    )
    {
        btn_tooltip.set_text(text);
    }

    void toggle_button::
    set_tooltip_text (
        const std::wstring& text
    )
    {
        btn_tooltip.set_text(text);
    }

    void toggle_button::
    set_tooltip_text (
        const dlib::ustring& text
    )
    {
        btn_tooltip.set_text(text);
    }

// ----------------------------------------------------------------------------------------

    const std::string toggle_button::
    tooltip_text (
    ) const
    {
        return btn_tooltip.text();
    }

    const std::wstring toggle_button::
    tooltip_wtext (
    ) const
    {
        return btn_tooltip.wtext();
    }

    const dlib::ustring toggle_button::
    tooltip_utext (
    ) const
    {
        return btn_tooltip.utext();
    }

// ----------------------------------------------------------------------------------------

    void toggle_button::
    set_main_font (
        const shared_ptr_thread_safe<font>& f
    )
    {
        auto_mutex M(m);
        mfont = f;
        set_name(name_);
    }

// ----------------------------------------------------------------------------------------

    void toggle_button::
    set_pos (
        long x,
        long y
    )
    {
        auto_mutex M(m);
        button_action::set_pos(x,y);
        btn_tooltip.set_pos(x,y);
    }

// ----------------------------------------------------------------------------------------

    void toggle_button::
    set_name (
        const std::string& name
    )
    {
        set_name(convert_mbstring_to_wstring(name));
    }

    void toggle_button::
    set_name (
        const std::wstring& name
    )
    {
        set_name(convert_wstring_to_utf32(name));
    }

    void toggle_button::
    set_name (
        const dlib::ustring& name
    )
    {
        auto_mutex M(m);
        name_ = name;
        // do this to get rid of any reference counting that may be present in
        // the std::string implementation.
        name_[0] = name_[0];

        rectangle old(rect);
        rect = move_rect(style->get_min_size(name,*mfont),rect.left(),rect.top());
        btn_tooltip.set_size(rect.width(),rect.height());

        parent.invalidate_rectangle(rect+old);
    }

// ----------------------------------------------------------------------------------------

    const std::string toggle_button::
    name (
    ) const
    {
        return convert_wstring_to_mbstring(wname());
    }

    const std::wstring toggle_button::
    wname (
    ) const
    {
        return convert_utf32_to_wstring(uname());
    }

    const dlib::ustring toggle_button::
    uname (
    ) const
    {
        auto_mutex M(m);
        dlib::ustring temp = name_;
        // do this to get rid of any reference counting that may be present in
        // the std::string implementation.
        temp[0] = name_[0];
        return temp;
    }

// ----------------------------------------------------------------------------------------

    void toggle_button::
    on_button_up (
        bool mouse_over
    )
    {
        if (mouse_over)
        {
            checked = !checked;
            // this is a valid toggle_button click
            if (event_handler.is_set())
                event_handler();
            else if (event_handler_self.is_set())
                event_handler_self(*this);
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // label object methods
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    void label::
    draw (
        const canvas& c
    ) const
    {
        rectangle area = rect.intersect(c);
        if (area.is_empty() || text_.size() == 0)
            return;

        using namespace std;
        unsigned char r = text_color_.red;
        unsigned char g = text_color_.green;
        unsigned char b = text_color_.blue;
        if (!enabled)
        {
            r = 128;
            g = 128;
            b = 128;
        }

        rectangle text_rect(rect);

        string::size_type first, last;
        first = 0;
        last = text_.find_first_of('\n');
        mfont->draw_string(c,text_rect,text_,rgb_pixel(r,g,b),first,last);

        while (last != string::npos)
        {
            first = last+1;
            last = text_.find_first_of('\n',first);
            text_rect.set_top(text_rect.top()+mfont->height());
            mfont->draw_string(c,text_rect,text_,rgb_pixel(r,g,b),first,last);
        }
    }

// ----------------------------------------------------------------------------------------

    void label::
    set_main_font (
        const shared_ptr_thread_safe<font>& f
    )
    {
        auto_mutex M(m);
        mfont = f;
        set_text(text_);
    }

// ----------------------------------------------------------------------------------------

    void label::
    set_text (
        const std::string& text
    )
    {
        set_text(convert_mbstring_to_wstring(text));
    }

    void label::
    set_text (
        const std::wstring& text
    )
    {
        set_text(convert_wstring_to_utf32(text));
    }

    void label::
    set_text (
        const dlib::ustring& text
    )
    {
        using namespace std;
        auto_mutex M(m);
        text_ = text;
        // do this to get rid of any reference counting that may be present in
        // the std::string implementation.
        text_[0] = text[0];

        rectangle old(rect);

        unsigned long width;
        unsigned long height;
        mfont->compute_size(text,width,height);

        rect.set_right(rect.left() + width - 1);
        rect.set_bottom(rect.top() + height - 1);

        parent.invalidate_rectangle(rect+old);
    }

// ----------------------------------------------------------------------------------------

    const std::string label::
    text (
    ) const
    {
        return convert_wstring_to_mbstring(wtext());
    }

    const std::wstring label::
    wtext (
    ) const
    {
        return convert_utf32_to_wstring(utext());
    }

    const dlib::ustring label::
    utext (
    ) const
    {
        auto_mutex M(m);
        dlib::ustring temp = text_;
        // do this to get rid of any reference counting that may be present in
        // the std::string implementation.
        temp[0] = text_[0];
        return temp;
    }

// ----------------------------------------------------------------------------------------

    void label::
    set_text_color (
        const rgb_pixel color
    )
    {
        m.lock();
        text_color_ = color;
        parent.invalidate_rectangle(rect);
        m.unlock();
    }

// ----------------------------------------------------------------------------------------

    const rgb_pixel label::
    text_color (
    ) const
    {
        auto_mutex M(m);
        return text_color_;
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // text_field object methods
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    rectangle text_field::
    get_text_rect (
    ) const
    {
        // figure out where the text string should appear
        unsigned long vertical_pad = (rect.height() - mfont->height())/2+1;

        rectangle text_rect;
        text_rect.set_left(rect.left()+style->get_padding(*mfont));
        text_rect.set_top(rect.top()+vertical_pad);
        text_rect.set_right(rect.right()-style->get_padding(*mfont));
        text_rect.set_bottom(text_rect.top()+mfont->height()-1);
        return text_rect;
    }

// ----------------------------------------------------------------------------------------

    void text_field::
    enable (
    )
    {
        drawable::enable();
        right_click_menu.enable();
    }

// ----------------------------------------------------------------------------------------

    void text_field::
    give_input_focus (
    )
    {
        auto_mutex M(m);
        has_focus = true;
        cursor_visible = true;
        parent.invalidate_rectangle(rect);
        t.start();
    }

// ----------------------------------------------------------------------------------------

    bool text_field::
    has_input_focus (
    ) const
    {
        auto_mutex M(m);
        return has_focus;
    }

// ----------------------------------------------------------------------------------------

    void text_field::
    select_all_text (
    )
    {
        auto_mutex M(m);
        on_select_all();
    }

// ----------------------------------------------------------------------------------------

    void text_field::
    on_cut (
    )
    {
        on_copy();
        on_delete_selected();
    }

// ----------------------------------------------------------------------------------------

    void text_field::
    on_copy (
    )
    {
        if (highlight_start <= highlight_end)
        {
            put_on_clipboard(text_.substr(highlight_start, highlight_end-highlight_start+1));
        }
    }

// ----------------------------------------------------------------------------------------

    void text_field::
    on_paste (
    )
    {
        ustring temp_str;
        get_from_clipboard(temp_str);

        // If this is a multi line string then just take the first line.
        ustring::size_type pos = temp_str.find_first_of('\n');
        if (pos != ustring::npos)
        {
            temp_str = temp_str.substr(0,pos);
        }

        if (highlight_start <= highlight_end)
        {
            text_ = text_.substr(0,highlight_start) + temp_str +
                text_.substr(highlight_end+1,text_.size()-highlight_end-1);
            move_cursor(highlight_start+temp_str.size());
            highlight_start = 0;
            highlight_end = -1;
            parent.invalidate_rectangle(rect);
            on_no_text_selected();

            // send out the text modified event
            if (text_modified_handler.is_set())
                text_modified_handler();
        }
        else
        {
            text_ = text_.substr(0,cursor_pos) + temp_str +
                text_.substr(cursor_pos,text_.size()-cursor_pos);
            move_cursor(cursor_pos+temp_str.size());

            // send out the text modified event
            if (temp_str.size() != 0 && text_modified_handler.is_set())
                text_modified_handler();
        }
    }

// ----------------------------------------------------------------------------------------

    void text_field::
    on_select_all (
    )
    {
        move_cursor(static_cast<long>(text_.size()));
        highlight_start = 0;
        highlight_end = static_cast<long>(text_.size()-1);
        if (highlight_start <= highlight_end)
            on_text_is_selected();
        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    void text_field::
    on_delete_selected (
    )
    {
        if (highlight_start <= highlight_end)
        {
            text_ = text_.erase(highlight_start,highlight_end-highlight_start+1);
            move_cursor(highlight_start);
            highlight_start = 0;
            highlight_end = -1;

            on_no_text_selected();
            // send out the text modified event
            if (text_modified_handler.is_set())
                text_modified_handler();

            parent.invalidate_rectangle(rect);
        }
    }

// ----------------------------------------------------------------------------------------

    void text_field::
    on_text_is_selected (
    )
    {
        right_click_menu.menu().enable_menu_item(0);
        right_click_menu.menu().enable_menu_item(1);
        right_click_menu.menu().enable_menu_item(3);
    }

// ----------------------------------------------------------------------------------------

    void text_field::
    on_no_text_selected (
    )
    {
        right_click_menu.menu().disable_menu_item(0);
        right_click_menu.menu().disable_menu_item(1);
        right_click_menu.menu().disable_menu_item(3);
    }

// ----------------------------------------------------------------------------------------

    void text_field::
    show (
    )
    {
        drawable::show();
        right_click_menu.show();
    }

// ----------------------------------------------------------------------------------------

    void text_field::
    disable (
    )
    {
        auto_mutex M(m);
        drawable::disable();
        t.stop();
        has_focus = false;
        cursor_visible = false;
        right_click_menu.disable();
    }

// ----------------------------------------------------------------------------------------

    void text_field::
    hide (
    )
    {
        auto_mutex M(m);
        drawable::hide();
        t.stop();
        has_focus = false;
        cursor_visible = false;
    }

// ----------------------------------------------------------------------------------------

    void text_field::
    set_main_font (
        const shared_ptr_thread_safe<font>& f
    )
    {
        auto_mutex M(m);
        mfont = f;
        // adjust the height of this text field so that it is appropriate for the current
        // font size
        rect.set_bottom(rect.top() + mfont->height()+ (style->get_padding(*mfont))*2);
        set_text(text_);
        right_click_menu.set_rect(get_text_rect());
    }

// ----------------------------------------------------------------------------------------

    void text_field::
    draw (
        const canvas& c
    ) const
    {
        rectangle area = rect.intersect(c);
        if (area.is_empty())
            return;

        style->draw_text_field(c,rect,get_text_rect(), enabled, *mfont, text_, cursor_x, text_pos,
                               text_color_, bg_color_, has_focus, cursor_visible, highlight_start,
                               highlight_end);
    }

// ----------------------------------------------------------------------------------------

    void text_field::
    set_text (
        const std::string& text
    )
    {
        set_text(convert_mbstring_to_wstring(text));
    }

    void text_field::
    set_text (
        const std::wstring& text
    )
    {
        set_text(convert_wstring_to_utf32(text));
    }

    void text_field::
    set_text (
        const dlib::ustring& text
    )
    {
        DLIB_ASSERT ( text.find_first_of('\n') == std::string::npos ,
                "\tvoid text_field::set_text()"
                << "\n\ttext:  " << narrow(text) );
        auto_mutex M(m);
        // do this to get rid of any reference counting that may be present in
        // the std::string implementation.
        text_ = text.c_str();

        move_cursor(0);

        highlight_start = 0;
        highlight_end = -1;

        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    const std::string text_field::
    text (
    ) const
    {
        std::string temp = convert_wstring_to_mbstring(wtext());
        return temp;
    }

    const std::wstring text_field::
    wtext (
    ) const
    {
        std::wstring temp = convert_utf32_to_wstring(utext());
        return temp;
    }

    const dlib::ustring text_field::
    utext (
    ) const
    {
        auto_mutex M(m);
        // do this to get rid of any reference counting that may be present in
        // the dlib::ustring implementation.
        dlib::ustring temp = text_.c_str();
        return temp;
    }

// ----------------------------------------------------------------------------------------

    void text_field::
    set_width (
        unsigned long width
    )
    {
        auto_mutex M(m);
        if (width < style->get_padding(*mfont)*2)
            return;

        rectangle old(rect);

        rect.set_right(rect.left() + width - 1);

        right_click_menu.set_rect(get_text_rect());
        parent.invalidate_rectangle(rect+old);
    }

// ----------------------------------------------------------------------------------------

    void text_field::
    set_pos (
        long x,
        long y
    )
    {
        drawable::set_pos(x,y);
        right_click_menu.set_rect(get_text_rect());
    }

// ----------------------------------------------------------------------------------------

    void text_field::
    set_background_color (
        const rgb_pixel color
    )
    {
        auto_mutex M(m);
        bg_color_ = color;
        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    const rgb_pixel text_field::
    background_color (
    ) const
    {
        auto_mutex M(m);
        return bg_color_;
    }

// ----------------------------------------------------------------------------------------

    void text_field::
    set_text_color (
        const rgb_pixel color
    )
    {
        auto_mutex M(m);
        text_color_ = color;
        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    const rgb_pixel text_field::
    text_color (
    ) const
    {
        auto_mutex M(m);
        return text_color_;
    }

// ----------------------------------------------------------------------------------------

    void text_field::
    on_mouse_move (
        unsigned long state,
        long x,
        long y
    )
    {
        if (!enabled || hidden || !has_focus)
        {
            return;
        }

        if (state & base_window::LEFT)
        {
            if (highlight_start <= highlight_end)
            {
                if (highlight_start == cursor_pos)
                    shift_pos = highlight_end + 1;
                else
                    shift_pos = highlight_start;
            }

            unsigned long new_pos = mfont->compute_cursor_pos(get_text_rect(),text_,x,y,text_pos);
            if (static_cast<long>(new_pos) != cursor_pos)
            {
                move_cursor(new_pos);
                parent.invalidate_rectangle(rect);
            }
        }
        else if (shift_pos != -1)
        {
            shift_pos = -1;
        }

    }

// ----------------------------------------------------------------------------------------

    void text_field::
    on_mouse_up (
        unsigned long btn,
        unsigned long,
        long ,
        long
    )
    {
        if (!enabled || hidden)
            return;

        if (btn == base_window::LEFT)
            shift_pos = -1;
    }

// ----------------------------------------------------------------------------------------

    void text_field::
    on_mouse_down (
        unsigned long btn,
        unsigned long state,
        long x,
        long y,
        bool double_clicked
    )
    {
        using namespace std;
        if (!enabled || hidden || btn != (unsigned long)base_window::LEFT)
            return;

        if (rect.contains(x,y))
        {
            has_focus = true;
            cursor_visible = true;
            parent.invalidate_rectangle(rect);
            t.start();

            if (double_clicked)
            {
                // highlight the double clicked word
                string::size_type first, last;
                const ustring ustr = convert_utf8_to_utf32(std::string(" \t\n"));
                first = text_.substr(0,cursor_pos).find_last_of(ustr.c_str());
                last = text_.find_first_of(ustr.c_str(),cursor_pos);
                long f = static_cast<long>(first);
                long l = static_cast<long>(last);
                if (first == string::npos)
                    f = -1;
                if (last == string::npos)
                    l = static_cast<long>(text_.size());

                ++f;
                --l;

                move_cursor(l+1);
                highlight_start = f;
                highlight_end = l;
                on_text_is_selected();
            }
            else
            {
                if (state & base_window::SHIFT)
                {
                    if (highlight_start <= highlight_end)
                    {
                        if (highlight_start == cursor_pos)
                            shift_pos = highlight_end + 1;
                        else
                            shift_pos = highlight_start;
                    }
                    else
                    {
                        shift_pos = cursor_pos;
                    }
                }

                bool at_end = false;
                if (cursor_pos == 0 || cursor_pos == static_cast<long>(text_.size()))
                    at_end = true;
                const long old_pos = cursor_pos;

                unsigned long new_pos = mfont->compute_cursor_pos(get_text_rect(),text_,x,y,text_pos);
                if (static_cast<long>(new_pos) != cursor_pos)
                {
                    move_cursor(new_pos);
                    parent.invalidate_rectangle(rect);
                }
                shift_pos = cursor_pos;

                if (at_end && cursor_pos == old_pos)
                {
                    highlight_start = 0;
                    highlight_end = -1;
                    on_no_text_selected();
                    parent.invalidate_rectangle(rect);
                }
            }

        }
        else if (has_focus)
        {
            t.stop();
            has_focus = false;
            cursor_visible = false;
            shift_pos = -1;
            highlight_start = 0;
            highlight_end = -1;
            on_no_text_selected();

            if (focus_lost_handler.is_set())
                focus_lost_handler();
            parent.invalidate_rectangle(rect);
        }
    }

// ----------------------------------------------------------------------------------------

    void text_field::
    on_keydown (
        unsigned long key,
        bool is_printable,
        unsigned long state
    )
    {
        // If the right click menu is up then we don't want to do anything with
        // the keyboard ourselves.  Let the popup menu use the keyboard for now.
        if (right_click_menu.popup_menu_visible())
            return;

        const ustring space_str = convert_utf8_to_utf32(std::string(" \t\n"));
        const bool shift = (state&base_window::KBD_MOD_SHIFT) != 0;
        const bool ctrl = (state&base_window::KBD_MOD_CONTROL) != 0;
        if (has_focus && enabled && !hidden)
        {
            if (shift && is_printable == false)
            {
                if (shift_pos == -1)
                {
                    if (highlight_start <= highlight_end)
                    {
                        if (highlight_start == cursor_pos)
                            shift_pos = highlight_end + 1;
                        else
                            shift_pos = highlight_start;
                    }
                    else
                    {
                        shift_pos = cursor_pos;
                    }
                }
            }
            else
            {
                shift_pos = -1;
            }

            if (key == base_window::KEY_LEFT ||
                key == base_window::KEY_UP)
            {
                if (cursor_pos != 0)
                {
                    unsigned long new_pos;
                    if (ctrl)
                    {
                        // find the first non-whitespace to our left
                        std::string::size_type pos = text_.find_last_not_of(space_str.c_str(),cursor_pos);
                        if (pos != std::string::npos)
                        {
                            pos = text_.find_last_of(space_str.c_str(),pos);
                            if (pos != std::string::npos)
                                new_pos = static_cast<unsigned long>(pos);
                            else
                                new_pos = 0;
                        }
                        else
                        {
                            new_pos = 0;
                        }
                    }
                    else
                    {
                        new_pos = cursor_pos-1;
                    }

                    move_cursor(new_pos);
                }
                else if (shift_pos == -1)
                {
                    highlight_start = 0;
                    highlight_end = -1;
                    on_no_text_selected();
                    parent.invalidate_rectangle(rect);
                }

            }
            else if (key == base_window::KEY_RIGHT ||
                key == base_window::KEY_DOWN)
            {
                if (cursor_pos != static_cast<long>(text_.size()))
                {
                    unsigned long new_pos;
                    if (ctrl)
                    {
                        // find the first non-whitespace to our left
                        std::string::size_type pos = text_.find_first_not_of(space_str.c_str(),cursor_pos);
                        if (pos != std::string::npos)
                        {
                            pos = text_.find_first_of(space_str.c_str(),pos);
                            if (pos != std::string::npos)
                                new_pos = static_cast<unsigned long>(pos+1);
                            else
                                new_pos = static_cast<unsigned long>(text_.size());
                        }
                        else
                        {
                            new_pos = static_cast<unsigned long>(text_.size());
                        }
                    }
                    else
                    {
                        new_pos = cursor_pos+1;
                    }

                    move_cursor(new_pos);
                }
                else if (shift_pos == -1)
                {
                    highlight_start = 0;
                    highlight_end = -1;
                    on_no_text_selected();
                    parent.invalidate_rectangle(rect);
                }
            }
            else if (is_printable)
            {
                if (ctrl)
                {
                    if (key == 'a')
                    {
                        on_select_all();
                    }
                    else if (key == 'c')
                    {
                        on_copy();
                    }
                    else if (key == 'v')
                    {
                        on_paste();
                    }
                    else if (key == 'x')
                    {
                        on_cut();
                    }
                }
                else if (key != '\n')
                {
                    if (highlight_start <= highlight_end)
                    {
                        text_ = text_.substr(0,highlight_start) + static_cast<unichar>(key) +
                            text_.substr(highlight_end+1,text_.size()-highlight_end-1);
                        move_cursor(highlight_start+1);
                        highlight_start = 0;
                        highlight_end = -1;
                        on_no_text_selected();
                        parent.invalidate_rectangle(rect);
                    }
                    else
                    {
                        text_ = text_.substr(0,cursor_pos) + static_cast<unichar>(key) +
                            text_.substr(cursor_pos,text_.size()-cursor_pos);
                        move_cursor(cursor_pos+1);
                    }
                    unsigned long height;
                    mfont->compute_size(text_,text_width,height,text_pos);

                    // send out the text modified event
                    if (text_modified_handler.is_set())
                        text_modified_handler();
                }
                else if (key == '\n')
                {
                    if (enter_key_handler.is_set())
                        enter_key_handler();
                }
            }
            else if (key == base_window::KEY_BACKSPACE)
            {
                // if something is highlighted then delete that
                if (highlight_start <= highlight_end)
                {
                    on_delete_selected();
                }
                else if (cursor_pos != 0)
                {
                    text_ = text_.erase(cursor_pos-1,1);
                    move_cursor(cursor_pos-1);

                    // send out the text modified event
                    if (text_modified_handler.is_set())
                        text_modified_handler();
                }
                else
                {
                    // do this just so it repaints itself right
                    move_cursor(cursor_pos);
                }
                unsigned long height;
                mfont->compute_size(text_,text_width,height,text_pos);
                parent.invalidate_rectangle(rect);
            }
            else if (key == base_window::KEY_DELETE)
            {
                // if something is highlighted then delete that
                if (highlight_start <= highlight_end)
                {
                    on_delete_selected();
                }
                else if (cursor_pos != static_cast<long>(text_.size()))
                {
                    text_ = text_.erase(cursor_pos,1);

                    // send out the text modified event
                    if (text_modified_handler.is_set())
                        text_modified_handler();
                }
                else
                {
                    // do this just so it repaints itself right
                    move_cursor(cursor_pos);
                }
                parent.invalidate_rectangle(rect);

                unsigned long height;
                mfont->compute_size(text_,text_width,height,text_pos);
            }
            else if (key == base_window::KEY_HOME)
            {
                move_cursor(0);
                if (shift_pos == -1)
                {
                    highlight_start = 0;
                    highlight_end = -1;
                    on_no_text_selected();
                    parent.invalidate_rectangle(rect);
                }
            }
            else if (key == base_window::KEY_END)
            {
                move_cursor(static_cast<unsigned long>(text_.size()));
                if (shift_pos == -1)
                {
                    highlight_start = 0;
                    highlight_end = -1;
                    on_no_text_selected();
                    parent.invalidate_rectangle(rect);
                }
            }
            cursor_visible = true;
            recent_movement = true;

        }
    }

// ----------------------------------------------------------------------------------------

    void text_field::
    on_string_put(
        const std::wstring &str
    )
    {
        if (has_focus && enabled && !hidden){
            ustring ustr = convert_wstring_to_utf32(str);
            if (highlight_start <= highlight_end)
            {
                text_ = text_.substr(0,highlight_start) + ustr +
                    text_.substr(highlight_end+1,text_.size()-highlight_end-1);
                move_cursor(highlight_start+ustr.size());
                highlight_start = 0;
                highlight_end = -1;
                on_no_text_selected();
                parent.invalidate_rectangle(rect);
            }
            else
            {
                text_ = text_.substr(0,cursor_pos) + ustr +
                    text_.substr(cursor_pos,text_.size()-cursor_pos);
                move_cursor(cursor_pos+ustr.size());
            }
            unsigned long height;
            mfont->compute_size(text_,text_width,height,text_pos);

            // send out the text modified event
            if (text_modified_handler.is_set())
                text_modified_handler();
        }
    }

// ----------------------------------------------------------------------------------------

    void text_field::
    move_cursor (
        unsigned long pos
    )
    {
        using namespace std;
        const long old_cursor_pos = cursor_pos;

        if (text_pos >= pos)
        {
            // the cursor should go all the way to the left side of the text
            if (pos >= 6)
                text_pos = pos-6;
            else
                text_pos = 0;

            cursor_pos = pos;
            unsigned long height;
            mfont->compute_size(text_,text_width,height,text_pos);

            unsigned long width;
            unsigned long new_x = style->get_padding(*mfont);
            if (static_cast<long>(cursor_pos)-1 >= static_cast<long>(text_pos))
            {
                mfont->compute_size(text_,width,height,text_pos,cursor_pos-1);
                if (cursor_pos != 0)
                    new_x += width - mfont->right_overflow();
            }

            cursor_x = new_x;
        }
        else
        {
            unsigned long height;
            unsigned long width;
            mfont->compute_size(text_,width,height,text_pos,pos-1);

            unsigned long new_x = style->get_padding(*mfont) +
                width - mfont->right_overflow();

            // move the text to the left if necessary
            if (new_x + 4 > rect.width())
            {
                while (new_x > rect.width() - rect.width()/5)
                {
                    new_x -= (*mfont)[text_[text_pos]].width();
                    ++text_pos;
                }
            }

            cursor_x = new_x;
            cursor_pos = pos;
            mfont->compute_size(text_,text_width,height,text_pos);
        }

        parent.set_im_pos(rect.left()+cursor_x, rect.top());

        if (old_cursor_pos != cursor_pos)
        {
            if (shift_pos != -1)
            {
                highlight_start = std::min(shift_pos,cursor_pos);
                highlight_end = std::max(shift_pos,cursor_pos)-1;
            }
            else
            {
                highlight_start = 0;
                highlight_end = -1;
            }

            if (highlight_start > highlight_end)
                on_no_text_selected();
            else
                on_text_is_selected();

            recent_movement = true;
            cursor_visible = true;
            parent.invalidate_rectangle(rect);
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//             tabbed_display object methods
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    tabbed_display::
    tabbed_display(
        drawable_window& w
    ) :
        drawable(w,MOUSE_CLICK),
        selected_tab_(0),
        left_pad(6),
        right_pad(4),
        top_pad(3),
        bottom_pad(3)
    {
        rect = rectangle(0,0,40,mfont->height()+top_pad+bottom_pad);
        enable_events();
        tabs.set_max_size(1);
        tabs.set_size(1);
    }

// ----------------------------------------------------------------------------------------

    tabbed_display::
    ~tabbed_display(
    )
    {
        disable_events();
        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    void tabbed_display::
    set_pos (
        long x,
        long y
    )
    {
        auto_mutex M(m);
        // we have to adjust the positions of all the tab rectangles
        const long xdelta = rect.left() - x;
        const long ydelta = rect.top() - y;
        for (unsigned long i = 0; i < tabs.size(); ++i)
        {
            tabs[i].rect.set_left(tabs[i].rect.left()+xdelta);
            tabs[i].rect.set_right(tabs[i].rect.right()+xdelta);

            tabs[i].rect.set_top(tabs[i].rect.top()+ydelta);
            tabs[i].rect.set_bottom(tabs[i].rect.bottom()+ydelta);

            // adjust the position of the group associated with this tab if it exists
            if (tabs[i].group)
                tabs[i].group->set_pos(x+3, y+mfont->height()+top_pad+bottom_pad+3);
        }
        drawable::set_pos(x,y);
        recompute_tabs();
    }

// ----------------------------------------------------------------------------------------

    void tabbed_display::
    fit_to_contents (
    )
    {
        auto_mutex M(m);
        rectangle new_rect;
        point p(rect.left(),rect.top());
        new_rect += p;

        for (unsigned long i = 0; i < tabs.size(); ++i)
        {
            if (tabs[i].group)
            {
                tabs[i].group->fit_to_contents();
                new_rect += tabs[i].group->get_rect();
            }
        }

        // and give the new rect an additional 4 pixels on the bottom and right sides
        // so that the contents to hit the edge of the tabbed display
        new_rect = resize_rect(new_rect, new_rect.width()+4, new_rect.height()+4);

        parent.invalidate_rectangle(new_rect+rect);
        rect = new_rect;
    }

// ----------------------------------------------------------------------------------------

    void tabbed_display::
    set_size (
        unsigned long width,
        unsigned long height
    )
    {
        auto_mutex M(m);
        rectangle old(rect);
        const long x = rect.left();
        const long y = rect.top();
        rect.set_right(x+width-1);
        rect.set_bottom(y+height-1);

        recompute_tabs();

        parent.invalidate_rectangle(rect+old);
    }

// ----------------------------------------------------------------------------------------

    void tabbed_display::
    set_number_of_tabs (
        unsigned long num
    )
    {
        auto_mutex M(m);

        DLIB_ASSERT ( num > 0 ,
                "\tvoid tabbed_display::set_number_of_tabs()"
                << "\n\tnum:  " << num );

        tabs.set_max_size(num);
        tabs.set_size(num);

        selected_tab_ = 0;

        recompute_tabs();
        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    unsigned long tabbed_display::
    number_of_tabs (
    ) const
    {
        auto_mutex M(m);
        return tabs.size();
    }

// ----------------------------------------------------------------------------------------

    const std::string tabbed_display::
    tab_name (
        unsigned long idx
    ) const
    {
        return convert_wstring_to_mbstring(tab_wname(idx));
    }

    const std::wstring tabbed_display::
    tab_wname (
        unsigned long idx
    ) const
    {
        return convert_utf32_to_wstring(tab_uname(idx));
    }

    const dlib::ustring& tabbed_display::
    tab_uname (
        unsigned long idx
    ) const
    {
        auto_mutex M(m);

        DLIB_ASSERT ( idx < number_of_tabs() ,
                "\tvoid tabbed_display::tab_name()"
                << "\n\tidx:              " << idx
                << "\n\tnumber_of_tabs(): " << number_of_tabs() );

        return tabs[idx].name;
    }

// ----------------------------------------------------------------------------------------

    void tabbed_display::
    set_tab_name (
        unsigned long idx,
        const std::string& new_name
    )
    {
        set_tab_name(idx, convert_mbstring_to_wstring(new_name));
    }

    void tabbed_display::
    set_tab_name (
        unsigned long idx,
        const std::wstring& new_name
    )
    {
        set_tab_name(idx, convert_wstring_to_utf32(new_name));
    }

    void tabbed_display::
    set_tab_name (
        unsigned long idx,
        const dlib::ustring& new_name
    )
    {
        auto_mutex M(m);

        DLIB_ASSERT ( idx < number_of_tabs() ,
                "\tvoid tabbed_display::set_tab_name()"
                << "\n\tidx:              " << idx
                << "\n\tnumber_of_tabs(): " << number_of_tabs() );

        tabs[idx].name = new_name;
        // do this so that there isn't any reference counting going on
        tabs[idx].name[0] = tabs[idx].name[0];
        unsigned long height;
        mfont->compute_size(new_name,tabs[idx].width,height);

        recompute_tabs();

        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    void tabbed_display::
    on_mouse_down (
        unsigned long btn,
        unsigned long,
        long x,
        long y,
        bool
    )
    {
        if (rect.contains(x,y) && btn == base_window::LEFT && enabled && !hidden)
        {
            rectangle temp = rect;
            const long offset = mfont->height() + bottom_pad + top_pad;
            temp.set_bottom(rect.top()+offset);
            if (temp.contains(x,y))
            {
                // now we have to figure out which tab was clicked
                for (unsigned long i = 0; i < tabs.size(); ++i)
                {
                    if (selected_tab_ != i && tabs[i].rect.contains(x,y) &&
                        tabs[selected_tab_].rect.contains(x,y) == false)
                    {
                        unsigned long old_idx = selected_tab_;
                        selected_tab_ = i;
                        recompute_tabs();
                        parent.invalidate_rectangle(temp);

                        // adjust the widget_group objects for these tabs if they exist
                        if (tabs[i].group)
                            tabs[i].group->show();
                        if (tabs[old_idx].group)
                            tabs[old_idx].group->hide();

                        if (event_handler.is_set())
                            event_handler(i,old_idx);
                        break;
                    }
                }
            }
        }
    }

// ----------------------------------------------------------------------------------------

    void tabbed_display::
    set_tab_group (
        unsigned long idx,
        widget_group& group
    )
    {
        auto_mutex M(m);

        DLIB_ASSERT ( idx < number_of_tabs() ,
                "\tvoid tabbed_display::set_tab_group()"
                << "\n\tidx:              " << idx
                << "\n\tnumber_of_tabs(): " << number_of_tabs() );

        tabs[idx].group = &group;
        group.set_pos(rect.left()+3,rect.top()+mfont->height()+top_pad+bottom_pad+2);
        if (idx == selected_tab_)
            group.show();
        else
            group.hide();
    }

// ----------------------------------------------------------------------------------------

    void tabbed_display::
    disable (
    )
    {
        auto_mutex M(m);
        if (tabs[selected_tab_].group)
            tabs[selected_tab_].group->disable();
        drawable::disable();
    }

// ----------------------------------------------------------------------------------------

    void tabbed_display::
    enable (
    )
    {
        auto_mutex M(m);
        if (tabs[selected_tab_].group)
            tabs[selected_tab_].group->enable();
        drawable::enable();
    }

// ----------------------------------------------------------------------------------------

    void tabbed_display::
    hide (
    )
    {
        auto_mutex M(m);
        if (tabs[selected_tab_].group)
            tabs[selected_tab_].group->hide();
        drawable::hide();
    }

// ----------------------------------------------------------------------------------------

    void tabbed_display::
    show (
    )
    {
        auto_mutex M(m);
        if (tabs[selected_tab_].group)
            tabs[selected_tab_].group->show();
        drawable::show();
    }

// ----------------------------------------------------------------------------------------

    void tabbed_display::
    draw (
        const canvas& c
    ) const
    {
        rectangle area = rect.intersect(c);
        if (area.is_empty())
            return;

        // draw the main border first
        rectangle main_box(rect.left(),rect.top()+mfont->height()+top_pad+bottom_pad,rect.right(),rect.bottom());
        draw_button_up(c,main_box);
        draw_pixel(c,point(main_box.right()-1,main_box.top()),rgb_pixel(128,128,128));

        rgb_pixel color;
        if (enabled)
        {
            color.red = 0;
            color.green = 0;
            color.blue = 0;
        }
        else
        {
            color.red = 128;
            color.green = 128;
            color.blue = 128;
        }

        // draw the tabs
        for (unsigned long i = 0; i < tabs.size(); ++i)
        {
            if (selected_tab_ != i)
                draw_tab(tabs[i].rect,c);

            // draw the name string
            rectangle temp = tabs[i].rect;
            temp.set_top(temp.top()+top_pad);
            temp.set_bottom(temp.bottom()+bottom_pad);
            temp.set_left(temp.left()+left_pad);
            temp.set_right(temp.right()+right_pad);
            mfont->draw_string(c,temp,tabs[i].name,color);
        }
        draw_tab(tabs[selected_tab_].rect,c);
        draw_line(c,
            point(tabs[selected_tab_].rect.left()+1,
            tabs[selected_tab_].rect.bottom()),
            point(tabs[selected_tab_].rect.right()-2,
            tabs[selected_tab_].rect.bottom()),
            rgb_pixel(212,208,200));
    }

// ----------------------------------------------------------------------------------------

    void tabbed_display::
    draw_tab (
        const rectangle& tab,
        const canvas& c
    ) const
    {
        const rgb_pixel white(255,255,255);
        const rgb_pixel background(212,208,200);
        const rgb_pixel dark_gray(64,64,64);
        const rgb_pixel gray(128,128,128);
        draw_line(c,point(tab.left(),tab.top()+2),point(tab.left(),tab.bottom()),white);
        draw_line(c,point(tab.left()+1,tab.top()+2),point(tab.left()+1,tab.bottom()),background);
        draw_line(c,point(tab.right(),tab.top()+2),point(tab.right(),tab.bottom()),dark_gray);
        draw_line(c,point(tab.right()-1,tab.top()+2),point(tab.right()-1,tab.bottom()),gray);
        draw_line(c,point(tab.left()+2,tab.top()),point(tab.right()-2,tab.top()),white);
        draw_pixel(c,point(tab.left()+1,tab.top()+1),white);
        draw_pixel(c,point(tab.right()-1,tab.top()+1),dark_gray);
    }

// ----------------------------------------------------------------------------------------

    void tabbed_display::
    set_main_font (
        const shared_ptr_thread_safe<font>& f
    )
    {
        auto_mutex M(m);
        mfont = f;

        for (unsigned long i = 0; i < tabs.size(); ++i)
        {
            unsigned long height;
            mfont->compute_size(tabs[i].name,tabs[i].width,height);
        }

        recompute_tabs();
        set_pos(rect.left(), rect.top());

        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    void tabbed_display::
    recompute_tabs (
    )
    {
        const long offset = mfont->height() + bottom_pad + top_pad;

        // figure out the size and position of all the tabs
        rectangle sel_tab_rect, other_tab;
        sel_tab_rect.set_top(rect.top());
        sel_tab_rect.set_bottom(rect.top()+offset);

        other_tab.set_top(rect.top()+2);
        other_tab.set_bottom(rect.top()+offset-1);

        long cur_x = rect.left();
        for (unsigned long i = 0; i < tabs.size(); ++i)
        {
            const unsigned long str_width = tabs[i].width;
            if (selected_tab_ != i)
            {
                other_tab.set_left(cur_x);
                cur_x += left_pad + str_width + right_pad;
                other_tab.set_right(cur_x);
                tabs[i].rect = other_tab;
                ++cur_x;

            }
            else
            {
                if (i != 0)
                    sel_tab_rect.set_left(cur_x-2);
                else
                    sel_tab_rect.set_left(cur_x);

                cur_x += left_pad + str_width + right_pad;

                if (i != tabs.size()-1)
                    sel_tab_rect.set_right(cur_x+2);
                else
                    sel_tab_rect.set_right(cur_x);
                ++cur_x;

                tabs[i].rect = sel_tab_rect;
            }
        }

        // make sure this object is wide enough
        const rectangle& last = tabs[tabs.size()-1].rect;
        const rectangle& first = tabs[0].rect;
        rect = last + rect + first;

    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//             named_rectangle object methods
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    named_rectangle::
    named_rectangle(
        drawable_window& w
    ) :
        drawable(w),
        name_width(0),
        name_height(0)
    {
        make_name_fit_in_rect();
        enable_events();
    }

// ----------------------------------------------------------------------------------------

    named_rectangle::
    ~named_rectangle(
    )
    {
        disable_events();
        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    void named_rectangle::
    set_size (
        unsigned long width,
        unsigned long height
    )
    {
        auto_mutex M(m);
        rectangle old(rect);
        const long x = rect.left();
        const long y = rect.top();
        rect.set_right(x+width-1);
        rect.set_bottom(y+height-1);

        make_name_fit_in_rect();
        parent.invalidate_rectangle(rect+old);
    }

// ----------------------------------------------------------------------------------------

    void named_rectangle::
    wrap_around (
        const rectangle& r
    )
    {
        auto_mutex M(m);
        rectangle old(rect);
        const unsigned long pad = name_height/2;

        rect = rectangle(r.left()-pad, r.top()-name_height*4/3, r.right()+pad, r.bottom()+pad);

        make_name_fit_in_rect();
        parent.invalidate_rectangle(rect+old);
    }

// ----------------------------------------------------------------------------------------

    void named_rectangle::
    set_main_font (
        const shared_ptr_thread_safe<font>& f
    )
    {
        auto_mutex M(m);
        mfont = f;
        mfont->compute_size(name_,name_width,name_height);
        make_name_fit_in_rect();
        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    void named_rectangle::
    make_name_fit_in_rect (
    )
    {
        // make sure the named rectangle is big enough to contain the name
        const unsigned long wtemp = mfont->height() + name_width;
        const unsigned long htemp = mfont->height() + name_height;
        if (rect.width() < wtemp)
            rect.set_right(rect.left() + wtemp - 1 );
        if (rect.height() < htemp)
            rect.set_bottom(rect.bottom() + htemp - 1 );
    }

// ----------------------------------------------------------------------------------------

    void named_rectangle::
    set_name (
        const std::string& name
    )
    {
        set_name(convert_mbstring_to_wstring(name));
    }

    void named_rectangle::
    set_name (
        const std::wstring& name
    )
    {
        set_name(convert_wstring_to_utf32(name));
    }

    void named_rectangle::
    set_name (
        const dlib::ustring& name
    )
    {
        auto_mutex M(m);
        name_ = name.c_str();
        mfont->compute_size(name_,name_width,name_height);

        make_name_fit_in_rect();
        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    const std::string named_rectangle::
    name (
    ) const
    {
        return convert_wstring_to_mbstring(wname());
    }

    const std::wstring named_rectangle::
    wname (
    ) const
    {
        return convert_utf32_to_wstring(uname());
    }

    const dlib::ustring named_rectangle::
    uname (
    ) const
    {
        auto_mutex M(m);
        return dlib::ustring(name_.c_str());
    }

// ----------------------------------------------------------------------------------------

    void named_rectangle::
    draw (
        const canvas& c
    ) const
    {
        rectangle area = rect.intersect(c);
        if (area.is_empty())
            return;

        const unsigned long gap = mfont->height()/2;
        rectangle strrect = rect;
        strrect.set_left(rect.left() + gap);

        const unsigned long rtop = rect.top() + name_height/2;

        const rgb_pixel white(255,255,255);
        const rgb_pixel gray(128,128,128);

        mfont->draw_string(c,strrect,name_);
        draw_line(c,point(rect.left(), rtop),
                  point(rect.left()+gap/2, rtop), gray);
        draw_line(c,point(rect.left(), rtop),
                  point(rect.left(), rect.bottom()-1), gray);
        draw_line(c,point(rect.left(), rect.bottom()-1),
                  point(rect.right()-1, rect.bottom()-1), gray);
        draw_line(c,point(rect.right()-1, rtop),
                  point(rect.right()-1, rect.bottom()-2), gray);
        draw_line(c,point(strrect.left() + name_width + 2, rtop),
                  point(rect.right()-1, rtop), gray);

        draw_line(c,point(strrect.left() + name_width + 2, rtop+1),
                  point( rect.right()-2, rtop+1), white);
        draw_line(c,point(rect.right(), rtop),
                  point(rect.right(), rect.bottom()), white);
        draw_line(c,point(rect.left(), rect.bottom()),
                  point(rect.right(), rect.bottom()), white);
        draw_line(c,point(rect.left()+1, rtop+1),
                  point(rect.left()+1, rect.bottom()-2), white);
        draw_line(c,point(rect.left()+1, rtop+1),
                  point(rect.left()+gap/2, rtop+1), white);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class mouse_tracker
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    mouse_tracker::
    mouse_tracker(
        drawable_window& w
    ) :
        draggable(w),
        offset(18),
        nr(w),
        x_label(w),
        y_label(w),
        click_x(-1),
        click_y(-1)
    {
        set_draggable_area(rectangle(0,0,500,500));

        x_label.set_text("x: ");
        y_label.set_text("y: ");
        nr.set_name("mouse position");

        x_label.set_pos(offset,offset);
        y_label.set_pos(x_label.get_rect().left(), x_label.get_rect().bottom()+3);

        nr.wrap_around(x_label.get_rect() + y_label.get_rect());
        rect = nr.get_rect();

        set_z_order(2000000000);
        x_label.set_z_order(2000000001);
        y_label.set_z_order(2000000001);
        nr.set_z_order(2000000001);

        enable_events();
    }

// ----------------------------------------------------------------------------------------

    mouse_tracker::
    ~mouse_tracker(
    )
    {
        disable_events();
        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    void mouse_tracker::
    set_main_font (
        const shared_ptr_thread_safe<font>& f
    )
    {
        auto_mutex M(m);
        nr.set_main_font(f);
        x_label.set_main_font(f);
        y_label.set_main_font(f);
        mfont = f;
        nr.wrap_around(x_label.get_rect() + y_label.get_rect());
        rect = nr.get_rect();
    }

// ----------------------------------------------------------------------------------------

    void mouse_tracker::
    set_pos (
        long x,
        long y
    )
    {
        draggable::set_pos(x,y);
        nr.set_pos(x,y);
        x_label.set_pos(rect.left()+offset,rect.top()+offset);
        y_label.set_pos(x_label.get_rect().left(), x_label.get_rect().bottom()+3);
    }

// ----------------------------------------------------------------------------------------

    void mouse_tracker::
    show (
    )
    {
        draggable::show();
        nr.show();
        x_label.show();
        y_label.show();
    }

// ----------------------------------------------------------------------------------------

    void mouse_tracker::
    hide (
    )
    {
        draggable::hide();
        nr.hide();
        x_label.hide();
        y_label.hide();
    }

// ----------------------------------------------------------------------------------------

    void mouse_tracker::
    enable (
    )
    {
        draggable::enable();
        nr.enable();
        x_label.enable();
        y_label.enable();
    }

// ----------------------------------------------------------------------------------------

    void mouse_tracker::
    disable (
    )
    {
        draggable::disable();
        nr.disable();
        x_label.disable();
        y_label.disable();
    }

// ----------------------------------------------------------------------------------------

    void mouse_tracker::
    on_mouse_down (
        unsigned long btn,
        unsigned long state,
        long x,
        long y,
        bool double_clicked
    )
    {
        draggable::on_mouse_down(btn,state,x,y,double_clicked);
        if ((state & base_window::SHIFT) && (btn == base_window::LEFT) && enabled && !hidden)
        {
            parent.invalidate_rectangle(rectangle(x,y,x,y));
            parent.invalidate_rectangle(rectangle(click_x,click_y,click_x,click_y));
            click_x = x;
            click_y = y;

            y_label.set_text("y: 0");
            x_label.set_text("x: 0");
        }
    }

// ----------------------------------------------------------------------------------------

    void mouse_tracker::
    on_mouse_move (
        unsigned long state,
        long x,
        long y
    )
    {
        if (!hidden && enabled)
        {
            parent.invalidate_rectangle(rect);
            draggable::on_mouse_move(state,x,y);

            long dx = 0;
            long dy = 0;
            if (click_x != -1)
                dx = click_x;
            if (click_y != -1)
                dy = click_y;

            sout.str("");
            sout << "y: " << y - dy;
            y_label.set_text(sout.str());

            sout.str("");
            sout << "x: " << x - dx;
            x_label.set_text(sout.str());
        }
    }

// ----------------------------------------------------------------------------------------

    void mouse_tracker::
    on_drag (
    )
    {
        nr.set_pos(rect.left(),rect.top());
        x_label.set_pos(rect.left()+offset,rect.top()+offset);
        y_label.set_pos(x_label.get_rect().left(), x_label.get_rect().bottom()+3);

        long x = 0;
        long y = 0;
        if (click_x != -1)
            x = click_x;
        if (click_y != -1)
            y = click_y;

        sout.str("");
        sout << "y: " << lasty - y;
        y_label.set_text(sout.str());

        sout.str("");
        sout << "x: " << lastx - x;
        x_label.set_text(sout.str());
    }

// ----------------------------------------------------------------------------------------

    void mouse_tracker::
    draw (
        const canvas& c
    ) const
    {
        fill_rect(c, rect,rgb_pixel(212,208,200));
        draw_pixel(c, point(click_x,click_y),rgb_pixel(255,0,0));
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class list_box
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    namespace list_box_helper{
    template <typename S>
    list_box<S>::
    list_box(
        drawable_window& w
    ) :
        scrollable_region(w,MOUSE_WHEEL|MOUSE_CLICK),
        ms_enabled(false),
        last_selected(0)
    {
        set_vertical_scroll_increment(mfont->height());
        set_horizontal_scroll_increment(mfont->height());

        style.reset(new list_box_style_default());
        enable_events();
    }

// ----------------------------------------------------------------------------------------

    template <typename S>
    list_box<S>::
    ~list_box(
    )
    {
        disable_events();
        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    template <typename S>
    void list_box<S>::
    set_main_font (
        const shared_ptr_thread_safe<font>& f
    )
    {
        auto_mutex M(m);
        mfont = f;
        // recompute the sizes of all the items
        for (unsigned long i = 0; i < items.size(); ++i)
        {
            mfont->compute_size(items[i].name,items[i].width, items[i].height);
        }
        set_vertical_scroll_increment(mfont->height());
        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    template <typename S>
    bool list_box<S>::
    is_selected (
        unsigned long index
    ) const
    {
        auto_mutex M(m);
        DLIB_ASSERT ( index < size() ,
                "\tbool list_box::is_selected(index)"
                << "\n\tindex:  " << index
                << "\n\tsize(): " << size() );

        return items[index].is_selected;
    }

// ----------------------------------------------------------------------------------------

    template <typename S>
    void list_box<S>::
    select (
        unsigned long index
    )
    {
        auto_mutex M(m);
        DLIB_ASSERT ( index < size() ,
                "\tvoid list_box::select(index)"
                << "\n\tindex:  " << index
                << "\n\tsize(): " << size() );

        last_selected = index;
        items[index].is_selected = true;
        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    template <typename S>
    void list_box<S>::
    unselect (
        unsigned long index
    )
    {
        auto_mutex M(m);
        DLIB_ASSERT ( index < size() ,
                "\tvoid list_box::unselect(index)"
                << "\n\tindex:  " << index
                << "\n\tsize(): " << size() );
        items[index].is_selected = false;
        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    template <typename S>
    const S& list_box<S>::operator [] (
        unsigned long index
    ) const
    {
        auto_mutex M(m);
        DLIB_ASSERT ( index < size() ,
                "\tconst std::string& list_box::operator[](index)"
                << "\n\tindex:  " << index
                << "\n\tsize(): " << size() );
        return items[index].name;
    }

// ----------------------------------------------------------------------------------------

    template <typename S>
    bool list_box<S>::
    multiple_select_enabled (
    ) const
    {
        auto_mutex M(m);
        return ms_enabled;
    }

// ----------------------------------------------------------------------------------------

    template <typename S>
    void list_box<S>::
    enable_multiple_select (
    )
    {
        auto_mutex M(m);
        ms_enabled = true;
    }

// ----------------------------------------------------------------------------------------

    template <typename S>
    void list_box<S>::
    disable_multiple_select (
    )
    {
        auto_mutex M(m);
        ms_enabled = false;
    }

// ----------------------------------------------------------------------------------------

    template <typename S>
    bool list_box<S>::
    at_start (
    ) const
    {
        auto_mutex M(m);
        return items.at_start();
    }

// ----------------------------------------------------------------------------------------

    template <typename S>
    void list_box<S>::
    reset (
    ) const
    {
        auto_mutex M(m);
        items.reset();
    }

// ----------------------------------------------------------------------------------------

    template <typename S>
    bool list_box<S>::
    current_element_valid (
    ) const
    {
        auto_mutex M(m);
        return items.current_element_valid();
    }

// ----------------------------------------------------------------------------------------

    template <typename S>
    const S &list_box<S>::
    element (
    ) const
    {
        auto_mutex M(m);
        DLIB_ASSERT ( current_element_valid() ,
                "\tconst std::string& list_box::element()"
                 );
        return items.element().name;
    }

// ----------------------------------------------------------------------------------------

    template <typename S>
    const S &list_box<S>::
    element (
    )
    {
        auto_mutex M(m);
        DLIB_ASSERT ( current_element_valid() ,
                "\tconst std::string& list_box::element()"
                 );
        return items.element().name;
    }

// ----------------------------------------------------------------------------------------

    template <typename S>
    bool list_box<S>::
    move_next (
    ) const
    {
        auto_mutex M(m);
        return items.move_next();
    }

// ----------------------------------------------------------------------------------------

    template <typename S>
    unsigned long list_box<S>::
    size (
    ) const
    {
        auto_mutex M(m);
        return items.size();
    }

// ----------------------------------------------------------------------------------------

    template <typename S>
    void list_box<S>::
    draw (
        const canvas& c
    ) const
    {
        scrollable_region::draw(c);

        rectangle area = display_rect().intersect(c);
        if (area.is_empty())
            return;

        style->draw_list_box_background(c, display_rect(), enabled);

        long y = total_rect().top();
        for (unsigned long i = 0; i < items.size(); ++i)
        {
            if (y+(long)items[i].height <= area.top())
            {
                y += items[i].height;
                continue;
            }

            rectangle r(total_rect().left(), y, display_rect().right(), y+items[i].height-1);

            style->draw_list_box_item(c,r, display_rect(), enabled, *mfont, items[i].name, items[i].is_selected);

            y += items[i].height;

            if (y > area.bottom())
                break;
        }
    }

// ----------------------------------------------------------------------------------------

    template <typename S>
    void list_box<S>::
    on_mouse_down (
        unsigned long btn,
        unsigned long state,
        long x,
        long y,
        bool is_double_click
    )
    {
        if (display_rect().contains(x,y) && btn == base_window::LEFT && enabled && !hidden )
        {
            if ( ms_enabled == false ||
                 ((!(state&base_window::CONTROL)) && !(state&base_window::SHIFT)))
            {
                items.reset();
                while (items.move_next())
                {
                    items.element().is_selected = false;
                }
            }

            y -= total_rect().top();
            long h = 0;
            for (unsigned long i = 0; i < items.size(); ++i)
            {
                h += items[i].height;
                if (h >= y)
                {
                    if (ms_enabled)
                    {
                        if (state&base_window::CONTROL)
                        {
                            items[i].is_selected = !items[i].is_selected;
                            if (items[i].is_selected)
                                last_selected = i;
                        }
                        else if (state&base_window::SHIFT)
                        {
                            // we want to select everything between (and including) the
                            // current thing clicked and last_selected.
                            const unsigned long first = std::min(i,last_selected);
                            const unsigned long last = std::max(i,last_selected);
                            for (unsigned long j = first; j <= last; ++j)
                                items[j].is_selected = true;
                        }
                        else
                        {
                            items[i].is_selected = true;
                            last_selected = i;
                            if (is_double_click && event_handler.is_set())
                                event_handler(i);
                            else if (single_click_event_handler.is_set())
                                single_click_event_handler(i);
                        }
                    }
                    else
                    {
                        items[i].is_selected = true;
                        last_selected = i;
                        if (is_double_click && event_handler.is_set())
                            event_handler(i);
                        else if (single_click_event_handler.is_set())
                            single_click_event_handler(i);
                    }

                    break;
                }
            }

            parent.invalidate_rectangle(rect);
        }
    }

// ----------------------------------------------------------------------------------------

    template <typename S>
    unsigned long list_box<S>::
    get_selected (
    ) const
    {
        auto_mutex M(m);
        DLIB_ASSERT ( multiple_select_enabled() == false,
                "\tunsigned long list_box::get_selected()"
                 );
        for (unsigned long i = 0; i < items.size(); ++i)
        {
            if (items[i].is_selected)
                return i;
        }
        return items.size();
    }
// ----------------------------------------------------------------------------------------

   // making instance of template
   template class list_box<std::string>;
   template class list_box<std::wstring>;
   template class list_box<dlib::ustring>;
   }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // function message_box()
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    namespace message_box_helper
    {
        void box_win::
        initialize (
        )
        {
            msg.set_pos(20,20);
            msg.set_text(message);
            rectangle msg_rect = msg.get_rect();
            btn_ok.set_name("OK");
            btn_ok.set_size(60,btn_ok.height());
            if (msg_rect.width() >= 60)
                btn_ok.set_pos(msg_rect.width()/2+msg_rect.left()-btn_ok.width()/2,msg_rect.bottom()+15);
            else
                btn_ok.set_pos(20,msg_rect.bottom()+15);
            btn_ok.set_click_handler(*this,&box_win::on_click);

            rectangle size = btn_ok.get_rect() + msg_rect;
            set_size(size.right()+20,size.bottom()+20);

            show();
            set_title(title);
        }

    // ------------------------------------------------------------------------------------

        box_win::
        box_win (
            const std::string& title_,
            const std::string& message_
        ) :
            drawable_window(false),
            title(convert_mbstring_to_wstring(title_)),
            message(convert_mbstring_to_wstring(message_)),
            msg(*this),
            btn_ok(*this)
        {
            initialize();
        }

    // ------------------------------------------------------------------------------------

        box_win::
        box_win (
            const std::wstring& title_,
            const std::wstring& message_
        ) :
            drawable_window(false),
            title(title_),
            message(message_),
            msg(*this),
            btn_ok(*this)
        {
            initialize();
        }

    // ------------------------------------------------------------------------------------

        box_win::
        box_win (
            const dlib::ustring& title_,
            const dlib::ustring& message_
        ) :
            drawable_window(false),
            title(convert_utf32_to_wstring(title_)),
            message(convert_utf32_to_wstring(message_)),
            msg(*this),
            btn_ok(*this)
        {
            initialize();
        }

    // ------------------------------------------------------------------------------------

        box_win::
        ~box_win (
        )
        {
            close_window();
        }

    // ------------------------------------------------------------------------------------

        void box_win::
        deleter_thread (
            void* param
        )
        {
            // The point of this extra event_handler stuff is to allow the user
            // to end the program from within the callback.  So we want to destroy the
            // window *before* we call their callback.
            box_win& w = *static_cast<box_win*>(param);
            w.close_window();
            any_function<void()> event_handler(w.event_handler);
            delete &w;
            if (event_handler.is_set())
                event_handler();
        }

    // ------------------------------------------------------------------------------------

        void box_win::
        on_click (
        )
        {
            hide();
            create_new_thread(&deleter_thread,this);
        }

    // ------------------------------------------------------------------------------------

        base_window::on_close_return_code box_win::
        on_window_close (
        )
        {
            // The point of this extra event_handler stuff is to allow the user
            // to end the program within the callback.  So we want to destroy the
            // window *before* we call their callback.
            any_function<void()> event_handler_copy(event_handler);
            delete this;
            if (event_handler_copy.is_set())
                event_handler_copy();
            return CLOSE_WINDOW;
        }

    // ------------------------------------------------------------------------------------
    // ------------------------------------------------------------------------------------
    // ------------------------------------------------------------------------------------

        void blocking_box_win::
        initialize (
        )
        {
            msg.set_pos(20,20);
            msg.set_text(message);
            rectangle msg_rect = msg.get_rect();
            btn_ok.set_name("OK");
            btn_ok.set_size(60,btn_ok.height());
            if (msg_rect.width() >= 60)
                btn_ok.set_pos(msg_rect.width()/2+msg_rect.left()-btn_ok.width()/2,msg_rect.bottom()+15);
            else
                btn_ok.set_pos(20,msg_rect.bottom()+15);
            btn_ok.set_click_handler(*this,&blocking_box_win::on_click);

            rectangle size = btn_ok.get_rect() + msg_rect;
            set_size(size.right()+20,size.bottom()+20);

            set_title(title);
            show();
        }

    // ------------------------------------------------------------------------------------

        blocking_box_win::
        blocking_box_win (
            const std::string& title_,
            const std::string& message_
        ) :
            drawable_window(false),
            title(convert_mbstring_to_wstring(title_)),
            message(convert_mbstring_to_wstring(message_)),
            msg(*this),
            btn_ok(*this)
        {
            initialize();
        }

    // ------------------------------------------------------------------------------------

        blocking_box_win::
        blocking_box_win (
            const std::wstring& title_,
            const std::wstring& message_
        ) :
            drawable_window(false),
            title(title_),
            message(message_),
            msg(*this),
            btn_ok(*this)
        {
            initialize();
        }

    // ------------------------------------------------------------------------------------

        blocking_box_win::
        blocking_box_win (
            const dlib::ustring& title_,
            const dlib::ustring& message_
        ) :
            drawable_window(false),
            title(convert_utf32_to_wstring(title_)),
            message(convert_utf32_to_wstring(message_)),
            msg(*this),
            btn_ok(*this)
        {
            initialize();
        }

    // ------------------------------------------------------------------------------------

        blocking_box_win::
        ~blocking_box_win (
        )
        {
            close_window();
        }

    // ------------------------------------------------------------------------------------

        void blocking_box_win::
        on_click (
        )
        {
            close_window();
        }

    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // function open_file_box()
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    namespace open_file_box_helper
    {
        box_win::
        box_win (
            const std::string& title,
            bool has_text_field
        ) :
            lbl_dirs(*this),
            lbl_files(*this),
            lbl_file_name(*this),
            lb_dirs(*this),
            lb_files(*this),
            btn_ok(*this),
            btn_cancel(*this),
            btn_root(*this),
            tf_file_name(*this)
        {
            if (has_text_field == false)
            {
                tf_file_name.hide();
                lbl_file_name.hide();
            }
            else
            {
                lbl_file_name.set_text("File: ");
            }

            cur_dir = -1;
            set_size(500,300);

            lbl_dirs.set_text("Directories:");
            lbl_files.set_text("Files:");
            btn_ok.set_name("Ok");
            btn_cancel.set_name("Cancel");
            btn_root.set_name("/");

            btn_root.set_click_handler(*this,&box_win::on_root_click);
            btn_cancel.set_click_handler(*this,&box_win::on_cancel_click);
            btn_ok.set_click_handler(*this,&box_win::on_open_click);
            lb_dirs.set_double_click_handler(*this,&box_win::on_dirs_click);
            lb_files.set_click_handler(*this,&box_win::on_files_click);
            lb_files.set_double_click_handler(*this,&box_win::on_files_double_click);

            btn_root.set_pos(5,5);

            set_sizes();
            set_title(title);

            on_root_click();

            // make it so that the file box starts out in our current working
            // directory
            std::string full_name(get_current_dir());

            while (full_name.size() > 0)
            {
                std::string::size_type pos = full_name.find_first_of("\\/");
                std::string left(full_name.substr(0,pos));
                if (pos != std::string::npos)
                    full_name = full_name.substr(pos+1);
                else
                    full_name.clear();

                if (left.size() > 0)
                    enter_folder(left);
            }

            show();
        }

    // ------------------------------------------------------------------------------------

        box_win::
        ~box_win (
        )
        {
            close_window();
        }

    // ------------------------------------------------------------------------------------

        void box_win::
        set_sizes(
        )
        {
            unsigned long width, height;
            get_size(width,height);

            if (lbl_file_name.is_hidden())
            {
                lbl_dirs.set_pos(0,btn_root.bottom()+5);
                lb_dirs.set_pos(0,lbl_dirs.bottom());
                lb_dirs.set_size(width/2,height-lb_dirs.top()-btn_cancel.height()-10);

                lbl_files.set_pos(lb_dirs.right(),btn_root.bottom()+5);
                lb_files.set_pos(lb_dirs.right(),lbl_files.bottom());
                lb_files.set_size(width-lb_files.left(),height-lb_files.top()-btn_cancel.height()-10);

                btn_ok.set_pos(width - btn_ok.width()-25,lb_files.bottom()+5);
                btn_cancel.set_pos(btn_ok.left() - btn_cancel.width()-5,lb_files.bottom()+5);
            }
            else
            {

                lbl_dirs.set_pos(0,btn_root.bottom()+5);
                lb_dirs.set_pos(0,lbl_dirs.bottom());
                lb_dirs.set_size(width/2,height-lb_dirs.top()-btn_cancel.height()-10-tf_file_name.height());

                lbl_files.set_pos(lb_dirs.right(),btn_root.bottom()+5);
                lb_files.set_pos(lb_dirs.right(),lbl_files.bottom());
                lb_files.set_size(width-lb_files.left(),height-lb_files.top()-btn_cancel.height()-10-tf_file_name.height());

                lbl_file_name.set_pos(lb_files.left(), lb_files.bottom()+8);
                tf_file_name.set_pos(lbl_file_name.right(), lb_files.bottom()+5);
                tf_file_name.set_width(width-tf_file_name.left()-5);

                btn_ok.set_pos(width - btn_ok.width()-25,tf_file_name.bottom()+5);
                btn_cancel.set_pos(btn_ok.left() - btn_cancel.width()-5,tf_file_name.bottom()+5);
            }

        }

    // ------------------------------------------------------------------------------------

        void box_win::
        on_window_resized (
        )
        {
            set_sizes();
        }

    // ------------------------------------------------------------------------------------

        void box_win::
        deleter_thread (
        )
        {
            close_window();
            delete this;
        }

    // ------------------------------------------------------------------------------------

        void box_win::
        enter_folder (
            const std::string& folder_name
        )
        {
            if (btn_root.is_checked())
                btn_root.set_unchecked();
            if (cur_dir != -1)
                sob[cur_dir]->set_unchecked();

            const std::string old_path = path;
            const long old_cur_dir = cur_dir;

            scoped_ptr<toggle_button> new_btn(new toggle_button(*this));
            new_btn->set_name(folder_name);
            new_btn->set_click_handler(*this,&box_win::on_path_button_click);

            // remove any path buttons that won't be part of the path anymore
            if (sob.size())
            {
                while (sob.size() > (unsigned long)(cur_dir+1))
                {
                    scoped_ptr<toggle_button> junk;
                    sob.remove(cur_dir+1,junk);
                }
            }

            if (sob.size())
                new_btn->set_pos(sob[sob.size()-1]->right()+5,sob[sob.size()-1]->top());
            else
                new_btn->set_pos(btn_root.right()+5,btn_root.top());

            cur_dir = sob.size();
            sob.add(sob.size(),new_btn);

            path += folder_name + directory::get_separator();
            if (set_dir(prefix + path) == false)
            {
                sob.remove(sob.size()-1,new_btn);
                path = old_path;
                cur_dir = old_cur_dir;
            }
            else
            {

                sob[cur_dir]->set_checked();
            }
        }

    // ------------------------------------------------------------------------------------

        void box_win::
        on_dirs_click (
            unsigned long idx
        )
        {
            enter_folder(lb_dirs[idx]);
        }

    // ------------------------------------------------------------------------------------

        void box_win::
        on_files_click (
            unsigned long idx
        )
        {
            if (tf_file_name.is_hidden() == false)
            {
                tf_file_name.set_text(lb_files[idx]);
            }
        }

    // ------------------------------------------------------------------------------------

        void box_win::
        on_files_double_click (
            unsigned long
        )
        {
            on_open_click();
        }

    // ------------------------------------------------------------------------------------

        void box_win::
        on_cancel_click (
        )
        {
            hide();
            create_new_thread<box_win,&box_win::deleter_thread>(*this);
        }

    // ------------------------------------------------------------------------------------

        void box_win::
        on_open_click (
        )
        {
            if (lb_files.get_selected() != lb_files.size() || tf_file_name.text().size() > 0)
            {
                if (event_handler.is_set())
                {
                    if (tf_file_name.is_hidden())
                        event_handler(prefix + path + lb_files[lb_files.get_selected()]);
                    else if (tf_file_name.text().size() > 0)
                        event_handler(prefix + path + tf_file_name.text());
                }
                hide();
                create_new_thread<box_win,&box_win::deleter_thread>(*this);
            }
        }

    // ------------------------------------------------------------------------------------

        void box_win::
        on_path_button_click (
            toggle_button& btn
        )
        {
            if (btn_root.is_checked())
                btn_root.set_unchecked();
            if (cur_dir != -1)
                sob[cur_dir]->set_unchecked();
            std::string new_path;

            for (unsigned long i = 0; i < sob.size(); ++i)
            {
                new_path += sob[i]->name() + directory::get_separator();
                if (sob[i].get() == &btn)
                {
                    cur_dir = i;
                    sob[i]->set_checked();
                    break;
                }
            }
            if (path != new_path)
            {
                path = new_path;
                set_dir(prefix+path);
            }
        }

    // ------------------------------------------------------------------------------------

        struct case_insensitive_compare
        {
            bool operator() (
                const std::string& a,
                const std::string& b
            ) const
            {
                std::string::size_type i, size;
                size = std::min(a.size(),b.size());
                for (i = 0; i < size; ++i)
                {
                    if (std::tolower(a[i]) < std::tolower(b[i]))
                        return true;
                    else if (std::tolower(a[i]) > std::tolower(b[i]))
                        return false;
                }
                if (a.size() < b.size())
                    return true;
                else
                    return false;
            }
        };

    // ------------------------------------------------------------------------------------

        bool box_win::
        set_dir (
            const std::string& dir
        )
        {
            try
            {
                directory d(dir);
                queue<directory>::kernel_1a_c qod;
                queue<file>::kernel_1a_c qof;
                queue<std::string>::sort_1a_c qos;
                d.get_dirs(qod);
                d.get_files(qof);

                qod.reset();
                while (qod.move_next())
                {
                    std::string temp = qod.element().name();
                    qos.enqueue(temp);
                }
                qos.sort(case_insensitive_compare());
                lb_dirs.load(qos);
                qos.clear();

                qof.reset();
                while (qof.move_next())
                {
                    std::string temp = qof.element().name();
                    qos.enqueue(temp);
                }
                qos.sort(case_insensitive_compare());
                lb_files.load(qos);
                return true;
            }
            catch (directory::listing_error& )
            {
                return false;
            }
            catch (directory::dir_not_found&)
            {
                return false;
            }
        }

    // ------------------------------------------------------------------------------------

        void box_win::
        on_root_click (
        )
        {
            btn_root.set_checked();
            if (cur_dir != -1)
                sob[cur_dir]->set_unchecked();

            queue<directory>::kernel_1a_c qod, qod2;
            queue<file>::kernel_1a_c qof;
            queue<std::string>::sort_1a_c qos;
            get_filesystem_roots(qod);
            path.clear();
            cur_dir = -1;
            if (qod.size() == 1)
            {
                qod.current().get_files(qof);
                qod.current().get_dirs(qod2);
                prefix = qod.current().full_name();

                qod2.reset();
                while (qod2.move_next())
                {
                    std::string temp = qod2.element().name();
                    qos.enqueue(temp);
                }
                qos.sort(case_insensitive_compare());
                lb_dirs.load(qos);
                qos.clear();

                qof.reset();
                while (qof.move_next())
                {
                    std::string temp = qof.element().name();
                    qos.enqueue(temp);
                }
                qos.sort(case_insensitive_compare());
                lb_files.load(qos);
            }
            else
            {
                prefix.clear();
                qod.reset();
                while (qod.move_next())
                {
                    std::string temp = qod.element().full_name();
                    temp = temp.substr(0,temp.size()-1);
                    qos.enqueue(temp);
                }
                qos.sort(case_insensitive_compare());
                lb_dirs.load(qos);
                qos.clear();
                lb_files.load(qos);
            }
        }

    // ------------------------------------------------------------------------------------

        base_window::on_close_return_code box_win::
        on_window_close (
        )
        {
            delete this;
            return CLOSE_WINDOW;
        }

    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class menu_bar
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    menu_bar::
    menu_bar(
        drawable_window& w
    ) :
        drawable(w, 0xFFFF), // listen for all events
        open_menu(0)
    {
        adjust_position();
        enable_events();
    }

// ----------------------------------------------------------------------------------------

    menu_bar::
    ~menu_bar()
    {
        disable_events();
        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    void menu_bar::
    set_main_font (
        const shared_ptr_thread_safe<font>& f
    )
    {
        auto_mutex M(m);
        mfont = f;
        adjust_position();
        compute_menu_geometry();
        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    void menu_bar::
    set_number_of_menus (
        unsigned long num
    )
    {
        auto_mutex M(m);
        menus.set_max_size(num);
        menus.set_size(num);
        open_menu = menus.size();
        compute_menu_geometry();

        for (unsigned long i = 0; i < menus.size(); ++i)
        {
            menus[i].menu.set_on_hide_handler(*this,&menu_bar::on_popup_hide);
        }

        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    unsigned long menu_bar::
    number_of_menus (
    ) const
    {
        auto_mutex M(m);
        return menus.size();
    }

// ----------------------------------------------------------------------------------------

    void menu_bar::
    set_menu_name (
        unsigned long idx,
        const std::string name,
        char underline_ch
    )
    {
        set_menu_name(idx, convert_mbstring_to_wstring(name), underline_ch);
    }

// ----------------------------------------------------------------------------------------

    void menu_bar::
    set_menu_name (
        unsigned long idx,
        const std::wstring name,
        char underline_ch
    )
    {
        set_menu_name(idx, convert_wstring_to_utf32(name), underline_ch);
    }

// ----------------------------------------------------------------------------------------

    void menu_bar::
    set_menu_name (
        unsigned long idx,
        const dlib::ustring name,
        char underline_ch
    )
    {
        DLIB_ASSERT ( idx < number_of_menus() ,
                      "\tvoid menu_bar::set_menu_name()"
                      << "\n\tidx:               " << idx
                      << "\n\tnumber_of_menus(): " << number_of_menus()
        );
        auto_mutex M(m);
        menus[idx].name = name.c_str();
        menus[idx].underline_pos = name.find_first_of(underline_ch);
        compute_menu_geometry();
        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    const std::string menu_bar::
    menu_name (
        unsigned long idx
    ) const
    {
        return convert_wstring_to_mbstring(menu_wname(idx));
    }

// ----------------------------------------------------------------------------------------

    const std::wstring menu_bar::
    menu_wname (
        unsigned long idx
    ) const
    {
        return convert_utf32_to_wstring(menu_uname(idx));
    }

// ----------------------------------------------------------------------------------------

    const dlib::ustring menu_bar::
    menu_uname (
        unsigned long idx
    ) const
    {
        DLIB_ASSERT ( idx < number_of_menus() ,
                      "\tstd::string menu_bar::menu_name()"
                      << "\n\tidx:               " << idx
                      << "\n\tnumber_of_menus(): " << number_of_menus()
        );
        auto_mutex M(m);
        return menus[idx].name.c_str();
    }

// ----------------------------------------------------------------------------------------

    popup_menu& menu_bar::
    menu (
        unsigned long idx
    )
    {
        DLIB_ASSERT ( idx < number_of_menus() ,
                      "\tpopup_menu& menu_bar::menu()"
                      << "\n\tidx:               " << idx
                      << "\n\tnumber_of_menus(): " << number_of_menus()
        );
        auto_mutex M(m);
        return menus[idx].menu;
    }

// ----------------------------------------------------------------------------------------

    const popup_menu& menu_bar::
    menu (
        unsigned long idx
    ) const
    {
        DLIB_ASSERT ( idx < number_of_menus() ,
                      "\tconst popup_menu& menu_bar::menu()"
                      << "\n\tidx:               " << idx
                      << "\n\tnumber_of_menus(): " << number_of_menus()
        );
        auto_mutex M(m);
        return menus[idx].menu;
    }

// ----------------------------------------------------------------------------------------

    void menu_bar::
    on_window_resized (
    )
    {
        adjust_position();
        hide_menu();
    }

// ----------------------------------------------------------------------------------------

    void menu_bar::
    draw (
        const canvas& c
    ) const
    {
        rectangle area(rect.intersect(c));
        if (area.is_empty())
            return;

        const unsigned char opacity = 40;
        fill_rect_with_vertical_gradient(c, rect,rgb_alpha_pixel(255,255,255,opacity),
                                         rgb_alpha_pixel(0,0,0,opacity));

        // first draw the border between the menu and the rest of the window
        draw_line(c, point(rect.left(),rect.bottom()-1),
                  point(rect.right(),rect.bottom()-1), 100);
        draw_line(c, point(rect.left(),rect.bottom()),
                  point(rect.right(),rect.bottom()), 255);

        // now draw all the menu buttons
        for (unsigned long i = 0; i < menus.size(); ++i)
        {
            mfont->draw_string(c,menus[i].rect, menus[i].name );
            if (menus[i].underline_p1 != menus[i].underline_p2)
                draw_line(c, menus[i].underline_p1, menus[i].underline_p2);

            if (open_menu == i)
            {
                fill_rect_with_vertical_gradient(c, menus[i].bgrect,rgb_alpha_pixel(255,255,0,40),  rgb_alpha_pixel(0,0,0,40));
            }
        }
    }

// ----------------------------------------------------------------------------------------

    void menu_bar::
    on_window_moved (
    )
    {
        hide_menu();
    }

// ----------------------------------------------------------------------------------------

    void menu_bar::
    on_focus_lost (
    )
    {
        hide_menu();
    }

// ----------------------------------------------------------------------------------------

    void menu_bar::
    on_mouse_down (
        unsigned long btn,
        unsigned long ,
        long x,
        long y,
        bool
    )
    {

        if (rect.contains(x,y) == false || btn != (unsigned long)base_window::LEFT)
        {
            hide_menu();
            return;
        }

        unsigned long old_menu = menus.size();

        // if a menu is currently open then save its index
        if (open_menu != menus.size())
        {
            old_menu = open_menu;
            hide_menu();
        }

        // figure out which menu should be open if any
        for (unsigned long i = 0; i < menus.size(); ++i)
        {
            if (menus[i].bgrect.contains(x,y))
            {
                if (old_menu != i)
                    show_menu(i);

                break;
            }
        }

    }

// ----------------------------------------------------------------------------------------

    void menu_bar::
    on_mouse_move (
        unsigned long ,
        long x,
        long y
    )
    {
        // if the mouse is over the menu_bar and some menu is currently open
        if (rect.contains(x,y) && open_menu != menus.size())
        {
            // if the mouse is still in the same rectangle then don't do anything
            if (menus[open_menu].bgrect.contains(x,y) == false)
            {
                // figure out which menu should be instead
                for (unsigned long i = 0; i < menus.size(); ++i)
                {
                    if (menus[i].bgrect.contains(x,y))
                    {
                        show_menu(i);
                        break;
                    }
                }

            }
        }
    }

// ----------------------------------------------------------------------------------------

    void menu_bar::
    on_keydown (
        unsigned long key,
        bool is_printable,
        unsigned long state
    )
    {
        if (state&base_window::KBD_MOD_ALT)
        {
            // check if the key matches any of our underlined keys
            for (unsigned long i = 0; i < menus.size(); ++i)
            {
                // if we have found a matching key
                if (is_printable &&
                    menus[i].underline_pos != std::string::npos &&
                    std::tolower(menus[i].name[menus[i].underline_pos]) == std::tolower(key))
                {
                    show_menu(i);
                    menus[open_menu].menu.select_first_item();
                    return;
                }
            }
        }

        if (open_menu != menus.size())
        {
            unsigned long i = open_menu;
            // if the submenu doesn't use this key for something then we will
            if (menus[open_menu].menu.forwarded_on_keydown(key,is_printable,state) == false)
            {
                if (key == base_window::KEY_LEFT)
                {
                    i = (i+menus.size()-1)%menus.size();
                    show_menu(i);
                    menus[open_menu].menu.select_first_item();
                }
                else if (key == base_window::KEY_RIGHT)
                {
                    i = (i+1)%menus.size();
                    show_menu(i);
                    menus[open_menu].menu.select_first_item();
                }
                else if (key == base_window::KEY_ESC)
                {
                    hide_menu();
                }
            }
        }
    }

// ----------------------------------------------------------------------------------------

    void menu_bar::
    show_menu (
        unsigned long i
    )
    {
        rectangle temp;

        // menu already open so do nothing
        if (i == open_menu)
            return;

        // if a menu is currently open
        if (open_menu != menus.size())
        {
            menus[open_menu].menu.hide();
            temp = menus[open_menu].bgrect;
        }

        // display the new menu
        open_menu = i;
        long wx, wy;
        parent.get_pos(wx,wy);
        wx += menus[i].bgrect.left();
        wy += menus[i].bgrect.bottom()+1;
        menus[i].menu.set_pos(wx,wy);
        menus[i].menu.show();
        parent.invalidate_rectangle(menus[i].bgrect+temp);
    }

// ----------------------------------------------------------------------------------------

    void menu_bar::
    hide_menu (
    )
    {
        // if a menu is currently open
        if (open_menu != menus.size())
        {
            menus[open_menu].menu.hide();
            parent.invalidate_rectangle(menus[open_menu].bgrect);
            open_menu = menus.size();
        }
    }

// ----------------------------------------------------------------------------------------

    void menu_bar::
    on_popup_hide (
    )
    {
        // if a menu is currently open
        if (open_menu != menus.size())
        {
            parent.invalidate_rectangle(menus[open_menu].bgrect);
            open_menu = menus.size();
        }
    }

// ----------------------------------------------------------------------------------------

    void menu_bar::
    compute_menu_geometry (
    )
    {
        long x = 7;
        long bg_x = 0;
        for (unsigned long i = 0; i < menus.size(); ++i)
        {
            // compute the locations of the text rectangles
            menus[i].rect.set_top(5);
            menus[i].rect.set_left(x);
            menus[i].rect.set_bottom(rect.bottom()-2);

            unsigned long width, height;
            mfont->compute_size(menus[i].name,width,height);
            menus[i].rect = resize_rect_width(menus[i].rect, width);
            x = menus[i].rect.right()+10;

            menus[i].bgrect.set_top(0);
            menus[i].bgrect.set_left(bg_x);
            menus[i].bgrect.set_bottom(rect.bottom()-2);
            menus[i].bgrect.set_right(x-5);
            bg_x = menus[i].bgrect.right()+1;

            if (menus[i].underline_pos != std::string::npos)
            {
                // now compute the location of the underline bar
                rectangle r1 = mfont->compute_cursor_rect(
                    menus[i].rect,
                    menus[i].name,
                    menus[i].underline_pos);

                rectangle r2 = mfont->compute_cursor_rect(
                    menus[i].rect,
                    menus[i].name,
                    menus[i].underline_pos+1);

                menus[i].underline_p1.x() = r1.left()+1;
                menus[i].underline_p2.x() = r2.left()-1;
                menus[i].underline_p1.y() = r1.bottom()-mfont->height()+mfont->ascender()+2;
                menus[i].underline_p2.y() = r2.bottom()-mfont->height()+mfont->ascender()+2;
            }
            else
            {
                // there is no underline in this case
                menus[i].underline_p1 = menus[i].underline_p2;
            }

        }
    }

// ----------------------------------------------------------------------------------------

    void menu_bar::
    adjust_position (
    )
    {
        unsigned long width, height;
        rectangle old(rect);
        parent.get_size(width,height);
        rect.set_left(0);
        rect.set_top(0);
        rect = resize_rect(rect,width,mfont->height()+10);
        parent.invalidate_rectangle(old+rect);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// class text_grid
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    text_grid::
    text_grid (
        drawable_window& w
    ) :
        scrollable_region(w, KEYBOARD_EVENTS | MOUSE_CLICK | FOCUS_EVENTS ),
        has_focus(false),
        cursor_timer(*this,&text_grid::timer_action),
        border_color_(128,128,128)
    {

        cursor_timer.set_delay_time(500);
        set_vertical_scroll_increment(10);
        set_horizontal_scroll_increment(10);
        enable_events();
    }

// ----------------------------------------------------------------------------------------

    text_grid::
    ~text_grid (
    )
    {
        // Disable all further events for this drawable object.  We have to do this
        // because we don't want draw() events coming to this object while or after
        // it has been destructed.
        disable_events();

        // wait for the timer to stop doing its thing
        cursor_timer.stop_and_wait();
        // Tell the parent window to redraw its area that previously contained this
        // drawable object.
        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    void text_grid::
    set_grid_size (
        unsigned long rows,
        unsigned long cols
    )
    {
        auto_mutex M(m);
        row_height.set_max_size(rows);
        row_height.set_size(rows);

        col_width.set_max_size(cols);
        col_width.set_size(cols);

        grid.set_size(rows,cols);

        for (unsigned long i = 0; i < row_height.size(); ++i)
            row_height[i] = (mfont->height()*3)/2;
        for (unsigned long i = 0; i < col_width.size(); ++i)
            col_width[i] = mfont->height()*5;

        compute_total_rect();
        compute_bg_rects();
    }

// ----------------------------------------------------------------------------------------

    unsigned long text_grid::
    number_of_columns (
    ) const
    {
        auto_mutex M(m);
        return grid.nc();
    }

// ----------------------------------------------------------------------------------------

    unsigned long text_grid::
    number_of_rows (
    ) const
    {
        auto_mutex M(m);
        return grid.nr();
    }

// ----------------------------------------------------------------------------------------

    int text_grid::
    next_free_user_event_number (
    ) const
    {
        return scrollable_region::next_free_user_event_number()+1;
    }

// ----------------------------------------------------------------------------------------

    rgb_pixel text_grid::
    border_color (
    ) const
    {
        auto_mutex M(m);
        return border_color_;
    }

// ----------------------------------------------------------------------------------------

    void text_grid::
    set_border_color (
        rgb_pixel color
    )
    {
        auto_mutex M(m);
        border_color_ = color;
        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    const std::string text_grid::
    text (
        unsigned long row,
        unsigned long col
    ) const
    {
        return convert_wstring_to_mbstring(wtext(row, col));
    }

// ----------------------------------------------------------------------------------------

    const std::wstring text_grid::
    wtext (
        unsigned long row,
        unsigned long col
    ) const
    {
        return convert_utf32_to_wstring(utext(row, col));
    }

// ----------------------------------------------------------------------------------------

    const dlib::ustring text_grid::
    utext (
        unsigned long row,
        unsigned long col
    ) const
    {
        auto_mutex M(m);
        DLIB_ASSERT ( row < number_of_rows()  && col < number_of_columns(),
                      "\tconst std::string text_grid::text(row,col)"
                      << "\n\trow:              " << row
                      << "\n\tcol:              " << col
                      << "\n\tnumber_of_rows(): " << number_of_rows()
                      << "\n\tnumber_of_columns(): " << number_of_columns()
                      << "\n\tthis:             " << this
        );
        return grid[row][col].text.c_str();
    }

// ----------------------------------------------------------------------------------------

    void text_grid::
    set_text (
        unsigned long row,
        unsigned long col,
        const std::string& str
    )
    {
        set_text(row, col, convert_mbstring_to_wstring(str));
    }

// ----------------------------------------------------------------------------------------

    void text_grid::
    set_text (
        unsigned long row,
        unsigned long col,
        const std::wstring& str
    )
    {
        set_text(row, col, convert_wstring_to_utf32(str));
    }

// ----------------------------------------------------------------------------------------

    void text_grid::
    set_text (
        unsigned long row,
        unsigned long col,
        const dlib::ustring& str
    )
    {
        auto_mutex M(m);
        DLIB_ASSERT ( row < number_of_rows()  && col < number_of_columns(),
                      "\tvoid text_grid::set_text(row,col)"
                      << "\n\trow:              " << row
                      << "\n\tcol:              " << col
                      << "\n\tnumber_of_rows(): " << number_of_rows()
                      << "\n\tnumber_of_columns(): " << number_of_columns()
                      << "\n\tthis:             " << this
        );
        grid[row][col].text = str.c_str();
        parent.invalidate_rectangle(get_text_rect(row,col));
    }

// ----------------------------------------------------------------------------------------

    const rgb_pixel text_grid::
    text_color (
        unsigned long row,
        unsigned long col
    ) const
    {
        auto_mutex M(m);
        DLIB_ASSERT ( row < number_of_rows()  && col < number_of_columns(),
                      "\tconst rgb_pixel text_grid::text_color(row,col)"
                      << "\n\trow:              " << row
                      << "\n\tcol:              " << col
                      << "\n\tnumber_of_rows(): " << number_of_rows()
                      << "\n\tnumber_of_columns(): " << number_of_columns()
                      << "\n\tthis:             " << this
        );
        return grid[row][col].text_color;
    }

// ----------------------------------------------------------------------------------------

    void text_grid::
    set_text_color (
        unsigned long row,
        unsigned long col,
        const rgb_pixel color
    )
    {
        auto_mutex M(m);
        DLIB_ASSERT ( row < number_of_rows()  && col < number_of_columns(),
                      "\tvoid text_grid::set_text_color(row,col,color)"
                      << "\n\trow:              " << row
                      << "\n\tcol:              " << col
                      << "\n\tnumber_of_rows(): " << number_of_rows()
                      << "\n\tnumber_of_columns(): " << number_of_columns()
                      << "\n\tthis:             " << this
        );
        grid[row][col].text_color = color;
        parent.invalidate_rectangle(get_text_rect(row,col));
    }

// ----------------------------------------------------------------------------------------

    const rgb_pixel text_grid::
    background_color (
        unsigned long row,
        unsigned long col
    ) const
    {
        auto_mutex M(m);
        DLIB_ASSERT ( row < number_of_rows()  && col < number_of_columns(),
                      "\tconst rgb_pixel text_grid::background_color(row,col,color)"
                      << "\n\trow:              " << row
                      << "\n\tcol:              " << col
                      << "\n\tnumber_of_rows(): " << number_of_rows()
                      << "\n\tnumber_of_columns(): " << number_of_columns()
                      << "\n\tthis:             " << this
        );
        return grid[row][col].bg_color;
    }

// ----------------------------------------------------------------------------------------

    void text_grid::
    set_background_color (
        unsigned long row,
        unsigned long col,
        const rgb_pixel color
    )
    {
        auto_mutex M(m);
        DLIB_ASSERT ( row < number_of_rows()  && col < number_of_columns(),
                      "\tvoid text_grid::set_background_color(row,col,color)"
                      << "\n\trow:              " << row
                      << "\n\tcol:              " << col
                      << "\n\tnumber_of_rows(): " << number_of_rows()
                      << "\n\tnumber_of_columns(): " << number_of_columns()
                      << "\n\tthis:             " << this
        );
        grid[row][col].bg_color = color;
        parent.invalidate_rectangle(get_bg_rect(row,col));
    }

// ----------------------------------------------------------------------------------------

    bool text_grid::
    is_editable (
        unsigned long row,
        unsigned long col
    ) const
    {
        auto_mutex M(m);
        DLIB_ASSERT ( row < number_of_rows()  && col < number_of_columns(),
                      "\tbool text_grid::is_editable(row,col)"
                      << "\n\trow:              " << row
                      << "\n\tcol:              " << col
                      << "\n\tnumber_of_rows(): " << number_of_rows()
                      << "\n\tnumber_of_columns(): " << number_of_columns()
                      << "\n\tthis:             " << this
        );
        return grid[row][col].is_editable;
    }

// ----------------------------------------------------------------------------------------

    void text_grid::
    set_editable (
        unsigned long row,
        unsigned long col,
        bool editable
    )
    {
        auto_mutex M(m);
        DLIB_ASSERT ( row < number_of_rows()  && col < number_of_columns(),
                      "\tvoid text_grid::set_editable(row,col,editable)"
                      << "\n\trow:              " << row
                      << "\n\tcol:              " << col
                      << "\n\tnumber_of_rows(): " << number_of_rows()
                      << "\n\tnumber_of_columns(): " << number_of_columns()
                      << "\n\teditable:         " << editable
                      << "\n\tthis:             " << this
        );
        grid[row][col].is_editable = editable;
        if (has_focus && active_row == static_cast<long>(row) && active_col == static_cast<long>(col))
        {
            drop_input_focus();
        }
    }

// ----------------------------------------------------------------------------------------

    void text_grid::
    set_column_width (
        unsigned long col,
        unsigned long width
    )
    {
        auto_mutex M(m);
        DLIB_ASSERT ( col < number_of_columns(),
                      "\tvoid text_grid::set_column_width(col,width)"
                      << "\n\tcol:              " << col
                      << "\n\tnumber_of_columns(): " << number_of_columns()
                      << "\n\twidth:            " << width
                      << "\n\tthis:             " << this
        );
        col_width[col] = width;
        compute_total_rect();
        compute_bg_rects();
    }

// ----------------------------------------------------------------------------------------

    void text_grid::
    set_row_height (
        unsigned long row,
        unsigned long height
    )
    {
        auto_mutex M(m);
        DLIB_ASSERT ( row < number_of_rows() ,
                      "\tvoid text_grid::set_row_height(row,height)"
                      << "\n\trow:              " << row
                      << "\n\tnumber_of_rows(): " << number_of_rows()
                      << "\n\theight:           " << height
                      << "\n\tthis:             " << this
        );
        row_height[row] = height;
        compute_total_rect();
        compute_bg_rects();
    }

// ----------------------------------------------------------------------------------------

    void text_grid::
    disable (
    )
    {
        auto_mutex M(m);
        scrollable_region::disable();
        drop_input_focus();
    }

// ----------------------------------------------------------------------------------------

    void text_grid::
    hide (
    )
    {
        auto_mutex M(m);
        scrollable_region::hide();
        drop_input_focus();
    }

// ----------------------------------------------------------------------------------------

    void text_grid::
    on_user_event (
        int num
    )
    {
        // ignore this user event if it isn't for us
        if (num != scrollable_region::next_free_user_event_number())
            return;

        if (has_focus && !recent_cursor_move && enabled && !hidden)
        {
            show_cursor = !show_cursor;
            parent.invalidate_rectangle(get_text_rect(active_row,active_col));
        }
        recent_cursor_move = false;
    }

// ----------------------------------------------------------------------------------------

    void text_grid::
    timer_action (
    )
    {
        parent.trigger_user_event(this,scrollable_region::next_free_user_event_number());
    }

// ----------------------------------------------------------------------------------------

    void text_grid::
    compute_bg_rects (
    )
    {
        // loop over each element in the grid and figure out what its rectangle should be
        // with respect to the total_rect()
        point p1, p2;
        p1.y() = total_rect().top();
        for (long row = 0; row < grid.nr(); ++row)
        {
            p1.x() = total_rect().left();
            p2.y() = p1.y() + row_height[row]-1;
            for (long col = 0; col < grid.nc(); ++col)
            {
                // if this is the last box in this row make it super wide so that it always
                // goes to the end of the widget
                if (col+1 == grid.nc())
                    p2.x() = 1000000;
                else
                    p2.x() = p1.x() + col_width[col]-1;

                // at this point p1 is the upper left corner of this box and p2 is the
                // lower right corner of the box;
                rectangle bg_rect(p1);
                bg_rect += p2;

                grid[row][col].bg_rect = translate_rect(bg_rect, -total_rect().left(), -total_rect().top());

                p1.x() += 1 + col_width[col];
            }
            p1.y() += 1 + row_height[row];
        }
    }

// ----------------------------------------------------------------------------------------

    void text_grid::
    compute_total_rect (
    )
    {
        if (grid.size() == 0)
        {
            set_total_rect_size(0,0);
        }
        else
        {
            unsigned long width = col_width.size()-1;
            unsigned long height = row_height.size()-1;

            for (unsigned long i = 0; i < col_width.size(); ++i)
                width += col_width[i];
            for (unsigned long i = 0; i < row_height.size(); ++i)
                height += row_height[i];

            set_total_rect_size(width,height);
        }
    }

// ----------------------------------------------------------------------------------------

    void text_grid::
    on_keydown (
        unsigned long key,
        bool is_printable,
        unsigned long state
    )
    {
        // ignore this event if we are disabled or hidden
        if (!enabled || hidden)
            return;

        if (has_focus)
        {
            if (is_printable)
            {
                // if the user hit the tab key then jump to the next box
                if (key == '\t')
                {
                    if (active_col+1 == grid.nc())
                    {
                        if (active_row+1 == grid.nr())
                            move_cursor(0,0,0);
                        else
                            move_cursor(active_row+1,0,0);
                    }
                    else
                    {
                        move_cursor(active_row,active_col+1,0);
                    }
                }
                if (key == '\n')
                {
                    // ignore the enter key
                }
                else if (grid[active_row][active_col].is_editable)
                {
                    // insert the key the user pressed into the string
                    grid[active_row][active_col].text.insert(cursor_pos,1,static_cast<char>(key));
                    move_cursor(active_row,active_col,cursor_pos+1);

                    if (text_modified_handler.is_set())
                        text_modified_handler(active_row,active_col);
                }
            }
            else if ((state & base_window::KBD_MOD_CONTROL))
            {
                if (key == base_window::KEY_LEFT)
                    move_cursor(active_row,active_col-1,0);
                else if (key == base_window::KEY_RIGHT)
                    move_cursor(active_row,active_col+1,0);
                else if (key == base_window::KEY_UP)
                    move_cursor(active_row-1,active_col,0);
                else if (key == base_window::KEY_DOWN)
                    move_cursor(active_row+1,active_col,0);
                else if (key == base_window::KEY_END)
                    move_cursor(active_row,active_col,grid[active_row][active_col].text.size());
                else if (key == base_window::KEY_HOME)
                    move_cursor(active_row,active_col,0);
            }
            else
            {
                if (key == base_window::KEY_LEFT)
                    move_cursor(active_row,active_col,cursor_pos-1);
                else if (key == base_window::KEY_RIGHT)
                    move_cursor(active_row,active_col,cursor_pos+1);
                else if (key == base_window::KEY_UP)
                    move_cursor(active_row-1,active_col,0);
                else if (key == base_window::KEY_DOWN)
                    move_cursor(active_row+1,active_col,0);
                else if (key == base_window::KEY_END)
                    move_cursor(active_row,active_col,grid[active_row][active_col].text.size());
                else if (key == base_window::KEY_HOME)
                    move_cursor(active_row,active_col,0);
                else if (key == base_window::KEY_BACKSPACE)
                {
                    if (cursor_pos > 0 && grid[active_row][active_col].is_editable)
                    {
                        grid[active_row][active_col].text.erase(
                            grid[active_row][active_col].text.begin()+cursor_pos-1,
                            grid[active_row][active_col].text.begin()+cursor_pos);
                        move_cursor(active_row,active_col,cursor_pos-1);

                        if (text_modified_handler.is_set())
                            text_modified_handler(active_row,active_col);
                    }
                }
                else if (key == base_window::KEY_DELETE)
                {
                    if (cursor_pos < static_cast<long>(grid[active_row][active_col].text.size()) &&
                        grid[active_row][active_col].is_editable)
                    {
                        grid[active_row][active_col].text.erase(
                            grid[active_row][active_col].text.begin()+cursor_pos);
                        move_cursor(active_row,active_col,cursor_pos);

                        if (text_modified_handler.is_set())
                            text_modified_handler(active_row,active_col);
                    }
                }
            }
        } // if (has_focus)
    }

// ----------------------------------------------------------------------------------------

    void text_grid::
    on_mouse_down (
        unsigned long btn,
        unsigned long state,
        long x,
        long y,
        bool is_double_click
    )
    {
        scrollable_region::on_mouse_down(btn, state, x, y, is_double_click);
        if (display_rect().contains(x,y) && enabled && !hidden)
        {
            // figure out which box this click landed in
            rectangle hit;

            // find which column we hit
            unsigned long col = 0;
            long box_x = total_rect().left();
            for (unsigned long i = 0; i < col_width.size(); ++i)
            {
                if (box_x <= x && (x < box_x+static_cast<long>(col_width[i]) || (i+1 == col_width.size())))
                {
                    col = i;
                    hit.set_left(box_x);
                    hit.set_right(box_x+col_width[i]-1);
                    break;
                }
                else
                {
                    box_x += col_width[i]+1;
                }
            }

            // find which row we hit
            unsigned long row = 0;
            long box_y = total_rect().top();
            for (unsigned long i = 0; i < row_height.size(); ++i)
            {
                if (box_y <= y && y < box_y+static_cast<long>(row_height[i]))
                {
                    row = i;
                    hit.set_top(box_y);
                    hit.set_bottom(box_y+row_height[i]-1);
                    break;
                }
                else
                {
                    box_y += row_height[i]+1;
                }
            }

            // if we hit a box
            if (hit.is_empty() == false)
            {
                move_cursor(row,
                            col,
                            mfont->compute_cursor_pos(get_text_rect(row,col), grid[row][col].text, x, y, grid[row][col].first)
                );
            }
            else
            {
                drop_input_focus();
            }
        }
        else
        {
            drop_input_focus();
        }
    }

// ----------------------------------------------------------------------------------------

    void text_grid::
    on_mouse_up (
        unsigned long btn,
        unsigned long state,
        long x,
        long y
    )
    {
        scrollable_region::on_mouse_up(btn, state, x, y);
    }

// ----------------------------------------------------------------------------------------

    void text_grid::
    on_focus_lost (
    )
    {
        drop_input_focus();
    }

// ----------------------------------------------------------------------------------------

    void text_grid::
    draw (
        const canvas& c
    ) const
    {
        scrollable_region::draw(c);
        rectangle area = c.intersect(display_rect());
        if (area.is_empty() == true)
            return;

        if (enabled)
            fill_rect(c, area, 255);

        // don't do anything if the grid is empty
        if (grid.size() == 0)
            return;

        // draw all the vertical lines
        point p1, p2;
        p1.x() = p2.x() = total_rect().left();
        p1.y() = total_rect().top();
        p2.y() = total_rect().bottom();
        for (unsigned long i = 0; i < col_width.size()-1; ++i)
        {
            p1.x() += col_width[i];
            p2.x() += col_width[i];
            if (enabled)
                draw_line(c,p1,p2,border_color_,area);
            else
                draw_line(c,p1,p2,128,area);
            p1.x() += 1;
            p2.x() += 1;
        }

        // draw all the horizontal lines
        p1.y() = p2.y() = total_rect().top();
        p1.x() = display_rect().left();
        p2.x() = display_rect().right();
        for (unsigned long i = 0; i < row_height.size(); ++i)
        {
            p1.y() += row_height[i];
            p2.y() += row_height[i];
            if (enabled)
                draw_line(c,p1,p2,border_color_,area);
            else
                draw_line(c,p1,p2,128,area);
            p1.y() += 1;
            p2.y() += 1;
        }

        // draw the backgrounds and text for each box
        for (long row = 0; row < grid.nr(); ++row)
        {
            for (long col = 0; col < grid.nc(); ++col)
            {
                rectangle bg_rect(get_bg_rect(row,col));

                rectangle text_rect(get_text_rect(row,col));

                if (enabled)
                {
                    fill_rect(c,bg_rect.intersect(area),grid[row][col].bg_color);

                    mfont->draw_string(c,
                                       text_rect,
                                       grid[row][col].text,
                                       grid[row][col].text_color,
                                       grid[row][col].first,
                                       std::string::npos,
                                       area);
                }
                else
                {
                    mfont->draw_string(c,
                                       text_rect,
                                       grid[row][col].text,
                                       128,
                                       grid[row][col].first,
                                       std::string::npos,
                                       area);
                }

                // if this box has input focus then draw it with a cursor
                if (has_focus && active_col == col && active_row == row && show_cursor)
                {
                    rectangle cursor_rect = mfont->compute_cursor_rect(text_rect,
                                                                       grid[row][col].text,
                                                                       cursor_pos,
                                                                       grid[row][col].first);
                    draw_rectangle(c,cursor_rect,0,area);
                }

            }
        }

    }

// ----------------------------------------------------------------------------------------

    rectangle text_grid::
    get_text_rect (
        unsigned long row,
        unsigned long col
    ) const
    {
        rectangle bg_rect(get_bg_rect(row,col));
        long padding = (bg_rect.height() - mfont->height())/2 + (bg_rect.height() - mfont->height())%2;
        if (padding < 0)
            padding = 0;
        bg_rect.set_left(bg_rect.left()+padding);
        bg_rect.set_top(bg_rect.top()+padding);
        bg_rect.set_right(bg_rect.right()-padding);
        bg_rect.set_bottom(bg_rect.bottom()-padding);
        return bg_rect;
    }

// ----------------------------------------------------------------------------------------

    rectangle text_grid::
    get_bg_rect (
        unsigned long row,
        unsigned long col
    ) const
    {
        return translate_rect(grid[row][col].bg_rect, total_rect().left(), total_rect().top());
    }

// ----------------------------------------------------------------------------------------

    void text_grid::
    drop_input_focus (
    )
    {
        if (has_focus)
        {
            parent.invalidate_rectangle(get_text_rect(active_row,active_col));
            has_focus = false;
            show_cursor = false;
            cursor_timer.stop();
        }
    }

// ----------------------------------------------------------------------------------------

    void text_grid::
    move_cursor (
        long row,
        long col,
        long new_cursor_pos
    )
    {
        // don't do anything if the grid is empty
        if (grid.size() == 0)
        {
            return;
        }

        if (row < 0)
            row = 0;
        if (row >= grid.nr())
            row = grid.nr()-1;
        if (col < 0)
            col = 0;
        if (col >= grid.nc())
            col = grid.nc()-1;

        if (new_cursor_pos < 0)
        {
            if (col == 0)
            {
                new_cursor_pos = 0;
            }
            else
            {
                --col;
                new_cursor_pos = grid[row][col].text.size();
            }
        }

        if (new_cursor_pos > static_cast<long>(grid[row][col].text.size()))
        {
            if (col+1 == grid.nc())
            {
                new_cursor_pos = grid[row][col].text.size();
            }
            else
            {
                ++col;
                new_cursor_pos = 0;
            }
        }

        // if some other box had the input focus then redraw it
        if (has_focus && (active_row != row || active_col != col ))
        {
            parent.invalidate_rectangle(get_text_rect(active_row,active_col));
        }

        if (has_focus == false)
        {
            cursor_timer.start();
        }

        has_focus = true;
        recent_cursor_move = true;
        show_cursor = true;
        active_row = row;
        active_col = col;
        cursor_pos = new_cursor_pos;

        // adjust the first character to draw so that the string is displayed well
        rectangle text_rect(get_text_rect(active_row,active_col));
        rectangle cursor_rect = mfont->compute_cursor_rect(text_rect,
                                                           grid[row][col].text,
                                                           cursor_pos,
                                                           grid[row][col].first);

        // if the cursor rect is too far to the left of the string
        if (cursor_pos < static_cast<long>(grid[row][col].first))
        {
            if (cursor_pos > 5)
            {
                grid[row][col].first = cursor_pos - 5;
            }
            else
            {
                grid[row][col].first = 0;
            }
        }
        // if the cursor rect is too far to the right of the string
        else if (cursor_rect.left() > text_rect.right())
        {
            long distance = (cursor_rect.left() - text_rect.right()) + text_rect.width()/3;
            // find the letter that is distance pixels from the start of the string
            long sum = 0;
            for (unsigned long i = grid[row][col].first; i < grid[row][col].text.size(); ++i)
            {
                sum += (*mfont)[grid[row][col].text[i]].width();
                if (sum >= distance)
                {
                    grid[row][col].first = i;
                    break;
                }
            }
        }

        scroll_to_rect(get_bg_rect(row,col));

        // redraw our box
        parent.invalidate_rectangle(text_rect);

    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // text_field object methods
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    rectangle text_box::
    get_text_rect (
    ) const
    {
        const unsigned long padding = style->get_padding(*mfont);

        rectangle text_rect;
        text_rect.set_left(total_rect().left()+padding);
        text_rect.set_top(total_rect().top()+padding);
        text_rect.set_right(total_rect().right()-padding);
        text_rect.set_bottom(total_rect().bottom()-padding);
        return text_rect;
    }

// ----------------------------------------------------------------------------------------

    void text_box::
    enable (
    )
    {
        scrollable_region::enable();
        right_click_menu.enable();
    }

// ----------------------------------------------------------------------------------------

    void text_box::
    on_cut (
    )
    {
        on_copy();
        on_delete_selected();
    }

// ----------------------------------------------------------------------------------------

    void text_box::
    on_copy (
    )
    {
        if (highlight_start <= highlight_end)
        {
            put_on_clipboard(text_.substr(highlight_start, highlight_end-highlight_start+1));
        }
    }

// ----------------------------------------------------------------------------------------

    void text_box::
    on_paste (
    )
    {
        ustring temp_str;
        get_from_clipboard(temp_str);

        if (highlight_start <= highlight_end)
        {
            text_ = text_.substr(0,highlight_start) + temp_str +
                text_.substr(highlight_end+1,text_.size()-highlight_end-1);
            move_cursor(highlight_start+temp_str.size());
            highlight_start = 0;
            highlight_end = -1;
            parent.invalidate_rectangle(rect);
            on_no_text_selected();

            // send out the text modified event
            if (text_modified_handler.is_set())
                text_modified_handler();
        }
        else
        {
            text_ = text_.substr(0,cursor_pos) + temp_str +
                text_.substr(cursor_pos,text_.size()-cursor_pos);
            move_cursor(cursor_pos+temp_str.size());

            // send out the text modified event
            if (temp_str.size() != 0 && text_modified_handler.is_set())
                text_modified_handler();
        }

        adjust_total_rect();
    }

// ----------------------------------------------------------------------------------------

    void text_box::
    on_select_all (
    )
    {
        move_cursor(static_cast<long>(text_.size()));
        highlight_start = 0;
        highlight_end = static_cast<long>(text_.size()-1);
        if (highlight_start <= highlight_end)
            on_text_is_selected();
        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    void text_box::
    on_delete_selected (
    )
    {
        if (highlight_start <= highlight_end)
        {
            text_ = text_.erase(highlight_start,highlight_end-highlight_start+1);
            move_cursor(highlight_start);
            highlight_start = 0;
            highlight_end = -1;

            on_no_text_selected();
            // send out the text modified event
            if (text_modified_handler.is_set())
                text_modified_handler();

            adjust_total_rect();

            parent.invalidate_rectangle(rect);
        }
    }

// ----------------------------------------------------------------------------------------

    void text_box::
    on_text_is_selected (
    )
    {
        right_click_menu.menu().enable_menu_item(0);
        right_click_menu.menu().enable_menu_item(1);
        right_click_menu.menu().enable_menu_item(3);
    }

// ----------------------------------------------------------------------------------------

    void text_box::
    on_no_text_selected (
    )
    {
        right_click_menu.menu().disable_menu_item(0);
        right_click_menu.menu().disable_menu_item(1);
        right_click_menu.menu().disable_menu_item(3);
    }

// ----------------------------------------------------------------------------------------

    void text_box::
    show (
    )
    {
        scrollable_region::show();
        right_click_menu.show();
    }

// ----------------------------------------------------------------------------------------

    void text_box::
    disable (
    )
    {
        auto_mutex M(m);
        scrollable_region::disable();
        t.stop();
        has_focus = false;
        cursor_visible = false;
        right_click_menu.disable();
    }

// ----------------------------------------------------------------------------------------

    void text_box::
    hide (
    )
    {
        auto_mutex M(m);
        scrollable_region::hide();
        t.stop();
        has_focus = false;
        cursor_visible = false;
    }

// ----------------------------------------------------------------------------------------

    void text_box::
    adjust_total_rect (
    )
    {
        const unsigned long padding = style->get_padding(*mfont);
        unsigned long text_width;
        unsigned long text_height;

        mfont->compute_size(text_, text_width, text_height);

        set_total_rect_size(text_width + padding*2, text_height + padding*2);
    }

// ----------------------------------------------------------------------------------------

    void text_box::
    set_main_font (
        const shared_ptr_thread_safe<font>& f
    )
    {
        auto_mutex M(m);
        mfont = f;
        adjust_total_rect();
        right_click_menu.set_rect(display_rect());
    }

// ----------------------------------------------------------------------------------------

    void text_box::
    draw (
        const canvas& c
    ) const
    {
        scrollable_region::draw(c);
        rectangle area = rect.intersect(c);
        if (area.is_empty())
            return;

        const point origin(total_rect().left(), total_rect().top());

        style->draw_text_box(c,display_rect(),get_text_rect(), enabled, *mfont, text_,
                             translate_rect(cursor_rect, origin),
                               text_color_, bg_color_, has_focus, cursor_visible, highlight_start,
                               highlight_end);
    }

// ----------------------------------------------------------------------------------------

    void text_box::
    set_text (
        const std::string& text
    )
    {
        set_text(convert_mbstring_to_wstring(text));
    }

    void text_box::
    set_text (
        const std::wstring& text
    )
    {
        set_text(convert_wstring_to_utf32(text));
    }

    void text_box::
    set_text (
        const dlib::ustring& text
    )
    {
        auto_mutex M(m);
        // do this to get rid of any reference counting that may be present in
        // the std::string implementation.
        text_ = text.c_str();

        adjust_total_rect();
        move_cursor(0);

        highlight_start = 0;
        highlight_end = -1;
    }

// ----------------------------------------------------------------------------------------

    const std::string text_box::
    text (
    ) const
    {
        std::string temp = convert_wstring_to_mbstring(wtext());
        return temp;
    }

    const std::wstring text_box::
    wtext (
    ) const
    {
        std::wstring temp = convert_utf32_to_wstring(utext());
        return temp;
    }

    const dlib::ustring text_box::
    utext (
    ) const
    {
        auto_mutex M(m);
        // do this to get rid of any reference counting that may be present in
        // the dlib::ustring implementation.
        dlib::ustring temp = text_.c_str();
        return temp;
    }

// ----------------------------------------------------------------------------------------

    void text_box::
    set_size (
        unsigned long width,
        unsigned long height
    )
    {
        auto_mutex M(m);
        scrollable_region::set_size(width,height);
        right_click_menu.set_rect(display_rect());
    }

// ----------------------------------------------------------------------------------------

    void text_box::
    set_pos (
        long x,
        long y
    )
    {
        scrollable_region::set_pos(x,y);
        right_click_menu.set_rect(get_text_rect());
    }

// ----------------------------------------------------------------------------------------

    void text_box::
    set_background_color (
        const rgb_pixel color
    )
    {
        auto_mutex M(m);
        bg_color_ = color;
        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    const rgb_pixel text_box::
    background_color (
    ) const
    {
        auto_mutex M(m);
        return bg_color_;
    }

// ----------------------------------------------------------------------------------------

    void text_box::
    set_text_color (
        const rgb_pixel color
    )
    {
        auto_mutex M(m);
        text_color_ = color;
        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    const rgb_pixel text_box::
    text_color (
    ) const
    {
        auto_mutex M(m);
        return text_color_;
    }

// ----------------------------------------------------------------------------------------

    void text_box::
    on_mouse_move (
        unsigned long state,
        long x,
        long y
    )
    {
        if (!enabled || hidden || !has_focus)
        {
            return;
        }

        if (state & base_window::LEFT)
        {
            if (highlight_start <= highlight_end)
            {
                if (highlight_start == cursor_pos)
                    shift_pos = highlight_end + 1;
                else
                    shift_pos = highlight_start;
            }

            unsigned long new_pos = mfont->compute_cursor_pos(get_text_rect(),text_,x,y);
            if (static_cast<long>(new_pos) != cursor_pos)
            {
                move_cursor(new_pos);
                parent.invalidate_rectangle(rect);
            }
        }
        else if (shift_pos != -1)
        {
            shift_pos = -1;
        }

    }

// ----------------------------------------------------------------------------------------

    void text_box::
    on_mouse_up (
        unsigned long btn,
        unsigned long,
        long ,
        long
    )
    {
        if (!enabled || hidden)
            return;

        if (btn == base_window::LEFT)
            shift_pos = -1;
    }

// ----------------------------------------------------------------------------------------

    void text_box::
    on_mouse_down (
        unsigned long btn,
        unsigned long state,
        long x,
        long y,
        bool double_clicked
    )
    {
        using namespace std;
        if (!enabled || hidden || btn != (unsigned long)base_window::LEFT)
            return;

        if (display_rect().contains(x,y))
        {
            has_focus = true;
            cursor_visible = true;
            parent.invalidate_rectangle(rect);
            t.start();

            if (double_clicked)
            {
                // highlight the double clicked word
                string::size_type first, last;
                const ustring ustr = convert_utf8_to_utf32(std::string(" \t\n"));
                first = text_.substr(0,cursor_pos).find_last_of(ustr.c_str());
                last = text_.find_first_of(ustr.c_str(),cursor_pos);
                long f = static_cast<long>(first);
                long l = static_cast<long>(last);
                if (first == string::npos)
                    f = -1;
                if (last == string::npos)
                    l = static_cast<long>(text_.size());

                ++f;
                --l;

                move_cursor(l+1);
                highlight_start = f;
                highlight_end = l;
                on_text_is_selected();
            }
            else
            {
                if (state & base_window::SHIFT)
                {
                    if (highlight_start <= highlight_end)
                    {
                        if (highlight_start == cursor_pos)
                            shift_pos = highlight_end + 1;
                        else
                            shift_pos = highlight_start;
                    }
                    else
                    {
                        shift_pos = cursor_pos;
                    }
                }

                bool at_end = false;
                if (cursor_pos == 0 || cursor_pos == static_cast<long>(text_.size()))
                    at_end = true;
                const long old_pos = cursor_pos;

                unsigned long new_pos = mfont->compute_cursor_pos(get_text_rect(),text_,x,y);
                move_cursor(new_pos);

                shift_pos = cursor_pos;

                if (at_end && cursor_pos == old_pos)
                {
                    highlight_start = 0;
                    highlight_end = -1;
                    on_no_text_selected();
                }
            }

        }
        else if (has_focus && rect.contains(x,y) == false)
        {
            t.stop();
            has_focus = false;
            cursor_visible = false;
            shift_pos = -1;
            highlight_start = 0;
            highlight_end = -1;
            on_no_text_selected();

            if (focus_lost_handler.is_set())
                focus_lost_handler();
            parent.invalidate_rectangle(rect);
        }
        else
        {
            has_focus = false;
        }
    }

// ----------------------------------------------------------------------------------------

    void text_box::
    on_keydown (
        unsigned long key,
        bool is_printable,
        unsigned long state
    )
    {
        // If the right click menu is up then we don't want to do anything with
        // the keyboard ourselves.  Let the popup menu use the keyboard for now.
        if (right_click_menu.popup_menu_visible())
            return;

        if (has_focus && enabled && !hidden)
        {
            const ustring space_str = convert_utf8_to_utf32(std::string(" \t\n"));
            const bool shift = (state&base_window::KBD_MOD_SHIFT) != 0;
            const bool ctrl = (state&base_window::KBD_MOD_CONTROL) != 0;

            if (shift && is_printable == false)
            {
                if (shift_pos == -1)
                {
                    if (highlight_start <= highlight_end)
                    {
                        if (highlight_start == cursor_pos)
                            shift_pos = highlight_end + 1;
                        else
                            shift_pos = highlight_start;
                    }
                    else
                    {
                        shift_pos = cursor_pos;
                    }
                }
            }
            else
            {
                shift_pos = -1;
            }

            if (key == base_window::KEY_LEFT)
            {
                if (cursor_pos != 0)
                {
                    unsigned long new_pos;
                    if (ctrl)
                    {
                        // find the first non-whitespace to our left
                        std::string::size_type pos = text_.find_last_not_of(space_str.c_str(),cursor_pos);
                        if (pos != std::string::npos)
                        {
                            pos = text_.find_last_of(space_str.c_str(),pos);
                            if (pos != std::string::npos)
                                new_pos = static_cast<unsigned long>(pos);
                            else
                                new_pos = 0;
                        }
                        else
                        {
                            new_pos = 0;
                        }
                    }
                    else
                    {
                        new_pos = cursor_pos-1;
                    }

                    move_cursor(new_pos);
                }
                else if (shift_pos == -1)
                {
                    highlight_start = 0;
                    highlight_end = -1;
                    on_no_text_selected();
                    parent.invalidate_rectangle(rect);
                }

            }
            else if (key == base_window::KEY_RIGHT)
            {
                if (cursor_pos != static_cast<long>(text_.size()))
                {
                    unsigned long new_pos;
                    if (ctrl)
                    {
                        // find the first non-whitespace to our left
                        std::string::size_type pos = text_.find_first_not_of(space_str.c_str(),cursor_pos);
                        if (pos != std::string::npos)
                        {
                            pos = text_.find_first_of(space_str.c_str(),pos);
                            if (pos != std::string::npos)
                                new_pos = static_cast<unsigned long>(pos+1);
                            else
                                new_pos = static_cast<unsigned long>(text_.size());
                        }
                        else
                        {
                            new_pos = static_cast<unsigned long>(text_.size());
                        }
                    }
                    else
                    {
                        new_pos = cursor_pos+1;
                    }

                    move_cursor(new_pos);
                }
                else if (shift_pos == -1)
                {
                    highlight_start = 0;
                    highlight_end = -1;
                    on_no_text_selected();
                    parent.invalidate_rectangle(rect);
                }
            }
            else if (key == base_window::KEY_UP)
            {
                if (ctrl)
                {
                    move_cursor(0);
                }
                else
                {
                    const point origin(total_rect().left(), total_rect().top());
                    // move the cursor so the position that is just a few pixels above
                    // the current cursor_rect
                    move_cursor(mfont->compute_cursor_pos(
                            get_text_rect(), text_, cursor_rect.left()+origin.x(),
                            cursor_rect.top()+origin.y()-mfont->height()/2));

                }

                if (shift_pos == -1)
                {
                    highlight_start = 0;
                    highlight_end = -1;
                    on_no_text_selected();
                    parent.invalidate_rectangle(rect);
                }
            }
            else if (key == base_window::KEY_DOWN)
            {
                if (ctrl)
                {
                    move_cursor(static_cast<unsigned long>(text_.size()));
                }
                else
                {
                    const point origin(total_rect().left(), total_rect().top());
                    // move the cursor so the position that is just a few pixels above
                    // the current cursor_rect
                    move_cursor(mfont->compute_cursor_pos(
                            get_text_rect(), text_, cursor_rect.left()+origin.x(),
                            cursor_rect.bottom()+origin.y()+mfont->height()/2));
                }

                if (shift_pos == -1)
                {
                    highlight_start = 0;
                    highlight_end = -1;
                    on_no_text_selected();
                    parent.invalidate_rectangle(rect);
                }
            }
            else if (is_printable)
            {
                if (ctrl)
                {
                    if (key == 'a')
                    {
                        on_select_all();
                    }
                    else if (key == 'c')
                    {
                        on_copy();
                    }
                    else if (key == 'v')
                    {
                        on_paste();
                    }
                    else if (key == 'x')
                    {
                        on_cut();
                    }
                }
                else
                {
                    if (highlight_start <= highlight_end)
                    {
                        text_ = text_.substr(0,highlight_start) + static_cast<unichar>(key) +
                            text_.substr(highlight_end+1,text_.size()-highlight_end-1);

                        adjust_total_rect();
                        move_cursor(highlight_start+1);
                        highlight_start = 0;
                        highlight_end = -1;
                        on_no_text_selected();
                    }
                    else
                    {
                        text_ = text_.substr(0,cursor_pos) + static_cast<unichar>(key) +
                            text_.substr(cursor_pos,text_.size()-cursor_pos);
                        adjust_total_rect();
                        move_cursor(cursor_pos+1);
                    }

                    // send out the text modified event
                    if (text_modified_handler.is_set())
                        text_modified_handler();

                }

                if (key == '\n')
                {
                    if (enter_key_handler.is_set())
                        enter_key_handler();
                }
            }
            else if (key == base_window::KEY_BACKSPACE)
            {
                // if something is highlighted then delete that
                if (highlight_start <= highlight_end)
                {
                    on_delete_selected();
                }
                else if (cursor_pos != 0)
                {
                    text_ = text_.erase(cursor_pos-1,1);
                    adjust_total_rect();
                    move_cursor(cursor_pos-1);

                    // send out the text modified event
                    if (text_modified_handler.is_set())
                        text_modified_handler();
                }
                else
                {
                    // do this just so it repaints itself right
                    move_cursor(cursor_pos);
                }

            }
            else if (key == base_window::KEY_DELETE)
            {
                // if something is highlighted then delete that
                if (highlight_start <= highlight_end)
                {
                    on_delete_selected();
                }
                else if (cursor_pos != static_cast<long>(text_.size()))
                {
                    text_ = text_.erase(cursor_pos,1);

                    adjust_total_rect();
                    // send out the text modified event
                    if (text_modified_handler.is_set())
                        text_modified_handler();
                }
                else
                {
                    // do this just so it repaints itself right
                    move_cursor(cursor_pos);
                }

            }
            else if (key == base_window::KEY_HOME)
            {
                if (ctrl)
                {
                    move_cursor(0);
                }
                else if (cursor_pos != 0)
                {
                    // find the start of the current line
                    ustring::size_type pos = text_.find_last_of('\n',cursor_pos-1);
                    if (pos == ustring::npos)
                        pos = 0;
                    else
                        pos += 1;
                    move_cursor(static_cast<unsigned long>(pos));

                }

                if (shift_pos == -1)
                {
                    highlight_start = 0;
                    highlight_end = -1;
                    on_no_text_selected();
                    parent.invalidate_rectangle(rect);
                }
            }
            else if (key == base_window::KEY_END)
            {
                if (ctrl)
                {
                    move_cursor(static_cast<unsigned long>(text_.size()));
                }
                {
                    ustring::size_type pos = text_.find_first_of('\n',cursor_pos);
                    if (pos == ustring::npos)
                        pos = text_.size();

                    move_cursor(static_cast<unsigned long>(pos));
                }

                if (shift_pos == -1)
                {
                    highlight_start = 0;
                    highlight_end = -1;
                    on_no_text_selected();
                    parent.invalidate_rectangle(rect);
                }
            }
            else if (key == base_window::KEY_PAGE_DOWN || key == base_window::KEY_PAGE_UP)
            {
                long jump_size = display_rect().height() -
                    std::min(mfont->height()*3, display_rect().height()/5);

                // if we are supposed to page up then just jump in the other direction
                if (key == base_window::KEY_PAGE_UP)
                    jump_size = -jump_size;

                scroll_to_rect(translate_rect(display_rect(), point(0, jump_size )));
            }

            cursor_visible = true;
            recent_movement = true;

        }
    }

// ----------------------------------------------------------------------------------------

    void text_box::
    on_string_put(
        const std::wstring &str
    )
    {
        if (has_focus && enabled && !hidden)
        {
            ustring ustr = convert_wstring_to_utf32(str);
            if (highlight_start <= highlight_end)
            {
                text_ = text_.substr(0,highlight_start) + ustr +
                    text_.substr(highlight_end+1,text_.size()-highlight_end-1);

                adjust_total_rect();
                move_cursor(highlight_start+ustr.size());
                highlight_start = 0;
                highlight_end = -1;
                on_no_text_selected();
            }
            else
            {
                text_ = text_.substr(0,cursor_pos) + ustr +
                    text_.substr(cursor_pos,text_.size()-cursor_pos);

                adjust_total_rect();
                move_cursor(cursor_pos+ustr.size());
            }

            // send out the text modified event
            if (text_modified_handler.is_set())
                text_modified_handler();
        }
    }

// ----------------------------------------------------------------------------------------

    void text_box::
    move_cursor (
        unsigned long pos
    )
    {
        using namespace std;
        const long old_cursor_pos = cursor_pos;

        // figure out where the cursor is supposed to be
        cursor_rect = mfont->compute_cursor_rect(get_text_rect(), text_, pos);
        const point origin(total_rect().left(), total_rect().top());

        cursor_pos = pos;

        const unsigned long padding = style->get_padding(*mfont);

        // find the delta between the cursor rect and the corner of the total rect
        point delta = point(cursor_rect.left(), cursor_rect.top()) - point(total_rect().left(), total_rect().top());

        // now scroll us so that we can see the current cursor
        scroll_to_rect(centered_rect(cursor_rect, cursor_rect.width() + padding + 6, cursor_rect.height() + 1));

        // adjust the cursor_rect so that it is relative to the total_rect
        cursor_rect = translate_rect(cursor_rect, -origin);

        parent.set_im_pos(cursor_rect.left(), cursor_rect.top());

        if (old_cursor_pos != cursor_pos)
        {
            if (shift_pos != -1)
            {
                highlight_start = std::min(shift_pos,cursor_pos);
                highlight_end = std::max(shift_pos,cursor_pos)-1;
            }

            if (highlight_start > highlight_end)
                on_no_text_selected();
            else
                on_text_is_selected();

            recent_movement = true;
            cursor_visible = true;
            parent.invalidate_rectangle(display_rect());
        }

        if (shift_pos == -1)
        {
            highlight_start = 0;
            highlight_end = -1;
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//       perspective_display member functions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    perspective_display::
    perspective_display(
        drawable_window& w
    ) :
        drawable(w,MOUSE_MOVE|MOUSE_CLICK|MOUSE_WHEEL)
    {
        clear_overlay();
        enable_events();
    }

// ----------------------------------------------------------------------------------------

    perspective_display::
    ~perspective_display(
    )
    {
        disable_events();
        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    void perspective_display::
    set_size (
        unsigned long width,
        unsigned long height
    )
    {
        auto_mutex lock(m);
        rectangle old(rect);
        rect = resize_rect(rect,width,height);
        tform = camera_transform(tform.get_camera_pos(),
            tform.get_camera_looking_at(),
            tform.get_camera_up_direction(),
            tform.get_camera_field_of_view(),
            std::min(rect.width(),rect.height()));
        parent.invalidate_rectangle(old+rect);
    }

// ----------------------------------------------------------------------------------------

    void perspective_display::
    add_overlay (
        const std::vector<overlay_line>& overlay
    )
    {
        auto_mutex M(m);
        if (overlay.size() == 0)
            return;
        // push this new overlay into our overlay vector
        overlay_lines.insert(overlay_lines.end(), overlay.begin(), overlay.end());

        for (unsigned long i = 0; i < overlay.size(); ++i)
        {
            sum_pts += overlay[i].p1;
            sum_pts += overlay[i].p2;
            max_pts.x() = std::max(overlay[i].p1.x(), max_pts.x());
            max_pts.x() = std::max(overlay[i].p2.x(), max_pts.x());
            max_pts.y() = std::max(overlay[i].p1.y(), max_pts.y());
            max_pts.y() = std::max(overlay[i].p2.y(), max_pts.y());
            max_pts.z() = std::max(overlay[i].p1.z(), max_pts.z());
            max_pts.z() = std::max(overlay[i].p2.z(), max_pts.z());
        }

        tform = camera_transform(max_pts,
            sum_pts/(overlay_lines.size()*2+overlay_dots.size()),
            vector<double>(0,0,1),
            tform.get_camera_field_of_view(),
            std::min(rect.width(),rect.height()));

        // make the parent window redraw us now that we changed the overlay
        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    void perspective_display::
    add_overlay (
        const std::vector<overlay_dot>& overlay
    )
    {
        auto_mutex M(m);
        if (overlay.size() == 0)
            return;

        for (unsigned long i = 0; i < overlay.size(); ++i)
        {
            overlay_dots.push_back(overlay[i]);

            sum_pts += overlay[i].p;
            max_pts.x() = std::max(overlay[i].p.x(), max_pts.x());
            max_pts.y() = std::max(overlay[i].p.y(), max_pts.y());
            max_pts.z() = std::max(overlay[i].p.z(), max_pts.z());
        }

        tform = camera_transform(max_pts,
            sum_pts/(overlay_lines.size()*2+overlay_dots.size()),
            vector<double>(0,0,1),
            tform.get_camera_field_of_view(),
            std::min(rect.width(),rect.height()));

        // make the parent window redraw us now that we changed the overlay
        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    void perspective_display::
    clear_overlay (
    )
    {
        auto_mutex lock(m);
        overlay_dots.clear();
        overlay_lines.clear();
        sum_pts = vector<double>();
        max_pts = vector<double>(-std::numeric_limits<double>::infinity(),
            -std::numeric_limits<double>::infinity(),
            -std::numeric_limits<double>::infinity());

        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    void perspective_display::
    set_dot_double_clicked_handler (
        const any_function<void(const vector<double>&)>& event_handler_
    )
    {
        auto_mutex M(m);
        dot_clicked_event_handler = event_handler_;
    }

// ----------------------------------------------------------------------------------------

    void perspective_display::
    draw (
        const canvas& c
    ) const
    {
        if (depth.nr() < (long)c.height() || depth.nc() < (long)c.width())
            depth.set_size(c.height(), c.width());
        assign_all_pixels(depth, std::numeric_limits<float>::infinity());

        rectangle area = rect.intersect(c);
        fill_rect(c, area, 0);
        for (unsigned long i = 0; i < overlay_lines.size(); ++i)
        {
            draw_line(c, tform(overlay_lines[i].p1)+rect.tl_corner(),
                         tform(overlay_lines[i].p2)+rect.tl_corner(),
                         overlay_lines[i].color,
                         area);
        }
        for (unsigned long i = 0; i < overlay_dots.size(); ++i)
        {
            double scale, distance;
            point p = tform(overlay_dots[i].p, scale, distance) + rect.tl_corner();
            if (area.contains(p) && depth[p.y()-c.top()][p.x()-c.left()] > distance)
            {
                depth[p.y()-c.top()][p.x()-c.left()] = distance;
                assign_pixel(c[p.y()-c.top()][p.x()-c.left()], overlay_dots[i].color);
            }
        }

    }

// ----------------------------------------------------------------------------------------

    void perspective_display::
    on_wheel_up (
        unsigned long //state
    )
    {
        if (rect.contains(lastx,lasty) == false || hidden || !enabled)
            return;

        const double alpha = 0.10;
        const vector<double> delta = alpha*(tform.get_camera_pos() - tform.get_camera_looking_at());
        tform = camera_transform(
            tform.get_camera_pos() - delta,
            tform.get_camera_looking_at(),
            tform.get_camera_up_direction(),
            tform.get_camera_field_of_view(),
            std::min(rect.width(),rect.height()));
        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    void perspective_display::
    on_wheel_down (
        unsigned long //state
    )
    {
        if (rect.contains(lastx,lasty) == false || hidden || !enabled)
            return;

        const double alpha = 0.10;
        const vector<double> delta = alpha*(tform.get_camera_pos() - tform.get_camera_looking_at());
        tform = camera_transform(
            tform.get_camera_pos() + delta,
            tform.get_camera_looking_at(),
            tform.get_camera_up_direction(),
            tform.get_camera_field_of_view(),
            std::min(rect.width(),rect.height()));
        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    void perspective_display::
    on_mouse_down (
        unsigned long btn,
        unsigned long, //state
        long x,
        long y,
        bool is_double_click
    )
    {
        if (btn == base_window::LEFT || btn == base_window::RIGHT)
        {
            last = point(x,y);
        }
        if (is_double_click && btn == base_window::LEFT && enabled && !hidden && overlay_dots.size() != 0)
        {
            double best_dist = std::numeric_limits<double>::infinity();
            unsigned long best_idx = 0;
            const dpoint pp(x,y);
            for (unsigned long i = 0; i < overlay_dots.size(); ++i)
            {
                dpoint p = tform(overlay_dots[i].p) + rect.tl_corner();
                double dist = length_squared(p-pp);
                if (dist < best_dist)
                {
                    best_dist = dist;
                    best_idx = i;
                }
            }
            if (dot_clicked_event_handler.is_set())
                dot_clicked_event_handler(overlay_dots[best_idx].p);
        }
    }

// ----------------------------------------------------------------------------------------

    void perspective_display::
    on_mouse_move (
        unsigned long state,
        long x,
        long y
    )
    {
        if (!enabled || hidden)
            return;

        if (state == base_window::LEFT)
        {
            const point cur(x, y);
            dpoint delta = last-cur;
            last = cur;

            const vector<double> radius = tform.get_camera_pos()-tform.get_camera_looking_at();
            delta *= 2*pi*length(radius)/600.0;
            vector<double> tangent_x = tform.get_camera_up_direction().cross(radius).normalize();
            vector<double> tangent_y = radius.cross(tangent_x).normalize();
            vector<double> new_pos = tform.get_camera_pos() + tangent_x*delta.x() + tangent_y*-delta.y();

            // now make it have the correct radius relative to the looking at point.
            new_pos = (new_pos-tform.get_camera_looking_at()).normalize()*length(radius) + tform.get_camera_looking_at();

            tform = camera_transform(new_pos,
                tform.get_camera_looking_at(),
                tangent_y,
                tform.get_camera_field_of_view(),
                std::min(rect.width(),rect.height()));
            parent.invalidate_rectangle(rect);
        }
        else if (state == (base_window::LEFT|base_window::SHIFT) ||
            state == base_window::RIGHT)
        {
            const point cur(x, y);
            dpoint delta = last-cur;
            last = cur;

            const vector<double> radius = tform.get_camera_pos()-tform.get_camera_looking_at();
            delta *= 2*pi*length(radius)/600.0;
            vector<double> tangent_x = tform.get_camera_up_direction().cross(radius).normalize();
            vector<double> tangent_y = radius.cross(tangent_x).normalize();

            vector<double> offset = tangent_x*delta.x() + tangent_y*-delta.y();

            tform = camera_transform(
                tform.get_camera_pos()+offset,
                tform.get_camera_looking_at()+offset,
                tform.get_camera_up_direction(),
                tform.get_camera_field_of_view(),
                std::min(rect.width(),rect.height()));
            parent.invalidate_rectangle(rect);
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//       image_display member functions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    namespace impl
    {
        class image_display_functor
        {
            const std::string str;
            const member_function_pointer<const std::string&> mfp;
        public:
            image_display_functor (
                const std::string& str_,
                const member_function_pointer<const std::string&>& mfp_
            ) : str(str_),
                mfp(mfp_)
            {}

            void operator() (
            ) const { mfp(str); }
        };
    }

    image_display::
    image_display(
        drawable_window& w
    ):
        scrollable_region(w,KEYBOARD_EVENTS),
        zoom_in_scale(1),
        zoom_out_scale(1),
        drawing_rect(true),
        rect_is_selected(false),
        selected_rect(0),
        default_rect_color(255,0,0,255),
        parts_menu(w),
        part_width(15), // width part circles are drawn on the screen
        overlay_editing_enabled(true),
        highlight_timer(*this, &image_display::timer_event_unhighlight_rect),
        highlighted_rect(std::numeric_limits<unsigned long>::max())
    {
        enable_mouse_drag();

        highlight_timer.set_delay_time(250);
        set_horizontal_scroll_increment(1);
        set_vertical_scroll_increment(1);
        set_horizontal_mouse_wheel_scroll_increment(30);
        set_vertical_mouse_wheel_scroll_increment(30);

        parts_menu.disable();

        enable_events();
    }

// ----------------------------------------------------------------------------------------

    void image_display::
    on_part_add (
        const std::string& part_name
    )
    {
        if (!rect_is_selected)
            return;

        const rectangle valid_area = get_rect_on_screen(selected_rect);
        const point loc = nearest_point(valid_area,last_right_click_pos);

        // Transform loc from gui window space into the space used by the overlay
        // rectangles (i.e. relative to the raw image)
        const point origin(total_rect().tl_corner());
        point c1 = loc - origin;
        if (zoom_in_scale != 1)
        {
            c1 = c1/(double)zoom_in_scale;
        }
        else if (zoom_out_scale != 1)
        {
            c1 = c1*(double)zoom_out_scale;
        }

        overlay_rects[selected_rect].parts[part_name] = c1;
        parent.invalidate_rectangle(rect);

        if (event_handler.is_set())
            event_handler();
    }

// ----------------------------------------------------------------------------------------

    image_display::
    ~image_display(
    )
    {
        highlight_timer.stop_and_wait();
        disable_events();
        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    rectangle image_display::
    get_image_display_rect (
    ) const
    {
        if (zoom_in_scale != 1)
        {
            return rectangle(0,0, img.nc()*zoom_in_scale-1, img.nr()*zoom_in_scale-1);
        }
        else if (zoom_out_scale != 1)
        {
            return rectangle(0,0, img.nc()/zoom_out_scale-1, img.nr()/zoom_out_scale-1);
        }
        else
        {
            return dlib::get_rect(img);
        }
    }

// ----------------------------------------------------------------------------------------

    void image_display::
    add_overlay (
        const overlay_rect& overlay
    )
    {
        auto_mutex M(m);
        // push this new overlay into our overlay vector
        overlay_rects.push_back(overlay);

        // make the parent window redraw us now that we changed the overlay
        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    void image_display::
    add_overlay (
        const overlay_line& overlay
    )
    {
        auto_mutex M(m);

        // push this new overlay into our overlay vector
        overlay_lines.push_back(overlay);

        // make the parent window redraw us now that we changed the overlay
        parent.invalidate_rectangle(get_rect_on_screen(rectangle(overlay.p1, overlay.p2)));
    }

// ----------------------------------------------------------------------------------------

    void image_display::
    add_overlay (
        const overlay_circle& overlay
    )
    {
        auto_mutex M(m);

        // push this new overlay into our overlay vector
        overlay_circles.push_back(overlay);

        // make the parent window redraw us now that we changed the overlay
        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    void image_display::
    add_overlay (
        const std::vector<overlay_rect>& overlay
    )
    {
        auto_mutex M(m);

        // push this new overlay into our overlay vector
        overlay_rects.insert(overlay_rects.end(), overlay.begin(), overlay.end());

        // make the parent window redraw us now that we changed the overlay
        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    void image_display::
    add_overlay (
        const std::vector<overlay_line>& overlay
    )
    {
        auto_mutex M(m);

        // push this new overlay into our overlay vector
        overlay_lines.insert(overlay_lines.end(), overlay.begin(), overlay.end());

        // make the parent window redraw us now that we changed the overlay
        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    void image_display::
    add_overlay (
        const std::vector<overlay_circle>& overlay
    )
    {
        auto_mutex M(m);

        // push this new overlay into our overlay vector
        overlay_circles.insert(overlay_circles.end(), overlay.begin(), overlay.end());

        // make the parent window redraw us now that we changed the overlay
        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    void image_display::
    clear_overlay (
    )
    {
        auto_mutex M(m);
        overlay_rects.clear();
        overlay_lines.clear();
        overlay_circles.clear();
        parent.invalidate_rectangle(rect);
    }

// ----------------------------------------------------------------------------------------

    rectangle image_display::
    get_rect_on_screen (
        rectangle orect
    ) const
    {
        const point origin(total_rect().tl_corner());
        orect.left()   = orect.left()*zoom_in_scale/zoom_out_scale;
        orect.top()    = orect.top()*zoom_in_scale/zoom_out_scale;
        if (zoom_in_scale != 1)
        {
            // make it so the box surrounds the pixels when we zoom in.
            orect.right()  = (orect.right()+1)*zoom_in_scale/zoom_out_scale;
            orect.bottom() = (orect.bottom()+1)*zoom_in_scale/zoom_out_scale;
        }
        else
        {
            orect.right()  = orect.right()*zoom_in_scale/zoom_out_scale;
            orect.bottom() = orect.bottom()*zoom_in_scale/zoom_out_scale;
        }

        return translate_rect(orect, origin);
    }

// ----------------------------------------------------------------------------------------

    rectangle image_display::
    get_rect_on_screen (
        unsigned long idx
    ) const
    {
        return get_rect_on_screen(overlay_rects[idx].rect);
    }

// ----------------------------------------------------------------------------------------

    void image_display::
    draw (
        const canvas& c
    ) const
    {
        scrollable_region::draw(c);

        rectangle area = display_rect().intersect(c);
        if (area.is_empty())
            return;

        const point origin(total_rect().tl_corner());

        // draw the image on the screen
        const rectangle img_area = total_rect().intersect(area);
        for (long row = img_area.top(); row <= img_area.bottom(); ++row)
        {
            for (long col = img_area.left(); col <= img_area.right(); ++col)
            {
                assign_pixel(c[row-c.top()][col-c.left()],
                             img[(row-origin.y())*zoom_out_scale/zoom_in_scale][(col-origin.x())*zoom_out_scale/zoom_in_scale]);
            }
        }

        // now draw all the overlay rectangles
        for (unsigned long i = 0; i < overlay_rects.size(); ++i)
        {
            const rectangle orect = get_rect_on_screen(i);

            if (rect_is_selected && selected_rect == i)
            {
                draw_rectangle(c, orect, invert_pixel(overlay_rects[i].color), area);
            }
            else if (highlighted_rect < overlay_rects.size() && highlighted_rect == i)
            {
                // Draw the rectangle wider and with a slightly different color that tapers
                // out at the edges of the line.
                hsi_pixel temp;
                assign_pixel(temp, 0);
                assign_pixel(temp, overlay_rects[i].color);
                temp.s = 255;
                temp.h = temp.h + 20;
                if (temp.i < 245)
                    temp.i += 10;
                rgb_pixel p;
                assign_pixel(p, temp);
                rgb_alpha_pixel po, po2;
                assign_pixel(po, p);
                po.alpha = 160;
                po2 = po;
                po2.alpha = 90;
                draw_rectangle(c, grow_rect(orect,2), po2, area);
                draw_rectangle(c, grow_rect(orect,1), po, area);
                draw_rectangle(c, orect, p, area);
                draw_rectangle(c, shrink_rect(orect,1), po, area);
                draw_rectangle(c, shrink_rect(orect,2), po2, area);
            }
            else
            {
                draw_rectangle(c, orect, overlay_rects[i].color, area);
            }

            if (overlay_rects[i].label.size() != 0)
            {
                // make a rectangle that is at the spot we want to draw our string
                rectangle r(orect.br_corner(),  c.br_corner());
                mfont->draw_string(c, r, overlay_rects[i].label, overlay_rects[i].color, 0,
                                   std::string::npos, area);
            }

            // draw circles for each "part" in this overlay rectangle.
            std::map<std::string,point>::const_iterator itr;
            for (itr = overlay_rects[i].parts.begin(); itr != overlay_rects[i].parts.end(); ++itr)
            {
                if (itr->second == OBJECT_PART_NOT_PRESENT)
                    continue;

                rectangle temp = centered_rect(get_rect_on_screen(centered_rect(itr->second,1,1)), part_width, part_width);

                if (rect_is_selected && selected_rect == i &&
                    selected_part_name.size() != 0 && selected_part_name == itr->first)
                {
                    draw_circle(c, center(temp), temp.width()/2, invert_pixel(overlay_rects[i].color), area);
                }
                else
                {
                    draw_circle(c, center(temp), temp.width()/2, overlay_rects[i].color, area);
                }

                // make a rectangle that is at the spot we want to draw our string
                rectangle r((temp.br_corner() + temp.bl_corner())/2,
                            c.br_corner());
                mfont->draw_string(c, r, itr->first, overlay_rects[i].color, 0,
                                   std::string::npos, area);
            }

            if (overlay_rects[i].crossed_out)
            {
                if (rect_is_selected && selected_rect == i)
                {
                    draw_line(c, orect.tl_corner(), orect.br_corner(),invert_pixel(overlay_rects[i].color), area);
                    draw_line(c, orect.bl_corner(), orect.tr_corner(),invert_pixel(overlay_rects[i].color), area);
                }
                else
                {
                    draw_line(c, orect.tl_corner(), orect.br_corner(),overlay_rects[i].color, area);
                    draw_line(c, orect.bl_corner(), orect.tr_corner(),overlay_rects[i].color, area);
                }
            }
        }

        // now draw all the overlay lines
        for (unsigned long i = 0; i < overlay_lines.size(); ++i)
        {
            draw_line(c,
                      zoom_in_scale*overlay_lines[i].p1/zoom_out_scale + origin,
                      zoom_in_scale*overlay_lines[i].p2/zoom_out_scale + origin,
                      overlay_lines[i].color, area);
        }

        // now draw all the overlay circles
        for (unsigned long i = 0; i < overlay_circles.size(); ++i)
        {
            const point center = zoom_in_scale*overlay_circles[i].center/zoom_out_scale + origin;
            const int radius = zoom_in_scale*overlay_circles[i].radius/zoom_out_scale;
            draw_circle(c,
                      center,
                      radius,
                      overlay_circles[i].color, area);

            if (overlay_circles[i].label.size() != 0)
            {
                const point temp = center + point(0,radius);

                // make a rectangle that is at the spot we want to draw our string
                rectangle r(temp,  c.br_corner());
                mfont->draw_string(c, r, overlay_circles[i].label, overlay_circles[i].color, 0,
                                   std::string::npos, area);
            }
        }

        if (drawing_rect)
            draw_rectangle(c, rect_to_draw, invert_pixel(default_rect_color), area);
    }

// ----------------------------------------------------------------------------------------

    void image_display::
    on_keydown (
        unsigned long key,
        bool is_printable,
        unsigned long state
    )
    {
        scrollable_region::on_keydown(key,is_printable, state);

        if (!is_printable && !hidden && enabled && rect_is_selected &&
            (key == base_window::KEY_BACKSPACE || key == base_window::KEY_DELETE))
        {
            moving_overlay = false;
            rect_is_selected = false;
            parts_menu.disable();
            if (selected_part_name.size() == 0)
                overlay_rects.erase(overlay_rects.begin() + selected_rect);
            else
                overlay_rects[selected_rect].parts.erase(selected_part_name);
            parent.invalidate_rectangle(rect);

            if (event_handler.is_set())
                event_handler();
        }

        if (is_printable && !hidden && enabled && rect_is_selected && (key == 'i'))
        {
            overlay_rects[selected_rect].crossed_out = !overlay_rects[selected_rect].crossed_out;
            parent.invalidate_rectangle(rect);

            if (event_handler.is_set())
                event_handler();
        }
    }

// ----------------------------------------------------------------------------------------

    void image_display::
    add_labelable_part_name (
        const std::string& name
    )
    {
        auto_mutex lock(m);
        if (part_names.insert(name).second)
        {
            member_function_pointer<const std::string&> mfp;
            mfp.set(*this,&image_display::on_part_add);
            parts_menu.menu().add_menu_item(menu_item_text("Add " + name,impl::image_display_functor(name,mfp)));
        }
    }

// ----------------------------------------------------------------------------------------

    void image_display::
    clear_labelable_part_names (
    )
    {
        auto_mutex lock(m);
        part_names.clear();
        parts_menu.menu().clear();
    }

// ----------------------------------------------------------------------------------------

    void image_display::
    on_mouse_down (
        unsigned long btn,
        unsigned long state,
        long x,
        long y,
        bool is_double_click
    )
    {
        scrollable_region::on_mouse_down(btn, state, x, y, is_double_click);

        if (rect.contains(x,y) == false || hidden || !enabled)
            return;

        if (image_clicked_handler.is_set())
        {
            const point origin(total_rect().tl_corner());
            point p(x,y);
            p -= origin;
            if (zoom_in_scale != 1)
                p = p/zoom_in_scale;
            else if (zoom_out_scale != 1)
                p = p*zoom_out_scale;

            if (dlib::get_rect(img).contains(p))
                image_clicked_handler(p, is_double_click, btn);
        }

        if (!overlay_editing_enabled)
            return;

        if (btn == base_window::RIGHT && (state&base_window::SHIFT))
        {
            const bool rect_was_selected = rect_is_selected;
            rect_is_selected = false;
            parts_menu.disable();

            long best_dist = std::numeric_limits<long>::max();
            long best_idx = 0;
            std::string best_part;

            // check if this click landed on any of the overlay rectangles
            for (unsigned long i = 0; i < overlay_rects.size(); ++i)
            {
                const rectangle orect = get_rect_on_screen(i);

                const long dist = distance_to_rect_edge(orect, point(x,y));

                if (dist < best_dist)
                {
                    best_dist = dist;
                    best_idx = i;
                    best_part.clear();
                }

                std::map<std::string,point>::const_iterator itr;
                for (itr = overlay_rects[i].parts.begin(); itr != overlay_rects[i].parts.end(); ++itr)
                {
                    if (itr->second == OBJECT_PART_NOT_PRESENT)
                        continue;

                    rectangle temp = centered_rect(get_rect_on_screen(centered_rect(itr->second,1,1)), part_width, part_width);
                    point c = center(temp);

                    // distance from edge of part circle
                    const long dist = static_cast<long>(std::abs(length(c - point(x,y)) + 0.5 - temp.width()/2));
                    if (dist < best_dist)
                    {
                        best_idx = i;
                        best_dist = dist;
                        best_part = itr->first;
                    }
                }
            }

            if (best_dist < 13)
            {
                moving_overlay = true;
                moving_rect = best_idx;
                moving_part_name = best_part;
                // If we are moving one of the sides  of the rectangle rather than one of
                // the parts circles then we need to figure out which side of the rectangle
                // we are moving.
                if (best_part.size() == 0)
                {
                    // which side is the click closest to?
                    const rectangle orect = get_rect_on_screen(best_idx);
                    const point p = nearest_point(orect,point(x,y));
                    long dist_left   = std::abs(p.x()-orect.left());
                    long dist_top    = std::abs(p.y()-orect.top());
                    long dist_right  = std::abs(p.x()-orect.right());
                    long dist_bottom = std::abs(p.y()-orect.bottom());
                    long min_val = std::min(std::min(dist_left,dist_right),std::min(dist_top,dist_bottom));
                    if (dist_left == min_val)
                        moving_what = MOVING_RECT_LEFT;
                    else if (dist_top == min_val)
                        moving_what = MOVING_RECT_TOP;
                    else if (dist_right == min_val)
                        moving_what = MOVING_RECT_RIGHT;
                    else
                        moving_what = MOVING_RECT_BOTTOM;
                }
                else
                {
                    moving_what = MOVING_PART;
                }
                // Do this to make the moving stuff snap to the mouse immediately.
                on_mouse_move(state|btn,x,y);
            }

            if (rect_was_selected)
                parent.invalidate_rectangle(rect);

            return;
        }

        if (btn == base_window::RIGHT && rect_is_selected)
        {
            last_right_click_pos = point(x,y);
            parts_menu.set_rect(get_rect_on_screen(selected_rect));
            return;
        }

        if (btn == base_window::LEFT && (state&base_window::CONTROL) && !drawing_rect)
        {
            long best_dist = std::numeric_limits<long>::max();
            long best_idx = 0;
            // check if this click landed on any of the overlay rectangles
            for (unsigned long i = 0; i < overlay_rects.size(); ++i)
            {
                const rectangle orect = get_rect_on_screen(i);
                const long dist = distance_to_rect_edge(orect, point(x,y));

                if (dist < best_dist)
                {
                    best_dist = dist;
                    best_idx = i;
                }
            }
            if (best_dist < 13)
            {
                overlay_rects[best_idx].label = default_rect_label;
                highlighted_rect = best_idx;
                highlight_timer.stop();
                highlight_timer.start();
                if (event_handler.is_set())
                    event_handler();
                parent.invalidate_rectangle(rect);
            }
            return;
        }

        if (!is_double_click && btn == base_window::LEFT && (state&base_window::SHIFT))
        {
            drawing_rect = true;
            rect_anchor = point(x,y);

            if (rect_is_selected)
            {
                rect_is_selected = false;
                parts_menu.disable();
                parent.invalidate_rectangle(rect);
            }
        }
        else if (drawing_rect)
        {
            if (rect_is_selected)
            {
                rect_is_selected = false;
                parts_menu.disable();
            }

            drawing_rect = false;
            parent.invalidate_rectangle(rect);
        }
        else if (is_double_click)
        {
            const bool rect_was_selected = rect_is_selected;
            rect_is_selected = false;
            parts_menu.disable();

            long best_dist = std::numeric_limits<long>::max();
            long best_idx = 0;
            std::string best_part;

            // check if this click landed on any of the overlay rectangles
            for (unsigned long i = 0; i < overlay_rects.size(); ++i)
            {
                const rectangle orect = get_rect_on_screen(i);

                const long dist = distance_to_rect_edge(orect, point(x,y));

                if (dist < best_dist)
                {
                    best_dist = dist;
                    best_idx = i;
                    best_part.clear();
                }

                std::map<std::string,point>::const_iterator itr;
                for (itr = overlay_rects[i].parts.begin(); itr != overlay_rects[i].parts.end(); ++itr)
                {
                    if (itr->second == OBJECT_PART_NOT_PRESENT)
                        continue;

                    rectangle temp = centered_rect(get_rect_on_screen(centered_rect(itr->second,1,1)), part_width, part_width);
                    point c = center(temp);

                    // distance from edge of part circle
                    const long dist = static_cast<long>(std::abs(length(c - point(x,y)) + 0.5 - temp.width()/2));
                    if (dist < best_dist)
                    {
                        best_idx = i;
                        best_dist = dist;
                        best_part = itr->first;
                    }
                }
            }

            if (best_dist < 13)
            {
                rect_is_selected = true;
                if (part_names.size() != 0)
                    parts_menu.enable();
                selected_rect = best_idx;
                selected_part_name = best_part;
                if (orect_selected_event_handler.is_set())
                    orect_selected_event_handler(overlay_rects[best_idx]);
            }

            if (rect_is_selected || rect_was_selected)
                parent.invalidate_rectangle(rect);
        }
        else if (rect_is_selected)
        {
            rect_is_selected = false;
            parts_menu.disable();
            parent.invalidate_rectangle(rect);
        }
    }

// ----------------------------------------------------------------------------------------

    std::vector<image_display::overlay_rect> image_display::
    get_overlay_rects (
    ) const
    {
        auto_mutex lock(m);
        return overlay_rects;
    }

// ----------------------------------------------------------------------------------------

    void image_display::
    set_default_overlay_rect_label (
        const std::string& label
    )
    {
        auto_mutex lock(m);
        default_rect_label = label;
    }

// ----------------------------------------------------------------------------------------

    std::string image_display::
    get_default_overlay_rect_label (
    ) const
    {
        auto_mutex lock(m);
        return default_rect_label;
    }

// ----------------------------------------------------------------------------------------

    void image_display::
    set_default_overlay_rect_color (
        const rgb_alpha_pixel& color
    )
    {
        auto_mutex lock(m);
        default_rect_color = color;
    }

// ----------------------------------------------------------------------------------------

    rgb_alpha_pixel image_display::
    get_default_overlay_rect_color (
    ) const
    {
        auto_mutex lock(m);
        return default_rect_color;
    }

// ----------------------------------------------------------------------------------------

    void image_display::
    on_mouse_up (
        unsigned long btn,
        unsigned long state,
        long x,
        long y
    )
    {
        scrollable_region::on_mouse_up(btn,state,x,y);

        if (drawing_rect && btn == base_window::LEFT && (state&base_window::SHIFT) &&
            !hidden && enabled)
        {
            const point origin(total_rect().tl_corner());
            point c1 = point(x,y) - origin;
            point c2 = rect_anchor - origin;

            if (zoom_in_scale != 1)
            {
                c1 = c1/(double)zoom_in_scale;
                c2 = c2/(double)zoom_in_scale;
            }
            else if (zoom_out_scale != 1)
            {
                c1 = c1*(double)zoom_out_scale;
                c2 = c2*(double)zoom_out_scale;
            }

            rectangle new_rect(c1,c2);
            if (zoom_in_scale != 1)
            {
                // When we are zoomed in we adjust the rectangles a little so they
                // are drown surrounding the pixels inside the rect.  This adjustment
                // is necessary to make this code consistent with this goal.
                new_rect.right() -= 1;
                new_rect.bottom() -= 1;
            }

            if (new_rect.width() > 0 && new_rect.height() > 0)
            {
                add_overlay(overlay_rect(new_rect, default_rect_color, default_rect_label));

                if (event_handler.is_set())
                    event_handler();
            }
        }

        if (drawing_rect)
        {
            drawing_rect = false;
            parent.invalidate_rectangle(rect);
        }
        if (moving_overlay)
        {
            moving_overlay = false;
        }
    }

// ----------------------------------------------------------------------------------------

    void image_display::
    on_mouse_move (
        unsigned long state,
        long x,
        long y
    )
    {
        scrollable_region::on_mouse_move(state,x,y);

        if (drawing_rect)
        {
            if ((state&base_window::LEFT) && (state&base_window::SHIFT) && !hidden && enabled)
            {
                rectangle new_rect(point(x,y), rect_anchor);
                parent.invalidate_rectangle(new_rect + rect_to_draw);
                rect_to_draw = new_rect;
            }
            else
            {
                drawing_rect = false;
                parent.invalidate_rectangle(rect);
            }
            moving_overlay = false;
        }
        else if (moving_overlay)
        {
            if ((state&base_window::RIGHT) && (state&base_window::SHIFT) && !hidden && enabled)
            {
                // map point(x,y) into the image coordinate space.
                point p = point(x,y) - total_rect().tl_corner();
                if (zoom_in_scale != 1)
                {
                    if (moving_what == MOVING_PART)
                        p = p/(double)zoom_in_scale-dpoint(0.5,0.5);
                    else
                        p = p/(double)zoom_in_scale;
                }
                else if (zoom_out_scale != 1)
                {
                    p = p*(double)zoom_out_scale;
                }

                if (moving_what == MOVING_PART)
                {
                    if (overlay_rects[moving_rect].parts[moving_part_name] != p)
                    {
                        overlay_rects[moving_rect].parts[moving_part_name] = p;
                        parent.invalidate_rectangle(rect);
                        if (event_handler.is_set())
                            event_handler();
                    }
                }
                else
                {
                    rectangle original = overlay_rects[moving_rect].rect;
                    if (moving_what == MOVING_RECT_LEFT)
                        overlay_rects[moving_rect].rect.left() = std::min(p.x(), overlay_rects[moving_rect].rect.right());
                    else if (moving_what == MOVING_RECT_RIGHT)
                        overlay_rects[moving_rect].rect.right() = std::max(p.x()-1, overlay_rects[moving_rect].rect.left());
                    else if (moving_what == MOVING_RECT_TOP)
                        overlay_rects[moving_rect].rect.top() = std::min(p.y(), overlay_rects[moving_rect].rect.bottom());
                    else
                        overlay_rects[moving_rect].rect.bottom() = std::max(p.y()-1, overlay_rects[moving_rect].rect.top());

                    if (original != overlay_rects[moving_rect].rect)
                    {
                        parent.invalidate_rectangle(rect);
                        if (event_handler.is_set())
                            event_handler();
                    }
                }
            }
            else
            {
                moving_overlay = false;
            }
        }
    }

// ----------------------------------------------------------------------------------------

    void image_display::
    on_wheel_up (
        unsigned long state
    )
    {
        // disable mouse wheel if the user is drawing a rectangle
        if (drawing_rect)
            return;

        // if CONTROL is not being held down
        if ((state & base_window::CONTROL) == 0)
        {
            scrollable_region::on_wheel_up(state);
            return;
        }

        if (rect.contains(lastx,lasty) == false || hidden || !enabled)
            return;

        if (zoom_in_scale < 100 && zoom_out_scale == 1)
        {
            const point mouse_loc(lastx, lasty);
            // the pixel in img that the mouse is over
            const point pix_loc = (mouse_loc - total_rect().tl_corner())/zoom_in_scale;

            zoom_in_scale = zoom_in_scale*10/9 + 1;

            set_total_rect_size(img.nc()*zoom_in_scale, img.nr()*zoom_in_scale);

            // make is to the pixel under the mouse doesn't move while we zoom
            const point delta = total_rect().tl_corner() - (mouse_loc - pix_loc*zoom_in_scale);
            scroll_to_rect(translate_rect(display_rect(), delta));
        }
        else if (zoom_out_scale != 1)
        {
            const point mouse_loc(lastx, lasty);
            // the pixel in img that the mouse is over
            const point pix_loc = (mouse_loc - total_rect().tl_corner())*zoom_out_scale;

            zoom_out_scale = zoom_out_scale*9/10;
            if (zoom_out_scale == 0)
                zoom_out_scale = 1;

            set_total_rect_size(img.nc()/zoom_out_scale, img.nr()/zoom_out_scale);

            // make is to the pixel under the mouse doesn't move while we zoom
            const point delta = total_rect().tl_corner() - (mouse_loc - pix_loc/zoom_out_scale);
            scroll_to_rect(translate_rect(display_rect(), delta));
        }
    }

// ----------------------------------------------------------------------------------------

    void image_display::
    on_wheel_down (
        unsigned long state
    )
    {
        // disable mouse wheel if the user is drawing a rectangle
        if (drawing_rect)
            return;

        // if CONTROL is not being held down
        if ((state & base_window::CONTROL) == 0)
        {
            scrollable_region::on_wheel_down(state);
            return;
        }

        if (rect.contains(lastx,lasty) == false || hidden || !enabled)
            return;

        if (zoom_in_scale != 1)
        {
            const point mouse_loc(lastx, lasty);
            // the pixel in img that the mouse is over
            const point pix_loc = (mouse_loc - total_rect().tl_corner())/zoom_in_scale;

            zoom_in_scale = zoom_in_scale*9/10;
            if (zoom_in_scale == 0)
                zoom_in_scale = 1;

            set_total_rect_size(img.nc()*zoom_in_scale, img.nr()*zoom_in_scale);

            // make is to the pixel under the mouse doesn't move while we zoom
            const point delta = total_rect().tl_corner() - (mouse_loc - pix_loc*zoom_in_scale);
            scroll_to_rect(translate_rect(display_rect(), delta));
        }
        else if (std::max(img.nr(), img.nc())/zoom_out_scale > 10)
        {
            const point mouse_loc(lastx, lasty);
            // the pixel in img that the mouse is over
            const point pix_loc = (mouse_loc - total_rect().tl_corner())*zoom_out_scale;

            zoom_out_scale = zoom_out_scale*10/9 + 1;

            set_total_rect_size(img.nc()/zoom_out_scale, img.nr()/zoom_out_scale);

            // make is to the pixel under the mouse doesn't move while we zoom
            const point delta = total_rect().tl_corner() - (mouse_loc - pix_loc/zoom_out_scale);
            scroll_to_rect(translate_rect(display_rect(), delta));
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//         image_window member functions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    image_window::
    image_window(
    ) :
        gui_img(*this),
        window_has_closed(false),
        have_last_click(false),
        mouse_btn(0),
        clicked_signaler(this->wm),
        tie_input_events(false)
    {

        gui_img.set_image_clicked_handler(*this, &image_window::on_image_clicked);
        gui_img.disable_overlay_editing();
        // show this window on the screen
        show();
    }

// ----------------------------------------------------------------------------------------

    image_window::
    ~image_window(
    )
    {
        // You should always call close_window() in the destructor of window
        // objects to ensure that no events will be sent to this window while
        // it is being destructed.
        close_window();
    }

// ----------------------------------------------------------------------------------------

    base_window::on_close_return_code image_window::
    on_window_close(
    )
    {
        window_has_closed = true;
        clicked_signaler.broadcast();
        return base_window::CLOSE_WINDOW;
    }

// ----------------------------------------------------------------------------------------

    bool image_window::
    get_next_keypress (
        unsigned long& key,
        bool& is_printable,
        unsigned long& state
    )
    {
        auto_mutex lock(wm);
        while (have_last_keypress == false && !window_has_closed &&
            (have_last_click == false || !tie_input_events))
        {
            clicked_signaler.wait();
        }

        if (window_has_closed)
            return false;

        if (have_last_keypress)
        {
            // Mark that we are taking the key click so the next call to get_next_keypress()
            // will have to wait for another click.
            have_last_keypress = false;
            key = next_key;
            is_printable = next_is_printable;
            state = next_state;
            return true;
        }
        else
        {
            key = 0;
            is_printable = true;
            return false;
        }
    }

// ----------------------------------------------------------------------------------------

    void image_window::
    on_keydown (
        unsigned long key,
        bool is_printable,
        unsigned long state
    )
    {
        dlib::drawable_window::on_keydown(key,is_printable,state);

        have_last_keypress = true;
        next_key = key;
        next_is_printable = is_printable;
        next_state = state;
        clicked_signaler.signal();
    }

// ----------------------------------------------------------------------------------------

    void image_window::
    tie_events (
    )
    {
        auto_mutex lock(wm);
        tie_input_events = true;
    }

// ----------------------------------------------------------------------------------------

    void image_window::
    untie_events (
    )
    {
        auto_mutex lock(wm);
        tie_input_events = false;
    }

// ----------------------------------------------------------------------------------------

    bool image_window::
    events_tied (
    ) const
    {
        auto_mutex lock(wm);
        return tie_input_events;
    }

// ----------------------------------------------------------------------------------------

    bool image_window::
    get_next_double_click (
        point& p,
        unsigned long& mouse_button
    )
    {
        p = point(-1,-1);

        auto_mutex lock(wm);
        while (have_last_click == false && !window_has_closed &&
            (have_last_keypress==false || !tie_input_events))
        {
            clicked_signaler.wait();
        }

        if (window_has_closed)
            return false;

        if (have_last_click)
        {
            // Mark that we are taking the point click so the next call to
            // get_next_double_click() will have to wait for another click.
            have_last_click = false;
            mouse_button = mouse_btn;
            p = last_clicked_point;
            return true;
        }
        else
        {
            return false;
        }
    }

// ----------------------------------------------------------------------------------------

    void image_window::
    on_image_clicked (
        const point& p,
        bool is_double_click,
        unsigned long btn
    )
    {
        if (is_double_click)
        {
            have_last_click = true;
            last_clicked_point = p;
            mouse_btn = btn;
            clicked_signaler.signal();
        }
    }

// ----------------------------------------------------------------------------------------

    void image_window::
    add_overlay (
        const overlay_rect& overlay
    )
    {
        gui_img.add_overlay(overlay);
    }

// ----------------------------------------------------------------------------------------

    void image_window::
    add_overlay (
        const overlay_line& overlay
    )
    {
        gui_img.add_overlay(overlay);
    }

// ----------------------------------------------------------------------------------------

    void image_window::
    add_overlay (
        const overlay_circle& overlay
    )
    {
        gui_img.add_overlay(overlay);
    }

// ----------------------------------------------------------------------------------------

    void image_window::
    add_overlay (
        const std::vector<overlay_rect>& overlay
    )
    {
        gui_img.add_overlay(overlay);
    }

// ----------------------------------------------------------------------------------------

    void image_window::
    add_overlay (
        const std::vector<overlay_line>& overlay
    )
    {
        gui_img.add_overlay(overlay);
    }

// ----------------------------------------------------------------------------------------

    void image_window::
    add_overlay (
        const std::vector<overlay_circle>& overlay
    )
    {
        gui_img.add_overlay(overlay);
    }

// ----------------------------------------------------------------------------------------

    void image_window::
    clear_overlay (
    )
    {
        gui_img.clear_overlay();
    }

// ----------------------------------------------------------------------------------------

    void image_window::
    on_window_resized(
    )
    {
        drawable_window::on_window_resized();
        unsigned long width, height;
        get_size(width,height);
        gui_img.set_size(width, height);

    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_WIDGETs_CPP_


dlib C++ Library - widgets.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net), Keita Mochizuki
// License: Boost Software License   See LICENSE.txt for the full license.

#ifndef DLIB_WIDGETs_
#define DLIB_WIDGETs_

#include "../algs.h"
#include "widgets_abstract.h"
#include "drawable.h"
#include "../gui_core.h"
#include "fonts.h"
#include <string>
#include <sstream>
#include "../timer.h"
#include "base_widgets.h"
#include "../member_function_pointer.h"
#include "../array.h"
#include "../array2d.h"
#include "../sequence.h"
#include "../dir_nav.h"
#include "../queue.h"
#include "../smart_pointers.h"
#include "style.h"
#include "../string.h"
#include "../misc_api.h"
#include <cctype>
#include <vector>
#include "../any.h"
#include <set>
#include "../image_processing/full_object_detection.h"

#ifdef _MSC_VER
// This #pragma directive is also located in the algs.h file but for whatever
// reason visual studio 9 just ignores it when it is only there.

// this is to disable the "'this' : used in base member initializer list"
// warning you get from some of the GUI objects since all the objects
// require that their parent class be passed into their constructor.
// In this case though it is totally safe so it is ok to disable this warning.
#pragma warning(disable : 4355)
#endif

namespace dlib
{

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class label
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class label : public drawable
    {
    public:
        label(
            drawable_window& w
        ) :
            drawable(w),
            text_color_(0,0,0)
        {
            enable_events();
        }

        ~label()
        { disable_events(); parent.invalidate_rectangle(rect); }

        void set_text (
            const std::string& text
        );

        void set_text (
            const std::wstring& text
        );

        void set_text (
            const dlib::ustring& text
        );

        const std::string text (
        ) const;

        const std::wstring wtext (
        ) const;

        const dlib::ustring utext (
        ) const;

        void set_text_color (
            const rgb_pixel color
        );

        const rgb_pixel text_color (
        ) const;

        void set_main_font (
            const shared_ptr_thread_safe<font>& f
        );

    private:
        dlib::ustring text_;
        rgb_pixel text_color_;

        // restricted functions
        label(label&);        // copy constructor
        label& operator=(label&);    // assignment operator

    protected:

        void draw (
            const canvas& c
        ) const;

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class toggle_button
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class toggle_button : public button_action
    {
        /*!
            INITIAL VALUE
                - checked == false

            CONVENTION
                - is_checked() == checked
        !*/

    public:

        toggle_button(
            drawable_window& w
        ) :
            button_action(w),
            btn_tooltip(w),
            checked(false)
        {
            style.reset(new toggle_button_style_default());
            enable_events();
        }

        ~toggle_button() { disable_events(); parent.invalidate_rectangle(rect); }

        void set_name (
            const std::string& name
        );

        void set_name (
            const std::wstring& name
        );

        void set_name (
            const dlib::ustring& name
        );

        void set_size (
            unsigned long width_,
            unsigned long height_
        );

        void set_tooltip_text (
            const std::string& text
        );

        void set_tooltip_text (
            const std::wstring& text
        );

        void set_tooltip_text (
            const ustring& text
        );

        const std::string tooltip_text (
        ) const;

        const std::wstring tooltip_wtext (
        ) const;

        const dlib::ustring tooltip_utext (
        ) const;

        bool is_checked (
        ) const;

        const std::string name (
        ) const;

        const std::wstring wname (
        ) const;

        const dlib::ustring uname (
        ) const;

        void set_checked (
        );

        void set_unchecked (
        );

        void show (
        );

        void hide (
        );

        void enable (
        );

        void disable (
        );

        void set_main_font (
            const shared_ptr_thread_safe<font>& f
        );

        void set_pos (
            long x,
            long y
        );

        template <
            typename style_type
            >
        void set_style (
            const style_type& style_
        )
        {
            auto_mutex M(m);
            style.reset(new style_type(style_));
            rect = move_rect(style->get_min_size(name_,*mfont), rect.left(), rect.top());
            parent.invalidate_rectangle(rect);
        }

        template <
            typename T
            >
        void set_click_handler (
            T& object,
            void (T::*event_handler_)()
        )
        {
            auto_mutex M(m);
            event_handler = make_mfp(object,event_handler_);
            event_handler_self.clear();
        }

        void set_click_handler (
            const any_function<void()>& event_handler_
        )
        {
            auto_mutex M(m);
            event_handler = event_handler_;
            event_handler_self.clear();
        }

        template <
            typename T
            >
        void set_click_handler (
            T& object,
            void (T::*event_handler_)(toggle_button&)
        )
        {
            auto_mutex M(m);
            event_handler_self = make_mfp(object,event_handler_);
            event_handler.clear();
        }

        void set_sourced_click_handler (
            const any_function<void(toggle_button&)>& event_handler_
        )
        {
            auto_mutex M(m);
            event_handler_self = event_handler_;
            event_handler.clear();
        }

    private:

        // restricted functions
        toggle_button(toggle_button&);        // copy constructor
        toggle_button& operator=(toggle_button&);    // assignment operator

        dlib::ustring name_;
        tooltip btn_tooltip;
        bool checked;

        any_function<void()> event_handler;
        any_function<void(toggle_button&)> event_handler_self;

        scoped_ptr<toggle_button_style> style;

    protected:

        void draw (
            const canvas& c
        ) const { style->draw_toggle_button(c,rect,enabled,*mfont,lastx,lasty,name_,is_depressed(),checked); }

        void on_button_up (
            bool mouse_over
        );

        void on_mouse_over (
        ){ if (style->redraw_on_mouse_over()) parent.invalidate_rectangle(rect); }

        void on_mouse_not_over (
        ){ if (style->redraw_on_mouse_over()) parent.invalidate_rectangle(rect); }
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class text_field
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class text_field : public drawable
    {
        /*!
            INITIAL VALUE
                text_color_ == rgb_pixel(0,0,0)
                bg_color_ == rgb_pixel(255,255,255)
                cursor_pos == 0
                text_width == 0
                text_ == ""
                has_focus == false
                cursor_visible == false
                recent_movement == false
                highlight_start == 0
                highlight_end == -1
                shift_pos == -1
                text_pos == 0

            CONVENTION
                - cursor_pos == the position of the cursor in the string text_.  The
                  cursor appears before the letter text_[cursor_pos]
                - cursor_x == the x coordinate of the cursor relative to the left side
                  of rect.  i.e. the number of pixels that separate the cursor from the
                  left side of the text_field.
                - has_focus == true if this text field has keyboard input focus
                - cursor_visible == true if the cursor should be painted
                - text_ == text()
                - text_pos == the index of the first letter in text_ that appears in
                  this text field.
                - text_width == the width of text_[text_pos] though text_[text.size()-1]

                - if (has_focus && the user has recently moved the cursor) then
                    - recent_movement == true
                - else
                    - recent_movement == false

                - if (highlight_start <= highlight_end) then
                    - text[highlight_start] though text[highlight_end] should be
                      highlighted

                - if (shift_pos != -1) then
                    - has_focus == true
                    - the shift key is being held down or the left mouse button is
                      being held down.
                    - shift_pos == the position of the cursor when the shift or mouse key
                      was first pressed.

                - text_color() == text_color_
                - background_color() == bg_color_
        !*/

    public:
        text_field(
            drawable_window& w
        ) :
            drawable(w,MOUSE_CLICK | KEYBOARD_EVENTS | MOUSE_MOVE | STRING_PUT),
            text_color_(0,0,0),
            bg_color_(255,255,255),
            text_width(0),
            text_pos(0),
            recent_movement(false),
            has_focus(false),
            cursor_visible(false),
            cursor_pos(0),
            highlight_start(0),
            highlight_end(-1),
            shift_pos(-1),
            t(*this,&text_field::timer_action),
            right_click_menu(w)
        {
            style.reset(new text_field_style_default());
            rect.set_bottom(mfont->height()+ (style->get_padding(*mfont))*2);
            rect.set_right((style->get_padding(*mfont))*2);
            cursor_x = style->get_padding(*mfont);

            right_click_menu.menu().add_menu_item(menu_item_text("Cut",*this,&text_field::on_cut,'t'));
            right_click_menu.menu().add_menu_item(menu_item_text("Copy",*this,&text_field::on_copy,'C'));
            right_click_menu.menu().add_menu_item(menu_item_text("Paste",*this,&text_field::on_paste,'P'));
            right_click_menu.menu().add_menu_item(menu_item_text("Delete",*this,&text_field::on_delete_selected,'D'));
            right_click_menu.menu().add_menu_item(menu_item_separator());
            right_click_menu.menu().add_menu_item(menu_item_text("Select All",*this,&text_field::on_select_all,'A'));

            right_click_menu.set_rect(get_text_rect());
            enable_events();

            t.set_delay_time(500);
        }

        ~text_field (
        )
        {
            disable_events();
            parent.invalidate_rectangle(rect);
            t.stop_and_wait();
        }

        template <
            typename style_type
            >
        void set_style (
            const style_type& style_
        )
        {
            auto_mutex M(m);
            style.reset(new style_type(style_));
            // call this just so that this widget redraws itself with the new style
            set_main_font(mfont);
        }

        void set_text (
            const std::string& text_
        );

        void set_text (
            const std::wstring& text_
        );

        void give_input_focus (
        );

        bool has_input_focus (
        ) const;

        void select_all_text (
        );

        void set_text (
            const dlib::ustring& text_
        );

        const std::string text (
        ) const;

        const std::wstring wtext (
        ) const;

        const dlib::ustring utext (
        ) const;

        void set_text_color (
            const rgb_pixel color
        );

        const rgb_pixel text_color (
        ) const;

        void set_background_color (
            const rgb_pixel color
        );

        const rgb_pixel background_color (
        ) const;

        void set_width (
            unsigned long width
        );

        void set_pos (
            long x,
            long y
        );

        void set_main_font (
            const shared_ptr_thread_safe<font>& f
        );

        int next_free_user_event_number (
        ) const
        {
            return drawable::next_free_user_event_number()+1;
        }

        void disable (
        );

        void enable (
        );

        void hide (
        );

        void show (
        );

        template <
            typename T
            >
        void set_text_modified_handler (
            T& object,
            void (T::*event_handler)()
        )
        {
            auto_mutex M(m);
            text_modified_handler = make_mfp(object,event_handler);
        }

        template <
            typename T
            >
        void set_enter_key_handler (
            T& object,
            void (T::*event_handler)()
        )
        {
            auto_mutex M(m);
            enter_key_handler = make_mfp(object,event_handler);
        }

        void set_text_modified_handler (
            const any_function<void()>& event_handler
        )
        {
            auto_mutex M(m);
            text_modified_handler = event_handler;
        }

        void set_enter_key_handler (
            const any_function<void()>& event_handler
        )
        {
            auto_mutex M(m);
            enter_key_handler = event_handler;
        }

        template <
            typename T
            >
        void set_focus_lost_handler (
            T& object,
            void (T::*event_handler)()
        )
        {
            auto_mutex M(m);
            focus_lost_handler = make_mfp(object,event_handler);
        }

        void set_focus_lost_handler (
            const any_function<void()>& event_handler
        )
        {
            auto_mutex M(m);
            focus_lost_handler = event_handler;
        }

    private:

        void on_cut (
        );

        void on_copy (
        );

        void on_paste (
        );

        void on_select_all (
        );

        void on_delete_selected (
        );

        void on_text_is_selected (
        );

        void on_no_text_selected (
        );

        void on_user_event (
            int num
        )
        {
            // ignore this user event if it isn't for us
            if (num != drawable::next_free_user_event_number())
                return;

            if (recent_movement == false)
            {
                cursor_visible = !cursor_visible;
                parent.invalidate_rectangle(rect);
            }
            else
            {
                if (cursor_visible == false)
                {
                    cursor_visible = true;
                    parent.invalidate_rectangle(rect);
                }
                recent_movement = false;
            }
        }

        void timer_action (
        ) { parent.trigger_user_event(this,drawable::next_free_user_event_number()); }
        /*!
            ensures
                - flips the state of cursor_visible
        !*/

        void move_cursor (
            unsigned long pos
        );
        /*!
            requires
                - pos <= text_.size()
            ensures
                - moves the cursor to the position given by pos and moves the text
                  in the text box if necessary
                - if the position changes then the parent window will be updated
        !*/

        rectangle get_text_rect (
        ) const;
        /*!
            ensures
                - returns the rectangle that should contain the text in this widget
        !*/

        dlib::ustring text_;
        rgb_pixel text_color_;
        rgb_pixel bg_color_;

        unsigned long text_width;
        unsigned long text_pos;

        bool recent_movement;
        bool has_focus;
        bool cursor_visible;
        long cursor_pos;
        unsigned long cursor_x;

        // this tells you what part of the text is highlighted
        long highlight_start;
        long highlight_end;
        long shift_pos;
        any_function<void()> text_modified_handler;
        any_function<void()> enter_key_handler;
        any_function<void()> focus_lost_handler;

        scoped_ptr<text_field_style> style;

        timer<text_field> t;

        popup_menu_region right_click_menu;

        // restricted functions
        text_field(text_field&);        // copy constructor
        text_field& operator=(text_field&);    // assignment operator

    protected:

        void draw (
            const canvas& c
        ) const;

        void on_mouse_down (
            unsigned long btn,
            unsigned long state,
            long x,
            long y,
            bool is_double_click
        );

        void on_mouse_up (
            unsigned long btn,
            unsigned long state,
            long x,
            long y
        );

        void on_mouse_move (
            unsigned long state,
            long x,
            long y
        );

        void on_keydown (
            unsigned long key,
            bool is_printable,
            unsigned long state
        );

        void on_string_put (
            const std::wstring &str
        );
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class text_box
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class text_box : public scrollable_region
    {
        /*!
            INITIAL VALUE
                text_color_ == rgb_pixel(0,0,0)
                bg_color_ == rgb_pixel(255,255,255)
                cursor_pos == 0
                text_ == ""
                has_focus == false
                cursor_visible == false
                recent_movement == false
                highlight_start == 0
                highlight_end == -1
                shift_pos == -1

            CONVENTION
                - cursor_pos == the position of the cursor in the string text_.  The
                  cursor appears before the letter text_[cursor_pos]
                - cursor_rect == The rectangle that should be drawn for the cursor.
                  The position is relative to total_rect().
                - has_focus == true if this text field has keyboard input focus
                - cursor_visible == true if the cursor should be painted
                - text_ == text()

                - if (has_focus && the user has recently moved the cursor) then
                    - recent_movement == true
                - else
                    - recent_movement == false

                - if (highlight_start <= highlight_end) then
                    - text[highlight_start] though text[highlight_end] should be
                      highlighted

                - if (shift_pos != -1) then
                    - has_focus == true
                    - the shift key is being held down or the left mouse button is
                      being held down.
                    - shift_pos == the position of the cursor when the shift or mouse key
                      was first pressed.

                - text_color() == text_color_
                - background_color() == bg_color_
        !*/

    public:
        text_box(
            drawable_window& w
        ) :
            scrollable_region(w,MOUSE_CLICK | KEYBOARD_EVENTS | MOUSE_MOVE | STRING_PUT),
            text_color_(0,0,0),
            bg_color_(255,255,255),
            recent_movement(false),
            has_focus(false),
            cursor_visible(false),
            cursor_pos(0),
            highlight_start(0),
            highlight_end(-1),
            shift_pos(-1),
            t(*this,&text_box::timer_action),
            right_click_menu(w)
        {
            style.reset(new text_box_style_default());

            const long padding = static_cast<long>(style->get_padding(*mfont));
            cursor_rect = mfont->compute_cursor_rect(rectangle(padding,padding,1000000,1000000), text_, 0);

            adjust_total_rect();

            set_vertical_mouse_wheel_scroll_increment(mfont->height());
            set_horizontal_mouse_wheel_scroll_increment(mfont->height());

            right_click_menu.menu().add_menu_item(menu_item_text("Cut",*this,&text_box::on_cut,'t'));
            right_click_menu.menu().add_menu_item(menu_item_text("Copy",*this,&text_box::on_copy,'C'));
            right_click_menu.menu().add_menu_item(menu_item_text("Paste",*this,&text_box::on_paste,'P'));
            right_click_menu.menu().add_menu_item(menu_item_text("Delete",*this,&text_box::on_delete_selected,'D'));
            right_click_menu.menu().add_menu_item(menu_item_separator());
            right_click_menu.menu().add_menu_item(menu_item_text("Select All",*this,&text_box::on_select_all,'A'));

            right_click_menu.set_rect(get_text_rect());

            set_size(100,100);

            enable_events();

            t.set_delay_time(500);
        }

        ~text_box (
        )
        {
            disable_events();
            parent.invalidate_rectangle(rect);
            t.stop_and_wait();
        }

        template <
            typename style_type
            >
        void set_style (
            const style_type& style_
        )
        {
            auto_mutex M(m);
            style.reset(new style_type(style_));

            scrollable_region::set_style(style_.get_scrollable_region_style());
            // call this just so that this widget redraws itself with the new style
            set_main_font(mfont);
        }

        void set_text (
            const std::string& text_
        );

        void set_text (
            const std::wstring& text_
        );

        void set_text (
            const dlib::ustring& text_
        );

        const std::string text (
        ) const;

        const std::wstring wtext (
        ) const;

        const dlib::ustring utext (
        ) const;

        void set_text_color (
            const rgb_pixel color
        );

        const rgb_pixel text_color (
        ) const;

        void set_background_color (
            const rgb_pixel color
        );

        const rgb_pixel background_color (
        ) const;

        void set_size (
            unsigned long width,
            unsigned long height
        );

        void set_pos (
            long x,
            long y
        );

        void set_main_font (
            const shared_ptr_thread_safe<font>& f
        );

        int next_free_user_event_number (
        ) const
        {
            return scrollable_region::next_free_user_event_number()+1;
        }

        void disable (
        );

        void enable (
        );

        void hide (
        );

        void show (
        );

        template <
            typename T
            >
        void set_text_modified_handler (
            T& object,
            void (T::*event_handler)()
        )
        {
            auto_mutex M(m);
            text_modified_handler = make_mfp(object,event_handler);
        }

        void set_text_modified_handler (
            const any_function<void()>& event_handler
        )
        {
            auto_mutex M(m);
            text_modified_handler = event_handler;
        }

        template <
            typename T
            >
        void set_enter_key_handler (
            T& object,
            void (T::*event_handler)()
        )
        {
            auto_mutex M(m);
            enter_key_handler = make_mfp(object,event_handler);
        }

        void set_enter_key_handler (
            const any_function<void()>& event_handler
        )
        {
            auto_mutex M(m);
            enter_key_handler = event_handler;
        }

        template <
            typename T
            >
        void set_focus_lost_handler (
            T& object,
            void (T::*event_handler)()
        )
        {
            auto_mutex M(m);
            focus_lost_handler = make_mfp(object,event_handler);
        }

        void set_focus_lost_handler (
            const any_function<void()>& event_handler
        )
        {
            auto_mutex M(m);
            focus_lost_handler = event_handler;
        }

    private:

        void on_cut (
        );

        void on_copy (
        );

        void on_paste (
        );

        void on_select_all (
        );

        void on_delete_selected (
        );

        void on_text_is_selected (
        );

        void on_no_text_selected (
        );

        void on_user_event (
            int num
        )
        {
            // ignore this user event if it isn't for us
            if (num != scrollable_region::next_free_user_event_number())
                return;

            if (recent_movement == false)
            {
                cursor_visible = !cursor_visible;
                parent.invalidate_rectangle(rect);
            }
            else
            {
                if (cursor_visible == false)
                {
                    cursor_visible = true;
                    parent.invalidate_rectangle(rect);
                }
                recent_movement = false;
            }
        }

        // The reason for using user actions here rather than just having the timer just call
        // what it needs directly is to avoid a potential deadlock during destruction of this widget.
        void timer_action (
        ) { parent.trigger_user_event(this,scrollable_region::next_free_user_event_number()); }
        /*!
            ensures
                - flips the state of cursor_visible
        !*/

        void move_cursor (
            unsigned long pos
        );
        /*!
            requires
                - pos <= text_.size()
            ensures
                - moves the cursor to the position given by pos and moves the text
                  in the text box if necessary
                - if the position changes then the parent window will be updated
        !*/

        rectangle get_text_rect (
        ) const;
        /*!
            ensures
                - returns the rectangle that should contain the text in this widget
        !*/

        void adjust_total_rect (
        );
        /*!
            ensures
                - adjusts total_rect() so that it is big enough to contain the text
                  currently in this object.
        !*/

        dlib::ustring text_;
        rgb_pixel text_color_;
        rgb_pixel bg_color_;

        bool recent_movement;
        bool has_focus;
        bool cursor_visible;
        long cursor_pos;
        rectangle cursor_rect;

        // this tells you what part of the text is highlighted
        long highlight_start;
        long highlight_end;
        long shift_pos;
        any_function<void()> text_modified_handler;
        any_function<void()> enter_key_handler;
        any_function<void()> focus_lost_handler;

        scoped_ptr<text_box_style> style;

        timer<text_box> t;

        popup_menu_region right_click_menu;

        // restricted functions
        text_box(text_box&);        // copy constructor
        text_box& operator=(text_box&);    // assignment operator

    protected:

        void draw (
            const canvas& c
        ) const;

        void on_mouse_down (
            unsigned long btn,
            unsigned long state,
            long x,
            long y,
            bool is_double_click
        );

        void on_mouse_up (
            unsigned long btn,
            unsigned long state,
            long x,
            long y
        );

        void on_mouse_move (
            unsigned long state,
            long x,
            long y
        );

        void on_keydown (
            unsigned long key,
            bool is_printable,
            unsigned long state
        );

        void on_string_put (
            const std::wstring &str
        );
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class check_box
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class check_box : public toggle_button
    {
    public:
        check_box(
            drawable_window& w
        ) : toggle_button(w)
        {
            set_style(toggle_button_style_check_box());
        }

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class radio_button
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class radio_button : public toggle_button
    {
    public:
        radio_button (
            drawable_window& w
        ) : toggle_button(w)
        {
            set_style(toggle_button_style_radio_button());
        }

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class tabbed_display
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class tabbed_display : public drawable
    {
        /*!
            INITIAL VALUE
                - tabs.size() == 0
                - selected_tab_ == 0

            CONVENTION
                - number_of_tabs() == tabs.size()
                - tab_name(idx) == tabs[idx]
                - if (tabs.size() > 0) then
                    - selected_tab_ == the index of the tab that is currently selected

                - for all valid i:
                    - tabs[i].width == mfont->compute_size(tabs[i].name)
                    - tabs[i].rect == the rectangle that defines where this tab is
                    - if (tabs[i].group != 0) then
                        - tabs[i].group == a pointer to the widget_group for this tab.

                - left_pad == the amount of padding in a tab to the left of the name string.
                - right_pad == the amount of padding in a tab to the right of the name string.
                - top_pad == the amount of padding in a tab to the top of the name string.
                - bottom_pad == the amount of padding in a tab to the bottom of the name string.

                - if (event_handler.is_set()) then
                    - event_handler() is what is called to process click events
                      on this object.
        !*/

    public:

        tabbed_display(
            drawable_window& w
        );

        virtual ~tabbed_display(
        );

        void set_size (
            unsigned long width,
            unsigned long height
        );

        void set_number_of_tabs (
            unsigned long num
        );

        unsigned long number_of_tabs (
        ) const;

        const std::string tab_name (
            unsigned long idx
        ) const;

        const std::wstring tab_wname (
            unsigned long idx
        ) const;

        const dlib::ustring& tab_uname (
            unsigned long idx
        ) const;

        void set_tab_name (
            unsigned long idx,
            const std::string& new_name
        );

        void set_tab_name (
            unsigned long idx,
            const std::wstring& new_name
        );

        void set_tab_name (
            unsigned long idx,
            const dlib::ustring& new_name
        );

        void set_pos (
            long x,
            long y
        );

        template <
            typename T
            >
        void set_click_handler (
            T& object,
            void (T::*eh)(unsigned long new_idx,unsigned long old_idx)
        )
        {
            auto_mutex M(m);
            event_handler = make_mfp(object,eh);
        }

        void set_click_handler (
            const any_function<void(unsigned long,unsigned long)>& eh
        )
        {
            auto_mutex M(m);
            event_handler = eh;
        }

        void set_tab_group (
            unsigned long idx,
            widget_group& group
        );

        void show (
        );

        void hide (
        );

        void enable (
        );

        void disable (
        );

        void set_main_font (
            const shared_ptr_thread_safe<font>& f
        );

        void fit_to_contents (
        );

    protected:
        void on_mouse_down (
            unsigned long btn,
            unsigned long state,
            long x,
            long y,
            bool is_double_click
        );

        void draw (
            const canvas& c
        ) const;

    private:
        void recompute_tabs (
        );
        /*!
            ensures
                - recomputes the rectangles for all the tabs and makes this object
                  wider if needed
        !*/

        void draw_tab (
            const rectangle& tab,
            const canvas& c
        ) const;
        /*!
            ensures
                - draws the outline of a tab as given by the rectangle onto c
        !*/

        struct tab_data
        {
            tab_data() : width(0), group(0) {}

            dlib::ustring name;
            unsigned long width;
            rectangle rect;
            widget_group* group;
        };

        unsigned long selected_tab_;

        array<tab_data> tabs;

        const long left_pad;
        const long right_pad;
        const long top_pad;
        const long bottom_pad;

        any_function<void(unsigned long,unsigned long)> event_handler;

        // restricted functions
        tabbed_display(tabbed_display&);        // copy constructor
        tabbed_display& operator=(tabbed_display&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class named_rectangle
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class named_rectangle : public drawable
    {
        /*!
            INITIAL VALUE
                name == ""

            CONVENTION
                name_ == name()
        !*/

    public:

        named_rectangle(
            drawable_window& w
        );

        virtual ~named_rectangle(
        );

        void set_size (
            unsigned long width,
            unsigned long height
        );

        void set_name (
            const std::string& name
        );

        void set_name (
            const std::wstring& name
        );

        void set_name (
            const dlib::ustring& name
        );

        const std::string name (
        ) const;

        const std::wstring wname (
        ) const;

        const dlib::ustring uname (
        ) const;

        void wrap_around (
            const rectangle& rect
        );

        void set_main_font (
            const shared_ptr_thread_safe<font>& f
        );

    protected:

        void draw (
            const canvas& c
        ) const;

    private:

        void make_name_fit_in_rect (
        );

        dlib::ustring name_;
        unsigned long name_width;
        unsigned long name_height;

        // restricted functions
        named_rectangle(named_rectangle&);        // copy constructor
        named_rectangle& operator=(named_rectangle&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class mouse_tracker
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class mouse_tracker : public draggable
    {

    public:

        mouse_tracker(
            drawable_window& w
        );

        ~mouse_tracker(
        );

        void show (
        );

        void hide (
        );

        void enable (
        );

        void disable (
        );

        void set_pos (
            long x,
            long y
        );

        void set_main_font (
            const shared_ptr_thread_safe<font>& f
        );

    protected:

        void on_mouse_move (
            unsigned long state,
            long x,
            long y
        );

        void on_drag (
        );

        void draw (
            const canvas& c
        ) const;

        void on_mouse_down (
            unsigned long btn,
            unsigned long state,
            long x,
            long y,
            bool is_double_click
        );

    private:

        const long offset;
        named_rectangle nr;
        label x_label;
        label y_label;
        std::ostringstream sout;

        long click_x, click_y;

        // restricted functions
        mouse_tracker(mouse_tracker&);        // copy constructor
        mouse_tracker& operator=(mouse_tracker&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // function message_box()
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    namespace message_box_helper
    {
        class box_win : public drawable_window
        {
            void initialize (
            );
        public:
            box_win (
                const std::string& title_,
                const std::string& message_
            );

            box_win (
                const std::wstring& title_,
                const std::wstring& message_
            );

            box_win (
                const dlib::ustring& title_,
                const dlib::ustring& message_
            );

            ~box_win (
            );

            void set_click_handler (
                const any_function<void()>& event_handler_
            )
            {
                auto_mutex M(wm);
                event_handler = event_handler_;
            }

        private:

            static void deleter_thread (
                void* param
            );

            void on_click (
            );

            on_close_return_code on_window_close (
            );

            const std::wstring title;
            const std::wstring message;
            label msg;
            button btn_ok;

            any_function<void()> event_handler;
        };

        class blocking_box_win : public drawable_window
        {
            void initialize (
            );

        public:
            blocking_box_win (
                const std::string& title_,
                const std::string& message_
            );

            blocking_box_win (
                const std::wstring& title_,
                const std::wstring& message_
            );

            blocking_box_win (
                const dlib::ustring& title_,
                const dlib::ustring& message_
            );

            ~blocking_box_win (
            );

        private:

            void on_click (
            );

            const std::wstring title;
            const std::wstring message;
            label msg;
            button btn_ok;
        };
    }

    template <
        typename T
        >
    void message_box (
        const std::string& title,
        const std::string& message,
        T& object,
        void (T::*event_handler)()
    )
    {
        using namespace message_box_helper;
        box_win* win = new box_win(title,message);
        win->set_click_handler(make_mfp(object,event_handler));
    }

    inline void message_box (
        const std::string& title,
        const std::string& message,
        const any_function<void()>& event_handler
    )
    {
        using namespace message_box_helper;
        box_win* win = new box_win(title,message);
        win->set_click_handler(event_handler);
    }

    inline void message_box (
        const std::string& title,
        const std::string& message
    )
    {
        using namespace message_box_helper;
        new box_win(title,message);
    }

    inline void message_box_blocking (
        const std::string& title,
        const std::string& message
    )
    {
        using namespace message_box_helper;
        blocking_box_win w(title,message);
        w.wait_until_closed();
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class list_box
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    namespace list_box_helper{
    template <typename S = std::string>
    class list_box : public scrollable_region,
                     public enumerable<const S>
    {
        /*!
            INITIAL VALUE
                - ms_enabled == false
                - items.size() == 0
                - last_selected = 0

            CONVENTION
                - size() == items.size()
                - (*this)[i] == items[i].name
                - is_selected(i) == items[i].is_selected
                - ms_enabled == multiple_select_enabled()

                - items[i].width == the width of items[i].name as given by font::compute_size()
                - items[i].height == the height of items[i].name as given by font::compute_size()

                - last_selected == the last item the user selected
        !*/

    public:

        list_box(
            drawable_window& w
        );

        ~list_box(
        );

        bool is_selected (
            unsigned long index
        ) const;

        void select (
            unsigned long index
        );

        void unselect (
            unsigned long index
        );

        template <
            typename style_type
            >
        void set_style (
            const style_type& style_
        )
        {
            auto_mutex M(m);
            style.reset(new style_type(style_));
            scrollable_region::set_style(style_.get_scrollable_region_style());
            parent.invalidate_rectangle(rect);
        }

        template <typename T>
        void get_selected (
            T& list
        ) const
        {
            auto_mutex M(m);
            list.clear();
            for (unsigned long i = 0; i < items.size(); ++i)
            {
                if (items[i].is_selected)
                {
                    unsigned long idx = i;
                    list.enqueue(idx);
                }
            }
        }

        template <typename T>
        void load (
            const T& list
        )
        {
            auto_mutex M(m);
            items.clear();
            unsigned long i = 0;
            items.set_max_size(list.size());
            items.set_size(list.size());
            list.reset();
            unsigned long max_width = 0;
            unsigned long total_height = 0;
            while (list.move_next())
            {
                items[i].is_selected = false;
                items[i].name = list.element();
                mfont->compute_size(items[i].name,items[i].width, items[i].height);

                if (items[i].width > max_width)
                    max_width = items[i].width;
                total_height += items[i].height;

                ++i;
            }
            set_total_rect_size(max_width, total_height);

            parent.invalidate_rectangle(rect);
            last_selected = 0;
        }

        const S& operator[] (
            unsigned long index
        ) const;

        bool multiple_select_enabled (
        ) const;

        void enable_multiple_select (
        );

        void disable_multiple_select (
        );

        template <
            typename T
            >
        void set_double_click_handler (
            T& object,
            void (T::*eh)(unsigned long index)
        ) { auto_mutex M(m); event_handler = make_mfp(object,eh); }

        void set_double_click_handler (
            const any_function<void(unsigned long)>& eh
        ) { auto_mutex M(m); event_handler = eh; }

        template <
            typename T
            >
        void set_click_handler (
            T& object,
            void (T::*eh)(unsigned long index)
        ) { auto_mutex M(m); single_click_event_handler = make_mfp(object,eh); }

        void set_click_handler (
            const any_function<void(unsigned long)>& eh
        ) { auto_mutex M(m); single_click_event_handler = eh; }

        bool at_start (
        ) const;

        void reset (
        ) const;

        bool current_element_valid (
        ) const;

        const S& element (
        ) const;

        const S& element (
        );

        bool move_next (
        ) const;

        unsigned long size (
        ) const;

        unsigned long get_selected (
        ) const;

        void set_main_font (
            const shared_ptr_thread_safe<font>& f
        );

    private:

        void on_mouse_down (
            unsigned long btn,
            unsigned long state,
            long x,
            long y,
            bool is_double_click
        );

        void draw (
            const canvas& c
        ) const;

        template <typename SS>
        struct data
        {
            SS name;
            bool is_selected;
            unsigned long width;
            unsigned long height;
        };

        bool ms_enabled;
        array<data<S> > items;
        any_function<void(unsigned long)> event_handler;
        any_function<void(unsigned long)> single_click_event_handler;
        unsigned long last_selected;

        scoped_ptr<list_box_style> style;

        // restricted functions
        list_box(list_box&);        // copy constructor
        list_box& operator=(list_box&);    // assignment operator
    };
    }
    typedef list_box_helper::list_box<std::string> list_box;
    typedef list_box_helper::list_box<std::wstring> wlist_box;
    typedef list_box_helper::list_box<dlib::ustring> ulist_box;

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // function open_file_box()
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    namespace open_file_box_helper
    {
        class box_win : public drawable_window
        {
        public:
            box_win (
                const std::string& title,
                bool has_text_field = false
            );

            ~box_win (
            );

            void set_click_handler (
                const any_function<void(const std::string&)>& event_handler_
            )
            {
                auto_mutex M(wm);
                event_handler = event_handler_;
            }

        private:

            void set_sizes(
            );

            void on_window_resized (
            );

            void deleter_thread (
            );

            void enter_folder (
                const std::string& folder_name
            );

            void on_dirs_click (
                unsigned long idx
            );

            void on_files_click (
                unsigned long idx
            );

            void on_files_double_click (
                unsigned long
            );

            void on_cancel_click (
            );

            void on_open_click (
            );

            void on_path_button_click (
                toggle_button& btn
            );

            bool set_dir (
                const std::string& dir
            );

            void on_root_click (
            );

            on_close_return_code on_window_close (
            );

            label lbl_dirs;
            label lbl_files;
            label lbl_file_name;
            list_box lb_dirs;
            list_box lb_files;
            button btn_ok;
            button btn_cancel;
            toggle_button btn_root;
            text_field tf_file_name;
            std::string path;
            std::string prefix;
            int cur_dir;

            any_function<void(const std::string&)> event_handler;
            sequence<scoped_ptr<toggle_button> >::kernel_2a_c sob;
        };
    }

    template <
        typename T
        >
    void open_file_box (
        T& object,
        void (T::*event_handler)(const std::string&)
    )
    {
        using namespace open_file_box_helper;
        box_win* win = new box_win("Open File",true);
        win->set_click_handler(make_mfp(object,event_handler));
    }

    inline void open_file_box (
        const any_function<void(const std::string&)>& event_handler
    )
    {
        using namespace open_file_box_helper;
        box_win* win = new box_win("Open File",true);
        win->set_click_handler(event_handler);
    }

    template <
        typename T
        >
    void open_existing_file_box (
        T& object,
        void (T::*event_handler)(const std::string&)
    )
    {
        using namespace open_file_box_helper;
        box_win* win = new box_win("Open File");
        win->set_click_handler(make_mfp(object,event_handler));
    }

    inline void open_existing_file_box (
        const any_function<void(const std::string&)>& event_handler
    )
    {
        using namespace open_file_box_helper;
        box_win* win = new box_win("Open File");
        win->set_click_handler(event_handler);
    }

    template <
        typename T
        >
    void save_file_box (
        T& object,
        void (T::*event_handler)(const std::string&)
    )
    {
        using namespace open_file_box_helper;
        box_win* win = new box_win("Save File",true);
        win->set_click_handler(make_mfp(object,event_handler));
    }

    inline void save_file_box (
        const any_function<void(const std::string&)>& event_handler
    )
    {
        using namespace open_file_box_helper;
        box_win* win = new box_win("Save File",true);
        win->set_click_handler(event_handler);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class menu_bar
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class menu_bar : public drawable
    {
        /*!
            INITIAL VALUE
                - menus.size() == 0
                - open_menu == 0

            CONVENTION
                - size() == menus.size()
                - all menu data is stored in menus
                - menus[x].name == the name of the xth menu
                - if (menus[x].underline_pos != std::string::npos) then
                    - menus[x].underline_pos == the position of the character in the
                      menu name that should be underlined
                    - menus[x].underline_p1 != menus[x].underline_p2
                      and these two points define the underline bar
                - else
                    - menus[x].underline_p1 == menus[x].underline_p2
                - menus[x].menu == menu(x)
                - menus[x].rect == the rectangle in which menus[x].name is drawn
                - menus[x].bgrect == the rectangle for the xth menu button

                - if (there is an open menu on the screen) then
                    - open_menu == the index of the open menu from menus
                - else
                    - open_menu == menus.size()
        !*/

    public:
        menu_bar(
            drawable_window& w
        );

        ~menu_bar();

        // this function does nothing
        void set_pos(long,long){}

        void set_main_font (
            const shared_ptr_thread_safe<font>& f
        );

        void set_number_of_menus (
            unsigned long num
        );

        unsigned long number_of_menus (
        ) const;

        void set_menu_name (
            unsigned long idx,
            const std::string name,
            char underline_ch = '\0'
        );

        void set_menu_name (
            unsigned long idx,
            const std::wstring name,
            char underline_ch = '\0'
        );

        void set_menu_name (
            unsigned long idx,
            const dlib::ustring name,
            char underline_ch = '\0'
        );

        const std::string menu_name (
            unsigned long idx
        ) const;

        const std::wstring menu_wname (
            unsigned long idx
        ) const;

        const dlib::ustring menu_uname (
            unsigned long idx
        ) const;

        popup_menu& menu (
            unsigned long idx
        );

        const popup_menu& menu (
            unsigned long idx
        ) const;

    protected:

        void on_window_resized (
        );

        void draw (
            const canvas& c
        ) const;

        void on_window_moved (
        );

        void on_focus_lost (
        );

        void on_mouse_down (
            unsigned long btn,
            unsigned long ,
            long x,
            long y,
            bool
        );

        void on_mouse_move (
            unsigned long ,
            long x,
            long y
        );

        void on_keydown (
            unsigned long key,
            bool is_printable,
            unsigned long state
        );

    private:

        void show_menu (
            unsigned long i
        );

        void hide_menu (
        );

        void on_popup_hide (
        );

        void compute_menu_geometry (
        );

        void adjust_position (
        );

        struct menu_data
        {
            menu_data():underline_pos(dlib::ustring::npos){}

            dlib::ustring name;
            dlib::ustring::size_type underline_pos;
            popup_menu menu;
            rectangle rect;
            rectangle bgrect;
            point underline_p1;
            point underline_p2;
        };

        array<menu_data> menus;
        unsigned long open_menu;

        // restricted functions
        menu_bar(menu_bar&);        // copy constructor
        menu_bar& operator=(menu_bar&);    // assignment operator

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class directed_graph_drawer
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <typename graph_type>
    class directed_graph_drawer : public zoomable_region
    {
        /*!
            INITIAL VALUE
                - edge_selected == false
                - mouse_drag == false
                - selected_node == 0
                - graph_.number_of_nodes() == 0
                - external_graph.number_of_nodes() == 0
                - radius == 25
                - last_mouse_click_in_display == false

            CONVENTION
                - radius == the radius of the nodes when they aren't zoomed
                - external_graph and graph_ have the same graph structure
                - external_graph == graph()
                - external_graph.node(i) == graph_node(i)

                - if (one of the nodes is selected) then
                    - selected_node < graph_.number_of_nodes()
                    - graph_.node(selected_node) == the selected node
                - else
                    - selected_node == graph_.number_of_nodes()

                - if (the user is dragging a node with the mouse) then
                    - mouse_drag == true
                    - drag_offset == the vector from the mouse position to the
                      center of the node
                - else
                    - mouse_drag == false

                - if (the user has selected an edge) then
                    - edge_selected == true
                    - the parent node is graph_.node(selected_edge_parent)
                    - the child node is graph_.node(selected_edge_parent)
                - else
                    - edge_selected == false

                - for all valid i:
                    - graph_.node(i).data.p == the center of the node in graph space
                    - graph_.node(i).data.name == node_label(i)
                    - graph_.node(i).data.color == node_color(i)
                    - graph_.node(i).data.str_rect == a rectangle sized to contain graph_.node(i).data.name

                - if (the last mouse click in our parent window as in our display_rect_ ) then
                    - last_mouse_click_in_display == true
                - else
                    - last_mouse_click_in_display == false
        !*/

    public:
        directed_graph_drawer (
            drawable_window& w
        ) :
            zoomable_region(w,MOUSE_CLICK | MOUSE_WHEEL | KEYBOARD_EVENTS),
            radius(25),
            edge_selected(false),
            last_mouse_click_in_display(false)
        {
            mouse_drag = false;
            selected_node = 0;

            // Whenever you make your own drawable (or inherit from draggable or button_action)
            // you have to remember to call this function to enable the events.  The idea
            // here is that you can perform whatever setup you need to do to get your
            // object into a valid state without needing to worry about event handlers
            // triggering before you are ready.
            enable_events();
        }

        ~directed_graph_drawer (
        )
        {
            // Disable all further events for this drawable object.  We have to do this
            // because we don't want draw() events coming to this object while or after
            // it has been destructed.
            disable_events();

            // Tell the parent window to redraw its area that previously contained this
            // drawable object.
            parent.invalidate_rectangle(rect);
        }

        void clear_graph (
        )
        {
            auto_mutex M(m);
            graph_.clear();
            external_graph.clear();
            parent.invalidate_rectangle(display_rect());
        }

        const typename graph_type::node_type& graph_node (
            unsigned long i
        )  const
        {
            DLIB_ASSERT ( i < number_of_nodes() ,
                    "\tgraph_type::node_type& directed_graph_drawer::graph_node(i)"
                    << "\n\ti:                 " << i
                    << "\n\tnumber_of_nodes(): " << number_of_nodes()
                    );
            return external_graph.node(i);
        }

        typename graph_type::node_type& graph_node (
            unsigned long i
        )
        {
            DLIB_ASSERT ( i < number_of_nodes() ,
                    "\tgraph_type::node_type& directed_graph_drawer::graph_node(i)"
                    << "\n\ti:                 " << i
                    << "\n\tnumber_of_nodes(): " << number_of_nodes()
                    );
            return external_graph.node(i);
        }

        const graph_type& graph (
        ) const
        {
            return external_graph;
        }

        void save_graph (
            std::ostream& out
        )
        {
            auto_mutex M(m);
            serialize(external_graph, out);
            serialize(graph_, out);
            parent.invalidate_rectangle(display_rect());
        }

        void load_graph (
            std::istream& in
        )
        {
            auto_mutex M(m);
            deserialize(external_graph, in);
            deserialize(graph_, in);
            parent.invalidate_rectangle(display_rect());
        }

        unsigned long number_of_nodes (
        ) const
        {
            auto_mutex M(m);
            return graph_.number_of_nodes();
        }

        void set_node_label (
            unsigned long i,
            const std::string& label
        )
        {
            set_node_label(i, convert_mbstring_to_wstring(label));
        }

        void set_node_label (
            unsigned long i,
            const std::wstring& label
        )
        {
            set_node_label(i, convert_wstring_to_utf32(label));
        }

        void set_node_label (
            unsigned long i,
            const dlib::ustring& label
        )
        {
            auto_mutex M(m);
            DLIB_ASSERT ( i < number_of_nodes() ,
                    "\tvoid directed_graph_drawer::set_node_label(i,label)"
                    << "\n\ti:                 " << i
                    << "\n\tlabel:             " << narrow(label)
                    << "\n\tnumber_of_nodes(): " << number_of_nodes()
                    );
            graph_.node(i).data.name = label.c_str();
            unsigned long width, height;
            mfont->compute_size(label,width,height);
            graph_.node(i).data.str_rect = rectangle(width,height);
            parent.invalidate_rectangle(display_rect());
        }

        void set_node_color (
            unsigned long i,
            rgb_pixel color
        )
        {
            auto_mutex M(m);
            DLIB_ASSERT ( i < number_of_nodes() ,
                    "\tvoid directed_graph_drawer::set_node_color(i,label)"
                    << "\n\ti:                 " << i
                    << "\n\tnumber_of_nodes(): " << number_of_nodes()
                    );
            graph_.node(i).data.color = color;
            parent.invalidate_rectangle(display_rect());
        }

        rgb_pixel node_color (
            unsigned long i
        ) const
        {
            auto_mutex M(m);
            DLIB_ASSERT ( i < number_of_nodes() ,
                    "\trgb_pixel directed_graph_drawer::node_color(i)"
                    << "\n\ti:                 " << i
                    << "\n\tnumber_of_nodes(): " << number_of_nodes()
                    );
            return graph_.node(i).data.color;
        }

        const std::string node_label (
            unsigned long i
        ) const
        {
            auto_mutex M(m);
            DLIB_ASSERT ( i < number_of_nodes() ,
                    "\tconst std::ustring directed_graph_drawer::node_label(i)"
                    << "\n\ti:                 " << i
                    << "\n\tnumber_of_nodes(): " << number_of_nodes()
                    );
            return narrow(graph_.node(i).data.name);
        }

        const std::wstring node_wlabel (
            unsigned long i
        ) const
        {
            return convert_utf32_to_wstring(node_ulabel(i));
        }

        const dlib::ustring node_ulabel (
            unsigned long i
        ) const
        {
            auto_mutex M(m);
            DLIB_ASSERT ( i < number_of_nodes() ,
                    "\tconst std::ustring directed_graph_drawer::node_label(i)"
                    << "\n\ti:                 " << i
                    << "\n\tnumber_of_nodes(): " << number_of_nodes()
                    );
            return graph_.node(i).data.name.c_str();
        }

        template <
            typename T
            >
        void set_node_selected_handler (
            T& object,
            void (T::*event_handler_)(unsigned long)
        )
        {
            auto_mutex M(m);
            node_selected_handler = make_mfp(object,event_handler_);
        }

        void set_node_selected_handler (
            const any_function<void(unsigned long)>& event_handler_
        )
        {
            auto_mutex M(m);
            node_selected_handler = event_handler_;
        }

        template <
            typename T
            >
        void set_node_deselected_handler (
            T& object,
            void (T::*event_handler_)(unsigned long)
        )
        {
            auto_mutex M(m);
            node_deselected_handler = make_mfp(object,event_handler_);
        }

        void set_node_deselected_handler (
            const any_function<void(unsigned long)>& event_handler_
        )
        {
            auto_mutex M(m);
            node_deselected_handler = event_handler_;
        }

        template <
            typename T
            >
        void set_node_deleted_handler (
            T& object,
            void (T::*event_handler_)()
        )
        {
            auto_mutex M(m);
            node_deleted_handler = make_mfp(object,event_handler_);
        }

        void set_node_deleted_handler (
            const any_function<void()>& event_handler_
        )
        {
            auto_mutex M(m);
            node_deleted_handler = event_handler_;
        }

        template <
            typename T
            >
        void set_graph_modified_handler (
            T& object,
            void (T::*event_handler_)()
        )
        {
            auto_mutex M(m);
            graph_modified_handler = make_mfp(object,event_handler_);
        }

        void set_graph_modified_handler (
            const any_function<void()>& event_handler_
        )
        {
            auto_mutex M(m);
            graph_modified_handler = event_handler_;
        }

    protected:

        void on_keydown (
            unsigned long key,
            bool ,
            unsigned long
        )
        {
            // ignore all keyboard input if the last thing the user clicked on
            // wasn't the display area
            if (last_mouse_click_in_display == false)
                return;

            // if a node is selected
            if (selected_node != graph_.number_of_nodes())
            {
                // deselect the node if the user hits escape
                if (key == base_window::KEY_ESC)
                {
                    parent.invalidate_rectangle(display_rect());
                    if (node_deselected_handler.is_set())
                        node_deselected_handler(selected_node);
                    selected_node = graph_.number_of_nodes();
                }

                // delete the node if the user hits delete
                if (key == base_window::KEY_DELETE || key == base_window::KEY_BACKSPACE)
                {
                    parent.invalidate_rectangle(display_rect());
                    graph_.remove_node(selected_node);
                    external_graph.remove_node(selected_node);
                    selected_node = graph_.number_of_nodes();
                    mouse_drag = false;
                    if (graph_modified_handler.is_set())
                        graph_modified_handler();
                    if (node_deleted_handler.is_set())
                        node_deleted_handler();
                }
            }

            // if an edge is selected
            if (edge_selected)
            {
                // deselect the node if the user hits escape
                if (key == base_window::KEY_ESC)
                {
                    parent.invalidate_rectangle(display_rect());
                    edge_selected = false;
                }

                // delete the node if the user hits delete
                if (key == base_window::KEY_DELETE || key == base_window::KEY_BACKSPACE)
                {
                    parent.invalidate_rectangle(display_rect());
                    graph_.remove_edge(selected_edge_parent, selected_edge_child);
                    external_graph.remove_edge(selected_edge_parent, selected_edge_child);
                    edge_selected = false;

                    if (graph_modified_handler.is_set())
                        graph_modified_handler();
                }
            }
        }

        void on_mouse_move (
            unsigned long state,
            long x,
            long y
        )
        {
            if (mouse_drag)
            {
                const point p(nearest_point(display_rect(),point(x,y)));

                point center = drag_offset + p;
                graph_.node(selected_node).data.p = gui_to_graph_space(center);
                parent.invalidate_rectangle(display_rect());
            }
            else
            {
                zoomable_region::on_mouse_move(state,x,y);
            }

            // check if the mouse isn't being dragged anymore
            if ((state & base_window::LEFT) == 0)
            {
                mouse_drag = false;
            }
        }

        void on_mouse_up (
            unsigned long btn,
            unsigned long state,
            long x,
            long y
        )
        {
            mouse_drag = false;
            zoomable_region::on_mouse_up(btn,state,x,y);
        }

        void on_mouse_down (
            unsigned long btn,
            unsigned long state,
            long x,
            long y,
            bool is_double_click
        )
        {
            bool redraw = false;

            if (display_rect().contains(x,y) &&
                (btn == base_window::RIGHT || btn == base_window::LEFT) &&
                (state & base_window::SHIFT) == 0 )
            {
                // start out saying no edge is selected
                if (edge_selected)
                {
                    edge_selected = false;
                    redraw = true;
                }

                bool click_hit_node = false;
                dlib::vector<double,2> p(gui_to_graph_space(point(x,y)));
                // check if this click is on an existing node
                for (unsigned long i = 0; i < graph_.number_of_nodes(); ++i)
                {
                    dlib::vector<double,2> n(graph_.node(i).data.p);
                    if ((p-n).length() < radius)
                    {
                        click_hit_node = true;
                        point center = graph_to_gui_space(graph_.node(i).data.p);
                        mouse_drag = true;
                        drag_offset = center - point(x,y);

                        // only do something if the click isn't on the currently
                        // selected node
                        if (selected_node != i)
                        {
                            // send out the deselected event if appropriate
                            if (selected_node != graph_.number_of_nodes() && node_deselected_handler.is_set())
                                node_deselected_handler(selected_node);

                            selected_node = i;
                            redraw = true;
                            if (node_selected_handler.is_set())
                                node_selected_handler(selected_node);
                        }
                        break;
                    }
                }

                // if the click didn't hit any node then make sure nothing is selected
                if (click_hit_node == false && selected_node != graph_.number_of_nodes())
                {
                    if (node_deselected_handler.is_set())
                        node_deselected_handler(selected_node);
                    selected_node = graph_.number_of_nodes();
                    redraw = true;
                }

                // check if this click is on an edge if we didn't click on a node
                if (click_hit_node == false)
                {
                    for (unsigned long n = 0; n < graph_.number_of_nodes() && edge_selected == false; ++n)
                    {
                        const dlib::vector<double,2> parent_center(graph_to_gui_space(graph_.node(n).data.p));
                        for (unsigned long e = 0; e < graph_.node(n).number_of_children() && edge_selected == false; ++e)
                        {
                            const dlib::vector<double,2> child_center(graph_to_gui_space(graph_.node(n).child(e).data.p));

                            rectangle area;
                            area += parent_center;
                            area += child_center;
                            // if the point(x,y) is between the two nodes then lets consider it further
                            if (area.contains(point(x,y)))
                            {
                                p = point(x,y);
                                const dlib::vector<double> z(0,0,1);
                                // find the distance from the line between the two nodes
                                const dlib::vector<double,2> perpendicular(z.cross(parent_center-child_center).normalize());
                                double distance = std::abs((child_center-p).dot(perpendicular));
                                if (distance < 8)
                                {
                                    edge_selected = true;
                                    selected_edge_parent = n;
                                    selected_edge_child = graph_.node(n).child(e).index();
                                    redraw = true;
                                }
                            }
                        }
                    }
                }

                // if the click didn't land on any node then add a new one if this was
                // a right mouse button click
                if (click_hit_node == false && btn == base_window::RIGHT)
                {
                    const unsigned long n = graph_.add_node();
                    external_graph.add_node();

                    graph_.node(n).data.p = gui_to_graph_space(point(x,y));

                    redraw = true;
                    selected_node = n;
                    mouse_drag = false;
                    if (graph_modified_handler.is_set())
                        graph_modified_handler();

                    if (node_selected_handler.is_set())
                        node_selected_handler(selected_node);

                }
                else if (selected_node == graph_.number_of_nodes())
                {
                    // in this case the click landed in the white area between nodes
                    zoomable_region::on_mouse_down( btn, state, x, y, is_double_click);
                }
            }

            // If the user is shift clicking with the mouse then see if we
            // should add a new edge.
            if (display_rect().contains(x,y) &&
                btn == base_window::LEFT &&
                (state & base_window::SHIFT) &&
                selected_node != graph_.number_of_nodes() )
            {
                dlib::vector<double,2> p(gui_to_graph_space(point(x,y)));
                // check if this click is on an existing node
                for (unsigned long i = 0; i < graph_.number_of_nodes(); ++i)
                {
                    dlib::vector<double,2> n(graph_.node(i).data.p);
                    if ((p-n).length() < radius)
                    {
                        // add the edge if it doesn't already exist and isn't an edge back to
                        // the same node
                        if (graph_.has_edge(selected_node,i) == false && selected_node != i &&
                            graph_.has_edge(i, selected_node) == false)
                        {
                            graph_.add_edge(selected_node,i);
                            external_graph.add_edge(selected_node,i);
                            redraw = true;

                            if (graph_modified_handler.is_set())
                                graph_modified_handler();
                        }
                        break;
                    }
                }
            }

            if (redraw)
                parent.invalidate_rectangle(display_rect());

            if (display_rect().contains(x,y) == false)
                last_mouse_click_in_display = false;
            else
                last_mouse_click_in_display = true;
        }

        void draw (
            const canvas& c
        ) const
        {
            zoomable_region::draw(c);

            rectangle area = c.intersect(display_rect());
            if (area.is_empty() == true)
                return;

            if (enabled)
                fill_rect(c,display_rect(),255);
            else
                fill_rect(c,display_rect(),128);

            const unsigned long rad = static_cast<unsigned long>(radius*zoom_scale());
            point center;

            // first draw all the edges
            for (unsigned long i = 0; i < graph_.number_of_nodes(); ++i)
            {
                center = graph_to_gui_space(graph_.node(i).data.p);
                const rectangle circle_area(centered_rect(center,2*(rad+8),2*(rad+8)));

                // draw lines to all this node's parents
                const dlib::vector<double> z(0,0,1);
                for (unsigned long j = 0; j < graph_.node(i).number_of_parents(); ++j)
                {
                    point p(graph_to_gui_space(graph_.node(i).parent(j).data.p));

                    rgb_pixel color(0,0,0);
                    // if this is the selected edge then draw it with red instead of black
                    if (edge_selected && selected_edge_child == i && selected_edge_parent == graph_.node(i).parent(j).index())
                    {
                        color.red = 255;
                        // we need to be careful when drawing this line to not draw it over the node dots since it
                        // has a different color from them and would look weird
                        dlib::vector<double,2> v(p-center);
                        v = v.normalize()*rad;
                        draw_line(c,center+v,p-v ,color, area);
                    }
                    else
                    {
                        draw_line(c,center,p ,color, area);
                    }

                    // draw the triangle pointing to this node
                    if (area.intersect(circle_area).is_empty() == false)
                    {
                        dlib::vector<double,2> v(p-center);
                        v = v.normalize();

                        dlib::vector<double,2> cross = z.cross(v).normalize();
                        dlib::vector<double,2> r(center + v*rad);
                        for (double i = 0; i < 8*zoom_scale(); i += 0.1)
                            draw_line(c,(r+v*i)+cross*i, (r+v*i)-cross*i,color,area);
                    }
                }
            }

            // now draw all the node dots
            for (unsigned long i = 0; i < graph_.number_of_nodes(); ++i)
            {
                center = graph_to_gui_space(graph_.node(i).data.p);
                const rectangle circle_area(centered_rect(center,2*(rad+8),2*(rad+8)));

                // draw the actual dot for this node
                if (area.intersect(circle_area).is_empty()==false)
                {
                    rgb_alpha_pixel color;
                    assign_pixel(color, graph_.node(i).data.color);
                    // this node is in area so lets draw it and all of it's edges as well
                    draw_solid_circle(c,center,rad-3,color,area);
                    color.alpha = 240;
                    draw_circle(c,center,rad-3,color,area);
                    color.alpha = 200;
                    draw_circle(c,center,rad-2.5,color,area);
                    color.alpha = 160;
                    draw_circle(c,center,rad-2.0,color,area);
                    color.alpha = 120;
                    draw_circle(c,center,rad-1.5,color,area);
                    color.alpha = 80;
                    draw_circle(c,center,rad-1.0,color,area);
                    color.alpha = 40;
                    draw_circle(c,center,rad-0.5,color,area);

                }

                if (i == selected_node)
                    draw_circle(c,center,rad+5,rgb_pixel(0,0,255),area);
            }

            // now draw all the strings last
            for (unsigned long i = 0; i < graph_.number_of_nodes(); ++i)
            {
                center = graph_to_gui_space(graph_.node(i).data.p);
                rectangle circle_area(centered_rect(center,2*rad+3,2*rad+3));
                if (area.intersect(circle_area).is_empty()==false)
                {
                    rgb_pixel color = graph_.node(i).data.color;
                    // invert this color
                    color.red = 255-color.red;
                    color.green = 255-color.green;
                    color.blue = 255-color.blue;
                    sout << i;
                    unsigned long width, height;
                    mfont->compute_size(sout.str(),width,height);
                    rectangle str_rect(centered_rect(center, width,height));
                    if (circle_area.contains(str_rect))
                    {
                        mfont->draw_string(c,str_rect,sout.str(),color,0,std::string::npos,area);

                        // draw the label for this node if it isn't empty
                        if(graph_.node(i).data.name.size() > 0)
                        {
                            rectangle str_rect(graph_.node(i).data.str_rect);
                            str_rect = centered_rect(center.x(), center.y()-rad-mfont->height(),  str_rect.width(), str_rect.height());
                            mfont->draw_string(c,str_rect,graph_.node(i).data.name,0,0,std::string::npos,area);
                        }
                    }
                    sout.str("");
                }
            }
        }

    private:

        struct data
        {
            data() : color(0,0,0) {}
            vector<double> p;
            dlib::ustring name;
            rectangle str_rect;
            rgb_pixel color;
        };

        friend void serialize(const data& item, std::ostream& out)
        {
            serialize(item.p, out);
            serialize(item.name, out);
            serialize(item.str_rect, out);
            serialize(item.color, out);
        }

        friend void deserialize(data& item, std::istream& in)
        {
            deserialize(item.p, in);
            deserialize(item.name, in);
            deserialize(item.str_rect, in);
            deserialize(item.color, in);
        }

        mutable std::ostringstream sout;

        const double radius;
        unsigned long selected_node;
        bool mouse_drag; // true if the user is dragging a node
        point drag_offset;

        bool edge_selected;
        unsigned long selected_edge_parent;
        unsigned long selected_edge_child;

        any_function<void(unsigned long)> node_selected_handler;
        any_function<void(unsigned long)> node_deselected_handler;
        any_function<void()> node_deleted_handler;
        any_function<void()> graph_modified_handler;

        graph_type external_graph;
        // rebind the graph_ type to make us a graph_ of data structs
        typename graph_type::template rebind<data,char, typename graph_type::mem_manager_type>::other graph_;

        bool last_mouse_click_in_display;
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // class text_grid
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class text_grid : public scrollable_region
    {
        /*!
            INITIAL VALUE
                - has_focus == false
                - vertical_scroll_increment() == 10
                - horizontal_scroll_increment() == 10
                - border_color_ == rgb_pixel(128,128,128)

            CONVENTION
                - grid.nr() == row_height.size()
                - grid.nc() == col_width.size()
                - border_color() == border_color_
                - text(r,c) == grid[r][c].text
                - text_color(r,c) == grid[r][c].text_color
                - background_color(r,c) == grid[r][c].bg_color

                - if (the user has clicked on this widget and caused one of the
                    boxes to have input focus) then
                    - has_focus == true
                    - grid[active_row][active_col] == the active text box
                    - cursor_pos == the position of the cursor in the above box
                    - if (the cursor should be displayed) then
                        - show_cursor == true
                    - else
                        - show_cursor == false
                - else
                    - has_focus == false
        !*/

    public:
        text_grid (
            drawable_window& w
        );

        ~text_grid (
        );

        void set_grid_size (
            unsigned long rows,
            unsigned long cols
        );

        unsigned long number_of_columns (
        ) const;

        unsigned long number_of_rows (
        ) const;

        int next_free_user_event_number (
        ) const;

        rgb_pixel border_color (
        ) const;

        void set_border_color (
            rgb_pixel color
        );

        const std::string text (
            unsigned long row,
            unsigned long col
        ) const;

        const std::wstring wtext (
            unsigned long row,
            unsigned long col
        ) const;

        const dlib::ustring utext (
            unsigned long row,
            unsigned long col
        ) const;

        void set_text (
            unsigned long row,
            unsigned long col,
            const std::string& str
        );

        void set_text (
            unsigned long row,
            unsigned long col,
            const std::wstring& str
        );

        void set_text (
            unsigned long row,
            unsigned long col,
            const dlib::ustring& str
        );

        const rgb_pixel text_color (
            unsigned long row,
            unsigned long col
        ) const;

        void set_text_color (
            unsigned long row,
            unsigned long col,
            const rgb_pixel color
        );

        const rgb_pixel background_color (
            unsigned long row,
            unsigned long col
        ) const;

        void set_background_color (
            unsigned long row,
            unsigned long col,
            const rgb_pixel color
        );

        bool is_editable (
            unsigned long row,
            unsigned long col
        ) const;

        void set_editable (
            unsigned long row,
            unsigned long col,
            bool editable
        );

        void set_column_width (
            unsigned long col,
            unsigned long width
        );

        void set_row_height (
            unsigned long row,
            unsigned long height
        );

        void disable (
        );

        void hide (
        );

        template <
            typename T
            >
        void set_text_modified_handler (
            T& object,
            void (T::*eh)(unsigned long, unsigned long)
        ) { text_modified_handler = make_mfp(object,eh); }

        void set_text_modified_handler (
            const any_function<void(unsigned long, unsigned long)>& eh
        ) { text_modified_handler = eh; }

    private:

        void on_user_event (
            int num
        );

        void timer_action (
        );
        /*!
            ensures
                - flips the state of show_cursor
        !*/

        void compute_bg_rects (
        );

        void compute_total_rect (
        );

        void on_keydown (
            unsigned long key,
            bool is_printable,
            unsigned long state
        );

        void on_mouse_down (
            unsigned long btn,
            unsigned long state,
            long x,
            long y,
            bool is_double_click
        );

        void on_mouse_up (
            unsigned long btn,
            unsigned long state,
            long x,
            long y
        );

        void on_focus_lost (
        );

        void draw (
            const canvas& c
        ) const;

        rectangle get_text_rect (
            unsigned long row,
            unsigned long col
        ) const;

        rectangle get_bg_rect (
            unsigned long row,
            unsigned long col
        ) const;

        struct data_type
        {
            data_type(): text_color(0,0,0), bg_color(255,255,255),
            first(0), is_editable(true)
            {}

            dlib::ustring text;
            rgb_pixel text_color;
            rgb_pixel bg_color;
            rectangle bg_rect;
            dlib::ustring::size_type first;
            bool is_editable;
        };

        void drop_input_focus (
        );

        void move_cursor (
            long row,
            long col,
            long new_cursor_pos
        );

        array2d<data_type> grid;
        array<unsigned long> col_width;
        array<unsigned long> row_height;
        bool has_focus;
        long active_col;
        long active_row;
        long cursor_pos;
        bool show_cursor;
        bool recent_cursor_move;
        timer<text_grid> cursor_timer;
        rgb_pixel border_color_;
        any_function<void(unsigned long, unsigned long)> text_modified_handler;
    };

// ----------------------------------------------------------------------------------------

    class image_display : public scrollable_region
    {
        /*!
            INITIAL VALUE
                - img.size() == 0
                - overlay_rects.size() == 0
                - overlay_lines.size() == 0
                - drawing_rect == false
                - rect_is_selected == false

            CONVENTION
                - img == the image this object displays
                - overlay_rects == the overlay rectangles this object displays
                - overlay_lines == the overlay lines this object displays

                - if (drawing_rect) then
                    - the user is drawing a rectangle on the screen and is
                      thus holding down CTRL and the left mouse button.
                    - rect_anchor == the point on the screen where the user
                      clicked to begin drawing the rectangle.
                    - rect_to_draw == the rectangle which should appear on the screen.

                - if (rect_is_selected) then
                    - selected_rect == the index in overlay_rects of the user selected
                      rectangle.
                    - last_right_click_pos == the last place we saw the user right click
                      the mouse.
                    - parts_menu.is_enabled() == true
                    - if (it is actually a part of this rect that is selected) then
                        - selected_part_name == the name of the part in overlay_rects[selected_rect].parts
                          that is selected.
                    - else
                        - selected_part_name.size() == 0
                - else
                    - parts_menu.is_enabled() == false
                    - selected_part_name.size() == 0

                - if (moving_overlay) then
                    - moving_rect == the index in overlay_rects that the move applies to.
                    - if (moving_what == MOVING_PART) then
                        - moving_part_name == the name of the part in
                          overlay_rects[moving_rect] that is being moved around with the
                          mouse.
                    - else
                        - moving_what will tell us which side of the rectangle in
                          overlay_rects[moving_rect] is being moved by the mouse.
        !*/

    public:

        image_display(
            drawable_window& w
        );

        ~image_display(
        );

        template <
            typename image_type
            >
        void set_image (
            const image_type& new_img
        )
        {
            auto_mutex M(m);

            // if the new image has a different size when compared to the previous image
            // then we should readjust the total rectangle size.
            if (num_rows(new_img) != img.nr() || num_columns(new_img) != img.nc())
            {
                if (zoom_in_scale != 1)
                    set_total_rect_size(num_columns(new_img)*zoom_in_scale, num_rows(new_img)*zoom_in_scale);
                else
                    set_total_rect_size(num_columns(new_img)/zoom_out_scale, num_rows(new_img)/zoom_out_scale);
            }
            else
            {
                parent.invalidate_rectangle(rect);
            }

            highlighted_rect = std::numeric_limits<unsigned long>::max();
            rect_is_selected = false;
            parts_menu.disable();
            assign_image_scaled(img,new_img);
        }

        virtual void set_pos (
            long x,
            long y
        )
        {
            auto_mutex lock(m);
            scrollable_region::set_pos(x,y);
            parts_menu.set_rect(rect);
        }

        virtual void set_size (
            unsigned long width,
            unsigned long height
        )
        {
            auto_mutex lock(m);
            scrollable_region::set_size(width,height);
            parts_menu.set_rect(rect);
        }

        struct overlay_rect
        {
            overlay_rect() :crossed_out(false) { assign_pixel(color, 0);}

            template <typename pixel_type>
            overlay_rect(const rectangle& r, pixel_type p)
                : rect(r),crossed_out(false) { assign_pixel(color, p); }

            template <typename pixel_type>
            overlay_rect(const rectangle& r, pixel_type p, const std::string& l)
                : rect(r),label(l),crossed_out(false) { assign_pixel(color, p); }

            template <typename pixel_type>
            overlay_rect(const rectangle& r, pixel_type p, const std::string& l, const std::map<std::string,point>& parts_)
                : rect(r),label(l),parts(parts_),crossed_out(false) { assign_pixel(color, p); }

            rectangle rect;
            rgb_alpha_pixel color;
            std::string label;
            std::map<std::string,point> parts;
            bool crossed_out;
        };

        struct overlay_line
        {
            overlay_line() { assign_pixel(color, 0);}

            template <typename pixel_type>
            overlay_line(const point& p1_, const point& p2_, pixel_type p)
                : p1(p1_), p2(p2_) { assign_pixel(color, p); }

            point p1;
            point p2;
            rgb_alpha_pixel color;
        };

        struct overlay_circle
        {
            overlay_circle():radius(0) { assign_pixel(color, 0);}

            template <typename pixel_type>
            overlay_circle(const point& center_, const int radius_, pixel_type p)
                : center(center_), radius(radius_) { assign_pixel(color, p); }

            template <typename pixel_type>
            overlay_circle(const point& center_, const int radius_, pixel_type p, const std::string& l)
                : center(center_), radius(radius_), label(l) { assign_pixel(color, p); }

            point center;
            int radius;
            rgb_alpha_pixel color;
            std::string label;
        };

        void add_overlay (
            const overlay_rect& overlay
        );

        void add_overlay (
            const overlay_line& overlay
        );

        void add_overlay (
            const overlay_circle& overlay
        );

        void add_overlay (
            const std::vector<overlay_rect>& overlay
        );

        void add_overlay (
            const std::vector<overlay_line>& overlay
        );

        void add_overlay (
            const std::vector<overlay_circle>& overlay
        );

        void clear_overlay (
        );

        rectangle get_image_display_rect (
        ) const;

        std::vector<overlay_rect> get_overlay_rects (
        ) const;

        void set_default_overlay_rect_label (
            const std::string& label
        );

        std::string get_default_overlay_rect_label (
        ) const;

        void set_default_overlay_rect_color (
            const rgb_alpha_pixel& color
        );

        rgb_alpha_pixel get_default_overlay_rect_color (
        ) const;

        template <
            typename T
            >
        void set_overlay_rects_changed_handler (
            T& object,
            void (T::*event_handler_)()
        )
        {
            auto_mutex M(m);
            event_handler = make_mfp(object,event_handler_);
        }

        void set_overlay_rects_changed_handler (
            const any_function<void()>& event_handler_
        )
        {
            auto_mutex M(m);
            event_handler = event_handler_;
        }

        template <
            typename T
            >
        void set_overlay_rect_selected_handler (
            T& object,
            void (T::*event_handler_)(const overlay_rect& orect)
        )
        {
            auto_mutex M(m);
            orect_selected_event_handler = make_mfp(object,event_handler_);
        }

        void set_overlay_rect_selected_handler (
            const any_function<void(const overlay_rect& orect)>& event_handler_
        )
        {
            auto_mutex M(m);
            orect_selected_event_handler = event_handler_;
        }

        template <
            typename T
            >
        void set_image_clicked_handler (
            T& object,
            void (T::*event_handler_)(const point& p, bool is_double_click, unsigned long btn)
        )
        {
            auto_mutex M(m);
            image_clicked_handler = make_mfp(object,event_handler_);
        }

        void set_image_clicked_handler (
            const any_function<void(const point& p, bool is_double_click, unsigned long btn)>& event_handler_
        )
        {
            auto_mutex M(m);
            image_clicked_handler = event_handler_;
        }

        void add_labelable_part_name (
            const std::string& name
        );

        void clear_labelable_part_names (
        );

        void enable_overlay_editing (
        ) { auto_mutex M(m); overlay_editing_enabled = true; }

        void disable_overlay_editing (
        )
        {
            auto_mutex M(m);
            overlay_editing_enabled = false;
            rect_is_selected = false;
            drawing_rect = false;
            parent.invalidate_rectangle(rect);
        }

        bool overlay_editing_is_enabled (
        ) const { auto_mutex M(m); return overlay_editing_enabled; }

    private:

        void draw (
            const canvas& c
        ) const;

        void on_wheel_up (
            unsigned long state
        );

        void on_wheel_down (
            unsigned long state
        );

        void on_mouse_down (
            unsigned long btn,
            unsigned long state,
            long x,
            long y,
            bool is_double_click
        );

        void on_mouse_up (
            unsigned long btn,
            unsigned long state,
            long x,
            long y
        );

        void on_mouse_move (
            unsigned long state,
            long x,
            long y
        );

        void on_keydown (
            unsigned long key,
            bool is_printable,
            unsigned long state
        );

        void on_part_add (
            const std::string& part_name
        );

        rectangle get_rect_on_screen (
            unsigned long idx
        ) const;

        rectangle get_rect_on_screen (
            rectangle orect
        ) const;

        rgb_alpha_pixel invert_pixel (const rgb_alpha_pixel& p) const
        { return rgb_alpha_pixel(255-p.red, 255-p.green, 255-p.blue, p.alpha); }

        virtual int next_free_user_event_number (
        ) const { return scrollable_region::next_free_user_event_number()+1; }
        // The reason for using user actions here rather than just having the timer just call
        // what it needs directly is to avoid a potential deadlock during destruction of this widget.
        void timer_event_unhighlight_rect()
        {
            highlight_timer.stop();
            parent.trigger_user_event(this,scrollable_region::next_free_user_event_number());
        }
        void on_user_event (int num)
        {
            // ignore this user event if it isn't for us
            if (num != scrollable_region::next_free_user_event_number())
                return;
            if (highlighted_rect < overlay_rects.size())
            {
                highlighted_rect = std::numeric_limits<unsigned long>::max();
                parent.invalidate_rectangle(rect);
            }
        }

        array2d<rgb_alpha_pixel> img;

        std::vector<overlay_rect> overlay_rects;
        std::vector<overlay_line> overlay_lines;
        std::vector<overlay_circle> overlay_circles;

        long zoom_in_scale;
        long zoom_out_scale;
        bool drawing_rect;
        point rect_anchor;
        rectangle rect_to_draw;
        bool rect_is_selected;
        std::string selected_part_name;
        unsigned long selected_rect;
        rgb_alpha_pixel default_rect_color;
        std::string default_rect_label;
        any_function<void()> event_handler;
        any_function<void(const overlay_rect& orect)> orect_selected_event_handler;
        any_function<void(const point& p, bool is_double_click, unsigned long btn)> image_clicked_handler;
        popup_menu_region parts_menu;
        point last_right_click_pos;
        const int part_width;
        std::set<std::string> part_names;
        bool overlay_editing_enabled;
        timer<image_display> highlight_timer;
        unsigned long highlighted_rect;

        bool moving_overlay;
        unsigned long moving_rect;
        enum  {
            MOVING_RECT_LEFT,
            MOVING_RECT_TOP,
            MOVING_RECT_RIGHT,
            MOVING_RECT_BOTTOM,
            MOVING_PART
        } moving_what;
        std::string moving_part_name;

        // restricted functions
        image_display(image_display&);        // copy constructor
        image_display& operator=(image_display&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------

    class perspective_display : public drawable, noncopyable
    {
    public:

        perspective_display(
            drawable_window& w
        );

        ~perspective_display(
        );

        virtual void set_size (
            unsigned long width,
            unsigned long height
        );

        struct overlay_line
        {
            overlay_line() { assign_pixel(color, 0);}

            overlay_line(const vector<double>& p1_, const vector<double>& p2_)
                : p1(p1_), p2(p2_) { assign_pixel(color, 255); }

            template <typename pixel_type>
            overlay_line(const vector<double>& p1_, const vector<double>& p2_, pixel_type p)
                : p1(p1_), p2(p2_) { assign_pixel(color, p); }

            vector<double> p1;
            vector<double> p2;
            rgb_pixel color;
        };

        struct overlay_dot
        {
            overlay_dot() { assign_pixel(color, 0);}

            overlay_dot(const vector<double>& p_)
                : p(p_) { assign_pixel(color, 255); }

            template <typename pixel_type>
            overlay_dot(const vector<double>& p_, pixel_type color_)
                : p(p_) { assign_pixel(color, color_); }

            vector<double> p;
            rgb_pixel color;
        };

        void add_overlay (
            const std::vector<overlay_line>& overlay
        );

        void add_overlay (
            const std::vector<overlay_dot>& overlay
        );

        void clear_overlay (
        );

        template <
            typename T
            >
        void set_dot_double_clicked_handler (
            T& object,
            void (T::*event_handler_)(const vector<double>&)
        )
        {
            auto_mutex M(m);
            dot_clicked_event_handler = make_mfp(object,event_handler_);
        }

        void set_dot_double_clicked_handler (
            const any_function<void(const vector<double>&)>& event_handler_
        );

    private:

        void draw (
            const canvas& c
        ) const;

        void on_wheel_up (
            unsigned long state
        );

        void on_wheel_down (
            unsigned long state
        );

        void on_mouse_down (
            unsigned long btn,
            unsigned long state,
            long x,
            long y,
            bool is_double_click
        );

        void on_mouse_move (
            unsigned long state,
            long x,
            long y
        );

        static bool compare_second (
            const std::pair<overlay_dot,float>& a,
            const std::pair<overlay_dot,float>& b
        ) { return a.second < b.second; }

        point last;
        std::vector<overlay_line> overlay_lines;
        std::vector<overlay_dot> overlay_dots;

        camera_transform tform;
        vector<double> sum_pts;
        vector<double> max_pts;
        any_function<void(const vector<double>&)> dot_clicked_event_handler;
        mutable array2d<float> depth;
    };

// ----------------------------------------------------------------------------------------

    class perspective_window : public drawable_window, noncopyable
    {
    public:

        typedef perspective_display::overlay_line overlay_line;
        typedef perspective_display::overlay_dot overlay_dot;

        perspective_window(
        ) : disp(*this)
        {
            set_size(100,100);
            on_window_resized();
            show();
        }

        perspective_window(
            const std::vector<dlib::vector<double> >& point_cloud
        ) :
            disp(*this)
        {
            set_size(100,100);
            on_window_resized();
            add_overlay(point_cloud);
            show();
        }

        perspective_window(
            const std::vector<dlib::vector<double> >& point_cloud,
            const std::string& title
        ) :
            disp(*this)
        {
            set_size(100,100);
            on_window_resized();
            add_overlay(point_cloud);
            set_title(title);
            show();
        }

        ~perspective_window(
        )
        {
            // You should always call close_window() in the destructor of window
            // objects to ensure that no events will be sent to this window while
            // it is being destructed.
            close_window();
        }

        void add_overlay (
            const std::vector<overlay_line>& overlay
        )
        {
            disp.add_overlay(overlay);
        }

        void add_overlay (
            const std::vector<overlay_dot>& overlay
        )
        {
            disp.add_overlay(overlay);
        }

        void clear_overlay (
        )
        {
            disp.clear_overlay();
        }

        template <typename pixel_type>
        void add_overlay(const vector<double>& p1, const vector<double>& p2, pixel_type p)
        {
            add_overlay(std::vector<overlay_line>(1,overlay_line(p1,p2,p)));
        }

        void add_overlay(const std::vector<dlib::vector<double> >& d)
        {
            add_overlay(d, 255);
        }

        template <typename pixel_type>
        void add_overlay(const std::vector<dlib::vector<double> >& d, pixel_type p)
        {
            std::vector<overlay_dot> temp;
            temp.resize(d.size());
            for (unsigned long i = 0; i < temp.size(); ++i)
                temp[i] = overlay_dot(d[i], p);

            add_overlay(temp);
        }

        template <
            typename T
            >
        void set_dot_double_clicked_handler (
            T& object,
            void (T::*event_handler_)(const vector<double>&)
        )
        {
            disp.set_dot_double_clicked_handler(object,event_handler_);
        }

        void set_dot_double_clicked_handler (
            const any_function<void(const vector<double>&)>& event_handler_
        )
        {
            disp.set_dot_double_clicked_handler(event_handler_);
        }

    private:

        void on_window_resized(
        )
        {
            drawable_window::on_window_resized();
            unsigned long width, height;
            get_size(width,height);
            disp.set_pos(0,0);
            disp.set_size(width, height);
        }

        perspective_display disp;
    };

// ----------------------------------------------------------------------------------------

    class image_window : public drawable_window
    {
    public:

        typedef image_display::overlay_rect overlay_rect;
        typedef image_display::overlay_line overlay_line;
        typedef image_display::overlay_circle overlay_circle;

        image_window(
        );

        template < typename image_type >
        image_window(
            const image_type& img
        ) :
            gui_img(*this),
            window_has_closed(false),
            have_last_click(false),
            mouse_btn(0),
            clicked_signaler(this->wm),
            have_last_keypress(false),
            tie_input_events(false)
        {
            gui_img.set_image_clicked_handler(*this, &image_window::on_image_clicked);
            gui_img.disable_overlay_editing();
            set_image(img);
            show();
        }

        template < typename image_type >
        image_window(
            const image_type& img,
            const std::string& title
        ) :
            gui_img(*this),
            window_has_closed(false),
            have_last_click(false),
            mouse_btn(0),
            clicked_signaler(this->wm),
            have_last_keypress(false),
            tie_input_events(false)
        {
            gui_img.set_image_clicked_handler(*this, &image_window::on_image_clicked);
            gui_img.disable_overlay_editing();
            set_image(img);
            set_title(title);
            show();
        }

        ~image_window(
        );

        template < typename image_type >
        void set_image (
            const image_type& img
        )
        {
            const unsigned long padding = scrollable_region_style_default().get_border_size();
            auto_mutex M(wm);
            gui_img.set_image(img);

            // Only ever mess with the size of the window if the user is giving us an image
            // that is a different size.  Otherwise we assume that they will have already
            // sized the window to whatever they feel is reasonable for an image of the
            // current size.
            if (previous_image_size != get_rect(img))
            {
                const rectangle r = gui_img.get_image_display_rect();
                if (image_rect != r)
                {
                    // set the size of this window to match the size of the input image
                    set_size(r.width()+padding*2,r.height()+padding*2);

                    // call this to make sure everything else is setup properly
                    on_window_resized();

                    image_rect = r;
                }
                previous_image_size = get_rect(img);
            }
        }

        void add_overlay (
            const overlay_rect& overlay
        );

        template <typename pixel_type>
        void add_overlay(const rectangle& r, pixel_type p)
        { add_overlay(image_display::overlay_rect(r,p)); }

        void add_overlay(const rectangle& r)
        { add_overlay(image_display::overlay_rect(r,rgb_pixel(255,0,0))); }

        template <typename pixel_type>
        void add_overlay(const rectangle& r, pixel_type p, const std::string& l)
        { add_overlay(image_display::overlay_rect(r,p,l)); }

        template <typename pixel_type>
        void add_overlay(const std::vector<rectangle>& r, pixel_type p)
        {
            std::vector<overlay_rect> temp;
            temp.resize(r.size());
            for (unsigned long i = 0; i < temp.size(); ++i)
                temp[i] = overlay_rect(r[i], p);

            add_overlay(temp);
        }

        void add_overlay(const std::vector<rectangle>& r)
        { add_overlay(r, rgb_pixel(255,0,0)); }

        void add_overlay(
            const full_object_detection& object,
            const std::vector<std::string>& part_names
        )
        {

            add_overlay(overlay_rect(object.get_rect(), rgb_pixel(255,0,0)));

            std::vector<overlay_circle> temp;
            temp.reserve(object.num_parts());
            for (unsigned long i = 0; i < object.num_parts(); ++i)
            {
                if (object.part(i) != OBJECT_PART_NOT_PRESENT)
                {
                    if (i < part_names.size())
                        temp.push_back(overlay_circle(object.part(i), 7, rgb_pixel(0,255,0), part_names[i]));
                    else
                        temp.push_back(overlay_circle(object.part(i), 7, rgb_pixel(0,255,0)));
                }
            }

            add_overlay(temp);
        }

        void add_overlay(
            const full_object_detection& object
        )
        {
            std::vector<std::string> part_names;
            add_overlay(object, part_names);
        }

        void add_overlay(
            const std::vector<full_object_detection>& objects,
            const std::vector<std::string>& part_names
        )
        {
            std::vector<overlay_rect> rtemp;
            rtemp.reserve(objects.size());
            for (unsigned long i = 0; i < objects.size(); ++i)
            {
                rtemp.push_back(overlay_rect(objects[i].get_rect(), rgb_pixel(255,0,0)));
            }

            add_overlay(rtemp);

            std::vector<overlay_circle> temp;

            for (unsigned long i = 0; i < objects.size(); ++i)
            {
                for (unsigned long j = 0; j < objects[i].num_parts(); ++j)
                {
                    if (objects[i].part(j) != OBJECT_PART_NOT_PRESENT)
                    {
                        if (j < part_names.size())
                            temp.push_back(overlay_circle(objects[i].part(j), 7, rgb_pixel(0,255,0),part_names[j]));
                        else
                            temp.push_back(overlay_circle(objects[i].part(j), 7, rgb_pixel(0,255,0)));
                    }
                }
            }

            add_overlay(temp);
        }

        void add_overlay(
            const std::vector<full_object_detection>& objects
        )
        {
            std::vector<std::string> part_names;
            add_overlay(objects, part_names);
        }

        void add_overlay (
            const overlay_line& overlay
        );

        void add_overlay (
            const overlay_circle& overlay
        );

        template <typename pixel_type>
        void add_overlay(const point& p1, const point& p2, pixel_type p)
        { add_overlay(image_display::overlay_line(p1,p2,p)); }

        void add_overlay (
            const std::vector<overlay_rect>& overlay
        );

        void add_overlay (
            const std::vector<overlay_line>& overlay
        );

        void add_overlay (
            const std::vector<overlay_circle>& overlay
        );

        void clear_overlay (
        );

        bool get_next_double_click (
            point& p,
            unsigned long& mouse_button
        );

        void tie_events (
        );

        void untie_events (
        );

        bool events_tied (
        ) const;

        bool get_next_double_click (
            point& p
        )
        {
            unsigned long mouse_button;
            return get_next_double_click(p, mouse_button);
        }

        bool get_next_keypress (
            unsigned long& key,
            bool& is_printable,
            unsigned long& state
        );

        bool get_next_keypress (
            unsigned long& key,
            bool& is_printable
        )
        {
            unsigned long state;
            return get_next_keypress(key,is_printable,state);
        }

    private:

        virtual base_window::on_close_return_code on_window_close(
        );

        void on_window_resized(
        );

        void on_image_clicked (
            const point& p,
            bool is_double_click,
            unsigned long btn
        );

        virtual void on_keydown (
            unsigned long key,
            bool is_printable,
            unsigned long state
        );

        // restricted functions
        image_window(image_window&);
        image_window& operator= (image_window&);

        image_display gui_img;
        rectangle image_rect;
        rectangle previous_image_size;
        bool window_has_closed;
        bool have_last_click;
        point last_clicked_point;
        unsigned long mouse_btn;
        rsignaler clicked_signaler;

        bool have_last_keypress;
        unsigned long next_key;
        bool next_is_printable;
        unsigned long next_state;
        bool tie_input_events;
    };

// ----------------------------------------------------------------------------------------

}

#ifdef NO_MAKEFILE
#include "widgets.cpp"
#endif

#endif // DLIB_WIDGETs_


dlib C++ Library - hash_map_kernel_1.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_HASH_MAP_KERNEl_1_
#define DLIB_HASH_MAP_KERNEl_1_

#include "hash_map_kernel_abstract.h"
#include "../algs.h"
#include "../general_hash/general_hash.h"
#include "../interfaces/enumerable.h"
#include "../interfaces/map_pair.h"
#include "../interfaces/remover.h"
#include "../assert.h"
#include "../serialize.h"

namespace dlib
{

    template <
        typename domain,
        typename range,
        unsigned long expnum,
        typename hash_table,
        typename mem_manager = default_memory_manager
        >
    class hash_map_kernel_1 : public enumerable<map_pair<domain,range> >,
                              public pair_remover<domain,range>
    {

        /*!
            REQUIREMENTS ON hash_table
                hash_table is instantiated with domain and range and
                T_is_POD must be set to false and
                implements hash_table/hash_table_kernel_abstract.h

            INITIAL VALUE
                table.size() == 0

            CONVENTION
                table.size() = size() == the number of elements in the map
                the elements in this hash_map are stored in table
        !*/

        public:

            typedef domain domain_type;
            typedef range range_type;
            typedef typename hash_table::compare_type compare_type;
            typedef mem_manager mem_manager_type;

            hash_map_kernel_1(
            ) :
                table(expnum)
            {
                COMPILE_TIME_ASSERT(expnum < 32);
            }

            virtual ~hash_map_kernel_1(
            )
            {}

            inline void clear(
            );

            void add (
                domain& d,
                range& r
            );

            inline bool is_in_domain (
                const domain& d
            ) const;

            void remove (
                const domain& d,
                domain& d_copy,
                range& r
            );

            void destroy (
                const domain& d
            );

            range& operator[] (
                const domain& d
            );

            const range& operator[] (
                const domain& d
            ) const;

            inline void swap (
                hash_map_kernel_1& item
            );

            // functions from the remover interface
            inline void remove_any (
                domain& d,
                range& r
            );

            // functions from the enumerable interface
            inline unsigned long size (
            ) const;

            inline bool at_start (
            ) const;

            inline void reset (
            ) const;

            inline bool current_element_valid (
            ) const;

            inline const map_pair<domain,range>& element (
            ) const;

            inline map_pair<domain,range>& element (
            );

            inline bool move_next (
            ) const;

        private:

            hash_table table;

            // restricted functions
            hash_map_kernel_1(hash_map_kernel_1&);
            hash_map_kernel_1& operator= ( hash_map_kernel_1&);

    };

    template <
        typename domain,
        typename range,
        unsigned long expnum,
        typename hash_table,
        typename mem_manager
        >
    inline void swap (
        hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>& a,
        hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>& b
    ) { a.swap(b); }

    template <
        typename domain,
        typename range,
        unsigned long expnum,
        typename hash_table,
        typename mem_manager
        >
    void deserialize (
        hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>& item,
        std::istream& in
    )
    {
        try
        {
            item.clear();
            unsigned long size;
            deserialize(size,in);
            domain d;
            range r;
            for (unsigned long i = 0; i < size; ++i)
            {
                deserialize(d,in);
                deserialize(r,in);
                item.add(d,r);
            }
        }
        catch (serialization_error e)
        {
            item.clear();
            throw serialization_error(e.info + "\n   while deserializing object of type hash_map_kernel_1");
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        unsigned long expnum,
        typename hash_table,
        typename mem_manager
        >
    void hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>::
    clear (
    )
    {
        table.clear();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        unsigned long expnum,
        typename hash_table,
        typename mem_manager
        >
    void hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>::
    add (
        domain& d,
        range& r
    )
    {
        table.add(d,r);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        unsigned long expnum,
        typename hash_table,
        typename mem_manager
        >
    bool hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>::
    is_in_domain(
        const domain& d
    ) const
    {
        return (table[d] != 0);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        unsigned long expnum,
        typename hash_table,
        typename mem_manager
        >
    void hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>::
    remove_any (
        domain& d,
        range& r
    )
    {
        table.remove_any(d,r);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        unsigned long expnum,
        typename hash_table,
        typename mem_manager
        >
    void hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>::
    remove(
        const domain& d,
        domain& d_copy,
        range& r
    )
    {
        table.remove(d,d_copy,r);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        unsigned long expnum,
        typename hash_table,
        typename mem_manager
        >
    void hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>::
    destroy(
        const domain& d
    )
    {
        table.destroy(d);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        unsigned long expnum,
        typename hash_table,
        typename mem_manager
        >
    range& hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>::
    operator[](
        const domain& d
    )
    {
        return *table[d];
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        unsigned long expnum,
        typename hash_table,
        typename mem_manager
        >
    const range& hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>::
    operator[](
        const domain& d
    ) const
    {
        return *table[d];
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        unsigned long expnum,
        typename hash_table,
        typename mem_manager
        >
    unsigned long hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>::
    size (
    ) const
    {
        return table.size();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        unsigned long expnum,
        typename hash_table,
        typename mem_manager
        >
    void hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>::
    swap (
        hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>& item
    )
    {
        table.swap(item.table);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // enumerable function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        unsigned long expnum,
        typename hash_table,
        typename mem_manager
        >
    bool hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>::
    at_start (
    ) const
    {
        return table.at_start();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        unsigned long expnum,
        typename hash_table,
        typename mem_manager
        >
    void hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>::
    reset (
    ) const
    {
        table.reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        unsigned long expnum,
        typename hash_table,
        typename mem_manager
        >
    bool hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>::
    current_element_valid (
    ) const
    {
        return table.current_element_valid();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        unsigned long expnum,
        typename hash_table,
        typename mem_manager
        >
    const map_pair<domain,range>& hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>::
    element (
    ) const
    {
        return table.element();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        unsigned long expnum,
        typename hash_table,
        typename mem_manager
        >
    map_pair<domain,range>& hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>::
    element (
    )
    {
        return table.element();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        unsigned long expnum,
        typename hash_table,
        typename mem_manager
        >
    bool hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>::
    move_next (
    ) const
    {
        return table.move_next();
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_HASH_MAP_KERNEl_1_


dlib C++ Library - hash_set_kernel_1.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_HASH_SET_KERNEl_1_
#define DLIB_HASH_SET_KERNEl_1_

#include "hash_set_kernel_abstract.h"
#include "../algs.h"
#include "../general_hash/general_hash.h"
#include "../interfaces/enumerable.h"
#include "../interfaces/remover.h"
#include "../assert.h"
#include "../serialize.h"

namespace dlib
{

    template <
        typename T,
        unsigned long expnum,
        typename hash_table,
        typename mem_manager = default_memory_manager
        >
    class hash_set_kernel_1 : public enumerable<const T>,
                              public remover<T>
    {

        /*!
            REQUIREMENTS ON hash_table
                hash_table is instantiated with <domain=T,range=char> and
                T_is_POD must be set to false and
                is an implementation of hash_table/hash_table_kernel_abstract.h

            INITIAL VALUE
                table.size() == 0

            CONVENTION
                table.size() = size() == the number of elements in the set and
                the elements in this hash_set are stored in table
        !*/

        public:

            typedef T type;
            typedef typename hash_table::compare_type compare_type;
            typedef mem_manager mem_manager_type;

            hash_set_kernel_1(
            ) :
                table(expnum)
            {
                COMPILE_TIME_ASSERT(expnum < 32);
            }

            virtual ~hash_set_kernel_1(
            )
            {}

            inline void clear(
            );

            inline void add (
                T& item
            );

            inline bool is_member (
                const T& item
            ) const;

            inline void remove (
                const T& item,
                T& item_copy
            );

            inline void destroy (
                const T& item
            );

            inline void swap (
                hash_set_kernel_1& item
            );

            // functions from the remover interface
            inline void remove_any (
                T& item
            );

            // functions from the enumerable interface
            inline unsigned long size (
            ) const;

            inline bool at_start (
            ) const;

            inline void reset (
            ) const;

            inline bool current_element_valid (
            ) const;

            inline const T& element (
            ) const;

            inline const T& element (
            );

            inline bool move_next (
            ) const;

        private:

            hash_table table;
            char junk;

            // restricted functions
            hash_set_kernel_1(hash_set_kernel_1&);
            hash_set_kernel_1& operator= ( hash_set_kernel_1&);

    };

    template <
        typename T,
        unsigned long expnum,
        typename hash_table,
        typename mem_manager
        >
    inline void swap (
        hash_set_kernel_1<T,expnum,hash_table,mem_manager>& a,
        hash_set_kernel_1<T,expnum,hash_table,mem_manager>& b
    ) { a.swap(b); }

    template <
        typename T,
        unsigned long expnum,
        typename hash_table,
        typename mem_manager
        >
    void deserialize (
        hash_set_kernel_1<T,expnum,hash_table,mem_manager>& item,
        std::istream& in
    )
    {
        try
        {
            item.clear();
            unsigned long size;
            deserialize(size,in);
            T temp;
            for (unsigned long i = 0; i < size; ++i)
            {
                deserialize(temp,in);
                item.add(temp);
            }
        }
        catch (serialization_error e)
        {
            item.clear();
            throw serialization_error(e.info + "\n   while deserializing object of type hash_set_kernel_1");
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        unsigned long expnum,
        typename hash_table,
        typename mem_manager
        >
    void hash_set_kernel_1<T,expnum,hash_table,mem_manager>::
    clear (
    )
    {
        table.clear();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        unsigned long expnum,
        typename hash_table,
        typename mem_manager
        >
    void hash_set_kernel_1<T,expnum,hash_table,mem_manager>::
    add (
        T& item
    )
    {
        table.add(item,junk);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        unsigned long expnum,
        typename hash_table,
        typename mem_manager
        >
    bool hash_set_kernel_1<T,expnum,hash_table,mem_manager>::
    is_member(
        const T& item
    ) const
    {
        return (table[item] != 0);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        unsigned long expnum,
        typename hash_table,
        typename mem_manager
        >
    void hash_set_kernel_1<T,expnum,hash_table,mem_manager>::
    remove_any (
        T& item
    )
    {
        table.remove_any(item,junk);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        unsigned long expnum,
        typename hash_table,
        typename mem_manager
        >
    void hash_set_kernel_1<T,expnum,hash_table,mem_manager>::
    remove(
        const T& item,
        T& item_copy
    )
    {
        table.remove(item,item_copy,junk);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        unsigned long expnum,
        typename hash_table,
        typename mem_manager
        >
    void hash_set_kernel_1<T,expnum,hash_table,mem_manager>::
    destroy(
        const T& item
    )
    {
        table.destroy(item);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        unsigned long expnum,
        typename hash_table,
        typename mem_manager
        >
    unsigned long hash_set_kernel_1<T,expnum,hash_table,mem_manager>::
    size (
    ) const
    {
        return table.size();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        unsigned long expnum,
        typename hash_table,
        typename mem_manager
        >
    void hash_set_kernel_1<T,expnum,hash_table,mem_manager>::
    swap (
        hash_set_kernel_1<T,expnum,hash_table,mem_manager>& item
    )
    {
        table.swap(item.table);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // enumerable function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        unsigned long expnum,
        typename hash_table,
        typename mem_manager
        >
    bool hash_set_kernel_1<T,expnum,hash_table,mem_manager>::
    at_start (
    ) const
    {
        return table.at_start();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        unsigned long expnum,
        typename hash_table,
        typename mem_manager
        >
    void hash_set_kernel_1<T,expnum,hash_table,mem_manager>::
    reset (
    ) const
    {
        table.reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        unsigned long expnum,
        typename hash_table,
        typename mem_manager
        >
    bool hash_set_kernel_1<T,expnum,hash_table,mem_manager>::
    current_element_valid (
    ) const
    {
        return table.current_element_valid();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        unsigned long expnum,
        typename hash_table,
        typename mem_manager
        >
    const T& hash_set_kernel_1<T,expnum,hash_table,mem_manager>::
    element (
    ) const
    {
        return table.element().key();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        unsigned long expnum,
        typename hash_table,
        typename mem_manager
        >
    const T& hash_set_kernel_1<T,expnum,hash_table,mem_manager>::
    element (
    )
    {
        return table.element().key();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        unsigned long expnum,
        typename hash_table,
        typename mem_manager
        >
    bool hash_set_kernel_1<T,expnum,hash_table,mem_manager>::
    move_next (
    ) const
    {
        return table.move_next();
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_HASH_SET_KERNEl_1_


dlib C++ Library - hash_table_kernel_1.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_HASH_TABLE_KERNEl_1_
#define DLIB_HASH_TABLE_KERNEl_1_

#include "hash_table_kernel_abstract.h"
#include "../general_hash/general_hash.h"
#include "../algs.h"
#include "../interfaces/map_pair.h"
#include "../interfaces/enumerable.h"
#include "../interfaces/remover.h"
#include "../assert.h"
#include "../serialize.h"
#include <functional>

namespace dlib
{

    template <
        typename domain,
        typename range,
        typename mem_manager = default_memory_manager,
        typename compare = std::less<domain>
        >
    class hash_table_kernel_1 : public enumerable<map_pair<domain, range> >,
                                public pair_remover<domain,range>
    {

        /*!
            INITIAL VALUE
                hash_size == 0
                table == pointer to an array of num_of_buckets node pointers
                num_of_buckets == the number of buckets in the hash table
                current_element == 0
                at_start_ == true
                mask == num_of_buckets-1

            CONVENTION
                current_element_valid() == (current_element != 0)
                element() == current_element->d and current_element->r
                at_start_ == at_start()
                if (current_element != 0) then
                    table[current_bucket] == a pointer to the linked list that contains
                                             the node pointed to by current_element

                mask == num_of_buckets-1

                hash_size = size() == the number of elements in the hash_table and
                table == pointer to an array of num_of_buckets node pointers and
                num_of_buckets == the number of buckets in the hash table and
                for all i:
                    table[i] == pointer to the first node in a linked list or
                    table[i] == 0 if this bucket is currently not in use

                for all nodes:
                    d == the domain element stored in this node
                    r == the range element stored in this node which is associated with
                         d.
                    next == pointer to the next node in the linked list or
                    next == 0 if this is the last node in the linked list

        !*/

        struct node
        {
            node* next;
            domain d;
            range r;
        };

        class mpair : public map_pair<domain,range>
        {
        public:
            const domain* d;
            range* r;

            const domain& key(
            ) const { return *d; }

            const range& value(
            ) const { return *r; }

            range& value(
            ) { return *r; }
        };

        public:

            typedef domain domain_type;
            typedef range range_type;
            typedef compare compare_type;
            typedef mem_manager mem_manager_type;

            explicit hash_table_kernel_1(
                unsigned long expnum
            );

            virtual ~hash_table_kernel_1(
            );

            void clear(
            );

            unsigned long count (
                const domain& item
            ) const;

            void add (
                domain& d,
                range& r
            );

            void remove (
                const domain& d,
                domain& d_copy,
                range& r
            );

            void destroy (
                const domain& d
            );

            const range* operator[] (
                const domain& d
            ) const;

            range* operator[] (
                const domain& d
            );

            void swap (
                hash_table_kernel_1& item
            );

            // functions from the remover interface
            void remove_any (
                domain& d,
                range& r
            );

            // functions from the enumerable interface
            inline unsigned long size (
            ) const;

            bool at_start (
            ) const;

            inline void reset (
            ) const;

            bool current_element_valid (
            ) const;

            const map_pair<domain,range>& element (
            ) const;

            map_pair<domain,range>& element (
            );

            bool move_next (
            ) const;

        private:

            // data members
            typename mem_manager::template rebind<node>::other pool;
            typename mem_manager::template rebind<node*>::other ppool;
            unsigned long hash_size;
            node** table;
            general_hash<domain> hash;
            unsigned long num_of_buckets;
            unsigned long mask;

            mutable mpair p;

            mutable unsigned long current_bucket;
            mutable node* current_element;
            mutable bool at_start_;
            compare comp;

            // restricted functions
            hash_table_kernel_1(hash_table_kernel_1&);
            hash_table_kernel_1& operator=(hash_table_kernel_1&);

    };

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    inline void swap (
        hash_table_kernel_1<domain,range,mem_manager,compare>& a,
        hash_table_kernel_1<domain,range,mem_manager,compare>& b
    ) { a.swap(b); }

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void deserialize (
        hash_table_kernel_1<domain,range,mem_manager,compare>& item,
        std::istream& in
    )
    {
        try
        {
            item.clear();
            unsigned long size;
            deserialize(size,in);
            domain d;
            range r;
            for (unsigned long i = 0; i < size; ++i)
            {
                deserialize(d,in);
                deserialize(r,in);
                item.add(d,r);
            }
        }
        catch (serialization_error e)
        {
            item.clear();
            throw serialization_error(e.info + "\n   while deserializing object of type hash_table_kernel_1");
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    hash_table_kernel_1<domain,range,mem_manager,compare>::
    hash_table_kernel_1(
        unsigned long expnum
    ) :
        hash_size(0),
        current_element(0),
        at_start_(true)
    {

        num_of_buckets = 1;
        while (expnum != 0)
        {
            --expnum;
            num_of_buckets <<= 1;
        }
        mask = num_of_buckets-1;

        table = ppool.allocate_array(num_of_buckets);
        for (unsigned long i = 0; i < num_of_buckets; ++i)
        {
            table[i] = 0;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    hash_table_kernel_1<domain,range,mem_manager,compare>::
    ~hash_table_kernel_1(
    )
    {
        for (unsigned long i = 0; i < num_of_buckets; ++i)
        {
            // delete this linked list
            node* temp = table[i];
            while (temp)
            {
                node* t = temp;
                temp = temp->next;
                pool.deallocate(t);
            }
            table[i] = 0;
        }
        ppool.deallocate_array(table);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void hash_table_kernel_1<domain,range,mem_manager,compare>::
    clear(
    )
    {
        if (hash_size > 0)
        {
            for (unsigned long i = 0; i < num_of_buckets; ++i)
            {
                // delete this linked list
                node* temp = table[i];
                while (temp)
                {
                    node* t = temp;
                    temp = temp->next;
                    pool.deallocate(t);
                }
                table[i] = 0;
            }
            hash_size = 0;
        }
        // reset the enumerator
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    unsigned long hash_table_kernel_1<domain,range,mem_manager,compare>::
    size(
    ) const
    {
        return hash_size;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    unsigned long hash_table_kernel_1<domain,range,mem_manager,compare>::
    count(
        const domain& d
    ) const
    {
        unsigned long items_found = 0;
        node* temp = table[hash(d)&mask];

        while (temp != 0)
        {
            // look for an element equivalent to d
            if ( !(comp(temp->d , d) || comp(d , temp->d)) )
            {
                ++items_found;
            }
            temp = temp->next;
        }

        return items_found;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void hash_table_kernel_1<domain,range,mem_manager,compare>::
    add(
        domain& d,
        range& r
    )
    {
        unsigned long hash_value = hash(d)&mask;

        // make a new node for this item
        node& temp = *(pool.allocate());
        exchange(d,temp.d);
        exchange(r,temp.r);

        // add this new node to the head of the linked list in bucket number hash_value
        temp.next = table[hash_value];
        table[hash_value] = &temp;

        ++hash_size;

        // reset the enumerator
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void hash_table_kernel_1<domain,range,mem_manager,compare>::
    destroy(
        const domain& d
    )
    {
        node* last;
        const unsigned long hash_value = hash(d)&mask;
        node* temp = table[hash_value];

        // if there is more than one thing in this bucket
        if (temp->next != 0)
        {
            // start looking with the second item in the list
            last = temp;
            temp = temp->next;
            while (true)
            {
                // if we hit the end of the list without finding item then it must
                // be the first element in the list so splice it out
                if (temp == 0)
                {
                    temp = table[hash_value];
                    table[hash_value] = temp->next;

                    break;
                }

                // look for an element equivalent to item
                if ( !(comp(temp->d , d) || comp(d , temp->d)) )
                {
                    // splice out the node we want to remove
                    last->next = temp->next;
                    break;
                }

                last = temp;
                temp = temp->next;
            }

        }
        // else there is only one node in this linked list
        else
        {
            table[hash_value] = 0;
        }

        pool.deallocate(temp);

        --hash_size;

        // reset the enumerator
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void hash_table_kernel_1<domain,range,mem_manager,compare>::
    remove(
        const domain& d,
        domain& d_copy,
        range& r
    )
    {
        node* last;
        const unsigned long hash_value = hash(d)&mask;
        node* temp = table[hash_value];

        // if there is more than one thing in this bucket
        if (temp->next != 0)
        {
            // start looking with the second item in the list
            last = temp;
            temp = temp->next;
            while (true)
            {
                // if we hit the end of the list without finding item then it must
                // be the first element in the list so splice it out
                if (temp == 0)
                {
                    temp = table[hash_value];
                    table[hash_value] = temp->next;

                    break;
                }

                // look for an element equivalent to item
                if ( !(comp(temp->d , d) || comp(d , temp->d)) )
                {
                    // splice out the node we want to remove
                    last->next = temp->next;
                    break;
                }

                last = temp;
                temp = temp->next;
            }

        }
        // else there is only one node in this linked list
        else
        {
            table[hash_value] = 0;
        }

        exchange(d_copy,temp->d);
        exchange(r,temp->r);
        pool.deallocate(temp);

        --hash_size;

        // reset the enumerator
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void hash_table_kernel_1<domain,range,mem_manager,compare>::
    remove_any(
        domain& d,
        range& r
    )
    {
        unsigned long i = 0;

        // while the ith bucket is empty keep looking
        while (table[i] == 0)
        {
            ++i;
        }

        // remove the first node in the linked list in the ith bucket
        node& temp = *(table[i]);

        exchange(temp.d,d);
        exchange(temp.r,r);
        table[i] = temp.next;

        pool.deallocate(&temp);

        --hash_size;

        // reset the enumerator
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    const range* hash_table_kernel_1<domain,range,mem_manager,compare>::
    operator[](
        const domain& d
    ) const
    {
        node* temp = table[hash(d)&mask];

        while (temp != 0)
        {
            // look for an element equivalent to item
            if ( !(comp(temp->d , d) || comp(d , temp->d)) )
                return &(temp->r);

            temp = temp->next;
        }

        return 0;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    range* hash_table_kernel_1<domain,range,mem_manager,compare>::
    operator[](
        const domain& d
    )
    {
        node* temp = table[hash(d)&mask];

        while (temp != 0)
        {
            // look for an element equivalent to item
            if ( !(comp(temp->d , d) || comp(d , temp->d)) )
                return &(temp->r);

            temp = temp->next;
        }

        return 0;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void hash_table_kernel_1<domain,range,mem_manager,compare>::
    swap(
        hash_table_kernel_1<domain,range,mem_manager,compare>& item
    )
    {
        exchange(mask,item.mask);
        exchange(table,item.table);
        exchange(hash_size,item.hash_size);
        exchange(num_of_buckets,item.num_of_buckets);
        exchange(current_bucket,item.current_bucket);
        exchange(current_element,item.current_element);
        exchange(at_start_,item.at_start_);
        pool.swap(item.pool);
        ppool.swap(item.ppool);
        exchange(p,item.p);
        exchange(comp,item.comp);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // enumerable function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    bool hash_table_kernel_1<domain,range,mem_manager,compare>::
    at_start (
    ) const
    {
        return at_start_;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    void hash_table_kernel_1<domain,range,mem_manager,compare>::
    reset (
    ) const
    {
        at_start_ = true;
        current_element = 0;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    bool hash_table_kernel_1<domain,range,mem_manager,compare>::
    current_element_valid (
    ) const
    {
        return (current_element != 0);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    const map_pair<domain,range>& hash_table_kernel_1<domain,range,mem_manager,compare>::
    element (
    ) const
    {
        p.d = &(current_element->d);
        p.r = &(current_element->r);
        return p;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    map_pair<domain,range>& hash_table_kernel_1<domain,range,mem_manager,compare>::
    element (
    )
    {
        p.d = &(current_element->d);
        p.r = &(current_element->r);
        return p;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename mem_manager,
        typename compare
        >
    bool hash_table_kernel_1<domain,range,mem_manager,compare>::
    move_next (
    ) const
    {
        if (at_start_)
        {
            at_start_ = false;
            // if the queue is empty then there is nothing to do
            if (hash_size == 0)
            {
                return false;
            }
            else
            {
                // find the first element in the hash table
                for (current_bucket = 0; true ; ++current_bucket)
                {
                    if (table[current_bucket] != 0)
                    {
                        current_element = table[current_bucket];
                        break;
                    }
                }
                return true;
            }
        }
        else
        {
            // if we have already enumerated every element
            if (current_element == 0)
            {
                return false;
            }
            else
            {
                // find the next element if it exists
                if (current_element->next != 0)
                {
                    current_element = current_element->next;
                    return true;
                }
                else
                {
                    // find next bucket with something in it
                    for (current_bucket+=1; current_bucket<num_of_buckets; ++current_bucket)
                    {
                        if (table[current_bucket] != 0)
                        {
                            // we just found the next bucket
                            current_element = table[current_bucket];
                            break;
                        }
                    }
                    // make sure we actually found another nonempty bucket
                    if (current_bucket == num_of_buckets)
                    {
                        // we didn't find anything
                        current_element = 0;
                        return false;
                    }
                    else
                    {
                        // we found another bucket
                        return true;
                    }
                }
            }
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_HASH_TABLE_KERNEl_1_


dlib C++ Library - hash_table_kernel_2.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_HASH_TABLE_KERNEl_2_
#define DLIB_HASH_TABLE_KERNEl_2_

#include "hash_table_kernel_abstract.h"
#include "../general_hash/general_hash.h"
#include "../algs.h"
#include "../interfaces/map_pair.h"
#include "../interfaces/enumerable.h"
#include "../interfaces/remover.h"
#include "../assert.h"
#include "../serialize.h"
#include <functional>

namespace dlib
{

    template <
        typename domain,
        typename range,
        typename bst_base,
        typename mem_manager = default_memory_manager,
        typename compare = std::less<domain>
        >
    class hash_table_kernel_2 : public enumerable<map_pair<domain,range> >,
                                public pair_remover<domain,range>
    {

        /*!
            REQUIREMENTS ON bst_base
                bst_base is instantiated with domain and range and
                implements binray_search_tree/binary_search_tree_kernel_abstract.h

             INITIAL VALUE
                hash_size == 0
                table == pointer to an array of num_of_buckets bst_base objects
                num_of_buckets == the number of buckets in the hash table
                current_bucket == 0
                at_start_ == true

            CONVENTION
                current_element_valid() == (current_bucket != 0)
                element() == current_bucket->element()
                at_start_ == at_start()

                mask == num_of_buckets-1

                for all integers i where &table[i] != current_bucket
                    table[i].at_start() == true

                hash_size = size() == the number of elements in the hash_table and
                table == pointer to an array of num_of_buckets bst_base objects
                num_of_buckets == the number of buckets in the hash table and
                the elements in this hash table are stored in the bst_base objects in the
                array table

        !*/

        public:

            typedef domain domain_type;
            typedef range range_type;
            typedef compare compare_type;
            typedef mem_manager mem_manager_type;

            explicit hash_table_kernel_2(
                unsigned long expnum
            );

            virtual ~hash_table_kernel_2(
            )
            { pool.deallocate_array(table); }

            void clear(
            );

            unsigned long count (
                const domain& item
            ) const;

            inline void add (
                domain& d,
                range& r
            );

            void destroy (
                const domain& d
            );

            void remove (
                const domain& d,
                domain& d_copy,
                range& r
            );

            const range* operator[] (
                const domain& item
            ) const;

            range* operator[] (
                const domain& item
            );

            inline void swap (
                hash_table_kernel_2& item
            );

            // functions from the remover interface
            void remove_any (
                domain& d,
                range& r
            );

            // functions from the enumerable interface
            inline unsigned long size (
            ) const;

            inline bool at_start (
            ) const;

            inline void reset (
            ) const;

            bool current_element_valid (
            ) const;

            inline const map_pair<domain,range>& element (
            ) const;

            inline map_pair<domain,range>& element (
            );

            bool move_next (
            ) const;

        private:

            // data members
            typename mem_manager::template rebind<bst_base>::other pool;
            unsigned long mask;
            unsigned long hash_size;
            unsigned long num_of_buckets;
            bst_base* table;
            general_hash<domain> hash;
            mutable bst_base* current_bucket;
            mutable bool at_start_;
            compare comp;

            // restricted functions
            hash_table_kernel_2(hash_table_kernel_2&);
            hash_table_kernel_2& operator=(hash_table_kernel_2&);

    };

    template <
        typename domain,
        typename range,
        typename bst_base,
        typename mem_manager,
        typename compare
        >
    inline void swap (
        hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>& a,
        hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>& b
    ) { a.swap(b); }

    template <
        typename domain,
        typename range,
        typename bst_base,
        typename mem_manager,
        typename compare
        >
    void deserialize (
        hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>& item,
        std::istream& in
    )
    {
        try
        {
            item.clear();
            unsigned long size;
            deserialize(size,in);
            domain d;
            range r;
            for (unsigned long i = 0; i < size; ++i)
            {
                deserialize(d,in);
                deserialize(r,in);
                item.add(d,r);
            }
        }
        catch (serialization_error e)
        {
            item.clear();
            throw serialization_error(e.info + "\n   while deserializing object of type hash_table_kernel_2");
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename bst_base,
        typename mem_manager,
        typename compare
        >
    hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::
    hash_table_kernel_2(
        unsigned long expnum
    ) :
        hash_size(0),
        current_bucket(0),
        at_start_(true)
    {

        num_of_buckets = 1;
        while (expnum != 0)
        {
            --expnum;
            num_of_buckets <<= 1;
        }
        mask = num_of_buckets-1;

        table = pool.allocate_array(num_of_buckets);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename bst_base,
        typename mem_manager,
        typename compare
        >
    void hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::
    clear(
    )
    {
        if (hash_size != 0)
        {
            hash_size = 0;
            for (unsigned long i = 0; i < num_of_buckets; ++i)
                table[i].clear();
        }
        // reset the enumerator
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename bst_base,
        typename mem_manager,
        typename compare
        >
    unsigned long hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::
    size(
    ) const
    {
        return hash_size;
    }
// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename bst_base,
        typename mem_manager,
        typename compare
        >
    unsigned long hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::
    count(
        const domain& item
    ) const
    {
        return table[hash(item)&mask].count(item);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename bst_base,
        typename mem_manager,
        typename compare
        >
    void hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::
    destroy(
        const domain& item
    )
    {
        table[hash(item)&mask].destroy(item);
        --hash_size;

        // reset the enumerator
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename bst_base,
        typename mem_manager,
        typename compare
        >
    void hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::
    add(
        domain& d,
        range& r
    )
    {
        table[hash(d)&mask].add(d,r);
        ++hash_size;

        // reset the enumerator
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename bst_base,
        typename mem_manager,
        typename compare
        >
    void hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::
    remove(
        const domain& d,
        domain& d_copy,
        range& r
    )
    {
        table[hash(d)&mask].remove(d,d_copy,r);
        --hash_size;

        // reset the enumerator
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename bst_base,
        typename mem_manager,
        typename compare
        >
    void hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::
    remove_any(
        domain& d,
        range& r
    )
    {
        unsigned long i = 0;
        while (table[i].size() == 0)
        {
            ++i;
        }
        table[i].remove_any(d,r);
        --hash_size;

        // reset the enumerator
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename bst_base,
        typename mem_manager,
        typename compare
        >
    const range* hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::
    operator[](
        const domain& d
    ) const
    {
        return table[hash(d)&mask][d];
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename bst_base,
        typename mem_manager,
        typename compare
        >
    range* hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::
    operator[](
        const domain& d
    )
    {
        return table[hash(d)&mask][d];
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename bst_base,
        typename mem_manager,
        typename compare
        >
    void hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::
    swap(
        hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>& item
    )
    {
        pool.swap(item.pool);
        exchange(mask,item.mask);
        exchange(hash_size,item.hash_size);
        exchange(num_of_buckets,item.num_of_buckets);
        exchange(table,item.table);
        exchange(current_bucket,item.current_bucket);
        exchange(at_start_,item.at_start_);
        exchange(comp,item.comp);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // enumerable function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename bst_base,
        typename mem_manager,
        typename compare
        >
    bool hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::
    at_start (
    ) const
    {
        return at_start_;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename bst_base,
        typename mem_manager,
        typename compare
        >
    void hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::
    reset (
    ) const
    {
        at_start_ = true;
        if (current_bucket != 0)
        {
            current_bucket->reset();
            current_bucket = 0;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename bst_base,
        typename mem_manager,
        typename compare
        >
    bool hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::
    current_element_valid (
    ) const
    {
        return (current_bucket != 0);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename bst_base,
        typename mem_manager,
        typename compare
        >
    const map_pair<domain,range>& hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::
    element (
    ) const
    {
        return current_bucket->element();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename bst_base,
        typename mem_manager,
        typename compare
        >
    map_pair<domain,range>& hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::
    element (
    )
    {
        return current_bucket->element();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename bst_base,
        typename mem_manager,
        typename compare
        >
    bool hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::
    move_next (
    ) const
    {
        if (at_start_)
        {
            at_start_ = false;
            // if the queue is empty then there is nothing to do
            if (hash_size == 0)
            {
                return false;
            }
            else
            {
                // find the first element in the hash table
                current_bucket = table;
                while (current_bucket->size() == 0)
                {
                    ++current_bucket;
                }

                current_bucket->move_next();

                return true;
            }
        }
        else
        {
            // if we have already enumerated every element
            if (current_bucket == 0)
            {
                return false;
            }
            else
            {
                if (current_bucket->move_next())
                {
                    // if there is another element in this current bucket then use that
                    return true;
                }
                else
                {
                    // find the next bucket
                    bst_base* end = table + num_of_buckets;
                    current_bucket->reset();

                    while (true)
                    {
                        ++current_bucket;
                        // if we ran out of buckets and didn't find anything
                        if (current_bucket == end)
                        {
                            current_bucket = 0;
                            return false;
                        }
                        if (current_bucket->size() > 0)
                        {
                            current_bucket->move_next();
                            return true;
                        }
                    }
                }
            }
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_HASH_TABLE_KERNEl_2_


dlib C++ Library - binned_vector_feature_image.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_BINNED_VECTOR_IMAGE_FEATUrES_Hh_
#define DLIB_BINNED_VECTOR_IMAGE_FEATUrES_Hh_

#include "../lsh/projection_hash.h"
#include "binned_vector_feature_image_abstract.h"
#include <vector>
#include "../algs.h"
#include "../matrix.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type_ = projection_hash
        >
    class binned_vector_feature_image : noncopyable
    {

    public:
        typedef feature_extractor feature_extractor_type;
        typedef hash_function_type_ hash_function_type;

        typedef std::vector<std::pair<unsigned int,double> > descriptor_type;

        binned_vector_feature_image (
        );

        void clear (
        );

        void set_hash (
            const hash_function_type& hash_
        );

        const hash_function_type& get_hash (
        ) const;

        void copy_configuration (
            const feature_extractor& item
        );

        void copy_configuration (
            const binned_vector_feature_image& item
        );

        template <
            typename image_type
            >
        inline void load (
            const image_type& img
        );

        inline unsigned long size (
        ) const;

        inline long nr (
        ) const;

        inline long nc (
        ) const;

        inline long get_num_dimensions (
        ) const;

        inline const descriptor_type& operator() (
            long row,
            long col
        ) const;

        inline const rectangle get_block_rect (
            long row,
            long col
        ) const;

        inline const point image_to_feat_space (
            const point& p
        ) const;

        inline const rectangle image_to_feat_space (
            const rectangle& rect
        ) const;

        inline const point feat_to_image_space (
            const point& p
        ) const;

        inline const rectangle feat_to_image_space (
            const rectangle& rect
        ) const;

        template <typename T>
        friend void serialize (
            const binned_vector_feature_image<T>& item,
            std::ostream& out
        );

        template <typename T>
        friend void deserialize (
            binned_vector_feature_image<T>& item,
            std::istream& in
        );

    private:

        array2d<descriptor_type> feats;
        feature_extractor fe;
        hash_function_type phash;
    };

// ----------------------------------------------------------------------------------------

    template <typename T>
    void serialize (
        const binned_vector_feature_image<T>& item,
        std::ostream& out
    )
    {
        int version = 1;
        serialize(version, out);
        serialize(item.feats, out);
        serialize(item.fe, out);
        serialize(item.phash, out);
    }

    template <typename T>
    void deserialize (
        binned_vector_feature_image<T>& item,
        std::istream& in
    )
    {
        int version = 0;
        deserialize(version, in);
        if (version != 1)
            throw dlib::serialization_error("Unexpected version found while deserializing dlib::binned_vector_feature_image");
        deserialize(item.feats, in);
        deserialize(item.fe, in);
        deserialize(item.phash, in);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                        binned_vector_feature_image member functions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type
        >
    binned_vector_feature_image<feature_extractor,hash_function_type>::
    binned_vector_feature_image (
    )
    {
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type
        >
    void binned_vector_feature_image<feature_extractor,hash_function_type>::
    clear (
    )
    {
        fe.clear();
        phash = hash_function_type();
        feats.clear();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type
        >
    void binned_vector_feature_image<feature_extractor,hash_function_type>::
    set_hash (
        const hash_function_type& hash_
    )
    {
        phash = hash_;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type
        >
    const hash_function_type& binned_vector_feature_image<feature_extractor,hash_function_type>::
    get_hash (
    ) const
    {
        return phash;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type
        >
    void binned_vector_feature_image<feature_extractor,hash_function_type>::
    copy_configuration (
        const feature_extractor& item
    )
    {
        fe.copy_configuration(item);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type
        >
    void binned_vector_feature_image<feature_extractor,hash_function_type>::
    copy_configuration (
        const binned_vector_feature_image& item
    )
    {
        fe.copy_configuration(item.fe);
        phash = item.phash;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type
        >
    template <
        typename image_type
        >
    void binned_vector_feature_image<feature_extractor,hash_function_type>::
    load (
        const image_type& img
    )
    {
        fe.load(img);

        if (fe.size() != 0)
        {
            feats.set_size(fe.nr(), fe.nc());
            for (long r = 0; r < feats.nr(); ++r)
            {
                for (long c = 0; c < feats.nc(); ++c)
                {
                    feats[r][c].clear();
                    feats[r][c].reserve(fe.get_num_dimensions()+1);
                    const typename feature_extractor::descriptor_type& des = fe(r,c);
                    const unsigned long idx = phash(des);
                    const unsigned long offset = idx*(fe.get_num_dimensions()+1);

                    for (long i = 0; i < des.size(); ++i)
                    {
                        feats[r][c].push_back(std::make_pair(offset + i, des(i)));
                    }
                    feats[r][c].push_back(std::make_pair(offset + des.size(), 1.0));
                }
            }
        }
        else
        {
            feats.set_size(0,0);
        }

        fe.unload();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type
        >
    unsigned long binned_vector_feature_image<feature_extractor,hash_function_type>::
    size (
    ) const
    {
        return feats.size();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type
        >
    long binned_vector_feature_image<feature_extractor,hash_function_type>::
    nr (
    ) const
    {
        return feats.nr();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type
        >
    long binned_vector_feature_image<feature_extractor,hash_function_type>::
    nc (
    ) const
    {
        return feats.nc();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type
        >
    long binned_vector_feature_image<feature_extractor,hash_function_type>::
    get_num_dimensions (
    ) const
    {
        return phash.num_hash_bins()*(fe.get_num_dimensions()+1);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type
        >
    const std::vector<std::pair<unsigned int,double> >& binned_vector_feature_image<feature_extractor,hash_function_type>::
    operator() (
        long row,
        long col
    ) const
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(0 <= row && row < nr() &&
                    0 <= col && col < nc(),
            "\t descriptor_type binned_vector_feature_image::operator(row,col)"
            << "\n\t Invalid inputs were given to this function"
            << "\n\t row:  " << row
            << "\n\t col:  " << col
            << "\n\t nr(): " << nr()
            << "\n\t nc(): " << nc()
            << "\n\t this: " << this
            );

        return feats[row][col];
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type
        >
    const rectangle binned_vector_feature_image<feature_extractor,hash_function_type>::
    get_block_rect (
        long row,
        long col
    ) const
    {
        return fe.get_block_rect(row,col);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type
        >
    const point binned_vector_feature_image<feature_extractor,hash_function_type>::
    image_to_feat_space (
        const point& p
    ) const
    {
        return fe.image_to_feat_space(p);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type
        >
    const rectangle binned_vector_feature_image<feature_extractor,hash_function_type>::
    image_to_feat_space (
        const rectangle& rect
    ) const
    {
        return fe.image_to_feat_space(rect);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type
        >
    const point binned_vector_feature_image<feature_extractor,hash_function_type>::
    feat_to_image_space (
        const point& p
    ) const
    {
        return fe.feat_to_image_space(p);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type
        >
    const rectangle binned_vector_feature_image<feature_extractor,hash_function_type>::
    feat_to_image_space (
        const rectangle& rect
    ) const
    {
        return fe.feat_to_image_space(rect);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_BINNED_VECTOR_IMAGE_FEATUrES_Hh_


dlib C++ Library - build_separable_poly_filters.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_BUILD_SEPARABLE_PoLY_FILTERS_Hh_
#define DLIB_BUILD_SEPARABLE_PoLY_FILTERS_Hh_

#include "../matrix.h"
#include "surf.h"
#include "../uintn.h"
#include <vector>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    typedef std::pair<matrix<double,0,1>, matrix<double,0,1> > separable_filter_type;
    typedef std::pair<matrix<int32,0,1>, matrix<int32,0,1> > separable_int32_filter_type;

// ----------------------------------------------------------------------------------------

    inline std::vector<std::vector<separable_filter_type> > build_separable_poly_filters (
        const long order,
        const long window_size
    )
    /*!
        requires
            - 1 <= order <= 6
            - window_size >= 3 && window_size is odd
        ensures
            - the "first" element is the row_filter, the second is the col_filter.
            - Some filters are not totally separable and that's why they are grouped
              into vectors of vectors.  The groups are all the parts of a partially
              separable filter.
    !*/
    {
        long num_filters = 6;
        switch (order)
        {
            case 1: num_filters = 3; break;
            case 2: num_filters = 6; break;
            case 3: num_filters = 10; break;
            case 4: num_filters = 15; break;
            case 5: num_filters = 21; break;
            case 6: num_filters = 28; break;
        }

        matrix<double> X(window_size*window_size,num_filters);
        matrix<double,0,1> G(window_size*window_size,1);
        const double sigma = window_size/4.0;

        long cnt = 0;
        for (double x = -window_size/2; x <= window_size/2; ++x)
        {
            for (double y = -window_size/2; y <= window_size/2; ++y)
            {
                X(cnt, 0) = 1;
                X(cnt, 1) = x;
                X(cnt, 2) = y;

                if (X.nc() > 5)
                {
                    X(cnt, 3) = x*x;
                    X(cnt, 4) = x*y;
                    X(cnt, 5) = y*y;
                }
                if (X.nc() > 9)
                {
                    X(cnt, 6) = x*x*x;
                    X(cnt, 7) = y*x*x;
                    X(cnt, 8) = y*y*x;
                    X(cnt, 9) = y*y*y;
                }
                if (X.nc() > 14)
                {
                    X(cnt, 10) = x*x*x*x;
                    X(cnt, 11) = y*x*x*x;
                    X(cnt, 12) = y*y*x*x;
                    X(cnt, 13) = y*y*y*x;
                    X(cnt, 14) = y*y*y*y;
                }
                if (X.nc() > 20)
                {
                    X(cnt, 15) = x*x*x*x*x;
                    X(cnt, 16) = y*x*x*x*x;
                    X(cnt, 17) = y*y*x*x*x;
                    X(cnt, 18) = y*y*y*x*x;
                    X(cnt, 19) = y*y*y*y*x;
                    X(cnt, 20) = y*y*y*y*y;
                }
                if (X.nc() > 27)
                {
                    X(cnt, 21) = x*x*x*x*x*x;
                    X(cnt, 22) = y*x*x*x*x*x;
                    X(cnt, 23) = y*y*x*x*x*x;
                    X(cnt, 24) = y*y*y*x*x*x;
                    X(cnt, 25) = y*y*y*y*x*x;
                    X(cnt, 26) = y*y*y*y*y*x;
                    X(cnt, 27) = y*y*y*y*y*y;
                }

                G(cnt) = std::sqrt(gaussian(x,y,sigma));
                ++cnt;
            }
        }

        X = diagm(G)*X;

        const matrix<double> S = inv(trans(X)*X)*trans(X)*diagm(G);

        matrix<double,0,1> row_filter, col_filter;

        matrix<double> u,v, temp;
        matrix<double,0,1> w;

        std::vector<std::vector<separable_filter_type> > results(num_filters);

        for (long r = 0; r < S.nr(); ++r)
        {
            temp = reshape(rowm(S,r), window_size, window_size);
            svd3(temp,u,w,v);
            const double thresh = max(w)*1e-8;
            for (long i = 0; i < w.size(); ++i)
            {
                if (w(i) > thresh)
                {
                    col_filter = std::sqrt(w(i))*colm(u,i);
                    row_filter = std::sqrt(w(i))*colm(v,i);
                    results[r].push_back(std::make_pair(row_filter, col_filter));
                }
            }
        }

        return results;
    }

// ----------------------------------------------------------------------------------------

    inline std::vector<std::vector<separable_int32_filter_type> > build_separable_int32_poly_filters (
        const long order,
        const long window_size,
        const double max_range = 300.0
    )
    /*!
        requires
            - 1 <= order <= 6
            - window_size >= 3 && window_size is odd
            - max_range > 1
        ensures
            - the "first" element is the row_filter, the second is the col_filter.
    !*/
    {
        const std::vector<std::vector<separable_filter_type> >& filters = build_separable_poly_filters(order, window_size);
        std::vector<std::vector<separable_int32_filter_type> > int_filters(filters.size());

        for (unsigned long i = 0; i < filters.size(); ++i)
        {

            double max_val = 0;
            for (unsigned long j = 0; j < filters[i].size(); ++j)
            {
                const separable_filter_type& filt = filters[i][j];
                max_val = std::max(max_val, max(abs(filt.first)));
                max_val = std::max(max_val, max(abs(filt.second)));
            }
            if (max_val == 0)
                max_val = 1;

            int_filters[i].resize(filters[i].size());
            for (unsigned long j = 0; j < filters[i].size(); ++j)
            {
                const separable_filter_type& filt = filters[i][j];
                int_filters[i][j].first  = matrix_cast<int32>(round(filt.first*max_range/max_val));
                int_filters[i][j].second = matrix_cast<int32>(round(filt.second*max_range/max_val));
            }
        }

        return int_filters;
    }

}

// ----------------------------------------------------------------------------------------

#endif // DLIB_BUILD_SEPARABLE_PoLY_FILTERS_Hh_


dlib C++ Library - fine_hog_image.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_FINE_HOG_IMaGE_Hh_
#define DLIB_FINE_HOG_IMaGE_Hh_

#include "fine_hog_image_abstract.h"
#include "../array2d.h"
#include "../matrix.h"
#include "hog.h"

namespace dlib
{
    template <
        unsigned long cell_size_,
        unsigned long block_size_,
        unsigned long pixel_stride_,
        unsigned char num_orientation_bins_,
        int           gradient_type_
        >
    class fine_hog_image : noncopyable
    {
        COMPILE_TIME_ASSERT(cell_size_ > 1);
        COMPILE_TIME_ASSERT(block_size_ > 0);
        COMPILE_TIME_ASSERT(pixel_stride_ > 0);
        COMPILE_TIME_ASSERT(num_orientation_bins_ > 0);

        COMPILE_TIME_ASSERT( gradient_type_ == hog_signed_gradient ||
                             gradient_type_ == hog_unsigned_gradient);

    public:

        const static unsigned long cell_size = cell_size_;
        const static unsigned long block_size = block_size_;
        const static unsigned long pixel_stride = pixel_stride_;
        const static unsigned long num_orientation_bins = num_orientation_bins_;
        const static int           gradient_type = gradient_type_;

        const static long min_size = cell_size*block_size+2;

        typedef matrix<double, block_size*block_size*num_orientation_bins, 1> descriptor_type;

        fine_hog_image (
        ) :
            num_block_rows(0),
            num_block_cols(0)
        {}

        void clear (
        )
        {
            num_block_rows = 0;
            num_block_cols = 0;
            hist_counts.clear();
        }

        void copy_configuration (
            const fine_hog_image&
        ){}

        template <
            typename image_type
            >
        inline void load (
            const image_type& img
        )
        {
            COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<image_type>::pixel_type>::has_alpha == false );
            load_impl(mat(img));
        }

        inline void unload(
        ) { clear(); }

        inline unsigned long size (
        ) const { return static_cast<unsigned long>(nr()*nc()); }

        inline long nr (
        ) const { return num_block_rows; }

        inline long nc (
        ) const { return num_block_cols; }

        long get_num_dimensions (
        ) const
        {
            return block_size*block_size*num_orientation_bins;
        }

        inline const descriptor_type& operator() (
            long row,
            long col
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT( 0 <= row && row < nr() &&
                         0 <= col && col < nc(),
                "\t descriptor_type fine_hog_image::operator()()"
                << "\n\t invalid row or col argument"
                << "\n\t row:  " << row
                << "\n\t col:  " << col
                << "\n\t nr(): " << nr()
                << "\n\t nc(): " << nc()
                << "\n\t this: " << this
                );

            row *= pixel_stride;
            col *= pixel_stride;

            des = 0;
            unsigned long off = 0;
            for (unsigned long r = 0; r < block_size; ++r)
            {
                for (unsigned long c = 0; c < block_size; ++c)
                {
                    for (unsigned long rr = 0; rr < cell_size; ++rr)
                    {
                        for (unsigned long cc = 0; cc < cell_size; ++cc)
                        {
                            const histogram_count& hist = hist_counts[row + r*cell_size + rr][col + c*cell_size + cc];
                            des(off + hist.quantized_angle_lower) += hist.lower_strength;
                            des(off + hist.quantized_angle_upper) += hist.upper_strength;
                        }
                    }

                    off += num_orientation_bins;
                }
            }

            des /= length(des) + 1e-8;

            return des;
        }

        const rectangle get_block_rect (
            long row,
            long col
        ) const
        {
            row *= pixel_stride;
            col *= pixel_stride;

            // do this to account for the 1 pixel padding we use all around the image
            ++row;
            ++col;

            return rectangle(col, row, col+cell_size*block_size-1, row+cell_size*block_size-1);
        }

        const point image_to_feat_space (
            const point& p
        ) const
        {
            const long border_size = 1 + cell_size*block_size/2;
            return (p-point(border_size,border_size))/(long)pixel_stride;
        }

        const rectangle image_to_feat_space (
            const rectangle& rect
        ) const
        {
            return rectangle(image_to_feat_space(rect.tl_corner()), image_to_feat_space(rect.br_corner()));
        }

        const point feat_to_image_space (
            const point& p
        ) const
        {
            const long border_size = 1 + cell_size*block_size/2;
            return p*(long)pixel_stride + point(border_size,border_size);
        }

        const rectangle feat_to_image_space (
            const rectangle& rect
        ) const
        {
            return rectangle(feat_to_image_space(rect.tl_corner()), feat_to_image_space(rect.br_corner()));
        }

        // these _PRIVATE_ functions are only here as a workaround for a bug in visual studio 2005.
        void _PRIVATE_serialize (std::ostream& out) const
        {
            // serialize hist_counts
            serialize(hist_counts.nc(),out);
            serialize(hist_counts.nr(),out);
            hist_counts.reset();
            while (hist_counts.move_next())
                hist_counts.element().serialize(out);
            hist_counts.reset();

            serialize(num_block_rows, out);
            serialize(num_block_cols, out);
        }

        void _PRIVATE_deserialize (std::istream& in )
        {
            // deserialize item.hist_counts
            long nc, nr;
            deserialize(nc,in);
            deserialize(nr,in);
            hist_counts.set_size(nr,nc);
            while (hist_counts.move_next())
                hist_counts.element().deserialize(in);
            hist_counts.reset();

            deserialize(num_block_rows, in);
            deserialize(num_block_cols, in);
        }

    private:

        template <
            typename image_type
            >
        void load_impl (
            const image_type& img
        )
        {
            // Note that we keep a border of 1 pixel all around the image so that we don't have
            // to worry about running outside the image when computing the horizontal and vertical
            // gradients.

            // check if the window is just too small
            if (img.nr() < min_size || img.nc() < min_size)
            {
                // If the image is smaller than our windows then there aren't any descriptors at all!
                num_block_rows = 0;
                num_block_cols = 0;
                hist_counts.clear();
                return;
            }

            hist_counts.set_size(img.nr()-2, img.nc()-2);

            for (long r = 0; r < hist_counts.nr(); ++r)
            {
                for (long c = 0; c < hist_counts.nc(); ++c)
                {
                    unsigned long left;
                    unsigned long right;
                    unsigned long top;
                    unsigned long bottom;

                    assign_pixel(left,   img(r+1,c));
                    assign_pixel(right,  img(r+1,c+2));
                    assign_pixel(top,    img(r  ,c+1));
                    assign_pixel(bottom, img(r+2,c+1));

                    double grad_x = (long)right-(long)left;
                    double grad_y = (long)top-(long)bottom;

                    // obtain the angle of the gradient.  Make sure it is scaled between 0 and 1.
                    double angle = std::max(0.0, std::atan2(grad_y, grad_x)/pi + 1)/2;

                    if (gradient_type == hog_unsigned_gradient)
                    {
                        angle *= 2;
                        if (angle >= 1)
                            angle -= 1;
                    }

                    // now scale angle to between 0 and num_orientation_bins
                    angle *= num_orientation_bins;

                    const double strength = std::sqrt(grad_y*grad_y + grad_x*grad_x);

                    unsigned char quantized_angle_lower = static_cast<unsigned char>(std::floor(angle));
                    unsigned char quantized_angle_upper = static_cast<unsigned char>(std::ceil(angle));

                    quantized_angle_lower %= num_orientation_bins;
                    quantized_angle_upper %= num_orientation_bins;

                    const double angle_split = (angle-std::floor(angle));
                    const double upper_strength = angle_split*strength;
                    const double lower_strength = (1-angle_split)*strength;

                    // Stick into gradient counts.  Note that we linearly interpolate between neighboring
                    // histogram buckets.
                    hist_counts[r][c].quantized_angle_lower = quantized_angle_lower;
                    hist_counts[r][c].quantized_angle_upper = quantized_angle_upper;
                    hist_counts[r][c].lower_strength = lower_strength;
                    hist_counts[r][c].upper_strength = upper_strength;

                }
            }

            // Now figure out how many feature extraction blocks we should have.
            num_block_rows = (hist_counts.nr() - block_size*cell_size + 1)/(long)pixel_stride;
            num_block_cols = (hist_counts.nc() - block_size*cell_size + 1)/(long)pixel_stride;

        }

        struct histogram_count
        {
            unsigned char quantized_angle_lower;
            unsigned char quantized_angle_upper;
            float lower_strength;
            float upper_strength;

            void serialize(std::ostream& out) const
            {
                dlib::serialize(quantized_angle_lower, out);
                dlib::serialize(quantized_angle_upper, out);
                dlib::serialize(lower_strength, out);
                dlib::serialize(upper_strength, out);
            }
            void deserialize(std::istream& in)
            {
                dlib::deserialize(quantized_angle_lower, in);
                dlib::deserialize(quantized_angle_upper, in);
                dlib::deserialize(lower_strength, in);
                dlib::deserialize(upper_strength, in);
            }
        };

        array2d<histogram_count> hist_counts;

        mutable descriptor_type des;

        long num_block_rows;
        long num_block_cols;

    };

// ----------------------------------------------------------------------------------------

    template <
        unsigned long T1,
        unsigned long T2,
        unsigned long T3,
        unsigned char T4,
        int           T5
        >
    void serialize (
        const fine_hog_image<T1,T2,T3,T4,T5>& item,
        std::ostream& out
    )
    {
        item._PRIVATE_serialize(out);
    }

    template <
        unsigned long T1,
        unsigned long T2,
        unsigned long T3,
        unsigned char T4,
        int           T5
        >
    void deserialize (
        fine_hog_image<T1,T2,T3,T4,T5>& item,
        std::istream& in
    )
    {
        item._PRIVATE_deserialize(in);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_FINE_HOG_IMaGE_Hh_


dlib C++ Library - hashed_feature_image.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_HASHED_IMAGE_FEATUrES_Hh_
#define DLIB_HASHED_IMAGE_FEATUrES_Hh_

#include "../lsh/projection_hash.h"
#include "hashed_feature_image_abstract.h"
#include <vector>
#include "../algs.h"
#include "../matrix.h"
#include "../statistics.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type_ = projection_hash
        >
    class hashed_feature_image : noncopyable
    {

    public:
        typedef feature_extractor feature_extractor_type;
        typedef hash_function_type_ hash_function_type;

        typedef std::vector<std::pair<unsigned int,double> > descriptor_type;

        hashed_feature_image (
        );

        void clear (
        );

        void set_hash (
            const hash_function_type& hash_
        );

        const hash_function_type& get_hash (
        ) const;

        void copy_configuration (
            const feature_extractor& item
        );

        void copy_configuration (
            const hashed_feature_image& item
        );

        template <
            typename image_type
            >
        inline void load (
            const image_type& img
        );

        inline unsigned long size (
        ) const;

        inline long nr (
        ) const;

        inline long nc (
        ) const;

        inline long get_num_dimensions (
        ) const;

        void use_relative_feature_weights (
        );

        void use_uniform_feature_weights (
        );

        bool uses_uniform_feature_weights (
        ) const;

        inline const descriptor_type& operator() (
            long row,
            long col
        ) const;

        inline const rectangle get_block_rect (
            long row,
            long col
        ) const;

        inline const point image_to_feat_space (
            const point& p
        ) const;

        inline const rectangle image_to_feat_space (
            const rectangle& rect
        ) const;

        inline const point feat_to_image_space (
            const point& p
        ) const;

        inline const rectangle feat_to_image_space (
            const rectangle& rect
        ) const;

        template <typename T>
        friend void serialize (
            const hashed_feature_image<T>& item,
            std::ostream& out
        );

        template <typename T>
        friend void deserialize (
            hashed_feature_image<T>& item,
            std::istream& in
        );

    private:

        array2d<unsigned long> feats;
        feature_extractor fe;
        hash_function_type phash;
        std::vector<float> feat_counts;
        bool uniform_feature_weights;

        // This is a transient variable.  It is just here so it doesn't have to be
        // reallocated over and over inside operator()
        mutable descriptor_type hash_feats;

    };

// ----------------------------------------------------------------------------------------

    template <typename T>
    void serialize (
        const hashed_feature_image<T>& item,
        std::ostream& out
    )
    {
        int version = 1;
        serialize(version, out);
        serialize(item.feats, out);
        serialize(item.fe, out);
        serialize(item.phash, out);
        serialize(item.feat_counts, out);
        serialize(item.uniform_feature_weights, out);
    }

    template <typename T>
    void deserialize (
        hashed_feature_image<T>& item,
        std::istream& in
    )
    {
        int version = 0;
        deserialize(version, in);
        if (version != 1)
            throw serialization_error("Unexpected version found while deserializing a dlib::hashed_feature_image object.");

        deserialize(item.feats, in);
        deserialize(item.fe, in);
        deserialize(item.phash, in);
        deserialize(item.feat_counts, in);
        deserialize(item.uniform_feature_weights, in);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                        hashed_feature_image member functions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type
        >
    hashed_feature_image<feature_extractor,hash_function_type>::
    hashed_feature_image (
    )
    {
        clear();
        hash_feats.resize(1);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type
        >
    void hashed_feature_image<feature_extractor,hash_function_type>::
    clear (
    )
    {
        fe.clear();
        phash = hash_function_type();
        feats.clear();
        feat_counts.clear();
        uniform_feature_weights = false;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type
        >
    void hashed_feature_image<feature_extractor,hash_function_type>::
    set_hash (
        const hash_function_type& hash_
    )
    {
        phash = hash_;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type
        >
    const hash_function_type& hashed_feature_image<feature_extractor,hash_function_type>::
    get_hash (
    ) const
    {
        return phash;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type
        >
    void hashed_feature_image<feature_extractor,hash_function_type>::
    copy_configuration (
        const feature_extractor& item
    )
    {
        fe.copy_configuration(item);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type
        >
    void hashed_feature_image<feature_extractor,hash_function_type>::
    copy_configuration (
        const hashed_feature_image& item
    )
    {
        fe.copy_configuration(item.fe);
        phash = item.phash;
        uniform_feature_weights = item.uniform_feature_weights;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type
        >
    template <
        typename image_type
        >
    void hashed_feature_image<feature_extractor,hash_function_type>::
    load (
        const image_type& img
    )
    {
        fe.load(img);

        if (fe.size() != 0)
        {
            feats.set_size(fe.nr(), fe.nc());
            feat_counts.assign(phash.num_hash_bins(),1);
            if (uniform_feature_weights)
            {
                for (long r = 0; r < feats.nr(); ++r)
                {
                    for (long c = 0; c < feats.nc(); ++c)
                    {
                        feats[r][c] = phash(fe(r,c));
                    }
                }
            }
            else
            {
                for (long r = 0; r < feats.nr(); ++r)
                {
                    for (long c = 0; c < feats.nc(); ++c)
                    {
                        feats[r][c] = phash(fe(r,c));
                        feat_counts[feats[r][c]]++;
                    }
                }
            }
        }
        else
        {
            feats.set_size(0,0);
        }

        if (!uniform_feature_weights)
        {
            // use the inverse frequency as the scale for each feature.  We also scale
            // these counts so that they are invariant to the size of the image (we scale
            // them so they all look like they come from a 500x400 images).
            const double scale = image_size(img)/(500.0*400.0);
            for (unsigned long i = 0; i < feat_counts.size(); ++i)
            {
                feat_counts[i] = scale/feat_counts[i];
            }
        }

        fe.unload();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type
        >
    unsigned long hashed_feature_image<feature_extractor,hash_function_type>::
    size (
    ) const
    {
        return feats.size();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type
        >
    long hashed_feature_image<feature_extractor,hash_function_type>::
    nr (
    ) const
    {
        return feats.nr();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type
        >
    long hashed_feature_image<feature_extractor,hash_function_type>::
    nc (
    ) const
    {
        return feats.nc();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type
        >
    long hashed_feature_image<feature_extractor,hash_function_type>::
    get_num_dimensions (
    ) const
    {
        return phash.num_hash_bins();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type
        >
    void hashed_feature_image<feature_extractor,hash_function_type>::
    use_relative_feature_weights (
    )
    {
        uniform_feature_weights = false;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type
        >
    void hashed_feature_image<feature_extractor,hash_function_type>::
    use_uniform_feature_weights (
    )
    {
        uniform_feature_weights = true;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type
        >
    bool hashed_feature_image<feature_extractor,hash_function_type>::
    uses_uniform_feature_weights (
    ) const
    {
        return uniform_feature_weights;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type
        >
    const std::vector<std::pair<unsigned int,double> >& hashed_feature_image<feature_extractor,hash_function_type>::
    operator() (
        long row,
        long col
    ) const
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(0 <= row && row < nr() &&
                    0 <= col && col < nc(),
            "\t descriptor_type hashed_feature_image::operator(row,col)"
            << "\n\t Invalid inputs were given to this function"
            << "\n\t row:  " << row
            << "\n\t col:  " << col
            << "\n\t nr(): " << nr()
            << "\n\t nc(): " << nc()
            << "\n\t this: " << this
            );

        hash_feats[0] = std::make_pair(feats[row][col],feat_counts[feats[row][col]]);
        return hash_feats;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type
        >
    const rectangle hashed_feature_image<feature_extractor,hash_function_type>::
    get_block_rect (
        long row,
        long col
    ) const
    {
        return fe.get_block_rect(row,col);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type
        >
    const point hashed_feature_image<feature_extractor,hash_function_type>::
    image_to_feat_space (
        const point& p
    ) const
    {
        return fe.image_to_feat_space(p);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type
        >
    const rectangle hashed_feature_image<feature_extractor,hash_function_type>::
    image_to_feat_space (
        const rectangle& rect
    ) const
    {
        return fe.image_to_feat_space(rect);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type
        >
    const point hashed_feature_image<feature_extractor,hash_function_type>::
    feat_to_image_space (
        const point& p
    ) const
    {
        return fe.feat_to_image_space(p);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor,
        typename hash_function_type
        >
    const rectangle hashed_feature_image<feature_extractor,hash_function_type>::
    feat_to_image_space (
        const rectangle& rect
    ) const
    {
        return fe.feat_to_image_space(rect);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_HASHED_IMAGE_FEATUrES_Hh_


dlib C++ Library - hessian_pyramid.h

// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_HESSIAN_PYRAMId_Hh_
#define DLIB_HESSIAN_PYRAMId_Hh_

#include "hessian_pyramid_abstract.h"
#include "../algs.h"
#include "../image_transforms/integral_image.h"
#include "../array.h"
#include "../array2d.h"
#include "../noncopyable.h"
#include "../matrix.h"
#include "../stl_checked.h"
#include <algorithm>
#include <vector>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    struct interest_point
    {
        interest_point() : scale(0), score(0), laplacian(0) {}

        dlib::vector<double,2> center;
        double scale;
        double score;
        double laplacian;

        bool operator < (const interest_point& p) const { return score < p.score; }
    };

// ----------------------------------------------------------------------------------------

    inline void serialize(
        const interest_point& item,
        std::ostream& out
    )
    {
        try
        {
            serialize(item.center,out);
            serialize(item.scale,out);
            serialize(item.score,out);
            serialize(item.laplacian,out);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while serializing object of type interest_point");
        }
    }

// ----------------------------------------------------------------------------------------

    inline void deserialize(
        interest_point& item,
        std::istream& in
    )
    {
        try
        {
            deserialize(item.center,in);
            deserialize(item.scale,in);
            deserialize(item.score,in);
            deserialize(item.laplacian,in);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while deserializing object of type interest_point");
        }
    }

// ----------------------------------------------------------------------------------------

    class hessian_pyramid : noncopyable
    {
    public:
        hessian_pyramid()
        {
            num_octaves = 0;
            num_intervals = 0;
            initial_step_size = 0;
        }

        template <typename integral_image_type>
        void build_pyramid (
            const integral_image_type& img,
            long num_octaves,
            long num_intervals,
            long initial_step_size
        )
        {
            DLIB_ASSERT(num_octaves > 0 && num_intervals > 0 && initial_step_size > 0,
                "\tvoid build_pyramid()"
                << "\n\tAll arguments to this function must be > 0"
                << "\n\t this:              " << this
                << "\n\t num_octaves:       " << num_octaves
                << "\n\t num_intervals:     " << num_intervals
                << "\n\t initial_step_size: " << initial_step_size
            );

            this->num_octaves = num_octaves;
            this->num_intervals = num_intervals;
            this->initial_step_size = initial_step_size;

            // allocate space for the pyramid
            pyramid.resize(num_octaves*num_intervals);
            for (long o = 0; o < num_octaves; ++o)
            {
                const long step_size = get_step_size(o);
                for (long i = 0; i < num_intervals; ++i)
                {
                    pyramid[num_intervals*o + i].set_size(img.nr()/step_size, img.nc()/step_size);
                }
            }

            // now fill out the pyramid with data
            for (long o = 0; o < num_octaves; ++o)
            {
                const long step_size = get_step_size(o);

                for (long i = 0; i < num_intervals; ++i)
                {
                    const long border_size = get_border_size(i)*step_size;
                    const long lobe_size = static_cast<long>(std::pow(2.0, o+1.0)+0.5)*(i+1) + 1;
                    const double area_inv = 1.0/std::pow(3.0*lobe_size, 2.0);

                    const long lobe_offset = lobe_size/2+1;
                    const point tl(-lobe_offset,-lobe_offset);
                    const point tr(lobe_offset,-lobe_offset);
                    const point bl(-lobe_offset,lobe_offset);
                    const point br(lobe_offset,lobe_offset);

                    for (long r = border_size; r < img.nr() - border_size; r += step_size)
                    {
                        for (long c = border_size; c < img.nc() - border_size; c += step_size)
                        {
                            const point p(c,r);

                            double Dxx = img.get_sum_of_area(centered_rect(p, lobe_size*3, 2*lobe_size-1)) -
                                         img.get_sum_of_area(centered_rect(p, lobe_size,   2*lobe_size-1))*3.0;

                            double Dyy = img.get_sum_of_area(centered_rect(p, 2*lobe_size-1, lobe_size*3)) -
                                         img.get_sum_of_area(centered_rect(p, 2*lobe_size-1, lobe_size))*3.0;

                            double Dxy = img.get_sum_of_area(centered_rect(p+bl, lobe_size, lobe_size)) +
                                         img.get_sum_of_area(centered_rect(p+tr, lobe_size, lobe_size)) -
                                         img.get_sum_of_area(centered_rect(p+tl, lobe_size, lobe_size)) -
                                         img.get_sum_of_area(centered_rect(p+br, lobe_size, lobe_size));

                            // now we normalize the filter responses
                            Dxx *= area_inv;
                            Dyy *= area_inv;
                            Dxy *= area_inv;

                            double sign_of_laplacian = +1;
                            if (Dxx + Dyy < 0)
                                sign_of_laplacian = -1;

                            double determinant = Dxx*Dyy - 0.81*Dxy*Dxy;

                            // If the determinant is negative then just blank it out by setting
                            // it to zero.
                            if (determinant < 0)
                                determinant = 0;

                            // Save the determinant of the Hessian into our image pyramid.  Also
                            // pack the laplacian sign into the value so we can get it out later.
                            pyramid[o*num_intervals + i][r/step_size][c/step_size] = sign_of_laplacian*determinant;

                        }
                    }

                }
            }
        }

        long get_border_size (
            long interval
        ) const
        {
            DLIB_ASSERT(0 <= interval && interval < intervals(),
                "\tlong get_border_size(interval)"
                << "\n\tInvalid interval value"
                << "\n\t this:   " << this
                << "\n\t interval: " << interval
            );

            const double lobe_size = 2.0*(interval+1) + 1;
            const double filter_size = 3*lobe_size;

            const long bs = static_cast<long>(std::ceil(filter_size/2.0));
            return bs;
        }

        long get_step_size (
            long octave
        ) const
        {
            DLIB_ASSERT(0 <= octave && octave < octaves(),
                "\tlong get_step_size(octave)"
                << "\n\tInvalid octave value"
                << "\n\t this:   " << this
                << "\n\t octave: " << octave
            );

            return initial_step_size*static_cast<long>(std::pow(2.0, (double)octave)+0.5);
        }

        long nr (
            long octave
        ) const
        {
            DLIB_ASSERT(0 <= octave && octave < octaves(),
                "\tlong nr(octave)"
                << "\n\tInvalid octave value"
                << "\n\t this:   " << this
                << "\n\t octave: " << octave
            );

            return pyramid[num_intervals*octave].nr();
        }

        long nc (
            long octave
        ) const
        {
            DLIB_ASSERT(0 <= octave && octave < octaves(),
                "\tlong nc(octave)"
                << "\n\tInvalid octave value"
                << "\n\t this:   " << this
                << "\n\t octave: " << octave
            );

            return pyramid[num_intervals*octave].nc();
        }

        double get_value (
            long octave,
            long interval,
            long r,
            long c
        ) const
        {
            DLIB_ASSERT(0 <= octave && octave < octaves() &&
                        0 <= interval && interval < intervals() &&
                        get_border_size(interval) <= r && r < nr(octave)-get_border_size(interval) &&
                        get_border_size(interval) <= c && c < nc(octave)-get_border_size(interval),
                "\tdouble get_value(octave, interval, r, c)"
                << "\n\tInvalid inputs to this function"
                << "\n\t this:      " << this
                << "\n\t octave:    " << octave
                << "\n\t interval:  " << interval
                << "\n\t octaves:   " << octaves()
                << "\n\t intervals: " << intervals()
                << "\n\t r:         " << r
                << "\n\t c:         " << c
                << "\n\t nr(octave): " << nr(octave)
                << "\n\t nc(octave): " << nc(octave)
                << "\n\t get_border_size(interval): " << get_border_size(interval)
            );

            return std::abs(pyramid[num_intervals*octave + interval][r][c]);
        }

        double get_laplacian (
            long octave,
            long interval,
            long r,
            long c
        ) const
        {
            DLIB_ASSERT(0 <= octave && octave < octaves() &&
                        0 <= interval && interval < intervals() &&
                        get_border_size(interval) <= r && r < nr(octave)-get_border_size(interval) &&
                        get_border_size(interval) <= c && c < nc(octave)-get_border_size(interval),
                "\tdouble get_laplacian(octave, interval, r, c)"
                << "\n\tInvalid inputs to this function"
                << "\n\t this:      " << this
                << "\n\t octave:    " << octave
                << "\n\t interval:  " << interval
                << "\n\t octaves:   " << octaves()
                << "\n\t intervals: " << intervals()
                << "\n\t r:         " << r
                << "\n\t c:         " << c
                << "\n\t nr(octave): " << nr(octave)
                << "\n\t nc(octave): " << nc(octave)
                << "\n\t get_border_size(interval): " << get_border_size(interval)
            );

            // return the sign of the laplacian
            if (pyramid[num_intervals*octave + interval][r][c] > 0)
                return +1;
            else
                return -1;
        }

        long octaves (
        ) const { return num_octaves; }

        long intervals (
        ) const { return num_intervals; }

    private:

        long num_octaves;
        long num_intervals;
        long initial_step_size;

        typedef array2d<double> image_type;
        typedef array<image_type> pyramid_type;

        pyramid_type pyramid;
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    namespace hessian_pyramid_helpers
    {
        inline bool is_maximum_in_region(
            const hessian_pyramid& pyr,
            long o,
            long i,
            long r,
            long c
        )
        {
            // First check if this point is near the edge of the octave
            // If it is then we say it isn't a maximum as these points are
            // not as reliable.
            if (i <= 0 || i+1 >= pyr.intervals())
            {
                return false;
            }

            const double val = pyr.get_value(o,i,r,c);

            // now check if there are any bigger values around this guy
            for (long ii = i-1; ii <= i+1; ++ii)
            {
                for (long rr = r-1; rr <= r+1; ++rr)
                {
                    for (long cc = c-1; cc <= c+1; ++cc)
                    {
                        if (pyr.get_value(o,ii,rr,cc) > val)
                            return false;
                    }
                }
            }

            return true;
        }

    // ------------------------------------------------------------------------------------

        inline const matrix<double,3,1> get_hessian_gradient (
            const hessian_pyramid& pyr,
            long o,
            long i,
            long r,
            long c
        )
        {
            matrix<double,3,1> grad;
            grad(0) = (pyr.get_value(o,i,r,c+1) - pyr.get_value(o,i,r,c-1))/2.0;
            grad(1) = (pyr.get_value(o,i,r+1,c) - pyr.get_value(o,i,r-1,c))/2.0;
            grad(2) = (pyr.get_value(o,i+1,r,c) - pyr.get_value(o,i-1,r,c))/2.0;
            return grad;
        }

    // ------------------------------------------------------------------------------------

        inline const matrix<double,3,3> get_hessian_hessian (
            const hessian_pyramid& pyr,
            long o,
            long i,
            long r,
            long c
        )
        {
            matrix<double,3,3> hess;
            const double val = pyr.get_value(o,i,r,c);

            double Dxx = (pyr.get_value(o,i,r,c+1) + pyr.get_value(o,i,r,c-1)) - 2*val;
            double Dyy = (pyr.get_value(o,i,r+1,c) + pyr.get_value(o,i,r-1,c)) - 2*val;
            double Dss = (pyr.get_value(o,i+1,r,c) + pyr.get_value(o,i-1,r,c)) - 2*val;

            double Dxy = (pyr.get_value(o,i,r+1,c+1) + pyr.get_value(o,i,r-1,c-1) -
                          pyr.get_value(o,i,r-1,c+1) - pyr.get_value(o,i,r+1,c-1)) / 4.0;

            double Dxs = (pyr.get_value(o,i+1,r,c+1) + pyr.get_value(o,i-1,r,c-1) -
                          pyr.get_value(o,i-1,r,c+1) - pyr.get_value(o,i+1,r,c-1)) / 4.0;

            double Dys = (pyr.get_value(o,i+1,r+1,c) + pyr.get_value(o,i-1,r-1,c) -
                          pyr.get_value(o,i-1,r+1,c) - pyr.get_value(o,i+1,r-1,c)) / 4.0;

            hess = Dxx, Dxy, Dxs,
            Dxy, Dyy, Dys,
            Dxs, Dys, Dss;

            return hess;
        }

    // ------------------------------------------------------------------------------------

        inline const interest_point interpolate_point (
            const hessian_pyramid& pyr,
            long o,
            long i,
            long r,
            long c
        )
        {
            dlib::vector<double,2> p(c,r);

            dlib::vector<double,3> start_point(c,r,i);
            dlib::vector<double,3> interpolated_point = -inv(get_hessian_hessian(pyr,o,i,r,c))*get_hessian_gradient(pyr,o,i,r,c);

            //cout << "inter: " <<  trans(interpolated_point);

            interest_point temp;
            if (max(abs(interpolated_point)) < 0.5)
            {
                p = (start_point+interpolated_point)*pyr.get_step_size(o);
                const double lobe_size = std::pow(2.0, o+1.0)*(i+interpolated_point.z()+1) + 1;
                const double filter_size = 3*lobe_size;
                const double scale = 1.2/9.0 * filter_size;

                temp.center = p;
                temp.scale = scale;
                temp.score = pyr.get_value(o,i,r,c);
                temp.laplacian = pyr.get_laplacian(o,i,r,c);
            }
            else
            {
                // this indicates to the caller that no interest point was found.
                temp.score = -1;
            }

            return temp;
        }

    }

// ----------------------------------------------------------------------------------------

    template <typename Alloc>
    void get_interest_points (
        const hessian_pyramid& pyr,
        double threshold,
        std::vector<interest_point,Alloc>& result_points
    )
    {
        DLIB_ASSERT(threshold >= 0,
            "\tvoid get_interest_points()"
            << "\n\t Invalid arguments to this function"
            << "\n\t threshold: " << threshold
        );
        using namespace std;
        using namespace hessian_pyramid_helpers;

        result_points.clear();

        for (long o = 0; o < pyr.octaves(); ++o)
        {
            const long nr = pyr.nr(o);
            const long nc = pyr.nc(o);

            // do non-maximum suppression on all the intervals in the current octave and
            // accumulate the results in result_points
            for (long i = 1; i < pyr.intervals()-1;  i += 1)
            {
                const long border_size = pyr.get_border_size(i+1);
                for (long r = border_size+1; r < nr - border_size-1; r += 1)
                {
                    for (long c = border_size+1; c < nc - border_size-1; c += 1)
                    {
                        double max_val = pyr.get_value(o,i,r,c);
                        long max_i = i;
                        long max_r = r;
                        long max_c = c;

                        // If the max point we found is really a maximum in its own region and
                        // is big enough then add it to the results.
                        if (max_val >= threshold && is_maximum_in_region(pyr, o, max_i, max_r, max_c))
                        {
                            //cout << max_val << endl;
                            interest_point sp = interpolate_point (pyr, o, max_i, max_r, max_c);
                            if (sp.score >= threshold)
                            {
                                result_points.push_back(sp);
                            }
                        }

                    }
                }
            }
        }

    }

// ----------------------------------------------------------------------------------------

    template <typename Alloc>
    void get_interest_points (
        const hessian_pyramid& pyr,
        double threshold,
        std_vector_c<interest_point,Alloc>& result_points
    )
    /*!
        This function is just an overload that automatically casts std_vector_c objects
        into std::vector objects.  (Usually this is automatic but the template argument
        there messes up the conversion so we have to do it explicitly)
    !*/
    {
        std::vector<interest_point,Alloc>& v = result_points;
        get_interest_points(pyr, threshold, v);
    }

// ----------------------------------------------------------------------------------------

}

#endif  // DLIB_HESSIAN_PYRAMId_Hh_


dlib C++ Library - hog.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_HoG_Hh_
#define DLIB_HoG_Hh_

#include "hog_abstract.h"
#include "../algs.h"
#include "../matrix.h"
#include "../array2d.h"
#include "../geometry.h"
#include <cmath>

namespace dlib
{
    enum
    {
        hog_no_interpolation,
        hog_angle_interpolation,
        hog_full_interpolation,
        hog_signed_gradient,
        hog_unsigned_gradient
    };

    template <
        unsigned long cell_size_,
        unsigned long block_size_,
        unsigned long cell_stride_,
        unsigned long num_orientation_bins_,
        int           gradient_type_,
        int           interpolation_type_
        >
    class hog_image : noncopyable
    {
        COMPILE_TIME_ASSERT(cell_size_ > 1);
        COMPILE_TIME_ASSERT(block_size_ > 0);
        COMPILE_TIME_ASSERT(cell_stride_ > 0);
        COMPILE_TIME_ASSERT(num_orientation_bins_ > 0);

        COMPILE_TIME_ASSERT( gradient_type_ == hog_signed_gradient ||
                             gradient_type_ == hog_unsigned_gradient);

        COMPILE_TIME_ASSERT( interpolation_type_ == hog_no_interpolation ||
                             interpolation_type_ == hog_angle_interpolation ||
                             interpolation_type_ == hog_full_interpolation );

    public:

        const static unsigned long cell_size = cell_size_;
        const static unsigned long block_size = block_size_;
        const static unsigned long cell_stride = cell_stride_;
        const static unsigned long num_orientation_bins = num_orientation_bins_;
        const static int           gradient_type = gradient_type_;
        const static int           interpolation_type = interpolation_type_;

        const static long min_size = cell_size*block_size+2;

        typedef matrix<double, block_size*block_size*num_orientation_bins, 1> descriptor_type;

        hog_image (
        ) :
            num_block_rows(0),
            num_block_cols(0)
        {}

        void clear (
        )
        {
            num_block_rows = 0;
            num_block_cols = 0;
            hist_cells.clear();
        }

        void copy_configuration (
            const hog_image&
        ){}

        template <
            typename image_type
            >
        inline void load (
            const image_type& img
        )
        {
            COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<image_type>::pixel_type>::has_alpha == false );
            load_impl(mat(img));
        }

        inline void unload(
        ) { clear(); }

        inline unsigned long size (
        ) const { return static_cast<unsigned long>(nr()*nc()); }

        inline long nr (
        ) const { return num_block_rows; }

        inline long nc (
        ) const { return num_block_cols; }

        long get_num_dimensions (
        ) const
        {
            return block_size*block_size*num_orientation_bins;
        }

        inline const descriptor_type& operator() (
            long row,
            long col
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT( 0 <= row && row < nr() &&
                         0 <= col && col < nc(),
                "\t descriptor_type hog_image::operator()()"
                << "\n\t invalid row or col argument"
                << "\n\t row:  " << row
                << "\n\t col:  " << col
                << "\n\t nr(): " << nr()
                << "\n\t nc(): " << nc()
                << "\n\t this: " << this
                );

            row *= cell_stride;
            col *= cell_stride;
            ++row;
            ++col;

            int feat = 0;
            for (unsigned long r = 0; r < block_size; ++r)
            {
                for (unsigned long c = 0; c < block_size; ++c)
                {
                    for (unsigned long i = 0; i < num_orientation_bins; ++i)
                    {
                        des(feat++) = hist_cells[row+r][col+c].values[i];
                    }
                }
            }

            des /= length(des) + 1e-8;

            return des;
        }

        const rectangle get_block_rect (
            long row,
            long col
        ) const
        {
            row *= cell_stride;
            col *= cell_stride;

            row *= cell_size;
            col *= cell_size;

            // do this to account for the 1 pixel padding we use all around the image
            ++row;
            ++col;

            return rectangle(col, row, col+cell_size*block_size-1, row+cell_size*block_size-1);
        }

        const point image_to_feat_space (
            const point& p
        ) const
        {

            const long half_block = block_size/2;
            if ((block_size%2) == 0)
            {
                return point(((p.x()-1)/(long)cell_size - half_block)/(long)cell_stride,
                             ((p.y()-1)/(long)cell_size - half_block)/(long)cell_stride);
            }
            else
            {
                return point(((p.x()-1-(long)cell_size/2)/(long)cell_size - half_block)/(long)cell_stride,
                             ((p.y()-1-(long)cell_size/2)/(long)cell_size - half_block)/(long)cell_stride);
            }
        }

        const rectangle image_to_feat_space (
            const rectangle& rect
        ) const
        {
            return rectangle(image_to_feat_space(rect.tl_corner()), image_to_feat_space(rect.br_corner()));
        }

        const point feat_to_image_space (
            const point& p
        ) const
        {
            const long half_block = block_size/2;
            if ((block_size%2) == 0)
            {
                return point((p.x()*cell_stride + half_block)*cell_size + 1,
                             (p.y()*cell_stride + half_block)*cell_size + 1);
            }
            else
            {
                return point((p.x()*cell_stride + half_block)*cell_size + 1 + cell_size/2,
                             (p.y()*cell_stride + half_block)*cell_size + 1 + cell_size/2);
            }
        }

        const rectangle feat_to_image_space (
            const rectangle& rect
        ) const
        {
            return rectangle(feat_to_image_space(rect.tl_corner()), feat_to_image_space(rect.br_corner()));
        }

        // these _PRIVATE_ functions are only here as a workaround for a bug in visual studio 2005.
        void _PRIVATE_serialize (std::ostream& out) const
        {
            // serialize hist_cells
            serialize(hist_cells.nc(),out);
            serialize(hist_cells.nr(),out);
            hist_cells.reset();
            while (hist_cells.move_next())
                serialize(hist_cells.element().values,out);
            hist_cells.reset();

            serialize(num_block_rows, out);
            serialize(num_block_cols, out);
        }

        void _PRIVATE_deserialize (std::istream& in )
        {
            // deserialize item.hist_cells
            long nc, nr;
            deserialize(nc,in);
            deserialize(nr,in);
            hist_cells.set_size(nr,nc);
            while (hist_cells.move_next())
                deserialize(hist_cells.element().values,in);
            hist_cells.reset();

            deserialize(num_block_rows, in);
            deserialize(num_block_cols, in);
        }

    private:

        template <
            typename image_type
            >
        void load_impl (
            const image_type& img
        )
        {
            // Note that we keep a border of 1 pixel all around the image so that we don't have
            // to worry about running outside the image when computing the horizontal and vertical
            // gradients.

            // Note also that we have a border of unused cells around the hist_cells array so that we
            // don't have to worry about edge effects when doing the interpolation in the main loop
            // below.

            // check if the window is just too small
            if (img.nr() < min_size || img.nc() < min_size)
            {
                // If the image is smaller than our windows then there aren't any descriptors at all!
                num_block_rows = 0;
                num_block_cols = 0;
                return;
            }

            // Make sure we have the right number of cell histograms and that they are
            // all set to zero.
            hist_cells.set_size((img.nr()-2)/cell_size+2, (img.nc()-2)/cell_size+2);
            for (long r = 0; r < hist_cells.nr(); ++r)
            {
                for (long c = 0; c < hist_cells.nc(); ++c)
                {
                    hist_cells[r][c].zero();
                }
            }

            // loop over all the histogram cells and fill them out
            for (long rh = 1; rh < hist_cells.nr()-1; ++rh)
            {
                for (long ch = 1; ch < hist_cells.nc()-1; ++ch)
                {
                    // Fill out the current histogram cell.
                    // First, figure out the row and column offsets into the image for the current histogram cell.
                    const long roff = (rh-1)*cell_size + 1;
                    const long coff = (ch-1)*cell_size + 1;

                    for (long r = 0; r < (long)cell_size; ++r)
                    {
                        for (long c = 0; c < (long)cell_size; ++c)
                        {
                            unsigned long left;
                            unsigned long right;
                            unsigned long top;
                            unsigned long bottom;

                            assign_pixel(left,   img(r+roff,c+coff-1));
                            assign_pixel(right,  img(r+roff,c+coff+1));
                            assign_pixel(top,    img(r+roff-1,c+coff));
                            assign_pixel(bottom, img(r+roff+1,c+coff));

                            double grad_x = (long)right-(long)left;
                            double grad_y = (long)top-(long)bottom;

                            // obtain the angle of the gradient.  Make sure it is scaled between 0 and 1.
                            double angle = std::max(0.0, std::atan2(grad_y, grad_x)/pi + 1)/2;

                            if (gradient_type == hog_unsigned_gradient)
                            {
                                angle *= 2;
                                if (angle >= 1)
                                    angle -= 1;
                            }

                            // now scale angle to between 0 and num_orientation_bins
                            angle *= num_orientation_bins;

                            const double strength = std::sqrt(grad_y*grad_y + grad_x*grad_x);

                            if (interpolation_type == hog_no_interpolation)
                            {
                                // no interpolation
                                hist_cells[rh][ch].values[round_to_int(angle)%num_orientation_bins] += strength;
                            }
                            else  // if we should do some interpolation
                            {
                                unsigned long quantized_angle_lower = static_cast<unsigned long>(std::floor(angle));
                                unsigned long quantized_angle_upper = static_cast<unsigned long>(std::ceil(angle));

                                quantized_angle_lower %= num_orientation_bins;
                                quantized_angle_upper %= num_orientation_bins;

                                const double angle_split = (angle-std::floor(angle));
                                const double upper_strength = angle_split*strength;
                                const double lower_strength = (1-angle_split)*strength;

                                if (interpolation_type == hog_angle_interpolation)
                                {
                                    // Stick into gradient histogram.  Note that we linearly interpolate between neighboring
                                    // histogram buckets.
                                    hist_cells[rh][ch].values[quantized_angle_lower] += lower_strength;
                                    hist_cells[rh][ch].values[quantized_angle_upper] += upper_strength;
                                }
                                else // here we do hog_full_interpolation
                                {
                                    const double center_r = (cell_size-1)/2.0;
                                    const double center_c = (cell_size-1)/2.0;

                                    const double lin_neighbor_r = std::abs(center_r - r)/cell_size;
                                    const double lin_main_r = 1-lin_neighbor_r;

                                    const double lin_neighbor_c = std::abs(center_c - c)/cell_size;
                                    const double lin_main_c = 1-lin_neighbor_c;

                                    // Which neighboring cells we interpolate into depends on which
                                    // corner of our main cell we are nearest.
                                    if (r < center_r)
                                    {
                                        if (c < center_c)
                                        {
                                            hist_cells[rh][ch].values[quantized_angle_upper] += upper_strength   * lin_main_r*lin_main_c;
                                            hist_cells[rh][ch].values[quantized_angle_lower] += lower_strength   * lin_main_r*lin_main_c;

                                            hist_cells[rh-1][ch].values[quantized_angle_upper] += upper_strength * lin_neighbor_r*lin_main_c;
                                            hist_cells[rh-1][ch].values[quantized_angle_lower] += lower_strength * lin_neighbor_r*lin_main_c;

                                            hist_cells[rh][ch-1].values[quantized_angle_upper] += upper_strength * lin_neighbor_c*lin_main_r;
                                            hist_cells[rh][ch-1].values[quantized_angle_lower] += lower_strength * lin_neighbor_c*lin_main_r;

                                            hist_cells[rh-1][ch-1].values[quantized_angle_upper] += upper_strength * lin_neighbor_c*lin_neighbor_r;
                                            hist_cells[rh-1][ch-1].values[quantized_angle_lower] += lower_strength * lin_neighbor_c*lin_neighbor_r;
                                        }
                                        else
                                        {
                                            hist_cells[rh][ch].values[quantized_angle_upper] += upper_strength   * lin_main_r*lin_main_c;
                                            hist_cells[rh][ch].values[quantized_angle_lower] += lower_strength   * lin_main_r*lin_main_c;

                                            hist_cells[rh-1][ch].values[quantized_angle_upper] += upper_strength * lin_neighbor_r*lin_main_c;
                                            hist_cells[rh-1][ch].values[quantized_angle_lower] += lower_strength * lin_neighbor_r*lin_main_c;

                                            hist_cells[rh][ch+1].values[quantized_angle_upper] += upper_strength * lin_neighbor_c*lin_main_r;
                                            hist_cells[rh][ch+1].values[quantized_angle_lower] += lower_strength * lin_neighbor_c*lin_main_r;

                                            hist_cells[rh-1][ch+1].values[quantized_angle_upper] += upper_strength * lin_neighbor_c*lin_neighbor_r;
                                            hist_cells[rh-1][ch+1].values[quantized_angle_lower] += lower_strength * lin_neighbor_c*lin_neighbor_r;
                                        }
                                    }
                                    else
                                    {
                                        if (c < center_c)
                                        {
                                            hist_cells[rh][ch].values[quantized_angle_upper] += upper_strength   * lin_main_r*lin_main_c;
                                            hist_cells[rh][ch].values[quantized_angle_lower] += lower_strength   * lin_main_r*lin_main_c;

                                            hist_cells[rh+1][ch].values[quantized_angle_upper] += upper_strength * lin_neighbor_r*lin_main_c;
                                            hist_cells[rh+1][ch].values[quantized_angle_lower] += lower_strength * lin_neighbor_r*lin_main_c;

                                            hist_cells[rh][ch-1].values[quantized_angle_upper] += upper_strength * lin_neighbor_c*lin_main_r;
                                            hist_cells[rh][ch-1].values[quantized_angle_lower] += lower_strength * lin_neighbor_c*lin_main_r;

                                            hist_cells[rh+1][ch-1].values[quantized_angle_upper] += upper_strength * lin_neighbor_c*lin_neighbor_r;
                                            hist_cells[rh+1][ch-1].values[quantized_angle_lower] += lower_strength * lin_neighbor_c*lin_neighbor_r;
                                        }
                                        else
                                        {
                                            hist_cells[rh][ch].values[quantized_angle_upper] += upper_strength   * lin_main_r*lin_main_c;
                                            hist_cells[rh][ch].values[quantized_angle_lower] += lower_strength   * lin_main_r*lin_main_c;

                                            hist_cells[rh+1][ch].values[quantized_angle_upper] += upper_strength * lin_neighbor_r*lin_main_c;
                                            hist_cells[rh+1][ch].values[quantized_angle_lower] += lower_strength * lin_neighbor_r*lin_main_c;

                                            hist_cells[rh][ch+1].values[quantized_angle_upper] += upper_strength * lin_neighbor_c*lin_main_r;
                                            hist_cells[rh][ch+1].values[quantized_angle_lower] += lower_strength * lin_neighbor_c*lin_main_r;

                                            hist_cells[rh+1][ch+1].values[quantized_angle_upper] += upper_strength * lin_neighbor_c*lin_neighbor_r;
                                            hist_cells[rh+1][ch+1].values[quantized_angle_lower] += lower_strength * lin_neighbor_c*lin_neighbor_r;
                                        }
                                    }
                                }
                            }

                        }
                    }
                }
            }

            // Now figure out how many blocks we should have.  Note again that the hist_cells has a border of
            // unused cells (thats where that -2 comes from).
            num_block_rows = (hist_cells.nr()-2 - (block_size-1) + cell_stride - 1)/cell_stride;
            num_block_cols = (hist_cells.nc()-2 - (block_size-1) + cell_stride - 1)/cell_stride;

        }

        unsigned long round_to_int(
            double val
        ) const
        {
            return static_cast<unsigned long>(std::floor(val + 0.5));
        }

        struct histogram
        {
            void zero()
            {
                for (unsigned long i = 0; i < num_orientation_bins; ++i)
                    values[i] = 0;
            }
            double values[num_orientation_bins];
        };

        array2d<histogram> hist_cells;

        mutable descriptor_type des;

        long num_block_rows;
        long num_block_cols;

    };

// ----------------------------------------------------------------------------------------

    template <
        unsigned long T1,
        unsigned long T2,
        unsigned long T3,
        unsigned long T4,
        int           T5,
        int           T6
        >
    void serialize (
        const hog_image<T1,T2,T3,T4,T5,T6>& item,
        std::ostream& out
    )
    {
        item._PRIVATE_serialize(out);
    }

    template <
        unsigned long T1,
        unsigned long T2,
        unsigned long T3,
        unsigned long T4,
        int           T5,
        int           T6
        >
    void deserialize (
        hog_image<T1,T2,T3,T4,T5,T6>& item,
        std::istream& in
    )
    {
        item._PRIVATE_deserialize(in);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_HoG_Hh_


dlib C++ Library - nearest_neighbor_feature_image.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_NEAREST_NEIGHBOR_FeATURE_IMAGE_Hh_
#define DLIB_NEAREST_NEIGHBOR_FeATURE_IMAGE_Hh_

#include "nearest_neighbor_feature_image_abstract.h"
#include <vector>
#include "../algs.h"
#include "../matrix.h"
#include "../statistics.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    class nearest_neighbor_feature_image : noncopyable
    {
        /*!
            INITIAL VALUE
                - nn_feats.size() == 1

            CONVENTION
                - nn_feats.size() == 1

        !*/

    public:

        typedef std::vector<std::pair<unsigned int,double> > descriptor_type;

        nearest_neighbor_feature_image (
        );

        void clear (
        );

        void copy_configuration (
            const feature_extractor& item
        );

        void copy_configuration (
            const nearest_neighbor_feature_image& item
        );

        template <
            typename image_type
            >
        inline void load (
            const image_type& img
        );

        inline unsigned long size (
        ) const;

        inline long nr (
        ) const;

        inline long nc (
        ) const;

        inline long get_num_dimensions (
        ) const;

        template <typename vector_type>
        void set_basis (
            const vector_type& new_basis
        );

        inline const descriptor_type& operator() (
            long row,
            long col
        ) const;

        inline const rectangle get_block_rect (
            long row,
            long col
        ) const;

        inline const point image_to_feat_space (
            const point& p
        ) const;

        inline const rectangle image_to_feat_space (
            const rectangle& rect
        ) const;

        inline const point feat_to_image_space (
            const point& p
        ) const;

        inline const rectangle feat_to_image_space (
            const rectangle& rect
        ) const;

        template <typename T>
        friend void serialize (
            const nearest_neighbor_feature_image<T>& item,
            std::ostream& out
        );

        template <typename T>
        friend void deserialize (
            nearest_neighbor_feature_image<T>& item,
            std::istream& in
        );

    private:

        array2d<unsigned long> feats;
        feature_extractor fe;
        std::vector<typename feature_extractor::descriptor_type> basis;

        // This is a transient variable.  It is just here so it doesn't have to be
        // reallocated over and over inside operator()
        mutable descriptor_type nn_feats;

    };

// ----------------------------------------------------------------------------------------

    template <typename T>
    void serialize (
        const nearest_neighbor_feature_image<T>& item,
        std::ostream& out
    )
    {
        serialize(item.feats, out);
        serialize(item.fe, out);
        serialize(item.basis, out);
    }

    template <typename T>
    void deserialize (
        nearest_neighbor_feature_image<T>& item,
        std::istream& in
    )
    {
        deserialize(item.feats, in);
        deserialize(item.fe, in);
        deserialize(item.basis, in);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                        nearest_neighbor_feature_image member functions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    nearest_neighbor_feature_image<feature_extractor>::
    nearest_neighbor_feature_image (
    )
    {
        nn_feats.resize(1);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    void nearest_neighbor_feature_image<feature_extractor>::
    clear (
    )
    {
        feats.clear();
        fe.clear();
        basis.clear();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    void nearest_neighbor_feature_image<feature_extractor>::
    copy_configuration (
        const feature_extractor& item
    )
    {
        fe.copy_configuration(item);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    void nearest_neighbor_feature_image<feature_extractor>::
    copy_configuration (
        const nearest_neighbor_feature_image& item
    )
    {
        fe.copy_configuration(item.fe);
        basis = item.basis;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    template <
        typename image_type
        >
    void nearest_neighbor_feature_image<feature_extractor>::
    load (
        const image_type& img
    )
    {
        fe.load(img);

        feats.set_size(fe.nr(), fe.nc());

        // find the nearest neighbor for each feature vector and store the
        // result in feats.
        for (long r = 0; r < feats.nr(); ++r)
        {
            for (long c = 0; c < feats.nc(); ++c)
            {
                const typename feature_extractor::descriptor_type& local_feat = fe(r,c);

                double best_dist = std::numeric_limits<double>::infinity();
                unsigned long best_idx = 0;
                for (unsigned long i = 0; i < basis.size(); ++i)
                {
                    double dist = length_squared(local_feat - basis[i]);
                    if (dist < best_dist)
                    {
                        best_dist = dist;
                        best_idx = i;
                    }
                }

                feats[r][c] = best_idx;
            }
        }

        fe.unload();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    unsigned long nearest_neighbor_feature_image<feature_extractor>::
    size (
    ) const
    {
        return feats.size();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    long nearest_neighbor_feature_image<feature_extractor>::
    nr (
    ) const
    {
        return feats.nr();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    long nearest_neighbor_feature_image<feature_extractor>::
    nc (
    ) const
    {
        return feats.nc();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    long nearest_neighbor_feature_image<feature_extractor>::
    get_num_dimensions (
    ) const
    {
        return basis.size();
    }

// ----------------------------------------------------------------------------------------

    template <typename feature_extractor>
    template <typename vector_type>
    void nearest_neighbor_feature_image<feature_extractor>::
    set_basis (
        const vector_type& new_basis
    )
    {
        basis.assign(new_basis.begin(), new_basis.end());
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    const typename nearest_neighbor_feature_image<feature_extractor>::descriptor_type&
    nearest_neighbor_feature_image<feature_extractor>::
    operator() (
        long row,
        long col
    ) const
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(0 <= row && row < nr() &&
                    0 <= col && col < nc(),
            "\t descriptor_type nearest_neighbor_feature_image::operator(row,col)"
            << "\n\t Invalid inputs were given to this function"
            << "\n\t row:  " << row
            << "\n\t col:  " << col
            << "\n\t nr(): " << nr()
            << "\n\t nc(): " << nc()
            << "\n\t this: " << this
            );

        nn_feats[0] = std::make_pair(feats[row][col],1);
        return nn_feats;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    const rectangle nearest_neighbor_feature_image<feature_extractor>::
    get_block_rect (
        long row,
        long col
    ) const
    {
        return fe.get_block_rect(row,col);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    const point nearest_neighbor_feature_image<feature_extractor>::
    image_to_feat_space (
        const point& p
    ) const
    {
        return fe.image_to_feat_space(p);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    const rectangle nearest_neighbor_feature_image<feature_extractor>::
    image_to_feat_space (
        const rectangle& rect
    ) const
    {
        return fe.image_to_feat_space(rect);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    const point nearest_neighbor_feature_image<feature_extractor>::
    feat_to_image_space (
        const point& p
    ) const
    {
        return fe.feat_to_image_space(p);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    const rectangle nearest_neighbor_feature_image<feature_extractor>::
    feat_to_image_space (
        const rectangle& rect
    ) const
    {
        return fe.feat_to_image_space(rect);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_NEAREST_NEIGHBOR_FeATURE_IMAGE_Hh_


dlib C++ Library - poly_image.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_POLY_ImAGE_Hh_
#define DLIB_POLY_ImAGE_Hh_

#include "poly_image_abstract.h"
#include "build_separable_poly_filters.h"
#include "../algs.h"
#include "../matrix.h"
#include "../array2d.h"
#include "../geometry.h"
#include <cmath>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        long Downsample
        >
    class poly_image : noncopyable
    {
        COMPILE_TIME_ASSERT(Downsample >= 1);
    public:
        const static long downsample = Downsample;
        typedef matrix<double, 0, 1> descriptor_type;

        poly_image(
            long order_,
            long window_size_,
            bool normalization = true,
            bool rotation_invariance_ = false
        )
        {
            setup(order_, window_size_);
            set_uses_normalization(normalization);
            set_is_rotationally_invariant(rotation_invariance_);
        }

        poly_image (
        )
        {
            clear();
        }

        void clear (
        )
        {
            normalize = true;
            rotation_invariance = false;
            poly_coef.clear();
            order = 3;
            window_size = 13;
            border_size = (long)std::ceil(std::floor(window_size/2.0)/downsample);
            num_rows = 0;
            num_cols = 0;
            filters = build_separable_poly_filters(order, window_size);
        }

        long get_order (
        ) const
        {
            return order;
        }

        long get_window_size (
        ) const
        {
            return window_size;
        }

        void setup (
            long order_,
            long window_size_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(1 <= order_ && order_ <= 6 &&
                        window_size_ >= 3 && (window_size_%2) == 1,
                "\t descriptor_type poly_image::setup()"
                << "\n\t Invalid arguments were given to this function."
                << "\n\t order_:       " << order_
                << "\n\t window_size_: " << window_size_
                << "\n\t this: " << this
                );

            poly_coef.clear();
            order = order_;
            window_size = window_size_;
            border_size = (long)std::ceil(std::floor(window_size/2.0)/downsample);
            num_rows = 0;
            num_cols = 0;
            filters = build_separable_poly_filters(order, window_size);
        }

        bool uses_normalization (
        ) const { return normalize; }

        void set_uses_normalization (
            bool normalization
        )
        {
            normalize = normalization;
        }

        bool is_rotationally_invariant (
        ) const { return rotation_invariance; }

        void set_is_rotationally_invariant (
            bool rotation_invariance_
        )
        {
            rotation_invariance = rotation_invariance_;
        }

        void copy_configuration (
            const poly_image& item
        )
        {
            normalize = item.normalize;
            rotation_invariance = item.rotation_invariance;
            if (order != item.order ||
                window_size != item.window_size)
            {
                order = item.order;
                window_size = item.window_size;
                border_size = item.border_size;
                filters = item.filters;
            }
        }

        template <
            typename image_type
            >
        inline void load (
            const image_type& img
        )
        {
            COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<image_type>::pixel_type>::has_alpha == false );

            poly_coef.resize(get_num_dimensions());
            des.set_size(get_num_dimensions());

            if (normalize)
            {
                array2d<float> coef0;
                rectangle rect = filter_image(img, coef0, filters[0]);
                num_rows = rect.height();
                num_cols = rect.width();

                for (unsigned long i = 1; i < filters.size(); ++i)
                {
                    filter_image(img, poly_coef[i-1], filters[i]);

                    // intensity normalize everything
                    for (long r = 0; r < coef0.nr(); ++r)
                    {
                        for (long c = 0; c < coef0.nc(); ++c)
                        {
                            if (coef0[r][c] >= 1)
                                poly_coef[i-1][r][c] /= coef0[r][c];
                            else
                                poly_coef[i-1][r][c] = 0;
                        }
                    }
                }

                if (rotation_invariance)
                    rotate_polys(rect);
            }
            else
            {
                rectangle rect;
                for (unsigned long i = 0; i < filters.size(); ++i)
                {
                    rect = filter_image(img, poly_coef[i], filters[i]);
                }
                num_rows = rect.height();
                num_cols = rect.width();

                if (rotation_invariance)
                    rotate_polys(rect);
            }
        }

        void unload()
        {
            poly_coef.clear();
            num_rows = 0;
            num_cols = 0;
        }

        inline unsigned long size (
        ) const { return static_cast<unsigned long>(nr()*nc()); }

        inline long nr (
        ) const { return num_rows; }

        inline long nc (
        ) const { return num_cols; }

        long get_num_dimensions (
        ) const
        {
            if (normalize)
            {
                // -1 because we discard the constant term of the polynomial.
                return filters.size()-1;
            }
            else
            {
                return filters.size();
            }
        }

        inline const descriptor_type& operator() (
            long row,
            long col
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT( 0 <= row && row < nr() &&
                         0 <= col && col < nc(),
                "\t descriptor_type poly_image::operator()()"
                << "\n\t invalid row or col argument"
                << "\n\t row:  " << row
                << "\n\t col:  " << col
                << "\n\t nr(): " << nr()
                << "\n\t nc(): " << nc()
                << "\n\t this: " << this
                );

            // add because of the zero border around the poly_coef images
            row += border_size;
            col += border_size;

            for (long i = 0; i < des.size(); ++i)
                des(i) = poly_coef[i][row][col];

            return des;
        }

        const rectangle get_block_rect (
            long row,
            long col
        ) const
        {
            return centered_rect(Downsample*point(col+border_size, row+border_size),
                                 window_size, window_size);
        }

        const point image_to_feat_space (
            const point& p
        ) const
        {
            return p/Downsample - point(border_size, border_size);
        }

        const rectangle image_to_feat_space (
            const rectangle& rect
        ) const
        {
            return rectangle(image_to_feat_space(rect.tl_corner()), image_to_feat_space(rect.br_corner()));
        }

        const point feat_to_image_space (
            const point& p
        ) const
        {
            return (p + point(border_size, border_size))*Downsample;
        }

        const rectangle feat_to_image_space (
            const rectangle& rect
        ) const
        {
            return rectangle(feat_to_image_space(rect.tl_corner()), feat_to_image_space(rect.br_corner()));
        }

        friend void serialize (const poly_image& item, std::ostream& out)
        {
            int version = 1;
            serialize(version, out);
            serialize(item.poly_coef, out);
            serialize(item.order, out);
            serialize(item.window_size, out);
            serialize(item.border_size, out);
            serialize(item.num_rows, out);
            serialize(item.num_cols, out);
            serialize(item.normalize, out);
            serialize(item.rotation_invariance, out);
            serialize(item.filters, out);
        }

        friend void deserialize (poly_image& item, std::istream& in )
        {
            int version = 0;
            deserialize(version, in);
            if (version != 1)
                throw dlib::serialization_error("Unexpected version found while deserializing dlib::poly_image");

            deserialize(item.poly_coef, in);
            deserialize(item.order, in);
            deserialize(item.window_size, in);
            deserialize(item.border_size, in);
            deserialize(item.num_rows, in);
            deserialize(item.num_cols, in);
            deserialize(item.normalize, in);
            deserialize(item.rotation_invariance, in);
            deserialize(item.filters, in);
        }

    private:

        matrix<float,2,1> rotate_order_1 (
            const matrix<float,2,1>& w,
            double cos_theta,
            double sin_theta
        ) const
        {
            const double w1 = w(0);
            const double w2 = w(1);
            matrix<double,2,2> M;
            M = w1,  w2,
                w2, -w1;

            matrix<double,2,1> x;
            x = cos_theta,
                sin_theta;

            return matrix_cast<float>(M*x);
        }

        matrix<float,3,1> rotate_order_2 (
            const matrix<float,3,1>& w,
            double cos_theta,
            double sin_theta
        ) const
        {
            const double w1 = w(0);
            const double w2 = w(1);
            const double w3 = w(2);
            matrix<double,3,3> M;
            M = w1, w2,           w3,
                w2, (2*w3-2*w1), -w2,
                w3, -w2,          w1;

            matrix<double,3,1> x;
            x = std::pow(cos_theta,2.0),
                cos_theta*sin_theta,
                std::pow(sin_theta,2.0);

            return matrix_cast<float>(M*x);
        }

        matrix<float,4,1> rotate_order_3 (
            const matrix<float,4,1>& w,
            double cos_theta,
            double sin_theta
        ) const
        {
            const double w1 = w(0);
            const double w2 = w(1);
            const double w3 = w(2);
            const double w4 = w(3);
            matrix<double,4,4> M;
            M = w1, w2,            w3,           w4,
                w2, (2*w3-3*w1), (3*w4-2*w2),   -w3,
                w3, (3*w4-2*w2), (3*w1-2*w3),    w2,
                w4, -w3,           w2,          -w1;

            matrix<double,4,1> x;
            x = std::pow(cos_theta,3.0),
                std::pow(cos_theta,2.0)*sin_theta,
                cos_theta*std::pow(sin_theta,2.0),
                std::pow(sin_theta,3.0);

            return matrix_cast<float>(M*x);
        }

        matrix<float,5,1> rotate_order_4 (
            const matrix<float,5,1>& w,
            double cos_theta,
            double sin_theta
        ) const
        {
            const double w1 = w(0);
            const double w2 = w(1);
            const double w3 = w(2);
            const double w4 = w(3);
            const double w5 = w(4);
            matrix<double,5,5> M;
            M = w1, w2,              w3,            w4,          w5,
                w2, (2*w3-4*w1), (3*w4-3*w2),      (4*w5-2*w3), -w4,
                w3, (3*w4-3*w2), (6*w1-4*w3+6*w5), (3*w2-3*w4),  w3,
                w4, (4*w5-2*w3), (3*w2-3*w4),      (2*w3-4*w1), -w2,
                w5, -w4,            w3,            -w2,          w1;

            matrix<double,5,1> x;
            x = std::pow(cos_theta,4.0),
                std::pow(cos_theta,3.0)*sin_theta,
                std::pow(cos_theta,2.0)*std::pow(sin_theta,2.0),
                cos_theta*std::pow(sin_theta,3.0),
                std::pow(sin_theta,4.0);

            return matrix_cast<float>(M*x);
        }

        matrix<float,6,1> rotate_order_5 (
            const matrix<float,6,1>& w,
            double cos_theta,
            double sin_theta
        ) const
        {
            const double w1 = w(0);
            const double w2 = w(1);
            const double w3 = w(2);
            const double w4 = w(3);
            const double w5 = w(4);
            const double w6 = w(5);
            matrix<double,6,6> M;
            M = w1,     w2,          w3,             w4,                 w5,          w6,
                w2, (2*w3-5*w1), (3*w4-4*w2),       (4*w5-3*w3),        (5*w6-2*w4), -w5,
                w3, (3*w4-4*w2), (10*w1-6*w3+6*w5), (6*w2-6*w4+10*w6),  (3*w3-4*w5),  w4,
                w4, (4*w5-3*w3), (6*w2-6*w4+10*w6), (-10*w1+6*w3-6*w5), (3*w4-4*w2), -w3,
                w5, (5*w6-2*w4), (3*w3-4*w5),       (3*w4-4*w2),        (5*w1-2*w3),  w2,
                w6,    -w5,          w4,            -w3,                 w2,         -w1;

            matrix<double,6,1> x;
            x = std::pow(cos_theta,5.0),
                std::pow(cos_theta,4.0)*sin_theta,
                std::pow(cos_theta,3.0)*std::pow(sin_theta,2.0),
                std::pow(cos_theta,2.0)*std::pow(sin_theta,3.0),
                cos_theta*std::pow(sin_theta,4.0),
                std::pow(sin_theta,5.0);

            return matrix_cast<float>(M*x);
        }

        matrix<float,7,1> rotate_order_6 (
            const matrix<float,7,1>& w,
            double cos_theta,
            double sin_theta
        ) const
        {
            const double w1 = w(0);
            const double w2 = w(1);
            const double w3 = w(2);
            const double w4 = w(3);
            const double w5 = w(4);
            const double w6 = w(5);
            const double w7 = w(6);
            matrix<double,7,7> M;
            M = w1,     w2,          w3,              w4,                           w5,                 w6,         w7,
                w2, (2*w3-6*w1), (3*w4-5*w2),        (4*w5-4*w3),                (5*w6-3*w4),         (6*w7-2*w5), -w6,
                w3, (3*w4-5*w2), (15*w1-8*w3+ 6*w5), ( 10*w2 -9*w4+10*w6),       (  6*w3-8*w5+15*w7), (3*w4-5*w6),  w5,
                w4, (4*w5-4*w3), (10*w2-9*w4+10*w6), (-20*w1+12*w3-12*w5+20*w7), (-10*w2+9*w4-10*w6), (4*w5-4*w3), -w4,
                w5, (5*w6-3*w4), ( 6*w3-8*w5+15*w7), (-10*w2 +9*w4-10*w6),       ( 15*w1-8*w3 +6*w5), (5*w2-3*w4),  w3,
                w6, (6*w7-2*w5), (3*w4-5*w6),        (4*w5-4*w3),                (5*w2-3*w4),         (2*w3-6*w1), -w2,
                w7,     -w6,          w5,            -w4,                          w3,                 -w2,         w1;

            matrix<double,7,1> x;
            x = std::pow(cos_theta,6.0),
                std::pow(cos_theta,5.0)*sin_theta,
                std::pow(cos_theta,4.0)*std::pow(sin_theta,2.0),
                std::pow(cos_theta,3.0)*std::pow(sin_theta,3.0),
                std::pow(cos_theta,2.0)*std::pow(sin_theta,4.0),
                cos_theta*std::pow(sin_theta,5.0),
                std::pow(sin_theta,6.0);

            return matrix_cast<float>(M*x);
        }

        void rotate_polys (
            const rectangle& rect
        )
        /*!
            ensures
                - rotates all the polynomials in poly_coef so that they are
                  rotationally invariant
        !*/
        {
            // The idea here is to use a rotation matrix to rotate the
            // coordinate system for the polynomial so that the x axis
            // always lines up with the gradient vector (or direction of
            // max curvature).  This way we can make the representation
            // rotation invariant.

            // Note that the rotation matrix is given by:
            // [ cos_theta -sin_theta ]
            // [ sin_theta cos_theta  ]

            // need to offset poly_coef to get past the constant term if there isn't any normalization.
            const int off = (normalize) ? 0 : 1;

            for (long r = rect.top(); r <= rect.bottom(); ++r)
            {
                for (long c = rect.left(); c <= rect.right(); ++c)
                {
                    dlib::vector<double,2> g(poly_coef[off+0][r][c],
                                             poly_coef[off+1][r][c]);

                    const double len = g.length();
                    if (len != 0)
                    {
                        g /= len;
                    }
                    else
                    {
                        g.x() = 1;
                        g.y() = 0;
                    }
                    // since we normalized g we can find the sin/cos of its angle easily.
                    const double cos_theta = g.x();
                    const double sin_theta = g.y();

                    if (order >= 1)
                    {
                        matrix<float,2,1> w;
                        w = poly_coef[off+0][r][c],
                            poly_coef[off+1][r][c];
                        w = rotate_order_1(w, cos_theta, sin_theta);
                        poly_coef[off+0][r][c] = w(0);
                        poly_coef[off+1][r][c] = w(1);
                    }
                    if (order >= 2)
                    {
                        matrix<float,3,1> w;
                        w = poly_coef[off+2][r][c],
                            poly_coef[off+3][r][c],
                            poly_coef[off+4][r][c];
                        w = rotate_order_2(w, cos_theta, sin_theta);
                        poly_coef[off+2][r][c] = w(0);
                        poly_coef[off+3][r][c] = w(1);
                        poly_coef[off+4][r][c] = w(2);
                    }
                    if (order >= 3)
                    {
                        matrix<float,4,1> w;
                        w = poly_coef[off+5][r][c],
                            poly_coef[off+6][r][c],
                            poly_coef[off+7][r][c],
                            poly_coef[off+8][r][c];
                        w = rotate_order_3(w, cos_theta, sin_theta);
                        poly_coef[off+5][r][c] = w(0);
                        poly_coef[off+6][r][c] = w(1);
                        poly_coef[off+7][r][c] = w(2);
                        poly_coef[off+8][r][c] = w(3);
                    }
                    if (order >= 4)
                    {
                        matrix<float,5,1> w;
                        w = poly_coef[off+9][r][c],
                            poly_coef[off+10][r][c],
                            poly_coef[off+11][r][c],
                            poly_coef[off+12][r][c],
                            poly_coef[off+13][r][c];
                        w = rotate_order_4(w, cos_theta, sin_theta);
                        poly_coef[off+9][r][c]  = w(0);
                        poly_coef[off+10][r][c] = w(1);
                        poly_coef[off+11][r][c] = w(2);
                        poly_coef[off+12][r][c] = w(3);
                        poly_coef[off+13][r][c] = w(4);
                    }
                    if (order >= 5)
                    {
                        matrix<float,6,1> w;
                        w = poly_coef[off+14][r][c],
                            poly_coef[off+15][r][c],
                            poly_coef[off+16][r][c],
                            poly_coef[off+17][r][c],
                            poly_coef[off+18][r][c],
                            poly_coef[off+19][r][c];
                        w = rotate_order_5(w, cos_theta, sin_theta);
                        poly_coef[off+14][r][c] = w(0);
                        poly_coef[off+15][r][c] = w(1);
                        poly_coef[off+16][r][c] = w(2);
                        poly_coef[off+17][r][c] = w(3);
                        poly_coef[off+18][r][c] = w(4);
                        poly_coef[off+19][r][c] = w(5);
                    }
                    if (order >= 6)
                    {
                        matrix<float,7,1> w;
                        w = poly_coef[off+20][r][c],
                            poly_coef[off+21][r][c],
                            poly_coef[off+22][r][c],
                            poly_coef[off+23][r][c],
                            poly_coef[off+24][r][c],
                            poly_coef[off+25][r][c],
                            poly_coef[off+26][r][c];
                        w = rotate_order_6(w, cos_theta, sin_theta);
                        poly_coef[off+20][r][c] = w(0);
                        poly_coef[off+21][r][c] = w(1);
                        poly_coef[off+22][r][c] = w(2);
                        poly_coef[off+23][r][c] = w(3);
                        poly_coef[off+24][r][c] = w(4);
                        poly_coef[off+25][r][c] = w(5);
                        poly_coef[off+26][r][c] = w(6);
                    }
                }
            }

        }

        template <typename image_type>
        rectangle filter_image (
            const image_type& img,
            array2d<float>& out,
            const std::vector<separable_filter_type>& filter
        ) const
        {
            rectangle rect = spatially_filter_image_separable_down(downsample, img, out, filter[0].first, filter[0].second);
            for (unsigned long i = 1; i < filter.size(); ++i)
            {
                spatially_filter_image_separable_down(downsample, img, out, filter[i].first, filter[i].second, 1, false, true);
            }
            return rect;
        }

        std::vector<std::vector<separable_filter_type> > filters;

        dlib::array<array2d<float> > poly_coef;
        long order;
        long window_size;
        long border_size;
        long num_rows;
        long num_cols;

        bool normalize;
        bool rotation_invariance;

        mutable descriptor_type des;
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_POLY_ImAGE_Hh_


dlib C++ Library - surf.h

// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SURf_H_
#define DLIB_SURf_H_

#include "surf_abstract.h"
#include "hessian_pyramid.h"
#include "../matrix.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    struct surf_point
    {
        interest_point p;
        matrix<double,64,1> des;
        double angle;
    };

// ----------------------------------------------------------------------------------------

    inline void serialize(
        const surf_point& item,
        std::ostream& out
    )
    {
        try
        {
            serialize(item.p,out);
            serialize(item.des,out);
            serialize(item.angle,out);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while serializing object of type surf_point");
        }
    }

// ----------------------------------------------------------------------------------------

    inline void deserialize(
        surf_point& item,
        std::istream& in
    )
    {
        try
        {
            deserialize(item.p,in);
            deserialize(item.des,in);
            deserialize(item.angle,in);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while deserializing object of type surf_point");
        }
    }

// ----------------------------------------------------------------------------------------

    inline double gaussian (double x, double y, double sig)
    {
        DLIB_ASSERT(sig > 0,
            "\tdouble gaussian()"
            << "\n\t sig must be bigger than 0"
            << "\n\t sig: " << sig
        );
        const double sqrt_2_pi = 2.5066282746310002416123552393401041626930;
        return 1.0/(sig*sqrt_2_pi) * std::exp( -(x*x + y*y)/(2*sig*sig));
    }

// ----------------------------------------------------------------------------------------

    template <typename integral_image_type, typename T>
    double compute_dominant_angle (
        const integral_image_type& img,
        const dlib::vector<T,2>& center,
        const double& scale
    )
    {
        DLIB_ASSERT(get_rect(img).contains(centered_rect(center, (unsigned long)(17*scale),(unsigned long)(17*scale))) == true &&
                    scale > 0,
            "\tdouble compute_dominant_angle(img, center, scale)"
            << "\n\tAll arguments to this function must be > 0"
            << "\n\t get_rect(img): " << get_rect(img)
            << "\n\t center:        " << center
            << "\n\t scale:         " << scale
        );

        std::vector<double> ang;
        std::vector<dlib::vector<double,2> > samples;

        const long sc = static_cast<long>(scale+0.5);

        // accumulate a bunch of angle and vector samples
        dlib::vector<double,2> vect;
        for (long r = -6; r <= 6; ++r)
        {
            for (long c = -6; c <= 6; ++c)
            {
                if (r*r + c*c < 36)
                {
                    // compute a Gaussian weighted gradient and the gradient's angle.
                    const double gauss = gaussian(c,r, 2.5);
                    vect.x() = gauss*haar_x(img, sc*point(c,r)+center, 4*sc);
                    vect.y() = gauss*haar_y(img, sc*point(c,r)+center, 4*sc);
                    samples.push_back(vect);
                    ang.push_back(atan2(vect.y(), vect.x()));
                }
            }
        }

        // now find the dominant direction
        double max_length = 0;
        double best_ang = 0;
        // look at a bunch of pie shaped slices of a circle
        const long slices = 45;
        const double ang_step = (2*pi)/slices;
        for (long ang_i = 0; ang_i < slices; ++ang_i)
        {
            // compute the bounding angles
            double ang1 = ang_step*ang_i - pi;
            double ang2 = ang1 + pi/3;

            // compute sum of all vectors that are within the above two angles
            vect.x() = 0;
            vect.y() = 0;
            for (unsigned long i = 0; i < ang.size(); ++i)
            {
                if (ang1 <= ang[i] && ang[i] <= ang2)
                {
                    vect += samples[i];
                }
                else if (ang2 > pi && (ang[i] >= ang1 || ang[i] <= (-2*pi+ang2)))
                {
                    vect += samples[i];
                }
            }

            // record the angle of the best vectors
            if (length_squared(vect) > max_length)
            {
                max_length = length_squared(vect);
                best_ang = atan2(vect.y(), vect.x());
            }
        }

        return best_ang;
    }

// ----------------------------------------------------------------------------------------

    template <typename integral_image_type, typename T, typename MM, typename L>
    void compute_surf_descriptor (
        const integral_image_type& img,
        const dlib::vector<T,2>& center,
        const double scale,
        const double angle,
        matrix<double,64,1,MM,L>& des
    )
    {
        DLIB_ASSERT(get_rect(img).contains(centered_rect(center, (unsigned long)(32*scale),(unsigned long)(32*scale))) == true &&
                    scale > 0,
            "\tvoid compute_surf_descriptor(img, center, scale, angle)"
            << "\n\tAll arguments to this function must be > 0"
            << "\n\t get_rect(img): " << get_rect(img)
            << "\n\t center:        " << center
            << "\n\t scale:         " << scale
        );

        point_rotator rot(angle);
        point_rotator inv_rot(-angle);

        const long sc = static_cast<long>(scale+0.5);
        long count = 0;

        // loop over the 4x4 grid of histogram buckets
        for (long r = -10; r < 10; r += 5)
        {
            for (long c = -10; c < 10; c += 5)
            {
                dlib::vector<double,2> vect, abs_vect, temp;

                // now loop over 25 points in this bucket and sum their features.  Note
                // that we include 1 pixels worth of padding around the outside of each 5x5
                // cell.  This is to help neighboring cells interpolate their counts into
                // each other a little bit.
                for (long y = r-1; y < r+5+1; ++y)
                {
                    if (y < -10 || y >= 10)
                        continue;
                    for (long x = c-1; x < c+5+1; ++x)
                    {
                        if (x < -10 || x >= 10)
                            continue;

                        // get the rotated point for this extraction point
                        point p(rot(point(x,y)*scale) + center);

                        // Give points farther from the center of the bucket a lower weight.
                        const long center_r = r+2;
                        const long center_c = c+2;
                        const double weight = 1.0/(4+std::abs(center_r-y) + std::abs(center_c-x));

                        temp.x() = weight*haar_x(img, p, 2*sc);
                        temp.y() = weight*haar_y(img, p, 2*sc);

                        // rotate this vector into alignment with the surf descriptor box
                        temp = inv_rot(temp);

                        vect += temp;
                        abs_vect += abs(temp);
                    }
                }

                des(count++) = vect.x();
                des(count++) = vect.y();
                des(count++) = abs_vect.x();
                des(count++) = abs_vect.y();
            }
        }

        // Return the length normalized descriptor.  Add a small number
        // to guard against division by zero.
        const double len = length(des) + 1e-7;
        des = des/len;
    }

// ----------------------------------------------------------------------------------------

    template <typename image_type>
    const std::vector<surf_point> get_surf_points (
        const image_type& img,
        long max_points = 10000,
        double detection_threshold = 30.0
    )
    {
        DLIB_ASSERT(max_points > 0 && detection_threshold >= 0,
            "\t std::vector<surf_point> get_surf_points()"
            << "\n\t Invalid arguments were given to this function."
            << "\n\t max_points:          " << max_points
            << "\n\t detection_threshold: " << detection_threshold
        );

        // Figure out the proper scalar type we should use to work with these pixels.
        typedef typename pixel_traits<typename image_traits<image_type>::pixel_type>::basic_pixel_type bp_type;
        typedef typename promote<bp_type>::type working_pixel_type;

        // make an integral image first
        integral_image_generic<working_pixel_type> int_img;
        int_img.load(img);

        // now make a hessian pyramid
        hessian_pyramid pyr;
        pyr.build_pyramid(int_img, 4, 6, 2);

        // now get all the interest points from the hessian pyramid
        std::vector<interest_point> points;
        get_interest_points(pyr, detection_threshold, points);
        std::vector<surf_point> spoints;

        // sort all the points by how strong their detect is
        std::sort(points.rbegin(), points.rend());

        // now extract SURF descriptors for the points
        surf_point sp;
        for (unsigned long i = 0; i < std::min((size_t)max_points,points.size()); ++i)
        {
            // ignore points that are close to the edge of the image
            const double border = 32;
            const unsigned long border_size = static_cast<unsigned long>(border*points[i].scale);
            if (get_rect(int_img).contains(centered_rect(points[i].center, border_size, border_size)))
            {
                sp.angle = compute_dominant_angle(int_img, points[i].center, points[i].scale);
                compute_surf_descriptor(int_img, points[i].center, points[i].scale, sp.angle, sp.des);
                sp.p = points[i];

                spoints.push_back(sp);
            }
        }

        return spoints;
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SURf_H_


dlib C++ Library - image_loader.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_IMAGE_LOADEr_
#define DLIB_IMAGE_LOADEr_

#include "image_loader_abstract.h"
#include <iostream>
#include <sstream>
#include "../algs.h"
#include "../pixel.h"
#include "../image_saver/dng_shared.h"
#include "../entropy_decoder_model.h"
#include "../entropy_decoder.h"
#include "../uintn.h"
#include "../image_transforms/assign_image.h"
#include <algorithm>
#include "../vectorstream.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class image_load_error : public dlib::error {
    public: image_load_error(const std::string& str) : error(EIMAGE_LOAD,str){}
    };

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    void load_bmp (
        image_type& image_,
        std::istream& in_
    )
    {
        image_view<image_type> image(image_);
        try
        {
            unsigned long bytes_read_so_far = 0;
            unsigned long bfSize;
            unsigned long bfOffBits;
            unsigned long bfReserved;
            unsigned long biSize;
            unsigned long biWidth;
            unsigned long biHeight;
            unsigned short biBitCount;
            unsigned long biCompression;
            /*
            unsigned long biSizeImage;
            unsigned long biClrUsed;
            unsigned long biClrImportant;
            */
            unsigned long a, b, c, d, i;

            using namespace std;

            streambuf& in = *in_.rdbuf();
    //        streamsize num;
            unsigned char buf[100];

            // first make sure the BMP starts with BM
            if (in.sgetn(reinterpret_cast<char*>(buf),2) != 2)
                throw image_load_error("bmp load error 1: header error");
            bytes_read_so_far += 2;

            if (buf[0] != 'B' || buf[1] != 'M')
                throw image_load_error("bmp load error 2: header error");

            // now read the BITMAPFILEHEADER
            if (in.sgetn(reinterpret_cast<char*>(buf),12) != 12)
                throw image_load_error("bmp load error 3: header error");

            bytes_read_so_far += 12;

            i = 0;
            a = buf[i]; b = buf[i+1]; c = buf[i+2]; d = buf[i+3];
            bfSize = a | (b<<8) | (c<<16) | (d<<24);

            i = 4;
            a = buf[i]; b = buf[i+1]; c = buf[i+2]; d = buf[i+3];
            bfReserved = a | (b<<8) | (c<<16) | (d<<24);

            i = 8;
            a = buf[i]; b = buf[i+1]; c = buf[i+2]; d = buf[i+3];
            bfOffBits = a | (b<<8) | (c<<16) | (d<<24);

            // if this value isn't zero then there is something wrong
            // with this bitmap.
            if (bfReserved != 0)
                throw image_load_error("bmp load error 4: reserved area not zero");

            // load the BITMAPINFOHEADER
            if (in.sgetn(reinterpret_cast<char*>(buf),40) != 40)
                throw image_load_error("bmp load error 5: file too short");
            bytes_read_so_far += 40;

            i = 0;
            a = buf[i]; b = buf[i+1]; c = buf[i+2]; d = buf[i+3];
            biSize = a | (b<<8) | (c<<16) | (d<<24);

            i += 4;
            a = buf[i]; b = buf[i+1]; c = buf[i+2]; d = buf[i+3];
            biWidth = a | (b<<8) | (c<<16) | (d<<24);

            i += 4;
            a = buf[i]; b = buf[i+1]; c = buf[i+2]; d = buf[i+3];
            biHeight = a | (b<<8) | (c<<16) | (d<<24);

            i += 4+2;
            a = buf[i]; b = buf[i+1];
            biBitCount = static_cast<unsigned short>(a | (b<<8));

            i += 2;
            a = buf[i]; b = buf[i+1]; c = buf[i+2]; d = buf[i+3];
            biCompression = a | (b<<8) | (c<<16) | (d<<24);

            /*
            i += 4;
            a = buf[i]; b = buf[i+1]; c = buf[i+2]; d = buf[i+3];
            biSizeImage = a | (b<<8) | (c<<16) | (d<<24);

            i += 4+4+4;
            a = buf[i]; b = buf[i+1]; c = buf[i+2]; d = buf[i+3];
            biClrUsed = a | (b<<8) | (c<<16) | (d<<24);

            i += 4;
            a = buf[i]; b = buf[i+1]; c = buf[i+2]; d = buf[i+3];
            biClrImportant = a | (b<<8) | (c<<16) | (d<<24);
            */

            if (biSize != 40)
                throw image_load_error("bmp load error 6: header too small");

            // read and discard any extra bytes that are part of the header
            if (biSize > 40)
            {
                if (in.sgetn(reinterpret_cast<char*>(buf),biSize-40) != static_cast<long>(biSize - 40))
                {
                    throw image_load_error("bmp load error 7: header too small");
                }
                bytes_read_so_far += biSize-40;
            }

            image.set_size(biHeight, biWidth);

            switch (biBitCount)
            {
                case 1:
                    {
                        // figure out how the pixels are packed
                        long padding;
                        if (bfSize - bfOffBits == biWidth*biHeight/8)
                            padding = 0;
                        else
                            padding = 4 - ((biWidth+7)/8)%4;

                        const unsigned int palette_size = 2;
                        unsigned char red[palette_size];
                        unsigned char green[palette_size];
                        unsigned char blue[palette_size];

                        for (unsigned int i = 0; i < palette_size; ++i)
                        {
                            if (in.sgetn(reinterpret_cast<char*>(buf),4) != 4)
                            {
                                throw image_load_error("bmp load error 20: color palette missing");
                            }
                            bytes_read_so_far += 4;
                            blue[i] = buf[0];
                            green[i] = buf[1];
                            red[i] = buf[2];
                        }

                        // seek to the start of the pixel data
                        while (bytes_read_so_far != bfOffBits)
                        {
                            const long to_read = (long)std::min(bfOffBits - bytes_read_so_far, (unsigned long)sizeof(buf));
                            if (in.sgetn(reinterpret_cast<char*>(buf), to_read) != to_read)
                            {
                                throw image_load_error("bmp load error: missing data");
                            }
                            bytes_read_so_far += to_read;
                        }

                        // load the image data
                        for (long row = biHeight-1; row >= 0; --row)
                        {
                            for (unsigned long col = 0; col < biWidth; col+=8)
                            {
                                if (in.sgetn(reinterpret_cast<char*>(buf),1) != 1)
                                {
                                    throw image_load_error("bmp load error 21.6: file too short");
                                }

                                unsigned char pixels[8];

                                pixels[0] = (buf[0]>>7);
                                pixels[1] = ((buf[0]>>6)&0x01);
                                pixels[2] = ((buf[0]>>5)&0x01);
                                pixels[3] = ((buf[0]>>4)&0x01);
                                pixels[4] = ((buf[0]>>3)&0x01);
                                pixels[5] = ((buf[0]>>2)&0x01);
                                pixels[6] = ((buf[0]>>1)&0x01);
                                pixels[7] = ((buf[0])&0x01);

                                for (int i = 0; i < 8 && col+i < biWidth; ++i)
                                {
                                    rgb_pixel p;
                                    p.red   = red[pixels[i]];
                                    p.green = green[pixels[i]];
                                    p.blue  = blue[pixels[i]];
                                    assign_pixel(image[row][col+i],p);
                                }
                            }
                            if (in.sgetn(reinterpret_cast<char*>(buf),padding) != padding)
                                throw image_load_error("bmp load error 9: file too short");
                        }

                    } break;
                case 4:
                    {
                        // figure out how the pixels are packed
                        long padding;
                        if (bfSize - bfOffBits == biWidth*biHeight/2)
                            padding = 0;
                        else
                            padding = 4 - ((biWidth+1)/2)%4;

                        const unsigned int palette_size = 16;
                        unsigned char red[palette_size];
                        unsigned char green[palette_size];
                        unsigned char blue[palette_size];

                        for (unsigned int i = 0; i < palette_size; ++i)
                        {
                            if (in.sgetn(reinterpret_cast<char*>(buf),4) != 4)
                            {
                                throw image_load_error("bmp load error 20: color palette missing");
                            }
                            bytes_read_so_far += 4;
                            blue[i] = buf[0];
                            green[i] = buf[1];
                            red[i] = buf[2];
                        }

                        // seek to the start of the pixel data
                        while (bytes_read_so_far != bfOffBits)
                        {
                            const long to_read = (long)std::min(bfOffBits - bytes_read_so_far, (unsigned long)sizeof(buf));
                            if (in.sgetn(reinterpret_cast<char*>(buf), to_read) != to_read)
                            {
                                throw image_load_error("bmp load error: missing data");
                            }
                            bytes_read_so_far += to_read;
                        }

                        // load the image data
                        for (long row = biHeight-1; row >= 0; --row)
                        {
                            for (unsigned long col = 0; col < biWidth; col+=2)
                            {
                                if (in.sgetn(reinterpret_cast<char*>(buf),1) != 1)
                                {
                                    throw image_load_error("bmp load error 21.7: file too short");
                                }

                                const unsigned char pixel1 = (buf[0]>>4);
                                const unsigned char pixel2 = (buf[0]&0x0F);

                                rgb_pixel p;
                                p.red = red[pixel1];
                                p.green = green[pixel1];
                                p.blue = blue[pixel1];
                                assign_pixel(image[row][col], p);

                                if (col+1 < biWidth)
                                {
                                    p.red   = red[pixel2];
                                    p.green = green[pixel2];
                                    p.blue  = blue[pixel2];
                                    assign_pixel(image[row][col+1], p);
                                }
                            }
                            if (in.sgetn(reinterpret_cast<char*>(buf),padding) != padding)
                                throw image_load_error("bmp load error 9: file too short");
                        }

                    } break;
                case 8:
                    {
                        // figure out how the pixels are packed
                        long padding;
                        if (bfSize - bfOffBits == biWidth*biHeight)
                            padding = 0;
                        else
                            padding = 4 - biWidth%4;

                        // check for this case.  It shouldn't happen but some BMP writers screw up the files
                        // so we have to do this.
                        if (biHeight*(biWidth+padding) > bfSize - bfOffBits)
                            padding = 0;

                        const unsigned int palette_size = 256;
                        unsigned char red[palette_size];
                        unsigned char green[palette_size];
                        unsigned char blue[palette_size];

                        for (unsigned int i = 0; i < palette_size; ++i)
                        {
                            if (in.sgetn(reinterpret_cast<char*>(buf),4) != 4)
                            {
                                throw image_load_error("bmp load error 20: color palette missing");
                            }
                            bytes_read_so_far += 4;
                            blue[i] = buf[0];
                            green[i] = buf[1];
                            red[i] = buf[2];
                        }

                        // seek to the start of the pixel data
                        while (bytes_read_so_far != bfOffBits)
                        {
                            const long to_read = (long)std::min(bfOffBits - bytes_read_so_far, (unsigned long)sizeof(buf));
                            if (in.sgetn(reinterpret_cast<char*>(buf), to_read) != to_read)
                            {
                                throw image_load_error("bmp load error: missing data");
                            }
                            bytes_read_so_far += to_read;
                        }

                        // Next we load the image data.

                        // if there is no RLE compression
                        if (biCompression == 0)
                        {
                            for (long row = biHeight-1; row >= 0; --row)
                            {
                                for (unsigned long col = 0; col < biWidth; ++col)
                                {
                                    if (in.sgetn(reinterpret_cast<char*>(buf),1) != 1)
                                    {
                                        throw image_load_error("bmp load error 21.8: file too short");
                                    }

                                    rgb_pixel p;
                                    p.red   = red[buf[0]];
                                    p.green = green[buf[0]];
                                    p.blue  = blue[buf[0]];
                                    assign_pixel(image[row][col],p);
                                }
                                if (in.sgetn(reinterpret_cast<char*>(buf),padding) != padding)
                                    throw image_load_error("bmp load error 9: file too short");
                            }
                        }
                        else
                        {
                            // Here we deal with the psychotic RLE used by BMP files.

                            // First zero the image since the RLE sometimes jumps over
                            // pixels and assumes the image has been zero initialized.
                            assign_all_pixels(image, 0);

                            long row = biHeight-1;
                            long col = 0;
                            while (true)
                            {
                                if (in.sgetn(reinterpret_cast<char*>(buf),2) != 2)
                                {
                                    throw image_load_error("bmp load error 21.9: file too short");
                                }

                                const unsigned char count = buf[0];
                                const unsigned char command = buf[1];

                                if (count == 0 && command == 0)
                                {
                                    // This is an escape code that means go to the next row
                                    // of the image
                                    --row;
                                    col = 0;
                                    continue;
                                }
                                else if (count == 0 && command == 1)
                                {
                                    // This is the end of the image.  So quit this loop.
                                    break;
                                }
                                else if (count == 0 && command == 2)
                                {
                                    // This is the escape code for the command to jump to
                                    // a new part of the image relative to where we are now.
                                    if (in.sgetn(reinterpret_cast<char*>(buf),2) != 2)
                                    {
                                        throw image_load_error("bmp load error 21.1: file too short");
                                    }
                                    col += buf[0];
                                    row -= buf[1];
                                    continue;
                                }
                                else if (count == 0)
                                {
                                    // This is the escape code for a run of uncompressed bytes

                                    if (row < 0 || col + command > image.nc())
                                    {
                                        // If this is just some padding bytes at the end then ignore them
                                        if (row >= 0 && col + count <= image.nc() + padding)
                                            continue;

                                        throw image_load_error("bmp load error 21.2: file data corrupt");
                                    }

                                    // put the bytes into the image
                                    for (unsigned int i = 0; i < command; ++i)
                                    {
                                        if (in.sgetn(reinterpret_cast<char*>(buf),1) != 1)
                                        {
                                            throw image_load_error("bmp load error 21.3: file too short");
                                        }
                                        rgb_pixel p;
                                        p.red   = red[buf[0]];
                                        p.green = green[buf[0]];
                                        p.blue  = blue[buf[0]];
                                        assign_pixel(image[row][col],p);

                                        ++col;
                                    }

                                    // if we read an uneven number of bytes then we need to read and
                                    // discard the next byte.
                                    if ((command&1) != 1)
                                    {
                                        if (in.sgetn(reinterpret_cast<char*>(buf),1) != 1)
                                        {
                                            throw image_load_error("bmp load error 21.4: file too short");
                                        }
                                    }

                                    continue;
                                }

                                rgb_pixel p;

                                if (row < 0 || col + count > image.nc())
                                {
                                    // If this is just some padding bytes at the end then ignore them
                                    if (row >= 0 && col + count <= image.nc() + padding)
                                        continue;

                                    throw image_load_error("bmp load error 21.5: file data corrupt");
                                }

                                // put the bytes into the image
                                for (unsigned int i = 0; i < count; ++i)
                                {
                                    p.red   = red[command];
                                    p.green = green[command];
                                    p.blue  = blue[command];
                                    assign_pixel(image[row][col],p);

                                    ++col;
                                }
                            }
                        }

                    }
                    break;
                case 16:
                    throw image_load_error ("16 bit BMP images not supported");
                case 24:
                    {
                        // figure out how the pixels are packed
                        long padding;
                        if (bfSize - bfOffBits == biWidth*biHeight*3)
                            padding = 0;
                        else
                            padding = 4 - (biWidth*3)%4;

                        // check for this case.  It shouldn't happen but some BMP writers screw up the files
                        // so we have to do this.
                        if (biHeight*(biWidth*3+padding) > bfSize - bfOffBits)
                            padding = 0;

                        // seek to the start of the pixel data
                        while (bytes_read_so_far != bfOffBits)
                        {
                            const long to_read = (long)std::min(bfOffBits - bytes_read_so_far, (unsigned long)sizeof(buf));
                            if (in.sgetn(reinterpret_cast<char*>(buf), to_read) != to_read)
                            {
                                throw image_load_error("bmp load error: missing data");
                            }
                            bytes_read_so_far += to_read;
                        }

                        // load the image data
                        for (long row = biHeight-1; row >= 0; --row)
                        {
                            for (unsigned long col = 0; col < biWidth; ++col)
                            {
                                if (in.sgetn(reinterpret_cast<char*>(buf),3) != 3)
                                {
                                    throw image_load_error("bmp load error 8: file too short");
                                }

                                rgb_pixel p;
                                p.red = buf[2];
                                p.green = buf[1];
                                p.blue = buf[0];
                                assign_pixel(image[row][col], p);

                            }
                            if (in.sgetn(reinterpret_cast<char*>(buf),padding) != padding)
                                throw image_load_error("bmp load error 9: file too short");
                        }

                        break;
                    }
                case 32:
                    throw image_load_error ("32 bit BMP images not supported");
                default:
                    throw image_load_error("bmp load error 10: unknown color depth");

            }
        }
        catch (...)
        {
            image.clear();
            throw;
        }

    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    void load_dng (
        image_type& image_,
        std::istream& in
    )
    {
        image_view<image_type> image(image_);
        using namespace dng_helpers_namespace;
        try
        {
            if (in.get() != 'D' || in.get() != 'N' || in.get() != 'G')
                throw image_load_error("the stream does not contain a dng image file");

            unsigned long version;
            deserialize(version,in);
            if (version != 1)
                throw image_load_error("You need the new version of the dlib library to read this dng file");

            unsigned long type;
            deserialize(type,in);

            long width, height;
            deserialize(width,in);
            deserialize(height,in);

            if (width > 0 && height > 0)
                image.set_size(height,width);
            else
                image.clear();

            if (type != grayscale_float)
            {
                typedef entropy_decoder::kernel_2a decoder_type;
                decoder_type decoder;
                decoder.set_stream(in);

                entropy_decoder_model<256,decoder_type>::kernel_5a edm(decoder);
                unsigned long symbol;
                rgb_pixel p_rgb;
                rgb_alpha_pixel p_rgba;
                hsi_pixel p_hsi;
                switch (type)
                {
                    case rgb_alpha_paeth:

                        for (long r = 0; r < image.nr(); ++r)
                        {
                            for (long c = 0; c < image.nc(); ++c)
                            {
                                p_rgba = predictor_rgb_alpha_paeth(image,r,c);
                                edm.decode(symbol);
                                p_rgba.red += static_cast<unsigned char>(symbol);

                                edm.decode(symbol);
                                p_rgba.green += static_cast<unsigned char>(symbol);

                                edm.decode(symbol);
                                p_rgba.blue += static_cast<unsigned char>(symbol);

                                edm.decode(symbol);
                                p_rgba.alpha += static_cast<unsigned char>(symbol);

                                assign_pixel(image[r][c],p_rgba);
                            }
                        }
                        break;

                    case rgb_alpha:

                        for (long r = 0; r < image.nr(); ++r)
                        {
                            for (long c = 0; c < image.nc(); ++c)
                            {
                                p_rgba = predictor_rgb_alpha(image,r,c);
                                edm.decode(symbol);
                                p_rgba.red += static_cast<unsigned char>(symbol);

                                edm.decode(symbol);
                                p_rgba.green += static_cast<unsigned char>(symbol);

                                edm.decode(symbol);
                                p_rgba.blue += static_cast<unsigned char>(symbol);

                                edm.decode(symbol);
                                p_rgba.alpha += static_cast<unsigned char>(symbol);

                                assign_pixel(image[r][c],p_rgba);
                            }
                        }
                        break;

                    case rgb_paeth:

                        for (long r = 0; r < image.nr(); ++r)
                        {
                            for (long c = 0; c < image.nc(); ++c)
                            {
                                p_rgb = predictor_rgb_paeth(image,r,c);
                                edm.decode(symbol);
                                p_rgb.red += static_cast<unsigned char>(symbol);

                                edm.decode(symbol);
                                p_rgb.green += static_cast<unsigned char>(symbol);

                                edm.decode(symbol);
                                p_rgb.blue += static_cast<unsigned char>(symbol);

                                assign_pixel(image[r][c],p_rgb);
                            }
                        }
                        break;

                    case rgb:

                        for (long r = 0; r < image.nr(); ++r)
                        {
                            for (long c = 0; c < image.nc(); ++c)
                            {
                                p_rgb = predictor_rgb(image,r,c);
                                edm.decode(symbol);
                                p_rgb.red += static_cast<unsigned char>(symbol);

                                edm.decode(symbol);
                                p_rgb.green += static_cast<unsigned char>(symbol);

                                edm.decode(symbol);
                                p_rgb.blue += static_cast<unsigned char>(symbol);

                                assign_pixel(image[r][c],p_rgb);
                            }
                        }
                        break;

                    case hsi:

                        for (long r = 0; r < image.nr(); ++r)
                        {
                            for (long c = 0; c < image.nc(); ++c)
                            {
                                p_hsi = predictor_hsi(image,r,c);
                                edm.decode(symbol);
                                p_hsi.h += static_cast<unsigned char>(symbol);

                                edm.decode(symbol);
                                p_hsi.s += static_cast<unsigned char>(symbol);

                                edm.decode(symbol);
                                p_hsi.i += static_cast<unsigned char>(symbol);

                                assign_pixel(image[r][c],p_hsi);
                            }
                        }
                        break;

                    case grayscale:
                        {
                            unsigned char p;
                            for (long r = 0; r < image.nr(); ++r)
                            {
                                for (long c = 0; c < image.nc(); ++c)
                                {
                                    edm.decode(symbol);
                                    p = static_cast<unsigned char>(symbol);
                                    p +=  predictor_grayscale(image,r,c);
                                    assign_pixel(image[r][c],p);
                                }
                            }
                        }
                        break;

                    case grayscale_16bit:
                        {
                            uint16 p;
                            for (long r = 0; r < image.nr(); ++r)
                            {
                                for (long c = 0; c < image.nc(); ++c)
                                {
                                    edm.decode(symbol);
                                    p = static_cast<uint16>(symbol);
                                    p <<= 8;
                                    edm.decode(symbol);
                                    p |= static_cast<uint16>(symbol);

                                    p +=  predictor_grayscale_16(image,r,c);
                                    assign_pixel(image[r][c],p);
                                }
                            }
                        }
                        break;

                    default:
                        throw image_load_error("corruption detected in the dng file");
                } // switch (type)

                edm.decode(symbol);
                if (symbol != dng_magic_byte)
                    throw image_load_error("corruption detected in the dng file");
                edm.decode(symbol);
                if (symbol != dng_magic_byte)
                    throw image_load_error("corruption detected in the dng file");
                edm.decode(symbol);
                if (symbol != dng_magic_byte)
                    throw image_load_error("corruption detected in the dng file");
                edm.decode(symbol);
                if (symbol != dng_magic_byte)
                    throw image_load_error("corruption detected in the dng file");
            }
            else // if this is a grayscale_float type image
            {
                std::vector<int64> man(image.size());
                std::vector<char> expbuf;
                // get the mantissa data
                for (unsigned long j = 0; j < man.size(); ++j)
                    deserialize(man[j], in);
                // get the compressed exponent data
                deserialize(expbuf, in);
                typedef entropy_decoder::kernel_2a decoder_type;
                typedef entropy_decoder_model<256,decoder_type>::kernel_4a edm_exp_type;
                vectorstream inexp(expbuf);
                decoder_type decoder;
                decoder.set_stream(inexp);

                edm_exp_type edm_exp(decoder);
                float_details prev;
                unsigned long i = 0;
                // fill out the image
                for (long r = 0; r < image.nr(); ++r)
                {
                    for (long c = 0; c < image.nc(); ++c)
                    {
                        unsigned long exp1, exp2;
                        edm_exp.decode(exp1);
                        edm_exp.decode(exp2);

                        float_details cur(man[i++],(exp2<<8) | exp1);
                        cur.exponent += prev.exponent;
                        cur.mantissa += prev.mantissa;
                        prev = cur;

                        // Only use long double precision if the target image contains long
                        // doubles because it's slower to use those.
                        if (!is_same_type<typename image_traits<image_type>::pixel_type,long double>::value)
                        {
                            double temp = cur;
                            assign_pixel(image[r][c],temp);
                        }
                        else
                        {
                            long double temp = cur;
                            assign_pixel(image[r][c],temp);
                        }
                    }
                }
                unsigned long symbol;
                edm_exp.decode(symbol);
                if (symbol != dng_magic_byte)
                    throw image_load_error("corruption detected in the dng file");
                edm_exp.decode(symbol);
                if (symbol != dng_magic_byte)
                    throw image_load_error("corruption detected in the dng file");
                edm_exp.decode(symbol);
                if (symbol != dng_magic_byte)
                    throw image_load_error("corruption detected in the dng file");
                edm_exp.decode(symbol);
                if (symbol != dng_magic_byte)
                    throw image_load_error("corruption detected in the dng file");
            }
        }
        catch (...)
        {
            image.clear();
            throw;
        }

    }

// ----------------------------------------------------------------------------------------

    template <typename image_type>
    void load_bmp (
        image_type& image,
        const std::string& file_name
    )
    {
        std::ifstream fin(file_name.c_str(), std::ios::binary);
        if (!fin)
            throw image_load_error("Unable to open " + file_name + " for reading.");
        load_bmp(image, fin);
    }

// ----------------------------------------------------------------------------------------

    template <typename image_type>
    void load_dng (
        image_type& image,
        const std::string& file_name
    )
    {
        std::ifstream fin(file_name.c_str(), std::ios::binary);
        if (!fin)
            throw image_load_error("Unable to open " + file_name + " for reading.");
        load_dng(image, fin);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_IMAGE_LOADEr_


dlib C++ Library - jpeg_loader.cpp

// Copyright (C) 2010  Davis E. King (davis@dlib.net), Nils Labugt
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_JPEG_LOADER_CPp_
#define DLIB_JPEG_LOADER_CPp_

// only do anything with this file if DLIB_JPEG_SUPPORT is defined
#ifdef DLIB_JPEG_SUPPORT

#include "../array2d.h"
#include "../pixel.h"
#include "../dir_nav.h"
#include "jpeg_loader.h"
#include <stdio.h>
#ifdef DLIB_JPEG_STATIC
#   include "../external/libjpeg/jpeglib.h"
#else
#   include <jpeglib.h>
#endif
#include <sstream>
#include <setjmp.h>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    jpeg_loader::
    jpeg_loader( const char* filename ) : height_( 0 ), width_( 0 ), output_components_(0)
    {
        read_image( filename );
    }

// ----------------------------------------------------------------------------------------

    jpeg_loader::
    jpeg_loader( const std::string& filename ) : height_( 0 ), width_( 0 ), output_components_(0)
    {
        read_image( filename.c_str() );
    }

// ----------------------------------------------------------------------------------------

    jpeg_loader::
    jpeg_loader( const dlib::file& f ) : height_( 0 ), width_( 0 ), output_components_(0)
    {
        read_image( f.full_name().c_str() );
    }

// ----------------------------------------------------------------------------------------

    bool jpeg_loader::is_gray() const
    {
        return (output_components_ == 1);
    }

// ----------------------------------------------------------------------------------------

    bool jpeg_loader::is_rgb() const
    {
        return (output_components_ == 3);
    }

// ----------------------------------------------------------------------------------------

    struct jpeg_loader_error_mgr
    {
        jpeg_error_mgr pub;    /* "public" fields */
        jmp_buf setjmp_buffer;  /* for return to caller */
    };

    void jpeg_loader_error_exit (j_common_ptr cinfo)
    {
        /* cinfo->err really points to a jpeg_loader_error_mgr struct, so coerce pointer */
        jpeg_loader_error_mgr* myerr = (jpeg_loader_error_mgr*) cinfo->err;

        /* Return control to the setjmp point */
        longjmp(myerr->setjmp_buffer, 1);
    }

// ----------------------------------------------------------------------------------------

    void jpeg_loader::read_image( const char* filename )
    {
        if ( filename == NULL )
        {
            throw image_load_error("jpeg_loader: invalid filename, it is NULL");
        }
        FILE *fp = fopen( filename, "rb" );
        if ( !fp )
        {
            throw image_load_error(std::string("jpeg_loader: unable to open file ") + filename);
        }

        jpeg_decompress_struct cinfo;
        jpeg_loader_error_mgr jerr;

        cinfo.err = jpeg_std_error(&jerr.pub);

        jerr.pub.error_exit = jpeg_loader_error_exit;

        /* Establish the setjmp return context for my_error_exit to use. */
        if (setjmp(jerr.setjmp_buffer))
        {
            /* If we get here, the JPEG code has signaled an error.
             * We need to clean up the JPEG object, close the input file, and return.
             */
            jpeg_destroy_decompress(&cinfo);
            fclose(fp);
            throw image_load_error(std::string("jpeg_loader: error while reading ") + filename);
        }

        jpeg_create_decompress(&cinfo);

        jpeg_stdio_src(&cinfo, fp);

        jpeg_read_header(&cinfo, TRUE);

        jpeg_start_decompress(&cinfo);

        height_ = cinfo.output_height;
        width_ = cinfo.output_width;
        output_components_ = cinfo.output_components;

        if (output_components_ != 1 &&
            output_components_ != 3)
        {
            fclose( fp );
            jpeg_destroy_decompress(&cinfo);
            std::ostringstream sout;
            sout << "jpeg_loader: Unsupported number of colors (" << output_components_ << ") in file " << filename;
            throw image_load_error(sout.str());
        }

        std::vector<unsigned char*> rows;
        rows.resize(height_);

        // size the image buffer
        data.resize(height_*width_*output_components_);

        // setup pointers to each row
        for (unsigned long i = 0; i < rows.size(); ++i)
            rows[i] = &data[i*width_*output_components_];

        // read the data into the buffer
        while (cinfo.output_scanline < cinfo.output_height)
        {
            jpeg_read_scanlines(&cinfo, &rows[cinfo.output_scanline], 100);
        }

        jpeg_finish_decompress(&cinfo);
        jpeg_destroy_decompress(&cinfo);

        fclose( fp );
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_JPEG_SUPPORT

#endif // DLIB_JPEG_LOADER_CPp_


dlib C++ Library - jpeg_loader.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net), Nils Labugt
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_JPEG_IMPORT
#define DLIB_JPEG_IMPORT

#include "jpeg_loader_abstract.h"
#include "../smart_pointers.h"
#include "image_loader.h"
#include "../pixel.h"
#include "../dir_nav.h"
#include <vector>

namespace dlib
{

    class jpeg_loader : noncopyable
    {
    public:

        jpeg_loader( const char* filename );
        jpeg_loader( const std::string& filename );
        jpeg_loader( const dlib::file& f );

        bool is_gray() const;
        bool is_rgb() const;

        template<typename T>
        void get_image( T& t_) const
        {
#ifndef DLIB_JPEG_SUPPORT
            /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                You are getting this error because you are trying to use the jpeg_loader
                object but you haven't defined DLIB_JPEG_SUPPORT.  You must do so to use
                this object.   You must also make sure you set your build environment
                to link against the libjpeg library.
            !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
            COMPILE_TIME_ASSERT(sizeof(T) == 0);
#endif
            image_view<T> t(t_);

            t.set_size( height_, width_ );
            for ( unsigned n = 0; n < height_;n++ )
            {
                const unsigned char* v = get_row( n );
                for ( unsigned m = 0; m < width_;m++ )
                {
                    if ( is_gray() )
                    {
                        unsigned char p = v[m];
                        assign_pixel( t[n][m], p );
                    }
                    else // if ( is_rgb() )
                    {
                        rgb_pixel p;
                        p.red = v[m*3];
                        p.green = v[m*3+1];
                        p.blue = v[m*3+2];
                        assign_pixel( t[n][m], p );
                    }
                }
            }
        }

    private:
        const unsigned char* get_row( unsigned long i ) const
        {
            return &data[i*width_*output_components_];
        }

        void read_image( const char* filename );
        unsigned long height_;
        unsigned long width_;
        unsigned long output_components_;
        std::vector<unsigned char> data;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    void load_jpeg (
        image_type& image,
        const std::string& file_name
    )
    {
        jpeg_loader(file_name).get_image(image);
    }

// ----------------------------------------------------------------------------------------

}

#ifdef NO_MAKEFILE
#include "jpeg_loader.cpp"
#endif

#endif // DLIB_JPEG_IMPORT


dlib C++ Library - png_loader.cpp

// Copyright (C) 2008  Davis E. King (davis@dlib.net), Nils Labugt
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_PNG_LOADER_CPp_
#define DLIB_PNG_LOADER_CPp_

// only do anything with this file if DLIB_PNG_SUPPORT is defined
#ifdef DLIB_PNG_SUPPORT

#include "../array2d.h"
#include "../pixel.h"
#include "../dir_nav.h"
#include "png_loader.h"
#include <png.h>
#include "../string.h"
#include "../byte_orderer.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    struct LibpngData
    {
        png_bytep* row_pointers_;
        png_structp png_ptr_;
        png_infop info_ptr_;
        png_infop end_info_;
    };

// ----------------------------------------------------------------------------------------

    png_loader::
    png_loader( const char* filename ) : height_( 0 ), width_( 0 )
    {
        read_image( filename );
    }

// ----------------------------------------------------------------------------------------

    png_loader::
    png_loader( const std::string& filename ) : height_( 0 ), width_( 0 )
    {
        read_image( filename.c_str() );
    }

// ----------------------------------------------------------------------------------------

    png_loader::
    png_loader( const dlib::file& f ) : height_( 0 ), width_( 0 )
    {
        read_image( f.full_name().c_str() );
    }

// ----------------------------------------------------------------------------------------

    const unsigned char* png_loader::get_row( unsigned i ) const
    {
        return ld_->row_pointers_[i];
    }

// ----------------------------------------------------------------------------------------

    png_loader::~png_loader()
    {
        if ( ld_ && ld_->row_pointers_ != NULL )
            png_destroy_read_struct( &( ld_->png_ptr_ ), &( ld_->info_ptr_ ), &( ld_->end_info_ ) );
    }

// ----------------------------------------------------------------------------------------

    bool png_loader::is_gray() const
    {
        return ( color_type_ == PNG_COLOR_TYPE_GRAY );
    }

// ----------------------------------------------------------------------------------------

    bool png_loader::is_graya() const
    {
        return ( color_type_ == PNG_COLOR_TYPE_GRAY_ALPHA );
    }

// ----------------------------------------------------------------------------------------

    bool png_loader::is_rgb() const
    {
        return ( color_type_ == PNG_COLOR_TYPE_RGB );
    }

// ----------------------------------------------------------------------------------------

    bool png_loader::is_rgba() const
    {
        return ( color_type_ == PNG_COLOR_TYPE_RGB_ALPHA );
    }

// ----------------------------------------------------------------------------------------

    // Don't do anything when libpng calls us to tell us about an error.  Just return to
    // our own code and throw an exception (at the long jump target).
    void png_loader_user_error_fn_silent(png_structp  png_struct, png_const_charp )
    {
        longjmp(png_jmpbuf(png_struct),1);
    }
    void png_loader_user_warning_fn_silent(png_structp , png_const_charp )
    {
    }

    void png_loader::read_image( const char* filename )
    {
        ld_.reset(new LibpngData);
        if ( filename == NULL )
        {
            throw image_load_error("png_loader: invalid filename, it is NULL");
        }
        FILE *fp = fopen( filename, "rb" );
        if ( !fp )
        {
            throw image_load_error(std::string("png_loader: unable to open file ") + filename);
        }
        png_byte sig[8];
        if (fread( sig, 1, 8, fp ) != 8)
        {
            fclose( fp );
            throw image_load_error(std::string("png_loader: error reading file ") + filename);
        }
        if ( png_sig_cmp( sig, 0, 8 ) != 0 )
        {
            fclose( fp );
            throw image_load_error(std::string("png_loader: format error in file ") + filename);
        }
        ld_->png_ptr_ = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, &png_loader_user_error_fn_silent, &png_loader_user_warning_fn_silent );
        if ( ld_->png_ptr_ == NULL )
        {
            fclose( fp );
            throw image_load_error(std::string("png_loader: parse error in file ") + filename);
        }
        ld_->info_ptr_ = png_create_info_struct( ld_->png_ptr_ );
        if ( ld_->info_ptr_ == NULL )
        {
            fclose( fp );
            png_destroy_read_struct( &( ld_->png_ptr_ ), ( png_infopp )NULL, ( png_infopp )NULL );
            throw image_load_error(std::string("png_loader: parse error in file ") + filename);
        }
        ld_->end_info_ = png_create_info_struct( ld_->png_ptr_ );
        if ( ld_->end_info_ == NULL )
        {
            fclose( fp );
            png_destroy_read_struct( &( ld_->png_ptr_ ), &( ld_->info_ptr_ ), ( png_infopp )NULL );
            throw image_load_error(std::string("png_loader: parse error in file ") + filename);
        }

        if (setjmp(png_jmpbuf(ld_->png_ptr_)))
        {
            // If we get here, we had a problem writing the file
            fclose(fp);
            png_destroy_read_struct( &( ld_->png_ptr_ ), &( ld_->info_ptr_ ), &( ld_->end_info_ ) );
            throw image_load_error(std::string("png_loader: parse error in file ") + filename);
        }

        png_set_palette_to_rgb(ld_->png_ptr_);

        png_init_io( ld_->png_ptr_, fp );
        png_set_sig_bytes( ld_->png_ptr_, 8 );
        // flags force one byte per channel output
        byte_orderer bo;
        int png_transforms = PNG_TRANSFORM_PACKING;
        if (bo.host_is_little_endian())
            png_transforms |= PNG_TRANSFORM_SWAP_ENDIAN;
        png_read_png( ld_->png_ptr_, ld_->info_ptr_, png_transforms, NULL );
        height_ = png_get_image_height( ld_->png_ptr_, ld_->info_ptr_ );
        width_ = png_get_image_width( ld_->png_ptr_, ld_->info_ptr_ );
        bit_depth_ = png_get_bit_depth( ld_->png_ptr_, ld_->info_ptr_ );
        color_type_ = png_get_color_type( ld_->png_ptr_, ld_-> info_ptr_ );

        if (color_type_ != PNG_COLOR_TYPE_GRAY &&
            color_type_ != PNG_COLOR_TYPE_RGB &&
            color_type_ != PNG_COLOR_TYPE_RGB_ALPHA &&
            color_type_ != PNG_COLOR_TYPE_GRAY_ALPHA)
        {
            fclose( fp );
            png_destroy_read_struct( &( ld_->png_ptr_ ), &( ld_->info_ptr_ ), &( ld_->end_info_ ) );
            throw image_load_error(std::string("png_loader: unsupported color type in file ") + filename);
        }

        if (bit_depth_ != 8 && bit_depth_ != 16)
        {
            fclose( fp );
            png_destroy_read_struct( &( ld_->png_ptr_ ), &( ld_->info_ptr_ ), &( ld_->end_info_ ) );
            throw image_load_error("png_loader: unsupported bit depth of " + cast_to_string(bit_depth_) + " in file " + std::string(filename));
        }

        ld_->row_pointers_ = png_get_rows( ld_->png_ptr_, ld_->info_ptr_ );

        fclose( fp );
        if ( ld_->row_pointers_ == NULL )
        {
            png_destroy_read_struct( &( ld_->png_ptr_ ), &( ld_->info_ptr_ ), &( ld_->end_info_ ) );
            throw image_load_error(std::string("png_loader: parse error in file ") + filename);
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_PNG_SUPPORT

#endif // DLIB_PNG_LOADER_CPp_


dlib C++ Library - png_loader.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net), Nils Labugt
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_PNG_IMPORT
#define DLIB_PNG_IMPORT

#include "png_loader_abstract.h"
#include "../smart_pointers.h"
#include "image_loader.h"
#include "../pixel.h"
#include "../dir_nav.h"

namespace dlib
{

    struct LibpngData;
    class png_loader : noncopyable
    {
    public:

        png_loader( const char* filename );
        png_loader( const std::string& filename );
        png_loader( const dlib::file& f );
        ~png_loader();

        bool is_gray() const;
        bool is_graya() const;
        bool is_rgb() const;
        bool is_rgba() const;

        unsigned int bit_depth () const { return bit_depth_; }

        template<typename T>
        void get_image( T& t_) const
        {
#ifndef DLIB_PNG_SUPPORT
            /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                You are getting this error because you are trying to use the png_loader
                object but you haven't defined DLIB_PNG_SUPPORT.  You must do so to use
                this object.   You must also make sure you set your build environment
                to link against the libpng library.
            !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
            COMPILE_TIME_ASSERT(sizeof(T) == 0);
#endif

            typedef typename image_traits<T>::pixel_type pixel_type;
            image_view<T> t(t_);
            t.set_size( height_, width_ );

            if (is_gray() && bit_depth_ == 8)
            {
                for ( unsigned n = 0; n < height_;n++ )
                {
                    const unsigned char* v = get_row( n );
                    for ( unsigned m = 0; m < width_;m++ )
                    {
                        unsigned char p = v[m];
                        assign_pixel( t[n][m], p );
                    }
                }
            }
            else if (is_gray() && bit_depth_ == 16)
            {
                for ( unsigned n = 0; n < height_;n++ )
                {
                    const uint16* v = (uint16*)get_row( n );
                    for ( unsigned m = 0; m < width_;m++ )
                    {
                        dlib::uint16 p = v[m];
                        assign_pixel( t[n][m], p );
                    }
                }
            }
            else if (is_graya() && bit_depth_ == 8)
            {
                for ( unsigned n = 0; n < height_;n++ )
                {
                    const unsigned char* v = get_row( n );
                    for ( unsigned m = 0; m < width_; m++ )
                    {
                        unsigned char p = v[m*2];
                        if (!pixel_traits<pixel_type>::has_alpha)
                        {
                            assign_pixel( t[n][m], p );
                        }
                        else
                        {
                            unsigned char pa = v[m*2+1];
                            rgb_alpha_pixel pix;
                            assign_pixel(pix, p);
                            assign_pixel(pix.alpha, pa);
                            assign_pixel(t[n][m], pix);
                        }
                    }
                }
            }
            else if (is_graya() && bit_depth_ == 16)
            {
                for ( unsigned n = 0; n < height_;n++ )
                {
                    const uint16* v = (uint16*)get_row( n );
                    for ( unsigned m = 0; m < width_; m++ )
                    {
                        dlib::uint16 p = v[m*2];
                        if (!pixel_traits<pixel_type>::has_alpha)
                        {
                            assign_pixel( t[n][m], p );
                        }
                        else
                        {
                            dlib::uint16 pa = v[m*2+1];
                            rgb_alpha_pixel pix;
                            assign_pixel(pix, p);
                            assign_pixel(pix.alpha, pa);
                            assign_pixel(t[n][m], pix);
                        }
                    }
                }
            }
            else if (is_rgb() && bit_depth_ == 8)
            {
                for ( unsigned n = 0; n < height_;n++ )
                {
                    const unsigned char* v = get_row( n );
                    for ( unsigned m = 0; m < width_;m++ )
                    {
                        rgb_pixel p;
                        p.red = v[m*3];
                        p.green = v[m*3+1];
                        p.blue = v[m*3+2];
                        assign_pixel( t[n][m], p );
                    }
                }
            }
            else if (is_rgb() && bit_depth_ == 16)
            {
                for ( unsigned n = 0; n < height_;n++ )
                {
                    const uint16* v = (uint16*)get_row( n );
                    for ( unsigned m = 0; m < width_;m++ )
                    {
                        rgb_pixel p;
                        p.red   = static_cast<uint8>(v[m*3]);
                        p.green = static_cast<uint8>(v[m*3+1]);
                        p.blue  = static_cast<uint8>(v[m*3+2]);
                        assign_pixel( t[n][m], p );
                    }
                }
            }
            else if (is_rgba() && bit_depth_ == 8)
            {
                if (!pixel_traits<pixel_type>::has_alpha)
                    assign_all_pixels(t,0);

                for ( unsigned n = 0; n < height_;n++ )
                {
                    const unsigned char* v = get_row( n );
                    for ( unsigned m = 0; m < width_;m++ )
                    {
                        rgb_alpha_pixel p;
                        p.red = v[m*4];
                        p.green = v[m*4+1];
                        p.blue = v[m*4+2];
                        p.alpha = v[m*4+3];
                        assign_pixel( t[n][m], p );
                    }
                }
            }
            else if (is_rgba() && bit_depth_ == 16)
            {
                if (!pixel_traits<pixel_type>::has_alpha)
                    assign_all_pixels(t,0);

                for ( unsigned n = 0; n < height_;n++ )
                {
                    const uint16* v = (uint16*)get_row( n );
                    for ( unsigned m = 0; m < width_;m++ )
                    {
                        rgb_alpha_pixel p;
                        p.red   = static_cast<uint8>(v[m*4]);
                        p.green = static_cast<uint8>(v[m*4+1]);
                        p.blue  = static_cast<uint8>(v[m*4+2]);
                        p.alpha = static_cast<uint8>(v[m*4+3]);
                        assign_pixel( t[n][m], p );
                    }
                }
            }
        }

    private:
        const unsigned char* get_row( unsigned i ) const;
        void read_image( const char* filename );
        unsigned height_, width_;
        unsigned bit_depth_;
        int color_type_;
        scoped_ptr<LibpngData> ld_;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    void load_png (
        image_type& image,
        const std::string& file_name
    )
    {
        png_loader(file_name).get_image(image);
    }

// ----------------------------------------------------------------------------------------

}

#ifdef NO_MAKEFILE
#include "png_loader.cpp"
#endif

#endif // DLIB_PNG_IMPORT


dlib C++ Library - box_overlap_testing.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_BOX_OVERlAP_TESTING_Hh_
#define DLIB_BOX_OVERlAP_TESTING_Hh_

#include "box_overlap_testing_abstract.h"
#include "../geometry.h"
#include <vector>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class test_box_overlap
    {
    public:
        test_box_overlap (
        ) : match_thresh(0.5), overlap_thresh(1.0)
        {}

        explicit test_box_overlap (
            double match_thresh_,
            double overlap_thresh_ = 1.0
        ) : match_thresh(match_thresh_), overlap_thresh(overlap_thresh_)
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(0 <= match_thresh && match_thresh <= 1  &&
                        0 <= overlap_thresh && overlap_thresh <= 1,
                "\t test_box_overlap::test_box_overlap(match_thresh, overlap_thresh)"
                << "\n\t Invalid inputs were given to this function "
                << "\n\t match_thresh:   " << match_thresh
                << "\n\t overlap_thresh: " << overlap_thresh
                << "\n\t this: " << this
                );

        }

        bool operator() (
            const dlib::rectangle& a,
            const dlib::rectangle& b
        ) const
        {
            const double inner = a.intersect(b).area();
            if (inner == 0)
                return false;

            const double outer = (a+b).area();
            if (inner/outer > match_thresh ||
                inner/a.area() > overlap_thresh ||
                inner/b.area() > overlap_thresh)
                return true;
            else
                return false;
        }

        double get_overlap_thresh (
        ) const
        {
            return overlap_thresh;
        }

        double get_match_thresh (
        ) const
        {
            return match_thresh;
        }

    private:
        double match_thresh;
        double overlap_thresh;
    };

// ----------------------------------------------------------------------------------------

    inline void serialize (
        const test_box_overlap& item,
        std::ostream& out
    )
    {
        serialize(item.get_match_thresh(), out);
        serialize(item.get_overlap_thresh(), out);
    }

    inline void deserialize (
        test_box_overlap& item,
        std::istream& in
    )
    {
        double overlap_thresh, match_thresh;
        deserialize(match_thresh, in);
        deserialize(overlap_thresh, in);
        item = test_box_overlap(match_thresh, overlap_thresh);
    }

// ----------------------------------------------------------------------------------------

    inline test_box_overlap find_tight_overlap_tester (
        const std::vector<std::vector<rectangle> >& rects
    )
    {
        double max_overlap = 0;
        double max_match_score = 0;
        for (unsigned long i = 0; i < rects.size(); ++i)
        {
            for (unsigned long j = 0; j < rects[i].size(); ++j)
            {
                for (unsigned long k = j+1; k < rects[i].size(); ++k)
                {
                    const rectangle a = rects[i][j];
                    const rectangle b = rects[i][k];
                    const double match_score = (a.intersect(b)).area()/(double)(a+b).area();
                    const double overlap_a   = (a.intersect(b)).area()/(double)(a).area();
                    const double overlap_b   = (a.intersect(b)).area()/(double)(b).area();

                    if (match_score > max_match_score)
                        max_match_score = match_score;

                    if (overlap_a > max_overlap)
                        max_overlap = overlap_a;
                    if (overlap_b > max_overlap)
                        max_overlap = overlap_b;
                }
            }
        }

        // Relax these thresholds very slightly.  We do this because on some systems the
        // boxes that generated the max values erroneously trigger a box overlap match
        // even though their overlap and match values are *equal* to the thresholds but not
        // greater.  That is, sometimes when double values get moved around they change
        // their values slightly, so this avoids the problems that can create.
        max_match_score = std::min(1.0000001*max_match_score, 1.0);
        max_overlap     = std::min(1.0000001*max_overlap,     1.0);
        return test_box_overlap(max_match_score, max_overlap);
    }

// ----------------------------------------------------------------------------------------

    inline bool overlaps_any_box (
        const test_box_overlap& tester,
        const std::vector<rectangle>& rects,
        const rectangle& rect
    )
    {
        for (unsigned long i = 0; i < rects.size(); ++i)
        {
            if (tester(rects[i],rect))
                return true;
        }
        return false;
    }

// ----------------------------------------------------------------------------------------

    inline bool overlaps_any_box (
        const std::vector<rectangle>& rects,
        const rectangle& rect
    )
    {
        return overlaps_any_box(test_box_overlap(),rects,rect);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_BOX_OVERlAP_TESTING_Hh_


dlib C++ Library - correlation_tracker.h

// Copyright (C) 2015  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_CORRELATION_TrACKER_H_
#define DLIB_CORRELATION_TrACKER_H_

#include "correlation_tracker_abstract.h"
#include "../geometry.h"
#include "../matrix.h"
#include "../array2d.h"
#include "../image_transforms/assign_image.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class correlation_tracker
    {
    public:

        correlation_tracker (
        )
        {
            // Create the cosine mask used for space filtering.
            mask = make_cosine_mask();

            // Create the cosine mask used for the scale filtering.
            scale_cos_mask.resize(get_num_scale_levels());
            const long max_level = get_num_scale_levels()/2;
            for (unsigned long k = 0; k < get_num_scale_levels(); ++k)
            {
                double dist = std::abs((double)k-max_level)/max_level*pi/2;
                dist = std::min(dist, pi/2);
                scale_cos_mask[k] = std::cos(dist);
            }
        }

        template <typename image_type>
        void start_track (
            const image_type& img,
            const drectangle& p
        )
        {
            DLIB_CASSERT(p.is_empty() == false,
                "\t void correlation_tracker::start_track()"
                << "\n\t You can't give an empty rectangle."
            );

            B.set_size(0,0);

            point_transform_affine tform = inv(make_chip(img, p, F));
            for (unsigned long i = 0; i < F.size(); ++i)
                fft_inplace(F[i]);
            make_target_location_image(tform(center(p)), G);
            A.resize(F.size());
            for (unsigned long i = 0; i < F.size(); ++i)
            {
                A[i] = pointwise_multiply(G, F[i]);
                B += squared(real(F[i]))+squared(imag(F[i]));
            }

            position = p;

            // now do the scale space stuff
            make_scale_space(img, Fs);
            for (unsigned long i = 0; i < Fs.size(); ++i)
                fft_inplace(Fs[i]);
            make_scale_target_location_image(get_num_scale_levels()/2, Gs);
            Bs.set_size(0);
            As.resize(Fs.size());
            for (unsigned long i = 0; i < Fs.size(); ++i)
            {
                As[i] = pointwise_multiply(Gs, Fs[i]);
                Bs += squared(real(Fs[i]))+squared(imag(Fs[i]));
            }
        }

        unsigned long get_filter_size (
        ) const { return 128/2; } // must be power of 2

        unsigned long get_num_scale_levels(
        ) const { return 32; }  // must be power of 2

        unsigned long get_scale_window_size (
        ) const { return 23; }

        double get_regularizer_space (
        ) const { return 0.001; }
        inline double get_nu_space (
        ) const { return 0.025;}

        double get_regularizer_scale (
        ) const { return 0.001; }
        double get_nu_scale (
        ) const { return 0.025;}

        drectangle get_position (
        ) const
        {
            return position;
        }

        double get_scale_pyramid_alpha (
        ) const
        {
            return 1.020;
        }

        template <typename image_type>
        double update (
            const image_type& img,
            const drectangle& guess
        )
        {
            DLIB_CASSERT(get_position().is_empty() == false,
                "\t double correlation_tracker::update()"
                << "\n\t You must call start_track() first before calling update()."
            );

            const point_transform_affine tform = make_chip(img, guess, F);
            for (unsigned long i = 0; i < F.size(); ++i)
                fft_inplace(F[i]);

            // use the current filter to predict the object's location
            G = 0;
            for (unsigned long i = 0; i < F.size(); ++i)
                G += pointwise_multiply(F[i],conj(A[i]));
            G = pointwise_multiply(G, reciprocal(B+get_regularizer_space()));
            ifft_inplace(G);
            const dlib::vector<double,2> pp = max_point_interpolated(real(G));

            // Compute the peak to side lobe ratio.
            const point p = pp;
            running_stats<double> rs;
            const rectangle peak = centered_rect(p, 8,8);
            for (long r = 0; r < G.nr(); ++r)
            {
                for (long c = 0; c < G.nc(); ++c)
                {
                    if (!peak.contains(point(c,r)))
                        rs.add(G(r,c).real());
                }
            }
            const double psr = (G(p.y(),p.x()).real()-rs.mean())/rs.stddev();

            // update the position of the object
            position = translate_rect(guess,tform(pp)-center(guess));

            // now update the position filters
            make_target_location_image(pp, G);
            B *= (1-get_nu_space());
            for (unsigned long i = 0; i < F.size(); ++i)
            {
                A[i] = get_nu_space()*pointwise_multiply(G, F[i]) + (1-get_nu_space())*A[i];
                B += get_nu_space()*(squared(real(F[i]))+squared(imag(F[i])));
            }

            // Now predict the scale change
            make_scale_space(img, Fs);
            for (unsigned long i = 0; i < Fs.size(); ++i)
                fft_inplace(Fs[i]);
            Gs = 0;
            for (unsigned long i = 0; i < Fs.size(); ++i)
                Gs += pointwise_multiply(Fs[i],conj(As[i]));
            Gs = pointwise_multiply(Gs, reciprocal(Bs+get_regularizer_scale()));
            ifft_inplace(Gs);
            const double pos = max_point_interpolated(real(Gs)).y();

            // update the rectangle's scale
            position *= std::pow(get_scale_pyramid_alpha(), pos-(double)get_num_scale_levels()/2);

            // Now update the scale filters
            make_scale_target_location_image(pos, Gs);
            Bs *= (1-get_nu_scale());
            for (unsigned long i = 0; i < Fs.size(); ++i)
            {
                As[i] = get_nu_scale()*pointwise_multiply(Gs, Fs[i]) + (1-get_nu_scale())*As[i];
                Bs += get_nu_scale()*(squared(real(Fs[i]))+squared(imag(Fs[i])));
            }

            return psr;
        }

        template <typename image_type>
        double update (
            const image_type& img
        )
        {
            return update(img, get_position());
        }

    private:

        template <typename image_type>
        void make_scale_space(
            const image_type& img,
            std::vector<matrix<std::complex<double>,0,1> >& Fs
        ) const
        {
            typedef typename image_traits<image_type>::pixel_type pixel_type;

            // Make an image pyramid and put it into the chips array.
            const long chip_size = get_scale_window_size();
            drectangle ppp = position*std::pow(get_scale_pyramid_alpha(), -(double)get_num_scale_levels()/2);
            dlib::array<array2d<pixel_type> > chips;
            std::vector<dlib::vector<double,2> > from_points, to_points;
            from_points.push_back(point(0,0));
            from_points.push_back(point(chip_size-1,0));
            from_points.push_back(point(chip_size-1,chip_size-1));
            for (unsigned long i = 0; i < get_num_scale_levels(); ++i)
            {
                array2d<pixel_type> chip(chip_size,chip_size);

                // pull box into chip
                to_points.clear();
                to_points.push_back(ppp.tl_corner());
                to_points.push_back(ppp.tr_corner());
                to_points.push_back(ppp.br_corner());
                transform_image(img,chip,interpolate_bilinear(),find_affine_transform(from_points, to_points));

                chips.push_back(chip);
                ppp *= get_scale_pyramid_alpha();
            }

            // extract HOG for each chip
            dlib::array<dlib::array<array2d<float> > > hogs(chips.size());
            for (unsigned long i = 0; i < chips.size(); ++i)
            {
                extract_fhog_features(chips[i], hogs[i], 4);
                hogs[i].resize(32);
                assign_image(hogs[i][31], chips[i]);
                assign_image(hogs[i][31], mat(hogs[i][31])/255.0);
            }

            // Now copy the hog features into the Fs outputs and also apply the cosine
            // windowing.
            Fs.resize(hogs[0].size()*hogs[0][0].size());
            unsigned long i = 0;
            for (long r = 0; r < hogs[0][0].nr(); ++r)
            {
                for (long c = 0; c < hogs[0][0].nc(); ++c)
                {
                    for (unsigned long j = 0; j < hogs[0].size(); ++j)
                    {
                        Fs[i].set_size(hogs.size());
                        for (unsigned long k = 0; k < hogs.size(); ++k)
                        {
                            Fs[i](k) = hogs[k][j][r][c]*scale_cos_mask[k];
                        }
                        ++i;
                    }
                }
            }
        }

        template <typename image_type>
        point_transform_affine make_chip (
            const image_type& img,
            drectangle p,
            std::vector<matrix<std::complex<double> > >& chip
        ) const
        {
            typedef typename image_traits<image_type>::pixel_type pixel_type;
            array2d<pixel_type> temp;
            const double padding = 1.4;
            const chip_details details(p*padding, chip_dims(get_filter_size(), get_filter_size()));
            extract_image_chip(img, details, temp);

            chip.resize(32);
            dlib::array<array2d<float> > hog;
            extract_fhog_features(temp, hog, 1, 3,3 );
            for (unsigned long i = 0; i < hog.size(); ++i)
                assign_image(chip[i], pointwise_multiply(matrix_cast<double>(mat(hog[i])), mask));

            assign_image(chip[31], temp);
            assign_image(chip[31], pointwise_multiply(mat(chip[31]), mask)/255.0);

            return inv(get_mapping_to_chip(details));
        }

        void make_target_location_image (
            const dlib::vector<double,2>& p,
            matrix<std::complex<double> >& g
        ) const
        {
            g.set_size(get_filter_size(), get_filter_size());
            g = 0;
            rectangle area = centered_rect(p, 21,21).intersect(get_rect(g));
            for (long r = area.top(); r <= area.bottom(); ++r)
            {
                for (long c = area.left(); c <= area.right(); ++c)
                {
                    double dist = length(point(c,r)-p);
                    g(r,c) = std::exp(-dist/3.0);
                }
            }
            fft_inplace(g);
            g = conj(g);
        }

        void make_scale_target_location_image (
            const double scale,
            matrix<std::complex<double>,0,1>& g
        ) const
        {
            g.set_size(get_num_scale_levels());
            for (long i = 0; i < g.size(); ++i)
            {
                double dist = std::pow((i-scale),2.0);
                g(i) = std::exp(-dist/1.000);
            }
            fft_inplace(g);
            g = conj(g);
        }

        matrix<double> make_cosine_mask (
        ) const
        {
            const long size = get_filter_size();
            matrix<double> temp(size,size);
            point cent = center(get_rect(temp));
            for (long r = 0; r < temp.nr(); ++r)
            {
                for (long c = 0; c < temp.nc(); ++c)
                {
                    point delta = point(c,r)-cent;
                    double dist = length(delta)/(size/2.0)*(pi/2);
                    dist = std::min(dist*1.0, pi/2);

                    temp(r,c) = std::cos(dist);
                }
            }
            return temp;
        }

        std::vector<matrix<std::complex<double> > > A, F;
        matrix<double> B;

        std::vector<matrix<std::complex<double>,0,1> > As, Fs;
        matrix<double,0,1> Bs;
        drectangle position;

        matrix<double> mask;
        std::vector<double> scale_cos_mask;

        // G and Gs do not logically contribute to the state of this object.  They are
        // here just so we can void reallocating them over and over.
        matrix<std::complex<double> > G;
        matrix<std::complex<double>,0,1> Gs;
    };
}

#endif // DLIB_CORRELATION_TrACKER_H_


dlib C++ Library - detection_template_tools.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_DETECTION_TEMPlATE_TOOLS_Hh_
#define DLIB_DETECTION_TEMPlATE_TOOLS_Hh_

#include "detection_template_tools_abstract.h"
#include "../geometry.h"
#include "../matrix.h"
#include <utility>
#include <vector>
#include <cmath>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    inline rectangle compute_box_dimensions (
        const double width_to_height_ratio,
        const double area
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(width_to_height_ratio > 0 && area > 0,
            "\t rectangle compute_box_dimensions()"
            << "\n\t Invalid arguments were given to this function. "
            << "\n\t width_to_height_ratio: " << width_to_height_ratio
            << "\n\t area: " << area
            );

        /*
            width*height == area
            width/height == width_to_height_ratio
        */
        using namespace std;

        const int height = (int)std::floor(std::sqrt(area/width_to_height_ratio) + 0.5);
        const int width  = (int)std::floor(area/height + 0.5);

        return centered_rect(0,0,width,height);
    }

// ----------------------------------------------------------------------------------------

    inline std::vector<rectangle> create_single_box_detection_template (
        const rectangle& object_box
    )
    {
        std::vector<rectangle> temp;
        temp.push_back(object_box);
        return temp;
    }

// ----------------------------------------------------------------------------------------

    inline std::vector<rectangle> create_overlapped_2x2_detection_template (
        const rectangle& object_box
    )
    {
        std::vector<rectangle> result;

        const point c = center(object_box);

        result.push_back(rectangle() + c + object_box.tl_corner() + object_box.tr_corner());
        result.push_back(rectangle() + c + object_box.bl_corner() + object_box.br_corner());
        result.push_back(rectangle() + c + object_box.tl_corner() + object_box.bl_corner());
        result.push_back(rectangle() + c + object_box.tr_corner() + object_box.br_corner());

        return result;
    }

// ----------------------------------------------------------------------------------------

    inline std::vector<rectangle> create_grid_detection_template (
        const rectangle& object_box,
        unsigned int cells_x,
        unsigned int cells_y
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(cells_x > 0 && cells_y > 0,
            "\t std::vector<rectangle> create_grid_detection_template()"
            << "\n\t The number of cells along a dimension can't be zero. "
            << "\n\t cells_x: " << cells_x
            << "\n\t cells_y: " << cells_y
            );

        std::vector<rectangle> result;

        const matrix<double,1> x = linspace(object_box.left(), object_box.right(), cells_x+1);
        const matrix<double,1> y = linspace(object_box.top(), object_box.bottom(), cells_y+1);

        for (long j = 0; j+1 < y.size(); ++j)
        {
            for (long i = 0; i+1 < x.size(); ++i)
            {
                const dlib::vector<double,2> tl(x(i),y(j));
                const dlib::vector<double,2> br(x(i+1),y(j+1));
                result.push_back(rectangle(tl,br));
            }
        }

        return result;
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_DETECTION_TEMPlATE_TOOLS_Hh_


dlib C++ Library - full_object_detection.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_FULL_OBJECT_DeTECTION_Hh_
#define DLIB_FULL_OBJECT_DeTECTION_Hh_

#include "../geometry.h"
#include "full_object_detection_abstract.h"
#include <vector>
#include "../serialize.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    const static point OBJECT_PART_NOT_PRESENT(0x7FFFFFFF,
                                                0x7FFFFFFF);

// ----------------------------------------------------------------------------------------

    class full_object_detection
    {
    public:
        full_object_detection(
            const rectangle& rect_,
            const std::vector<point>& parts_
        ) : rect(rect_), parts(parts_) {}

        full_object_detection(){}

        explicit full_object_detection(
            const rectangle& rect_
        ) : rect(rect_) {}

        const rectangle& get_rect() const { return rect; }
        rectangle& get_rect() { return rect; }
        unsigned long num_parts() const { return parts.size(); }

        const point& part(
            unsigned long idx
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(idx < num_parts(),
                "\t point full_object_detection::part()"
                << "\n\t Invalid inputs were given to this function "
                << "\n\t idx:         " << idx
                << "\n\t num_parts(): " << num_parts()
                << "\n\t this:        " << this
                );
            return parts[idx];
        }

        point& part(
            unsigned long idx
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(idx < num_parts(),
                "\t point full_object_detection::part()"
                << "\n\t Invalid inputs were given to this function "
                << "\n\t idx:         " << idx
                << "\n\t num_parts(): " << num_parts()
                << "\n\t this:        " << this
                );
            return parts[idx];
        }

        friend void serialize (
            const full_object_detection& item,
            std::ostream& out
        )
        {
            int version = 1;
            serialize(version, out);
            serialize(item.rect, out);
            serialize(item.parts, out);
        }

        friend void deserialize (
            full_object_detection& item,
            std::istream& in
        )
        {
            int version = 0;
            deserialize(version, in);
            if (version != 1)
                throw serialization_error("Unexpected version encountered while deserializing dlib::full_object_detection.");

            deserialize(item.rect, in);
            deserialize(item.parts, in);
        }

    private:
        rectangle rect;
        std::vector<point> parts;
    };

// ----------------------------------------------------------------------------------------

    inline bool all_parts_in_rect (
        const full_object_detection& obj
    )
    {
        for (unsigned long i = 0; i < obj.num_parts(); ++i)
        {
            if (obj.get_rect().contains(obj.part(i)) == false &&
                obj.part(i) != OBJECT_PART_NOT_PRESENT)
                return false;
        }
        return true;
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_FULL_OBJECT_DeTECTION_H_


dlib C++ Library - generic_image.h

// Copyright (C) 2014  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_GeNERIC_IMAGE_Hh_
#define DLIB_GeNERIC_IMAGE_Hh_

#include "../assert.h"

namespace dlib
{

    /*!
        In dlib, an "image" is any object that implements the generic image interface.  In
        particular, this simply means that an image type (let's refer to it as image_type
        from here on) has the following seven global functions defined for it:
            - long        num_rows      (const image_type& img)
            - long        num_columns   (const image_type& img)
            - void        set_image_size(      image_type& img, long rows, long cols)
            - void*       image_data    (      image_type& img)
            - const void* image_data    (const image_type& img)
            - long        width_step    (const image_type& img)
            - void        swap          (      image_type& a, image_type& b)
        And also provides a specialization of the image_traits template that looks like:
            namespace dlib
            {
                template <>
                struct image_traits<image_type>
                {
                    typedef the_type_of_pixel_used_in_image_type pixel_type;
                };
            }

        Additionally, an image object must be default constructable.  This means that
        expressions of the form:
            image_type img;
        Must be legal.

        Finally, the type of pixel in image_type must have a pixel_traits specialization.
        That is, pixel_traits<typename image_traits<image_type>::pixel_type> must be one of
        the specializations of pixel_traits.

        To be very precise, the seven functions defined above are defined thusly:

            long num_rows(
                const image_type& img
            );
            /!*
                ensures
                    - returns the number of rows in the given image
            *!/

            long num_columns(
                const image_type& img
            );
            /!*
                ensures
                    - returns the number of columns in the given image
            *!/

            void set_image_size(
                image_type& img,
                long rows,
                long cols
            );
            /!*
                requires
                    - rows >= 0 && cols >= 0
                ensures
                    - num_rows(#img) == rows
                    - num_columns(#img) == cols
            *!/

            void* image_data(
                image_type& img
            );
            /!*
                ensures
                    - returns a non-const pointer to the pixel at row and column position 0,0
                      in the given image.  Or if the image has zero rows or columns in it
                      then this function returns NULL.
                    - The image lays pixels down in row major order.  However, there might
                      be padding at the end of each row.  The amount of padding is given by
                      width_step(img).
            *!/

            const void* image_data(
                const image_type& img
            );
            /!*
                ensures
                    - returns a const pointer to the pixel at row and column position 0,0 in
                      the given image.  Or if the image has zero rows or columns in it then
                      this function returns NULL.
                    - The image lays pixels down in row major order.  However, there might
                      be padding at the end of each row.  The amount of padding is given by
                      width_step(img).
            *!/

            long width_step(
                const image_type& img
            );
            /!*
                ensures
                    - returns the size of one row of the image, in bytes.  More precisely,
                      return a number N such that: (char*)image_data(img) + N*R == a
                      pointer to the first pixel in the R-th row of the image. This means
                      that the image must lay its pixels down in row major order.
            *!/

            void swap(
                image_type& a,
                image_type& b
            );
            /!*
                ensures
                    - swaps the state of a and b
            *!/
    !*/

// ----------------------------------------------------------------------------------------

    template <typename image_type>
    struct image_traits;
    /*!
        WHAT THIS OBJECT REPRESENTS
            This is a traits class for generic image objects.  You can use it to find out
            the pixel type contained within an image via an expression of the form:
                image_traits<image_type>::pixel_type
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                   UTILITIES TO MAKE ACCESSING IMAGE PIXELS SIMPLER
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    class image_view
    {
        /*!
            REQUIREMENTS ON image_type
                image_type must be an image object as defined at the top of this file.

            WHAT THIS OBJECT REPRESENTS
                This object takes an image object and wraps it with an interface that makes
                it look like a dlib::array2d.  That is, it makes it look similar to a
                regular 2-dimensional C style array, making code which operates on the
                pixels simple to read.

                Note that an image_view instance is valid until the image given to its
                constructor is modified through an interface other than the image_view
                instance.  This is because, for example, someone might cause the underlying
                image object to reallocate its memory, thus invalidating the pointer to its
                pixel data stored in the image_view.

                As an side, the reason why this object stores a pointer to the image
                object's data and uses that pointer instead of calling image_data() each
                time a pixel is accessed is to allow for image objects to implement
                complex, and possibly slow, image_data() functions.  For example, an image
                object might perform some kind of synchronization between a GPU and the
                host memory during a call to image_data().  Therefore, we call image_data()
                only in image_view's constructor to avoid the performance penalty of
                calling it for each pixel access.
        !*/

    public:
        typedef typename image_traits<image_type>::pixel_type pixel_type;

        image_view(
            image_type& img
        ) :
            _data((char*)image_data(img)),
            _width_step(width_step(img)),
            _nr(num_rows(img)),
            _nc(num_columns(img)),
            _img(&img)
        {}

        long nr() const { return _nr; }
        /*!
            ensures
                - returns the number of rows in this image.
        !*/

        long nc() const { return _nc; }
        /*!
            ensures
                - returns the number of columns in this image.
        !*/

        unsigned long size() const { return static_cast<unsigned long>(nr()*nc()); }
        /*!
            ensures
                - returns the number of pixels in this image.
        !*/

#ifndef ENABLE_ASSERTS
        pixel_type* operator[] (long row) { return (pixel_type*)(_data+_width_step*row); }
        /*!
            requires
                - 0 <= row < nr()
            ensures
                - returns a pointer to the first pixel in the row-th row.  Therefore, the
                  pixel at row and column position r,c can be accessed via (*this)[r][c].
        !*/

        const pixel_type* operator[] (long row) const { return (const pixel_type*)(_data+_width_step*row); }
        /*!
            requires
                - 0 <= row < nr()
            ensures
                - returns a const pointer to the first pixel in the row-th row.  Therefore,
                  the pixel at row and column position r,c can be accessed via
                  (*this)[r][c].
        !*/
#else
        // If asserts are enabled then we need to return a proxy class so we can make sure
        // the column accesses don't go out of bounds.
        struct pix_row
        {
            pix_row(pixel_type* data_, long nc_) : data(data_),_nc(nc_) {}
            const pixel_type& operator[] (long col) const
            {
                DLIB_ASSERT(0 <= col && col < _nc,
                    "\t The given column index is out of range."
                    << "\n\t col: " << col
                    << "\n\t _nc: " << _nc);
                return data[col];
            }
            pixel_type& operator[] (long col)
            {
                DLIB_ASSERT(0 <= col && col < _nc,
                    "\t The given column index is out of range."
                    << "\n\t col: " << col
                    << "\n\t _nc: " << _nc);
                return data[col];
            }
        private:
            pixel_type* const data;
            const long _nc;
        };
        pix_row operator[] (long row)
        {
            DLIB_ASSERT(0 <= row && row < _nr,
                "\t The given row index is out of range."
                << "\n\t row: " << row
                << "\n\t _nr: " << _nr);
            return pix_row((pixel_type*)(_data+_width_step*row), _nc);
        }
        const pix_row operator[] (long row) const
        {
            DLIB_ASSERT(0 <= row && row < _nr,
                "\t The given row index is out of range."
                << "\n\t row: " << row
                << "\n\t _nr: " << _nr);
            return pix_row((pixel_type*)(_data+_width_step*row), _nc);
        }
#endif

        void set_size(long rows, long cols)
        /*!
            requires
                - rows >= 0 && cols >= 0
            ensures
                - Tells the underlying image to resize itself to have the given number of
                  rows and columns.
                - #nr() == rows
                - #nc() == cols
        !*/
        {
            DLIB_ASSERT((cols >= 0 && rows >= 0),
                        "\t image_view::set_size(long rows, long cols)"
                        << "\n\t The images can't have negative rows or columns."
                        << "\n\t cols: " << cols
                        << "\n\t rows: " << rows
            );
            set_image_size(*_img, rows, cols); *this = *_img;
        }

        void clear() { set_size(0,0); }
        /*!
            ensures
                - sets the image to have 0 pixels in it.
        !*/

    private:

        char* _data;
        long _width_step;
        long _nr;
        long _nc;
        image_type* _img;
    };

// ----------------------------------------------------------------------------------------

    template <typename image_type>
    class const_image_view
    {
        /*!
            REQUIREMENTS ON image_type
                image_type must be an image object as defined at the top of this file.

            WHAT THIS OBJECT REPRESENTS
                This object is just like the image_view except that it provides a "const"
                view into an image.  That is, it has the same interface as image_view
                except that you can't modify the image through a const_image_view.
        !*/

    public:
        typedef typename image_traits<image_type>::pixel_type pixel_type;

        const_image_view(
            const image_type& img
        ) :
            _data((char*)image_data(img)),
            _width_step(width_step(img)),
            _nr(num_rows(img)),
            _nc(num_columns(img))
        {}

        long nr() const { return _nr; }
        long nc() const { return _nc; }
        unsigned long size() const { return static_cast<unsigned long>(nr()*nc()); }
#ifndef ENABLE_ASSERTS
        const pixel_type* operator[] (long row) const { return (const pixel_type*)(_data+_width_step*row); }
#else
        // If asserts are enabled then we need to return a proxy class so we can make sure
        // the column accesses don't go out of bounds.
        struct pix_row
        {
            pix_row(pixel_type* data_, long nc_) : data(data_),_nc(nc_) {}
            const pixel_type& operator[] (long col) const
            {
                DLIB_ASSERT(0 <= col && col < _nc,
                    "\t The given column index is out of range."
                    << "\n\t col: " << col
                    << "\n\t _nc: " << _nc);
                return data[col];
            }
        private:
            pixel_type* const data;
            const long _nc;
        };
        const pix_row operator[] (long row) const
        {
            DLIB_ASSERT(0 <= row && row < _nr,
                "\t The given row index is out of range."
                << "\n\t row: " << row
                << "\n\t _nr: " << _nr);
            return pix_row((pixel_type*)(_data+_width_step*row), _nc);
        }
#endif

    private:
        const char* _data;
        long _width_step;
        long _nr;
        long _nc;
    };

// ----------------------------------------------------------------------------------------

    template <typename image_type>
    image_view<image_type> make_image_view ( image_type& img)
    { return image_view<image_type>(img); }
    /*!
        requires
            - image_type == an image object that implements the interface defined at the
              top of this file.
        ensures
            - constructs an image_view from an image object
    !*/

    template <typename image_type>
    const_image_view<image_type> make_image_view (const image_type& img)
    { return const_image_view<image_type>(img); }
    /*!
        requires
            - image_type == an image object that implements the interface defined at the
              top of this file.
        ensures
            - constructs a const_image_view from an image object
    !*/

// ----------------------------------------------------------------------------------------

    template <typename image_type>
    inline unsigned long image_size(
        const image_type& img
    ) { return num_columns(img)*num_rows(img); }
    /*!
        requires
            - image_type == an image object that implements the interface defined at the
              top of this file.
        ensures
            - returns the number of pixels in the given image.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename image_type>
    inline long num_rows(
        const image_type& img
    ) { return img.nr(); }
    /*!
        ensures
            - By default, try to use the member function .nr() to determine the number
              of rows in an image.  However, as stated at the top of this file, image
              objects should provide their own overload of num_rows() if needed.
    !*/

    template <typename image_type>
    inline long num_columns(
        const image_type& img
    ) { return img.nc(); }
    /*!
        ensures
            - By default, try to use the member function .nc() to determine the number
              of columns in an image.  However, as stated at the top of this file, image
              objects should provide their own overload of num_rows() if needed.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_GeNERIC_IMAGE_Hh_


dlib C++ Library - object_detector.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_OBJECT_DeTECTOR_Hh_
#define DLIB_OBJECT_DeTECTOR_Hh_

#include "object_detector_abstract.h"
#include "../geometry.h"
#include <vector>
#include "box_overlap_testing.h"
#include "full_object_detection.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    struct rect_detection
    {
        double detection_confidence;
        unsigned long weight_index;
        rectangle rect;

        bool operator<(const rect_detection& item) const { return detection_confidence < item.detection_confidence; }
    };

    struct full_detection
    {
        double detection_confidence;
        unsigned long weight_index;
        full_object_detection rect;

        bool operator<(const full_detection& item) const { return detection_confidence < item.detection_confidence; }
    };

// ----------------------------------------------------------------------------------------

    template <typename image_scanner_type>
    struct processed_weight_vector
    {
        processed_weight_vector(){}

        typedef typename image_scanner_type::feature_vector_type feature_vector_type;

        void init (
            const image_scanner_type&
        )
        /*!
            requires
                - w has already been assigned its value.  Note that the point of this
                  function is to allow an image scanner to overload the
                  processed_weight_vector template and provide some different kind of
                  object as the output of get_detect_argument().  For example, the
                  scan_fhog_pyramid object uses an overload that causes
                  get_detect_argument() to return the special fhog_filterbank object
                  instead of a feature_vector_type.  This avoids needing to construct the
                  fhog_filterbank during each call to detect and therefore speeds up
                  detection.
        !*/
        {}

        // return the first argument to image_scanner_type::detect()
        const feature_vector_type& get_detect_argument() const { return w; }

        feature_vector_type w;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename image_scanner_type_
        >
    class object_detector
    {
    public:
        typedef image_scanner_type_ image_scanner_type;
        typedef typename image_scanner_type::feature_vector_type feature_vector_type;

        object_detector (
        );

        object_detector (
            const object_detector& item
        );

        object_detector (
            const image_scanner_type& scanner_,
            const test_box_overlap& overlap_tester_,
            const feature_vector_type& w_
        );

        object_detector (
            const image_scanner_type& scanner_,
            const test_box_overlap& overlap_tester_,
            const std::vector<feature_vector_type>& w_
        );

        explicit object_detector (
            const std::vector<object_detector>& detectors
        );

        unsigned long num_detectors (
        ) const { return w.size(); }

        const feature_vector_type& get_w (
            unsigned long idx = 0
        ) const { return w[idx].w; }

        const processed_weight_vector<image_scanner_type>& get_processed_w (
            unsigned long idx = 0
        ) const { return w[idx]; }

        const test_box_overlap& get_overlap_tester (
        ) const;

        const image_scanner_type& get_scanner (
        ) const;

        object_detector& operator= (
            const object_detector& item
        );

        template <
            typename image_type
            >
        std::vector<rectangle> operator() (
            const image_type& img,
            double adjust_threshold = 0
        );

        template <
            typename image_type
            >
        void operator() (
            const image_type& img,
            std::vector<std::pair<double, rectangle> >& final_dets,
            double adjust_threshold = 0
        );

        template <
            typename image_type
            >
        void operator() (
            const image_type& img,
            std::vector<std::pair<double, full_object_detection> >& final_dets,
            double adjust_threshold = 0
        );

        template <
            typename image_type
            >
        void operator() (
            const image_type& img,
            std::vector<full_object_detection>& final_dets,
            double adjust_threshold = 0
        );

        // These typedefs are here for backwards compatibility with previous versions of
        // dlib.
        typedef ::dlib::rect_detection rect_detection;
        typedef ::dlib::full_detection full_detection;

        template <
            typename image_type
            >
        void operator() (
            const image_type& img,
            std::vector<rect_detection>& final_dets,
            double adjust_threshold = 0
        );

        template <
            typename image_type
            >
        void operator() (
            const image_type& img,
            std::vector<full_detection>& final_dets,
            double adjust_threshold = 0
        );

        template <typename T>
        friend void serialize (
            const object_detector<T>& item,
            std::ostream& out
        );

        template <typename T>
        friend void deserialize (
            object_detector<T>& item,
            std::istream& in
        );

    private:

        bool overlaps_any_box (
            const std::vector<rect_detection>& rects,
            const dlib::rectangle& rect
        ) const
        {
            for (unsigned long i = 0; i < rects.size(); ++i)
            {
                if (boxes_overlap(rects[i].rect, rect))
                    return true;
            }
            return false;
        }

        test_box_overlap boxes_overlap;
        std::vector<processed_weight_vector<image_scanner_type> > w;
        image_scanner_type scanner;
    };

// ----------------------------------------------------------------------------------------

    template <typename T>
    void serialize (
        const object_detector<T>& item,
        std::ostream& out
    )
    {
        int version = 2;
        serialize(version, out);

        T scanner;
        scanner.copy_configuration(item.scanner);
        serialize(scanner, out);
        serialize(item.boxes_overlap, out);
        // serialize all the weight vectors
        serialize(item.w.size(), out);
        for (unsigned long i = 0; i < item.w.size(); ++i)
            serialize(item.w[i].w, out);
    }

// ----------------------------------------------------------------------------------------

    template <typename T>
    void deserialize (
        object_detector<T>& item,
        std::istream& in
    )
    {
        int version = 0;
        deserialize(version, in);
        if (version == 1)
        {
            deserialize(item.scanner, in);
            item.w.resize(1);
            deserialize(item.w[0].w, in);
            item.w[0].init(item.scanner);
            deserialize(item.boxes_overlap, in);
        }
        else if (version == 2)
        {
            deserialize(item.scanner, in);
            deserialize(item.boxes_overlap, in);
            unsigned long num_detectors = 0;
            deserialize(num_detectors, in);
            item.w.resize(num_detectors);
            for (unsigned long i = 0; i < item.w.size(); ++i)
            {
                deserialize(item.w[i].w, in);
                item.w[i].init(item.scanner);
            }
        }
        else
        {
            throw serialization_error("Unexpected version encountered while deserializing a dlib::object_detector object.");
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                      object_detector member functions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename image_scanner_type
        >
    object_detector<image_scanner_type>::
    object_detector (
    )
    {
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_scanner_type
        >
    object_detector<image_scanner_type>::
    object_detector (
        const object_detector& item
    )
    {
        boxes_overlap = item.boxes_overlap;
        w = item.w;
        scanner.copy_configuration(item.scanner);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_scanner_type
        >
    object_detector<image_scanner_type>::
    object_detector (
        const image_scanner_type& scanner_,
        const test_box_overlap& overlap_tester,
        const feature_vector_type& w_
    ) :
        boxes_overlap(overlap_tester)
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(scanner_.get_num_detection_templates() > 0 &&
                    w_.size() == scanner_.get_num_dimensions() + 1,
            "\t object_detector::object_detector(scanner_,overlap_tester,w_)"
            << "\n\t Invalid inputs were given to this function "
            << "\n\t scanner_.get_num_detection_templates(): " << scanner_.get_num_detection_templates()
            << "\n\t w_.size():                     " << w_.size()
            << "\n\t scanner_.get_num_dimensions(): " << scanner_.get_num_dimensions()
            << "\n\t this: " << this
            );

        scanner.copy_configuration(scanner_);
        w.resize(1);
        w[0].w = w_;
        w[0].init(scanner);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_scanner_type
        >
    object_detector<image_scanner_type>::
    object_detector (
        const image_scanner_type& scanner_,
        const test_box_overlap& overlap_tester,
        const std::vector<feature_vector_type>& w_
    ) :
        boxes_overlap(overlap_tester)
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(scanner_.get_num_detection_templates() > 0 && w_.size() > 0,
            "\t object_detector::object_detector(scanner_,overlap_tester,w_)"
            << "\n\t Invalid inputs were given to this function "
            << "\n\t scanner_.get_num_detection_templates(): " << scanner_.get_num_detection_templates()
            << "\n\t w_.size():                     " << w_.size()
            << "\n\t this: " << this
            );

        for (unsigned long i = 0; i < w_.size(); ++i)
        {
            DLIB_CASSERT(w_[i].size() == scanner_.get_num_dimensions() + 1,
                "\t object_detector::object_detector(scanner_,overlap_tester,w_)"
                << "\n\t Invalid inputs were given to this function "
                << "\n\t scanner_.get_num_detection_templates(): " << scanner_.get_num_detection_templates()
                << "\n\t w_["<<i<<"].size():                     " << w_[i].size()
                << "\n\t scanner_.get_num_dimensions(): " << scanner_.get_num_dimensions()
                << "\n\t this: " << this
                );
        }

        scanner.copy_configuration(scanner_);
        w.resize(w_.size());
        for (unsigned long i = 0; i < w.size(); ++i)
        {
            w[i].w = w_[i];
            w[i].init(scanner);
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_scanner_type
        >
    object_detector<image_scanner_type>::
    object_detector (
        const std::vector<object_detector>& detectors
    )
    {
        DLIB_CASSERT(detectors.size() != 0,
                "\t object_detector::object_detector(detectors)"
                << "\n\t Invalid inputs were given to this function "
                << "\n\t this: " << this
        );
        std::vector<feature_vector_type> weights;
        weights.reserve(detectors.size());
        for (unsigned long i = 0; i < detectors.size(); ++i)
        {
            for (unsigned long j = 0; j < detectors[i].num_detectors(); ++j)
                weights.push_back(detectors[i].get_w(j));
        }

        *this = object_detector(detectors[0].get_scanner(), detectors[0].get_overlap_tester(), weights);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_scanner_type
        >
    object_detector<image_scanner_type>& object_detector<image_scanner_type>::
    operator= (
        const object_detector& item
    )
    {
        if (this == &item)
            return *this;

        boxes_overlap = item.boxes_overlap;
        w = item.w;
        scanner.copy_configuration(item.scanner);
        return *this;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_scanner_type
        >
    template <
        typename image_type
        >
    void object_detector<image_scanner_type>::
    operator() (
        const image_type& img,
        std::vector<rect_detection>& final_dets,
        double adjust_threshold
    )
    {
        scanner.load(img);
        std::vector<std::pair<double, rectangle> > dets;
        std::vector<rect_detection> dets_accum;
        for (unsigned long i = 0; i < w.size(); ++i)
        {
            const double thresh = w[i].w(scanner.get_num_dimensions());
            scanner.detect(w[i].get_detect_argument(), dets, thresh + adjust_threshold);
            for (unsigned long j = 0; j < dets.size(); ++j)
            {
                rect_detection temp;
                temp.detection_confidence = dets[j].first-thresh;
                temp.weight_index = i;
                temp.rect = dets[j].second;
                dets_accum.push_back(temp);
            }
        }

        // Do non-max suppression
        final_dets.clear();
        if (w.size() > 1)
            std::sort(dets_accum.rbegin(), dets_accum.rend());
        for (unsigned long i = 0; i < dets_accum.size(); ++i)
        {
            if (overlaps_any_box(final_dets, dets_accum[i].rect))
                continue;

            final_dets.push_back(dets_accum[i]);
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_scanner_type
        >
    template <
        typename image_type
        >
    void object_detector<image_scanner_type>::
    operator() (
        const image_type& img,
        std::vector<full_detection>& final_dets,
        double adjust_threshold
    )
    {
        std::vector<rect_detection> dets;
        (*this)(img,dets,adjust_threshold);

        final_dets.resize(dets.size());

        // convert all the rectangle detections into full_object_detections.
        for (unsigned long i = 0; i < dets.size(); ++i)
        {
            final_dets[i].detection_confidence = dets[i].detection_confidence;
            final_dets[i].weight_index = dets[i].weight_index;
            final_dets[i].rect = scanner.get_full_object_detection(dets[i].rect, w[dets[i].weight_index].w);
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_scanner_type
        >
    template <
        typename image_type
        >
    std::vector<rectangle> object_detector<image_scanner_type>::
    operator() (
        const image_type& img,
        double adjust_threshold
    )
    {
        std::vector<rect_detection> dets;
        (*this)(img,dets,adjust_threshold);

        std::vector<rectangle> final_dets(dets.size());
        for (unsigned long i = 0; i < dets.size(); ++i)
            final_dets[i] = dets[i].rect;

        return final_dets;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_scanner_type
        >
    template <
        typename image_type
        >
    void object_detector<image_scanner_type>::
    operator() (
        const image_type& img,
        std::vector<std::pair<double, rectangle> >& final_dets,
        double adjust_threshold
    )
    {
        std::vector<rect_detection> dets;
        (*this)(img,dets,adjust_threshold);

        final_dets.resize(dets.size());
        for (unsigned long i = 0; i < dets.size(); ++i)
            final_dets[i] = std::make_pair(dets[i].detection_confidence,dets[i].rect);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_scanner_type
        >
    template <
        typename image_type
        >
    void object_detector<image_scanner_type>::
    operator() (
        const image_type& img,
        std::vector<std::pair<double, full_object_detection> >& final_dets,
        double adjust_threshold
    )
    {
        std::vector<rect_detection> dets;
        (*this)(img,dets,adjust_threshold);

        final_dets.clear();
        final_dets.reserve(dets.size());

        // convert all the rectangle detections into full_object_detections.
        for (unsigned long i = 0; i < dets.size(); ++i)
        {
            final_dets.push_back(std::make_pair(dets[i].detection_confidence,
                                                scanner.get_full_object_detection(dets[i].rect, w[dets[i].weight_index].w)));
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_scanner_type
        >
    template <
        typename image_type
        >
    void object_detector<image_scanner_type>::
    operator() (
        const image_type& img,
        std::vector<full_object_detection>& final_dets,
        double adjust_threshold
    )
    {
        std::vector<rect_detection> dets;
        (*this)(img,dets,adjust_threshold);

        final_dets.clear();
        final_dets.reserve(dets.size());

        // convert all the rectangle detections into full_object_detections.
        for (unsigned long i = 0; i < dets.size(); ++i)
        {
            final_dets.push_back(scanner.get_full_object_detection(dets[i].rect, w[dets[i].weight_index].w));
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_scanner_type
        >
    const test_box_overlap& object_detector<image_scanner_type>::
    get_overlap_tester (
    ) const
    {
        return boxes_overlap;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_scanner_type
        >
    const image_scanner_type& object_detector<image_scanner_type>::
    get_scanner (
    ) const
    {
        return scanner;
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_OBJECT_DeTECTOR_Hh_


dlib C++ Library - remove_unobtainable_rectangles.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_REMOVE_UnOBTAINABLE_RECTANGLES_Hh_
#define DLIB_REMOVE_UnOBTAINABLE_RECTANGLES_Hh_

#include "remove_unobtainable_rectangles_abstract.h"
#include "scan_image_pyramid.h"
#include "scan_image_boxes.h"
#include "scan_image_custom.h"
#include "scan_fhog_pyramid.h"
#include "../svm/structural_object_detection_trainer.h"
#include "../geometry.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    namespace impl
    {
        inline bool matches_rect (
            const std::vector<rectangle>& rects,
            const rectangle& rect,
            const double eps
        )
        {
            for (unsigned long i = 0; i < rects.size(); ++i)
            {
                const double score = (rect.intersect(rects[i])).area()/(double)(rect+rects[i]).area();
                if (score > eps)
                    return true;
            }

            return false;
        }

        inline rectangle get_best_matching_rect (
            const std::vector<rectangle>& rects,
            const rectangle& rect
        )
        {
            double best_score = -1;
            rectangle best_rect;
            for (unsigned long i = 0; i < rects.size(); ++i)
            {
                const double score = (rect.intersect(rects[i])).area()/(double)(rect+rects[i]).area();
                if (score > best_score)
                {
                    best_score = score;
                    best_rect = rects[i];
                }
            }
            return best_rect;
        }

    // ------------------------------------------------------------------------------------

        template <
            typename image_array_type,
            typename image_scanner_type
            >
        std::vector<std::vector<rectangle> > pyramid_remove_unobtainable_rectangles (
            const structural_object_detection_trainer<image_scanner_type>& trainer,
            const image_array_type& images,
            std::vector<std::vector<rectangle> >& object_locations
        )
        {
            using namespace dlib::impl;
            // make sure requires clause is not broken
            DLIB_ASSERT(images.size() == object_locations.size(),
                "\t std::vector<std::vector<rectangle>> remove_unobtainable_rectangles()"
                << "\n\t Invalid inputs were given to this function."
            );

            std::vector<std::vector<rectangle> > rejects(images.size());

            // If the trainer is setup to automatically fit the overlap tester to the data then
            // we should use the loosest possible overlap tester here.  Otherwise we should use
            // the tester the trainer will use.
            test_box_overlap boxes_overlap(0.9999999,1);
            if (!trainer.auto_set_overlap_tester())
                boxes_overlap = trainer.get_overlap_tester();

            for (unsigned long k = 0; k < images.size(); ++k)
            {
                std::vector<rectangle> objs = object_locations[k];

                // First remove things that don't have any matches with the candidate object
                // locations.
                std::vector<rectangle> good_rects;
                for (unsigned long j = 0; j < objs.size(); ++j)
                {
                    const rectangle rect = trainer.get_scanner().get_best_matching_rect(objs[j]);
                    const double score = (objs[j].intersect(rect)).area()/(double)(objs[j] + rect).area();
                    if (score > trainer.get_match_eps())
                        good_rects.push_back(objs[j]);
                    else
                        rejects[k].push_back(objs[j]);
                }
                object_locations[k] = good_rects;

                // Remap these rectangles to the ones that can come out of the scanner.  That
                // way when we compare them to each other in the following loop we will know if
                // any distinct truth rectangles get mapped to overlapping boxes.
                objs.resize(good_rects.size());
                for (unsigned long i = 0; i < good_rects.size(); ++i)
                    objs[i] = trainer.get_scanner().get_best_matching_rect(good_rects[i]);

                good_rects.clear();
                // now check for truth rects that are too close together.
                for (unsigned long i = 0; i < objs.size(); ++i)
                {
                    // check if objs[i] hits another box
                    bool hit_box = false;
                    for (unsigned long j = i+1; j < objs.size(); ++j)
                    {
                        if (boxes_overlap(objs[i], objs[j]))
                        {
                            hit_box = true;
                            break;
                        }
                    }
                    if (hit_box)
                        rejects[k].push_back(object_locations[k][i]);
                    else
                        good_rects.push_back(object_locations[k][i]);
                }
                object_locations[k] = good_rects;
            }

            return rejects;
        }

    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_array_type,
        typename Pyramid_type,
        typename Feature_extractor_type
        >
    std::vector<std::vector<rectangle> > remove_unobtainable_rectangles (
        const structural_object_detection_trainer<scan_image_pyramid<Pyramid_type, Feature_extractor_type> >& trainer,
        const image_array_type& images,
        std::vector<std::vector<rectangle> >& object_locations
    )
    {
        return impl::pyramid_remove_unobtainable_rectangles(trainer, images, object_locations);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_array_type,
        typename Pyramid_type
        >
    std::vector<std::vector<rectangle> > remove_unobtainable_rectangles (
        const structural_object_detection_trainer<scan_fhog_pyramid<Pyramid_type> >& trainer,
        const image_array_type& images,
        std::vector<std::vector<rectangle> >& object_locations
    )
    {
        return impl::pyramid_remove_unobtainable_rectangles(trainer, images, object_locations);
    }

// ----------------------------------------------------------------------------------------

    namespace impl
    {
        template <
            typename image_array_type,
            typename scanner_type,
            typename get_boxes_functor
            >
        std::vector<std::vector<rectangle> > remove_unobtainable_rectangles (
            get_boxes_functor& bg,
            const structural_object_detection_trainer<scanner_type>& trainer,
            const image_array_type& images,
            std::vector<std::vector<rectangle> >& object_locations
        )
        {
            using namespace dlib::impl;
            // make sure requires clause is not broken
            DLIB_ASSERT(images.size() == object_locations.size(),
                "\t std::vector<std::vector<rectangle>> remove_unobtainable_rectangles()"
                << "\n\t Invalid inputs were given to this function."
            );

            std::vector<rectangle> rects;

            std::vector<std::vector<rectangle> > rejects(images.size());

            // If the trainer is setup to automatically fit the overlap tester to the data then
            // we should use the loosest possible overlap tester here.  Otherwise we should use
            // the tester the trainer will use.
            test_box_overlap boxes_overlap(0.9999999,1);
            if (!trainer.auto_set_overlap_tester())
                boxes_overlap = trainer.get_overlap_tester();

            for (unsigned long k = 0; k < images.size(); ++k)
            {
                std::vector<rectangle> objs = object_locations[k];
                // Don't even bother computing the candidate rectangles if there aren't any
                // object locations for this image since there isn't anything to do anyway.
                if (objs.size() == 0)
                    continue;

                bg(images[k], rects);

                // First remove things that don't have any matches with the candidate object
                // locations.
                std::vector<rectangle> good_rects;
                for (unsigned long j = 0; j < objs.size(); ++j)
                {
                    if (matches_rect(rects, objs[j], trainer.get_match_eps()))
                        good_rects.push_back(objs[j]);
                    else
                        rejects[k].push_back(objs[j]);
                }
                object_locations[k] = good_rects;

                // Remap these rectangles to the ones that can come out of the scanner.  That
                // way when we compare them to each other in the following loop we will know if
                // any distinct truth rectangles get mapped to overlapping boxes.
                objs.resize(good_rects.size());
                for (unsigned long i = 0; i < good_rects.size(); ++i)
                    objs[i] = get_best_matching_rect(rects, good_rects[i]);

                good_rects.clear();
                // now check for truth rects that are too close together.
                for (unsigned long i = 0; i < objs.size(); ++i)
                {
                    // check if objs[i] hits another box
                    bool hit_box = false;
                    for (unsigned long j = i+1; j < objs.size(); ++j)
                    {
                        if (boxes_overlap(objs[i], objs[j]))
                        {
                            hit_box = true;
                            break;
                        }
                    }
                    if (hit_box)
                        rejects[k].push_back(object_locations[k][i]);
                    else
                        good_rects.push_back(object_locations[k][i]);
                }
                object_locations[k] = good_rects;
            }

            return rejects;
        }

    // ----------------------------------------------------------------------------------------

        template <typename T>
        struct load_to_functor
        {
            load_to_functor(T& obj_) : obj(obj_) {}
            T& obj;

            template <typename U, typename V>
            void operator()(const U& u, V& v)
            {
                obj.load(u,v);
            }
        };
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_array_type,
        typename feature_extractor,
        typename box_generator
        >
    std::vector<std::vector<rectangle> > remove_unobtainable_rectangles (
        const structural_object_detection_trainer<scan_image_boxes<feature_extractor, box_generator> >& trainer,
        const image_array_type& images,
        std::vector<std::vector<rectangle> >& object_locations
    )
    {
        box_generator bg = trainer.get_scanner().get_box_generator();
        return impl::remove_unobtainable_rectangles(bg, trainer, images, object_locations);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_array_type,
        typename feature_extractor
        >
    std::vector<std::vector<rectangle> > remove_unobtainable_rectangles (
        const structural_object_detection_trainer<scan_image_custom<feature_extractor> >& trainer,
        const image_array_type& images,
        std::vector<std::vector<rectangle> >& object_locations
    )
    {
        feature_extractor fe;
        fe.copy_configuration(trainer.get_scanner().get_feature_extractor());
        impl::load_to_functor<feature_extractor> bg(fe);
        return impl::remove_unobtainable_rectangles(bg, trainer, images, object_locations);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_REMOVE_UnOBTAINABLE_RECTANGLES_Hh_


dlib C++ Library - scan_fhog_pyramid.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SCAN_fHOG_PYRAMID_Hh_
#define DLIB_SCAN_fHOG_PYRAMID_Hh_

#include "scan_fhog_pyramid_abstract.h"
#include "../matrix.h"
#include "../image_transforms.h"
#include "../array.h"
#include "../array2d.h"
#include "object_detector.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class default_fhog_feature_extractor
    {
    public:
        inline rectangle image_to_feats (
            const rectangle& rect,
            int cell_size,
            int filter_rows_padding,
            int filter_cols_padding
        ) const
        {
            return image_to_fhog(rect, cell_size, filter_rows_padding, filter_cols_padding);
        }

        inline rectangle feats_to_image (
            const rectangle& rect,
            int cell_size,
            int filter_rows_padding,
            int filter_cols_padding
        ) const
        {
            return fhog_to_image(rect, cell_size, filter_rows_padding, filter_cols_padding);
        }

        template <
            typename image_type
            >
        void operator()(
            const image_type& img,
            dlib::array<array2d<float> >& hog,
            int cell_size,
            int filter_rows_padding,
            int filter_cols_padding
        ) const
        {
            extract_fhog_features(img,hog,cell_size,filter_rows_padding,filter_cols_padding);
        }

        inline unsigned long get_num_planes (
        ) const
        {
            return 31;
        }
    };

    inline void serialize   (const default_fhog_feature_extractor&, std::ostream&) {}
    inline void deserialize (default_fhog_feature_extractor&, std::istream&) {}

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename Feature_extractor_type = default_fhog_feature_extractor
        >
    class scan_fhog_pyramid : noncopyable
    {

    public:

        typedef matrix<double,0,1> feature_vector_type;

        typedef Pyramid_type pyramid_type;
        typedef Feature_extractor_type feature_extractor_type;

        scan_fhog_pyramid (
        );

        explicit scan_fhog_pyramid (
            const feature_extractor_type& fe_
        );

        template <
            typename image_type
            >
        void load (
            const image_type& img
        );

        inline bool is_loaded_with_image (
        ) const;

        inline void copy_configuration (
            const scan_fhog_pyramid& item
        );

        void set_detection_window_size (
            unsigned long width,
            unsigned long height
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(width > 0 && height > 0,
                "\t void scan_fhog_pyramid::set_detection_window_size()"
                << "\n\t Invalid inputs were given to this function "
                << "\n\t width:  " << width
                << "\n\t height: " << height
                << "\n\t this:   " << this
                );

            window_width = width;
            window_height = height;
            feats.clear();
        }

        inline unsigned long get_detection_window_width (
        ) const { return window_width; }
        inline unsigned long get_detection_window_height (
        ) const { return window_height; }

        inline unsigned long get_num_detection_templates (
        ) const;

        inline unsigned long get_num_movable_components_per_detection_template (
        ) const;

        void set_padding (
            unsigned long new_padding
        )
        {
            padding = new_padding;
            feats.clear();
        }

        unsigned long get_padding (
        ) const { return padding; }

        void set_cell_size (
            unsigned long new_cell_size
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(new_cell_size > 0 ,
                "\t void scan_fhog_pyramid::set_cell_size()"
                << "\n\t You can't have zero sized fHOG cells. "
                << "\n\t this: " << this
                );

            cell_size = new_cell_size;
            feats.clear();
        }

        unsigned long get_cell_size (
        ) const { return cell_size; }

        inline long get_num_dimensions (
        ) const;

        unsigned long get_max_pyramid_levels (
        ) const;

        const feature_extractor_type& get_feature_extractor(
        ) const { return fe; }

        void set_max_pyramid_levels (
            unsigned long max_levels
        );

        void set_min_pyramid_layer_size (
            unsigned long width,
            unsigned long height
        );

        inline unsigned long get_min_pyramid_layer_width (
        ) const;

        inline unsigned long get_min_pyramid_layer_height (
        ) const;

        void detect (
            const feature_vector_type& w,
            std::vector<std::pair<double, rectangle> >& dets,
            const double thresh
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(is_loaded_with_image() &&
                        w.size() >= get_num_dimensions(),
                "\t void scan_fhog_pyramid::detect()"
                << "\n\t Invalid inputs were given to this function "
                << "\n\t is_loaded_with_image(): " << is_loaded_with_image()
                << "\n\t w.size():               " << w.size()
                << "\n\t get_num_dimensions():   " << get_num_dimensions()
                << "\n\t this: " << this
                );

            fhog_filterbank temp = build_fhog_filterbank(w);
            detect(temp, dets, thresh);
        }

        class fhog_filterbank
        {
            friend class scan_fhog_pyramid;
        public:
            inline long get_num_dimensions() const
            {
                unsigned long dims = 0;
                for (unsigned long i = 0; i < filters.size(); ++i)
                {
                    dims += filters[i].size();
                }
                return dims;
            }

            const std::vector<matrix<float> >& get_filters() const { return filters;}

            unsigned long num_separable_filters() const
            {
                unsigned long num = 0;
                for (unsigned long i = 0; i < row_filters.size(); ++i)
                {
                    num += row_filters[i].size();
                }
                return num;
            }

            std::vector<matrix<float> > filters;
            std::vector<std::vector<matrix<float,0,1> > > row_filters, col_filters;
        };

        fhog_filterbank build_fhog_filterbank (
            const feature_vector_type& weights
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(weights.size() >= get_num_dimensions(),
                "\t fhog_filterbank scan_fhog_pyramid::build_fhog_filterbank()"
                << "\n\t The number of weights isn't enough to fill out the filterbank. "
                << "\n\t weights.size():       " << weights.size()
                << "\n\t get_num_dimensions(): " << get_num_dimensions()
                << "\n\t this: " << this
                );

            fhog_filterbank temp;
            temp.filters.resize(fe.get_num_planes());
            temp.row_filters.resize(fe.get_num_planes());
            temp.col_filters.resize(fe.get_num_planes());

            // load filters from w
            unsigned long width, height;
            compute_fhog_window_size(width, height);
            const long size = width*height;
            for (unsigned long i = 0; i < temp.filters.size(); ++i)
            {
                matrix<double> u,v,w,f;
                f = reshape(rowm(weights, range(i*size, (i+1)*size-1)), height, width);
                temp.filters[i] = matrix_cast<float>(f);

                svd3(f, u,w,v);

                matrix<double> w2 = w;
                rsort_columns(u,w);
                rsort_columns(v,w2);

                double thresh = std::max(1e-4, max(w)*0.001);
                w = round_zeros(w, thresh);

                for (long j = 0; j < w.size(); ++j)
                {
                    if (w(j) != 0)
                    {
                        temp.col_filters[i].push_back(matrix_cast<float>(colm(u,j)*std::sqrt(w(j))));
                        temp.row_filters[i].push_back(matrix_cast<float>(colm(v,j)*std::sqrt(w(j))));
                    }
                }
            }

            return temp;
        }

        void detect (
            const fhog_filterbank& w,
            std::vector<std::pair<double, rectangle> >& dets,
            const double thresh
        ) const;

        void get_feature_vector (
            const full_object_detection& obj,
            feature_vector_type& psi
        ) const;

        full_object_detection get_full_object_detection (
            const rectangle& rect,
            const feature_vector_type& w
        ) const;

        const rectangle get_best_matching_rect (
            const rectangle& rect
        ) const;

        double get_nuclear_norm_regularization_strength (
        ) const { return nuclear_norm_regularization_strength; }

        void set_nuclear_norm_regularization_strength (
            double strength
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(strength >= 0 ,
                "\t void scan_fhog_pyramid::set_nuclear_norm_regularization_strength()"
                << "\n\t You can't have a negative regularization strength."
                << "\n\t strength: " << strength
                << "\n\t this: " << this
            );

            nuclear_norm_regularization_strength = strength;
        }

        unsigned long get_fhog_window_width (
        ) const
        {
            unsigned long width, height;
            compute_fhog_window_size(width, height);
            return width;
        }

        unsigned long get_fhog_window_height (
        ) const
        {
            unsigned long width, height;
            compute_fhog_window_size(width, height);
            return height;
        }

        template <typename T, typename U>
        friend void serialize (
            const scan_fhog_pyramid<T,U>& item,
            std::ostream& out
        );

        template <typename T, typename U>
        friend void deserialize (
            scan_fhog_pyramid<T,U>& item,
            std::istream& in
        );

    private:
        inline void compute_fhog_window_size(
            unsigned long& width,
            unsigned long& height
        ) const
        {
            const rectangle rect = centered_rect(point(0,0),window_width,window_height);
            const rectangle temp = grow_rect(fe.image_to_feats(rect, cell_size, 1, 1), padding);
            width = temp.width();
            height = temp.height();
        }

        void get_mapped_rect_and_metadata (
            const unsigned long number_pyramid_levels,
            const rectangle& rect,
            rectangle& mapped_rect,
            rectangle& fhog_rect,
            unsigned long& best_level
        ) const;

        double get_match_score (
            rectangle r1,
            rectangle r2
        ) const
        {
            // make the rectangles overlap as much as possible before computing the match score.
            r1 = move_rect(r1, r2.tl_corner());
            return (r1.intersect(r2).area())/(double)(r1 + r2).area();
        }

        typedef array<array2d<float> > fhog_image;

        feature_extractor_type fe;
        array<fhog_image> feats;
        int cell_size;
        unsigned long padding;
        unsigned long window_width;
        unsigned long window_height;
        unsigned long max_pyramid_levels;
        unsigned long min_pyramid_layer_width;
        unsigned long min_pyramid_layer_height;
        double nuclear_norm_regularization_strength;

        void init()
        {
            cell_size = 8;
            padding = 1;
            window_width = 64;
            window_height = 64;
            max_pyramid_levels = 1000;
            min_pyramid_layer_width = 64;
            min_pyramid_layer_height = 64;
            nuclear_norm_regularization_strength = 0;
        }

    };

// ----------------------------------------------------------------------------------------

    namespace impl
    {
        template <typename fhog_filterbank>
        rectangle apply_filters_to_fhog (
            const fhog_filterbank& w,
            const array<array2d<float> >& feats,
            array2d<float>& saliency_image
        )
        {
            const unsigned long num_separable_filters = w.num_separable_filters();
            rectangle area;
            // use the separable filters if they would be faster than running the regular filters.
            if (num_separable_filters > w.filters.size()*std::min(w.filters[0].nr(),w.filters[0].nc())/3.0)
            {
                area = spatially_filter_image(feats[0], saliency_image, w.filters[0]);
                for (unsigned long i = 1; i < w.filters.size(); ++i)
                {
                    // now we filter but the output adds to saliency_image rather than
                    // overwriting it.
                    spatially_filter_image(feats[i], saliency_image, w.filters[i], 1, false, true);
                }
            }
            else
            {
                saliency_image.clear();
                array2d<float> scratch;

                // find the first filter to apply
                unsigned long i = 0;
                while (i < w.row_filters.size() && w.row_filters[i].size() == 0)
                    ++i;

                for (; i < w.row_filters.size(); ++i)
                {
                    for (unsigned long j = 0; j < w.row_filters[i].size(); ++j)
                    {
                        if (saliency_image.size() == 0)
                            area = float_spatially_filter_image_separable(feats[i], saliency_image, w.row_filters[i][j], w.col_filters[i][j],scratch,false);
                        else
                            area = float_spatially_filter_image_separable(feats[i], saliency_image, w.row_filters[i][j], w.col_filters[i][j],scratch,true);
                    }
                }
                if (saliency_image.size() == 0)
                {
                    saliency_image.set_size(feats[0].nr(), feats[0].nc());
                    assign_all_pixels(saliency_image, 0);
                }
            }
            return area;
        }
    }

// ----------------------------------------------------------------------------------------

    template <typename T, typename U>
    void serialize (
        const scan_fhog_pyramid<T,U>& item,
        std::ostream& out
    )
    {
        int version = 1;
        serialize(version, out);
        serialize(item.fe, out);
        serialize(item.feats, out);
        serialize(item.cell_size, out);
        serialize(item.padding, out);
        serialize(item.window_width, out);
        serialize(item.window_height, out);
        serialize(item.max_pyramid_levels, out);
        serialize(item.min_pyramid_layer_width, out);
        serialize(item.min_pyramid_layer_height, out);
        serialize(item.nuclear_norm_regularization_strength, out);
        serialize(item.get_num_dimensions(), out);
    }

// ----------------------------------------------------------------------------------------

    template <typename T, typename U>
    void deserialize (
        scan_fhog_pyramid<T,U>& item,
        std::istream& in
    )
    {
        int version = 0;
        deserialize(version, in);
        if (version != 1)
            throw serialization_error("Unsupported version found when deserializing a scan_fhog_pyramid object.");

        deserialize(item.fe, in);
        deserialize(item.feats, in);
        deserialize(item.cell_size, in);
        deserialize(item.padding, in);
        deserialize(item.window_width, in);
        deserialize(item.window_height, in);
        deserialize(item.max_pyramid_levels, in);
        deserialize(item.min_pyramid_layer_width, in);
        deserialize(item.min_pyramid_layer_height, in);
        deserialize(item.nuclear_norm_regularization_strength, in);

        // When developing some feature extractor, it's easy to accidentally change its
        // number of dimensions and then try to deserialize data from an older version of
        // your extractor into the current code.  This check is here to catch that kind of
        // user error.
        long dims;
        deserialize(dims, in);
        if (item.get_num_dimensions() != dims)
            throw serialization_error("Number of dimensions in serialized scan_fhog_pyramid doesn't match the expected number.");
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                         scan_fhog_pyramid member functions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename feature_extractor_type
        >
    scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::
    scan_fhog_pyramid (
    )
    {
        init();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename feature_extractor_type
        >
    scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::
    scan_fhog_pyramid (
        const feature_extractor_type& fe_
    )
    {
        init();
        fe = fe_;
    }

// ----------------------------------------------------------------------------------------

    namespace impl
    {
        template <
            typename pyramid_type,
            typename image_type,
            typename feature_extractor_type
            >
        void create_fhog_pyramid (
            const image_type& img,
            const feature_extractor_type& fe,
            array<array<array2d<float> > >& feats,
            int cell_size,
            int filter_rows_padding,
            int filter_cols_padding,
            unsigned long min_pyramid_layer_width,
            unsigned long min_pyramid_layer_height,
            unsigned long max_pyramid_levels
        )
        {
            unsigned long levels = 0;
            rectangle rect = get_rect(img);

            // figure out how many pyramid levels we should be using based on the image size
            pyramid_type pyr;
            do
            {
                rect = pyr.rect_down(rect);
                ++levels;
            } while (rect.width() >= min_pyramid_layer_width && rect.height() >= min_pyramid_layer_height &&
                levels < max_pyramid_levels);

            if (feats.max_size() < levels)
                feats.set_max_size(levels);
            feats.set_size(levels);

            // build our feature pyramid
            fe(img, feats[0], cell_size,filter_rows_padding,filter_cols_padding);
            DLIB_ASSERT(feats[0].size() == fe.get_num_planes(),
                "Invalid feature extractor used with dlib::scan_fhog_pyramid.  The output does not have the \n"
                "indicated number of planes.");

            if (feats.size() > 1)
            {
                typedef typename image_traits<image_type>::pixel_type pixel_type;
                array2d<pixel_type> temp1, temp2;
                pyr(img, temp1);
                fe(temp1, feats[1], cell_size,filter_rows_padding,filter_cols_padding);
                swap(temp1,temp2);

                for (unsigned long i = 2; i < feats.size(); ++i)
                {
                    pyr(temp2, temp1);
                    fe(temp1, feats[i], cell_size,filter_rows_padding,filter_cols_padding);
                    swap(temp1,temp2);
                }
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename feature_extractor_type
        >
    template <
        typename image_type
        >
    void scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::
    load (
        const image_type& img
    )
    {
        unsigned long width, height;
        compute_fhog_window_size(width,height);
        impl::create_fhog_pyramid<Pyramid_type>(img, fe, feats, cell_size, height,
            width, min_pyramid_layer_width, min_pyramid_layer_height,
            max_pyramid_levels);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename feature_extractor_type
        >
    bool scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::
    is_loaded_with_image (
    ) const
    {
        return feats.size() != 0;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename feature_extractor_type
        >
    void scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::
    copy_configuration (
        const scan_fhog_pyramid& item
    )
    {
        cell_size = item.cell_size;
        padding = item.padding;
        window_width = item.window_width;
        window_height = item.window_height;
        max_pyramid_levels = item.max_pyramid_levels;
        min_pyramid_layer_width = item.min_pyramid_layer_width;
        min_pyramid_layer_height = item.min_pyramid_layer_height;
        nuclear_norm_regularization_strength = item.nuclear_norm_regularization_strength;
        fe = item.fe;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename feature_extractor_type
        >
    unsigned long scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::
    get_num_detection_templates (
    ) const
    {
        return 1;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename feature_extractor_type
        >
    unsigned long scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::
    get_num_movable_components_per_detection_template (
    ) const
    {
        return 0;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename feature_extractor_type
        >
    long scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::
    get_num_dimensions (
    ) const
    {
        unsigned long width, height;
        compute_fhog_window_size(width,height);
        return width*height*fe.get_num_planes();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename feature_extractor_type
        >
    unsigned long scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::
    get_max_pyramid_levels (
    ) const
    {
        return max_pyramid_levels;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename feature_extractor_type
        >
    void scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::
    set_max_pyramid_levels (
        unsigned long max_levels
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(max_levels > 0 ,
            "\t void scan_fhog_pyramid::set_max_pyramid_levels()"
            << "\n\t You can't have zero levels. "
            << "\n\t max_levels: " << max_levels
            << "\n\t this: " << this
            );

        max_pyramid_levels = max_levels;
    }

// ----------------------------------------------------------------------------------------

    namespace impl
    {
        inline bool compare_pair_rect (
            const std::pair<double, rectangle>& a,
            const std::pair<double, rectangle>& b
        )
        {
            return a.first < b.first;
        }

        template <
            typename pyramid_type,
            typename feature_extractor_type,
            typename fhog_filterbank
            >
        void detect_from_fhog_pyramid (
            const array<array<array2d<float> > >& feats,
            const feature_extractor_type& fe,
            const fhog_filterbank& w,
            const double thresh,
            const unsigned long det_box_height,
            const unsigned long det_box_width,
            const int cell_size,
            const int filter_rows_padding,
            const int filter_cols_padding,
            std::vector<std::pair<double, rectangle> >& dets
        )
        {
            dets.clear();

            array2d<float> saliency_image;
            pyramid_type pyr;

            // for all pyramid levels
            for (unsigned long l = 0; l < feats.size(); ++l)
            {
                const rectangle area = apply_filters_to_fhog(w, feats[l], saliency_image);

                // now search the saliency image for any detections
                for (long r = area.top(); r <= area.bottom(); ++r)
                {
                    for (long c = area.left(); c <= area.right(); ++c)
                    {
                        // if we found a detection
                        if (saliency_image[r][c] >= thresh)
                        {
                            rectangle rect = fe.feats_to_image(centered_rect(point(c,r),det_box_width,det_box_height),
                                cell_size, filter_rows_padding, filter_cols_padding);
                            rect = pyr.rect_up(rect, l);
                            dets.push_back(std::make_pair(saliency_image[r][c], rect));
                        }
                    }
                }
            }

            std::sort(dets.rbegin(), dets.rend(), compare_pair_rect);
        }

        inline bool overlaps_any_box (
            const test_box_overlap& tester,
            const std::vector<rect_detection>& rects,
            const rect_detection& rect
        )
        {
            for (unsigned long i = 0; i < rects.size(); ++i)
            {
                // Only compare detections from the same detector.  That is, we don't want
                // the output of one detector to stop on the output of another detector.
                if (rects[i].weight_index == rect.weight_index && tester(rects[i].rect, rect.rect))
                    return true;
            }
            return false;
        }

    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename feature_extractor_type
        >
    void scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::
    detect (
        const fhog_filterbank& w,
        std::vector<std::pair<double, rectangle> >& dets,
        const double thresh
    ) const
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(is_loaded_with_image() &&
                    w.get_num_dimensions() == get_num_dimensions(),
            "\t void scan_fhog_pyramid::detect()"
            << "\n\t Invalid inputs were given to this function "
            << "\n\t is_loaded_with_image(): " << is_loaded_with_image()
            << "\n\t w.get_num_dimensions(): " << w.get_num_dimensions()
            << "\n\t get_num_dimensions():   " << get_num_dimensions()
            << "\n\t this: " << this
            );

        unsigned long width, height;
        compute_fhog_window_size(width,height);

        impl::detect_from_fhog_pyramid<pyramid_type>(feats, fe, w, thresh,
            height-2*padding, width-2*padding, cell_size, height, width, dets);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename feature_extractor_type
        >
    const rectangle scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::
    get_best_matching_rect (
        const rectangle& rect
    ) const
    {
        rectangle mapped_rect, fhog_rect;
        unsigned long best_level;
        get_mapped_rect_and_metadata(max_pyramid_levels, rect, mapped_rect, fhog_rect, best_level);
        return mapped_rect;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename feature_extractor_type
        >
    void scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::
    get_mapped_rect_and_metadata (
        const unsigned long number_pyramid_levels,
        const rectangle& rect,
        rectangle& mapped_rect,
        rectangle& fhog_rect,
        unsigned long& best_level
    ) const
    {
        pyramid_type pyr;
        best_level = 0;
        double best_match_score = -1;

        unsigned long width, height;
        compute_fhog_window_size(width,height);

        // Figure out the pyramid level which best matches rect against our detection
        // window.
        for (unsigned long l = 0; l < number_pyramid_levels; ++l)
        {
            const rectangle rect_fhog_space = fe.image_to_feats(pyr.rect_down(rect,l), cell_size, height,width);

            const rectangle win_image_space = pyr.rect_up(fe.feats_to_image(centered_rect(center(rect_fhog_space),width-2*padding,height-2*padding), cell_size, height,width), l);

            const double match_score = get_match_score(win_image_space, rect);
            if (match_score > best_match_score)
            {
                best_match_score = match_score;
                best_level = l;
                fhog_rect = centered_rect(center(rect_fhog_space), width, height);
            }

            if (rect_fhog_space.area() <= 1)
                break;
        }
        mapped_rect = pyr.rect_up(fe.feats_to_image(shrink_rect(fhog_rect,padding), cell_size,height,width),best_level);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename feature_extractor_type
        >
    full_object_detection scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::
    get_full_object_detection (
        const rectangle& rect,
        const feature_vector_type&
    ) const
    {
        return full_object_detection(rect);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename feature_extractor_type
        >
    void scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::
    get_feature_vector (
        const full_object_detection& obj,
        feature_vector_type& psi
    ) const
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(is_loaded_with_image() &&
                    psi.size() >= get_num_dimensions() &&
                    obj.num_parts() == 0,
            "\t void scan_fhog_pyramid::get_feature_vector()"
            << "\n\t Invalid inputs were given to this function "
            << "\n\t is_loaded_with_image(): " << is_loaded_with_image()
            << "\n\t psi.size():             " << psi.size()
            << "\n\t get_num_dimensions():   " << get_num_dimensions()
            << "\n\t obj.num_parts():                            " << obj.num_parts()
            << "\n\t this: " << this
            );

        rectangle mapped_rect;
        unsigned long best_level;
        rectangle fhog_rect;
        get_mapped_rect_and_metadata(feats.size(), obj.get_rect(), mapped_rect, fhog_rect, best_level);

        long i = 0;
        for (unsigned long ii = 0; ii < feats[best_level].size(); ++ii)
        {
            const rectangle rect = get_rect(feats[best_level][0]);
            for (long r = fhog_rect.top(); r <= fhog_rect.bottom(); ++r)
            {
                for (long c = fhog_rect.left(); c <= fhog_rect.right(); ++c)
                {
                    if (rect.contains(c,r))
                        psi(i) += feats[best_level][ii][r][c];
                    ++i;
                }
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename feature_extractor_type
        >
    void scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::
    set_min_pyramid_layer_size (
        unsigned long width,
        unsigned long height
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(width > 0 && height > 0 ,
            "\t void scan_fhog_pyramid::set_min_pyramid_layer_size()"
            << "\n\t These sizes can't be zero. "
            << "\n\t width:  " << width
            << "\n\t height: " << height
            << "\n\t this:   " << this
            );

        min_pyramid_layer_width = width;
        min_pyramid_layer_height = height;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename feature_extractor_type
        >
    unsigned long scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::
    get_min_pyramid_layer_width (
    ) const
    {
        return min_pyramid_layer_width;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename feature_extractor_type
        >
    unsigned long scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::
    get_min_pyramid_layer_height (
    ) const
    {
        return min_pyramid_layer_height;
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename feature_extractor_type
        >
    matrix<unsigned char> draw_fhog (
        const object_detector<scan_fhog_pyramid<Pyramid_type,feature_extractor_type> >& detector,
        const unsigned long weight_index = 0,
        const long cell_draw_size = 15
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(weight_index < detector.num_detectors(),
            "\t matrix draw_fhog()"
            << "\n\t Invalid arguments were given to this function. "
            << "\n\t weight_index:             " << weight_index
            << "\n\t detector.num_detectors(): " << detector.num_detectors()
            );
        DLIB_ASSERT(cell_draw_size > 0 && detector.get_w(weight_index).size() >= detector.get_scanner().get_num_dimensions(),
            "\t matrix draw_fhog()"
            << "\n\t Invalid arguments were given to this function. "
            << "\n\t cell_draw_size:                              " << cell_draw_size
            << "\n\t weight_index:                                " << weight_index
            << "\n\t detector.get_w(weight_index).size():         " << detector.get_w(weight_index).size()
            << "\n\t detector.get_scanner().get_num_dimensions(): " << detector.get_scanner().get_num_dimensions()
            );

        typename scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::fhog_filterbank fb = detector.get_scanner().build_fhog_filterbank(detector.get_w(weight_index));
        return draw_fhog(fb.get_filters(),cell_draw_size);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename feature_extractor_type
        >
    unsigned long num_separable_filters (
        const object_detector<scan_fhog_pyramid<Pyramid_type,feature_extractor_type> >& detector,
        const unsigned long weight_index = 0
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(weight_index < detector.num_detectors(),
            "\t unsigned long num_separable_filters()"
            << "\n\t Invalid arguments were given to this function. "
            << "\n\t weight_index:             " << weight_index
            << "\n\t detector.num_detectors(): " << detector.num_detectors()
            );
        DLIB_ASSERT(detector.get_w(weight_index).size() >= detector.get_scanner().get_num_dimensions() ,
            "\t unsigned long num_separable_filters()"
            << "\n\t Invalid arguments were given to this function. "
            << "\n\t detector.get_w(weight_index).size():         " << detector.get_w(weight_index).size()
            << "\n\t detector.get_scanner().get_num_dimensions(): " << detector.get_scanner().get_num_dimensions()
            );

        typename scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::fhog_filterbank fb = detector.get_scanner().build_fhog_filterbank(detector.get_w(weight_index));
        return fb.num_separable_filters();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename feature_extractor_type
        >
    object_detector<scan_fhog_pyramid<Pyramid_type,feature_extractor_type> > threshold_filter_singular_values (
        const object_detector<scan_fhog_pyramid<Pyramid_type,feature_extractor_type> >& detector,
        double thresh,
        const unsigned long weight_index = 0
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(thresh >= 0 ,
            "\t object_detector threshold_filter_singular_values()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t thresh: " << thresh
        );

        DLIB_ASSERT(weight_index < detector.num_detectors(),
            "\t object_detector threshold_filter_singular_values()"
            << "\n\t Invalid arguments were given to this function. "
            << "\n\t weight_index:             " << weight_index
            << "\n\t detector.num_detectors(): " << detector.num_detectors()
            );
        DLIB_ASSERT(detector.get_w(weight_index).size() >= detector.get_scanner().get_num_dimensions() ,
            "\t object_detector threshold_filter_singular_values()"
            << "\n\t Invalid arguments were given to this function. "
            << "\n\t detector.get_w(weight_index).size():         " << detector.get_w(weight_index).size()
            << "\n\t detector.get_scanner().get_num_dimensions(): " << detector.get_scanner().get_num_dimensions()
            );

        const unsigned long width = detector.get_scanner().get_fhog_window_width();
        const unsigned long height = detector.get_scanner().get_fhog_window_height();
        const long num_planes = detector.get_scanner().get_feature_extractor().get_num_planes();
        const long size = width*height;

        std::vector<matrix<double,0,1> > detector_weights;
        for (unsigned long j = 0; j < detector.num_detectors(); ++j)
        {
            matrix<double,0,1> weights = detector.get_w(j);

            if (j == weight_index)
            {
                matrix<double> u,v,w,f;
                for (long i = 0; i < num_planes; ++i)
                {
                    f = reshape(rowm(weights, range(i*size, (i+1)*size-1)), height, width);

                    svd3(f, u,w,v);
                    const double scaled_thresh = std::max(1e-3, max(w)*thresh);
                    w = round_zeros(w, scaled_thresh);
                    f = u*diagm(w)*trans(v);

                    set_rowm(weights,range(i*size, (i+1)*size-1)) = reshape_to_column_vector(f);
                }
            }
            detector_weights.push_back(weights);
        }

        return object_detector<scan_fhog_pyramid<Pyramid_type,feature_extractor_type> >(detector.get_scanner(),
                                                                 detector.get_overlap_tester(),
                                                                 detector_weights);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename feature_extractor_type,
        typename svm_struct_prob_type
        >
    void configure_nuclear_norm_regularizer (
        const scan_fhog_pyramid<Pyramid_type,feature_extractor_type>& scanner,
        svm_struct_prob_type& prob
    )
    {
        const double strength = scanner.get_nuclear_norm_regularization_strength();
        const long num_planes = scanner.get_feature_extractor().get_num_planes();
        if (strength != 0)
        {
            const unsigned long width = scanner.get_fhog_window_width();
            const unsigned long height = scanner.get_fhog_window_height();
            for (long i = 0; i < num_planes; ++i)
            {
                prob.add_nuclear_norm_regularizer(i*width*height, height, width, strength);
            }
            prob.set_cache_based_epsilon(0.001);
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename feature_extractor_type
        >
    struct processed_weight_vector<scan_fhog_pyramid<Pyramid_type,feature_extractor_type> >
    {
        processed_weight_vector(){}

        typedef matrix<double,0,1> feature_vector_type;
        typedef typename scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::fhog_filterbank fhog_filterbank;

        void init (
            const scan_fhog_pyramid<Pyramid_type,feature_extractor_type>& scanner
        )
        {
            fb = scanner.build_fhog_filterbank(w);
        }

        const fhog_filterbank& get_detect_argument() const { return fb; }

        feature_vector_type w;
        fhog_filterbank fb;

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename pyramid_type,
        typename image_type
        >
    void evaluate_detectors (
        const std::vector<object_detector<scan_fhog_pyramid<pyramid_type> > >& detectors,
        const image_type& img,
        std::vector<rect_detection>& dets,
        const double adjust_threshold = 0
    )
    {
        typedef scan_fhog_pyramid<pyramid_type> scanner_type;

        dets.clear();
        if (detectors.size() == 0)
            return;

        const unsigned long cell_size = detectors[0].get_scanner().get_cell_size();

        // Find the maximum sized filters and also most extreme pyramiding settings used.
        unsigned long max_filter_width = 0;
        unsigned long max_filter_height = 0;
        unsigned long min_pyramid_layer_width = std::numeric_limits<unsigned long>::max();
        unsigned long min_pyramid_layer_height = std::numeric_limits<unsigned long>::max();
        unsigned long max_pyramid_levels = 0;
        bool all_cell_sizes_the_same = true;
        for (unsigned long i = 0; i < detectors.size(); ++i)
        {
            const scanner_type& scanner = detectors[i].get_scanner();
            max_filter_width = std::max(max_filter_width, scanner.get_fhog_window_width());
            max_filter_height = std::max(max_filter_height, scanner.get_fhog_window_height());
            max_pyramid_levels = std::max(max_pyramid_levels, scanner.get_max_pyramid_levels());
            min_pyramid_layer_width = std::min(min_pyramid_layer_width, scanner.get_min_pyramid_layer_width());
            min_pyramid_layer_height = std::min(min_pyramid_layer_height, scanner.get_min_pyramid_layer_height());
            if (cell_size != scanner.get_cell_size())
                all_cell_sizes_the_same = false;
        }

        std::vector<rect_detection> dets_accum;
        // Do to the HOG feature extraction to make the fhog pyramid.  Again, note that we
        // are making a pyramid that will work with any of the detectors.  But only if all
        // the cell sizes are the same.  If they aren't then we have to calculate the
        // pyramid for each detector individually.
        array<array<array2d<float> > > feats;
        if (all_cell_sizes_the_same)
        {
            impl::create_fhog_pyramid<pyramid_type>(img,
                detectors[0].get_scanner().get_feature_extractor(), feats, cell_size,
                max_filter_height, max_filter_width, min_pyramid_layer_width,
                min_pyramid_layer_height, max_pyramid_levels);
        }

        std::vector<std::pair<double, rectangle> > temp_dets;
        for (unsigned long i = 0; i < detectors.size(); ++i)
        {
            const scanner_type& scanner = detectors[i].get_scanner();
            if (!all_cell_sizes_the_same)
            {
                impl::create_fhog_pyramid<pyramid_type>(img,
                    scanner.get_feature_extractor(), feats, scanner.get_cell_size(),
                    max_filter_height, max_filter_width, min_pyramid_layer_width,
                    min_pyramid_layer_height, max_pyramid_levels);
            }

            const unsigned long det_box_width  = scanner.get_fhog_window_width()  - 2*scanner.get_padding();
            const unsigned long det_box_height = scanner.get_fhog_window_height() - 2*scanner.get_padding();
            // A single detector object might itself have multiple weight vectors in it. So
            // we need to evaluate all of them.
            for (unsigned d = 0; d < detectors[i].num_detectors(); ++d)
            {
                const double thresh = detectors[i].get_processed_w(d).w(scanner.get_num_dimensions());

                impl::detect_from_fhog_pyramid<pyramid_type>(feats, scanner.get_feature_extractor(),
                    detectors[i].get_processed_w(d).get_detect_argument(), thresh+adjust_threshold,
                    det_box_height, det_box_width, cell_size, max_filter_height,
                    max_filter_width, temp_dets);

                for (unsigned long j = 0; j < temp_dets.size(); ++j)
                {
                    rect_detection temp;
                    temp.detection_confidence = temp_dets[j].first-thresh;
                    temp.weight_index = i;
                    temp.rect = temp_dets[j].second;
                    dets_accum.push_back(temp);
                }
            }
        }

        // Do non-max suppression
        dets.clear();
        if (detectors.size() > 1)
            std::sort(dets_accum.rbegin(), dets_accum.rend());
        for (unsigned long i = 0; i < dets_accum.size(); ++i)
        {
            const test_box_overlap tester = detectors[dets_accum[i].weight_index].get_overlap_tester();
            if (impl::overlaps_any_box(tester, dets, dets_accum[i]))
                continue;

            dets.push_back(dets_accum[i]);
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename image_type
        >
    std::vector<rectangle> evaluate_detectors (
        const std::vector<object_detector<scan_fhog_pyramid<Pyramid_type> > >& detectors,
        const image_type& img,
        const double adjust_threshold = 0
    )
    {
        std::vector<rectangle> out_dets;
        std::vector<rect_detection> dets;
        evaluate_detectors(detectors, img, dets, adjust_threshold);
        out_dets.reserve(dets.size());
        for (unsigned long i = 0; i < dets.size(); ++i)
            out_dets.push_back(dets[i].rect);
        return out_dets;
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SCAN_fHOG_PYRAMID_Hh_


dlib C++ Library - scan_image.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SCAN_iMAGE_Hh_
#define DLIB_SCAN_iMAGE_Hh_

#include <vector>
#include <utility>
#include "scan_image_abstract.h"
#include "../matrix.h"
#include "../algs.h"
#include "../rand.h"
#include "../array2d.h"
#include "../image_transforms/spatial_filtering.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    namespace impl
    {

        inline rectangle bounding_box_of_rects (
            const std::vector<std::pair<unsigned int, rectangle> >& rects,
            const point& position
        )
        /*!
            ensures
                - returns the smallest rectangle that contains all the
                  rectangles in rects.  That is, returns the rectangle that
                  contains translate_rect(rects[i].second,position) for all valid i.
        !*/
        {
            rectangle rect;

            for (unsigned long i = 0; i < rects.size(); ++i)
            {
                rect += translate_rect(rects[i].second,position);
            }

            return rect;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_array_type
        >
    bool all_images_same_size (
        const image_array_type& images
    )
    {
        if (images.size() == 0)
            return true;

        for (unsigned long i = 0; i < images.size(); ++i)
        {
            if (num_rows(images[0]) != num_rows(images[i]) ||
                num_columns(images[0]) != num_columns(images[i]))
                return false;
        }

        return true;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_array_type
        >
    double sum_of_rects_in_images (
        const image_array_type& images,
        const std::vector<std::pair<unsigned int, rectangle> >& rects,
        const point& position
    )
    {
        DLIB_ASSERT(all_images_same_size(images),
            "\t double sum_of_rects_in_images()"
            << "\n\t Invalid arguments given to this function."
            << "\n\t all_images_same_size(images): " << all_images_same_size(images)
        );
#ifdef ENABLE_ASSERTS
        for (unsigned long i = 0; i < rects.size(); ++i)
        {
            DLIB_ASSERT(rects[i].first < images.size(),
                "\t double sum_of_rects_in_images()"
                << "\n\t rects["<<i<<"].first must refer to a valid image."
                << "\n\t rects["<<i<<"].first: " << rects[i].first
                << "\n\t images.size(): " << images.size()
            );
        }
#endif

        typedef typename image_traits<typename image_array_type::type>::pixel_type pixel_type;
        typedef typename promote<pixel_type>::type ptype;

        ptype temp = 0;

        for (unsigned long i = 0; i < rects.size(); ++i)
        {
            const typename image_array_type::type& img = images[rects[i].first];
            const rectangle rect = get_rect(img).intersect(translate_rect(rects[i].second,position));
            temp += sum(matrix_cast<ptype>(subm(mat(img), rect)));
        }

        return static_cast<double>(temp);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_array_type
        >
    double sum_of_rects_in_images_movable_parts (
        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 point& position
    )
    {
        DLIB_ASSERT(all_images_same_size(images) && center(window) == point(0,0),
            "\t double sum_of_rects_in_images_movable_parts()"
            << "\n\t Invalid arguments given to this function."
            << "\n\t all_images_same_size(images): " << all_images_same_size(images)
            << "\n\t center(window): " << center(window)
        );
#ifdef ENABLE_ASSERTS
        for (unsigned long i = 0; i < fixed_rects.size(); ++i)
        {
            DLIB_ASSERT(fixed_rects[i].first < images.size(),
                "\t double sum_of_rects_in_images_movable_parts()"
                << "\n\t fixed_rects["<<i<<"].first must refer to a valid image."
                << "\n\t fixed_rects["<<i<<"].first: " << fixed_rects[i].first
                << "\n\t images.size(): " << images.size()
            );
        }
        for (unsigned long i = 0; i < movable_rects.size(); ++i)
        {
            DLIB_ASSERT(movable_rects[i].first < images.size(),
                "\t double sum_of_rects_in_images_movable_parts()"
                << "\n\t movable_rects["<<i<<"].first must refer to a valid image."
                << "\n\t movable_rects["<<i<<"].first: " << movable_rects[i].first
                << "\n\t images.size(): " << images.size()
            );
            DLIB_ASSERT(center(movable_rects[i].second) == point(0,0),
                "\t double sum_of_rects_in_images_movable_parts()"
                << "\n\t movable_rects["<<i<<"].second: " << movable_rects[i].second
            );
        }
#endif
        typedef typename image_traits<typename image_array_type::type>::pixel_type pixel_type;
        typedef typename promote<pixel_type>::type ptype;

        ptype temp = 0;

        // compute TOTAL_FIXED part
        for (unsigned long i = 0; i < fixed_rects.size(); ++i)
        {
            const typename image_array_type::type& img = images[fixed_rects[i].first];
            const rectangle rect = get_rect(img).intersect(translate_rect(fixed_rects[i].second,position));
            temp += sum(matrix_cast<ptype>(subm(mat(img), rect)));
        }

        if (images.size() > 0)
        {
            // compute TOTAL_MOVABLE part
            array2d<ptype> tempimg(images[0].nr(), images[0].nc());
            for (unsigned long i = 0; i < movable_rects.size(); ++i)
            {
                const typename image_array_type::type& img = images[movable_rects[i].first];

                sum_filter_assign(img, tempimg, movable_rects[i].second);

                const rectangle rect = get_rect(tempimg).intersect(translate_rect(window,position));
                if (rect.is_empty() == false)
                    temp += std::max(0,max(matrix_cast<ptype>(subm(mat(tempimg), rect))));
            }
        }

        return static_cast<double>(temp);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    void find_points_above_thresh (
        std::vector<std::pair<double, point> >& dets,
        const image_type& img_,
        const double thresh,
        const unsigned long max_dets
    )
    {
        const_image_view<image_type> img(img_);
        typedef typename image_traits<image_type>::pixel_type ptype;

        dets.clear();
        if (max_dets == 0)
            return;

        unsigned long count = 0;
        dlib::rand rnd;
        for (long r = 0; r < img.nr(); ++r)
        {
            for (long c = 0; c < img.nc(); ++c)
            {
                const ptype val = img[r][c];
                if (val >= thresh)
                {
                    ++count;

                    if (dets.size() < max_dets)
                    {
                        dets.push_back(std::make_pair(val, point(c,r)));
                    }
                    else
                    {
                        // The idea here is to cause us to randomly sample possible detection
                        // locations throughout the image rather than just stopping the detection
                        // procedure once we hit the max_dets limit. So this method will result
                        // in a random subsample of all the detections >= thresh being in dets
                        // at the end of scan_image().
                        const unsigned long random_index = rnd.get_random_32bit_number()%count;
                        if (random_index < dets.size())
                        {
                            dets[random_index] = std::make_pair(val, point(c,r));
                        }
                    }
                }
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_array_type
        >
    void scan_image (
        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
    )
    {
        DLIB_ASSERT(images.size() > 0 && rects.size() > 0 && all_images_same_size(images),
            "\t void scan_image()"
            << "\n\t Invalid arguments given to this function."
            << "\n\t images.size(): " << images.size()
            << "\n\t rects.size():  " << rects.size()
            << "\n\t all_images_same_size(images): " << all_images_same_size(images)
        );
#ifdef ENABLE_ASSERTS
        for (unsigned long i = 0; i < rects.size(); ++i)
        {
            DLIB_ASSERT(rects[i].first < images.size(),
                "\t void scan_image()"
                << "\n\t rects["<<i<<"].first must refer to a valid image."
                << "\n\t rects["<<i<<"].first: " << rects[i].first
                << "\n\t images.size(): " << images.size()
            );
        }
#endif

        typedef typename image_traits<typename image_array_type::type>::pixel_type pixel_type;
        typedef typename promote<pixel_type>::type ptype;

        array2d<ptype> accum(images[0].nr(), images[0].nc());
        assign_all_pixels(accum, 0);

        for (unsigned long i = 0; i < rects.size(); ++i)
            sum_filter(images[rects[i].first], accum, rects[i].second);

        find_points_above_thresh(dets, accum, thresh, max_dets);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_array_type
        >
    void 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 max_dets
    )
    {
        DLIB_ASSERT(images.size() > 0 && all_images_same_size(images) &&
                    center(window) == point(0,0) && window.area() > 0,
            "\t void scan_image_movable_parts()"
            << "\n\t Invalid arguments given to this function."
            << "\n\t all_images_same_size(images): " << all_images_same_size(images)
            << "\n\t center(window): " << center(window)
            << "\n\t window.area():  " << window.area()
            << "\n\t images.size():  " << images.size()
        );
#ifdef ENABLE_ASSERTS
        for (unsigned long i = 0; i < fixed_rects.size(); ++i)
        {
            DLIB_ASSERT(fixed_rects[i].first < images.size(),
                "\t void scan_image_movable_parts()"
                << "\n\t Invalid arguments given to this function."
                << "\n\t fixed_rects["<<i<<"].first must refer to a valid image."
                << "\n\t fixed_rects["<<i<<"].first: " << fixed_rects[i].first
                << "\n\t images.size(): " << images.size()
            );
        }
        for (unsigned long i = 0; i < movable_rects.size(); ++i)
        {
            DLIB_ASSERT(movable_rects[i].first < images.size(),
                "\t void scan_image_movable_parts()"
                << "\n\t Invalid arguments given to this function."
                << "\n\t movable_rects["<<i<<"].first must refer to a valid image."
                << "\n\t movable_rects["<<i<<"].first: " << movable_rects[i].first
                << "\n\t images.size(): " << images.size()
            );
            DLIB_ASSERT(center(movable_rects[i].second) == point(0,0) &&
                        movable_rects[i].second.area() > 0,
                "\t void scan_image_movable_parts()"
                << "\n\t Invalid arguments given to this function."
                << "\n\t movable_rects["<<i<<"].second: " << movable_rects[i].second
                << "\n\t movable_rects["<<i<<"].second.area(): " << movable_rects[i].second.area()
            );
        }
#endif

        if (movable_rects.size() == 0 && fixed_rects.size() == 0)
            return;

        typedef typename image_traits<typename image_array_type::type>::pixel_type pixel_type;
        typedef typename promote<pixel_type>::type ptype;

        array2d<ptype> accum(images[0].nr(), images[0].nc());
        assign_all_pixels(accum, 0);

        for (unsigned long i = 0; i < fixed_rects.size(); ++i)
            sum_filter(images[fixed_rects[i].first], accum, fixed_rects[i].second);

        array2d<ptype> temp(accum.nr(), accum.nc());
        for (unsigned long i = 0; i < movable_rects.size(); ++i)
        {
            const rectangle rect = movable_rects[i].second;
            sum_filter_assign(images[movable_rects[i].first], temp, rect);
            max_filter(temp, accum, window.width(), window.height(), 0);
        }

        find_points_above_thresh(dets, accum, thresh, max_dets);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SCAN_iMAGE_Hh_


dlib C++ Library - scan_image_boxes.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SCAN_IMAGE_bOXES_Hh_
#define DLIB_SCAN_IMAGE_bOXES_Hh_

#include "scan_image_boxes_abstract.h"
#include "../matrix.h"
#include "../geometry.h"
#include "../array2d.h"
#include <vector>
#include "../image_processing/full_object_detection.h"
#include "../image_transforms.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class default_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, rects);
        }
    };

    inline void serialize(const default_box_generator&, std::ostream& ) {}
    inline void deserialize(default_box_generator&, std::istream& ) {}

// ----------------------------------------------------------------------------------------

    template <
        typename Feature_extractor_type,
        typename Box_generator = default_box_generator
        >
    class scan_image_boxes : noncopyable
    {

    public:

        typedef matrix<double,0,1> feature_vector_type;

        typedef Feature_extractor_type feature_extractor_type;
        typedef Box_generator box_generator;

        scan_image_boxes (
        );

        template <
            typename image_type
            >
        void load (
            const image_type& img
        );

        inline bool is_loaded_with_image (
        ) const;

        inline void copy_configuration(
            const feature_extractor_type& fe
        );

        inline void copy_configuration(
            const box_generator& bg
        );

        const box_generator& get_box_generator (
        ) const { return detect_boxes; }

        const Feature_extractor_type& get_feature_extractor (
        ) const { return feats; }

        inline void copy_configuration (
            const scan_image_boxes& item
        );

        inline long get_num_dimensions (
        ) const;

        unsigned long get_num_spatial_pyramid_levels (
        ) const;

        void set_num_spatial_pyramid_levels (
            unsigned long levels
        );

        void detect (
            const feature_vector_type& w,
            std::vector<std::pair<double, rectangle> >& dets,
            const double thresh
        ) const;

        void get_feature_vector (
            const full_object_detection& obj,
            feature_vector_type& psi
        ) const;

        full_object_detection get_full_object_detection (
            const rectangle& rect,
            const feature_vector_type& w
        ) const;

        const rectangle get_best_matching_rect (
            const rectangle& rect
        ) const;
        /*!
            requires
                - is_loaded_with_image() == true
        !*/

        inline unsigned long get_num_detection_templates (
        ) const { return 1; }

        inline unsigned long get_num_movable_components_per_detection_template (
        ) const { return 0; }

        template <typename T, typename U>
        friend void serialize (
            const scan_image_boxes<T,U>& item,
            std::ostream& out
        );

        template <typename T, typename U>
        friend void deserialize (
            scan_image_boxes<T,U>& item,
            std::istream& in
        );

    private:
        static bool compare_pair_rect (
            const std::pair<double, rectangle>& a,
            const std::pair<double, rectangle>& b
        )
        {
            return a.first < b.first;
        }

        void test_coordinate_transforms()
        {
            for (long x = -10; x <= 10; x += 10)
            {
                for (long y = -10; y <= 10; y += 10)
                {
                    const rectangle rect = centered_rect(x,y,5,6);
                    rectangle a;

                    a = feats.image_to_feat_space(rect);
                    if (a.width()  > 10000000 || a.height() > 10000000 )
                    {
                        DLIB_CASSERT(false, "The image_to_feat_space() routine is outputting rectangles of an implausibly "
                                     << "\nlarge size.  This means there is probably a bug in your feature extractor.");
                    }
                    a = feats.feat_to_image_space(rect);
                    if (a.width()  > 10000000 || a.height() > 10000000 )
                    {
                        DLIB_CASSERT(false, "The feat_to_image_space() routine is outputting rectangles of an implausibly "
                                     << "\nlarge size.  This means there is probably a bug in your feature extractor.");
                    }
                }
            }

        }

        static void add_grid_rects (
            std::vector<rectangle>& rects,
            const rectangle& object_box,
            unsigned int cells_x,
            unsigned int cells_y
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(cells_x > 0 && cells_y > 0,
                "\t void add_grid_rects()"
                << "\n\t The number of cells along a dimension can't be zero. "
                << "\n\t cells_x: " << cells_x
                << "\n\t cells_y: " << cells_y
            );

            const matrix_range_exp<double>& x = linspace(object_box.left(), object_box.right(), cells_x+1);
            const matrix_range_exp<double>& y = linspace(object_box.top(), object_box.bottom(), cells_y+1);

            for (long j = 0; j+1 < y.size(); ++j)
            {
                for (long i = 0; i+1 < x.size(); ++i)
                {
                    const dlib::vector<double,2> tl(x(i),y(j));
                    const dlib::vector<double,2> br(x(i+1),y(j+1));
                    rects.push_back(rectangle(tl,br));
                }
            }
        }

        void get_feature_extraction_regions (
            const rectangle& rect,
            std::vector<rectangle>& regions
        ) const
        /*!
            ensures
                - #regions.size() is always the same number no matter what the input is.  The
                  regions also have a consistent ordering.
                - all the output rectangles are contained within rect.
        !*/
        {
            regions.clear();

            for (unsigned int l = 1; l <= num_spatial_pyramid_levels; ++l)
            {
                const int cells = (int)std::pow(2.0, l-1.0);
                add_grid_rects(regions, rect, cells, cells);
            }
        }

        unsigned int get_num_components_per_detection_template(
        ) const
        {
            return (unsigned int)(std::pow(4.0,(double)num_spatial_pyramid_levels)-1)/3;
        }

        feature_extractor_type feats;
        std::vector<rectangle> search_rects;
        bool loaded_with_image;
        unsigned int num_spatial_pyramid_levels;
        box_generator detect_boxes;

        const long box_sizedims;
        const long box_maxsize;
    };

// ----------------------------------------------------------------------------------------

    template <typename T, typename U>
    void serialize (
        const scan_image_boxes<T,U>& item,
        std::ostream& out
    )
    {
        int version = 1;
        serialize(version, out);
        serialize(item.feats, out);
        serialize(item.search_rects, out);
        serialize(item.loaded_with_image, out);
        serialize(item.num_spatial_pyramid_levels, out);
        serialize(item.detect_boxes, out);
        serialize(item.get_num_dimensions(), out);
    }

// ----------------------------------------------------------------------------------------

    template <typename T, typename U>
    void deserialize (
        scan_image_boxes<T,U>& item,
        std::istream& in
    )
    {
        int version = 0;
        deserialize(version, in);
        if (version != 1)
            throw serialization_error("Unsupported version found when deserializing a scan_image_boxes object.");

        deserialize(item.feats, in);
        deserialize(item.search_rects, in);
        deserialize(item.loaded_with_image, in);
        deserialize(item.num_spatial_pyramid_levels, in);
        deserialize(item.detect_boxes, in);

        // When developing some feature extractor, it's easy to accidentally change its
        // number of dimensions and then try to deserialize data from an older version of
        // your extractor into the current code.  This check is here to catch that kind of
        // user error.
        long dims;
        deserialize(dims, in);
        if (item.get_num_dimensions() != dims)
            throw serialization_error("Number of dimensions in serialized scan_image_boxes doesn't match the expected number.");
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                         scan_image_boxes member functions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename Feature_extractor_type,
        typename Box_generator
        >
    scan_image_boxes<Feature_extractor_type,Box_generator>::
    scan_image_boxes (
    ) :
        loaded_with_image(false),
        num_spatial_pyramid_levels(3),
        box_sizedims(20),
        box_maxsize(1200)
    {
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Feature_extractor_type,
        typename Box_generator
        >
    template <
        typename image_type
        >
    void scan_image_boxes<Feature_extractor_type,Box_generator>::
    load (
        const image_type& img
    )
    {
        feats.load(img);
        detect_boxes(img, search_rects);
        loaded_with_image = true;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Feature_extractor_type,
        typename Box_generator
        >
    bool scan_image_boxes<Feature_extractor_type,Box_generator>::
    is_loaded_with_image (
    ) const
    {
        return loaded_with_image;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Feature_extractor_type,
        typename Box_generator
        >
    void scan_image_boxes<Feature_extractor_type,Box_generator>::
    copy_configuration(
        const feature_extractor_type& fe
    )
    {
        test_coordinate_transforms();
        feats.copy_configuration(fe);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Feature_extractor_type,
        typename Box_generator
        >
    void scan_image_boxes<Feature_extractor_type,Box_generator>::
    copy_configuration(
        const box_generator& bg
    )
    {
        detect_boxes = bg;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Feature_extractor_type,
        typename Box_generator
        >
    void scan_image_boxes<Feature_extractor_type,Box_generator>::
    copy_configuration (
        const scan_image_boxes& item
    )
    {
        feats.copy_configuration(item.feats);
        detect_boxes = item.detect_boxes;
        num_spatial_pyramid_levels = item.num_spatial_pyramid_levels;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Feature_extractor_type,
        typename Box_generator
        >
    unsigned long scan_image_boxes<Feature_extractor_type,Box_generator>::
    get_num_spatial_pyramid_levels (
    ) const
    {
        return num_spatial_pyramid_levels;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Feature_extractor_type,
        typename Box_generator
        >
    void scan_image_boxes<Feature_extractor_type,Box_generator>::
    set_num_spatial_pyramid_levels (
        unsigned long levels
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(levels > 0,
            "\t void scan_image_boxes::set_num_spatial_pyramid_levels()"
            << "\n\t Invalid inputs were given to this function "
            << "\n\t levels: " << levels
            << "\n\t this: " << this
            );

        num_spatial_pyramid_levels = levels;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Feature_extractor_type,
        typename Box_generator
        >
    long scan_image_boxes<Feature_extractor_type,Box_generator>::
    get_num_dimensions (
    ) const
    {
        return feats.get_num_dimensions()*get_num_components_per_detection_template() + box_sizedims*2;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Feature_extractor_type,
        typename Box_generator
        >
    void scan_image_boxes<Feature_extractor_type,Box_generator>::
    detect (
        const feature_vector_type& w,
        std::vector<std::pair<double, rectangle> >& dets,
        const double thresh
    ) const
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(is_loaded_with_image() &&
                    w.size() >= get_num_dimensions(),
            "\t void scan_image_boxes::detect()"
            << "\n\t Invalid inputs were given to this function "
            << "\n\t is_loaded_with_image(): " << is_loaded_with_image()
            << "\n\t w.size():               " << w.size()
            << "\n\t get_num_dimensions():   " << get_num_dimensions()
            << "\n\t this: " << this
            );

        dets.clear();

        array<integral_image_generic<double> > saliency_images(get_num_components_per_detection_template());

        array2d<double> temp_img(feats.nr(), feats.nc());

        // build saliency images
        for (unsigned long i = 0; i < saliency_images.size(); ++i)
        {
            const unsigned long offset = 2*box_sizedims + feats.get_num_dimensions()*i;

            // make the basic saliency image for the i-th feature extraction region
            for (long r = 0; r < feats.nr(); ++r)
            {
                for (long c = 0; c < feats.nc(); ++c)
                {
                    const typename feature_extractor_type::descriptor_type& descriptor = feats(r,c);

                    double sum = 0;
                    for (unsigned long k = 0; k < descriptor.size(); ++k)
                    {
                        sum += w(descriptor[k].first + offset)*descriptor[k].second;
                    }
                    temp_img[r][c] = sum;
                }
            }

            // now convert base saliency image into final integral image
            saliency_images[i].load(temp_img);
        }

        // now search the saliency images
        std::vector<rectangle> regions;
        const rectangle bounds = get_rect(feats);
        for (unsigned long i = 0; i < search_rects.size(); ++i)
        {
            const rectangle rect = feats.image_to_feat_space(search_rects[i]).intersect(bounds);
            if (rect.is_empty())
                continue;
            get_feature_extraction_regions(rect, regions);
            double score = 0;
            for (unsigned long k = 0; k < regions.size(); ++k)
            {
                score += saliency_images[k].get_sum_of_area(regions[k]);
            }
            const double width = search_rects[i].width();
            const double height = search_rects[i].height();

            score += dot(linpiece(width,  linspace(0, box_maxsize, box_sizedims+1)), rowm(w, range(0,box_sizedims-1)));
            score += dot(linpiece(height, linspace(0, box_maxsize, box_sizedims+1)), rowm(w, range(box_sizedims,2*box_sizedims-1)));

            if (score >= thresh)
            {
                dets.push_back(std::make_pair(score, search_rects[i]));
            }
        }

        std::sort(dets.rbegin(), dets.rend(), compare_pair_rect);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Feature_extractor_type,
        typename Box_generator
        >
    const rectangle scan_image_boxes<Feature_extractor_type,Box_generator>::
    get_best_matching_rect (
        const rectangle& rect
    ) const
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(is_loaded_with_image(),
            "\t const rectangle scan_image_boxes::get_best_matching_rect()"
            << "\n\t Invalid inputs were given to this function "
            << "\n\t is_loaded_with_image(): " << is_loaded_with_image()
            << "\n\t this: " << this
            );

        double best_score = -1;
        rectangle best_rect;
        for (unsigned long i = 0; i < search_rects.size(); ++i)
        {
            const double score = (rect.intersect(search_rects[i])).area()/(double)(rect+search_rects[i]).area();
            if (score > best_score)
            {
                best_score = score;
                best_rect = search_rects[i];
            }
        }
        return best_rect;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Feature_extractor_type,
        typename Box_generator
        >
    full_object_detection scan_image_boxes<Feature_extractor_type,Box_generator>::
    get_full_object_detection (
        const rectangle& rect,
        const feature_vector_type& /*w*/
    ) const
    {
        return full_object_detection(rect);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Feature_extractor_type,
        typename Box_generator
        >
    void scan_image_boxes<Feature_extractor_type,Box_generator>::
    get_feature_vector (
        const full_object_detection& obj,
        feature_vector_type& psi
    ) const
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(is_loaded_with_image() &&
                    psi.size() >= get_num_dimensions() &&
                    obj.num_parts() == 0,
            "\t void scan_image_boxes::get_feature_vector()"
            << "\n\t Invalid inputs were given to this function "
            << "\n\t is_loaded_with_image(): " << is_loaded_with_image()
            << "\n\t psi.size():             " << psi.size()
            << "\n\t get_num_dimensions():   " << get_num_dimensions()
            << "\n\t obj.num_parts():                            " << obj.num_parts()
            << "\n\t this: " << this
            );

        const rectangle best_rect = get_best_matching_rect(obj.get_rect());
        const rectangle mapped_rect = feats.image_to_feat_space(best_rect).intersect(get_rect(feats));
        if (mapped_rect.is_empty())
            return;

        std::vector<rectangle> regions;
        get_feature_extraction_regions(mapped_rect, regions);

        // pull features out of all the boxes in regions.
        for (unsigned long j = 0; j < regions.size(); ++j)
        {
            const rectangle rect = regions[j];

            const unsigned long template_region_id = j;
            const unsigned long offset = box_sizedims*2 + feats.get_num_dimensions()*template_region_id;
            for (long r = rect.top(); r <= rect.bottom(); ++r)
            {
                for (long c = rect.left(); c <= rect.right(); ++c)
                {
                    const typename feature_extractor_type::descriptor_type& descriptor = feats(r,c);
                    for (unsigned long k = 0; k < descriptor.size(); ++k)
                    {
                        psi(descriptor[k].first + offset) += descriptor[k].second;
                    }
                }
            }
        }

        const double width = best_rect.width();
        const double height = best_rect.height();
        set_rowm(psi, range(0,box_sizedims-1))              += linpiece(width,  linspace(0, box_maxsize, box_sizedims+1));
        set_rowm(psi, range(box_sizedims,box_sizedims*2-1)) += linpiece(height, linspace(0, box_maxsize, box_sizedims+1));
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SCAN_IMAGE_bOXES_Hh_


dlib C++ Library - scan_image_custom.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SCAN_IMAGE_CuSTOM_Hh_
#define DLIB_SCAN_IMAGE_CuSTOM_Hh_

#include "scan_image_custom_abstract.h"
#include "../matrix.h"
#include "../geometry.h"
#include <vector>
#include "../image_processing/full_object_detection.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename Feature_extractor_type
        >
    class scan_image_custom : noncopyable
    {

    public:

        typedef matrix<double,0,1> feature_vector_type;
        typedef Feature_extractor_type feature_extractor_type;

        scan_image_custom (
        );

        template <
            typename image_type
            >
        void load (
            const image_type& img
        );

        inline bool is_loaded_with_image (
        ) const;

        inline void copy_configuration(
            const feature_extractor_type& fe
        );

        const Feature_extractor_type& get_feature_extractor (
        ) const { return feats; }

        inline void copy_configuration (
            const scan_image_custom& item
        );

        inline long get_num_dimensions (
        ) const;

        void detect (
            const feature_vector_type& w,
            std::vector<std::pair<double, rectangle> >& dets,
            const double thresh
        ) const;

        void get_feature_vector (
            const full_object_detection& obj,
            feature_vector_type& psi
        ) const;

        full_object_detection get_full_object_detection (
            const rectangle& rect,
            const feature_vector_type& w
        ) const;

        const rectangle get_best_matching_rect (
            const rectangle& rect
        ) const;

        inline unsigned long get_num_detection_templates (
        ) const { return 1; }

        inline unsigned long get_num_movable_components_per_detection_template (
        ) const { return 0; }

        template <typename T>
        friend void serialize (
            const scan_image_custom<T>& item,
            std::ostream& out
        );

        template <typename T>
        friend void deserialize (
            scan_image_custom<T>& item,
            std::istream& in
        );

    private:
        static bool compare_pair_rect (
            const std::pair<double, rectangle>& a,
            const std::pair<double, rectangle>& b
        )
        {
            return a.first < b.first;
        }

        DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST(
            has_compute_object_score,
            double,
            compute_object_score,
            ( const matrix<double,0,1>& w, const rectangle& obj) const
        );

        template <typename fe_type>
        typename enable_if<has_compute_object_score<fe_type> >::type compute_all_rect_scores (
            const fe_type& feats,
            const feature_vector_type& w,
            std::vector<std::pair<double, rectangle> >& dets,
            const double thresh
        ) const
        {
            for (unsigned long i = 0; i < search_rects.size(); ++i)
            {
                const double score = feats.compute_object_score(w, search_rects[i]);
                if (score >= thresh)
                {
                    dets.push_back(std::make_pair(score, search_rects[i]));
                }
            }
        }

        template <typename fe_type>
        typename disable_if<has_compute_object_score<fe_type> >::type compute_all_rect_scores (
            const fe_type& feats,
            const feature_vector_type& w,
            std::vector<std::pair<double, rectangle> >& dets,
            const double thresh
        ) const
        {
            matrix<double,0,1> psi(w.size());
            psi = 0;
            double prev_dot = 0;
            for (unsigned long i = 0; i < search_rects.size(); ++i)
            {
                // Reset these back to zero every so often to avoid the accumulation of
                // rounding error.  Note that the only reason we do this loop in this
                // complex way is to avoid needing to zero the psi vector every iteration.
                if ((i%500) == 499)
                {
                    psi = 0;
                    prev_dot = 0;
                }

                feats.get_feature_vector(search_rects[i], psi);
                const double cur_dot = dot(psi, w);
                const double score = cur_dot - prev_dot;
                if (score >= thresh)
                {
                    dets.push_back(std::make_pair(score, search_rects[i]));
                }
                prev_dot = cur_dot;
            }
        }

        feature_extractor_type feats;
        std::vector<rectangle> search_rects;
        bool loaded_with_image;
    };

// ----------------------------------------------------------------------------------------

    template <typename T>
    void serialize (
        const scan_image_custom<T>& item,
        std::ostream& out
    )
    {
        int version = 1;
        serialize(version, out);
        serialize(item.feats, out);
        serialize(item.search_rects, out);
        serialize(item.loaded_with_image, out);
        serialize(item.get_num_dimensions(), out);
    }

// ----------------------------------------------------------------------------------------

    template <typename T>
    void deserialize (
        scan_image_custom<T>& item,
        std::istream& in
    )
    {
        int version = 0;
        deserialize(version, in);
        if (version != 1)
            throw serialization_error("Unsupported version found when deserializing a scan_image_custom object.");

        deserialize(item.feats, in);
        deserialize(item.search_rects, in);
        deserialize(item.loaded_with_image, in);

        // When developing some feature extractor, it's easy to accidentally change its
        // number of dimensions and then try to deserialize data from an older version of
        // your extractor into the current code.  This check is here to catch that kind of
        // user error.
        long dims;
        deserialize(dims, in);
        if (item.get_num_dimensions() != dims)
            throw serialization_error("Number of dimensions in serialized scan_image_custom doesn't match the expected number.");
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                         scan_image_custom member functions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename Feature_extractor_type
        >
    scan_image_custom<Feature_extractor_type>::
    scan_image_custom (
    ) :
        loaded_with_image(false)
    {
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Feature_extractor_type
        >
    template <
        typename image_type
        >
    void scan_image_custom<Feature_extractor_type>::
    load (
        const image_type& img
    )
    {
        feats.load(img, search_rects);
        loaded_with_image = true;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Feature_extractor_type
        >
    bool scan_image_custom<Feature_extractor_type>::
    is_loaded_with_image (
    ) const
    {
        return loaded_with_image;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Feature_extractor_type
        >
    void scan_image_custom<Feature_extractor_type>::
    copy_configuration(
        const feature_extractor_type& fe
    )
    {
        feats.copy_configuration(fe);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Feature_extractor_type
        >
    void scan_image_custom<Feature_extractor_type>::
    copy_configuration (
        const scan_image_custom& item
    )
    {
        feats.copy_configuration(item.feats);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Feature_extractor_type
        >
    long scan_image_custom<Feature_extractor_type>::
    get_num_dimensions (
    ) const
    {
        return feats.get_num_dimensions();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Feature_extractor_type
        >
    void scan_image_custom<Feature_extractor_type>::
    detect (
        const feature_vector_type& w,
        std::vector<std::pair<double, rectangle> >& dets,
        const double thresh
    ) const
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(is_loaded_with_image() &&
                    w.size() >= get_num_dimensions(),
            "\t void scan_image_custom::detect()"
            << "\n\t Invalid inputs were given to this function "
            << "\n\t is_loaded_with_image(): " << is_loaded_with_image()
            << "\n\t w.size():               " << w.size()
            << "\n\t get_num_dimensions():   " << get_num_dimensions()
            << "\n\t this: " << this
            );

        dets.clear();
        compute_all_rect_scores(feats, w,dets,thresh);
        std::sort(dets.rbegin(), dets.rend(), compare_pair_rect);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Feature_extractor_type
        >
    const rectangle scan_image_custom<Feature_extractor_type>::
    get_best_matching_rect (
        const rectangle& rect
    ) const
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(is_loaded_with_image(),
            "\t const rectangle scan_image_custom::get_best_matching_rect()"
            << "\n\t Invalid inputs were given to this function "
            << "\n\t is_loaded_with_image(): " << is_loaded_with_image()
            << "\n\t this: " << this
            );

        double best_score = -1;
        rectangle best_rect;
        for (unsigned long i = 0; i < search_rects.size(); ++i)
        {
            const double score = (rect.intersect(search_rects[i])).area()/(double)(rect+search_rects[i]).area();
            if (score > best_score)
            {
                best_score = score;
                best_rect = search_rects[i];
            }
        }
        return best_rect;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Feature_extractor_type
        >
    full_object_detection scan_image_custom<Feature_extractor_type>::
    get_full_object_detection (
        const rectangle& rect,
        const feature_vector_type& /*w*/
    ) const
    {
        return full_object_detection(rect);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Feature_extractor_type
        >
    void scan_image_custom<Feature_extractor_type>::
    get_feature_vector (
        const full_object_detection& obj,
        feature_vector_type& psi
    ) const
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(is_loaded_with_image() &&
                    psi.size() >= get_num_dimensions() &&
                    obj.num_parts() == 0,
            "\t void scan_image_custom::get_feature_vector()"
            << "\n\t Invalid inputs were given to this function "
            << "\n\t is_loaded_with_image(): " << is_loaded_with_image()
            << "\n\t psi.size():             " << psi.size()
            << "\n\t get_num_dimensions():   " << get_num_dimensions()
            << "\n\t obj.num_parts():                            " << obj.num_parts()
            << "\n\t this: " << this
            );

        feats.get_feature_vector(get_best_matching_rect(obj.get_rect()), psi);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SCAN_IMAGE_CuSTOM_Hh_


dlib C++ Library - scan_image_pyramid.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SCAN_IMaGE_PYRAMID_Hh_
#define DLIB_SCAN_IMaGE_PYRAMID_Hh_

#include "scan_image_pyramid_abstract.h"
#include "../matrix.h"
#include "../geometry.h"
#include "scan_image.h"
#include "../array2d.h"
#include <vector>
#include "full_object_detection.h"
#include "../image_processing/generic_image.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename Feature_extractor_type
        >
    class scan_image_pyramid : noncopyable
    {

    public:

        typedef matrix<double,0,1> feature_vector_type;

        typedef Pyramid_type pyramid_type;
        typedef Feature_extractor_type feature_extractor_type;

        scan_image_pyramid (
        );

        template <
            typename image_type
            >
        void load (
            const image_type& img
        );

        inline bool is_loaded_with_image (
        ) const;

        inline void copy_configuration(
            const feature_extractor_type& fe
        );

        inline void copy_configuration (
            const scan_image_pyramid& item
        );

        const Feature_extractor_type& get_feature_extractor (
        ) const { return feats_config; }

        void add_detection_template (
            const rectangle& object_box,
            const std::vector<rectangle>& stationary_feature_extraction_regions,
            const std::vector<rectangle>& movable_feature_extraction_regions
        );

        void add_detection_template (
            const rectangle& object_box,
            const std::vector<rectangle>& stationary_feature_extraction_regions
        );

        inline unsigned long get_num_detection_templates (
        ) const;

        inline unsigned long get_num_movable_components_per_detection_template (
        ) const;

        inline unsigned long get_num_stationary_components_per_detection_template (
        ) const;

        inline unsigned long get_num_components_per_detection_template (
        ) const;

        inline long get_num_dimensions (
        ) const;

        unsigned long get_max_pyramid_levels (
        ) const;

        void set_max_pyramid_levels (
            unsigned long max_levels
        );

        inline unsigned long get_max_detections_per_template (
        ) const;

        void set_min_pyramid_layer_size (
            unsigned long width,
            unsigned long height
        );

        inline unsigned long get_min_pyramid_layer_width (
        ) const;

        inline unsigned long get_min_pyramid_layer_height (
        ) const;

        void set_max_detections_per_template (
            unsigned long max_dets
        );

        void detect (
            const feature_vector_type& w,
            std::vector<std::pair<double, rectangle> >& dets,
            const double thresh
        ) const;

        void get_feature_vector (
            const full_object_detection& obj,
            feature_vector_type& psi
        ) const;

        full_object_detection get_full_object_detection (
            const rectangle& rect,
            const feature_vector_type& w
        ) const;

        const rectangle get_best_matching_rect (
            const rectangle& rect
        ) const;

        template <typename T, typename U>
        friend void serialize (
            const scan_image_pyramid<T,U>& item,
            std::ostream& out
        );

        template <typename T, typename U>
        friend void deserialize (
            scan_image_pyramid<T,U>& item,
            std::istream& in
        );

    private:
        static bool compare_pair_rect (
            const std::pair<double, rectangle>& a,
            const std::pair<double, rectangle>& b
        )
        {
            return a.first < b.first;
        }

        struct detection_template
        {
            rectangle object_box; // always centered at (0,0)
            std::vector<rectangle> rects; // template with respect to (0,0)
            std::vector<rectangle> movable_rects;
        };

        friend void serialize(const detection_template& item, std::ostream& out)
        {
            int version = 1;
            serialize(version, out);
            serialize(item.object_box, out);
            serialize(item.rects, out);
            serialize(item.movable_rects, out);
        }
        friend void deserialize(detection_template& item, std::istream& in)
        {
            int version = 0;
            deserialize(version, in);
            if (version != 1)
                throw serialization_error("Unexpected version found while deserializing a dlib::scan_image_pyramid::detection_template object.");

            deserialize(item.object_box, in);
            deserialize(item.rects, in);
            deserialize(item.movable_rects, in);
        }

        void get_mapped_rect_and_metadata (
            const unsigned long number_pyramid_levels,
            rectangle rect,
            rectangle& mapped_rect,
            detection_template& best_template,
            rectangle& object_box,
            unsigned long& best_level,
            unsigned long& detection_template_idx
        ) const;

        double get_match_score (
            rectangle r1,
            rectangle r2
        ) const
        {
            // make the rectangles overlap as much as possible before computing the match score.
            r1 = move_rect(r1, r2.tl_corner());
            return (r1.intersect(r2).area())/(double)(r1 + r2).area();
        }

        void test_coordinate_transforms()
        {
            for (long x = -10; x <= 10; x += 10)
            {
                for (long y = -10; y <= 10; y += 10)
                {
                    const rectangle rect = centered_rect(x,y,5,6);
                    rectangle a;

                    a = feats_config.image_to_feat_space(rect);
                    if (a.width()  > 10000000 || a.height() > 10000000 )
                    {
                        DLIB_CASSERT(false, "The image_to_feat_space() routine is outputting rectangles of an implausibly "
                                     << "\nlarge size.  This means there is probably a bug in your feature extractor.");
                    }
                    a = feats_config.feat_to_image_space(rect);
                    if (a.width()  > 10000000 || a.height() > 10000000 )
                    {
                        DLIB_CASSERT(false, "The feat_to_image_space() routine is outputting rectangles of an implausibly "
                                     << "\nlarge size.  This means there is probably a bug in your feature extractor.");
                    }
                }
            }

        }

        feature_extractor_type feats_config; // just here to hold configuration.  use it to populate the feats elements.
        array<feature_extractor_type> feats;
        std::vector<detection_template> det_templates;
        unsigned long max_dets_per_template;
        unsigned long max_pyramid_levels;
        unsigned long min_pyramid_layer_width;
        unsigned long min_pyramid_layer_height;

    };

// ----------------------------------------------------------------------------------------

    template <typename T, typename U>
    void serialize (
        const scan_image_pyramid<T,U>& item,
        std::ostream& out
    )
    {
        int version = 3;
        serialize(version, out);
        serialize(item.feats_config, out);
        serialize(item.feats, out);
        serialize(item.det_templates, out);
        serialize(item.max_dets_per_template, out);
        serialize(item.max_pyramid_levels, out);
        serialize(item.min_pyramid_layer_width, out);
        serialize(item.min_pyramid_layer_height, out);
        serialize(item.get_num_dimensions(), out);
    }

// ----------------------------------------------------------------------------------------

    template <typename T, typename U>
    void deserialize (
        scan_image_pyramid<T,U>& item,
        std::istream& in
    )
    {
        int version = 0;
        deserialize(version, in);
        if (version != 3)
            throw serialization_error("Unsupported version found when deserializing a scan_image_pyramid object.");

        deserialize(item.feats_config, in);
        deserialize(item.feats, in);
        deserialize(item.det_templates, in);
        deserialize(item.max_dets_per_template, in);
        deserialize(item.max_pyramid_levels, in);
        deserialize(item.min_pyramid_layer_width, in);
        deserialize(item.min_pyramid_layer_height, in);

        // When developing some feature extractor, it's easy to accidentally change its
        // number of dimensions and then try to deserialize data from an older version of
        // your extractor into the current code.  This check is here to catch that kind of
        // user error.
        long dims;
        deserialize(dims, in);
        if (item.get_num_dimensions() != dims)
            throw serialization_error("Number of dimensions in serialized scan_image_pyramid doesn't match the expected number.");
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                         scan_image_pyramid member functions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename Feature_extractor_type
        >
    scan_image_pyramid<Pyramid_type,Feature_extractor_type>::
    scan_image_pyramid (
    ) :
        max_dets_per_template(10000),
        max_pyramid_levels(1000),
        min_pyramid_layer_width(20),
        min_pyramid_layer_height(20)
    {
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename Feature_extractor_type
        >
    template <
        typename image_type
        >
    void scan_image_pyramid<Pyramid_type,Feature_extractor_type>::
    load (
        const image_type& img
    )
    {
        unsigned long levels = 0;
        rectangle rect = get_rect(img);

        // figure out how many pyramid levels we should be using based on the image size
        pyramid_type pyr;
        do
        {
            rect = pyr.rect_down(rect);
            ++levels;
        } while (rect.width() >= min_pyramid_layer_width && rect.height() >= min_pyramid_layer_height &&
                 levels < max_pyramid_levels);

        if (feats.max_size() < levels)
            feats.set_max_size(levels);
        feats.set_size(levels);

        for (unsigned long i = 0; i < feats.size(); ++i)
            feats[i].copy_configuration(feats_config);

        // build our feature pyramid
        feats[0].load(img);
        if (feats.size() > 1)
        {
            image_type temp1, temp2;
            pyr(img, temp1);
            feats[1].load(temp1);
            swap(temp1,temp2);

            for (unsigned long i = 2; i < feats.size(); ++i)
            {
                pyr(temp2, temp1);
                feats[i].load(temp1);
                swap(temp1,temp2);
            }
        }

    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename Feature_extractor_type
        >
    unsigned long scan_image_pyramid<Pyramid_type,Feature_extractor_type>::
    get_max_detections_per_template (
    ) const
    {
        return max_dets_per_template;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename Feature_extractor_type
        >
    void scan_image_pyramid<Pyramid_type,Feature_extractor_type>::
    set_max_detections_per_template (
        unsigned long max_dets
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(max_dets > 0 ,
            "\t void scan_image_pyramid::set_max_detections_per_template()"
            << "\n\t The max number of possible detections can't be zero. "
            << "\n\t max_dets: " << max_dets
            << "\n\t this: " << this
            );

        max_dets_per_template = max_dets;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename Feature_extractor_type
        >
    bool scan_image_pyramid<Pyramid_type,Feature_extractor_type>::
    is_loaded_with_image (
    ) const
    {
        return feats.size() != 0;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename Feature_extractor_type
        >
    void scan_image_pyramid<Pyramid_type,Feature_extractor_type>::
    copy_configuration(
        const feature_extractor_type& fe
    )
    {
        test_coordinate_transforms();
        feats_config.copy_configuration(fe);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename Feature_extractor_type
        >
    void scan_image_pyramid<Pyramid_type,Feature_extractor_type>::
    copy_configuration (
        const scan_image_pyramid& item
    )
    {
        feats_config.copy_configuration(item.feats_config);
        det_templates = item.det_templates;
        max_dets_per_template = item.max_dets_per_template;
        max_pyramid_levels = item.max_pyramid_levels;
        min_pyramid_layer_width = item.min_pyramid_layer_width;
        min_pyramid_layer_height = item.min_pyramid_layer_height;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename Feature_extractor_type
        >
    void scan_image_pyramid<Pyramid_type,Feature_extractor_type>::
    add_detection_template (
        const rectangle& object_box,
        const std::vector<rectangle>& stationary_feature_extraction_regions,
        const std::vector<rectangle>& movable_feature_extraction_regions
    )
    {
#ifdef ENABLE_ASSERTS
        // make sure requires clause is not broken
        DLIB_ASSERT((get_num_detection_templates() == 0 ||
                        (get_num_stationary_components_per_detection_template() == stationary_feature_extraction_regions.size() &&
                        get_num_movable_components_per_detection_template() == movable_feature_extraction_regions.size())) &&
                        center(object_box) == point(0,0),
            "\t void scan_image_pyramid::add_detection_template()"
            << "\n\t The number of rects in this new detection template doesn't match "
            << "\n\t the number in previous detection templates."
            << "\n\t get_num_stationary_components_per_detection_template(): " << get_num_stationary_components_per_detection_template()
            << "\n\t stationary_feature_extraction_regions.size():           " << stationary_feature_extraction_regions.size()
            << "\n\t get_num_movable_components_per_detection_template():    " << get_num_movable_components_per_detection_template()
            << "\n\t movable_feature_extraction_regions.size():              " << movable_feature_extraction_regions.size()
            << "\n\t this: " << this
            );

        for (unsigned long i = 0; i < movable_feature_extraction_regions.size(); ++i)
        {
            DLIB_ASSERT(center(movable_feature_extraction_regions[i]) == point(0,0),
                        "Invalid inputs were given to this function."
                        << "\n\t center(movable_feature_extraction_regions["<<i<<"]): " << center(movable_feature_extraction_regions[i])
                        << "\n\t this: " << this
            );
        }
#endif

        detection_template temp;
        temp.object_box = object_box;
        temp.rects = stationary_feature_extraction_regions;
        temp.movable_rects = movable_feature_extraction_regions;
        det_templates.push_back(temp);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename Feature_extractor_type
        >
    void scan_image_pyramid<Pyramid_type,Feature_extractor_type>::
    add_detection_template (
        const rectangle& object_box,
        const std::vector<rectangle>& stationary_feature_extraction_regions
    )
    {
        // an empty set of movable feature regions
        const std::vector<rectangle> movable_feature_extraction_regions;
        add_detection_template(object_box, stationary_feature_extraction_regions,
                               movable_feature_extraction_regions);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename Feature_extractor_type
        >
    unsigned long scan_image_pyramid<Pyramid_type,Feature_extractor_type>::
    get_num_detection_templates (
    ) const
    {
        return det_templates.size();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename Feature_extractor_type
        >
    unsigned long scan_image_pyramid<Pyramid_type,Feature_extractor_type>::
    get_num_stationary_components_per_detection_template (
    ) const
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(get_num_detection_templates() > 0 ,
            "\t unsigned long scan_image_pyramid::get_num_stationary_components_per_detection_template()"
            << "\n\t You need to give some detection templates before calling this function. "
            << "\n\t get_num_detection_templates(): " << get_num_detection_templates()
            << "\n\t this: " << this
            );

        return det_templates[0].rects.size();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename Feature_extractor_type
        >
    unsigned long scan_image_pyramid<Pyramid_type,Feature_extractor_type>::
    get_num_movable_components_per_detection_template (
    ) const
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(get_num_detection_templates() > 0 ,
            "\t unsigned long scan_image_pyramid::get_num_movable_components_per_detection_template()"
            << "\n\t You need to give some detection templates before calling this function. "
            << "\n\t get_num_detection_templates(): " << get_num_detection_templates()
            << "\n\t this: " << this
            );

        return det_templates[0].movable_rects.size();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename Feature_extractor_type
        >
    unsigned long scan_image_pyramid<Pyramid_type,Feature_extractor_type>::
    get_num_components_per_detection_template (
    ) const
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(get_num_detection_templates() > 0 ,
            "\t unsigned long scan_image_pyramid::get_num_components_per_detection_template()"
            << "\n\t You need to give some detection templates before calling this function. "
            << "\n\t get_num_detection_templates(): " << get_num_detection_templates()
            << "\n\t this: " << this
            );

        return get_num_movable_components_per_detection_template() +
               get_num_stationary_components_per_detection_template();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename Feature_extractor_type
        >
    long scan_image_pyramid<Pyramid_type,Feature_extractor_type>::
    get_num_dimensions (
    ) const
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(get_num_detection_templates() > 0 ,
            "\t long scan_image_pyramid::get_num_dimensions()"
            << "\n\t You need to give some detection templates before calling this function. "
            << "\n\t get_num_detection_templates(): " << get_num_detection_templates()
            << "\n\t this: " << this
            );

        return feats_config.get_num_dimensions()*get_num_components_per_detection_template() + get_num_detection_templates();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename Feature_extractor_type
        >
    unsigned long scan_image_pyramid<Pyramid_type,Feature_extractor_type>::
    get_max_pyramid_levels (
    ) const
    {
        return max_pyramid_levels;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename Feature_extractor_type
        >
    void scan_image_pyramid<Pyramid_type,Feature_extractor_type>::
    set_max_pyramid_levels (
        unsigned long max_levels
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(max_levels > 0 ,
            "\t void scan_image_pyramid::set_max_pyramid_levels()"
            << "\n\t You can't have zero levels. "
            << "\n\t max_levels: " << max_levels
            << "\n\t this: " << this
            );

        max_pyramid_levels = max_levels;

    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename Feature_extractor_type
        >
    void scan_image_pyramid<Pyramid_type,Feature_extractor_type>::
    detect (
        const feature_vector_type& w,
        std::vector<std::pair<double, rectangle> >& dets,
        const double thresh
    ) const
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(get_num_detection_templates() > 0 &&
                    is_loaded_with_image() &&
                    w.size() >= get_num_dimensions(),
            "\t void scan_image_pyramid::detect()"
            << "\n\t Invalid inputs were given to this function "
            << "\n\t get_num_detection_templates(): " << get_num_detection_templates()
            << "\n\t is_loaded_with_image(): " << is_loaded_with_image()
            << "\n\t w.size():               " << w.size()
            << "\n\t get_num_dimensions():   " << get_num_dimensions()
            << "\n\t this: " << this
            );

        dets.clear();

        array<array2d<double> > saliency_images;
        saliency_images.set_max_size(get_num_components_per_detection_template());
        saliency_images.set_size(get_num_components_per_detection_template());
        std::vector<std::pair<unsigned int,rectangle> > stationary_region_rects(get_num_stationary_components_per_detection_template());
        std::vector<std::pair<unsigned int,rectangle> > movable_region_rects(get_num_movable_components_per_detection_template());
        pyramid_type pyr;
        std::vector<std::pair<double, point> > point_dets;

        // for all pyramid levels
        for (unsigned long l = 0; l < feats.size(); ++l)
        {
            for (unsigned long i = 0; i < saliency_images.size(); ++i)
            {
                saliency_images[i].set_size(feats[l].nr(), feats[l].nc());
                const unsigned long offset = get_num_detection_templates() + feats_config.get_num_dimensions()*i;

                // build saliency images for pyramid level l
                for (long r = 0; r < feats[l].nr(); ++r)
                {
                    for (long c = 0; c < feats[l].nc(); ++c)
                    {
                        const typename feature_extractor_type::descriptor_type& descriptor = feats[l](r,c);

                        double sum = 0;
                        for (unsigned long k = 0; k < descriptor.size(); ++k)
                        {
                            sum += w(descriptor[k].first + offset)*descriptor[k].second;
                        }
                        saliency_images[i][r][c] = sum;
                    }
                }
            }

            // now search the saliency images
            for (unsigned long i = 0; i < det_templates.size(); ++i)
            {
                const point offset = -feats[l].image_to_feat_space(point(0,0));
                for (unsigned long j = 0; j < stationary_region_rects.size(); ++j)
                {
                    stationary_region_rects[j] = std::make_pair(j, translate_rect(feats[l].image_to_feat_space(det_templates[i].rects[j]),offset));
                }
                for (unsigned long j = 0; j < movable_region_rects.size(); ++j)
                {
                    // Scale the size of the movable rectangle but make sure its center
                    // stays at point(0,0).
                    const rectangle temp = feats[l].image_to_feat_space(det_templates[i].movable_rects[j]);
                    movable_region_rects[j] = std::make_pair(j+stationary_region_rects.size(),
                                                             centered_rect(point(0,0),temp.width(), temp.height()));
                }

                // Scale the object box into the feature extraction image, but keeping it
                // centered at point(0,0).
                rectangle scaled_object_box = feats[l].image_to_feat_space(det_templates[i].object_box);
                scaled_object_box = centered_rect(point(0,0),scaled_object_box.width(), scaled_object_box.height());

                // Each detection template gets its own special threshold in addition to
                // the global detection threshold.  This allows us to model the fact that
                // some detection templates might be more prone to false alarming or since
                // their size is different naturally require a larger or smaller threshold
                // (since they integrate over a larger or smaller region of the image).
                const double template_specific_thresh = w(i);

                scan_image_movable_parts(point_dets, saliency_images, scaled_object_box,
                                         stationary_region_rects, movable_region_rects,
                                         thresh+template_specific_thresh, max_dets_per_template);

                // convert all the point detections into rectangles at the original image scale and coordinate system
                for (unsigned long j = 0; j < point_dets.size(); ++j)
                {
                    const double score = point_dets[j].first-template_specific_thresh;
                    point p = point_dets[j].second;
                    p = feats[l].feat_to_image_space(p);
                    rectangle rect = translate_rect(det_templates[i].object_box, p);
                    rect = pyr.rect_up(rect, l);

                    dets.push_back(std::make_pair(score, rect));
                }
            }
        }

        std::sort(dets.rbegin(), dets.rend(), compare_pair_rect);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename Feature_extractor_type
        >
    const rectangle scan_image_pyramid<Pyramid_type,Feature_extractor_type>::
    get_best_matching_rect (
        const rectangle& rect
    ) const
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(get_num_detection_templates() > 0 ,
            "\t const rectangle scan_image_pyramid::get_best_matching_rect()"
            << "\n\t Invalid inputs were given to this function "
            << "\n\t get_num_detection_templates(): " << get_num_detection_templates()
            << "\n\t this: " << this
            );

        rectangle mapped_rect, object_box;
        detection_template best_template;
        unsigned long best_level, junk;
        get_mapped_rect_and_metadata(max_pyramid_levels, rect, mapped_rect, best_template, object_box, best_level, junk);
        return mapped_rect;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename Feature_extractor_type
        >
    void scan_image_pyramid<Pyramid_type,Feature_extractor_type>::
    get_mapped_rect_and_metadata (
        const unsigned long number_pyramid_levels,
        rectangle rect,
        rectangle& mapped_rect,
        detection_template& best_template,
        rectangle& object_box,
        unsigned long& best_level,
        unsigned long& detection_template_idx
    ) const
    {
        pyramid_type pyr;
        // Figure out the pyramid level which best matches rect against one of our
        // detection template object boxes.
        best_level = 0;
        double best_match_score = -1;

        // Find the best matching detection template for rect
        for (unsigned long l = 0; l < number_pyramid_levels; ++l)
        {
            const rectangle temp = pyr.rect_down(rect,l);
            if (temp.area() <= 1)
                break;

            // At this pyramid level, what matches best?
            for (unsigned long t = 0; t < det_templates.size(); ++t)
            {
                const double match_score = get_match_score(det_templates[t].object_box, temp);
                if (match_score > best_match_score)
                {
                    best_match_score = match_score;
                    best_level = l;
                    best_template = det_templates[t];
                    detection_template_idx = t;
                }
            }
        }

        // Now we translate best_template into the right spot (it should be centered at the location
        // determined by rect) and convert it into the feature image coordinate system.
        rect = pyr.rect_down(rect,best_level);
        const point offset = -feats_config.image_to_feat_space(point(0,0));
        const point origin = feats_config.image_to_feat_space(center(rect)) + offset;
        for (unsigned long k = 0; k < best_template.rects.size(); ++k)
        {
            rectangle temp = best_template.rects[k];
            temp = feats_config.image_to_feat_space(temp);
            temp = translate_rect(temp, origin);
            best_template.rects[k] = temp;
        }
        for (unsigned long k = 0; k < best_template.movable_rects.size(); ++k)
        {
            rectangle temp = best_template.movable_rects[k];
            temp = feats_config.image_to_feat_space(temp);
            temp = centered_rect(point(0,0), temp.width(), temp.height());
            best_template.movable_rects[k] = temp;
        }

        const rectangle scaled_object_box = feats_config.image_to_feat_space(best_template.object_box);
        object_box = centered_rect(origin-offset, scaled_object_box.width(), scaled_object_box.height());

        // The input rectangle was mapped to one of the detection templates.  Reverse the process
        // to figure out what the mapped rectangle is in the original input space.
        mapped_rect = translate_rect(best_template.object_box, feats_config.feat_to_image_space(origin-offset));
        mapped_rect = pyr.rect_up(mapped_rect, best_level);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename Feature_extractor_type
        >
    full_object_detection scan_image_pyramid<Pyramid_type,Feature_extractor_type>::
    get_full_object_detection (
        const rectangle& rect,
        const feature_vector_type& w
    ) const
    {
        // fill in movable part positions.

        rectangle mapped_rect;
        detection_template best_template;
        unsigned long best_level, junk;
        rectangle object_box;
        get_mapped_rect_and_metadata(feats.size(), rect, mapped_rect, best_template, object_box, best_level, junk);

        Pyramid_type pyr;

        array2d<double> saliency_image, sum_img;

        double total_temp_score = 0;
        // convert into feature space.
        object_box = object_box.intersect(get_rect(feats[best_level]));

        std::vector<point> movable_parts;
        movable_parts.reserve(get_num_movable_components_per_detection_template());
        for (unsigned long i = 0; i < get_num_movable_components_per_detection_template(); ++i)
        {
            // make the saliency_image for the ith movable part.

            const rectangle part_rect = best_template.movable_rects[i];
            const rectangle area = grow_rect(object_box,
                                             part_rect.width()/2,
                                             part_rect.height()/2).intersect(get_rect(feats[best_level]));

            saliency_image.set_size(area.height(), area.width());
            const unsigned long offset = get_num_detection_templates() + feats_config.get_num_dimensions()*(i+get_num_stationary_components_per_detection_template());

            // build saliency image for pyramid level best_level
            for (long r = area.top(); r <= area.bottom(); ++r)
            {
                for (long c = area.left(); c <= area.right(); ++c)
                {
                    const typename feature_extractor_type::descriptor_type& descriptor = feats[best_level](r,c);

                    double sum = 0;
                    for (unsigned long k = 0; k < descriptor.size(); ++k)
                    {
                        sum += w(descriptor[k].first + offset)*descriptor[k].second;
                    }
                    saliency_image[r-area.top()][c-area.left()] = sum;
                }
            }

            sum_img.set_size(saliency_image.nr(), saliency_image.nc());
            sum_filter_assign(saliency_image, sum_img, part_rect);
            // Figure out where the maximizer is in sum_img.  Note that we
            // only look in the part of sum_img that corresponds to a location inside
            // object_box.
            rectangle valid_area = get_rect(sum_img);
            valid_area.left()   += object_box.left()   - area.left();
            valid_area.top()    += object_box.top()    - area.top();
            valid_area.right()  += object_box.right()  - area.right();
            valid_area.bottom() += object_box.bottom() - area.bottom();
            double max_val = 0;
            point max_loc;
            for (long r = valid_area.top(); r <= valid_area.bottom(); ++r)
            {
                for (long c = valid_area.left(); c <= valid_area.right(); ++c)
                {
                    if (sum_img[r][c] > max_val)
                    {
                        //if (object_box.contains(point(c,r) + area.tl_corner()))
                        {
                            max_loc = point(c,r);
                            max_val = sum_img[r][c];
                        }
                    }
                }
            }

            if (max_val <= 0)
            {
                max_loc = OBJECT_PART_NOT_PRESENT;
            }
            else
            {
                total_temp_score += max_val;
                // convert max_loc back into feature image space from our cropped image.
                max_loc += area.tl_corner();

                // now convert from feature space to image space.
                max_loc = feats[best_level].feat_to_image_space(max_loc);
                max_loc = pyr.point_up(max_loc, best_level);
                max_loc = nearest_point(rect, max_loc);
            }

            movable_parts.push_back(max_loc);
        }

        return full_object_detection(rect, movable_parts);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename Feature_extractor_type
        >
    void scan_image_pyramid<Pyramid_type,Feature_extractor_type>::
    get_feature_vector (
        const full_object_detection& obj,
        feature_vector_type& psi
    ) const
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(get_num_detection_templates() > 0 &&
                    is_loaded_with_image() &&
                    psi.size() >= get_num_dimensions() &&
                    obj.num_parts() == get_num_movable_components_per_detection_template(),
            "\t void scan_image_pyramid::get_feature_vector()"
            << "\n\t Invalid inputs were given to this function "
            << "\n\t get_num_detection_templates(): " << get_num_detection_templates()
            << "\n\t is_loaded_with_image(): " << is_loaded_with_image()
            << "\n\t psi.size():             " << psi.size()
            << "\n\t get_num_dimensions():   " << get_num_dimensions()
            << "\n\t get_num_movable_components_per_detection_template(): " << get_num_movable_components_per_detection_template()
            << "\n\t obj.num_parts():                            " << obj.num_parts()
            << "\n\t this: " << this
            );
        DLIB_ASSERT(all_parts_in_rect(obj),
            "\t void scan_image_pyramid::get_feature_vector()"
            << "\n\t Invalid inputs were given to this function "
            << "\n\t obj.get_rect(): " << obj.get_rect()
            << "\n\t this: " << this
        );

        rectangle mapped_rect;
        detection_template best_template;
        unsigned long best_level, detection_template_idx;
        rectangle object_box;
        get_mapped_rect_and_metadata(feats.size(), obj.get_rect(), mapped_rect, best_template, object_box, best_level, detection_template_idx);

        psi(detection_template_idx) -= 1;

        Pyramid_type pyr;

        // put the movable rects at the places indicated by obj.
        std::vector<rectangle> rects = best_template.rects;
        for (unsigned long i = 0; i < obj.num_parts(); ++i)
        {
            if (obj.part(i) != OBJECT_PART_NOT_PRESENT)
            {
                // map from the original image to scaled feature space.
                point loc = feats[best_level].image_to_feat_space(pyr.point_down(obj.part(i), best_level));
                // Make sure the movable part always stays within the object_box.
                // Otherwise it would be at a place that the detect() function can never
                // look.
                loc = nearest_point(object_box, loc);
                rects.push_back(translate_rect(best_template.movable_rects[i], loc));
            }
            else
            {
                // add an empty rectangle since this part wasn't observed.
                rects.push_back(rectangle());
            }
        }

        // pull features out of all the boxes in rects.
        for (unsigned long j = 0; j < rects.size(); ++j)
        {
            const rectangle rect = rects[j].intersect(get_rect(feats[best_level]));
            const unsigned long template_region_id = j;
            const unsigned long offset = get_num_detection_templates() + feats_config.get_num_dimensions()*template_region_id;
            for (long r = rect.top(); r <= rect.bottom(); ++r)
            {
                for (long c = rect.left(); c <= rect.right(); ++c)
                {
                    const typename feature_extractor_type::descriptor_type& descriptor = feats[best_level](r,c);
                    for (unsigned long k = 0; k < descriptor.size(); ++k)
                    {
                        psi(descriptor[k].first + offset) += descriptor[k].second;
                    }
                }
            }
        }

    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename Feature_extractor_type
        >
    void scan_image_pyramid<Pyramid_type,Feature_extractor_type>::
    set_min_pyramid_layer_size (
        unsigned long width,
        unsigned long height
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(width > 0 && height > 0 ,
            "\t void scan_image_pyramid::set_min_pyramid_layer_size()"
            << "\n\t These sizes can't be zero. "
            << "\n\t width:  " << width
            << "\n\t height: " << height
            << "\n\t this:   " << this
            );

        min_pyramid_layer_width = width;
        min_pyramid_layer_height = height;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename Feature_extractor_type
        >
    unsigned long scan_image_pyramid<Pyramid_type,Feature_extractor_type>::
    get_min_pyramid_layer_width (
    ) const
    {
        return min_pyramid_layer_width;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename Pyramid_type,
        typename Feature_extractor_type
        >
    unsigned long scan_image_pyramid<Pyramid_type,Feature_extractor_type>::
    get_min_pyramid_layer_height (
    ) const
    {
        return min_pyramid_layer_height;
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SCAN_IMaGE_PYRAMID_Hh_


dlib C++ Library - scan_image_pyramid_tools.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SCAN_IMaGE_PYRAMID_TOOLS_Hh_
#define DLIB_SCAN_IMaGE_PYRAMID_TOOLS_Hh_

#include "scan_image_pyramid_tools_abstract.h"
#include "../statistics.h"
#include <list>
#include "../geometry.h"
#include <iostream>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    namespace impl
    {
        inline bool compare_first (
            const std::pair<unsigned long,rectangle>& a,
            const std::pair<unsigned long,rectangle>& b
        )
        {
            return a.first < b.first;
        }
    }

    template <typename image_scanner_type>
    std::vector<rectangle> determine_object_boxes (
        const image_scanner_type& scanner,
        const std::vector<rectangle>& rects,
        double min_match_score
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(0 < min_match_score && min_match_score <= 1,
            "\t std::vector<rectangle> determine_object_boxes()"
            << "\n\t Invalid inputs were given to this function. "
            << "\n\t min_match_score: " << min_match_score
            );

        typename image_scanner_type::pyramid_type pyr;

        typedef std::list<std::pair<unsigned long, rectangle> > list_type;

        unsigned long max_area = 0;

        // Copy rects into sorted_rects and sort them in order of increasing area.  But
        // only include the rectangles that aren't already obtainable by the scanner.
        list_type sorted_rects;
        for (unsigned long i = 0; i < rects.size(); ++i)
        {
            if (scanner.get_num_detection_templates() > 0)
            {
                rectangle temp = scanner.get_best_matching_rect(rects[i]);
                const double match_score = (rects[i].intersect(temp).area())/(double)(rects[i] + temp).area();
                // skip this rectangle if it's already matched well enough.
                if (match_score > min_match_score)
                    continue;
            }
            max_area = std::max(rects[i].area(), max_area);
            sorted_rects.push_back(std::make_pair(rects[i].area(), rects[i]));
        }
        sorted_rects.sort(dlib::impl::compare_first);

        // Make sure this area value is comfortably larger than all the
        // rectangles' areas.
        max_area = 3*max_area + 100;

        std::vector<rectangle> object_boxes;

        while (sorted_rects.size() != 0)
        {
            rectangle cur = sorted_rects.front().second;
            sorted_rects.pop_front();
            object_boxes.push_back(centered_rect(point(0,0), cur.width(), cur.height()));

            // Scale cur up the image pyramid and remove any rectangles which match.
            // But also stop when cur gets large enough to not match anything.
            for (unsigned long itr = 0;
                 itr < scanner.get_max_pyramid_levels() && cur.area() < max_area;
                 ++itr)
            {
                list_type::iterator i = sorted_rects.begin();
                while (i != sorted_rects.end())
                {
                    const rectangle temp = move_rect(i->second, cur.tl_corner());
                    const double match_score = (cur.intersect(temp).area())/(double)(cur + temp).area();
                    if (match_score > min_match_score)
                    {
                        i = sorted_rects.erase(i);
                    }
                    else
                    {
                        ++i;
                    }
                }

                cur = pyr.rect_up(cur);
            }

        }

        return object_boxes;
    }

// ----------------------------------------------------------------------------------------

    template <typename image_scanner_type>
    std::vector<rectangle> determine_object_boxes (
        const image_scanner_type& scanner,
        const std::vector<std::vector<rectangle> >& rects,
        double min_match_score
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(0 < min_match_score && min_match_score <= 1,
            "\t std::vector<rectangle> determine_object_boxes()"
            << "\n\t Invalid inputs were given to this function. "
            << "\n\t min_match_score: " << min_match_score
            );

        std::vector<rectangle> temp;
        for (unsigned long i = 0; i < rects.size(); ++i)
        {
            for (unsigned long j = 0; j < rects[i].size(); ++j)
            {
                temp.push_back(rects[i][j]);
            }
        }

        return determine_object_boxes(scanner, temp, min_match_score);
    }

// ----------------------------------------------------------------------------------------

    template <typename image_scanner_type>
    void setup_grid_detection_templates (
        image_scanner_type& scanner,
        const std::vector<std::vector<rectangle> >& rects,
        unsigned int cells_x,
        unsigned int cells_y,
        double min_match_score = 0.75
    )
    {
        const std::vector<rectangle>& object_boxes = determine_object_boxes(scanner, rects, min_match_score);
        for (unsigned long i = 0; i < object_boxes.size(); ++i)
        {
            scanner.add_detection_template(object_boxes[i], create_grid_detection_template(object_boxes[i], cells_x, cells_y));
        }
    }

// ----------------------------------------------------------------------------------------

    template <typename image_scanner_type>
    void setup_grid_detection_templates_verbose (
        image_scanner_type& scanner,
        const std::vector<std::vector<rectangle> >& rects,
        unsigned int cells_x,
        unsigned int cells_y,
        double min_match_score = 0.75
    )
    {
        const std::vector<rectangle>& object_boxes = determine_object_boxes(scanner, rects, min_match_score);
        std::cout << "number of detection templates: "<< object_boxes.size() << std::endl;
        for (unsigned long i = 0; i < object_boxes.size(); ++i)
        {
            std::cout << "  object box " << i << ":  width: " << object_boxes[i].width()
                      << "  height: "<< object_boxes[i].height() << std::endl;
            scanner.add_detection_template(object_boxes[i], create_grid_detection_template(object_boxes[i], cells_x, cells_y));
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SCAN_IMaGE_PYRAMID_TOOLS_Hh_


dlib C++ Library - setup_hashed_features.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SETUP_HAShED_FEATURES_Hh_
#define DLIB_SETUP_HAShED_FEATURES_Hh_

#include "setup_hashed_features_abstract.h"
#include "scan_image_pyramid.h"
#include "scan_image_boxes.h"
#include "../lsh.h"
#include "../statistics.h"
#include "../image_keypoint.h"
#include "../geometry.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class image_hash_construction_failure : public error
    {
    public:
        image_hash_construction_failure(
            const std::string& a
        ): error(a) {}
    };

// ----------------------------------------------------------------------------------------

    template <
        typename image_scanner
        >
    void use_uniform_feature_weights (
        image_scanner& scanner
    )
    {
        typename image_scanner::feature_extractor_type fe;
        fe.copy_configuration(scanner.get_feature_extractor());
        fe.use_uniform_feature_weights();
        scanner.copy_configuration(fe);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_scanner
        >
    void use_relative_feature_weights (
        image_scanner& scanner
    )
    {
        typename image_scanner::feature_extractor_type fe;
        fe.copy_configuration(scanner.get_feature_extractor());
        fe.use_relative_feature_weights();
        scanner.copy_configuration(fe);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                                 stuff for scan_image_pyramid
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename image_array,
        typename pyramid,
        typename feature_extractor,
        template <typename fe, typename hash> class feature_image
        >
    void setup_hashed_features (
        scan_image_pyramid<pyramid, feature_image<feature_extractor, projection_hash> >& scanner,
        const image_array& images,
        const feature_extractor& fe,
        int bits,
        unsigned long num_samples = 200000
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(0 < bits && bits <= 32 &&
                    num_samples > 1 &&
                    images.size() > 0,
            "\t void setup_hashed_features()"
            << "\n\t Invalid inputs were given to this function. "
            << "\n\t bits:          " << bits
            << "\n\t num_samples:   " << num_samples
            << "\n\t images.size(): " << images.size()
            );

        pyramid pyr;

        const random_subset_selector<typename feature_extractor::descriptor_type>& samps =
            randomly_sample_image_features(images, pyr, fe, num_samples);

        if (samps.size() <= 1)
            throw dlib::image_hash_construction_failure("Images too small, not able to gather enough samples to make hash");

        projection_hash phash = create_random_projection_hash(samps, bits);

        feature_image<feature_extractor, projection_hash> hfe;
        hfe.copy_configuration(scanner.get_feature_extractor());
        hfe.set_hash(phash);
        hfe.copy_configuration(fe);
        scanner.copy_configuration(hfe);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_array,
        typename pyramid,
        typename feature_extractor,
        template <typename fe, typename hash> class feature_image
        >
    void setup_hashed_features (
        scan_image_pyramid<pyramid, feature_image<feature_extractor, projection_hash> >& scanner,
        const image_array& images,
        int bits,
        unsigned long num_samples = 200000
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(0 < bits && bits <= 32 &&
                    num_samples > 1 &&
                    images.size() > 0,
            "\t void setup_hashed_features()"
            << "\n\t Invalid inputs were given to this function. "
            << "\n\t bits:          " << bits
            << "\n\t num_samples:   " << num_samples
            << "\n\t images.size(): " << images.size()
            );

        feature_extractor fe;
        setup_hashed_features(scanner, images, fe, bits, num_samples);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                                 stuff for scan_image_boxes
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename image_array,
        typename feature_extractor,
        template <typename fe, typename hash> class feature_image,
        typename box_generator
        >
    void setup_hashed_features (
        scan_image_boxes<feature_image<feature_extractor, projection_hash>,box_generator >& scanner,
        const image_array& images,
        const feature_extractor& fe,
        int bits,
        unsigned long num_samples = 200000
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(0 < bits && bits <= 32 &&
                    num_samples > 1 &&
                    images.size() > 0,
            "\t void setup_hashed_features()"
            << "\n\t Invalid inputs were given to this function. "
            << "\n\t bits:          " << bits
            << "\n\t num_samples:   " << num_samples
            << "\n\t images.size(): " << images.size()
            );

        pyramid_disable pyr;

        const random_subset_selector<typename feature_extractor::descriptor_type>& samps =
            randomly_sample_image_features(images, pyr, fe, num_samples);

        if (samps.size() <= 1)
            throw dlib::image_hash_construction_failure("Images too small, not able to gather enough samples to make hash");

        projection_hash phash = create_random_projection_hash(samps, bits);

        feature_image<feature_extractor, projection_hash> hfe;
        hfe.copy_configuration(scanner.get_feature_extractor());
        hfe.set_hash(phash);
        hfe.copy_configuration(fe);
        scanner.copy_configuration(hfe);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_array,
        typename feature_extractor,
        template <typename fe, typename hash> class feature_image,
        typename box_generator
        >
    void setup_hashed_features (
        scan_image_boxes<feature_image<feature_extractor, projection_hash>,box_generator>& scanner,
        const image_array& images,
        int bits,
        unsigned long num_samples = 200000
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(0 < bits && bits <= 32 &&
                    num_samples > 1 &&
                    images.size() > 0,
            "\t void setup_hashed_features()"
            << "\n\t Invalid inputs were given to this function. "
            << "\n\t bits:          " << bits
            << "\n\t num_samples:   " << num_samples
            << "\n\t images.size(): " << images.size()
            );

        feature_extractor fe;
        setup_hashed_features(scanner, images, fe, bits, num_samples);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SETUP_HAShED_FEATURES_Hh_


dlib C++ Library - shape_predictor.h

// Copyright (C) 2014  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SHAPE_PREDICToR_H_
#define DLIB_SHAPE_PREDICToR_H_

#include "shape_predictor_abstract.h"
#include "full_object_detection.h"
#include "../algs.h"
#include "../matrix.h"
#include "../geometry.h"
#include "../pixel.h"
#include "../console_progress_indicator.h"
#include <utility>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    namespace impl
    {
        struct split_feature
        {
            unsigned long idx1;
            unsigned long idx2;
            float thresh;

            friend inline void serialize (const split_feature& item, std::ostream& out)
            {
                dlib::serialize(item.idx1, out);
                dlib::serialize(item.idx2, out);
                dlib::serialize(item.thresh, out);
            }
            friend inline void deserialize (split_feature& item, std::istream& in)
            {
                dlib::deserialize(item.idx1, in);
                dlib::deserialize(item.idx2, in);
                dlib::deserialize(item.thresh, in);
            }
        };

        // a tree is just a std::vector<impl::split_feature>.  We use this function to navigate the
        // tree nodes
        inline unsigned long left_child (unsigned long idx) { return 2*idx + 1; }
        /*!
            ensures
                - returns the index of the left child of the binary tree node idx
        !*/
        inline unsigned long right_child (unsigned long idx) { return 2*idx + 2; }
        /*!
            ensures
                - returns the index of the left child of the binary tree node idx
        !*/

        struct regression_tree
        {
            std::vector<split_feature> splits;
            std::vector<matrix<float,0,1> > leaf_values;

            unsigned long num_leaves() const { return leaf_values.size(); }

            inline const matrix<float,0,1>& operator()(
                const std::vector<float>& feature_pixel_values,
                unsigned long& i
            ) const
            /*!
                requires
                    - All the index values in splits are less than feature_pixel_values.size()
                    - leaf_values.size() is a power of 2.
                      (i.e. we require a tree with all the levels fully filled out.
                    - leaf_values.size() == splits.size()+1
                      (i.e. there needs to be the right number of leaves given the number of splits in the tree)
                ensures
                    - runs through the tree and returns the vector at the leaf we end up in.
                    - #i == the selected leaf node index.
            !*/
            {
                i = 0;
                while (i < splits.size())
                {
                    if (feature_pixel_values[splits[i].idx1] - feature_pixel_values[splits[i].idx2] > splits[i].thresh)
                        i = left_child(i);
                    else
                        i = right_child(i);
                }
                i = i - splits.size();
                return leaf_values[i];
            }

            friend void serialize (const regression_tree& item, std::ostream& out)
            {
                dlib::serialize(item.splits, out);
                dlib::serialize(item.leaf_values, out);
            }
            friend void deserialize (regression_tree& item, std::istream& in)
            {
                dlib::deserialize(item.splits, in);
                dlib::deserialize(item.leaf_values, in);
            }
        };

    // ------------------------------------------------------------------------------------

        inline vector<float,2> location (
            const matrix<float,0,1>& shape,
            unsigned long idx
        )
        /*!
            requires
                - idx < shape.size()/2
                - shape.size()%2 == 0
            ensures
                - returns the idx-th point from the shape vector.
        !*/
        {
            return vector<float,2>(shape(idx*2), shape(idx*2+1));
        }

    // ------------------------------------------------------------------------------------

        inline unsigned long nearest_shape_point (
            const matrix<float,0,1>& shape,
            const dlib::vector<float,2>& pt
        )
        {
            // find the nearest part of the shape to this pixel
            float best_dist = std::numeric_limits<float>::infinity();
            const unsigned long num_shape_parts = shape.size()/2;
            unsigned long best_idx = 0;
            for (unsigned long j = 0; j < num_shape_parts; ++j)
            {
                const float dist = length_squared(location(shape,j)-pt);
                if (dist < best_dist)
                {
                    best_dist = dist;
                    best_idx = j;
                }
            }
            return best_idx;
        }

    // ------------------------------------------------------------------------------------

        inline void create_shape_relative_encoding (
            const matrix<float,0,1>& shape,
            const std::vector<dlib::vector<float,2> >& pixel_coordinates,
            std::vector<unsigned long>& anchor_idx,
            std::vector<dlib::vector<float,2> >& deltas
        )
        /*!
            requires
                - shape.size()%2 == 0
                - shape.size() > 0
            ensures
                - #anchor_idx.size() == pixel_coordinates.size()
                - #deltas.size()     == pixel_coordinates.size()
                - for all valid i:
                    - pixel_coordinates[i] == location(shape,#anchor_idx[i]) + #deltas[i]
        !*/
        {
            anchor_idx.resize(pixel_coordinates.size());
            deltas.resize(pixel_coordinates.size());

            for (unsigned long i = 0; i < pixel_coordinates.size(); ++i)
            {
                anchor_idx[i] = nearest_shape_point(shape, pixel_coordinates[i]);
                deltas[i] = pixel_coordinates[i] - location(shape,anchor_idx[i]);
            }
        }

    // ------------------------------------------------------------------------------------

        inline point_transform_affine find_tform_between_shapes (
            const matrix<float,0,1>& from_shape,
            const matrix<float,0,1>& to_shape
        )
        {
            DLIB_ASSERT(from_shape.size() == to_shape.size() && (from_shape.size()%2) == 0 && from_shape.size() > 0,"");
            std::vector<vector<float,2> > from_points, to_points;
            const unsigned long num = from_shape.size()/2;
            from_points.reserve(num);
            to_points.reserve(num);
            if (num == 1)
            {
                // Just use an identity transform if there is only one landmark.
                return point_transform_affine();
            }

            for (unsigned long i = 0; i < num; ++i)
            {
                from_points.push_back(location(from_shape,i));
                to_points.push_back(location(to_shape,i));
            }
            return find_similarity_transform(from_points, to_points);
        }

    // ------------------------------------------------------------------------------------

        inline point_transform_affine normalizing_tform (
            const rectangle& rect
        )
        /*!
            ensures
                - returns a transform that maps rect.tl_corner() to (0,0) and rect.br_corner()
                  to (1,1).
        !*/
        {
            std::vector<vector<float,2> > from_points, to_points;
            from_points.push_back(rect.tl_corner()); to_points.push_back(point(0,0));
            from_points.push_back(rect.tr_corner()); to_points.push_back(point(1,0));
            from_points.push_back(rect.br_corner()); to_points.push_back(point(1,1));
            return find_affine_transform(from_points, to_points);
        }

    // ------------------------------------------------------------------------------------

        inline point_transform_affine unnormalizing_tform (
            const rectangle& rect
        )
        /*!
            ensures
                - returns a transform that maps (0,0) to rect.tl_corner() and (1,1) to
                  rect.br_corner().
        !*/
        {
            std::vector<vector<float,2> > from_points, to_points;
            to_points.push_back(rect.tl_corner()); from_points.push_back(point(0,0));
            to_points.push_back(rect.tr_corner()); from_points.push_back(point(1,0));
            to_points.push_back(rect.br_corner()); from_points.push_back(point(1,1));
            return find_affine_transform(from_points, to_points);
        }

    // ------------------------------------------------------------------------------------

        template <typename image_type>
        void extract_feature_pixel_values (
            const image_type& img_,
            const rectangle& rect,
            const matrix<float,0,1>& current_shape,
            const matrix<float,0,1>& reference_shape,
            const std::vector<unsigned long>& reference_pixel_anchor_idx,
            const std::vector<dlib::vector<float,2> >& reference_pixel_deltas,
            std::vector<float>& feature_pixel_values
        )
        /*!
            requires
                - image_type == an image object that implements the interface defined in
                  dlib/image_processing/generic_image.h
                - reference_pixel_anchor_idx.size() == reference_pixel_deltas.size()
                - current_shape.size() == reference_shape.size()
                - reference_shape.size()%2 == 0
                - max(mat(reference_pixel_anchor_idx)) < reference_shape.size()/2
            ensures
                - #feature_pixel_values.size() == reference_pixel_deltas.size()
                - for all valid i:
                    - #feature_pixel_values[i] == the value of the pixel in img_ that
                      corresponds to the pixel identified by reference_pixel_anchor_idx[i]
                      and reference_pixel_deltas[i] when the pixel is located relative to
                      current_shape rather than reference_shape.
        !*/
        {
            const matrix<float,2,2> tform = matrix_cast<float>(find_tform_between_shapes(reference_shape, current_shape).get_m());
            const point_transform_affine tform_to_img = unnormalizing_tform(rect);

            const rectangle area = get_rect(img_);

            const_image_view<image_type> img(img_);
            feature_pixel_values.resize(reference_pixel_deltas.size());
            for (unsigned long i = 0; i < feature_pixel_values.size(); ++i)
            {
                // Compute the point in the current shape corresponding to the i-th pixel and
                // then map it from the normalized shape space into pixel space.
                point p = tform_to_img(tform*reference_pixel_deltas[i] + location(current_shape, reference_pixel_anchor_idx[i]));
                if (area.contains(p))
                    feature_pixel_values[i] = get_pixel_intensity(img[p.y()][p.x()]);
                else
                    feature_pixel_values[i] = 0;
            }
        }

    } // end namespace impl

// ----------------------------------------------------------------------------------------

    class shape_predictor
    {
    public:

        shape_predictor (
        )
        {}

        shape_predictor (
            const matrix<float,0,1>& initial_shape_,
            const std::vector<std::vector<impl::regression_tree> >& forests_,
            const std::vector<std::vector<dlib::vector<float,2> > >& pixel_coordinates
        ) : initial_shape(initial_shape_), forests(forests_)
        /*!
            requires
                - initial_shape.size()%2 == 0
                - forests.size() == pixel_coordinates.size() == the number of cascades
                - for all valid i:
                    - all the index values in forests[i] are less than pixel_coordinates[i].size()
                - for all valid i and j:
                    - forests[i][j].leaf_values.size() is a power of 2.
                      (i.e. we require a tree with all the levels fully filled out.
                    - forests[i][j].leaf_values.size() == forests[i][j].splits.size()+1
                      (i.e. there need to be the right number of leaves given the number of splits in the tree)
        !*/
        {
            anchor_idx.resize(pixel_coordinates.size());
            deltas.resize(pixel_coordinates.size());
            // Each cascade uses a different set of pixels for its features.  We compute
            // their representations relative to the initial shape now and save it.
            for (unsigned long i = 0; i < pixel_coordinates.size(); ++i)
                impl::create_shape_relative_encoding(initial_shape, pixel_coordinates[i], anchor_idx[i], deltas[i]);
        }

        unsigned long num_parts (
        ) const
        {
            return initial_shape.size()/2;
        }

        unsigned long num_features (
        ) const
        {
            unsigned long num = 0;
            for (unsigned long iter = 0; iter < forests.size(); ++iter)
                for (unsigned long i = 0; i < forests[iter].size(); ++i)
                    num += forests[iter][i].num_leaves();
            return num;
        }

        template <typename image_type>
        full_object_detection operator()(
            const image_type& img,
            const rectangle& rect
        ) const
        {
            using namespace impl;
            matrix<float,0,1> current_shape = initial_shape;
            std::vector<float> feature_pixel_values;
            for (unsigned long iter = 0; iter < forests.size(); ++iter)
            {
                extract_feature_pixel_values(img, rect, current_shape, initial_shape,
                                             anchor_idx[iter], deltas[iter], feature_pixel_values);
                unsigned long leaf_idx;
                // evaluate all the trees at this level of the cascade.
                for (unsigned long i = 0; i < forests[iter].size(); ++i)
                    current_shape += forests[iter][i](feature_pixel_values, leaf_idx);
            }

            // convert the current_shape into a full_object_detection
            const point_transform_affine tform_to_img = unnormalizing_tform(rect);
            std::vector<point> parts(current_shape.size()/2);
            for (unsigned long i = 0; i < parts.size(); ++i)
                parts[i] = tform_to_img(location(current_shape, i));
            return full_object_detection(rect, parts);
        }

        template <typename image_type, typename T, typename U>
        full_object_detection operator()(
            const image_type& img,
            const rectangle& rect,
            std::vector<std::pair<T,U> >& feats
        ) const
        {
            feats.clear();
            using namespace impl;
            matrix<float,0,1> current_shape = initial_shape;
            std::vector<float> feature_pixel_values;
            unsigned long feat_offset = 0;
            for (unsigned long iter = 0; iter < forests.size(); ++iter)
            {
                extract_feature_pixel_values(img, rect, current_shape, initial_shape,
                                             anchor_idx[iter], deltas[iter], feature_pixel_values);
                // evaluate all the trees at this level of the cascade.
                for (unsigned long i = 0; i < forests[iter].size(); ++i)
                {
                    unsigned long leaf_idx;
                    current_shape += forests[iter][i](feature_pixel_values, leaf_idx);

                    feats.push_back(std::make_pair(feat_offset+leaf_idx, 1));
                    feat_offset += forests[iter][i].num_leaves();
                }
            }

            // convert the current_shape into a full_object_detection
            const point_transform_affine tform_to_img = unnormalizing_tform(rect);
            std::vector<point> parts(current_shape.size()/2);
            for (unsigned long i = 0; i < parts.size(); ++i)
                parts[i] = tform_to_img(location(current_shape, i));
            return full_object_detection(rect, parts);
        }

        friend void serialize (const shape_predictor& item, std::ostream& out)
        {
            int version = 1;
            dlib::serialize(version, out);
            dlib::serialize(item.initial_shape, out);
            dlib::serialize(item.forests, out);
            dlib::serialize(item.anchor_idx, out);
            dlib::serialize(item.deltas, out);
        }
        friend void deserialize (shape_predictor& item, std::istream& in)
        {
            int version = 0;
            dlib::deserialize(version, in);
            if (version != 1)
                throw serialization_error("Unexpected version found while deserializing dlib::shape_predictor.");
            dlib::deserialize(item.initial_shape, in);
            dlib::deserialize(item.forests, in);
            dlib::deserialize(item.anchor_idx, in);
            dlib::deserialize(item.deltas, in);
        }

    private:
        matrix<float,0,1> initial_shape;
        std::vector<std::vector<impl::regression_tree> > forests;
        std::vector<std::vector<unsigned long> > anchor_idx;
        std::vector<std::vector<dlib::vector<float,2> > > deltas;
    };

// ----------------------------------------------------------------------------------------

    class shape_predictor_trainer
    {
        /*!
            This thing really only works with unsigned char or rgb_pixel images (since we assume the threshold
            should be in the range [-128,128]).
        !*/
    public:

        shape_predictor_trainer (
        )
        {
            _cascade_depth = 10;
            _tree_depth = 4;
            _num_trees_per_cascade_level = 500;
            _nu = 0.1;
            _oversampling_amount = 20;
            _feature_pool_size = 400;
            _lambda = 0.1;
            _num_test_splits = 20;
            _feature_pool_region_padding = 0;
            _verbose = false;
        }

        unsigned long get_cascade_depth (
        ) const { return _cascade_depth; }

        void set_cascade_depth (
            unsigned long depth
        )
        {
            DLIB_CASSERT(depth > 0,
                "\t void shape_predictor_trainer::set_cascade_depth()"
                << "\n\t Invalid inputs were given to this function. "
                << "\n\t depth:  " << depth
            );

            _cascade_depth = depth;
        }

        unsigned long get_tree_depth (
        ) const { return _tree_depth; }

        void set_tree_depth (
            unsigned long depth
        )
        {
            DLIB_CASSERT(depth > 0,
                "\t void shape_predictor_trainer::set_tree_depth()"
                << "\n\t Invalid inputs were given to this function. "
                << "\n\t depth:  " << depth
            );

            _tree_depth = depth;
        }

        unsigned long get_num_trees_per_cascade_level (
        ) const { return _num_trees_per_cascade_level; }

        void set_num_trees_per_cascade_level (
            unsigned long num
        )
        {
            DLIB_CASSERT( num > 0,
                "\t void shape_predictor_trainer::set_num_trees_per_cascade_level()"
                << "\n\t Invalid inputs were given to this function. "
                << "\n\t num:  " << num
            );
            _num_trees_per_cascade_level = num;
        }

        double get_nu (
        ) const { return _nu; }
        void set_nu (
            double nu
        )
        {
            DLIB_CASSERT(0 < nu && nu <= 1,
                "\t void shape_predictor_trainer::set_nu()"
                << "\n\t Invalid inputs were given to this function. "
                << "\n\t nu:  " << nu
            );

            _nu = nu;
        }

        std::string get_random_seed (
        ) const { return rnd.get_seed(); }
        void set_random_seed (
            const std::string& seed
        ) { rnd.set_seed(seed); }

        unsigned long get_oversampling_amount (
        ) const { return _oversampling_amount; }
        void set_oversampling_amount (
            unsigned long amount
        )
        {
            DLIB_CASSERT(amount > 0,
                "\t void shape_predictor_trainer::set_oversampling_amount()"
                << "\n\t Invalid inputs were given to this function. "
                << "\n\t amount: " << amount
            );

            _oversampling_amount = amount;
        }

        unsigned long get_feature_pool_size (
        ) const { return _feature_pool_size; }
        void set_feature_pool_size (
            unsigned long size
        )
        {
            DLIB_CASSERT(size > 1,
                "\t void shape_predictor_trainer::set_feature_pool_size()"
                << "\n\t Invalid inputs were given to this function. "
                << "\n\t size: " << size
            );

            _feature_pool_size = size;
        }

        double get_lambda (
        ) const { return _lambda; }
        void set_lambda (
            double lambda
        )
        {
            DLIB_CASSERT(lambda > 0,
                "\t void shape_predictor_trainer::set_lambda()"
                << "\n\t Invalid inputs were given to this function. "
                << "\n\t lambda: " << lambda
            );

            _lambda = lambda;
        }

        unsigned long get_num_test_splits (
        ) const { return _num_test_splits; }
        void set_num_test_splits (
            unsigned long num
        )
        {
            DLIB_CASSERT(num > 0,
                "\t void shape_predictor_trainer::set_num_test_splits()"
                << "\n\t Invalid inputs were given to this function. "
                << "\n\t num: " << num
            );

            _num_test_splits = num;
        }

        double get_feature_pool_region_padding (
        ) const { return _feature_pool_region_padding; }
        void set_feature_pool_region_padding (
            double padding
        )
        {
            _feature_pool_region_padding = padding;
        }

        void be_verbose (
        )
        {
            _verbose = true;
        }

        void be_quiet (
        )
        {
            _verbose = false;
        }

        template <typename image_array>
        shape_predictor train (
            const image_array& images,
            const std::vector<std::vector<full_object_detection> >& objects
        ) const
        {
            using namespace impl;
            DLIB_CASSERT(images.size() == objects.size() && images.size() > 0,
                "\t shape_predictor shape_predictor_trainer::train()"
                << "\n\t Invalid inputs were given to this function. "
                << "\n\t images.size():  " << images.size()
                << "\n\t objects.size(): " << objects.size()
            );
            // make sure the objects agree on the number of parts and that there is at
            // least one full_object_detection.
            unsigned long num_parts = 0;
            std::vector<int> part_present;
            for (unsigned long i = 0; i < objects.size(); ++i)
            {
                for (unsigned long j = 0; j < objects[i].size(); ++j)
                {
                    if (num_parts == 0)
                    {
                        num_parts = objects[i][j].num_parts();
                        DLIB_CASSERT(objects[i][j].num_parts() != 0,
                            "\t shape_predictor shape_predictor_trainer::train()"
                            << "\n\t You can't give objects that don't have any parts to the trainer."
                        );
                        part_present.resize(num_parts);
                    }
                    else
                    {
                        DLIB_CASSERT(objects[i][j].num_parts() == num_parts,
                            "\t shape_predictor shape_predictor_trainer::train()"
                            << "\n\t All the objects must agree on the number of parts. "
                            << "\n\t objects["<<i<<"]["<<j<<"].num_parts(): " << objects[i][j].num_parts()
                            << "\n\t num_parts:  " << num_parts
                        );
                    }
                    for (unsigned long p = 0; p < objects[i][j].num_parts(); ++p)
                    {
                        if (objects[i][j].part(p) != OBJECT_PART_NOT_PRESENT)
                            part_present[p] = 1;
                    }
                }
            }
            DLIB_CASSERT(num_parts != 0,
                "\t shape_predictor shape_predictor_trainer::train()"
                << "\n\t You must give at least one full_object_detection if you want to train a shape model and it must have parts."
            );
            DLIB_CASSERT(sum(mat(part_present)) == (long)num_parts,
                "\t shape_predictor shape_predictor_trainer::train()"
                << "\n\t Each part must appear at least once in this training data.  That is, "
                << "\n\t you can't have a part that is always set to OBJECT_PART_NOT_PRESENT."
            );

            rnd.set_seed(get_random_seed());

            std::vector<training_sample> samples;
            const matrix<float,0,1> initial_shape = populate_training_sample_shapes(objects, samples);
            const std::vector<std::vector<dlib::vector<float,2> > > pixel_coordinates = randomly_sample_pixel_coordinates(initial_shape);

            unsigned long trees_fit_so_far = 0;
            console_progress_indicator pbar(get_cascade_depth()*get_num_trees_per_cascade_level());
            if (_verbose)
                std::cout << "Fitting trees..." << std::endl;

            std::vector<std::vector<impl::regression_tree> > forests(get_cascade_depth());
            // Now start doing the actual training by filling in the forests
            for (unsigned long cascade = 0; cascade < get_cascade_depth(); ++cascade)
            {
                // Each cascade uses a different set of pixels for its features.  We compute
                // their representations relative to the initial shape first.
                std::vector<unsigned long> anchor_idx;
                std::vector<dlib::vector<float,2> > deltas;
                create_shape_relative_encoding(initial_shape, pixel_coordinates[cascade], anchor_idx, deltas);

                // First compute the feature_pixel_values for each training sample at this
                // level of the cascade.
                for (unsigned long i = 0; i < samples.size(); ++i)
                {
                    extract_feature_pixel_values(images[samples[i].image_idx], samples[i].rect,
                        samples[i].current_shape, initial_shape, anchor_idx,
                        deltas, samples[i].feature_pixel_values);
                }

                // Now start building the trees at this cascade level.
                for (unsigned long i = 0; i < get_num_trees_per_cascade_level(); ++i)
                {
                    forests[cascade].push_back(make_regression_tree(samples, pixel_coordinates[cascade]));

                    if (_verbose)
                    {
                        ++trees_fit_so_far;
                        pbar.print_status(trees_fit_so_far);
                    }
                }
            }

            if (_verbose)
                std::cout << "Training complete                          " << std::endl;

            return shape_predictor(initial_shape, forests, pixel_coordinates);
        }

    private:

        static void object_to_shape (
            const full_object_detection& obj,
            matrix<float,0,1>& shape,
            matrix<float,0,1>& present // a mask telling which elements of #shape are present.
        )
        {
            shape.set_size(obj.num_parts()*2);
            present.set_size(obj.num_parts()*2);
            const point_transform_affine tform_from_img = impl::normalizing_tform(obj.get_rect());
            for (unsigned long i = 0; i < obj.num_parts(); ++i)
            {
                if (obj.part(i) != OBJECT_PART_NOT_PRESENT)
                {
                    vector<float,2> p = tform_from_img(obj.part(i));
                    shape(2*i)   = p.x();
                    shape(2*i+1) = p.y();
                    present(2*i)   = 1;
                    present(2*i+1) = 1;
                }
                else
                {
                    shape(2*i)   = 0;
                    shape(2*i+1) = 0;
                    present(2*i)   = 0;
                    present(2*i+1) = 0;
                }
            }
        }

        struct training_sample
        {
            /*!

            CONVENTION
                - feature_pixel_values.size() == get_feature_pool_size()
                - feature_pixel_values[j] == the value of the j-th feature pool
                  pixel when you look it up relative to the shape in current_shape.

                - target_shape == The truth shape.  Stays constant during the whole
                  training process (except for the parts that are not present, those are
                  always equal to the current_shape values).
                - present == 0/1 mask saying which parts of target_shape are present.
                - rect == the position of the object in the image_idx-th image.  All shape
                  coordinates are coded relative to this rectangle.
            !*/

            unsigned long image_idx;
            rectangle rect;
            matrix<float,0,1> target_shape;
            matrix<float,0,1> present;

            matrix<float,0,1> current_shape;
            std::vector<float> feature_pixel_values;

            void swap(training_sample& item)
            {
                std::swap(image_idx, item.image_idx);
                std::swap(rect, item.rect);
                target_shape.swap(item.target_shape);
                present.swap(item.present);
                current_shape.swap(item.current_shape);
                feature_pixel_values.swap(item.feature_pixel_values);
            }
        };

        impl::regression_tree make_regression_tree (
            std::vector<training_sample>& samples,
            const std::vector<dlib::vector<float,2> >& pixel_coordinates
        ) const
        {
            using namespace impl;
            std::deque<std::pair<unsigned long, unsigned long> > parts;
            parts.push_back(std::make_pair(0, (unsigned long)samples.size()));

            impl::regression_tree tree;

            // walk the tree in breadth first order
            const unsigned long num_split_nodes = static_cast<unsigned long>(std::pow(2.0, (double)get_tree_depth())-1);
            std::vector<matrix<float,0,1> > sums(num_split_nodes*2+1);
            for (unsigned long i = 0; i < samples.size(); ++i)
                sums[0] += samples[i].target_shape - samples[i].current_shape;

            for (unsigned long i = 0; i < num_split_nodes; ++i)
            {
                std::pair<unsigned long,unsigned long> range = parts.front();
                parts.pop_front();

                const impl::split_feature split = generate_split(samples, range.first,
                    range.second, pixel_coordinates, sums[i], sums[left_child(i)],
                    sums[right_child(i)]);
                tree.splits.push_back(split);
                const unsigned long mid = partition_samples(split, samples, range.first, range.second);

                parts.push_back(std::make_pair(range.first, mid));
                parts.push_back(std::make_pair(mid, range.second));
            }

            // Now all the parts contain the ranges for the leaves so we can use them to
            // compute the average leaf values.
            matrix<float,0,1> present_counts(samples[0].target_shape.size());
            tree.leaf_values.resize(parts.size());
            for (unsigned long i = 0; i < parts.size(); ++i)
            {
                // Get the present counts for each dimension so we can divide each
                // dimension by the number of observations we have on it to find the mean
                // displacement in each leaf.
                present_counts = 0;
                for (unsigned long j = parts[i].first; j < parts[i].second; ++j)
                    present_counts += samples[j].present;
                present_counts = dlib::reciprocal(present_counts);

                if (parts[i].second != parts[i].first)
                    tree.leaf_values[i] = pointwise_multiply(present_counts,sums[num_split_nodes+i]*get_nu());
                else
                    tree.leaf_values[i] = zeros_matrix(samples[0].target_shape);

                // now adjust the current shape based on these predictions
                for (unsigned long j = parts[i].first; j < parts[i].second; ++j)
                {
                    samples[j].current_shape += tree.leaf_values[i];
                    // For parts that aren't present in the training data, we just make
                    // sure that the target shape always matches and therefore gives zero
                    // error.  So this makes the algorithm simply ignore non-present
                    // landmarks.
                    for (long k = 0; k < samples[j].present.size(); ++k)
                    {
                        // if this part is not present
                        if (samples[j].present(k) == 0)
                            samples[j].target_shape(k) = samples[j].current_shape(k);
                    }
                }
            }

            return tree;
        }

        impl::split_feature randomly_generate_split_feature (
            const std::vector<dlib::vector<float,2> >& pixel_coordinates
        ) const
        {
            const double lambda = get_lambda();
            impl::split_feature feat;
            double accept_prob;
            do
            {
                feat.idx1   = rnd.get_random_32bit_number()%get_feature_pool_size();
                feat.idx2   = rnd.get_random_32bit_number()%get_feature_pool_size();
                const double dist = length(pixel_coordinates[feat.idx1]-pixel_coordinates[feat.idx2]);
                accept_prob = std::exp(-dist/lambda);
            }
            while(feat.idx1 == feat.idx2 || !(accept_prob > rnd.get_random_double()));

            feat.thresh = (rnd.get_random_double()*256 - 128)/2.0;

            return feat;
        }

        impl::split_feature generate_split (
            const std::vector<training_sample>& samples,
            unsigned long begin,
            unsigned long end,
            const std::vector<dlib::vector<float,2> >& pixel_coordinates,
            const matrix<float,0,1>& sum,
            matrix<float,0,1>& left_sum,
            matrix<float,0,1>& right_sum
        ) const
        {
            // generate a bunch of random splits and test them and return the best one.

            const unsigned long num_test_splits = get_num_test_splits();

            // sample the random features we test in this function
            std::vector<impl::split_feature> feats;
            feats.reserve(num_test_splits);
            for (unsigned long i = 0; i < num_test_splits; ++i)
                feats.push_back(randomly_generate_split_feature(pixel_coordinates));

            std::vector<matrix<float,0,1> > left_sums(num_test_splits);
            std::vector<unsigned long> left_cnt(num_test_splits);

            // now compute the sums of vectors that go left for each feature
            matrix<float,0,1> temp;
            for (unsigned long j = begin; j < end; ++j)
            {
                temp = samples[j].target_shape-samples[j].current_shape;
                for (unsigned long i = 0; i < num_test_splits; ++i)
                {
                    if (samples[j].feature_pixel_values[feats[i].idx1] - samples[j].feature_pixel_values[feats[i].idx2] > feats[i].thresh)
                    {
                        left_sums[i] += temp;
                        ++left_cnt[i];
                    }
                }
            }

            // now figure out which feature is the best
            double best_score = -1;
            unsigned long best_feat = 0;
            for (unsigned long i = 0; i < num_test_splits; ++i)
            {
                // check how well the feature splits the space.
                double score = 0;
                unsigned long right_cnt = end-begin-left_cnt[i];
                if (left_cnt[i] != 0 && right_cnt != 0)
                {
                    temp = sum - left_sums[i];
                    score = dot(left_sums[i],left_sums[i])/left_cnt[i] + dot(temp,temp)/right_cnt;
                    if (score > best_score)
                    {
                        best_score = score;
                        best_feat = i;
                    }
                }
            }

            left_sums[best_feat].swap(left_sum);
            if (left_sum.size() != 0)
            {
                right_sum = sum - left_sum;
            }
            else
            {
                right_sum = sum;
                left_sum = zeros_matrix(sum);
            }
            return feats[best_feat];
        }

        unsigned long partition_samples (
            const impl::split_feature& split,
            std::vector<training_sample>& samples,
            unsigned long begin,
            unsigned long end
        ) const
        {
            // splits samples based on split (sorta like in quick sort) and returns the mid
            // point.  make sure you return the mid in a way compatible with how we walk
            // through the tree.

            unsigned long i = begin;
            for (unsigned long j = begin; j < end; ++j)
            {
                if (samples[j].feature_pixel_values[split.idx1] - samples[j].feature_pixel_values[split.idx2] > split.thresh)
                {
                    samples[i].swap(samples[j]);
                    ++i;
                }
            }
            return i;
        }

        matrix<float,0,1> populate_training_sample_shapes(
            const std::vector<std::vector<full_object_detection> >& objects,
            std::vector<training_sample>& samples
        ) const
        {
            samples.clear();
            matrix<float,0,1> mean_shape;
            matrix<float,0,1> count;
            // first fill out the target shapes
            for (unsigned long i = 0; i < objects.size(); ++i)
            {
                for (unsigned long j = 0; j < objects[i].size(); ++j)
                {
                    training_sample sample;
                    sample.image_idx = i;
                    sample.rect = objects[i][j].get_rect();
                    object_to_shape(objects[i][j], sample.target_shape, sample.present);
                    for (unsigned long itr = 0; itr < get_oversampling_amount(); ++itr)
                        samples.push_back(sample);
                    mean_shape += sample.target_shape;
                    count += sample.present;
                }
            }

            mean_shape = pointwise_multiply(mean_shape,reciprocal(count));

            // now go pick random initial shapes
            for (unsigned long i = 0; i < samples.size(); ++i)
            {
                if ((i%get_oversampling_amount()) == 0)
                {
                    // The mean shape is what we really use as an initial shape so always
                    // include it in the training set as an example starting shape.
                    samples[i].current_shape = mean_shape;
                }
                else
                {
                    samples[i].current_shape.set_size(0);

                    matrix<float,0,1> hits(mean_shape.size());
                    hits = 0;

                    int iter = 0;
                    // Pick a few samples at random and randomly average them together to
                    // make the initial shape.  Note that we make sure we get at least one
                    // observation (i.e. non-OBJECT_PART_NOT_PRESENT) on each part
                    // location.
                    while(min(hits) == 0 || iter < 2)
                    {
                        ++iter;
                        const unsigned long rand_idx = rnd.get_random_32bit_number()%samples.size();
                        const double alpha = rnd.get_random_double()+0.1;
                        samples[i].current_shape += alpha*samples[rand_idx].target_shape;
                        hits += alpha*samples[rand_idx].present;
                    }
                    samples[i].current_shape = pointwise_multiply(samples[i].current_shape, reciprocal(hits));
                }

            }
            for (unsigned long i = 0; i < samples.size(); ++i)
            {
                for (long k = 0; k < samples[i].present.size(); ++k)
                {
                    // if this part is not present
                    if (samples[i].present(k) == 0)
                        samples[i].target_shape(k) = samples[i].current_shape(k);
                }
            }

            return mean_shape;
        }

        void randomly_sample_pixel_coordinates (
            std::vector<dlib::vector<float,2> >& pixel_coordinates,
            const double min_x,
            const double min_y,
            const double max_x,
            const double max_y
        ) const
        /*!
            ensures
                - #pixel_coordinates.size() == get_feature_pool_size()
                - for all valid i:
                    - pixel_coordinates[i] == a point in the box defined by the min/max x/y arguments.
        !*/
        {
            pixel_coordinates.resize(get_feature_pool_size());
            for (unsigned long i = 0; i < get_feature_pool_size(); ++i)
            {
                pixel_coordinates[i].x() = rnd.get_random_double()*(max_x-min_x) + min_x;
                pixel_coordinates[i].y() = rnd.get_random_double()*(max_y-min_y) + min_y;
            }
        }

        std::vector<std::vector<dlib::vector<float,2> > > randomly_sample_pixel_coordinates (
            const matrix<float,0,1>& initial_shape
        ) const
        {
            const double padding = get_feature_pool_region_padding();
            // Figure figure out the bounds on the object shapes.  We will sample uniformly
            // from this box.
            matrix<float> temp = reshape(initial_shape, initial_shape.size()/2, 2);
            const double min_x = min(colm(temp,0))-padding;
            const double min_y = min(colm(temp,1))-padding;
            const double max_x = max(colm(temp,0))+padding;
            const double max_y = max(colm(temp,1))+padding;

            std::vector<std::vector<dlib::vector<float,2> > > pixel_coordinates;
            pixel_coordinates.resize(get_cascade_depth());
            for (unsigned long i = 0; i < get_cascade_depth(); ++i)
                randomly_sample_pixel_coordinates(pixel_coordinates[i], min_x, min_y, max_x, max_y);
            return pixel_coordinates;
        }

        mutable dlib::rand rnd;

        unsigned long _cascade_depth;
        unsigned long _tree_depth;
        unsigned long _num_trees_per_cascade_level;
        double _nu;
        unsigned long _oversampling_amount;
        unsigned long _feature_pool_size;
        double _lambda;
        unsigned long _num_test_splits;
        double _feature_pool_region_padding;
        bool _verbose;
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename image_array
        >
    double test_shape_predictor (
        const shape_predictor& sp,
        const image_array& images,
        const std::vector<std::vector<full_object_detection> >& objects,
        const std::vector<std::vector<double> >& scales
    )
    {
        // make sure requires clause is not broken
#ifdef ENABLE_ASSERTS
        DLIB_CASSERT( images.size() == objects.size() ,
            "\t double test_shape_predictor()"
            << "\n\t Invalid inputs were given to this function. "
            << "\n\t images.size():  " << images.size()
            << "\n\t objects.size(): " << objects.size()
        );
        for (unsigned long i = 0; i < objects.size(); ++i)
        {
            for (unsigned long j = 0; j < objects[i].size(); ++j)
            {
                DLIB_CASSERT(objects[i][j].num_parts() == sp.num_parts(),
                    "\t double test_shape_predictor()"
                    << "\n\t Invalid inputs were given to this function. "
                    << "\n\t objects["<<i<<"]["<<j<<"].num_parts(): " << objects[i][j].num_parts()
                    << "\n\t sp.num_parts(): " << sp.num_parts()
                );
            }
            if (scales.size() != 0)
            {
                DLIB_CASSERT(objects[i].size() == scales[i].size(),
                    "\t double test_shape_predictor()"
                    << "\n\t Invalid inputs were given to this function. "
                    << "\n\t objects["<<i<<"].size(): " << objects[i].size()
                    << "\n\t scales["<<i<<"].size(): " << scales[i].size()
                );

            }
        }
#endif

        running_stats<double> rs;
        for (unsigned long i = 0; i < objects.size(); ++i)
        {
            for (unsigned long j = 0; j < objects[i].size(); ++j)
            {
                // Just use a scale of 1 (i.e. no scale at all) if the caller didn't supply
                // any scales.
                const double scale = scales.size()==0 ? 1 : scales[i][j];

                full_object_detection det = sp(images[i], objects[i][j].get_rect());

                for (unsigned long k = 0; k < det.num_parts(); ++k)
                {
                    if (objects[i][j].part(k) != OBJECT_PART_NOT_PRESENT)
                    {
                        double score = length(det.part(k) - objects[i][j].part(k))/scale;
                        rs.add(score);
                    }
                }
            }
        }
        return rs.mean();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_array
        >
    double test_shape_predictor (
        const shape_predictor& sp,
        const image_array& images,
        const std::vector<std::vector<full_object_detection> >& objects
    )
    {
        std::vector<std::vector<double> > no_scales;
        return test_shape_predictor(sp, images, objects, no_scales);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SHAPE_PREDICToR_H_


dlib C++ Library - dng_shared.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_DNG_SHAREd_
#define DLIB_DNG_SHAREd_

#include "../pixel.h"
#include <cmath>
#include "../uintn.h"

namespace dlib
{

    namespace dng_helpers_namespace
    {
        enum
        {
            grayscale = 1,
            rgb,
            hsi,
            rgb_paeth,
            rgb_alpha,
            rgb_alpha_paeth,
            grayscale_16bit,
            grayscale_float
        };

        const unsigned long dng_magic_byte = 100;

        template <typename T>
        rgb_pixel predictor_rgb_paeth (const T& img, long row, long col)
        /*
            This is similar to the Paeth filter from the PNG image format.
        */
        {
            // a = left, b = above, c = upper left
            rgb_pixel a(0,0,0), b(0,0,0), c(0,0,0);

            const long c1 = col-1;
            const long r1 = row-1;

            if (c1 >= 0)
                assign_pixel(a, img[row][c1]);
            else
                assign_pixel(a,(unsigned char)0);

            if (c1 >= 0 && r1 >= 0)
                assign_pixel(c, img[r1][c1]);
            else
                assign_pixel(c,(unsigned char)0);

            if (r1 >= 0)
                assign_pixel(b, img[r1][col]);
            else
                assign_pixel(b,(unsigned char)0);

            rgb_pixel p;
            p.red = a.red + b.red - c.red;
            p.green = a.green + b.green - c.green;
            p.blue = a.blue + b.blue - c.blue;

            short pa = std::abs((short)p.red - (short)a.red) +
                       std::abs((short)p.green - (short)a.green) +
                       std::abs((short)p.blue - (short)a.blue);
            short pb = std::abs((short)p.red - (short)b.red) +
                       std::abs((short)p.green - (short)b.green) +
                       std::abs((short)p.blue - (short)b.blue);
            short pc = std::abs((short)p.red - (short)c.red) +
                       std::abs((short)p.green - (short)c.green) +
                       std::abs((short)p.blue - (short)c.blue);

            if (pa <= pb && pa <= pc)
                return a;
            else if (pb <= pc)
                return b;
            else
                return c;
        }

        template <typename T>
        rgb_pixel predictor_rgb (const T& img, long row, long col)
        {
            // a = left, b = above, c = upper left
            rgb_pixel a(0,0,0), b(0,0,0), c(0,0,0);

            const long c1 = col-1;
            const long r1 = row-1;

            if (c1 >= 0)
                assign_pixel(a, img[row][c1]);
            else
                assign_pixel(a,(unsigned char)0);

            if (c1 >= 0 && r1 >= 0)
                assign_pixel(c, img[r1][c1]);
            else
                assign_pixel(c,(unsigned char)0);

            if (r1 >= 0)
                assign_pixel(b, img[r1][col]);
            else
                assign_pixel(b,(unsigned char)0);

            rgb_pixel p;
            p.red = a.red + b.red - c.red;
            p.green = a.green + b.green - c.green;
            p.blue = a.blue + b.blue - c.blue;
            return p;
        }

        template <typename T>
        rgb_alpha_pixel predictor_rgb_alpha_paeth (const T& img, long row, long col)
        /*
            This is similar to the Paeth filter from the PNG image format.
        */
        {
            // a = left, b = above, c = upper left
            rgb_alpha_pixel a, b, c;

            const long c1 = col-1;
            const long r1 = row-1;

            if (c1 >= 0)
                assign_pixel(a, img[row][c1]);
            else
                assign_pixel(a,(unsigned char)0);

            if (c1 >= 0 && r1 >= 0)
                assign_pixel(c, img[r1][c1]);
            else
                assign_pixel(c,(unsigned char)0);

            if (r1 >= 0)
                assign_pixel(b, img[r1][col]);
            else
                assign_pixel(b,(unsigned char)0);

            rgb_alpha_pixel p;
            p.red = a.red + b.red - c.red;
            p.green = a.green + b.green - c.green;
            p.blue = a.blue + b.blue - c.blue;

            short pa = std::abs((short)p.red - (short)a.red) +
                       std::abs((short)p.green - (short)a.green) +
                       std::abs((short)p.blue - (short)a.blue);
            short pb = std::abs((short)p.red - (short)b.red) +
                       std::abs((short)p.green - (short)b.green) +
                       std::abs((short)p.blue - (short)b.blue);
            short pc = std::abs((short)p.red - (short)c.red) +
                       std::abs((short)p.green - (short)c.green) +
                       std::abs((short)p.blue - (short)c.blue);

            if (pa <= pb && pa <= pc)
                return a;
            else if (pb <= pc)
                return b;
            else
                return c;
        }

        template <typename T>
        rgb_alpha_pixel predictor_rgb_alpha (const T& img, long row, long col)
        {
            // a = left, b = above, c = upper left
            rgb_alpha_pixel a, b, c;

            const long c1 = col-1;
            const long r1 = row-1;

            if (c1 >= 0)
                assign_pixel(a, img[row][c1]);
            else
                assign_pixel(a,(unsigned char)0);

            if (c1 >= 0 && r1 >= 0)
                assign_pixel(c, img[r1][c1]);
            else
                assign_pixel(c,(unsigned char)0);

            if (r1 >= 0)
                assign_pixel(b, img[r1][col]);
            else
                assign_pixel(b,(unsigned char)0);

            rgb_alpha_pixel p;
            p.red = a.red + b.red - c.red;
            p.green = a.green + b.green - c.green;
            p.blue = a.blue + b.blue - c.blue;
            p.alpha = a.alpha + b.alpha - c.alpha;
            return p;
        }

        template <typename T>
        hsi_pixel predictor_hsi (const T& img, long row, long col)
        {
            // a = left, b = above, c = upper left
            hsi_pixel a(0,0,0), b(0,0,0), c(0,0,0);

            const long c1 = col-1;
            const long r1 = row-1;

            if (c1 >= 0)
                assign_pixel(a, img[row][c1]);
            else
                assign_pixel(a,(unsigned char)0);

            if (c1 >= 0 && r1 >= 0)
                assign_pixel(c, img[r1][c1]);
            else
                assign_pixel(c,(unsigned char)0);

            if (r1 >= 0)
                assign_pixel(b, img[r1][col]);
            else
                assign_pixel(b,(unsigned char)0);

            hsi_pixel p;
            p.h = a.h + b.h - c.h;
            p.s = a.s + b.s - c.s;
            p.i = a.i + b.i - c.i;
            return p;
        }

        template <typename T>
        unsigned char predictor_grayscale (const T& img, long row, long col)
        {
            // a = left, b = above, c = upper left
            unsigned char a = 0, b = 0, c = 0;

            const long c1 = col-1;
            const long r1 = row-1;

            if (c1 >= 0)
                assign_pixel(a, img[row][c1]);

            if (c1 >= 0 && r1 >= 0)
                assign_pixel(c, img[r1][c1]);

            if (r1 >= 0)
                assign_pixel(b, img[r1][col]);

            unsigned char p = a + b - c;
            return p;
        }

        template <typename T>
        uint16 predictor_grayscale_16 (const T& img, long row, long col)
        {
            // a = left, b = above, c = upper left
            uint16 a = 0, b = 0, c = 0;

            const long c1 = col-1;
            const long r1 = row-1;

            if (c1 >= 0)
                assign_pixel(a, img[row][c1]);

            if (c1 >= 0 && r1 >= 0)
                assign_pixel(c, img[r1][c1]);

            if (r1 >= 0)
                assign_pixel(b, img[r1][col]);

            uint16 p = a + b - c;
            return p;
        }

    }
}

#endif  // DLIB_DNG_SHAREd_


dlib C++ Library - image_saver.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_IMAGE_SAVEr_
#define DLIB_IMAGE_SAVEr_

#include "image_saver_abstract.h"
#include <iostream>
#include <fstream>
#include <sstream>
#include "../algs.h"
#include "../pixel.h"
#include "../byte_orderer.h"
#include "../entropy_encoder.h"
#include "../entropy_encoder_model.h"
#include "dng_shared.h"
#include "../uintn.h"
#include "../dir_nav.h"
#include "../float_details.h"
#include "../vectorstream.h"
#include "../matrix/matrix_exp.h"
#include "../image_transforms/assign_image.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class image_save_error : public dlib::error {
    public: image_save_error(const std::string& str) : error(EIMAGE_SAVE,str){}
    };

// ----------------------------------------------------------------------------------------

    template <
        typename image_type,
        bool grayscale = pixel_traits<typename image_traits<image_type>::pixel_type>::grayscale
        >
    struct save_bmp_helper;

    template <typename image_type>
    struct save_bmp_helper<image_type,false>
    {
        static void save_bmp (
            const image_type& image_,
            std::ostream& out
        )
        {
            const_image_view<image_type> image(image_);
            // we are going to write out a 24bit color image.
            byte_orderer::kernel_1a bo;

            out.write("BM",2);

            if (!out)
                throw image_save_error("error writing image to output stream");

            unsigned long pad = 4 - (image.nc()*3)%4;
            if (pad == 4)
                pad = 0;

            unsigned long bfSize = 14 + 40 + (image.nc()*3 + pad)*image.nr();
            unsigned long bfReserved = 0;
            unsigned long bfOffBits = 14 + 40;
            unsigned long biSize = 40;
            unsigned long biWidth = image.nc();
            unsigned long biHeight = image.nr();
            unsigned short biPlanes = 1;
            unsigned short biBitCount = 24;
            unsigned long biCompression = 0;
            unsigned long biSizeImage = 0;
            unsigned long biXPelsPerMeter = 0;
            unsigned long biYPelsPerMeter = 0;
            unsigned long biClrUsed = 0;
            unsigned long biClrImportant = 0;

            bo.host_to_little(bfSize);
            bo.host_to_little(bfOffBits);
            bo.host_to_little(biSize);
            bo.host_to_little(biWidth);
            bo.host_to_little(biHeight);
            bo.host_to_little(biPlanes);
            bo.host_to_little(biBitCount);

            out.write((char*)&bfSize,4);
            out.write((char*)&bfReserved,4);
            out.write((char*)&bfOffBits,4);
            out.write((char*)&biSize,4);
            out.write((char*)&biWidth,4);
            out.write((char*)&biHeight,4);
            out.write((char*)&biPlanes,2);
            out.write((char*)&biBitCount,2);
            out.write((char*)&biCompression,4);
            out.write((char*)&biSizeImage,4);
            out.write((char*)&biXPelsPerMeter,4);
            out.write((char*)&biYPelsPerMeter,4);
            out.write((char*)&biClrUsed,4);
            out.write((char*)&biClrImportant,4);

            if (!out)
                throw image_save_error("error writing image to output stream");

            // now we write out the pixel data
            for (long row = image.nr()-1; row >= 0; --row)
            {
                for (long col = 0; col < image.nc(); ++col)
                {
                    rgb_pixel p;
                    p.red = 0;
                    p.green = 0;
                    p.blue = 0;
                    assign_pixel(p,image[row][col]);
                    out.write((char*)&p.blue,1);
                    out.write((char*)&p.green,1);
                    out.write((char*)&p.red,1);
                }

                // write out some zeros so that this line is a multiple of 4 bytes
                for (unsigned long i = 0; i < pad; ++i)
                {
                    unsigned char p = 0;
                    out.write((char*)&p,1);
                }
            }

            if (!out)
                throw image_save_error("error writing image to output stream");
        }
    };

    template <typename image_type>
    struct save_bmp_helper<image_type,true>
    {
        static void save_bmp (
            const image_type& image_,
            std::ostream& out
        )
        {
            const_image_view<image_type> image(image_);
            // we are going to write out an 8bit color image.
            byte_orderer::kernel_1a bo;

            out.write("BM",2);

            if (!out)
                throw image_save_error("error writing image to output stream");

            unsigned long pad = 4 - image.nc()%4;
            if (pad == 4)
                pad = 0;

            unsigned long bfSize = 14 + 40 + (image.nc() + pad)*image.nr() + 256*4;
            unsigned long bfReserved = 0;
            unsigned long bfOffBits = 14 + 40 + 256*4;
            unsigned long biSize = 40;
            unsigned long biWidth = image.nc();
            unsigned long biHeight = image.nr();
            unsigned short biPlanes = 1;
            unsigned short biBitCount = 8;
            unsigned long biCompression = 0;
            unsigned long biSizeImage = 0;
            unsigned long biXPelsPerMeter = 0;
            unsigned long biYPelsPerMeter = 0;
            unsigned long biClrUsed = 0;
            unsigned long biClrImportant = 0;

            bo.host_to_little(bfSize);
            bo.host_to_little(bfOffBits);
            bo.host_to_little(biSize);
            bo.host_to_little(biWidth);
            bo.host_to_little(biHeight);
            bo.host_to_little(biPlanes);
            bo.host_to_little(biBitCount);

            out.write((char*)&bfSize,4);
            out.write((char*)&bfReserved,4);
            out.write((char*)&bfOffBits,4);
            out.write((char*)&biSize,4);
            out.write((char*)&biWidth,4);
            out.write((char*)&biHeight,4);
            out.write((char*)&biPlanes,2);
            out.write((char*)&biBitCount,2);
            out.write((char*)&biCompression,4);
            out.write((char*)&biSizeImage,4);
            out.write((char*)&biXPelsPerMeter,4);
            out.write((char*)&biYPelsPerMeter,4);
            out.write((char*)&biClrUsed,4);
            out.write((char*)&biClrImportant,4);

            // write out the color palette
            for (unsigned int i = 0; i <= 255; ++i)
            {
                unsigned char ch = static_cast<unsigned char>(i);
                out.write((char*)&ch,1);
                out.write((char*)&ch,1);
                out.write((char*)&ch,1);
                ch = 0;
                out.write((char*)&ch,1);
            }

            if (!out)
                throw image_save_error("error writing image to output stream");

            // now we write out the pixel data
            for (long row = image.nr()-1; row >= 0; --row)
            {
                for (long col = 0; col < image.nc(); ++col)
                {
                    unsigned char p = 0;
                    assign_pixel(p,image[row][col]);
                    out.write((char*)&p,1);
                }

                // write out some zeros so that this line is a multiple of 4 bytes
                for (unsigned long i = 0; i < pad; ++i)
                {
                    unsigned char p = 0;
                    out.write((char*)&p,1);
                }
            }

            if (!out)
                throw image_save_error("error writing image to output stream");

        }
    };

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    inline typename disable_if<is_matrix<image_type> >::type save_bmp (
        const image_type& image,
        std::ostream& out
    )
    {
        save_bmp_helper<image_type>::save_bmp(image,out);
    }

    template <
        typename EXP
        >
    inline void save_bmp (
        const matrix_exp<EXP>& image,
        std::ostream& out
    )
    {
        array2d<typename EXP::type> temp;
        assign_image(temp, image);
        save_bmp_helper<array2d<typename EXP::type> >::save_bmp(temp,out);
    }

// ----------------------------------------------------------------------------------------

    namespace dng_helpers_namespace
    {
        template <
            typename image_type,
            typename enabled = void
            >
        struct save_dng_helper;

        typedef entropy_encoder::kernel_2a encoder_type;
        typedef entropy_encoder_model<256,encoder_type>::kernel_5a eem_type;

        typedef entropy_encoder_model<256,encoder_type>::kernel_4a eem_exp_type;

        template <typename image_type >
        struct save_dng_helper<image_type, typename enable_if<is_float_type<typename image_traits<image_type>::pixel_type> >::type >
        {
            static void save_dng (
                const image_type& image_,
                std::ostream& out
            )
            {
                const_image_view<image_type> image(image_);
                out.write("DNG",3);
                unsigned long version = 1;
                serialize(version,out);
                unsigned long type = grayscale_float;
                serialize(type,out);
                serialize(image.nc(),out);
                serialize(image.nr(),out);

                // Write the compressed exponent data into expbuf.  We will append it
                // to the stream at the end of the loops.
                std::vector<char> expbuf;
                expbuf.reserve(image.size()*2);
                vectorstream outexp(expbuf);
                encoder_type encoder;
                encoder.set_stream(outexp);

                eem_exp_type eem_exp(encoder);
                float_details prev;
                for (long r = 0; r < image.nr(); ++r)
                {
                    for (long c = 0; c < image.nc(); ++c)
                    {
                        float_details cur = image[r][c];
                        int16 exp = cur.exponent-prev.exponent;
                        int64 man = cur.mantissa-prev.mantissa;
                        prev = cur;

                        unsigned char ebyte1 = exp&0xFF;
                        unsigned char ebyte2 = exp>>8;
                        eem_exp.encode(ebyte1);
                        eem_exp.encode(ebyte2);

                        serialize(man, out);
                    }
                }
                // write out the magic byte to mark the end of the compressed data.
                eem_exp.encode(dng_magic_byte);
                eem_exp.encode(dng_magic_byte);
                eem_exp.encode(dng_magic_byte);
                eem_exp.encode(dng_magic_byte);

                encoder.clear();
                serialize(expbuf, out);
            }
        };

        template <typename image_type>
        struct is_non_float_non8bit_grayscale
        {
            typedef typename image_traits<image_type>::pixel_type pixel_type;
            const static bool value = pixel_traits<pixel_type>::grayscale &&
                                      sizeof(pixel_type) != 1 &&
                                      !is_float_type<pixel_type>::value;
        };

        template <typename image_type >
        struct save_dng_helper<image_type, typename enable_if<is_non_float_non8bit_grayscale<image_type> >::type>
        {
            static void save_dng (
                const image_type& image_,
                std::ostream& out
            )
            {
                const_image_view<image_type> image(image_);
                out.write("DNG",3);
                unsigned long version = 1;
                serialize(version,out);
                unsigned long type = grayscale_16bit;
                serialize(type,out);
                serialize(image.nc(),out);
                serialize(image.nr(),out);

                encoder_type encoder;
                encoder.set_stream(out);

                eem_type eem(encoder);
                for (long r = 0; r < image.nr(); ++r)
                {
                    for (long c = 0; c < image.nc(); ++c)
                    {
                        uint16 cur;
                        assign_pixel(cur, image[r][c]);
                        cur -= predictor_grayscale_16(image,r,c);
                        unsigned char byte1 = cur&0xFF;
                        unsigned char byte2 = cur>>8;
                        eem.encode(byte2);
                        eem.encode(byte1);
                    }
                }
                // write out the magic byte to mark the end of the data
                eem.encode(dng_magic_byte);
                eem.encode(dng_magic_byte);
                eem.encode(dng_magic_byte);
                eem.encode(dng_magic_byte);
            }
        };

        template <typename image_type>
        struct is_8bit_grayscale
        {
            typedef typename image_traits<image_type>::pixel_type pixel_type;
            const static bool value = pixel_traits<pixel_type>::grayscale && sizeof(pixel_type) == 1;
        };

        template <typename image_type>
        struct save_dng_helper<image_type, typename enable_if<is_8bit_grayscale<image_type> >::type>
        {
            static void save_dng (
                const image_type& image_,
                std::ostream& out
            )
            {
                const_image_view<image_type> image(image_);
                out.write("DNG",3);
                unsigned long version = 1;
                serialize(version,out);
                unsigned long type = grayscale;
                serialize(type,out);
                serialize(image.nc(),out);
                serialize(image.nr(),out);

                encoder_type encoder;
                encoder.set_stream(out);

                eem_type eem(encoder);
                for (long r = 0; r < image.nr(); ++r)
                {
                    for (long c = 0; c < image.nc(); ++c)
                    {
                        unsigned char cur;
                        assign_pixel(cur, image[r][c]);
                        cur -= predictor_grayscale(image,r,c);
                        eem.encode(cur);
                    }
                }
                // write out the magic byte to mark the end of the data
                eem.encode(dng_magic_byte);
                eem.encode(dng_magic_byte);
                eem.encode(dng_magic_byte);
                eem.encode(dng_magic_byte);
            }
        };

        template <typename image_type>
        struct is_rgb_image
        {
            typedef typename image_traits<image_type>::pixel_type pixel_type;
            const static bool value = pixel_traits<pixel_type>::rgb;
        };

        template <typename image_type>
        struct save_dng_helper<image_type,typename enable_if<is_rgb_image<image_type> >::type>
        {
            static void save_dng (
                const image_type& image_,
                std::ostream& out
            )
            {
                const_image_view<image_type> image(image_);
                out.write("DNG",3);
                unsigned long version = 1;
                serialize(version,out);

                unsigned long type = rgb;
                // if this is a small image then we will use a different predictor
                if (image.size() < 4000)
                    type = rgb_paeth;

                serialize(type,out);
                serialize(image.nc(),out);
                serialize(image.nr(),out);

                encoder_type encoder;
                encoder.set_stream(out);

                rgb_pixel pre, cur;
                eem_type eem(encoder);

                if (type == rgb)
                {
                    for (long r = 0; r < image.nr(); ++r)
                    {
                        for (long c = 0; c < image.nc(); ++c)
                        {
                            pre = predictor_rgb(image,r,c);
                            assign_pixel(cur, image[r][c]);

                            eem.encode((unsigned char)(cur.red - pre.red));
                            eem.encode((unsigned char)(cur.green - pre.green));
                            eem.encode((unsigned char)(cur.blue - pre.blue));
                        }
                    }
                }
                else
                {
                    for (long r = 0; r < image.nr(); ++r)
                    {
                        for (long c = 0; c < image.nc(); ++c)
                        {
                            pre = predictor_rgb_paeth(image,r,c);
                            assign_pixel(cur, image[r][c]);

                            eem.encode((unsigned char)(cur.red - pre.red));
                            eem.encode((unsigned char)(cur.green - pre.green));
                            eem.encode((unsigned char)(cur.blue - pre.blue));
                        }
                    }
                }
                // write out the magic byte to mark the end of the data
                eem.encode(dng_magic_byte);
                eem.encode(dng_magic_byte);
                eem.encode(dng_magic_byte);
                eem.encode(dng_magic_byte);
            }
        };

        template <typename image_type>
        struct is_rgb_alpha_image
        {
            typedef typename image_traits<image_type>::pixel_type pixel_type;
            const static bool value = pixel_traits<pixel_type>::rgb_alpha;
        };

        template <typename image_type>
        struct save_dng_helper<image_type,typename enable_if<is_rgb_alpha_image<image_type> >::type>
        {
            static void save_dng (
                const image_type& image_,
                std::ostream& out
            )
            {
                const_image_view<image_type> image(image_);
                out.write("DNG",3);
                unsigned long version = 1;
                serialize(version,out);

                unsigned long type = rgb_alpha;
                // if this is a small image then we will use a different predictor
                if (image.size() < 4000)
                    type = rgb_alpha_paeth;

                serialize(type,out);
                serialize(image.nc(),out);
                serialize(image.nr(),out);

                encoder_type encoder;
                encoder.set_stream(out);

                rgb_alpha_pixel pre, cur;
                eem_type eem(encoder);

                if (type == rgb_alpha)
                {
                    for (long r = 0; r < image.nr(); ++r)
                    {
                        for (long c = 0; c < image.nc(); ++c)
                        {
                            pre = predictor_rgb_alpha(image,r,c);
                            assign_pixel(cur, image[r][c]);

                            eem.encode((unsigned char)(cur.red - pre.red));
                            eem.encode((unsigned char)(cur.green - pre.green));
                            eem.encode((unsigned char)(cur.blue - pre.blue));
                            eem.encode((unsigned char)(cur.alpha - pre.alpha));
                        }
                    }
                }
                else
                {
                    for (long r = 0; r < image.nr(); ++r)
                    {
                        for (long c = 0; c < image.nc(); ++c)
                        {
                            pre = predictor_rgb_alpha_paeth(image,r,c);
                            assign_pixel(cur, image[r][c]);

                            eem.encode((unsigned char)(cur.red - pre.red));
                            eem.encode((unsigned char)(cur.green - pre.green));
                            eem.encode((unsigned char)(cur.blue - pre.blue));
                            eem.encode((unsigned char)(cur.alpha - pre.alpha));
                        }
                    }
                }
                // write out the magic byte to mark the end of the data
                eem.encode(dng_magic_byte);
                eem.encode(dng_magic_byte);
                eem.encode(dng_magic_byte);
                eem.encode(dng_magic_byte);
            }
        };

        template <typename image_type>
        struct is_hsi_image
        {
            typedef typename image_traits<image_type>::pixel_type pixel_type;
            const static bool value = pixel_traits<pixel_type>::hsi;
        };

        template <typename image_type>
        struct save_dng_helper<image_type,typename enable_if<is_hsi_image<image_type> >::type>
        {
            static void save_dng (
                const image_type& image_,
                std::ostream& out
            )
            {
                const_image_view<image_type> image(image_);
                out.write("DNG",3);
                unsigned long version = 1;
                serialize(version,out);
                unsigned long type = hsi;
                serialize(type,out);
                serialize(image.nc(),out);
                serialize(image.nr(),out);

                encoder_type encoder;
                encoder.set_stream(out);

                hsi_pixel pre, cur;
                eem_type eem(encoder);
                for (long r = 0; r < image.nr(); ++r)
                {
                    for (long c = 0; c < image.nc(); ++c)
                    {
                        pre = predictor_hsi(image,r,c);
                        assign_pixel(cur, image[r][c]);

                        eem.encode((unsigned char)(cur.h - pre.h));
                        eem.encode((unsigned char)(cur.s - pre.s));
                        eem.encode((unsigned char)(cur.i - pre.i));
                    }
                }
                // write out the magic byte to mark the end of the data
                eem.encode(dng_magic_byte);
                eem.encode(dng_magic_byte);
                eem.encode(dng_magic_byte);
                eem.encode(dng_magic_byte);
            }
        };
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    inline typename disable_if<is_matrix<image_type> >::type save_dng (
        const image_type& image,
        std::ostream& out
    )
    {
        using namespace dng_helpers_namespace;
        save_dng_helper<image_type>::save_dng(image,out);
    }

    template <
        typename EXP
        >
    inline void save_dng (
        const matrix_exp<EXP>& image,
        std::ostream& out
    )
    {
        array2d<typename EXP::type> temp;
        assign_image(temp, image);
        using namespace dng_helpers_namespace;
        save_dng_helper<array2d<typename EXP::type> >::save_dng(temp,out);
    }

// ----------------------------------------------------------------------------------------

    template <typename image_type>
    void save_dng (
        const image_type& image,
        const std::string& file_name
    )
    {
        std::ofstream fout(file_name.c_str(), std::ios::binary);
        if (!fout)
            throw image_save_error("Unable to open " + file_name + " for writing.");
        save_dng(image, fout);
    }

// ----------------------------------------------------------------------------------------

    template <typename image_type>
    void save_bmp (
        const image_type& image,
        const std::string& file_name
    )
    {
        std::ofstream fout(file_name.c_str(), std::ios::binary);
        if (!fout)
            throw image_save_error("Unable to open " + file_name + " for writing.");
        save_bmp(image, fout);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_IMAGE_SAVEr_


dlib C++ Library - save_jpeg.cpp

// Copyright (C) 2014  Davis E. King (davis@dlib.net), Nils Labugt
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_JPEG_SAVER_CPp_
#define DLIB_JPEG_SAVER_CPp_

// only do anything with this file if DLIB_JPEG_SUPPORT is defined
#ifdef DLIB_JPEG_SUPPORT

#include "../array2d.h"
#include "../pixel.h"
#include "save_jpeg.h"
#include <stdio.h>
#ifdef DLIB_JPEG_STATIC
#   include "../external/libjpeg/jpeglib.h"
#else
#   include <jpeglib.h>
#endif
#include <sstream>
#include <setjmp.h>
#include "image_saver.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    struct jpeg_saver_error_mgr
    {
        jpeg_error_mgr pub;    /* "public" fields */
        jmp_buf setjmp_buffer;  /* for return to caller */
    };

    void jpeg_saver_error_exit (j_common_ptr cinfo)
    {
        /* cinfo->err really points to a jpeg_saver_error_mgr struct, so coerce pointer */
        jpeg_saver_error_mgr* myerr = (jpeg_saver_error_mgr*) cinfo->err;

        /* Return control to the setjmp point */
        longjmp(myerr->setjmp_buffer, 1);
    }

// ----------------------------------------------------------------------------------------

    void save_jpeg (
        const array2d<rgb_pixel>& img,
        const std::string& filename,
        int quality
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(img.size() != 0,
            "\t save_jpeg()"
            << "\n\t You can't save an empty image as a JPEG."
            );
        DLIB_CASSERT(0 <= quality && quality <= 100,
            "\t save_jpeg()"
            << "\n\t Invalid quality value."
            << "\n\t quality: " << quality
            );

        FILE* outfile = fopen(filename.c_str(), "wb");
        if (!outfile)
            throw image_save_error("Can't open file " + filename + " for writing.");

        jpeg_compress_struct cinfo;

        jpeg_saver_error_mgr jerr;
        cinfo.err = jpeg_std_error(&jerr.pub);
        jerr.pub.error_exit = jpeg_saver_error_exit;
        /* Establish the setjmp return context for my_error_exit to use. */
        if (setjmp(jerr.setjmp_buffer))
        {
            /* If we get here, the JPEG code has signaled an error.
             * We need to clean up the JPEG object, close the input file, and return.
             */
            jpeg_destroy_compress(&cinfo);
            fclose(outfile);
            throw image_save_error("save_jpeg: error while writing " + filename);
        }

        jpeg_create_compress(&cinfo);
        jpeg_stdio_dest(&cinfo, outfile);

        cinfo.image_width      = img.nc();
        cinfo.image_height     = img.nr();
        cinfo.input_components = 3;
        cinfo.in_color_space   = JCS_RGB;
        jpeg_set_defaults(&cinfo);
        jpeg_set_quality (&cinfo, quality, true);
        jpeg_start_compress(&cinfo, true);

        // now write out the rows one at a time
        while (cinfo.next_scanline < cinfo.image_height) {
            JSAMPROW row_pointer = (JSAMPROW) &img[cinfo.next_scanline][0];
            jpeg_write_scanlines(&cinfo, &row_pointer, 1);
        }

        jpeg_finish_compress(&cinfo);
        jpeg_destroy_compress(&cinfo);
        fclose( outfile );
    }

// ----------------------------------------------------------------------------------------

    void save_jpeg (
        const array2d<unsigned char>& img,
        const std::string& filename,
        int quality
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(img.size() != 0,
            "\t save_jpeg()"
            << "\n\t You can't save an empty image as a JPEG."
            );
        DLIB_CASSERT(0 <= quality && quality <= 100,
            "\t save_jpeg()"
            << "\n\t Invalid quality value."
            << "\n\t quality: " << quality
            );

        FILE* outfile = fopen(filename.c_str(), "wb");
        if (!outfile)
            throw image_save_error("Can't open file " + filename + " for writing.");

        jpeg_compress_struct cinfo;

        jpeg_saver_error_mgr jerr;
        cinfo.err = jpeg_std_error(&jerr.pub);
        jerr.pub.error_exit = jpeg_saver_error_exit;
        /* Establish the setjmp return context for my_error_exit to use. */
        if (setjmp(jerr.setjmp_buffer))
        {
            /* If we get here, the JPEG code has signaled an error.
             * We need to clean up the JPEG object, close the input file, and return.
             */
            jpeg_destroy_compress(&cinfo);
            fclose(outfile);
            throw image_save_error("save_jpeg: error while writing " + filename);
        }

        jpeg_create_compress(&cinfo);
        jpeg_stdio_dest(&cinfo, outfile);

        cinfo.image_width      = img.nc();
        cinfo.image_height     = img.nr();
        cinfo.input_components = 1;
        cinfo.in_color_space   = JCS_GRAYSCALE;
        jpeg_set_defaults(&cinfo);
        jpeg_set_quality (&cinfo, quality, true);
        jpeg_start_compress(&cinfo, true);

        // now write out the rows one at a time
        while (cinfo.next_scanline < cinfo.image_height) {
            JSAMPROW row_pointer = (JSAMPROW) &img[cinfo.next_scanline][0];
            jpeg_write_scanlines(&cinfo, &row_pointer, 1);
        }

        jpeg_finish_compress(&cinfo);
        jpeg_destroy_compress(&cinfo);
        fclose( outfile );
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_JPEG_SUPPORT

#endif // DLIB_JPEG_SAVER_CPp_


dlib C++ Library - save_jpeg.h

// Copyright (C) 2014  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SAVE_JPEG_Hh_
#define DLIB_SAVE_JPEG_Hh_

#include "save_jpeg_abstract.h"

#include "../enable_if.h"
#include "../matrix.h"
#include "../array2d.h"
#include "../pixel.h"
#include "../image_processing/generic_image.h"
#include <string>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    void save_jpeg (
        const array2d<rgb_pixel>& img,
        const std::string& filename,
        int quality = 75
    );

// ----------------------------------------------------------------------------------------

    void save_jpeg (
        const array2d<unsigned char>& img,
        const std::string& filename,
        int quality = 75
    );

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    typename disable_if<is_matrix<image_type> >::type save_jpeg(
        const image_type& img,
        const std::string& filename,
        int quality = 75
    )
    {
        // Convert any kind of grayscale image to an unsigned char image
        if (pixel_traits<typename image_traits<image_type>::pixel_type>::grayscale)
        {
            array2d<unsigned char> temp;
            assign_image(temp, img);
            save_jpeg(temp, filename, quality);
        }
        else
        {
            // This is some other kind of color image so just save it as an RGB image.
            array2d<rgb_pixel> temp;
            assign_image(temp, img);
            save_jpeg(temp, filename, quality);
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP
        >
    void save_jpeg(
        const matrix_exp<EXP>& img,
        const std::string& file_name,
        int quality = 75
    )
    {
        array2d<typename EXP::type> temp;
        assign_image(temp, img);
        save_jpeg(temp, file_name, quality);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SAVE_JPEG_Hh_


dlib C++ Library - save_png.cpp

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SAVE_PnG_CPPh_
#define DLIB_SAVE_PnG_CPPh_

// only do anything with this file if DLIB_PNG_SUPPORT is defined
#ifdef DLIB_PNG_SUPPORT

#include "save_png.h"
#include <cstdio>
#include <png.h>
#include "../byte_orderer.h"

namespace dlib
{
    // Don't do anything when libpng calls us to tell us about an error.  Just return to
    // our own code and throw an exception (at the long jump target).
    void png_reader_user_error_fn_silent(png_structp  png_struct, png_const_charp )
    {
        longjmp(png_jmpbuf(png_struct),1);
    }
    void png_reader_user_warning_fn_silent(png_structp , png_const_charp )
    {
    }

    namespace impl
    {
        void impl_save_png (
            const std::string& file_name,
            std::vector<unsigned char*>& row_pointers,
            const long width,
            const png_type type,
            const int bit_depth
        )
        {

            FILE *fp;
            png_structp png_ptr;
            png_infop info_ptr;

            /* Open the file */
            fp = fopen(file_name.c_str(), "wb");
            if (fp == NULL)
                throw image_save_error("Unable to open " + file_name + " for writing.");

            /* Create and initialize the png_struct with the desired error handler
            * functions.  If you want to use the default stderr and longjump method,
            * you can supply NULL for the last three parameters.  We also check that
            * the library version is compatible with the one used at compile time,
            * in case we are using dynamically linked libraries.  REQUIRED.
            */
            png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, &png_reader_user_error_fn_silent, &png_reader_user_warning_fn_silent);

            if (png_ptr == NULL)
            {
                fclose(fp);
                throw image_save_error("Error while writing PNG file " + file_name);
            }

            /* Allocate/initialize the image information data.  REQUIRED */
            info_ptr = png_create_info_struct(png_ptr);
            if (info_ptr == NULL)
            {
                fclose(fp);
                png_destroy_write_struct(&png_ptr,  NULL);
                throw image_save_error("Error while writing PNG file " + file_name);
            }

            /* Set error handling.  REQUIRED if you aren't supplying your own
            * error handling functions in the png_create_write_struct() call.
            */
            if (setjmp(png_jmpbuf(png_ptr)))
            {
                /* If we get here, we had a problem writing the file */
                fclose(fp);
                png_destroy_write_struct(&png_ptr, &info_ptr);
                throw image_save_error("Error while writing PNG file " + file_name);
            }

            int color_type = 0;
            switch(type)
            {
                case png_type_rgb:       color_type = PNG_COLOR_TYPE_RGB; break;
                case png_type_rgb_alpha: color_type = PNG_COLOR_TYPE_RGB_ALPHA; break;
                case png_type_gray:      color_type = PNG_COLOR_TYPE_GRAY; break;
                default:
                    {
                        fclose(fp);
                        png_destroy_write_struct(&png_ptr, &info_ptr);
                        throw image_save_error("Invalid color type");
                    }
            }

            /* Set up the output control if you are using standard C streams */
            png_init_io(png_ptr, fp);

            int png_transforms = PNG_TRANSFORM_IDENTITY;
            byte_orderer bo;
            if (bo.host_is_little_endian())
                png_transforms |= PNG_TRANSFORM_SWAP_ENDIAN;

            const long height = row_pointers.size();

            png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
            png_set_rows(png_ptr, info_ptr, &row_pointers[0]);
            png_write_png(png_ptr, info_ptr, png_transforms, NULL);

            /* Clean up after the write, and free any memory allocated */
            png_destroy_write_struct(&png_ptr, &info_ptr);

            /* Close the file */
            fclose(fp);
        }
    }
}

#endif // DLIB_PNG_SUPPORT

#endif // DLIB_SAVE_PnG_CPPh_


dlib C++ Library - save_png.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SAVE_PnG_Hh_
#define DLIB_SAVE_PnG_Hh_

#include "save_png_abstract.h"
#include "image_saver.h"
#include "../array2d.h"
#include <vector>
#include <string>
#include "../pixel.h"
#include "../matrix/matrix_exp.h"
#include "../image_transforms/assign_image.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    namespace impl
    {
        enum png_type
        {
            png_type_rgb,
            png_type_rgb_alpha,
            png_type_gray,
        };

        void impl_save_png (
            const std::string& file_name,
            std::vector<unsigned char*>& row_pointers,
            const long width,
            const png_type type,
            const int bit_depth
        );
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    typename disable_if<is_matrix<image_type> >::type save_png(
        const image_type& img_,
        const std::string& file_name
    )
    {
        const_image_view<image_type> img(img_);

        // make sure requires clause is not broken
        DLIB_CASSERT(img.size() != 0,
            "\t save_png()"
            << "\n\t You can't save an empty image as a PNG"
            );

#ifndef DLIB_PNG_SUPPORT
            /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                You are getting this error because you are trying to use save_png()
                but you haven't defined DLIB_PNG_SUPPORT.  You must do so to use
                this function.   You must also make sure you set your build environment
                to link against the libpng library.
            !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
            COMPILE_TIME_ASSERT(sizeof(image_type) == 0);
#else
        std::vector<unsigned char*> row_pointers(img.nr());
        typedef typename image_traits<image_type>::pixel_type pixel_type;

        if (is_same_type<rgb_pixel,pixel_type>::value)
        {
            for (unsigned long i = 0; i < row_pointers.size(); ++i)
                row_pointers[i] = (unsigned char*)(&img[i][0]);

            impl::impl_save_png(file_name, row_pointers, img.nc(), impl::png_type_rgb, 8);
        }
        else if (is_same_type<rgb_alpha_pixel,pixel_type>::value)
        {
            for (unsigned long i = 0; i < row_pointers.size(); ++i)
                row_pointers[i] = (unsigned char*)(&img[i][0]);

            impl::impl_save_png(file_name, row_pointers, img.nc(), impl::png_type_rgb_alpha, 8);
        }
        else if (pixel_traits<pixel_type>::hsi || pixel_traits<pixel_type>::rgb)
        {
            // convert from HSI to RGB (Or potentially RGB pixels that aren't laid out as R G B)
            array2d<rgb_pixel> temp_img;
            assign_image(temp_img, img_);
            for (unsigned long i = 0; i < row_pointers.size(); ++i)
                row_pointers[i] = (unsigned char*)(&temp_img[i][0]);

            impl::impl_save_png(file_name, row_pointers, img.nc(), impl::png_type_rgb, 8);
        }
        else if (pixel_traits<pixel_type>::rgb_alpha)
        {
            // convert from RGBA pixels that aren't laid out as R G B A
            array2d<rgb_alpha_pixel> temp_img;
            assign_image(temp_img, img_);
            for (unsigned long i = 0; i < row_pointers.size(); ++i)
                row_pointers[i] = (unsigned char*)(&temp_img[i][0]);

            impl::impl_save_png(file_name, row_pointers, img.nc(), impl::png_type_rgb_alpha, 8);
        }
        else // this is supposed to be grayscale
        {
            DLIB_CASSERT(pixel_traits<pixel_type>::grayscale, "impossible condition detected");

            if (pixel_traits<pixel_type>::is_unsigned && sizeof(pixel_type) == 1)
            {
                for (unsigned long i = 0; i < row_pointers.size(); ++i)
                    row_pointers[i] = (unsigned char*)(&img[i][0]);

                impl::impl_save_png(file_name, row_pointers, img.nc(), impl::png_type_gray, 8);
            }
            else if (pixel_traits<pixel_type>::is_unsigned && sizeof(pixel_type) == 2)
            {
                for (unsigned long i = 0; i < row_pointers.size(); ++i)
                    row_pointers[i] = (unsigned char*)(&img[i][0]);

                impl::impl_save_png(file_name, row_pointers, img.nc(), impl::png_type_gray, 16);
            }
            else
            {
                // convert from whatever this is to 16bit grayscale
                array2d<dlib::uint16> temp_img;
                assign_image(temp_img, img_);
                for (unsigned long i = 0; i < row_pointers.size(); ++i)
                    row_pointers[i] = (unsigned char*)(&temp_img[i][0]);

                impl::impl_save_png(file_name, row_pointers, img.nc(), impl::png_type_gray, 16);
            }
        }

#endif

    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP
        >
    void save_png(
        const matrix_exp<EXP>& img,
        const std::string& file_name
    )
    {
        array2d<typename EXP::type> temp;
        assign_image(temp, img);
        save_png(temp, file_name);
    }

// ----------------------------------------------------------------------------------------

}

#ifdef NO_MAKEFILE
#include "save_png.cpp"
#endif

#endif // DLIB_SAVE_PnG_Hh_


dlib C++ Library - assign_image.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ASSIGN_IMAGe_
#define DLIB_ASSIGN_IMAGe_

#include "../pixel.h"
#include "assign_image_abstract.h"
#include "../statistics.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename dest_image_type,
        typename src_image_type
        >
    void impl_assign_image (
        image_view<dest_image_type>& dest,
        const src_image_type& src
    )
    {
        dest.set_size(src.nr(),src.nc());
        for (long r = 0; r < src.nr(); ++r)
        {
            for (long c = 0; c < src.nc(); ++c)
            {
                assign_pixel(dest[r][c], src(r,c));
            }
        }
    }

    template <
        typename dest_image_type,
        typename src_image_type
        >
    void impl_assign_image (
        dest_image_type& dest_,
        const src_image_type& src
    )
    {
        image_view<dest_image_type> dest(dest_);
        impl_assign_image(dest, src);
    }

    template <
        typename dest_image_type,
        typename src_image_type
        >
    void assign_image (
        dest_image_type& dest,
        const src_image_type& src
    )
    {
        // check for the case where dest is the same object as src
        if (is_same_object(dest,src))
            return;

        impl_assign_image(dest, mat(src));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename dest_image_type,
        typename src_image_type
        >
    void impl_assign_image_scaled (
        image_view<dest_image_type>& dest,
        const src_image_type& src,
        const double thresh
    )
    {
        DLIB_ASSERT( thresh > 0,
            "\tvoid assign_image_scaled()"
            << "\n\t You have given an threshold value"
            << "\n\t thresh: " << thresh
            );

        typedef typename image_traits<dest_image_type>::pixel_type dest_pixel;

        // If the destination has a dynamic range big enough to contain the source image data then just do a
        // regular assign_image()
        if (pixel_traits<dest_pixel>::max() >= pixel_traits<typename src_image_type::type>::max() &&
            pixel_traits<dest_pixel>::min() <= pixel_traits<typename src_image_type::type>::min() )
        {
            impl_assign_image(dest, src);
            return;
        }

        dest.set_size(src.nr(),src.nc());

        if (src.size() == 0)
            return;

        if (src.size() == 1)
        {
            impl_assign_image(dest, src);
            return;
        }

        // gather image statistics
        running_stats<double> rs;
        for (long r = 0; r < src.nr(); ++r)
        {
            for (long c = 0; c < src.nc(); ++c)
            {
                rs.add(get_pixel_intensity(src(r,c)));
            }
        }
        typedef typename pixel_traits<typename src_image_type::type>::basic_pixel_type spix_type;

        if (std::numeric_limits<spix_type>::is_integer)
        {
            // If the destination has a dynamic range big enough to contain the source image data then just do a
            // regular assign_image()
            if (pixel_traits<dest_pixel>::max() >= rs.max() &&
                pixel_traits<dest_pixel>::min() <= rs.min() )
            {
                impl_assign_image(dest, src);
                return;
            }
        }

        // Figure out the range of pixel values based on image statistics.  There might be some huge
        // outliers so don't just pick the min and max values.
        const double upper = std::min(rs.mean() + thresh*rs.stddev(), rs.max());
        const double lower = std::max(rs.mean() - thresh*rs.stddev(), rs.min());

        const double dest_min = pixel_traits<dest_pixel>::min();
        const double dest_max = pixel_traits<dest_pixel>::max();

        const double scale = (upper!=lower)? ((dest_max - dest_min) / (upper - lower)) : 0;

        for (long r = 0; r < src.nr(); ++r)
        {
            for (long c = 0; c < src.nc(); ++c)
            {
                const double val = get_pixel_intensity(src(r,c)) - lower;

                assign_pixel(dest[r][c], scale*val + dest_min);
            }
        }
    }

    template <
        typename dest_image_type,
        typename src_image_type
        >
    void impl_assign_image_scaled (
        dest_image_type& dest_,
        const src_image_type& src,
        const double thresh
    )
    {
        image_view<dest_image_type> dest(dest_);
        impl_assign_image_scaled(dest, src, thresh);
    }

    template <
        typename dest_image_type,
        typename src_image_type
        >
    void assign_image_scaled (
        dest_image_type& dest,
        const src_image_type& src,
        const double thresh = 4
    )
    {
        // check for the case where dest is the same object as src
        if (is_same_object(dest,src))
            return;

        impl_assign_image_scaled(dest, mat(src),thresh);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename dest_image_type,
        typename src_pixel_type
        >
    void assign_all_pixels (
        image_view<dest_image_type>& dest_img,
        const src_pixel_type& src_pixel
    )
    {
        for (long r = 0; r < dest_img.nr(); ++r)
        {
            for (long c = 0; c < dest_img.nc(); ++c)
            {
                assign_pixel(dest_img[r][c], src_pixel);
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename dest_image_type,
        typename src_pixel_type
        >
    void assign_all_pixels (
        dest_image_type& dest_img_,
        const src_pixel_type& src_pixel
    )
    {
        image_view<dest_image_type> dest_img(dest_img_);
        assign_all_pixels(dest_img, src_pixel);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    void assign_border_pixels (
        image_view<image_type>& img,
        long x_border_size,
        long y_border_size,
        const typename image_traits<image_type>::pixel_type& p
    )
    {
        DLIB_ASSERT( x_border_size >= 0 && y_border_size >= 0,
            "\tvoid assign_border_pixels(img, p, border_size)"
            << "\n\tYou have given an invalid border_size"
            << "\n\tx_border_size: " << x_border_size
            << "\n\ty_border_size: " << y_border_size
            );

        y_border_size = std::min(y_border_size, img.nr()/2+1);
        x_border_size = std::min(x_border_size, img.nc()/2+1);

        // assign the top border
        for (long r = 0; r < y_border_size; ++r)
        {
            for (long c = 0; c < img.nc(); ++c)
            {
                img[r][c] = p;
            }
        }

        // assign the bottom border
        for (long r = img.nr()-y_border_size; r < img.nr(); ++r)
        {
            for (long c = 0; c < img.nc(); ++c)
            {
                img[r][c] = p;
            }
        }

        // now assign the two sides
        for (long r = y_border_size; r < img.nr()-y_border_size; ++r)
        {
            // left border
            for (long c = 0; c < x_border_size; ++c)
                img[r][c] = p;

            // right border
            for (long c = img.nc()-x_border_size; c < img.nc(); ++c)
                img[r][c] = p;
        }
    }

    template <
        typename image_type
        >
    void assign_border_pixels (
        image_type& img_,
        long x_border_size,
        long y_border_size,
        const typename image_traits<image_type>::pixel_type& p
    )
    {
        image_view<image_type> img(img_);
        assign_border_pixels(img, x_border_size, y_border_size, p);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    void zero_border_pixels (
        image_type& img,
        long x_border_size,
        long y_border_size
    )
    {
        DLIB_ASSERT( x_border_size >= 0 && y_border_size >= 0,
            "\tvoid zero_border_pixels(img, p, border_size)"
            << "\n\tYou have given an invalid border_size"
            << "\n\tx_border_size: " << x_border_size
            << "\n\ty_border_size: " << y_border_size
            );

        typename image_traits<image_type>::pixel_type zero_pixel;
        assign_pixel_intensity(zero_pixel, 0);
        assign_border_pixels(img, x_border_size, y_border_size, zero_pixel);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    void zero_border_pixels (
        image_view<image_type>& img,
        long x_border_size,
        long y_border_size
    )
    {
        DLIB_ASSERT( x_border_size >= 0 && y_border_size >= 0,
            "\tvoid zero_border_pixels(img, p, border_size)"
            << "\n\tYou have given an invalid border_size"
            << "\n\tx_border_size: " << x_border_size
            << "\n\ty_border_size: " << y_border_size
            );

        typename image_traits<image_type>::pixel_type zero_pixel;
        assign_pixel_intensity(zero_pixel, 0);
        assign_border_pixels(img, x_border_size, y_border_size, zero_pixel);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    void zero_border_pixels (
        image_view<image_type>& img,
        rectangle inside
    )
    {
        inside = inside.intersect(get_rect(img));
        if (inside.is_empty())
        {
            assign_all_pixels(img, 0);
            return;
        }

        for (long r = 0; r < inside.top(); ++r)
        {
            for (long c = 0; c < img.nc(); ++c)
                assign_pixel(img[r][c], 0);
        }
        for (long r = inside.top(); r <= inside.bottom(); ++r)
        {
            for (long c = 0; c < inside.left(); ++c)
                assign_pixel(img[r][c], 0);
            for (long c = inside.right()+1; c < img.nc(); ++c)
                assign_pixel(img[r][c], 0);
        }
        for (long r = inside.bottom()+1; r < img.nr(); ++r)
        {
            for (long c = 0; c < img.nc(); ++c)
                assign_pixel(img[r][c], 0);
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    void zero_border_pixels (
        image_type& img_,
        const rectangle& inside
    )
    {
        image_view<image_type> img(img_);
        zero_border_pixels(img, inside);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_ASSIGN_IMAGe_


dlib C++ Library - colormaps.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_RANDOMLY_COlOR_IMAGE_Hh_
#define DLIB_RANDOMLY_COlOR_IMAGE_Hh_

#include "colormaps_abstract.h"
#include "../hash.h"
#include "../pixel.h"
#include "../matrix.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <typename T>
    struct op_randomly_color_image : does_not_alias
    {
        op_randomly_color_image( const T& img_) : img(img_){}

        const T& img;

        const static long cost = 7;
        const static long NR = 0;
        const static long NC = 0;
        typedef rgb_pixel type;
        typedef const rgb_pixel const_ret_type;
        typedef default_memory_manager mem_manager_type;
        typedef row_major_layout layout_type;

        const_ret_type apply (long r, long c ) const
        {
            const unsigned long gray = get_pixel_intensity(mat(img)(r,c));
            if (gray != 0)
            {
                const uint32 h = murmur_hash3_2(gray,0);
                rgb_pixel pix;
                pix.red   = static_cast<unsigned char>(h)%200 + 55;
                pix.green = static_cast<unsigned char>(h>>8)%200 + 55;
                pix.blue  = static_cast<unsigned char>(h>>16)%200 + 55;
                return pix;
            }
            else
            {
                // keep black pixels black
                return rgb_pixel(0,0,0);
            }
        }

        long nr () const { return num_rows(img); }
        long nc () const { return num_columns(img); }
    };

    template <
        typename image_type
        >
    const matrix_op<op_randomly_color_image<image_type> >
    randomly_color_image (
        const image_type& img
    )
    {
        typedef op_randomly_color_image<image_type> op;
        return matrix_op<op>(op(img));
    }

// ----------------------------------------------------------------------------------------

    inline rgb_pixel colormap_heat (
        double value,
        double min_val,
        double max_val
    )
    {
        // scale the gray value into the range [0, 1]
        const double gray = put_in_range(0, 1, (value - min_val)/(max_val-min_val));
        rgb_pixel pix(0,0,0);

        pix.red = static_cast<unsigned char>(std::min(gray/0.4,1.0)*255 + 0.5);

        if (gray > 0.4)
        {
            pix.green = static_cast<unsigned char>(std::min((gray-0.4)/0.4,1.0)*255 + 0.5);
        }
        if (gray > 0.8)
        {
            pix.blue = static_cast<unsigned char>(std::min((gray-0.8)/0.2,1.0)*255 + 0.5);
        }

        return pix;
    }

// ----------------------------------------------------------------------------------------

    template <typename T>
    struct op_heatmap : does_not_alias
    {
        op_heatmap(
            const T& img_,
            const double max_val_,
            const double min_val_
            ) : img(img_), max_val(max_val_), min_val(min_val_){}

        const T& img;

        const double max_val;
        const double min_val;

        const static long cost = 7;
        const static long NR = 0;
        const static long NC = 0;
        typedef rgb_pixel type;
        typedef const rgb_pixel const_ret_type;
        typedef default_memory_manager mem_manager_type;
        typedef row_major_layout layout_type;

        const_ret_type apply (long r, long c ) const
        {
            return colormap_heat(get_pixel_intensity(mat(img)(r,c)), min_val, max_val);
        }

        long nr () const { return num_rows(img); }
        long nc () const { return num_columns(img); }
    };

    template <
        typename image_type
        >
    const matrix_op<op_heatmap<image_type> >
    heatmap (
        const image_type& img,
        double max_val,
        double min_val = 0
    )
    {
        typedef op_heatmap<image_type> op;
        return matrix_op<op>(op(img,max_val,min_val));
    }

    template <
        typename image_type
        >
    const matrix_op<op_heatmap<image_type> >
    heatmap (
        const image_type& img
    )
    {
        typedef op_heatmap<image_type> op;
        if (img.size() != 0)
            return matrix_op<op>(op(img,max(mat(img)),min(mat(img))));
        else
            return matrix_op<op>(op(img,0,0));
    }

// ----------------------------------------------------------------------------------------

    inline rgb_pixel colormap_jet (
        double value,
        double min_val,
        double max_val
    )
    {
        // scale the gray value into the range [0, 8]
        const double gray = 8*put_in_range(0, 1, (value - min_val)/(max_val-min_val));
        rgb_pixel pix;
        // s is the slope of color change
        const double s = 1.0/2.0;

        if (gray <= 1)
        {
            pix.red = 0;
            pix.green = 0;
            pix.blue = static_cast<unsigned char>((gray+1)*s*255 + 0.5);
        }
        else if (gray <= 3)
        {
            pix.red = 0;
            pix.green = static_cast<unsigned char>((gray-1)*s*255 + 0.5);
            pix.blue = 255;
        }
        else if (gray <= 5)
        {
            pix.red = static_cast<unsigned char>((gray-3)*s*255 + 0.5);
            pix.green = 255;
            pix.blue = static_cast<unsigned char>((5-gray)*s*255 + 0.5);
        }
        else if (gray <= 7)
        {
            pix.red = 255;
            pix.green = static_cast<unsigned char>((7-gray)*s*255 + 0.5);
            pix.blue = 0;
        }
        else
        {
            pix.red = static_cast<unsigned char>((9-gray)*s*255 + 0.5);
            pix.green = 0;
            pix.blue = 0;
        }

        return pix;
    }

// ----------------------------------------------------------------------------------------

    template <typename T>
    struct op_jet : does_not_alias
    {
        op_jet(
            const T& img_,
            const double max_val_,
            const double min_val_
            ) : img(img_), max_val(max_val_), min_val(min_val_){}

        const T& img;

        const double max_val;
        const double min_val;

        const static long cost = 7;
        const static long NR = 0;
        const static long NC = 0;
        typedef rgb_pixel type;
        typedef const rgb_pixel const_ret_type;
        typedef default_memory_manager mem_manager_type;
        typedef row_major_layout layout_type;

        const_ret_type apply (long r, long c ) const
        {
            return colormap_jet(get_pixel_intensity(mat(img)(r,c)), min_val, max_val);
        }

        long nr () const { return num_rows(img); }
        long nc () const { return num_columns(img); }
    };

    template <
        typename image_type
        >
    const matrix_op<op_jet<image_type> >
    jet (
        const image_type& img,
        double max_val,
        double min_val = 0
    )
    {
        typedef op_jet<image_type> op;
        return matrix_op<op>(op(img,max_val,min_val));
    }

    template <
        typename image_type
        >
    const matrix_op<op_jet<image_type> >
    jet (
        const image_type& img
    )
    {
        typedef op_jet<image_type> op;
        if (img.size() != 0)
            return matrix_op<op>(op(img,max(mat(img)),min(mat(img))));
        else
            return matrix_op<op>(op(img,0,0));
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_RANDOMLY_COlOR_IMAGE_Hh_


dlib C++ Library - draw.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_DRAW_IMAGe_
#define DLIB_DRAW_IMAGe_

#include "draw_abstract.h"
#include "../algs.h"
#include "../pixel.h"
#include "../matrix.h"
#include <cmath>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename image_type,
        typename pixel_type
        >
    void draw_line (
        long x1,
        long y1,
        long x2,
        long y2,
        image_type& c_,
        const pixel_type& val
    )
    {
        image_view<image_type> c(c_);
        if (x1 == x2)
        {
            // make sure y1 comes before y2
            if (y1 > y2)
                swap(y1,y2);

            if (x1 < 0 || x1 >= c.nc())
                return;

            // this is a vertical line
            for (long y = y1; y <= y2; ++y)
            {
                if (y < 0 || y >= c.nr())
                    continue;

                assign_pixel(c[y][x1], val);
            }
        }
        else if (y1 == y2)
        {

            // make sure x1 comes before x2
            if (x1 > x2)
                swap(x1,x2);

            if (y1 < 0 || y1 >= c.nr())
                return;

            // this is a horizontal line
            for (long x = x1; x <= x2; ++x)
            {
                if (x < 0 || x >= c.nc())
                    continue;

                assign_pixel(c[y1][x] , val);
            }
        }
        else
        {
            // This part is a little more complicated because we are going to perform alpha
            // blending so the diagonal lines look nice.
            const rectangle valid_area = get_rect(c);
            rgb_alpha_pixel alpha_pixel;
            assign_pixel(alpha_pixel, val);
            const unsigned char max_alpha = alpha_pixel.alpha;

            const long rise = (((long)y2) - ((long)y1));
            const long run = (((long)x2) - ((long)x1));
            if (std::abs(rise) < std::abs(run))
            {
                const double slope = ((double)rise)/run;

                double first, last;

                if (x1 > x2)
                {
                    first = std::max(x2,valid_area.left());
                    last = std::min(x1,valid_area.right());
                }
                else
                {
                    first = std::max(x1,valid_area.left());
                    last = std::min(x2,valid_area.right());
                }

                long y;
                long x;
                const double x1f = x1;
                const double y1f = y1;
                for (double i = first; i <= last; ++i)
                {
                    const double dy = slope*(i-x1f) + y1f;
                    const double dx = i;

                    y = static_cast<long>(dy);
                    x = static_cast<long>(dx);

                    if (y >= valid_area.top() && y <= valid_area.bottom())
                    {
                        alpha_pixel.alpha = static_cast<unsigned char>((1.0-(dy-y))*max_alpha);
                        assign_pixel(c[y][x], alpha_pixel);
                    }
                    if (y+1 >= valid_area.top() && y+1 <= valid_area.bottom())
                    {
                        alpha_pixel.alpha = static_cast<unsigned char>((dy-y)*max_alpha);
                        assign_pixel(c[y+1][x], alpha_pixel);
                    }
                }
            }
            else
            {
                const double slope = ((double)run)/rise;

                double first, last;

                if (y1 > y2)
                {
                    first = std::max(y2,valid_area.top());
                    last = std::min(y1,valid_area.bottom());
                }
                else
                {
                    first = std::max(y1,valid_area.top());
                    last = std::min(y2,valid_area.bottom());
                }

                long x;
                long y;
                const double x1f = x1;
                const double y1f = y1;
                for (double i = first; i <= last; ++i)
                {
                    const double dx = slope*(i-y1f) + x1f;
                    const double dy = i;

                    y = static_cast<long>(dy);
                    x = static_cast<long>(dx);

                    if (x >= valid_area.left() && x <= valid_area.right())
                    {
                        alpha_pixel.alpha = static_cast<unsigned char>((1.0-(dx-x))*max_alpha);
                        assign_pixel(c[y][x], alpha_pixel);
                    }
                    if (x+1 >= valid_area.left() && x+1 <= valid_area.right())
                    {
                        alpha_pixel.alpha = static_cast<unsigned char>((dx-x)*max_alpha);
                        assign_pixel(c[y][x+1], alpha_pixel);
                    }
                }
            }
        }

    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_type,
        typename pixel_type
        >
    void draw_line (
        image_type& c,
        const point& p1,
        const point& p2,
        const pixel_type& val
    )
    {
        draw_line(p1.x(),p1.y(),p2.x(),p2.y(),c,val);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_type,
        typename pixel_type
        >
    void draw_rectangle (
        image_type& c,
        const rectangle& rect,
        const pixel_type& val
    )
    {
        draw_line(c, rect.tl_corner(), rect.tr_corner(), val);
        draw_line(c, rect.bl_corner(), rect.br_corner(), val);
        draw_line(c, rect.tl_corner(), rect.bl_corner(), val);
        draw_line(c, rect.tr_corner(), rect.br_corner(), val);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_type,
        typename pixel_type
        >
    void draw_rectangle (
        image_type& c,
        const rectangle& rect,
        const pixel_type& val,
        unsigned int thickness
    )
    {
        for (unsigned int i = 0; i < thickness; ++i)
        {
            if ((i%2)==0)
                draw_rectangle(c,shrink_rect(rect,(i+1)/2),val);
            else
                draw_rectangle(c,grow_rect(rect,(i+1)/2),val);
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_type,
        typename pixel_type
        >
    void fill_rect (
        image_type& img_,
        const rectangle& rect,
        const pixel_type& pixel
    )
    {
        image_view<image_type> img(img_);
        rectangle area = rect.intersect(get_rect(img));

        for (long r = area.top(); r <= area.bottom(); ++r)
        {
            for (long c = area.left(); c <= area.right(); ++c)
            {
                assign_pixel(img[r][c], pixel);
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_array_type
        >
    matrix<typename image_traits<typename image_array_type::value_type>::pixel_type> tile_images (
        const image_array_type& images
    )
    {
        typedef typename image_traits<typename image_array_type::value_type>::pixel_type T;

        if (images.size() == 0)
            return matrix<T>();

        const unsigned long size_nc = square_root(images.size());
        const unsigned long size_nr = (size_nc*(size_nc-1)>=images.size())? size_nc-1 : size_nc;
        // Figure out the size we have to use for each chip in the big main image.  We will
        // use the largest dimensions seen across all the chips.
        long nr = 0;
        long nc = 0;
        for (unsigned long i = 0; i < images.size(); ++i)
        {
            nr = std::max(num_rows(images[i]), nr);
            nc = std::max(num_columns(images[i]), nc);
        }

        matrix<T> temp(size_nr*nr, size_nc*nc);
        T background_color;
        assign_pixel(background_color, 0);
        temp = background_color;
        unsigned long idx = 0;
        for (unsigned long r = 0; r < size_nr; ++r)
        {
            for (unsigned long c = 0; c < size_nc; ++c)
            {
                if (idx < images.size())
                {
                    set_subm(temp, r*nr, c*nc, nr, nc) = mat(images[idx]);
                }
                ++idx;
            }
        }
        return temp;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_type,
        typename pixel_type
        >
    void draw_solid_circle (
        image_type& img_,
        const dpoint& center_point,
        double radius,
        const pixel_type& pixel
    )
    {
        image_view<image_type> img(img_);
        using std::sqrt;
        const rectangle valid_area(get_rect(img));
        const double x = center_point.x();
        const double y = center_point.y();
        const point cp(center_point);
        if (radius > 1)
        {
            long first_x = static_cast<long>(x - radius + 0.5);
            long last_x = static_cast<long>(x + radius + 0.5);
            const double rs = radius*radius;

            // ensure that we only loop over the part of the x dimension that this
            // image contains.
            if (first_x < valid_area.left())
                first_x = valid_area.left();
            if (last_x > valid_area.right())
                last_x = valid_area.right();

            long top, bottom;

            top = static_cast<long>(sqrt(std::max(rs - (first_x-x-0.5)*(first_x-x-0.5),0.0))+0.5);
            top += y;
            long last = top;

            // draw the left half of the circle
            long middle = std::min(cp.x()-1,last_x);
            for (long i = first_x; i <= middle; ++i)
            {
                double a = i - x + 0.5;
                // find the top of the arc
                top = static_cast<long>(sqrt(std::max(rs - a*a,0.0))+0.5);
                top += y;
                long temp = top;

                while(top >= last)
                {
                    bottom = y - top + y;
                    draw_line(img_, point(i,top),point(i,bottom),pixel);
                    --top;
                }

                last = temp;
            }

            middle = std::max(cp.x(),first_x);
            top = static_cast<long>(sqrt(std::max(rs - (last_x-x+0.5)*(last_x-x+0.5),0.0))+0.5);
            top += y;
            last = top;
            // draw the right half of the circle
            for (long i = last_x; i >= middle; --i)
            {
                double a = i - x - 0.5;
                // find the top of the arc
                top = static_cast<long>(sqrt(std::max(rs - a*a,0.0))+0.5);
                top += y;
                long temp = top;

                while(top >= last)
                {
                    bottom = y - top + y;
                    draw_line(img_, point(i,top),point(i,bottom),pixel);
                    --top;
                }

                last = temp;
            }
        }
        else if (valid_area.contains(cp))
        {
            // For circles smaller than a pixel we will just alpha blend them in proportion
            // to how small they are.
            rgb_alpha_pixel temp;
            assign_pixel(temp, pixel);
            temp.alpha = static_cast<unsigned char>(255*radius + 0.5);
            assign_pixel(img[cp.y()][cp.x()], temp);
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_DRAW_IMAGe_


dlib C++ Library - edge_detector.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_EDGE_DETECTOr_
#define DLIB_EDGE_DETECTOr_

#include "edge_detector_abstract.h"
#include "../pixel.h"
#include "../array2d.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    inline char edge_orientation (
        const T& x_,
        const T& y_
    )
    {

        // if this is a perfectly horizontal gradient then return right away
        if (x_ == 0)
        {
            return '|';
        }
        else if (y_ == 0) // if this is a perfectly vertical gradient then return right away
        {
            return '-';
        }

        // Promote x so that when we multiply by 128 later we know overflow won't happen.
        typedef typename promote<T>::type type;
        type x = x_;
        type y = y_;

        if (x < 0)
        {
            x = -x;
            if (y < 0)
            {
                y = -y;
                x *= 128;
                const type temp = x/y;
                if (temp > 309)
                    return '-';
                else if (temp > 53)
                    return '/';
                else
                    return '|';
            }
            else
            {
                x *= 128;
                const type temp = x/y;
                if (temp > 309)
                    return '-';
                else if (temp > 53)
                    return '\\';
                else
                    return '|';
            }
        }
        else
        {
            if (y < 0)
            {
                y = -y;
                x *= 128;

                const type temp = x/y;
                if (temp > 309)
                    return '-';
                else if (temp > 53)
                    return '\\';
                else
                    return '|';
            }
            else
            {
                x *= 128;

                const type temp = x/y;
                if (temp > 309)
                    return '-';
                else if (temp > 53)
                    return '/';
                else
                    return '|';
            }
        }

    }

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type
        >
    void sobel_edge_detector (
        const in_image_type& in_img_,
        out_image_type& horz_,
        out_image_type& vert_
    )
    {
        typedef typename image_traits<out_image_type>::pixel_type pixel_type;
        COMPILE_TIME_ASSERT(pixel_traits<pixel_type>::is_unsigned == false);
        DLIB_ASSERT( !is_same_object(in_img_,horz_) && !is_same_object(in_img_,vert_) &&
                     !is_same_object(horz_,vert_),
            "\tvoid sobel_edge_detector(in_img_, horz_, vert_)"
            << "\n\t You can't give the same image as more than one argument"
            << "\n\t is_same_object(in_img_,horz_): " << is_same_object(in_img_,horz_)
            << "\n\t is_same_object(in_img_,vert_): " << is_same_object(in_img_,vert_)
            << "\n\t is_same_object(horz_,vert_):    " << is_same_object(horz_,vert_)
            );

        const int vert_filter[3][3] = {{-1,-2,-1},
        {0,0,0},
        {1,2,1}};
        const int horz_filter[3][3] = { {-1,0,1},
        {-2,0,2},
        {-1,0,1}};

        const long M = 3;
        const long N = 3;

        const_image_view<in_image_type> in_img(in_img_);
        image_view<out_image_type> horz(horz_);
        image_view<out_image_type> vert(vert_);

        horz.set_size(in_img.nr(),in_img.nc());
        vert.set_size(in_img.nr(),in_img.nc());

        assign_border_pixels(horz,1,1,0);
        assign_border_pixels(vert,1,1,0);

        // figure out the range that we should apply the filter to
        const long first_row = M/2;
        const long first_col = N/2;
        const long last_row = in_img.nr() - M/2;
        const long last_col = in_img.nc() - N/2;

        // apply the filter to the image
        for (long r = first_row; r < last_row; ++r)
        {
            for (long c = first_col; c < last_col; ++c)
            {
                typedef typename pixel_traits<typename image_traits<in_image_type>::pixel_type>::basic_pixel_type bp_type;

                typename promote<bp_type>::type p, horz_temp, vert_temp;
                horz_temp = 0;
                vert_temp = 0;
                for (long m = 0; m < M; ++m)
                {
                    for (long n = 0; n < N; ++n)
                    {
                        // pull out the current pixel and put it into p
                        p = get_pixel_intensity(in_img[r-M/2+m][c-N/2+n]);

                        horz_temp += p*horz_filter[m][n];
                        vert_temp += p*vert_filter[m][n];
                    }
                }

                assign_pixel(horz[r][c] , horz_temp);
                assign_pixel(vert[r][c] , vert_temp);

            }
        }
    }

// ----------------------------------------------------------------------------------------

    namespace impl
    {
        template <typename T>
        typename promote<T>::type square (const T& a)
        {
            return static_cast<T>(a)*static_cast<T>(a);
        }
    }

    template <
        typename in_image_type,
        typename out_image_type
        >
    void suppress_non_maximum_edges (
        const in_image_type& horz_,
        const in_image_type& vert_,
        out_image_type& out_img_
    )
    {
        const_image_view<in_image_type> horz(horz_);
        const_image_view<in_image_type> vert(vert_);
        image_view<out_image_type> out_img(out_img_);

        COMPILE_TIME_ASSERT(is_signed_type<typename image_traits<in_image_type>::pixel_type>::value);
        DLIB_ASSERT( horz.nr() == vert.nr() && horz.nc() == vert.nc(),
            "\tvoid suppress_non_maximum_edges(horz, vert, out_img)"
            << "\n\tYou have to give horz and vert gradient images that are the same size"
            << "\n\thorz.nr():   " << horz.nr()
            << "\n\thorz.nc():   " << horz.nc()
            << "\n\tvert.nr():   " << vert.nr()
            << "\n\tvert.nc():   " << vert.nc()
            );
        DLIB_ASSERT( !is_same_object(out_img_,horz_) && !is_same_object(out_img_,vert_),
            "\tvoid suppress_non_maximum_edges(horz_, vert_, out_img_)"
            << "\n\t out_img can't be the same as one of the input images."
            << "\n\t is_same_object(out_img_,horz_):    " << is_same_object(out_img_,horz_)
            << "\n\t is_same_object(out_img_,vert_):    " << is_same_object(out_img_,vert_)
            );

        using std::min;
        using std::abs;

        // if there isn't any input image then don't do anything
        if (horz.size() == 0)
        {
            out_img.clear();
            return;
        }

        out_img.set_size(horz.nr(),horz.nc());

        zero_border_pixels(out_img,1,1);

        // now do non maximum suppression while we copy the
        const long M = 3;
        const long N = 3;

        // figure out the range that we should apply the filter to
        const long first_row = M/2;
        const long first_col = N/2;
        const long last_row = horz.nr() - M/2;
        const long last_col = horz.nc() - N/2;

        // apply the filter to the image
        for (long r = first_row; r < last_row; ++r)
        {
            for (long c = first_col; c < last_col; ++c)
            {
                typedef typename promote<typename image_traits<in_image_type>::pixel_type>::type T;
                const T y = horz[r][c];
                const T x = vert[r][c];

                using impl::square;

                const T val = square(horz[r][c]) + square(vert[r][c]);

                const char ori = edge_orientation(x,y);
                const unsigned char zero = 0;
                switch (ori)
                {
                    case '-':
                        if (square(horz[r-1][c])+square(vert[r-1][c]) > val || square(horz[r+1][c]) + square(vert[r+1][c]) > val)
                            assign_pixel(out_img[r][c] , zero);
                        else
                            assign_pixel(out_img[r][c] , std::sqrt((double)val));
                        break;

                    case '|':
                        if (square(horz[r][c-1]) + square(vert[r][c-1]) > val || square(horz[r][c+1]) + square(vert[r][c+1]) > val)
                            assign_pixel(out_img[r][c] , zero);
                        else
                            assign_pixel(out_img[r][c] , std::sqrt((double)val));
                        break;

                    case '/':
                        if (square(horz[r-1][c-1]) + square(vert[r-1][c-1]) > val || square(horz[r+1][c+1]) + square(vert[r+1][c+1]) > val)
                            assign_pixel(out_img[r][c] , zero);
                        else
                            assign_pixel(out_img[r][c] , std::sqrt((double)val));
                        break;

                    case '\\':
                        if (square(horz[r+1][c-1]) + square(vert[r+1][c-1]) > val || square(horz[r-1][c+1]) + square(vert[r-1][c+1]) > val)
                            assign_pixel(out_img[r][c] , zero);
                        else
                            assign_pixel(out_img[r][c] , std::sqrt((double)val));
                        break;

                }
            }
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_EDGE_DETECTOr_


dlib C++ Library - equalize_histogram.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_EQUALIZE_HISTOGRAm_
#define DLIB_EQUALIZE_HISTOGRAm_

#include "../pixel.h"
#include "equalize_histogram_abstract.h"
#include <vector>
#include "../enable_if.h"
#include "../matrix.h"

namespace dlib
{

// ---------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        long R,
        long C,
        typename MM
        >
    void get_histogram (
        const in_image_type& in_img_,
        matrix<unsigned long,R,C,MM>& hist
    )
    {
        typedef typename image_traits<in_image_type>::pixel_type pixel_type;
        COMPILE_TIME_ASSERT( pixel_traits<pixel_type>::is_unsigned == true );

        typedef typename pixel_traits<pixel_type>::basic_pixel_type in_image_basic_pixel_type;
        COMPILE_TIME_ASSERT( sizeof(in_image_basic_pixel_type) <= 2);

        // make sure hist is the right size
        if (R == 1)
            hist.set_size(1,pixel_traits<pixel_type>::max()+1);
        else
            hist.set_size(pixel_traits<pixel_type>::max()+1,1);

        set_all_elements(hist,0);

        const_image_view<in_image_type> in_img(in_img_);
        // compute the histogram
        for (long r = 0; r < in_img.nr(); ++r)
        {
            for (long c = 0; c < in_img.nc(); ++c)
            {
                unsigned long p = get_pixel_intensity(in_img[r][c]);
                ++hist(p);
            }
        }
    }

// ---------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type
        >
    void equalize_histogram (
        const in_image_type& in_img_,
        out_image_type& out_img_
    )
    {
        const_image_view<in_image_type> in_img(in_img_);
        image_view<out_image_type> out_img(out_img_);

        typedef typename image_traits<in_image_type>::pixel_type in_pixel_type;
        typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;

        COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type>::has_alpha == false );
        COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::has_alpha == false );

        COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type>::is_unsigned == true );
        COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::is_unsigned == true );

        typedef typename pixel_traits<in_pixel_type>::basic_pixel_type in_image_basic_pixel_type;
        COMPILE_TIME_ASSERT( sizeof(in_image_basic_pixel_type) <= 2);

        // if there isn't any input image then don't do anything
        if (in_img.size() == 0)
        {
            out_img.clear();
            return;
        }

        out_img.set_size(in_img.nr(),in_img.nc());

        unsigned long p;

        matrix<unsigned long,1,0> histogram;
        get_histogram(in_img_, histogram);
        in_img = in_img_;

        double scale = pixel_traits<out_pixel_type>::max();
        if (in_img.size() > histogram(0))
            scale /= in_img.size()-histogram(0);
        else
            scale = 0;

        // make the black pixels remain black in the output image
        histogram(0) = 0;

        // compute the transform function
        for (long i = 1; i < histogram.size(); ++i)
            histogram(i) += histogram(i-1);
        // scale so that it is in the range [0,pixel_traits<out_pixel_type>::max()]
        for (long i = 0; i < histogram.size(); ++i)
            histogram(i) = static_cast<unsigned long>(histogram(i)*scale);

        // now do the transform
        for (long row = 0; row < in_img.nr(); ++row)
        {
            for (long col = 0; col < in_img.nc(); ++col)
            {
                p = histogram(get_pixel_intensity(in_img[row][col]));
                assign_pixel(out_img[row][col], in_img[row][col]);
                assign_pixel_intensity(out_img[row][col],p);
            }
        }

    }

    template <
        typename image_type
        >
    void equalize_histogram (
        image_type& img
    )
    {
        equalize_histogram(img,img);
    }

// ---------------------------------------------------------------------------------------

}

#endif // DLIB_EQUALIZE_HISTOGRAm_


dlib C++ Library - fhog.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_fHOG_Hh_
#define DLIB_fHOG_Hh_

#include "fhog_abstract.h"
#include "../matrix.h"
#include "../array2d.h"
#include "../array.h"
#include "../geometry.h"
#include "assign_image.h"
#include "draw.h"
#include "interpolation.h"
#include "../simd/simd4i.h"
#include "../simd/simd4f.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    namespace impl_fhog
    {
        template <typename image_type>
        inline typename dlib::enable_if_c<pixel_traits<typename image_type::pixel_type>::rgb>::type get_gradient (
            const int r,
            const int c,
            const image_type& img,
            matrix<double,2,1>& grad,
            double& len
        )
        {
            matrix<double,2,1> grad2, grad3;
            // get the red gradient
            grad(0) = (int)img[r][c+1].red-(int)img[r][c-1].red;
            grad(1) = (int)img[r+1][c].red-(int)img[r-1][c].red;
            len = length_squared(grad);

            // get the green gradient
            grad2(0) = (int)img[r][c+1].green-(int)img[r][c-1].green;
            grad2(1) = (int)img[r+1][c].green-(int)img[r-1][c].green;
            double v2 = length_squared(grad2);

            // get the blue gradient
            grad3(0) = (int)img[r][c+1].blue-(int)img[r][c-1].blue;
            grad3(1) = (int)img[r+1][c].blue-(int)img[r-1][c].blue;
            double v3 = length_squared(grad3);

            // pick color with strongest gradient
            if (v2 > len)
            {
                len = v2;
                grad = grad2;
            }
            if (v3 > len)
            {
                len = v3;
                grad = grad3;
            }
        }

        template <typename image_type>
        inline typename dlib::enable_if_c<pixel_traits<typename image_type::pixel_type>::rgb>::type get_gradient (
            const int r,
            const int c,
            const image_type& img,
            simd4f& grad_x,
            simd4f& grad_y,
            simd4f& len
        )
        {
            simd4i rleft((int)img[r][c-1].red,
                        (int)img[r][c].red,
                        (int)img[r][c+1].red,
                        (int)img[r][c+2].red);
            simd4i rright((int)img[r][c+1].red,
                         (int)img[r][c+2].red,
                         (int)img[r][c+3].red,
                         (int)img[r][c+4].red);
            simd4i rtop((int)img[r-1][c].red,
                       (int)img[r-1][c+1].red,
                       (int)img[r-1][c+2].red,
                       (int)img[r-1][c+3].red);
            simd4i rbottom((int)img[r+1][c].red,
                          (int)img[r+1][c+1].red,
                          (int)img[r+1][c+2].red,
                          (int)img[r+1][c+3].red);

            simd4i gleft((int)img[r][c-1].green,
                        (int)img[r][c].green,
                        (int)img[r][c+1].green,
                        (int)img[r][c+2].green);
            simd4i gright((int)img[r][c+1].green,
                         (int)img[r][c+2].green,
                         (int)img[r][c+3].green,
                         (int)img[r][c+4].green);
            simd4i gtop((int)img[r-1][c].green,
                       (int)img[r-1][c+1].green,
                       (int)img[r-1][c+2].green,
                       (int)img[r-1][c+3].green);
            simd4i gbottom((int)img[r+1][c].green,
                          (int)img[r+1][c+1].green,
                          (int)img[r+1][c+2].green,
                          (int)img[r+1][c+3].green);

            simd4i bleft((int)img[r][c-1].blue,
                        (int)img[r][c].blue,
                        (int)img[r][c+1].blue,
                        (int)img[r][c+2].blue);
            simd4i bright((int)img[r][c+1].blue,
                         (int)img[r][c+2].blue,
                         (int)img[r][c+3].blue,
                         (int)img[r][c+4].blue);
            simd4i btop((int)img[r-1][c].blue,
                       (int)img[r-1][c+1].blue,
                       (int)img[r-1][c+2].blue,
                       (int)img[r-1][c+3].blue);
            simd4i bbottom((int)img[r+1][c].blue,
                          (int)img[r+1][c+1].blue,
                          (int)img[r+1][c+2].blue,
                          (int)img[r+1][c+3].blue);

            simd4i grad_x_red   = rright-rleft;
            simd4i grad_y_red   = rbottom-rtop;
            simd4i grad_x_green = gright-gleft;
            simd4i grad_y_green = gbottom-gtop;
            simd4i grad_x_blue  = bright-bleft;
            simd4i grad_y_blue  = bbottom-btop;

            simd4i rlen = grad_x_red*grad_x_red + grad_y_red*grad_y_red;
            simd4i glen = grad_x_green*grad_x_green + grad_y_green*grad_y_green;
            simd4i blen = grad_x_blue*grad_x_blue + grad_y_blue*grad_y_blue;

            simd4i cmp = rlen>glen;
            simd4i tgrad_x = select(cmp,grad_x_red,grad_x_green);
            simd4i tgrad_y = select(cmp,grad_y_red,grad_y_green);
            simd4i tlen = select(cmp,rlen,glen);

            cmp = tlen>blen;
            grad_x = select(cmp,tgrad_x,grad_x_blue);
            grad_y = select(cmp,tgrad_y,grad_y_blue);
            len = select(cmp,tlen,blen);
        }

    // ------------------------------------------------------------------------------------

        template <typename image_type>
        inline typename dlib::disable_if_c<pixel_traits<typename image_type::pixel_type>::rgb>::type get_gradient (
            const int r,
            const int c,
            const image_type& img,
            matrix<double,2,1>& grad,
            double& len
        )
        {
            grad(0) = (int)get_pixel_intensity(img[r][c+1])-(int)get_pixel_intensity(img[r][c-1]);
            grad(1) = (int)get_pixel_intensity(img[r+1][c])-(int)get_pixel_intensity(img[r-1][c]);
            len = length_squared(grad);
        }

        template <typename image_type>
        inline typename dlib::disable_if_c<pixel_traits<typename image_type::pixel_type>::rgb>::type get_gradient (
            int r,
            int c,
            const image_type& img,
            simd4f& grad_x,
            simd4f& grad_y,
            simd4f& len
        )
        {
            simd4i left((int)get_pixel_intensity(img[r][c-1]),
                        (int)get_pixel_intensity(img[r][c]),
                        (int)get_pixel_intensity(img[r][c+1]),
                        (int)get_pixel_intensity(img[r][c+2]));
            simd4i right((int)get_pixel_intensity(img[r][c+1]),
                         (int)get_pixel_intensity(img[r][c+2]),
                         (int)get_pixel_intensity(img[r][c+3]),
                         (int)get_pixel_intensity(img[r][c+4]));

            simd4i top((int)get_pixel_intensity(img[r-1][c]),
                       (int)get_pixel_intensity(img[r-1][c+1]),
                       (int)get_pixel_intensity(img[r-1][c+2]),
                       (int)get_pixel_intensity(img[r-1][c+3]));
            simd4i bottom((int)get_pixel_intensity(img[r+1][c]),
                          (int)get_pixel_intensity(img[r+1][c+1]),
                          (int)get_pixel_intensity(img[r+1][c+2]),
                          (int)get_pixel_intensity(img[r+1][c+3]));

            grad_x = right-left;
            grad_y = bottom-top;

            len = (grad_x*grad_x + grad_y*grad_y);
        }

    // ------------------------------------------------------------------------------------

        template <typename T, typename mm1, typename mm2>
        inline void set_hog (
            dlib::array<array2d<T,mm1>,mm2>& hog,
            int o,
            int x,
            int y,
            const double& value
        )
        {
            hog[o][y][x] = value;
        }

        template <typename T, typename mm1, typename mm2>
        void init_hog (
            dlib::array<array2d<T,mm1>,mm2>& hog,
            int hog_nr,
            int hog_nc,
            int filter_rows_padding,
            int filter_cols_padding
        )
        {
            const int num_hog_bands = 27+4;
            hog.resize(num_hog_bands);
            for (int i = 0; i < num_hog_bands; ++i)
            {
                hog[i].set_size(hog_nr+filter_rows_padding-1, hog_nc+filter_cols_padding-1);
                rectangle rect = get_rect(hog[i]);
                rect.top() +=   (filter_rows_padding-1)/2;
                rect.left() +=  (filter_cols_padding-1)/2;
                rect.right() -= filter_cols_padding/2;
                rect.bottom() -= filter_rows_padding/2;
                zero_border_pixels(hog[i],rect);
            }
        }

        template <typename T, typename mm1, typename mm2>
        void init_hog_zero_everything (
            dlib::array<array2d<T,mm1>,mm2>& hog,
            int hog_nr,
            int hog_nc,
            int filter_rows_padding,
            int filter_cols_padding
        )
        {
            const int num_hog_bands = 27+4;
            hog.resize(num_hog_bands);
            for (int i = 0; i < num_hog_bands; ++i)
            {
                hog[i].set_size(hog_nr+filter_rows_padding-1, hog_nc+filter_cols_padding-1);
                assign_all_pixels(hog[i], 0);
            }
        }

    // ------------------------------------------------------------------------------------

        template <typename T, typename mm>
        inline void set_hog (
            array2d<matrix<T,31,1>,mm>& hog,
            int o,
            int x,
            int y,
            const double& value
        )
        {
            hog[y][x](o) = value;
        }

        template <typename T, typename mm>
        void init_hog (
            array2d<matrix<T,31,1>,mm>& hog,
            int hog_nr,
            int hog_nc,
            int filter_rows_padding,
            int filter_cols_padding
        )
        {
            hog.set_size(hog_nr+filter_rows_padding-1, hog_nc+filter_cols_padding-1);

            // now zero out the border region
            rectangle rect = get_rect(hog);
            rect.top() +=   (filter_rows_padding-1)/2;
            rect.left() +=  (filter_cols_padding-1)/2;
            rect.right() -= filter_cols_padding/2;
            rect.bottom() -= filter_rows_padding/2;
            border_enumerator be(get_rect(hog),rect);
            while (be.move_next())
            {
                const point p = be.element();
                set_all_elements(hog[p.y()][p.x()], 0);
            }
        }

        template <typename T, typename mm>
        void init_hog_zero_everything (
            array2d<matrix<T,31,1>,mm>& hog,
            int hog_nr,
            int hog_nc,
            int filter_rows_padding,
            int filter_cols_padding
        )
        {
            hog.set_size(hog_nr+filter_rows_padding-1, hog_nc+filter_cols_padding-1);

            for (long r = 0; r < hog.nr(); ++r)
            {
                for (long c = 0; c < hog.nc(); ++c)
                {
                    set_all_elements(hog[r][c], 0);
                }
            }
        }

    // ------------------------------------------------------------------------------------

        template <
            typename image_type,
            typename out_type
            >
        void impl_extract_fhog_features_cell_size_1(
            const image_type& img_,
            out_type& hog,
            int filter_rows_padding,
            int filter_cols_padding
        )
        {
            const_image_view<image_type> img(img_);
            // make sure requires clause is not broken
            DLIB_ASSERT( filter_rows_padding > 0 &&
                         filter_cols_padding > 0 ,
                "\t void extract_fhog_features()"
                << "\n\t Invalid inputs were given to this function. "
                << "\n\t filter_rows_padding: " << filter_rows_padding
                << "\n\t filter_cols_padding: " << filter_cols_padding
                );

            /*
                This function is an optimized version of impl_extract_fhog_features() for
                the case where cell_size == 1.
            */

            // unit vectors used to compute gradient orientation
            matrix<double,2,1> directions[9];
            directions[0] =  1.0000, 0.0000;
            directions[1] =  0.9397, 0.3420;
            directions[2] =  0.7660, 0.6428;
            directions[3] =  0.500,  0.8660;
            directions[4] =  0.1736, 0.9848;
            directions[5] = -0.1736, 0.9848;
            directions[6] = -0.5000, 0.8660;
            directions[7] = -0.7660, 0.6428;
            directions[8] = -0.9397, 0.3420;

            if (img.nr() <= 2 || img.nc() <= 2)
            {
                hog.clear();
                return;
            }

            array2d<unsigned char> angle(img.nr(), img.nc());

            array2d<float> norm(img.nr(), img.nc());
            zero_border_pixels(norm,1,1);

            // memory for HOG features
            const long hog_nr = img.nr()-2;
            const long hog_nc = img.nc()-2;

            const int padding_rows_offset = (filter_rows_padding-1)/2;
            const int padding_cols_offset = (filter_cols_padding-1)/2;
            init_hog_zero_everything(hog, hog_nr, hog_nc, filter_rows_padding, filter_cols_padding);

            const int visible_nr = img.nr()-1;
            const int visible_nc = img.nc()-1;

            // First populate the gradient histograms
            for (int y = 1; y < visible_nr; y++)
            {
                int x;
                for (x = 1; x < visible_nc-3; x+=4)
                {
                    // v will be the length of the gradient vectors.
                    simd4f grad_x, grad_y, v;
                    get_gradient(y,x,img,grad_x,grad_y,v);

                    float _vv[4];
                    v.store(_vv);

                    // Now snap the gradient to one of 18 orientations
                    simd4f best_dot = 0;
                    simd4f best_o = 0;
                    for (int o = 0; o < 9; o++)
                    {
                        simd4f dot = grad_x*directions[o](0) + grad_y*directions[o](1);
                        simd4f_bool cmp = dot>best_dot;
                        best_dot = select(cmp,dot,best_dot);
                        dot *= -1;
                        best_o = select(cmp,o,best_o);

                        cmp = dot>best_dot;
                        best_dot = select(cmp,dot,best_dot);
                        best_o = select(cmp,o+9,best_o);
                    }

                    int32 _best_o[4]; simd4i(best_o).store(_best_o);

                    norm[y][x+0] = _vv[0];
                    norm[y][x+1] = _vv[1];
                    norm[y][x+2] = _vv[2];
                    norm[y][x+3] = _vv[3];

                    angle[y][x+0] = _best_o[0];
                    angle[y][x+1] = _best_o[1];
                    angle[y][x+2] = _best_o[2];
                    angle[y][x+3] = _best_o[3];

                }
                // Now process the right columns that don't fit into simd registers.
                for (; x < visible_nc; x++)
                {
                    matrix<double,2,1> grad;
                    double v;
                    get_gradient(y,x,img,grad,v);

                    // snap to one of 18 orientations
                    double best_dot = 0;
                    int best_o = 0;
                    for (int o = 0; o < 9; o++)
                    {
                        const double dot = dlib::dot(directions[o], grad);
                        if (dot > best_dot)
                        {
                            best_dot = dot;
                            best_o = o;
                        }
                        else if (-dot > best_dot)
                        {
                            best_dot = -dot;
                            best_o = o+9;
                        }
                    }

                    norm[y][x] = v;
                    angle[y][x] = best_o;
                }
            }

            const double eps = 0.0001;
            // compute features
            for (int y = 0; y < hog_nr; y++)
            {
                const int yy = y+padding_rows_offset;
                for (int x = 0; x < hog_nc; x++)
                {
                    const simd4f z1(norm[y+1][x+1],
                                    norm[y][x+1],
                                    norm[y+1][x],
                                    norm[y][x]);

                    const simd4f z2(norm[y+1][x+2],
                                    norm[y][x+2],
                                    norm[y+1][x+1],
                                    norm[y][x+1]);

                    const simd4f z3(norm[y+2][x+1],
                                    norm[y+1][x+1],
                                    norm[y+2][x],
                                    norm[y+1][x]);

                    const simd4f z4(norm[y+2][x+2],
                                    norm[y+1][x+2],
                                    norm[y+2][x+1],
                                    norm[y+1][x+1]);

                    const simd4f temp0 = std::sqrt(norm[y+1][x+1]);
                    const simd4f nn = 0.2*sqrt(z1+z2+z3+z4+eps);
                    const simd4f n = 0.1/nn;

                    simd4f t = 0;

                    const int xx = x+padding_cols_offset;

                    simd4f h0 = min(temp0,nn)*n;
                    const float vv = sum(h0);
                    set_hog(hog,angle[y+1][x+1],xx,yy,   vv);
                    t += h0;

                    t *= 2*0.2357;

                    // contrast-insensitive features
                    set_hog(hog,angle[y+1][x+1]%9+18,xx,yy, vv);

                    float temp[4];
                    t.store(temp);

                    // texture features
                    set_hog(hog,27,xx,yy, temp[0]);
                    set_hog(hog,28,xx,yy, temp[1]);
                    set_hog(hog,29,xx,yy, temp[2]);
                    set_hog(hog,30,xx,yy, temp[3]);
                }
            }
        }

    // ------------------------------------------------------------------------------------

        template <
            typename image_type,
            typename out_type
            >
        void impl_extract_fhog_features(
            const image_type& img_,
            out_type& hog,
            int cell_size,
            int filter_rows_padding,
            int filter_cols_padding
        )
        {
            const_image_view<image_type> img(img_);
            // make sure requires clause is not broken
            DLIB_ASSERT( cell_size > 0 &&
                         filter_rows_padding > 0 &&
                         filter_cols_padding > 0 ,
                "\t void extract_fhog_features()"
                << "\n\t Invalid inputs were given to this function. "
                << "\n\t cell_size: " << cell_size
                << "\n\t filter_rows_padding: " << filter_rows_padding
                << "\n\t filter_cols_padding: " << filter_cols_padding
                );

            /*
                This function implements the HOG feature extraction method described in
                the paper:
                    P. Felzenszwalb, R. Girshick, D. McAllester, D. Ramanan
                    Object Detection with Discriminatively Trained Part Based Models
                    IEEE Transactions on Pattern Analysis and Machine Intelligence, Vol. 32, No. 9, Sep. 2010

                Moreover, this function is derived from the HOG feature extraction code
                from the features.cc file in the voc-releaseX code (see
                http://people.cs.uchicago.edu/~rbg/latent/) which is has the following
                license (note that the code has been modified to work with grayscale and
                color as well as planar and interlaced input and output formats):

                Copyright (C) 2011, 2012 Ross Girshick, Pedro Felzenszwalb
                Copyright (C) 2008, 2009, 2010 Pedro Felzenszwalb, Ross Girshick
                Copyright (C) 2007 Pedro Felzenszwalb, Deva Ramanan

                Permission is hereby granted, free of charge, to any person obtaining
                a copy of this software and associated documentation files (the
                "Software"), to deal in the Software without restriction, including
                without limitation the rights to use, copy, modify, merge, publish,
                distribute, sublicense, and/or sell copies of the Software, and to
                permit persons to whom the Software is furnished to do so, subject to
                the following conditions:

                The above copyright notice and this permission notice shall be
                included in all copies or substantial portions of the Software.

                THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
                EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
                MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
                NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
                LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
                OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
                WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
            */

            if (cell_size == 1)
            {
                impl_extract_fhog_features_cell_size_1(img_,hog,filter_rows_padding,filter_cols_padding);
                return;
            }

            // unit vectors used to compute gradient orientation
            matrix<double,2,1> directions[9];
            directions[0] =  1.0000, 0.0000;
            directions[1] =  0.9397, 0.3420;
            directions[2] =  0.7660, 0.6428;
            directions[3] =  0.500,  0.8660;
            directions[4] =  0.1736, 0.9848;
            directions[5] = -0.1736, 0.9848;
            directions[6] = -0.5000, 0.8660;
            directions[7] = -0.7660, 0.6428;
            directions[8] = -0.9397, 0.3420;

            // First we allocate memory for caching orientation histograms & their norms.
            const int cells_nr = (int)((double)img.nr()/(double)cell_size + 0.5);
            const int cells_nc = (int)((double)img.nc()/(double)cell_size + 0.5);

            if (cells_nr == 0 || cells_nc == 0)
            {
                hog.clear();
                return;
            }

            // We give hist extra padding around the edges (1 cell all the way around the
            // edge) so we can avoid needing to do boundary checks when indexing into it
            // later on.  So some statements assign to the boundary but those values are
            // never used.
            array2d<matrix<float,18,1> > hist(cells_nr+2, cells_nc+2);
            for (long r = 0; r < hist.nr(); ++r)
            {
                for (long c = 0; c < hist.nc(); ++c)
                {
                    hist[r][c] = 0;
                }
            }

            array2d<float> norm(cells_nr, cells_nc);
            assign_all_pixels(norm, 0);

            // memory for HOG features
            const int hog_nr = std::max(cells_nr-2, 0);
            const int hog_nc = std::max(cells_nc-2, 0);
            if (hog_nr == 0 || hog_nc == 0)
            {
                hog.clear();
                return;
            }
            const int padding_rows_offset = (filter_rows_padding-1)/2;
            const int padding_cols_offset = (filter_cols_padding-1)/2;
            init_hog(hog, hog_nr, hog_nc, filter_rows_padding, filter_cols_padding);

            const int visible_nr = std::min((long)cells_nr*cell_size,img.nr())-1;
            const int visible_nc = std::min((long)cells_nc*cell_size,img.nc())-1;

            // First populate the gradient histograms
            for (int y = 1; y < visible_nr; y++)
            {
                const double yp = ((double)y+0.5)/(double)cell_size - 0.5;
                const int iyp = (int)std::floor(yp);
                const double vy0 = yp-iyp;
                const double vy1 = 1.0-vy0;
                int x;
                for (x = 1; x < visible_nc-3; x+=4)
                {
                    simd4f xx(x,x+1,x+2,x+3);
                    // v will be the length of the gradient vectors.
                    simd4f grad_x, grad_y, v;
                    get_gradient(y,x,img,grad_x,grad_y,v);

                    // We will use bilinear interpolation to add into the histogram bins.
                    // So first we precompute the values needed to determine how much each
                    // pixel votes into each bin.
                    simd4f xp = (xx+0.5)/(float)cell_size + 0.5;
                    simd4i ixp = simd4i(xp);
                    simd4f vx0 = xp-ixp;
                    simd4f vx1 = 1.0f-vx0;

                    v = sqrt(v);

                    // Now snap the gradient to one of 18 orientations
                    simd4f best_dot = 0;
                    simd4f best_o = 0;
                    for (int o = 0; o < 9; o++)
                    {
                        simd4f dot = grad_x*directions[o](0) + grad_y*directions[o](1);
                        simd4f_bool cmp = dot>best_dot;
                        best_dot = select(cmp,dot,best_dot);
                        dot *= -1;
                        best_o = select(cmp,o,best_o);

                        cmp = dot>best_dot;
                        best_dot = select(cmp,dot,best_dot);
                        best_o = select(cmp,o+9,best_o);
                    }

                    // Add the gradient magnitude, v, to 4 histograms around pixel using
                    // bilinear interpolation.
                    vx1 *= v;
                    vx0 *= v;
                    // The amounts for each bin
                    simd4f v11 = vy1*vx1;
                    simd4f v01 = vy0*vx1;
                    simd4f v10 = vy1*vx0;
                    simd4f v00 = vy0*vx0;

                    int32 _best_o[4]; simd4i(best_o).store(_best_o);
                    int32 _ixp[4];    ixp.store(_ixp);
                    float _v11[4];    v11.store(_v11);
                    float _v01[4];    v01.store(_v01);
                    float _v10[4];    v10.store(_v10);
                    float _v00[4];    v00.store(_v00);

                    hist[iyp+1]  [_ixp[0]  ](_best_o[0]) += _v11[0];
                    hist[iyp+1+1][_ixp[0]  ](_best_o[0]) += _v01[0];
                    hist[iyp+1]  [_ixp[0]+1](_best_o[0]) += _v10[0];
                    hist[iyp+1+1][_ixp[0]+1](_best_o[0]) += _v00[0];

                    hist[iyp+1]  [_ixp[1]  ](_best_o[1]) += _v11[1];
                    hist[iyp+1+1][_ixp[1]  ](_best_o[1]) += _v01[1];
                    hist[iyp+1]  [_ixp[1]+1](_best_o[1]) += _v10[1];
                    hist[iyp+1+1][_ixp[1]+1](_best_o[1]) += _v00[1];

                    hist[iyp+1]  [_ixp[2]  ](_best_o[2]) += _v11[2];
                    hist[iyp+1+1][_ixp[2]  ](_best_o[2]) += _v01[2];
                    hist[iyp+1]  [_ixp[2]+1](_best_o[2]) += _v10[2];
                    hist[iyp+1+1][_ixp[2]+1](_best_o[2]) += _v00[2];

                    hist[iyp+1]  [_ixp[3]  ](_best_o[3]) += _v11[3];
                    hist[iyp+1+1][_ixp[3]  ](_best_o[3]) += _v01[3];
                    hist[iyp+1]  [_ixp[3]+1](_best_o[3]) += _v10[3];
                    hist[iyp+1+1][_ixp[3]+1](_best_o[3]) += _v00[3];
                }
                // Now process the right columns that don't fit into simd registers.
                for (; x < visible_nc; x++)
                {
                    matrix<double,2,1> grad;
                    double v;
                    get_gradient(y,x,img,grad,v);

                    // snap to one of 18 orientations
                    double best_dot = 0;
                    int best_o = 0;
                    for (int o = 0; o < 9; o++)
                    {
                        const double dot = dlib::dot(directions[o], grad);
                        if (dot > best_dot)
                        {
                            best_dot = dot;
                            best_o = o;
                        }
                        else if (-dot > best_dot)
                        {
                            best_dot = -dot;
                            best_o = o+9;
                        }
                    }

                    v = std::sqrt(v);
                    // add to 4 histograms around pixel using bilinear interpolation
                    const double xp = ((double)x+0.5)/(double)cell_size - 0.5;
                    const int ixp = (int)std::floor(xp);
                    const double vx0 = xp-ixp;
                    const double vx1 = 1.0-vx0;

                    hist[iyp+1][ixp+1](best_o) += vy1*vx1*v;
                    hist[iyp+1+1][ixp+1](best_o) += vy0*vx1*v;
                    hist[iyp+1][ixp+1+1](best_o) += vy1*vx0*v;
                    hist[iyp+1+1][ixp+1+1](best_o) += vy0*vx0*v;
                }
            }

            // compute energy in each block by summing over orientations
            for (int r = 0; r < cells_nr; ++r)
            {
                for (int c = 0; c < cells_nc; ++c)
                {
                    for (int o = 0; o < 9; o++)
                    {
                        norm[r][c] += (hist[r+1][c+1](o) + hist[r+1][c+1](o+9)) * (hist[r+1][c+1](o) + hist[r+1][c+1](o+9));
                    }
                }
            }

            const double eps = 0.0001;
            // compute features
            for (int y = 0; y < hog_nr; y++)
            {
                const int yy = y+padding_rows_offset;
                for (int x = 0; x < hog_nc; x++)
                {
                    const simd4f z1(norm[y+1][x+1],
                                    norm[y][x+1],
                                    norm[y+1][x],
                                    norm[y][x]);

                    const simd4f z2(norm[y+1][x+2],
                                    norm[y][x+2],
                                    norm[y+1][x+1],
                                    norm[y][x+1]);

                    const simd4f z3(norm[y+2][x+1],
                                    norm[y+1][x+1],
                                    norm[y+2][x],
                                    norm[y+1][x]);

                    const simd4f z4(norm[y+2][x+2],
                                    norm[y+1][x+2],
                                    norm[y+2][x+1],
                                    norm[y+1][x+1]);

                    const simd4f nn = 0.2*sqrt(z1+z2+z3+z4+eps);
                    const simd4f n = 0.1/nn;

                    simd4f t = 0;

                    const int xx = x+padding_cols_offset;

                    // contrast-sensitive features
                    for (int o = 0; o < 18; o+=3)
                    {
                        simd4f temp0(hist[y+1+1][x+1+1](o));
                        simd4f temp1(hist[y+1+1][x+1+1](o+1));
                        simd4f temp2(hist[y+1+1][x+1+1](o+2));
                        simd4f h0 = min(temp0,nn)*n;
                        simd4f h1 = min(temp1,nn)*n;
                        simd4f h2 = min(temp2,nn)*n;
                        set_hog(hog,o,xx,yy,   sum(h0));
                        set_hog(hog,o+1,xx,yy, sum(h1));
                        set_hog(hog,o+2,xx,yy, sum(h2));
                        t += h0+h1+h2;
                    }

                    t *= 2*0.2357;

                    // contrast-insensitive features
                    for (int o = 0; o < 9; o+=3)
                    {
                        simd4f temp0 = hist[y+1+1][x+1+1](o)   + hist[y+1+1][x+1+1](o+9);
                        simd4f temp1 = hist[y+1+1][x+1+1](o+1) + hist[y+1+1][x+1+1](o+9+1);
                        simd4f temp2 = hist[y+1+1][x+1+1](o+2) + hist[y+1+1][x+1+1](o+9+2);
                        simd4f h0 = min(temp0,nn)*n;
                        simd4f h1 = min(temp1,nn)*n;
                        simd4f h2 = min(temp2,nn)*n;
                        set_hog(hog,o+18,xx,yy, sum(h0));
                        set_hog(hog,o+18+1,xx,yy, sum(h1));
                        set_hog(hog,o+18+2,xx,yy, sum(h2));
                    }

                    float temp[4];
                    t.store(temp);

                    // texture features
                    set_hog(hog,27,xx,yy, temp[0]);
                    set_hog(hog,28,xx,yy, temp[1]);
                    set_hog(hog,29,xx,yy, temp[2]);
                    set_hog(hog,30,xx,yy, temp[3]);
                }
            }
        }

    // ------------------------------------------------------------------------------------

        inline void create_fhog_bar_images (
            dlib::array<matrix<float> >& mbars,
            const long w
        )
        {
            const long bdims = 9;
            // Make the oriented lines we use to draw on each HOG cell.
            mbars.resize(bdims);
            dlib::array<array2d<unsigned char> > bars(bdims);
            array2d<unsigned char> temp(w,w);
            for (unsigned long i = 0; i < bars.size(); ++i)
            {
                assign_all_pixels(temp, 0);
                draw_line(temp, point(w/2,0), point(w/2,w-1), 255);
                rotate_image(temp, bars[i], i*-pi/bars.size());

                mbars[i] = subm(matrix_cast<float>(mat(bars[i])), centered_rect(get_rect(bars[i]),w,w) );
            }
        }

    } // end namespace impl_fhog

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename image_type,
        typename T,
        typename mm1,
        typename mm2
        >
    void extract_fhog_features(
        const image_type& img,
        dlib::array<array2d<T,mm1>,mm2>& hog,
        int cell_size = 8,
        int filter_rows_padding = 1,
        int filter_cols_padding = 1
    )
    {
        impl_fhog::impl_extract_fhog_features(img, hog, cell_size, filter_rows_padding, filter_cols_padding);
        // If the image is too small then the above function outputs an empty feature map.
        // But to make things very uniform in usage we require the output to still have the
        // 31 planes (but they are just empty).
        if (hog.size() == 0)
            hog.resize(31);
    }

    template <
        typename image_type,
        typename T,
        typename mm
        >
    void extract_fhog_features(
        const image_type& img,
        array2d<matrix<T,31,1>,mm>& hog,
        int cell_size = 8,
        int filter_rows_padding = 1,
        int filter_cols_padding = 1
    )
    {
        impl_fhog::impl_extract_fhog_features(img, hog, cell_size, filter_rows_padding, filter_cols_padding);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_type,
        typename T
        >
    void extract_fhog_features(
        const image_type& img,
        matrix<T,0,1>& feats,
        int cell_size = 8,
        int filter_rows_padding = 1,
        int filter_cols_padding = 1
    )
    {
        dlib::array<array2d<T> > hog;
        extract_fhog_features(img, hog, cell_size, filter_rows_padding, filter_cols_padding);
        feats.set_size(hog.size()*hog[0].size());
        for (unsigned long i = 0; i < hog.size(); ++i)
        {
            const long size = hog[i].size();
            set_rowm(feats, range(i*size, (i+1)*size-1)) = reshape_to_column_vector(mat(hog[i]));
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    matrix<double,0,1> extract_fhog_features(
        const image_type& img,
        int cell_size = 8,
        int filter_rows_padding = 1,
        int filter_cols_padding = 1
    )
    {
        matrix<double,0,1> feats;
        extract_fhog_features(img, feats, cell_size, filter_rows_padding, filter_cols_padding);
        return feats;
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    inline point image_to_fhog (
        point p,
        int cell_size = 8,
        int filter_rows_padding = 1,
        int filter_cols_padding = 1
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( cell_size > 0 &&
            filter_rows_padding > 0 &&
            filter_cols_padding > 0 ,
            "\t point image_to_fhog()"
            << "\n\t Invalid inputs were given to this function. "
            << "\n\t cell_size: " << cell_size
            << "\n\t filter_rows_padding: " << filter_rows_padding
            << "\n\t filter_cols_padding: " << filter_cols_padding
        );

        // There is a one pixel border around the image.
        p -= point(1,1);
        // There is also a 1 "cell" border around the HOG image formation.
        return p/cell_size - point(1,1) + point((filter_cols_padding-1)/2,(filter_rows_padding-1)/2);
    }

// ----------------------------------------------------------------------------------------

    inline rectangle image_to_fhog (
        const rectangle& rect,
        int cell_size = 8,
        int filter_rows_padding = 1,
        int filter_cols_padding = 1
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( cell_size > 0 &&
            filter_rows_padding > 0 &&
            filter_cols_padding > 0 ,
            "\t rectangle image_to_fhog()"
            << "\n\t Invalid inputs were given to this function. "
            << "\n\t cell_size: " << cell_size
            << "\n\t filter_rows_padding: " << filter_rows_padding
            << "\n\t filter_cols_padding: " << filter_cols_padding
        );

        return rectangle(image_to_fhog(rect.tl_corner(),cell_size,filter_rows_padding,filter_cols_padding),
                         image_to_fhog(rect.br_corner(),cell_size,filter_rows_padding,filter_cols_padding));
    }

// ----------------------------------------------------------------------------------------

    inline point fhog_to_image (
        point p,
        int cell_size = 8,
        int filter_rows_padding = 1,
        int filter_cols_padding = 1
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( cell_size > 0 &&
            filter_rows_padding > 0 &&
            filter_cols_padding > 0 ,
            "\t point fhog_to_image()"
            << "\n\t Invalid inputs were given to this function. "
            << "\n\t cell_size: " << cell_size
            << "\n\t filter_rows_padding: " << filter_rows_padding
            << "\n\t filter_cols_padding: " << filter_cols_padding
        );

        // Convert to image space and then set to the center of the cell.
        point offset;

        p = (p+point(1,1)-point((filter_cols_padding-1)/2,(filter_rows_padding-1)/2))*cell_size + point(1,1);
        if (p.x() >= 0 && p.y() >= 0) offset = point(cell_size/2,cell_size/2);
        if (p.x() <  0 && p.y() >= 0) offset = point(-cell_size/2,cell_size/2);
        if (p.x() >= 0 && p.y() <  0) offset = point(cell_size/2,-cell_size/2);
        if (p.x() <  0 && p.y() <  0) offset = point(-cell_size/2,-cell_size/2);
        return p + offset;
    }

// ----------------------------------------------------------------------------------------

    inline rectangle fhog_to_image (
        const rectangle& rect,
        int cell_size = 8,
        int filter_rows_padding = 1,
        int filter_cols_padding = 1
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( cell_size > 0 &&
            filter_rows_padding > 0 &&
            filter_cols_padding > 0 ,
            "\t rectangle fhog_to_image()"
            << "\n\t Invalid inputs were given to this function. "
            << "\n\t cell_size: " << cell_size
            << "\n\t filter_rows_padding: " << filter_rows_padding
            << "\n\t filter_cols_padding: " << filter_cols_padding
        );

        return rectangle(fhog_to_image(rect.tl_corner(),cell_size,filter_rows_padding,filter_cols_padding),
                         fhog_to_image(rect.br_corner(),cell_size,filter_rows_padding,filter_cols_padding));
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mm1,
        typename mm2
        >
    matrix<unsigned char> draw_fhog(
        const dlib::array<array2d<T,mm1>,mm2>& hog,
        const long cell_draw_size = 15
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( cell_draw_size > 0 && hog.size()==31,
            "\t matrix<unsigned char> draw_fhog()"
            << "\n\t Invalid inputs were given to this function. "
            << "\n\t cell_draw_size: " << cell_draw_size
            << "\n\t hog.size(): " << hog.size()
        );

        dlib::array<matrix<float> > mbars;
        impl_fhog::create_fhog_bar_images(mbars,cell_draw_size);

        // now draw the bars onto the HOG cells
        matrix<float> himg(hog[0].nr()*cell_draw_size, hog[0].nc()*cell_draw_size);
        himg = 0;
        for (unsigned long d = 0; d < mbars.size(); ++d)
        {
            for (long r = 0; r < himg.nr(); r+=cell_draw_size)
            {
                for (long c = 0; c < himg.nc(); c+=cell_draw_size)
                {
                    const float val = hog[d][r/cell_draw_size][c/cell_draw_size] +
                        hog[d+mbars.size()][r/cell_draw_size][c/cell_draw_size] +
                        hog[d+mbars.size()*2][r/cell_draw_size][c/cell_draw_size];
                    if (val > 0)
                    {
                        set_subm(himg, r, c, cell_draw_size, cell_draw_size) += val*mbars[d%mbars.size()];
                    }
                }
            }
        }

        const double thresh = mean(himg) + 4*stddev(himg);
        if (thresh != 0)
            return matrix_cast<unsigned char>(upperbound(round(himg*255/thresh),255));
        else
            return matrix_cast<unsigned char>(himg);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    matrix<unsigned char> draw_fhog (
        const std::vector<matrix<T> >& hog,
        const long cell_draw_size = 15
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( cell_draw_size > 0 && hog.size()==31,
            "\t matrix<unsigned char> draw_fhog()"
            << "\n\t Invalid inputs were given to this function. "
            << "\n\t cell_draw_size: " << cell_draw_size
            << "\n\t hog.size(): " << hog.size()
        );

        // Just convert the input into the right object and then call the above draw_fhog()
        // function on it.
        dlib::array<array2d<T> > temp(hog.size());
        for (unsigned long i = 0; i < temp.size(); ++i)
        {
            temp[i].set_size(hog[i].nr(), hog[i].nc());
            for (long r = 0; r < hog[i].nr(); ++r)
            {
                for (long c = 0; c < hog[i].nc(); ++c)
                {
                    temp[i][r][c] = hog[i](r,c);
                }
            }
        }
        return draw_fhog(temp,cell_draw_size);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mm
        >
    matrix<unsigned char> draw_fhog(
        const array2d<matrix<T,31,1>,mm>& hog,
        const long cell_draw_size = 15
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( cell_draw_size > 0,
            "\t matrix<unsigned char> draw_fhog()"
            << "\n\t Invalid inputs were given to this function. "
            << "\n\t cell_draw_size: " << cell_draw_size
        );

        dlib::array<matrix<float> > mbars;
        impl_fhog::create_fhog_bar_images(mbars,cell_draw_size);

        // now draw the bars onto the HOG cells
        matrix<float> himg(hog.nr()*cell_draw_size, hog.nc()*cell_draw_size);
        himg = 0;
        for (unsigned long d = 0; d < mbars.size(); ++d)
        {
            for (long r = 0; r < himg.nr(); r+=cell_draw_size)
            {
                for (long c = 0; c < himg.nc(); c+=cell_draw_size)
                {
                    const float val = hog[r/cell_draw_size][c/cell_draw_size](d) +
                        hog[r/cell_draw_size][c/cell_draw_size](d+mbars.size()) +
                        hog[r/cell_draw_size][c/cell_draw_size](d+mbars.size()*2);
                    if (val > 0)
                    {
                        set_subm(himg, r, c, cell_draw_size, cell_draw_size) += val*mbars[d%mbars.size()];
                    }
                }
            }
        }

        const double thresh = mean(himg) + 4*stddev(himg);
        if (thresh != 0)
            return matrix_cast<unsigned char>(upperbound(round(himg*255/thresh),255));
        else
            return matrix_cast<unsigned char>(himg);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_fHOG_Hh_


dlib C++ Library - hough_transform.h

// Copyright (C) 2014  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_HOUGH_tRANSFORM_Hh_
#define DLIB_HOUGH_tRANSFORM_Hh_

#include "hough_transform_abstract.h"
#include "../image_processing/generic_image.h"
#include "../geometry.h"
#include "../algs.h"
#include "assign_image.h"
#include <limits>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class hough_transform
    {

    public:
        explicit hough_transform (
            unsigned long size_
        ) : _size(size_)
        {
            DLIB_CASSERT(size_ > 0,
                "\t hough_transform::hough_transform(size_)"
                << "\n\t Invalid arguments given to this function."
                );

            even_size = _size - (_size%2);

            const point cent = center(rectangle(0,0,size_-1,size_-1));
            xcos_theta.set_size(size_, size_);
            ysin_theta.set_size(size_, size_);

            std::vector<double> cos_theta(size_), sin_theta(size_);
            const double scale = 1<<16;
            for (unsigned long t = 0; t < size_; ++t)
            {
                double theta = t*pi/even_size;

                cos_theta[t] = scale*std::cos(theta)/sqrt_2;
                sin_theta[t] = scale*std::sin(theta)/sqrt_2;
            }
            const double offset = scale*even_size/4.0 + 0.5;

            for (unsigned long c = 0; c < size_; ++c)
            {
                const long x = c - cent.x();
                for (unsigned long t = 0; t < size_; ++t)
                    xcos_theta(c,t) = static_cast<int32>(x*cos_theta[t] + offset);
            }
            for (unsigned long r = 0; r < size_; ++r)
            {
                const long y = r - cent.y();
                for (unsigned long t = 0; t < size_; ++t)
                    ysin_theta(r,t) = static_cast<int32>(y*sin_theta[t] + offset);
            }
        }

        unsigned long size(
        ) const { return _size; }

        long nr(
        ) const { return _size; }

        long nc(
        ) const { return _size; }

        std::pair<point, point> get_line (
            const point& p
        ) const
        {
            DLIB_ASSERT(rectangle(0,0,size()-1,size()-1).contains(p) == true,
                "\t pair<point,point> hough_transform::get_line(point)"
                << "\n\t Invalid arguments given to this function."
                << "\n\t p:      " << p
                << "\n\t size(): " << size()
                );

            // First we compute the radius measured in pixels from the center and the theta
            // angle in radians.
            typedef dlib::vector<double,2> vect;
            const rectangle box(0,0,size()-1,size()-1);
            const vect cent = center(box);
            double theta = p.x()-cent.x();
            double radius = p.y()-cent.y();
            theta = theta*pi/even_size;
            radius = radius*sqrt_2 + 0.5;

            // now make a line segment on the line.
            vect v1 = cent + vect(size()+1000,0) + vect(0,radius);
            vect v2 = cent - vect(size()+1000,0) + vect(0,radius);
            point p1 = rotate_point(cent, v1, theta);
            point p2 = rotate_point(cent, v2, theta);

            clip_line_to_rectangle(box, p1, p2);

            return std::make_pair(p1,p2);
        }

        template <
            typename image_type
            >
        point get_best_hough_point (
            const point& p,
            const image_type& himg_
        )
        {
            const const_image_view<image_type> himg(himg_);

            DLIB_ASSERT(himg.nr() == size() && himg.nc() == size() &&
                rectangle(0,0,size()-1,size()-1).contains(p) == true,
                "\t point hough_transform::get_best_hough_point()"
                << "\n\t Invalid arguments given to this function."
                << "\n\t himg.nr(): " << himg.nr()
                << "\n\t himg.nc(): " << himg.nc()
                << "\n\t size():    " << size()
                << "\n\t p:         " << p
                );

            typedef typename image_traits<image_type>::pixel_type pixel_type;
            COMPILE_TIME_ASSERT(pixel_traits<pixel_type>::grayscale == true);
            pixel_type best_val = std::numeric_limits<pixel_type>::min();
            point best_point;

            const long max_n8 = (himg.nc()/8)*8;
            const long max_n4 = (himg.nc()/4)*4;
            const long r = p.y();
            const long c = p.x();

            const int32* ysin = &ysin_theta(r,0);
            const int32* xcos = &xcos_theta(c,0);
            long t = 0;
            while(t < max_n8)
            {
                long rr0 = (*xcos++ + *ysin++)>>16;
                long rr1 = (*xcos++ + *ysin++)>>16;
                long rr2 = (*xcos++ + *ysin++)>>16;
                long rr3 = (*xcos++ + *ysin++)>>16;
                long rr4 = (*xcos++ + *ysin++)>>16;
                long rr5 = (*xcos++ + *ysin++)>>16;
                long rr6 = (*xcos++ + *ysin++)>>16;
                long rr7 = (*xcos++ + *ysin++)>>16;

                if (himg[rr0][t++] > best_val)
                {
                    best_val = himg[rr0][t-1];
                    best_point.x() = t-1;
                    best_point.y() = rr0;
                }
                if (himg[rr1][t++] > best_val)
                {
                    best_val = himg[rr1][t-1];
                    best_point.x() = t-1;
                    best_point.y() = rr1;
                }
                if (himg[rr2][t++] > best_val)
                {
                    best_val = himg[rr2][t-1];
                    best_point.x() = t-1;
                    best_point.y() = rr2;
                }
                if (himg[rr3][t++] > best_val)
                {
                    best_val = himg[rr3][t-1];
                    best_point.x() = t-1;
                    best_point.y() = rr3;
                }
                if (himg[rr4][t++] > best_val)
                {
                    best_val = himg[rr4][t-1];
                    best_point.x() = t-1;
                    best_point.y() = rr4;
                }
                if (himg[rr5][t++] > best_val)
                {
                    best_val = himg[rr5][t-1];
                    best_point.x() = t-1;
                    best_point.y() = rr5;
                }
                if (himg[rr6][t++] > best_val)
                {
                    best_val = himg[rr6][t-1];
                    best_point.x() = t-1;
                    best_point.y() = rr6;
                }
                if (himg[rr7][t++] > best_val)
                {
                    best_val = himg[rr7][t-1];
                    best_point.x() = t-1;
                    best_point.y() = rr7;
                }
            }
            while(t < max_n4)
            {
                long rr0 = (*xcos++ + *ysin++)>>16;
                long rr1 = (*xcos++ + *ysin++)>>16;
                long rr2 = (*xcos++ + *ysin++)>>16;
                long rr3 = (*xcos++ + *ysin++)>>16;
                if (himg[rr0][t++] > best_val)
                {
                    best_val = himg[rr0][t-1];
                    best_point.x() = t-1;
                    best_point.y() = rr0;
                }
                if (himg[rr1][t++] > best_val)
                {
                    best_val = himg[rr1][t-1];
                    best_point.x() = t-1;
                    best_point.y() = rr1;
                }
                if (himg[rr2][t++] > best_val)
                {
                    best_val = himg[rr2][t-1];
                    best_point.x() = t-1;
                    best_point.y() = rr2;
                }
                if (himg[rr3][t++] > best_val)
                {
                    best_val = himg[rr3][t-1];
                    best_point.x() = t-1;
                    best_point.y() = rr3;
                }
            }
            while(t < himg.nc())
            {
                long rr0 = (*xcos++ + *ysin++)>>16;
                if (himg[rr0][t++] > best_val)
                {
                    best_val = himg[rr0][t-1];
                    best_point.x() = t-1;
                    best_point.y() = rr0;
                }
            }

            return best_point;
        }

        template <
            typename in_image_type,
            typename out_image_type
            >
        void operator() (
            const in_image_type& img_,
            const rectangle& box,
            out_image_type& himg_
        ) const
        {
            typedef typename image_traits<in_image_type>::pixel_type in_pixel_type;
            typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;

            DLIB_CASSERT(box.width() == size() && box.height() == size(),
                "\t hough_transform::hough_transform(size_)"
                << "\n\t Invalid arguments given to this function."
                << "\n\t box.width():  " << box.width()
                << "\n\t box.height(): " << box.height()
                << "\n\t size():       " << size()
                );

            COMPILE_TIME_ASSERT(pixel_traits<in_pixel_type>::grayscale == true);
            COMPILE_TIME_ASSERT(pixel_traits<out_pixel_type>::grayscale == true);

            const_image_view<in_image_type> img(img_);
            image_view<out_image_type> himg(himg_);

            himg.set_size(size(), size());
            assign_all_pixels(himg, 0);

            const rectangle area = box.intersect(get_rect(img));

            const long max_n8 = (himg.nc()/8)*8;
            const long max_n4 = (himg.nc()/4)*4;
            for (long r = area.top(); r <= area.bottom(); ++r)
            {
                const int32* ysin_base = &ysin_theta(r-box.top(),0);
                for (long c = area.left(); c <= area.right(); ++c)
                {
                    const out_pixel_type val = static_cast<out_pixel_type>(img[r][c]);
                    if (val != 0)
                    {
                        /*
                        // The code in this comment is equivalent to the more complex but
                        // faster code below.  We keep this simple version of the Hough
                        // transform implementation here just to document what it's doing
                        // more clearly.
                        const point cent = center(box);
                        const long x = c - cent.x();
                        const long y = r - cent.y();
                        for (long t = 0; t < himg.nc(); ++t)
                        {
                            double theta = t*pi/even_size;
                            double radius = (x*std::cos(theta) + y*std::sin(theta))/sqrt_2 + even_size/2 + 0.5;
                            long rr = static_cast<long>(radius);
                            himg[rr][t] += val;
                        }
                        continue;
                        */

                        // Run the speed optimized version of the code in the above
                        // comment.
                        const int32* ysin = ysin_base;
                        const int32* xcos = &xcos_theta(c-box.left(),0);
                        long t = 0;
                        while(t < max_n8)
                        {
                            long rr0 = (*xcos++ + *ysin++)>>16;
                            long rr1 = (*xcos++ + *ysin++)>>16;
                            long rr2 = (*xcos++ + *ysin++)>>16;
                            long rr3 = (*xcos++ + *ysin++)>>16;
                            long rr4 = (*xcos++ + *ysin++)>>16;
                            long rr5 = (*xcos++ + *ysin++)>>16;
                            long rr6 = (*xcos++ + *ysin++)>>16;
                            long rr7 = (*xcos++ + *ysin++)>>16;

                            himg[rr0][t++] += val;
                            himg[rr1][t++] += val;
                            himg[rr2][t++] += val;
                            himg[rr3][t++] += val;
                            himg[rr4][t++] += val;
                            himg[rr5][t++] += val;
                            himg[rr6][t++] += val;
                            himg[rr7][t++] += val;
                        }
                        while(t < max_n4)
                        {
                            long rr0 = (*xcos++ + *ysin++)>>16;
                            long rr1 = (*xcos++ + *ysin++)>>16;
                            long rr2 = (*xcos++ + *ysin++)>>16;
                            long rr3 = (*xcos++ + *ysin++)>>16;
                            himg[rr0][t++] += val;
                            himg[rr1][t++] += val;
                            himg[rr2][t++] += val;
                            himg[rr3][t++] += val;
                        }
                        while(t < himg.nc())
                        {
                            long rr0 = (*xcos++ + *ysin++)>>16;
                            himg[rr0][t++] += val;
                        }
                    }
                }
            }
        }

    private:

        unsigned long _size;
        unsigned long even_size; // equal to _size if _size is even, otherwise equal to _size-1.
        matrix<int32> xcos_theta, ysin_theta;
    };
}

#endif // DLIB_HOUGH_tRANSFORM_Hh_


dlib C++ Library - image_pyramid.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_IMAGE_PYRaMID_Hh_
#define DLIB_IMAGE_PYRaMID_Hh_

#include "image_pyramid_abstract.h"
#include "../pixel.h"
#include "../array2d.h"
#include "../geometry.h"
#include "spatial_filtering.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class pyramid_disable : noncopyable
    {
    public:

        template <typename T>
        vector<double,2> point_down (
            const vector<T,2>&
        ) const
        {
            return vector<double,2>(0,0);
        }

        template <typename T>
        vector<double,2> point_up (
            const vector<T,2>&
        ) const
        {
            return vector<double,2>(0,0);
        }

    // -----------------------------

        template <typename T>
        vector<double,2> point_down (
            const vector<T,2>& p,
            unsigned int levels
        ) const
        {
            if (levels == 0)
                return p;
            else
                return vector<double,2>(0,0);
        }

        template <typename T>
        vector<double,2> point_up (
            const vector<T,2>& p,
            unsigned int levels
        ) const
        {
            if (levels == 0)
                return p;
            else
                return vector<double,2>(0,0);
        }

    // -----------------------------

        drectangle rect_up (
            const drectangle& rect
        ) const
        {
            return drectangle(point_up(rect.tl_corner()), point_up(rect.br_corner()));
        }

        drectangle rect_up (
            const drectangle& rect,
            unsigned int levels
        ) const
        {
            return drectangle(point_up(rect.tl_corner(),levels), point_up(rect.br_corner(),levels));
        }

    // -----------------------------

        drectangle rect_down (
            const drectangle& rect
        ) const
        {
            return drectangle(point_down(rect.tl_corner()), point_down(rect.br_corner()));
        }

        drectangle rect_down (
            const drectangle& rect,
            unsigned int levels
        ) const
        {
            return drectangle(point_down(rect.tl_corner(),levels), point_down(rect.br_corner(),levels));
        }

    // -----------------------------

    public:

        template <
            typename in_image_type,
            typename out_image_type
            >
        void operator() (
            // we do this #ifdef stuff to avoid compiler warnings about unused variables.
#ifdef ENABLE_ASSERTS
            const in_image_type& original,
#else
            const in_image_type& ,
#endif
            out_image_type& down
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(is_same_object(original, down) == false,
                        "\t void pyramid_disable::operator()"
                        << "\n\t is_same_object(original, down): " << is_same_object(original, down)
                        << "\n\t this:                           " << this
                        );

            typedef typename image_traits<in_image_type>::pixel_type in_pixel_type;
            typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;
            COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type>::has_alpha == false );
            COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::has_alpha == false );

            set_image_size(down, 0, 0);
        }

        template <
            typename image_type
            >
        void operator() (
            image_type& img
        ) const
        {
            typedef typename image_traits<image_type>::pixel_type pixel_type;
            COMPILE_TIME_ASSERT( pixel_traits<pixel_type>::has_alpha == false );
            set_image_size(img, 0, 0);
        }
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    namespace impl
    {

        class pyramid_down_2_1 : noncopyable
        {
        public:

            template <typename T>
            vector<double,2> point_down (
                const vector<T,2>& p
            ) const
            {
                return p/2.0 - vector<double,2>(1.25,0.75);
            }

            template <typename T>
            vector<double,2> point_up (
                const vector<T,2>& p
            ) const
            {
                return (p + vector<T,2>(1.25,0.75))*2;
            }

        // -----------------------------

            template <typename T>
            vector<double,2> point_down (
                const vector<T,2>& p,
                unsigned int levels
            ) const
            {
                vector<double,2> temp = p;
                for (unsigned int i = 0; i < levels; ++i)
                    temp = point_down(temp);
                return temp;
            }

            template <typename T>
            vector<double,2> point_up (
                const vector<T,2>& p,
                unsigned int levels
            ) const
            {
                vector<double,2> temp = p;
                for (unsigned int i = 0; i < levels; ++i)
                    temp = point_up(temp);
                return temp;
            }

        // -----------------------------

            drectangle rect_up (
                const drectangle& rect
            ) const
            {
                return drectangle(point_up(rect.tl_corner()), point_up(rect.br_corner()));
            }

            drectangle rect_up (
                const drectangle& rect,
                unsigned int levels
            ) const
            {
                return drectangle(point_up(rect.tl_corner(),levels), point_up(rect.br_corner(),levels));
            }

        // -----------------------------

            drectangle rect_down (
                const drectangle& rect
            ) const
            {
                return drectangle(point_down(rect.tl_corner()), point_down(rect.br_corner()));
            }

            drectangle rect_down (
                const drectangle& rect,
                unsigned int levels
            ) const
            {
                return drectangle(point_down(rect.tl_corner(),levels), point_down(rect.br_corner(),levels));
            }

        // -----------------------------

        private:
            template <typename T, typename U>
            struct both_images_rgb
            {
                typedef typename image_traits<T>::pixel_type T_pix;
                typedef typename image_traits<U>::pixel_type U_pix;
                const static bool value = pixel_traits<T_pix>::rgb && pixel_traits<U_pix>::rgb;
            };
        public:

            template <
                typename in_image_type,
                typename out_image_type
                >
            typename disable_if<both_images_rgb<in_image_type,out_image_type> >::type operator() (
                const in_image_type& original_,
                out_image_type& down_
            ) const
            {
                // make sure requires clause is not broken
                DLIB_ASSERT( is_same_object(original_, down_) == false,
                            "\t void pyramid_down_2_1::operator()"
                            << "\n\t is_same_object(original_, down_): " << is_same_object(original_, down_)
                            << "\n\t this:                           " << this
                            );

                typedef typename image_traits<in_image_type>::pixel_type in_pixel_type;
                typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;
                COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type>::has_alpha == false );
                COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::has_alpha == false );

                const_image_view<in_image_type> original(original_);
                image_view<out_image_type> down(down_);

                if (original.nr() <= 8 || original.nc() <= 8)
                {
                    down.clear();
                    return;
                }

                typedef typename pixel_traits<in_pixel_type>::basic_pixel_type bp_type;
                typedef typename promote<bp_type>::type ptype;
                array2d<ptype> temp_img;
                temp_img.set_size(original.nr(), (original.nc()-3)/2);
                down.set_size((original.nr()-3)/2, (original.nc()-3)/2);

                // This function applies a 5x5 Gaussian filter to the image.  It
                // does this by separating the filter into its horizontal and vertical
                // components and then downsamples the image by dropping every other
                // row and column.  Note that we can do these things all together in
                // one step.

                // apply row filter
                for (long r = 0; r < temp_img.nr(); ++r)
                {
                    long oc = 0;
                    for (long c = 0; c < temp_img.nc(); ++c)
                    {
                        ptype pix1;
                        ptype pix2;
                        ptype pix3;
                        ptype pix4;
                        ptype pix5;

                        assign_pixel(pix1, original[r][oc]);
                        assign_pixel(pix2, original[r][oc+1]);
                        assign_pixel(pix3, original[r][oc+2]);
                        assign_pixel(pix4, original[r][oc+3]);
                        assign_pixel(pix5, original[r][oc+4]);

                        pix2 *= 4;
                        pix3 *= 6;
                        pix4 *= 4;

                        assign_pixel(temp_img[r][c], pix1 + pix2 + pix3 + pix4 + pix5);
                        oc += 2;
                    }
                }

                // apply column filter
                long dr = 0;
                for (long r = 2; r < temp_img.nr()-2; r += 2)
                {
                    for (long c = 0; c < temp_img.nc(); ++c)
                    {
                        ptype temp = temp_img[r-2][c] +
                                    temp_img[r-1][c]*4 +
                                    temp_img[r  ][c]*6 +
                                    temp_img[r-1][c]*4 +
                                    temp_img[r-2][c];

                        assign_pixel(down[dr][c],temp/256);
                    }
                    ++dr;
                }

            }

        private:
            struct rgbptype
            {
                uint16 red;
                uint16 green;
                uint16 blue;
            };
        public:
        // ------------------------------------------
        //       OVERLOAD FOR RGB TO RGB IMAGES
        // ------------------------------------------
            template <
                typename in_image_type,
                typename out_image_type
                >
            typename enable_if<both_images_rgb<in_image_type,out_image_type> >::type operator() (
                const in_image_type& original_,
                out_image_type& down_
            ) const
            {
                // make sure requires clause is not broken
                DLIB_ASSERT( is_same_object(original_, down_) == false,
                            "\t void pyramid_down_2_1::operator()"
                            << "\n\t is_same_object(original_, down_): " << is_same_object(original_, down_)
                            << "\n\t this:                           " << this
                            );

                typedef typename image_traits<in_image_type>::pixel_type in_pixel_type;
                typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;
                COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type>::has_alpha == false );
                COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::has_alpha == false );

                const_image_view<in_image_type> original(original_);
                image_view<out_image_type> down(down_);

                if (original.nr() <= 8 || original.nc() <= 8)
                {
                    down.clear();
                    return;
                }

                array2d<rgbptype> temp_img;
                temp_img.set_size(original.nr(), (original.nc()-3)/2);
                down.set_size((original.nr()-3)/2, (original.nc()-3)/2);

                // This function applies a 5x5 Gaussian filter to the image.  It
                // does this by separating the filter into its horizontal and vertical
                // components and then downsamples the image by dropping every other
                // row and column.  Note that we can do these things all together in
                // one step.

                // apply row filter
                for (long r = 0; r < temp_img.nr(); ++r)
                {
                    long oc = 0;
                    for (long c = 0; c < temp_img.nc(); ++c)
                    {
                        rgbptype pix1;
                        rgbptype pix2;
                        rgbptype pix3;
                        rgbptype pix4;
                        rgbptype pix5;

                        pix1.red = original[r][oc].red;
                        pix2.red = original[r][oc+1].red;
                        pix3.red = original[r][oc+2].red;
                        pix4.red = original[r][oc+3].red;
                        pix5.red = original[r][oc+4].red;
                        pix1.green = original[r][oc].green;
                        pix2.green = original[r][oc+1].green;
                        pix3.green = original[r][oc+2].green;
                        pix4.green = original[r][oc+3].green;
                        pix5.green = original[r][oc+4].green;
                        pix1.blue = original[r][oc].blue;
                        pix2.blue = original[r][oc+1].blue;
                        pix3.blue = original[r][oc+2].blue;
                        pix4.blue = original[r][oc+3].blue;
                        pix5.blue = original[r][oc+4].blue;

                        pix2.red *= 4;
                        pix3.red *= 6;
                        pix4.red *= 4;

                        pix2.green *= 4;
                        pix3.green *= 6;
                        pix4.green *= 4;

                        pix2.blue *= 4;
                        pix3.blue *= 6;
                        pix4.blue *= 4;

                        rgbptype temp;
                        temp.red = pix1.red + pix2.red + pix3.red + pix4.red + pix5.red;
                        temp.green = pix1.green + pix2.green + pix3.green + pix4.green + pix5.green;
                        temp.blue = pix1.blue + pix2.blue + pix3.blue + pix4.blue + pix5.blue;

                        temp_img[r][c] = temp;

                        oc += 2;
                    }
                }

                // apply column filter
                long dr = 0;
                for (long r = 2; r < temp_img.nr()-2; r += 2)
                {
                    for (long c = 0; c < temp_img.nc(); ++c)
                    {
                        rgbptype temp;
                        temp.red = temp_img[r-2][c].red +
                                temp_img[r-1][c].red*4 +
                                temp_img[r  ][c].red*6 +
                                temp_img[r-1][c].red*4 +
                                temp_img[r-2][c].red;
                        temp.green = temp_img[r-2][c].green +
                                    temp_img[r-1][c].green*4 +
                                    temp_img[r  ][c].green*6 +
                                    temp_img[r-1][c].green*4 +
                                    temp_img[r-2][c].green;
                        temp.blue = temp_img[r-2][c].blue +
                                    temp_img[r-1][c].blue*4 +
                                    temp_img[r  ][c].blue*6 +
                                    temp_img[r-1][c].blue*4 +
                                    temp_img[r-2][c].blue;

                        down[dr][c].red = temp.red/256;
                        down[dr][c].green = temp.green/256;
                        down[dr][c].blue = temp.blue/256;
                    }
                    ++dr;
                }

            }

            template <
                typename image_type
                >
            void operator() (
                image_type& img
            ) const
            {
                image_type temp;
                (*this)(img, temp);
                swap(temp, img);
            }

        private:

        };

    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------

        class pyramid_down_3_2 : noncopyable
        {
        public:

            template <typename T>
            vector<double,2> point_down (
                const vector<T,2>& p
            ) const
            {
                const double ratio = 2.0/3.0;
                return p*ratio - vector<double,2>(1,1);
            }

            template <typename T>
            vector<double,2> point_up (
                const vector<T,2>& p
            ) const
            {
                const double ratio = 3.0/2.0;
                return p*ratio + vector<T,2>(ratio,ratio);
            }

        // -----------------------------

            template <typename T>
            vector<double,2> point_down (
                const vector<T,2>& p,
                unsigned int levels
            ) const
            {
                vector<double,2> temp = p;
                for (unsigned int i = 0; i < levels; ++i)
                    temp = point_down(temp);
                return temp;
            }

            template <typename T>
            vector<double,2> point_up (
                const vector<T,2>& p,
                unsigned int levels
            ) const
            {
                vector<double,2> temp = p;
                for (unsigned int i = 0; i < levels; ++i)
                    temp = point_up(temp);
                return temp;
            }

        // -----------------------------

            drectangle rect_up (
                const drectangle& rect
            ) const
            {
                return drectangle(point_up(rect.tl_corner()), point_up(rect.br_corner()));
            }

            drectangle rect_up (
                const drectangle& rect,
                unsigned int levels
            ) const
            {
                return drectangle(point_up(rect.tl_corner(),levels), point_up(rect.br_corner(),levels));
            }

        // -----------------------------

            drectangle rect_down (
                const drectangle& rect
            ) const
            {
                return drectangle(point_down(rect.tl_corner()), point_down(rect.br_corner()));
            }

            drectangle rect_down (
                const drectangle& rect,
                unsigned int levels
            ) const
            {
                return drectangle(point_down(rect.tl_corner(),levels), point_down(rect.br_corner(),levels));
            }

        // -----------------------------

        private:
            template <typename T, typename U>
            struct both_images_rgb
            {
                typedef typename image_traits<T>::pixel_type T_pix;
                typedef typename image_traits<U>::pixel_type U_pix;
                const static bool value = pixel_traits<T_pix>::rgb && pixel_traits<U_pix>::rgb;
            };
        public:

            template <
                typename in_image_type,
                typename out_image_type
                >
            typename disable_if<both_images_rgb<in_image_type,out_image_type> >::type operator() (
                const in_image_type& original_,
                out_image_type& down_
            ) const
            {
                // make sure requires clause is not broken
                DLIB_ASSERT(is_same_object(original_, down_) == false,
                            "\t void pyramid_down_3_2::operator()"
                            << "\n\t is_same_object(original_, down_): " << is_same_object(original_, down_)
                            << "\n\t this:                           " << this
                            );

                typedef typename image_traits<in_image_type>::pixel_type in_pixel_type;
                typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;
                COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type>::has_alpha == false );
                COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::has_alpha == false );

                const_image_view<in_image_type> original(original_);
                image_view<out_image_type> down(down_);

                if (original.nr() <= 8 || original.nc() <= 8)
                {
                    down.clear();
                    return;
                }

                const long size_in = 3;
                const long size_out = 2;

                typedef typename pixel_traits<in_pixel_type>::basic_pixel_type bp_type;
                typedef typename promote<bp_type>::type ptype;
                const long full_nr =  size_out*((original.nr()-2)/size_in);
                const long part_nr = (size_out*(original.nr()-2))/size_in;
                const long full_nc =  size_out*((original.nc()-2)/size_in);
                const long part_nc = (size_out*(original.nc()-2))/size_in;
                down.set_size(part_nr, part_nc);

                long rr = 1;
                long r;
                for (r = 0; r < full_nr; r+=size_out)
                {
                    long cc = 1;
                    long c;
                    for (c = 0; c < full_nc; c+=size_out)
                    {
                        ptype block[size_in][size_in];
                        separable_3x3_filter_block_grayscale(block, original_, rr, cc, 2, 12, 2);

                        // bi-linearly interpolate block
                        assign_pixel(down[r][c]     , (block[0][0]*9 + block[1][0]*3 + block[0][1]*3 + block[1][1])/(16*256));
                        assign_pixel(down[r][c+1]   , (block[0][2]*9 + block[1][2]*3 + block[0][1]*3 + block[1][1])/(16*256));
                        assign_pixel(down[r+1][c]   , (block[2][0]*9 + block[1][0]*3 + block[2][1]*3 + block[1][1])/(16*256));
                        assign_pixel(down[r+1][c+1] , (block[2][2]*9 + block[1][2]*3 + block[2][1]*3 + block[1][1])/(16*256));

                        cc += size_in;
                    }
                    if (part_nc - full_nc == 1)
                    {
                        ptype block[size_in][2];
                        separable_3x3_filter_block_grayscale(block, original_, rr, cc, 2, 12, 2);

                        // bi-linearly interpolate partial block
                        assign_pixel(down[r][c]     , (block[0][0]*9 + block[1][0]*3 + block[0][1]*3 + block[1][1])/(16*256));
                        assign_pixel(down[r+1][c]   , (block[2][0]*9 + block[1][0]*3 + block[2][1]*3 + block[1][1])/(16*256));
                    }
                    rr += size_in;
                }
                if (part_nr - full_nr == 1)
                {
                    long cc = 1;
                    long c;
                    for (c = 0; c < full_nc; c+=size_out)
                    {
                        ptype block[2][size_in];
                        separable_3x3_filter_block_grayscale(block, original_, rr, cc, 2, 12, 2);

                        // bi-linearly interpolate partial block
                        assign_pixel(down[r][c]     , (block[0][0]*9 + block[1][0]*3 + block[0][1]*3 + block[1][1])/(16*256));
                        assign_pixel(down[r][c+1]   , (block[0][2]*9 + block[1][2]*3 + block[0][1]*3 + block[1][1])/(16*256));

                        cc += size_in;
                    }
                    if (part_nc - full_nc == 1)
                    {
                        ptype block[2][2];
                        separable_3x3_filter_block_grayscale(block, original_, rr, cc, 2, 12, 2);

                        // bi-linearly interpolate partial block
                        assign_pixel(down[r][c]     , (block[0][0]*9 + block[1][0]*3 + block[0][1]*3 + block[1][1])/(16*256));
                    }
                }

            }

        private:
            struct rgbptype
            {
                uint32 red;
                uint32 green;
                uint32 blue;
            };

        public:
        // ------------------------------------------
        //       OVERLOAD FOR RGB TO RGB IMAGES
        // ------------------------------------------
            template <
                typename in_image_type,
                typename out_image_type
                >
            typename enable_if<both_images_rgb<in_image_type,out_image_type> >::type operator() (
                const in_image_type& original_,
                out_image_type& down_
            ) const
            {
                // make sure requires clause is not broken
                DLIB_ASSERT( is_same_object(original_, down_) == false,
                            "\t void pyramid_down_3_2::operator()"
                            << "\n\t is_same_object(original_, down_): " << is_same_object(original_, down_)
                            << "\n\t this:                           " << this
                            );

                typedef typename image_traits<in_image_type>::pixel_type in_pixel_type;
                typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;
                COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type>::has_alpha == false );
                COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::has_alpha == false );

                const_image_view<in_image_type> original(original_);
                image_view<out_image_type> down(down_);

                if (original.nr() <= 8 || original.nc() <= 8)
                {
                    down.clear();
                    return;
                }

                const long size_in = 3;
                const long size_out = 2;

                const long full_nr =  size_out*((original.nr()-2)/size_in);
                const long part_nr = (size_out*(original.nr()-2))/size_in;
                const long full_nc =  size_out*((original.nc()-2)/size_in);
                const long part_nc = (size_out*(original.nc()-2))/size_in;
                down.set_size(part_nr, part_nc);

                long rr = 1;
                long r;
                for (r = 0; r < full_nr; r+=size_out)
                {
                    long cc = 1;
                    long c;
                    for (c = 0; c < full_nc; c+=size_out)
                    {
                        rgbptype block[size_in][size_in];
                        separable_3x3_filter_block_rgb(block, original_, rr, cc, 2, 12, 2);

                        // bi-linearly interpolate block
                        down[r][c].red       = (block[0][0].red*9   + block[1][0].red*3   + block[0][1].red*3   + block[1][1].red)/(16*256);
                        down[r][c].green     = (block[0][0].green*9 + block[1][0].green*3 + block[0][1].green*3 + block[1][1].green)/(16*256);
                        down[r][c].blue      = (block[0][0].blue*9  + block[1][0].blue*3  + block[0][1].blue*3  + block[1][1].blue)/(16*256);

                        down[r][c+1].red     = (block[0][2].red*9   + block[1][2].red*3   + block[0][1].red*3   + block[1][1].red)/(16*256);
                        down[r][c+1].green   = (block[0][2].green*9 + block[1][2].green*3 + block[0][1].green*3 + block[1][1].green)/(16*256);
                        down[r][c+1].blue    = (block[0][2].blue*9  + block[1][2].blue*3  + block[0][1].blue*3  + block[1][1].blue)/(16*256);

                        down[r+1][c].red     = (block[2][0].red*9   + block[1][0].red*3   + block[2][1].red*3   + block[1][1].red)/(16*256);
                        down[r+1][c].green   = (block[2][0].green*9 + block[1][0].green*3 + block[2][1].green*3 + block[1][1].green)/(16*256);
                        down[r+1][c].blue    = (block[2][0].blue*9  + block[1][0].blue*3  + block[2][1].blue*3  + block[1][1].blue)/(16*256);

                        down[r+1][c+1].red   = (block[2][2].red*9   + block[1][2].red*3   + block[2][1].red*3   + block[1][1].red)/(16*256);
                        down[r+1][c+1].green = (block[2][2].green*9 + block[1][2].green*3 + block[2][1].green*3 + block[1][1].green)/(16*256);
                        down[r+1][c+1].blue  = (block[2][2].blue*9  + block[1][2].blue*3  + block[2][1].blue*3  + block[1][1].blue)/(16*256);

                        cc += size_in;
                    }
                    if (part_nc - full_nc == 1)
                    {
                        rgbptype block[size_in][2];
                        separable_3x3_filter_block_rgb(block, original_, rr, cc, 2, 12, 2);

                        // bi-linearly interpolate partial block
                        down[r][c].red       = (block[0][0].red*9   + block[1][0].red*3   + block[0][1].red*3   + block[1][1].red)/(16*256);
                        down[r][c].green     = (block[0][0].green*9 + block[1][0].green*3 + block[0][1].green*3 + block[1][1].green)/(16*256);
                        down[r][c].blue      = (block[0][0].blue*9  + block[1][0].blue*3  + block[0][1].blue*3  + block[1][1].blue)/(16*256);

                        down[r+1][c].red     = (block[2][0].red*9   + block[1][0].red*3   + block[2][1].red*3   + block[1][1].red)/(16*256);
                        down[r+1][c].green   = (block[2][0].green*9 + block[1][0].green*3 + block[2][1].green*3 + block[1][1].green)/(16*256);
                        down[r+1][c].blue    = (block[2][0].blue*9  + block[1][0].blue*3  + block[2][1].blue*3  + block[1][1].blue)/(16*256);
                    }
                    rr += size_in;
                }
                if (part_nr - full_nr == 1)
                {
                    long cc = 1;
                    long c;
                    for (c = 0; c < full_nc; c+=size_out)
                    {
                        rgbptype block[2][size_in];
                        separable_3x3_filter_block_rgb(block, original_, rr, cc, 2, 12, 2);

                        // bi-linearly interpolate partial block
                        down[r][c].red       = (block[0][0].red*9   + block[1][0].red*3   + block[0][1].red*3   + block[1][1].red)/(16*256);
                        down[r][c].green     = (block[0][0].green*9 + block[1][0].green*3 + block[0][1].green*3 + block[1][1].green)/(16*256);
                        down[r][c].blue      = (block[0][0].blue*9  + block[1][0].blue*3  + block[0][1].blue*3  + block[1][1].blue)/(16*256);

                        down[r][c+1].red     = (block[0][2].red*9   + block[1][2].red*3   + block[0][1].red*3   + block[1][1].red)/(16*256);
                        down[r][c+1].green   = (block[0][2].green*9 + block[1][2].green*3 + block[0][1].green*3 + block[1][1].green)/(16*256);
                        down[r][c+1].blue    = (block[0][2].blue*9  + block[1][2].blue*3  + block[0][1].blue*3  + block[1][1].blue)/(16*256);

                        cc += size_in;
                    }
                    if (part_nc - full_nc == 1)
                    {
                        rgbptype block[2][2];
                        separable_3x3_filter_block_rgb(block, original_, rr, cc, 2, 12, 2);

                        // bi-linearly interpolate partial block
                        down[r][c].red       = (block[0][0].red*9   + block[1][0].red*3   + block[0][1].red*3   + block[1][1].red)/(16*256);
                        down[r][c].green     = (block[0][0].green*9 + block[1][0].green*3 + block[0][1].green*3 + block[1][1].green)/(16*256);
                        down[r][c].blue      = (block[0][0].blue*9  + block[1][0].blue*3  + block[0][1].blue*3  + block[1][1].blue)/(16*256);
                    }
                }
            }

            template <
                typename image_type
                >
            void operator() (
                image_type& img
            ) const
            {
                image_type temp;
                (*this)(img, temp);
                swap(temp, img);
            }
        private:

        };

    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        unsigned int N
        >
    class pyramid_down : noncopyable
    {
    public:

        COMPILE_TIME_ASSERT(N > 0);

        template <typename T>
        vector<double,2> point_down (
            const vector<T,2>& p
        ) const
        {
            const double ratio = (N-1.0)/N;
            return p*ratio;
        }

        template <typename T>
        vector<double,2> point_up (
            const vector<T,2>& p
        ) const
        {
            const double ratio = N/(N-1.0);
            return p*ratio;
        }

    // -----------------------------

        template <typename T>
        vector<double,2> point_down (
            const vector<T,2>& p,
            unsigned int levels
        ) const
        {
            vector<double,2> temp = p;
            for (unsigned int i = 0; i < levels; ++i)
                temp = point_down(temp);
            return temp;
        }

        template <typename T>
        vector<double,2> point_up (
            const vector<T,2>& p,
            unsigned int levels
        ) const
        {
            vector<double,2> temp = p;
            for (unsigned int i = 0; i < levels; ++i)
                temp = point_up(temp);
            return temp;
        }

    // -----------------------------

        drectangle rect_up (
            const drectangle& rect
        ) const
        {
            return drectangle(point_up(rect.tl_corner()), point_up(rect.br_corner()));
        }

        drectangle rect_up (
            const drectangle& rect,
            unsigned int levels
        ) const
        {
            return drectangle(point_up(rect.tl_corner(),levels), point_up(rect.br_corner(),levels));
        }

    // -----------------------------

        drectangle rect_down (
            const drectangle& rect
        ) const
        {
            return drectangle(point_down(rect.tl_corner()), point_down(rect.br_corner()));
        }

        drectangle rect_down (
            const drectangle& rect,
            unsigned int levels
        ) const
        {
            return drectangle(point_down(rect.tl_corner(),levels), point_down(rect.br_corner(),levels));
        }

        template <
            typename in_image_type,
            typename out_image_type
            >
        void operator() (
            const in_image_type& original,
            out_image_type& down
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(is_same_object(original, down) == false,
                        "\t void pyramid_down::operator()"
                        << "\n\t is_same_object(original, down): " << is_same_object(original, down)
                        << "\n\t this:                           " << this
                        );

            typedef typename image_traits<in_image_type>::pixel_type in_pixel_type;
            typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;
            COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type>::has_alpha == false );
            COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::has_alpha == false );

            set_image_size(down, ((N-1)*num_rows(original))/N, ((N-1)*num_columns(original))/N);
            resize_image(original, down);
        }

        template <
            typename image_type
            >
        void operator() (
            image_type& img
        ) const
        {
            image_type temp;
            (*this)(img, temp);
            swap(temp, img);
        }
    };

    template <>
    class pyramid_down<1> : public pyramid_disable {};

    template <>
    class pyramid_down<2> : public dlib::impl::pyramid_down_2_1 {};

    template <>
    class pyramid_down<3> : public dlib::impl::pyramid_down_3_2 {};

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

}

#endif // DLIB_IMAGE_PYRaMID_Hh_


dlib C++ Library - integral_image.h

// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_INTEGRAL_IMAGE
#define DLIB_INTEGRAL_IMAGE

#include "integral_image_abstract.h"

#include "../algs.h"
#include "../assert.h"
#include "../geometry.h"
#include "../array2d.h"
#include "../matrix.h"
#include "../pixel.h"
#include "../noncopyable.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    class integral_image_generic : noncopyable
    {
    public:
        typedef T value_type;

        long nr() const { return int_img.nr(); }
        long nc() const { return int_img.nc(); }

        template <typename image_type>
        void load (
            const image_type& img_
        )
        {
            const_image_view<image_type> img(img_);
            T pixel;
            int_img.set_size(img.nr(), img.nc());

            // compute the first row of the integral image
            T temp = 0;
            for (long c = 0; c < img.nc(); ++c)
            {
                assign_pixel(pixel, img[0][c]);
                temp += pixel;
                int_img[0][c] = temp;
            }

            // now compute the rest of the integral image
            for (long r = 1; r < img.nr(); ++r)
            {
                temp = 0;
                for (long c = 0; c < img.nc(); ++c)
                {
                    assign_pixel(pixel, img[r][c]);
                    temp += pixel;
                    int_img[r][c] = temp + int_img[r-1][c];
                }
            }

        }

        value_type get_sum_of_area (
            const rectangle& rect
        ) const
        {
            DLIB_ASSERT(get_rect(*this).contains(rect) == true && rect.is_empty() == false,
                "\tvalue_type get_sum_of_area(rect)"
                << "\n\tYou have given a rectangle that goes outside the image"
                << "\n\tthis:            " << this
                << "\n\trect.is_empty(): " << rect.is_empty()
                << "\n\trect:            " << rect
                << "\n\tget_rect(*this): " << get_rect(*this)
            );

            T top_left = 0, top_right = 0, bottom_left = 0, bottom_right = 0;

            bottom_right = int_img[rect.bottom()][rect.right()];
            if (rect.left()-1 >= 0 && rect.top()-1 >= 0)
            {
                top_left = int_img[rect.top()-1][rect.left()-1];
                bottom_left = int_img[rect.bottom()][rect.left()-1];
                top_right = int_img[rect.top()-1][rect.right()];
            }
            else if (rect.left()-1 >= 0)
            {
                bottom_left = int_img[rect.bottom()][rect.left()-1];
            }
            else if (rect.top()-1 >= 0)
            {
                top_right = int_img[rect.top()-1][rect.right()];
            }

            return bottom_right - bottom_left - top_right + top_left;
        }

        void swap(integral_image_generic& item)
        {
            int_img.swap(item.int_img);
        }

    private:

        array2d<T> int_img;
    };

    template <
        typename T
        >
    void swap (
        integral_image_generic<T>& a,
        integral_image_generic<T>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------

    typedef integral_image_generic<long> integral_image;

// ----------------------------------------------------------------------------------------

    template <typename integral_image_type>
    typename integral_image_type::value_type haar_x (
        const integral_image_type& img,
        const point& p,
        long width
    )
    {
        DLIB_ASSERT(get_rect(img).contains(centered_rect(p,width,width)) == true,
            "\tlong haar_x(img,p,width)"
            << "\n\tYou have given a point and with that goes outside the image"
            << "\n\tget_rect(img):  " << get_rect(img)
            << "\n\tp:              " << p
            << "\n\twidth:          " << width
        );

        rectangle left_rect;
        left_rect.set_left ( p.x() - width / 2 );
        left_rect.set_top ( p.y() - width / 2 );
        left_rect.set_right ( p.x()-1 );
        left_rect.set_bottom ( left_rect.top() + width - 1 );

        rectangle right_rect;
        right_rect.set_left ( p.x() );
        right_rect.set_top ( left_rect.top() );
        right_rect.set_right ( left_rect.left() + width -1 );
        right_rect.set_bottom ( left_rect.bottom() );

        return img.get_sum_of_area(right_rect) - img.get_sum_of_area(left_rect);
    }

    //  ----------------------------------------------------------------------------

    template <typename integral_image_type>
    typename integral_image_type::value_type haar_y (
        const integral_image_type& img,
        const point& p,
        long width
    )
    {
        DLIB_ASSERT(get_rect(img).contains(centered_rect(p,width,width)) == true,
            "\tlong haar_y(img,p,width)"
            << "\n\tYou have given a point and with that goes outside the image"
            << "\n\tget_rect(img):  " << get_rect(img)
            << "\n\tp:              " << p
            << "\n\twidth:          " << width
        );

        rectangle top_rect;
        top_rect.set_left ( p.x() - width / 2 );
        top_rect.set_top ( p.y() - width / 2 );
        top_rect.set_right ( top_rect.left() + width - 1 );
        top_rect.set_bottom ( p.y()-1 );

        rectangle bottom_rect;
        bottom_rect.set_left ( top_rect.left() );
        bottom_rect.set_top ( p.y() );
        bottom_rect.set_right ( top_rect.right() );
        bottom_rect.set_bottom ( top_rect.top() + width - 1 );

        return img.get_sum_of_area(bottom_rect) - img.get_sum_of_area(top_rect);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_INTEGRAL_IMAGE


dlib C++ Library - interpolation.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_INTERPOlATIONh_
#define DLIB_INTERPOlATIONh_

#include "interpolation_abstract.h"
#include "../pixel.h"
#include "../matrix.h"
#include "assign_image.h"
#include "image_pyramid.h"
#include "../simd.h"
#include "../image_processing/full_object_detection.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <typename T>
    struct sub_image_proxy
    {
        sub_image_proxy (
            T& img,
            rectangle rect
        )
        {
            rect = rect.intersect(get_rect(img));
            typedef typename image_traits<T>::pixel_type pixel_type;

            _nr = rect.height();
            _nc = rect.width();
            _width_step = width_step(img);
            _data = (char*)image_data(img) + sizeof(pixel_type)*rect.left() + rect.top()*_width_step;
        }

        void* _data;
        long _width_step;
        long _nr;
        long _nc;
    };

    template <typename T>
    struct const_sub_image_proxy
    {
        const_sub_image_proxy (
            const T& img,
            rectangle rect
        )
        {
            rect = rect.intersect(get_rect(img));
            typedef typename image_traits<T>::pixel_type pixel_type;

            _nr = rect.height();
            _nc = rect.width();
            _width_step = width_step(img);
            _data = (const char*)image_data(img) + sizeof(pixel_type)*rect.left() + rect.top()*_width_step;
        }

        const void* _data;
        long _width_step;
        long _nr;
        long _nc;
    };

    template <typename T>
    struct image_traits<sub_image_proxy<T> >
    {
        typedef typename image_traits<T>::pixel_type pixel_type;
    };
    template <typename T>
    struct image_traits<const sub_image_proxy<T> >
    {
        typedef typename image_traits<T>::pixel_type pixel_type;
    };
    template <typename T>
    struct image_traits<const_sub_image_proxy<T> >
    {
        typedef typename image_traits<T>::pixel_type pixel_type;
    };
    template <typename T>
    struct image_traits<const const_sub_image_proxy<T> >
    {
        typedef typename image_traits<T>::pixel_type pixel_type;
    };

    template <typename T>
    inline long num_rows( const sub_image_proxy<T>& img) { return img._nr; }
    template <typename T>
    inline long num_columns( const sub_image_proxy<T>& img) { return img._nc; }

    template <typename T>
    inline long num_rows( const const_sub_image_proxy<T>& img) { return img._nr; }
    template <typename T>
    inline long num_columns( const const_sub_image_proxy<T>& img) { return img._nc; }

    template <typename T>
    inline void* image_data( sub_image_proxy<T>& img)
    {
        return img._data;
    }
    template <typename T>
    inline const void* image_data( const sub_image_proxy<T>& img)
    {
        return img._data;
    }

    template <typename T>
    inline const void* image_data( const const_sub_image_proxy<T>& img)
    {
        return img._data;
    }

    template <typename T>
    inline long width_step(
        const sub_image_proxy<T>& img
    ) { return img._width_step; }

    template <typename T>
    inline long width_step(
        const const_sub_image_proxy<T>& img
    ) { return img._width_step; }

    template <
        typename image_type
        >
    sub_image_proxy<image_type> sub_image (
        image_type& img,
        const rectangle& rect
    )
    {
        return sub_image_proxy<image_type>(img,rect);
    }

    template <
        typename image_type
        >
    const const_sub_image_proxy<image_type> sub_image (
        const image_type& img,
        const rectangle& rect
    )
    {
        return const_sub_image_proxy<image_type>(img,rect);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class interpolate_nearest_neighbor
    {
    public:

        template <typename image_view_type, typename pixel_type>
        bool operator() (
            const image_view_type& img,
            const dlib::point& p,
            pixel_type& result
        ) const
        {
            COMPILE_TIME_ASSERT(pixel_traits<typename image_view_type::pixel_type>::has_alpha == false);

            if (get_rect(img).contains(p))
            {
                assign_pixel(result, img[p.y()][p.x()]);
                return true;
            }
            else
            {
                return false;
            }
        }

    };

// ----------------------------------------------------------------------------------------

    class interpolate_bilinear
    {
        template <typename T>
        struct is_rgb_image
        {
            const static bool value = pixel_traits<typename T::pixel_type>::rgb;
        };

    public:

        template <typename T, typename image_view_type, typename pixel_type>
        typename disable_if<is_rgb_image<image_view_type>,bool>::type operator() (
            const image_view_type& img,
            const dlib::vector<T,2>& p,
            pixel_type& result
        ) const
        {
            COMPILE_TIME_ASSERT(pixel_traits<typename image_view_type::pixel_type>::has_alpha == false);

            const long left   = static_cast<long>(std::floor(p.x()));
            const long top    = static_cast<long>(std::floor(p.y()));
            const long right  = left+1;
            const long bottom = top+1;

            // if the interpolation goes outside img
            if (!(left >= 0 && top >= 0 && right < img.nc() && bottom < img.nr()))
                return false;

            const double lr_frac = p.x() - left;
            const double tb_frac = p.y() - top;

            double tl = 0, tr = 0, bl = 0, br = 0;

            assign_pixel(tl, img[top][left]);
            assign_pixel(tr, img[top][right]);
            assign_pixel(bl, img[bottom][left]);
            assign_pixel(br, img[bottom][right]);

            double temp = (1-tb_frac)*((1-lr_frac)*tl + lr_frac*tr) +
                              tb_frac*((1-lr_frac)*bl + lr_frac*br);

            assign_pixel(result, temp);
            return true;
        }

        template <typename T, typename image_view_type, typename pixel_type>
        typename enable_if<is_rgb_image<image_view_type>,bool>::type operator() (
            const image_view_type& img,
            const dlib::vector<T,2>& p,
            pixel_type& result
        ) const
        {
            COMPILE_TIME_ASSERT(pixel_traits<typename image_view_type::pixel_type>::has_alpha == false);

            const long left   = static_cast<long>(std::floor(p.x()));
            const long top    = static_cast<long>(std::floor(p.y()));
            const long right  = left+1;
            const long bottom = top+1;

            // if the interpolation goes outside img
            if (!(left >= 0 && top >= 0 && right < img.nc() && bottom < img.nr()))
                return false;

            const double lr_frac = p.x() - left;
            const double tb_frac = p.y() - top;

            double tl, tr, bl, br;

            tl = img[top][left].red;
            tr = img[top][right].red;
            bl = img[bottom][left].red;
            br = img[bottom][right].red;
            const double red = (1-tb_frac)*((1-lr_frac)*tl + lr_frac*tr) +
                                   tb_frac*((1-lr_frac)*bl + lr_frac*br);

            tl = img[top][left].green;
            tr = img[top][right].green;
            bl = img[bottom][left].green;
            br = img[bottom][right].green;
            const double green = (1-tb_frac)*((1-lr_frac)*tl + lr_frac*tr) +
                                   tb_frac*((1-lr_frac)*bl + lr_frac*br);

            tl = img[top][left].blue;
            tr = img[top][right].blue;
            bl = img[bottom][left].blue;
            br = img[bottom][right].blue;
            const double blue = (1-tb_frac)*((1-lr_frac)*tl + lr_frac*tr) +
                                   tb_frac*((1-lr_frac)*bl + lr_frac*br);

            rgb_pixel temp;
            assign_pixel(temp.red, red);
            assign_pixel(temp.green, green);
            assign_pixel(temp.blue, blue);
            assign_pixel(result, temp);
            return true;
        }
    };

// ----------------------------------------------------------------------------------------

    class interpolate_quadratic
    {
        template <typename T>
        struct is_rgb_image
        {
            const static bool value = pixel_traits<typename T::pixel_type>::rgb;
        };

    public:

        template <typename T, typename image_view_type, typename pixel_type>
        typename disable_if<is_rgb_image<image_view_type>,bool>::type operator() (
            const image_view_type& img,
            const dlib::vector<T,2>& p,
            pixel_type& result
        ) const
        {
            COMPILE_TIME_ASSERT(pixel_traits<typename image_view_type::pixel_type>::has_alpha == false);

            const point pp(p);

            // if the interpolation goes outside img
            if (!get_rect(img).contains(grow_rect(pp,1)))
                return false;

            const long r = pp.y();
            const long c = pp.x();

            const double temp = interpolate(p-pp,
                                    img[r-1][c-1],
                                    img[r-1][c  ],
                                    img[r-1][c+1],
                                    img[r  ][c-1],
                                    img[r  ][c  ],
                                    img[r  ][c+1],
                                    img[r+1][c-1],
                                    img[r+1][c  ],
                                    img[r+1][c+1]);

            assign_pixel(result, temp);
            return true;
        }

        template <typename T, typename image_view_type, typename pixel_type>
        typename enable_if<is_rgb_image<image_view_type>,bool>::type operator() (
            const image_view_type& img,
            const dlib::vector<T,2>& p,
            pixel_type& result
        ) const
        {
            COMPILE_TIME_ASSERT(pixel_traits<typename image_view_type::pixel_type>::has_alpha == false);

            const point pp(p);

            // if the interpolation goes outside img
            if (!get_rect(img).contains(grow_rect(pp,1)))
                return false;

            const long r = pp.y();
            const long c = pp.x();

            const double red = interpolate(p-pp,
                            img[r-1][c-1].red,
                            img[r-1][c  ].red,
                            img[r-1][c+1].red,
                            img[r  ][c-1].red,
                            img[r  ][c  ].red,
                            img[r  ][c+1].red,
                            img[r+1][c-1].red,
                            img[r+1][c  ].red,
                            img[r+1][c+1].red);
            const double green = interpolate(p-pp,
                            img[r-1][c-1].green,
                            img[r-1][c  ].green,
                            img[r-1][c+1].green,
                            img[r  ][c-1].green,
                            img[r  ][c  ].green,
                            img[r  ][c+1].green,
                            img[r+1][c-1].green,
                            img[r+1][c  ].green,
                            img[r+1][c+1].green);
            const double blue = interpolate(p-pp,
                            img[r-1][c-1].blue,
                            img[r-1][c  ].blue,
                            img[r-1][c+1].blue,
                            img[r  ][c-1].blue,
                            img[r  ][c  ].blue,
                            img[r  ][c+1].blue,
                            img[r+1][c-1].blue,
                            img[r+1][c  ].blue,
                            img[r+1][c+1].blue);

            rgb_pixel temp;
            assign_pixel(temp.red, red);
            assign_pixel(temp.green, green);
            assign_pixel(temp.blue, blue);
            assign_pixel(result, temp);

            return true;
        }

    private:

        /*  tl tm tr
            ml mm mr
            bl bm br
        */
        // The above is the pixel layout in our little 3x3 neighborhood.  interpolate() will
        // fit a quadratic to these 9 pixels and then use that quadratic to find the interpolated
        // value at point p.
        inline double interpolate(
            const dlib::vector<double,2>& p,
            double tl, double tm, double tr,
            double ml, double mm, double mr,
            double bl, double bm, double br
        ) const
        {
            matrix<double,6,1> w;
            // x
            w(0) = (tr + mr + br - tl - ml - bl)*0.16666666666;
            // y
            w(1) = (bl + bm + br - tl - tm - tr)*0.16666666666;
            // x^2
            w(2) = (tl + tr + ml + mr + bl + br)*0.16666666666 - (tm + mm + bm)*0.333333333;
            // x*y
            w(3) = (tl - tr - bl + br)*0.25;
            // y^2
            w(4) = (tl + tm + tr + bl + bm + br)*0.16666666666 - (ml + mm + mr)*0.333333333;
            // 1 (constant term)
            w(5) = (tm + ml + mr + bm)*0.222222222 - (tl + tr + bl + br)*0.11111111 + (mm)*0.55555556;

            const double x = p.x();
            const double y = p.y();

            matrix<double,6,1> z;
            z = x, y, x*x, x*y, y*y, 1.0;

            return dot(w,z);
        }
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class black_background
    {
    public:
        template <typename pixel_type>
        void operator() ( pixel_type& p) const { assign_pixel(p, 0); }
    };

    class white_background
    {
    public:
        template <typename pixel_type>
        void operator() ( pixel_type& p) const { assign_pixel(p, 255); }
    };

    class no_background
    {
    public:
        template <typename pixel_type>
        void operator() ( pixel_type& ) const { }
    };

// ----------------------------------------------------------------------------------------

    template <
        typename image_type1,
        typename image_type2,
        typename interpolation_type,
        typename point_mapping_type,
        typename background_type
        >
    void transform_image (
        const image_type1& in_img,
        image_type2& out_img,
        const interpolation_type& interp,
        const point_mapping_type& map_point,
        const background_type& set_background,
        const rectangle& area
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( get_rect(out_img).contains(area) == true &&
                     is_same_object(in_img, out_img) == false ,
            "\t void transform_image()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t get_rect(out_img).contains(area): " << get_rect(out_img).contains(area)
            << "\n\t get_rect(out_img): " << get_rect(out_img)
            << "\n\t area:              " << area
            << "\n\t is_same_object(in_img, out_img):  " << is_same_object(in_img, out_img)
            );

        const_image_view<image_type1> imgv(in_img);
        image_view<image_type2> out_imgv(out_img);

        for (long r = area.top(); r <= area.bottom(); ++r)
        {
            for (long c = area.left(); c <= area.right(); ++c)
            {
                if (!interp(imgv, map_point(dlib::vector<double,2>(c,r)), out_imgv[r][c]))
                    set_background(out_imgv[r][c]);
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_type1,
        typename image_type2,
        typename interpolation_type,
        typename point_mapping_type,
        typename background_type
        >
    void transform_image (
        const image_type1& in_img,
        image_type2& out_img,
        const interpolation_type& interp,
        const point_mapping_type& map_point,
        const background_type& set_background
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( is_same_object(in_img, out_img) == false ,
            "\t void transform_image()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t is_same_object(in_img, out_img):  " << is_same_object(in_img, out_img)
            );

        transform_image(in_img, out_img, interp, map_point, set_background, get_rect(out_img));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_type1,
        typename image_type2,
        typename interpolation_type,
        typename point_mapping_type
        >
    void transform_image (
        const image_type1& in_img,
        image_type2& out_img,
        const interpolation_type& interp,
        const point_mapping_type& map_point
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( is_same_object(in_img, out_img) == false ,
            "\t void transform_image()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t is_same_object(in_img, out_img):  " << is_same_object(in_img, out_img)
            );

        transform_image(in_img, out_img, interp, map_point, black_background(), get_rect(out_img));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_type1,
        typename image_type2,
        typename interpolation_type
        >
    point_transform_affine rotate_image (
        const image_type1& in_img,
        image_type2& out_img,
        double angle,
        const interpolation_type& interp
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( is_same_object(in_img, out_img) == false ,
            "\t point_transform_affine rotate_image()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t is_same_object(in_img, out_img):  " << is_same_object(in_img, out_img)
            );

        const rectangle rimg = get_rect(in_img);

        // figure out bounding box for rotated rectangle
        rectangle rect;
        rect += rotate_point(center(rimg), rimg.tl_corner(), -angle);
        rect += rotate_point(center(rimg), rimg.tr_corner(), -angle);
        rect += rotate_point(center(rimg), rimg.bl_corner(), -angle);
        rect += rotate_point(center(rimg), rimg.br_corner(), -angle);
        out_img.set_size(rect.height(), rect.width());

        const matrix<double,2,2> R = rotation_matrix(angle);

        point_transform_affine trans = point_transform_affine(R, -R*dcenter(get_rect(out_img)) + dcenter(rimg));
        transform_image(in_img, out_img, interp, trans);
        return inv(trans);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_type1,
        typename image_type2
        >
    point_transform_affine rotate_image (
        const image_type1& in_img,
        image_type2& out_img,
        double angle
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( is_same_object(in_img, out_img) == false ,
            "\t point_transform_affine rotate_image()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t is_same_object(in_img, out_img):  " << is_same_object(in_img, out_img)
            );

        return rotate_image(in_img, out_img, angle, interpolate_quadratic());
    }

// ----------------------------------------------------------------------------------------

    namespace impl
    {
        class helper_resize_image
        {
        public:
            helper_resize_image(
                double x_scale_,
                double y_scale_
            ):
                x_scale(x_scale_),
                y_scale(y_scale_)
            {}

            dlib::vector<double,2> operator() (
                const dlib::vector<double,2>& p
            ) const
            {
                return dlib::vector<double,2>(p.x()*x_scale, p.y()*y_scale);
            }

        private:
            const double x_scale;
            const double y_scale;
        };
    }

    template <
        typename image_type1,
        typename image_type2,
        typename interpolation_type
        >
    void resize_image (
        const image_type1& in_img,
        image_type2& out_img,
        const interpolation_type& interp
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( is_same_object(in_img, out_img) == false ,
            "\t void resize_image()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t is_same_object(in_img, out_img):  " << is_same_object(in_img, out_img)
            );

        const double x_scale = (num_columns(in_img)-1)/(double)std::max<long>((num_columns(out_img)-1),1);
        const double y_scale = (num_rows(in_img)-1)/(double)std::max<long>((num_rows(out_img)-1),1);
        transform_image(in_img, out_img, interp,
                        dlib::impl::helper_resize_image(x_scale,y_scale));
    }

// ----------------------------------------------------------------------------------------

    template <typename image_type>
    struct is_rgb_image { const static bool value = pixel_traits<typename image_traits<image_type>::pixel_type>::rgb; };
    template <typename image_type>
    struct is_grayscale_image { const static bool value = pixel_traits<typename image_traits<image_type>::pixel_type>::grayscale; };

    // This is an optimized version of resize_image for the case where bilinear
    // interpolation is used.
    template <
        typename image_type1,
        typename image_type2
        >
    typename disable_if_c<(is_rgb_image<image_type1>::value&&is_rgb_image<image_type2>::value) ||
                          (is_grayscale_image<image_type1>::value&&is_grayscale_image<image_type2>::value)>::type
    resize_image (
        const image_type1& in_img_,
        image_type2& out_img_,
        interpolate_bilinear
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( is_same_object(in_img_, out_img_) == false ,
            "\t void resize_image()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t is_same_object(in_img_, out_img_):  " << is_same_object(in_img_, out_img_)
            );

        const_image_view<image_type1> in_img(in_img_);
        image_view<image_type2> out_img(out_img_);

        if (out_img.nr() <= 1 || out_img.nc() <= 1)
        {
            assign_all_pixels(out_img, 0);
            return;
        }

        typedef typename image_traits<image_type1>::pixel_type T;
        typedef typename image_traits<image_type2>::pixel_type U;
        const double x_scale = (in_img.nc()-1)/(double)std::max<long>((out_img.nc()-1),1);
        const double y_scale = (in_img.nr()-1)/(double)std::max<long>((out_img.nr()-1),1);
        double y = -y_scale;
        for (long r = 0; r < out_img.nr(); ++r)
        {
            y += y_scale;
            const long top    = static_cast<long>(std::floor(y));
            const long bottom = std::min(top+1, in_img.nr()-1);
            const double tb_frac = y - top;
            double x = -x_scale;
            if (pixel_traits<U>::grayscale)
            {
                for (long c = 0; c < out_img.nc(); ++c)
                {
                    x += x_scale;
                    const long left   = static_cast<long>(std::floor(x));
                    const long right  = std::min(left+1, in_img.nc()-1);
                    const double lr_frac = x - left;

                    double tl = 0, tr = 0, bl = 0, br = 0;

                    assign_pixel(tl, in_img[top][left]);
                    assign_pixel(tr, in_img[top][right]);
                    assign_pixel(bl, in_img[bottom][left]);
                    assign_pixel(br, in_img[bottom][right]);

                    double temp = (1-tb_frac)*((1-lr_frac)*tl + lr_frac*tr) +
                        tb_frac*((1-lr_frac)*bl + lr_frac*br);

                    assign_pixel(out_img[r][c], temp);
                }
            }
            else
            {
                for (long c = 0; c < out_img.nc(); ++c)
                {
                    x += x_scale;
                    const long left   = static_cast<long>(std::floor(x));
                    const long right  = std::min(left+1, in_img.nc()-1);
                    const double lr_frac = x - left;

                    const T tl = in_img[top][left];
                    const T tr = in_img[top][right];
                    const T bl = in_img[bottom][left];
                    const T br = in_img[bottom][right];

                    T temp;
                    assign_pixel(temp, 0);
                    vector_to_pixel(temp,
                        (1-tb_frac)*((1-lr_frac)*pixel_to_vector<double>(tl) + lr_frac*pixel_to_vector<double>(tr)) +
                            tb_frac*((1-lr_frac)*pixel_to_vector<double>(bl) + lr_frac*pixel_to_vector<double>(br)));
                    assign_pixel(out_img[r][c], temp);
                }
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    typename enable_if<is_grayscale_image<image_type> >::type resize_image (
        const image_type& in_img_,
        image_type& out_img_,
        interpolate_bilinear
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( is_same_object(in_img_, out_img_) == false ,
            "\t void resize_image()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t is_same_object(in_img_, out_img_):  " << is_same_object(in_img_, out_img_)
            );

        const_image_view<image_type> in_img(in_img_);
        image_view<image_type> out_img(out_img_);

        if (out_img.nr() <= 1 || out_img.nc() <= 1)
        {
            assign_all_pixels(out_img, 0);
            return;
        }

        typedef typename image_traits<image_type>::pixel_type T;
        const double x_scale = (in_img.nc()-1)/(double)std::max<long>((out_img.nc()-1),1);
        const double y_scale = (in_img.nr()-1)/(double)std::max<long>((out_img.nr()-1),1);
        double y = -y_scale;
        for (long r = 0; r < out_img.nr(); ++r)
        {
            y += y_scale;
            const long top    = static_cast<long>(std::floor(y));
            const long bottom = std::min(top+1, in_img.nr()-1);
            const double tb_frac = y - top;
            double x = -4*x_scale;

            const simd4f _tb_frac = tb_frac;
            const simd4f _inv_tb_frac = 1-tb_frac;
            const simd4f _x_scale = 4*x_scale;
            simd4f _x(x, x+x_scale, x+2*x_scale, x+3*x_scale);
            long c = 0;
            for (;; c+=4)
            {
                _x += _x_scale;
                simd4i left = simd4i(_x);

                simd4f _lr_frac = _x-left;
                simd4f _inv_lr_frac = 1-_lr_frac;
                simd4i right = left+1;

                simd4f tlf = _inv_tb_frac*_inv_lr_frac;
                simd4f trf = _inv_tb_frac*_lr_frac;
                simd4f blf = _tb_frac*_inv_lr_frac;
                simd4f brf = _tb_frac*_lr_frac;

                int32 fleft[4];
                int32 fright[4];
                left.store(fleft);
                right.store(fright);

                if (fright[3] >= in_img.nc())
                    break;
                simd4f tl(in_img[top][fleft[0]],     in_img[top][fleft[1]],     in_img[top][fleft[2]],     in_img[top][fleft[3]]);
                simd4f tr(in_img[top][fright[0]],    in_img[top][fright[1]],    in_img[top][fright[2]],    in_img[top][fright[3]]);
                simd4f bl(in_img[bottom][fleft[0]],  in_img[bottom][fleft[1]],  in_img[bottom][fleft[2]],  in_img[bottom][fleft[3]]);
                simd4f br(in_img[bottom][fright[0]], in_img[bottom][fright[1]], in_img[bottom][fright[2]], in_img[bottom][fright[3]]);

                simd4i out = simd4i(tlf*tl + trf*tr + blf*bl + brf*br);
                int32 fout[4];
                out.store(fout);

                out_img[r][c]   = static_cast<T>(fout[0]);
                out_img[r][c+1] = static_cast<T>(fout[1]);
                out_img[r][c+2] = static_cast<T>(fout[2]);
                out_img[r][c+3] = static_cast<T>(fout[3]);
            }
            x = -x_scale + c*x_scale;
            for (; c < out_img.nc(); ++c)
            {
                x += x_scale;
                const long left   = static_cast<long>(std::floor(x));
                const long right  = std::min(left+1, in_img.nc()-1);
                const float lr_frac = x - left;

                float tl = 0, tr = 0, bl = 0, br = 0;

                assign_pixel(tl, in_img[top][left]);
                assign_pixel(tr, in_img[top][right]);
                assign_pixel(bl, in_img[bottom][left]);
                assign_pixel(br, in_img[bottom][right]);

                float temp = (1-tb_frac)*((1-lr_frac)*tl + lr_frac*tr) +
                    tb_frac*((1-lr_frac)*bl + lr_frac*br);

                assign_pixel(out_img[r][c], temp);
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    typename enable_if<is_rgb_image<image_type> >::type resize_image (
        const image_type& in_img_,
        image_type& out_img_,
        interpolate_bilinear
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( is_same_object(in_img_, out_img_) == false ,
            "\t void resize_image()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t is_same_object(in_img_, out_img_):  " << is_same_object(in_img_, out_img_)
            );

        const_image_view<image_type> in_img(in_img_);
        image_view<image_type> out_img(out_img_);

        if (out_img.nr() <= 1 || out_img.nc() <= 1)
        {
            assign_all_pixels(out_img, 0);
            return;
        }

        typedef typename image_traits<image_type>::pixel_type T;
        const double x_scale = (in_img.nc()-1)/(double)std::max<long>((out_img.nc()-1),1);
        const double y_scale = (in_img.nr()-1)/(double)std::max<long>((out_img.nr()-1),1);
        double y = -y_scale;
        for (long r = 0; r < out_img.nr(); ++r)
        {
            y += y_scale;
            const long top    = static_cast<long>(std::floor(y));
            const long bottom = std::min(top+1, in_img.nr()-1);
            const double tb_frac = y - top;
            double x = -4*x_scale;

            const simd4f _tb_frac = tb_frac;
            const simd4f _inv_tb_frac = 1-tb_frac;
            const simd4f _x_scale = 4*x_scale;
            simd4f _x(x, x+x_scale, x+2*x_scale, x+3*x_scale);
            long c = 0;
            for (;; c+=4)
            {
                _x += _x_scale;
                simd4i left = simd4i(_x);
                simd4f lr_frac = _x-left;
                simd4f _inv_lr_frac = 1-lr_frac;
                simd4i right = left+1;

                simd4f tlf = _inv_tb_frac*_inv_lr_frac;
                simd4f trf = _inv_tb_frac*lr_frac;
                simd4f blf = _tb_frac*_inv_lr_frac;
                simd4f brf = _tb_frac*lr_frac;

                int32 fleft[4];
                int32 fright[4];
                left.store(fleft);
                right.store(fright);

                if (fright[3] >= in_img.nc())
                    break;
                simd4f tl(in_img[top][fleft[0]].red,     in_img[top][fleft[1]].red,     in_img[top][fleft[2]].red,     in_img[top][fleft[3]].red);
                simd4f tr(in_img[top][fright[0]].red,    in_img[top][fright[1]].red,    in_img[top][fright[2]].red,    in_img[top][fright[3]].red);
                simd4f bl(in_img[bottom][fleft[0]].red,  in_img[bottom][fleft[1]].red,  in_img[bottom][fleft[2]].red,  in_img[bottom][fleft[3]].red);
                simd4f br(in_img[bottom][fright[0]].red, in_img[bottom][fright[1]].red, in_img[bottom][fright[2]].red, in_img[bottom][fright[3]].red);

                simd4i out = simd4i(tlf*tl + trf*tr + blf*bl + brf*br);
                int32 fout[4];
                out.store(fout);

                out_img[r][c].red   = static_cast<unsigned char>(fout[0]);
                out_img[r][c+1].red = static_cast<unsigned char>(fout[1]);
                out_img[r][c+2].red = static_cast<unsigned char>(fout[2]);
                out_img[r][c+3].red = static_cast<unsigned char>(fout[3]);

                tl = simd4f(in_img[top][fleft[0]].green,    in_img[top][fleft[1]].green,    in_img[top][fleft[2]].green,    in_img[top][fleft[3]].green);
                tr = simd4f(in_img[top][fright[0]].green,   in_img[top][fright[1]].green,   in_img[top][fright[2]].green,   in_img[top][fright[3]].green);
                bl = simd4f(in_img[bottom][fleft[0]].green, in_img[bottom][fleft[1]].green, in_img[bottom][fleft[2]].green, in_img[bottom][fleft[3]].green);
                br = simd4f(in_img[bottom][fright[0]].green, in_img[bottom][fright[1]].green, in_img[bottom][fright[2]].green, in_img[bottom][fright[3]].green);
                out = simd4i(tlf*tl + trf*tr + blf*bl + brf*br);
                out.store(fout);
                out_img[r][c].green   = static_cast<unsigned char>(fout[0]);
                out_img[r][c+1].green = static_cast<unsigned char>(fout[1]);
                out_img[r][c+2].green = static_cast<unsigned char>(fout[2]);
                out_img[r][c+3].green = static_cast<unsigned char>(fout[3]);

                tl = simd4f(in_img[top][fleft[0]].blue,     in_img[top][fleft[1]].blue,     in_img[top][fleft[2]].blue,     in_img[top][fleft[3]].blue);
                tr = simd4f(in_img[top][fright[0]].blue,    in_img[top][fright[1]].blue,    in_img[top][fright[2]].blue,    in_img[top][fright[3]].blue);
                bl = simd4f(in_img[bottom][fleft[0]].blue,  in_img[bottom][fleft[1]].blue,  in_img[bottom][fleft[2]].blue,  in_img[bottom][fleft[3]].blue);
                br = simd4f(in_img[bottom][fright[0]].blue, in_img[bottom][fright[1]].blue, in_img[bottom][fright[2]].blue, in_img[bottom][fright[3]].blue);
                out = simd4i(tlf*tl + trf*tr + blf*bl + brf*br);
                out.store(fout);
                out_img[r][c].blue   = static_cast<unsigned char>(fout[0]);
                out_img[r][c+1].blue = static_cast<unsigned char>(fout[1]);
                out_img[r][c+2].blue = static_cast<unsigned char>(fout[2]);
                out_img[r][c+3].blue = static_cast<unsigned char>(fout[3]);
            }
            x = -x_scale + c*x_scale;
            for (; c < out_img.nc(); ++c)
            {
                x += x_scale;
                const long left   = static_cast<long>(std::floor(x));
                const long right  = std::min(left+1, in_img.nc()-1);
                const double lr_frac = x - left;

                const T tl = in_img[top][left];
                const T tr = in_img[top][right];
                const T bl = in_img[bottom][left];
                const T br = in_img[bottom][right];

                T temp;
                assign_pixel(temp, 0);
                vector_to_pixel(temp,
                    (1-tb_frac)*((1-lr_frac)*pixel_to_vector<double>(tl) + lr_frac*pixel_to_vector<double>(tr)) +
                    tb_frac*((1-lr_frac)*pixel_to_vector<double>(bl) + lr_frac*pixel_to_vector<double>(br)));
                assign_pixel(out_img[r][c], temp);
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_type1,
        typename image_type2
        >
    void resize_image (
        const image_type1& in_img,
        image_type2& out_img
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( is_same_object(in_img, out_img) == false ,
            "\t void resize_image()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t is_same_object(in_img, out_img):  " << is_same_object(in_img, out_img)
            );

        resize_image(in_img, out_img, interpolate_bilinear());
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_type1,
        typename image_type2
        >
    point_transform_affine flip_image_left_right (
        const image_type1& in_img,
        image_type2& out_img
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( is_same_object(in_img, out_img) == false ,
            "\t void flip_image_left_right()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t is_same_object(in_img, out_img):  " << is_same_object(in_img, out_img)
            );

        assign_image(out_img, fliplr(mat(in_img)));
        std::vector<dlib::vector<double,2> > from, to;
        rectangle r = get_rect(in_img);
        from.push_back(r.tl_corner()); to.push_back(r.tr_corner());
        from.push_back(r.bl_corner()); to.push_back(r.br_corner());
        from.push_back(r.tr_corner()); to.push_back(r.tl_corner());
        from.push_back(r.br_corner()); to.push_back(r.bl_corner());
        return find_affine_transform(from,to);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_type1,
        typename image_type2
        >
    void flip_image_up_down (
        const image_type1& in_img,
        image_type2& out_img
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( is_same_object(in_img, out_img) == false ,
            "\t void flip_image_up_down()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t is_same_object(in_img, out_img):  " << is_same_object(in_img, out_img)
            );

        assign_image(out_img, flipud(mat(in_img)));
    }

// ----------------------------------------------------------------------------------------

    namespace impl
    {
        inline rectangle flip_rect_left_right (
            const rectangle& rect,
            const rectangle& window
        )
        {
            rectangle temp;
            temp.top() = rect.top();
            temp.bottom() = rect.bottom();

            const long left_dist = rect.left()-window.left();

            temp.right() = window.right()-left_dist;
            temp.left()  = temp.right()-rect.width()+1;
            return temp;
        }

        inline rectangle tform_object (
            const point_transform_affine& tran,
            const rectangle& rect
        )
        {
            return centered_rect(tran(center(rect)), rect.width(), rect.height());
        }

        inline full_object_detection tform_object(
            const point_transform_affine& tran,
            const full_object_detection& obj
        )
        {
            std::vector<point> parts;
            parts.reserve(obj.num_parts());
            for (unsigned long i = 0; i < obj.num_parts(); ++i)
            {
                parts.push_back(tran(obj.part(i)));
            }
            return full_object_detection(tform_object(tran,obj.get_rect()), parts);
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_array_type,
        typename T
        >
    void add_image_left_right_flips (
        image_array_type& images,
        std::vector<std::vector<T> >& objects
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( images.size() == objects.size(),
            "\t void add_image_left_right_flips()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t images.size():  " << images.size()
            << "\n\t objects.size(): " << objects.size()
            );

        typename image_array_type::value_type temp;
        std::vector<T> rects;

        const unsigned long num = images.size();
        for (unsigned long j = 0; j < num; ++j)
        {
            const point_transform_affine tran = flip_image_left_right(images[j], temp);

            rects.clear();
            for (unsigned long i = 0; i < objects[j].size(); ++i)
                rects.push_back(impl::tform_object(tran, objects[j][i]));

            images.push_back(temp);
            objects.push_back(rects);
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_array_type,
        typename T,
        typename U
        >
    void add_image_left_right_flips (
        image_array_type& images,
        std::vector<std::vector<T> >& objects,
        std::vector<std::vector<U> >& objects2
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( images.size() == objects.size() &&
                     images.size() == objects2.size(),
            "\t void add_image_left_right_flips()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t images.size():   " << images.size()
            << "\n\t objects.size():  " << objects.size()
            << "\n\t objects2.size(): " << objects2.size()
            );

        typename image_array_type::value_type temp;
        std::vector<T> rects;
        std::vector<U> rects2;

        const unsigned long num = images.size();
        for (unsigned long j = 0; j < num; ++j)
        {
            const point_transform_affine tran = flip_image_left_right(images[j], temp);
            images.push_back(temp);

            rects.clear();
            for (unsigned long i = 0; i < objects[j].size(); ++i)
                rects.push_back(impl::tform_object(tran, objects[j][i]));
            objects.push_back(rects);

            rects2.clear();
            for (unsigned long i = 0; i < objects2[j].size(); ++i)
                rects2.push_back(impl::tform_object(tran, objects2[j][i]));
            objects2.push_back(rects2);
        }
    }

// ----------------------------------------------------------------------------------------

    template <typename image_array_type>
    void flip_image_dataset_left_right (
        image_array_type& images,
        std::vector<std::vector<rectangle> >& objects
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( images.size() == objects.size(),
            "\t void flip_image_dataset_left_right()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t images.size():   " << images.size()
            << "\n\t objects.size():  " << objects.size()
            );

        typename image_array_type::value_type temp;
        for (unsigned long i = 0; i < images.size(); ++i)
        {
            flip_image_left_right(images[i], temp);
            swap(temp,images[i]);
            for (unsigned long j = 0; j < objects[i].size(); ++j)
            {
                objects[i][j] = impl::flip_rect_left_right(objects[i][j], get_rect(images[i]));
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <typename image_array_type>
    void flip_image_dataset_left_right (
        image_array_type& images,
        std::vector<std::vector<rectangle> >& objects,
        std::vector<std::vector<rectangle> >& objects2
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( images.size() == objects.size() &&
                     images.size() == objects2.size(),
            "\t void flip_image_dataset_left_right()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t images.size():   " << images.size()
            << "\n\t objects.size():  " << objects.size()
            << "\n\t objects2.size(): " << objects2.size()
            );

        typename image_array_type::value_type temp;
        for (unsigned long i = 0; i < images.size(); ++i)
        {
            flip_image_left_right(images[i], temp);
            swap(temp, images[i]);
            for (unsigned long j = 0; j < objects[i].size(); ++j)
            {
                objects[i][j] = impl::flip_rect_left_right(objects[i][j], get_rect(images[i]));
            }
            for (unsigned long j = 0; j < objects2[i].size(); ++j)
            {
                objects2[i][j] = impl::flip_rect_left_right(objects2[i][j], get_rect(images[i]));
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename pyramid_type,
        typename image_array_type
        >
    void upsample_image_dataset (
        image_array_type& images,
        std::vector<std::vector<rectangle> >& objects
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( images.size() == objects.size(),
            "\t void upsample_image_dataset()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t images.size():   " << images.size()
            << "\n\t objects.size():  " << objects.size()
            );

        typename image_array_type::value_type temp;
        pyramid_type pyr;
        for (unsigned long i = 0; i < images.size(); ++i)
        {
            pyramid_up(images[i], temp, pyr);
            swap(temp, images[i]);
            for (unsigned long j = 0; j < objects[i].size(); ++j)
            {
                objects[i][j] = pyr.rect_up(objects[i][j]);
            }
        }
    }

    template <
        typename pyramid_type,
        typename image_array_type
        >
    void upsample_image_dataset (
        image_array_type& images,
        std::vector<std::vector<rectangle> >& objects,
        std::vector<std::vector<rectangle> >& objects2
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( images.size() == objects.size() &&
                     images.size() == objects2.size(),
            "\t void upsample_image_dataset()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t images.size():   " << images.size()
            << "\n\t objects.size():  " << objects.size()
            << "\n\t objects2.size(): " << objects2.size()
            );

        typename image_array_type::value_type temp;
        pyramid_type pyr;
        for (unsigned long i = 0; i < images.size(); ++i)
        {
            pyramid_up(images[i], temp, pyr);
            swap(temp, images[i]);
            for (unsigned long j = 0; j < objects[i].size(); ++j)
            {
                objects[i][j] = pyr.rect_up(objects[i][j]);
            }
            for (unsigned long j = 0; j < objects2[i].size(); ++j)
            {
                objects2[i][j] = pyr.rect_up(objects2[i][j]);
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <typename image_array_type>
    void rotate_image_dataset (
        double angle,
        image_array_type& images,
        std::vector<std::vector<rectangle> >& objects
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( images.size() == objects.size(),
            "\t void rotate_image_dataset()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t images.size():   " << images.size()
            << "\n\t objects.size():  " << objects.size()
            );

        typename image_array_type::value_type temp;
        for (unsigned long i = 0; i < images.size(); ++i)
        {
            const point_transform_affine tran = rotate_image(images[i], temp, angle);
            swap(temp, images[i]);
            for (unsigned long j = 0; j < objects[i].size(); ++j)
            {
                const rectangle rect = objects[i][j];
                objects[i][j] = centered_rect(tran(center(rect)), rect.width(), rect.height());
            }
        }
    }

    template <typename image_array_type>
    void rotate_image_dataset (
        double angle,
        image_array_type& images,
        std::vector<std::vector<rectangle> >& objects,
        std::vector<std::vector<rectangle> >& objects2
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( images.size() == objects.size() &&
                     images.size() == objects2.size(),
            "\t void rotate_image_dataset()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t images.size():   " << images.size()
            << "\n\t objects.size():  " << objects.size()
            << "\n\t objects2.size(): " << objects2.size()
            );

        typename image_array_type::value_type temp;
        for (unsigned long i = 0; i < images.size(); ++i)
        {
            const point_transform_affine tran = rotate_image(images[i], temp, angle);
            swap(temp, images[i]);
            for (unsigned long j = 0; j < objects[i].size(); ++j)
            {
                const rectangle rect = objects[i][j];
                objects[i][j] = centered_rect(tran(center(rect)), rect.width(), rect.height());
            }
            for (unsigned long j = 0; j < objects2[i].size(); ++j)
            {
                const rectangle rect = objects2[i][j];
                objects2[i][j] = centered_rect(tran(center(rect)), rect.width(), rect.height());
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_array_type,
        typename EXP,
        typename T,
        typename U
        >
    void add_image_rotations (
        const matrix_exp<EXP>& angles,
        image_array_type& images,
        std::vector<std::vector<T> >& objects,
        std::vector<std::vector<U> >& objects2
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( is_vector(angles) && angles.size() > 0 &&
                     images.size() == objects.size() &&
                     images.size() == objects2.size(),
            "\t void add_image_rotations()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t is_vector(angles): " << is_vector(angles)
            << "\n\t angles.size():     " << angles.size()
            << "\n\t images.size():     " << images.size()
            << "\n\t objects.size():    " << objects.size()
            << "\n\t objects2.size():   " << objects2.size()
            );

        image_array_type new_images;
        std::vector<std::vector<T> > new_objects;
        std::vector<std::vector<U> > new_objects2;

        using namespace impl;

        std::vector<T> objtemp;
        std::vector<U> objtemp2;
        typename image_array_type::value_type temp;
        for (long i = 0; i < angles.size(); ++i)
        {
            for (unsigned long j = 0; j < images.size(); ++j)
            {
                const point_transform_affine tran = rotate_image(images[j], temp, angles(i));
                new_images.push_back(temp);

                objtemp.clear();
                for (unsigned long k = 0; k < objects[j].size(); ++k)
                    objtemp.push_back(tform_object(tran, objects[j][k]));
                new_objects.push_back(objtemp);

                objtemp2.clear();
                for (unsigned long k = 0; k < objects2[j].size(); ++k)
                    objtemp2.push_back(tform_object(tran, objects2[j][k]));
                new_objects2.push_back(objtemp2);
            }
        }

        new_images.swap(images);
        new_objects.swap(objects);
        new_objects2.swap(objects2);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_array_type,
        typename EXP,
        typename T
        >
    void add_image_rotations (
        const matrix_exp<EXP>& angles,
        image_array_type& images,
        std::vector<std::vector<T> >& objects
    )
    {
        std::vector<std::vector<T> > objects2(objects.size());
        add_image_rotations(angles, images, objects, objects2);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename image_type1,
        typename image_type2,
        typename pyramid_type,
        typename interpolation_type
        >
    void pyramid_up (
        const image_type1& in_img,
        image_type2& out_img,
        const pyramid_type& pyr,
        const interpolation_type& interp
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( is_same_object(in_img, out_img) == false ,
            "\t void pyramid_up()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t is_same_object(in_img, out_img):  " << is_same_object(in_img, out_img)
            );

        if (image_size(in_img) == 0)
        {
            set_image_size(out_img, 0, 0);
            return;
        }

        rectangle rect = get_rect(in_img);
        rectangle uprect = pyr.rect_up(rect);
        if (uprect.is_empty())
        {
            set_image_size(out_img, 0, 0);
            return;
        }
        set_image_size(out_img, uprect.bottom()+1, uprect.right()+1);

        resize_image(in_img, out_img, interp);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_type1,
        typename image_type2,
        typename pyramid_type
        >
    void pyramid_up (
        const image_type1& in_img,
        image_type2& out_img,
        const pyramid_type& pyr
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( is_same_object(in_img, out_img) == false ,
            "\t void pyramid_up()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t is_same_object(in_img, out_img):  " << is_same_object(in_img, out_img)
            );

        pyramid_up(in_img, out_img, pyr, interpolate_bilinear());
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_type,
        typename pyramid_type
        >
    void pyramid_up (
        image_type& img,
        const pyramid_type& pyr
    )
    {
        image_type temp;
        pyramid_up(img, temp, pyr);
        swap(temp, img);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    void pyramid_up (
        image_type& img
    )
    {
        pyramid_down<2> pyr;
        pyramid_up(img, pyr);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    struct chip_dims
    {
        chip_dims (
            unsigned long rows_,
            unsigned long cols_
        ) : rows(rows_), cols(cols_) { }

        unsigned long rows;
        unsigned long cols;
    };

    struct chip_details
    {
        chip_details() : angle(0), rows(0), cols(0) {}
        chip_details(const rectangle& rect_) : rect(rect_),angle(0), rows(rect_.height()), cols(rect_.width()) {}
        chip_details(const drectangle& rect_) : rect(rect_),angle(0),
          rows((unsigned long)(rect_.height()+0.5)), cols((unsigned long)(rect_.width()+0.5)) {}
        chip_details(const drectangle& rect_, unsigned long size) : rect(rect_),angle(0)
        { compute_dims_from_size(size); }
        chip_details(const drectangle& rect_, unsigned long size, double angle_) : rect(rect_),angle(angle_)
        { compute_dims_from_size(size); }

        chip_details(const drectangle& rect_, const chip_dims& dims) :
            rect(rect_),angle(0),rows(dims.rows), cols(dims.cols) {}
        chip_details(const drectangle& rect_, const chip_dims& dims, double angle_) :
            rect(rect_),angle(angle_),rows(dims.rows), cols(dims.cols) {}

        template <typename T>
        chip_details(
            const std::vector<dlib::vector<T,2> >& chip_points,
            const std::vector<dlib::vector<T,2> >& img_points,
            const chip_dims& dims
        ) :
            rows(dims.rows), cols(dims.cols)
        {
            DLIB_CASSERT( chip_points.size() == img_points.size() && chip_points.size() >= 2,
                "\t chip_details::chip_details(chip_points,img_points,dims)"
                << "\n\t Invalid inputs were given to this function."
                << "\n\t chip_points.size(): " << chip_points.size()
                << "\n\t img_points.size():  " << img_points.size()
            );

            const point_transform_affine tform = find_similarity_transform(chip_points,img_points);
            dlib::vector<double,2> p(1,0);
            p = tform.get_m()*p;

            // There are only 3 things happening in a similarity transform.  There is a
            // rescaling, a rotation, and a translation.  So here we pick out the scale and
            // rotation parameters.
            angle = std::atan2(p.y(),p.x());
            // Note that the translation and scale part are represented by the extraction
            // rectangle.  So here we build the appropriate rectangle.
            const double scale = length(p);
            rect = centered_drect(tform(point(dims.cols,dims.rows)/2.0),
                                  dims.cols*scale,
                                  dims.rows*scale);
        }

        drectangle rect;
        double angle;
        unsigned long rows;
        unsigned long cols;

        inline unsigned long size() const
        {
            return rows*cols;
        }

    private:
        void compute_dims_from_size (
            unsigned long size
        )
        {
            const double relative_size = std::sqrt(size/(double)rect.area());
            rows = static_cast<unsigned long>(rect.height()*relative_size + 0.5);
            cols  = static_cast<unsigned long>(size/(double)rows + 0.5);
            rows = std::max(1ul,rows);
            cols = std::max(1ul,cols);
        }
    };

// ----------------------------------------------------------------------------------------

    inline point_transform_affine get_mapping_to_chip (
        const chip_details& details
    )
    {
        std::vector<dlib::vector<double,2> > from, to;
        point p1(0,0);
        point p2(details.cols-1,0);
        point p3(details.cols-1, details.rows-1);
        to.push_back(p1);
        from.push_back(rotate_point<double>(center(details.rect),details.rect.tl_corner(),details.angle));
        to.push_back(p2);
        from.push_back(rotate_point<double>(center(details.rect),details.rect.tr_corner(),details.angle));
        to.push_back(p3);
        from.push_back(rotate_point<double>(center(details.rect),details.rect.br_corner(),details.angle));
        return find_affine_transform(from, to);
    }

// ----------------------------------------------------------------------------------------

    inline full_object_detection map_det_to_chip(
        const full_object_detection& det,
        const chip_details& details
    )
    {
        point_transform_affine tform = get_mapping_to_chip(details);
        full_object_detection res(det);
        // map the parts
        for (unsigned long l = 0; l < det.num_parts(); ++l)
            res.part(l) = tform(det.part(l));
        // map the main rectangle
        rectangle rect;
        rect += tform(det.get_rect().tl_corner());
        rect += tform(det.get_rect().tr_corner());
        rect += tform(det.get_rect().bl_corner());
        rect += tform(det.get_rect().br_corner());
        res.get_rect() = rect;
        return res;
    }

// ----------------------------------------------------------------------------------------

    namespace impl
    {
        template <
            typename image_type1,
            typename image_type2
            >
        void basic_extract_image_chip (
            const image_type1& img,
            const rectangle& location,
            image_type2& chip
        )
        /*!
            ensures
                - This function doesn't do any scaling or rotating. It just pulls out the
                  chip in the given rectangle.  This also means the output image has the
                  same dimensions as the location rectangle.
        !*/
        {
            const_image_view<image_type1> vimg(img);
            image_view<image_type2> vchip(chip);

            vchip.set_size(location.height(), location.width());

            // location might go outside img so clip it
            rectangle area = location.intersect(get_rect(img));

            // find the part of the chip that corresponds to area in img.
            rectangle chip_area = translate_rect(area, -location.tl_corner());

            zero_border_pixels(chip, chip_area);
            // now pull out the contents of area/chip_area.
            for (long r = chip_area.top(), rr = area.top(); r <= chip_area.bottom(); ++r,++rr)
            {
                for (long c = chip_area.left(), cc = area.left(); c <= chip_area.right(); ++c,++cc)
                {
                    assign_pixel(vchip[r][c], vimg[rr][cc]);
                }
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_type1,
        typename image_type2
        >
    void extract_image_chips (
        const image_type1& img,
        const std::vector<chip_details>& chip_locations,
        dlib::array<image_type2>& chips
    )
    {
        // make sure requires clause is not broken
#ifdef ENABLE_ASSERTS
        for (unsigned long i = 0; i < chip_locations.size(); ++i)
        {
            DLIB_CASSERT(chip_locations[i].size() != 0 &&
                         chip_locations[i].rect.is_empty() == false,
            "\t void extract_image_chips()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t chip_locations["<<i<<"].size():            " << chip_locations[i].size()
            << "\n\t chip_locations["<<i<<"].rect.is_empty(): " << chip_locations[i].rect.is_empty()
            );
        }
#endif

        pyramid_down<2> pyr;
        long max_depth = 0;
        // If the chip is supposed to be much smaller than the source subwindow then you
        // can't just extract it using bilinear interpolation since at a high enough
        // downsampling amount it would effectively turn into nearest neighbor
        // interpolation.  So we use an image pyramid to make sure the interpolation is
        // fast but also high quality.  The first thing we do is figure out how deep the
        // image pyramid needs to be.
        rectangle bounding_box;
        for (unsigned long i = 0; i < chip_locations.size(); ++i)
        {
            long depth = 0;
            double grow = 2;
            drectangle rect = pyr.rect_down(chip_locations[i].rect);
            while (rect.area() > chip_locations[i].size())
            {
                rect = pyr.rect_down(rect);
                ++depth;
                // We drop the image size by a factor of 2 each iteration and then assume a
                // border of 2 pixels is needed to avoid any border effects of the crop.
                grow = grow*2 + 2;
            }
            drectangle rot_rect;
            const vector<double,2> cent = center(chip_locations[i].rect);
            rot_rect += rotate_point<double>(cent,chip_locations[i].rect.tl_corner(),chip_locations[i].angle);
            rot_rect += rotate_point<double>(cent,chip_locations[i].rect.tr_corner(),chip_locations[i].angle);
            rot_rect += rotate_point<double>(cent,chip_locations[i].rect.bl_corner(),chip_locations[i].angle);
            rot_rect += rotate_point<double>(cent,chip_locations[i].rect.br_corner(),chip_locations[i].angle);
            bounding_box += grow_rect(rot_rect, grow).intersect(get_rect(img));
            max_depth = std::max(depth,max_depth);
        }
        //std::cout << "max_depth: " << max_depth << std::endl;
        //std::cout << "crop amount: " << bounding_box.area()/(double)get_rect(img).area() << std::endl;

        // now make an image pyramid
        dlib::array<array2d<typename image_traits<image_type1>::pixel_type> > levels(max_depth);
        if (levels.size() != 0)
            pyr(sub_image(img,bounding_box),levels[0]);
        for (unsigned long i = 1; i < levels.size(); ++i)
            pyr(levels[i-1],levels[i]);

        std::vector<dlib::vector<double,2> > from, to;

        // now pull out the chips
        chips.resize(chip_locations.size());
        for (unsigned long i = 0; i < chips.size(); ++i)
        {
            // If the chip doesn't have any rotation or scaling then use the basic version
            // of chip extraction that just does a fast copy.
            if (chip_locations[i].angle == 0 &&
                chip_locations[i].rows == chip_locations[i].rect.height() &&
                chip_locations[i].cols == chip_locations[i].rect.width())
            {
                impl::basic_extract_image_chip(img, chip_locations[i].rect, chips[i]);
            }
            else
            {
                set_image_size(chips[i], chip_locations[i].rows, chip_locations[i].cols);

                // figure out which level in the pyramid to use to extract the chip
                int level = -1;
                drectangle rect = translate_rect(chip_locations[i].rect, -bounding_box.tl_corner());
                while (pyr.rect_down(rect).area() > chip_locations[i].size())
                {
                    ++level;
                    rect = pyr.rect_down(rect);
                }

                // find the appropriate transformation that maps from the chip to the input
                // image
                from.clear();
                to.clear();
                from.push_back(get_rect(chips[i]).tl_corner());  to.push_back(rotate_point<double>(center(rect),rect.tl_corner(),chip_locations[i].angle));
                from.push_back(get_rect(chips[i]).tr_corner());  to.push_back(rotate_point<double>(center(rect),rect.tr_corner(),chip_locations[i].angle));
                from.push_back(get_rect(chips[i]).bl_corner());  to.push_back(rotate_point<double>(center(rect),rect.bl_corner(),chip_locations[i].angle));
                point_transform_affine trns = find_affine_transform(from,to);

                // now extract the actual chip
                if (level == -1)
                    transform_image(sub_image(img,bounding_box),chips[i],interpolate_bilinear(),trns);
                else
                    transform_image(levels[level],chips[i],interpolate_bilinear(),trns);
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_type1,
        typename image_type2
        >
    void extract_image_chip (
        const image_type1& img,
        const chip_details& location,
        image_type2& chip
    )
    {
        // If the chip doesn't have any rotation or scaling then use the basic version of
        // chip extraction that just does a fast copy.
        if (location.angle == 0 &&
            location.rows == location.rect.height() &&
            location.cols == location.rect.width())
        {
            impl::basic_extract_image_chip(img, location.rect, chip);
        }
        else
        {
            std::vector<chip_details> chip_locations(1,location);
            dlib::array<image_type2> chips;
            extract_image_chips(img, chip_locations, chips);
            swap(chips[0], chip);
        }
    }

// ----------------------------------------------------------------------------------------

    inline chip_details get_face_chip_details (
        const full_object_detection& det,
        const unsigned long size = 200,
        const double padding = 0.2
    )
    {
        DLIB_CASSERT(det.num_parts() == 68,
            "\t chip_details get_face_chip_details()"
            << "\n\t You must give a detection with exactly 68 parts in it."
            << "\n\t det.num_parts(): " << det.num_parts()
        );
        DLIB_CASSERT(padding >= 0 && size > 0,
            "\t chip_details get_face_chip_details()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t padding: " << padding
            << "\n\t size:    " << size
            );

        // Average positions of face points 17-67
        const double mean_face_shape_x[] = {
            0.000213256, 0.0752622, 0.18113, 0.29077, 0.393397, 0.586856, 0.689483, 0.799124,
            0.904991, 0.98004, 0.490127, 0.490127, 0.490127, 0.490127, 0.36688, 0.426036,
            0.490127, 0.554217, 0.613373, 0.121737, 0.187122, 0.265825, 0.334606, 0.260918,
            0.182743, 0.645647, 0.714428, 0.793132, 0.858516, 0.79751, 0.719335, 0.254149,
            0.340985, 0.428858, 0.490127, 0.551395, 0.639268, 0.726104, 0.642159, 0.556721,
            0.490127, 0.423532, 0.338094, 0.290379, 0.428096, 0.490127, 0.552157, 0.689874,
            0.553364, 0.490127, 0.42689
        };
        const double mean_face_shape_y[] = {
            0.106454, 0.038915, 0.0187482, 0.0344891, 0.0773906, 0.0773906, 0.0344891,
            0.0187482, 0.038915, 0.106454, 0.203352, 0.307009, 0.409805, 0.515625, 0.587326,
            0.609345, 0.628106, 0.609345, 0.587326, 0.216423, 0.178758, 0.179852, 0.231733,
            0.245099, 0.244077, 0.231733, 0.179852, 0.178758, 0.216423, 0.244077, 0.245099,
            0.780233, 0.745405, 0.727388, 0.742578, 0.727388, 0.745405, 0.780233, 0.864805,
            0.902192, 0.909281, 0.902192, 0.864805, 0.784792, 0.778746, 0.785343, 0.778746,
            0.784792, 0.824182, 0.831803, 0.824182
        };

        COMPILE_TIME_ASSERT(sizeof(mean_face_shape_x)/sizeof(double) == 68-17);

        std::vector<dlib::vector<double,2> > from_points, to_points;
        for (unsigned long i = 17; i < det.num_parts(); ++i)
        {
            // Ignore the lower lip
            if ((55 <= i && i <= 59) || (65 <= i && i <= 67))
                continue;
            // Ignore the eyebrows
            if (17 <= i && i <= 26)
                continue;

            dlib::vector<double,2> p;
            p.x() = (padding+mean_face_shape_x[i-17])/(2*padding+1);
            p.y() = (padding+mean_face_shape_y[i-17])/(2*padding+1);
            from_points.push_back(p*size);
            to_points.push_back(det.part(i));
        }

        return chip_details(from_points, to_points, chip_dims(size,size));
    }

// ----------------------------------------------------------------------------------------

    inline std::vector<chip_details> get_face_chip_details (
        const std::vector<full_object_detection>& dets,
        const unsigned long size = 200,
        const double padding = 0.2
    )
    {
        std::vector<chip_details> res;
        res.reserve(dets.size());
        for (unsigned long i = 0; i < dets.size(); ++i)
            res.push_back(get_face_chip_details(dets[i], size, padding));
        return res;
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_INTERPOlATIONh_


dlib C++ Library - label_connected_blobs.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_LABEL_CONNeCTED_BLOBS_H_
#define DLIB_LABEL_CONNeCTED_BLOBS_H_

#include "label_connected_blobs_abstract.h"
#include "../geometry.h"
#include <stack>
#include <vector>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    struct neighbors_8
    {
        void operator() (
            const point& p,
            std::vector<point>& neighbors
        ) const
        {
            neighbors.push_back(point(p.x()+1,p.y()+1));
            neighbors.push_back(point(p.x()+1,p.y()  ));
            neighbors.push_back(point(p.x()+1,p.y()-1));

            neighbors.push_back(point(p.x(),p.y()+1));
            neighbors.push_back(point(p.x(),p.y()-1));

            neighbors.push_back(point(p.x()-1,p.y()+1));
            neighbors.push_back(point(p.x()-1,p.y()  ));
            neighbors.push_back(point(p.x()-1,p.y()-1));
        }
    };

    struct neighbors_4
    {
        void operator() (
            const point& p,
            std::vector<point>& neighbors
        ) const
        {
            neighbors.push_back(point(p.x()+1,p.y()));
            neighbors.push_back(point(p.x()-1,p.y()));
            neighbors.push_back(point(p.x(),p.y()+1));
            neighbors.push_back(point(p.x(),p.y()-1));
        }
    };

// ----------------------------------------------------------------------------------------

    struct connected_if_both_not_zero
    {
        template <typename image_type>
        bool operator() (
            const image_type& img,
            const point& a,
            const point& b
        ) const
        {
            return (img[a.y()][a.x()] != 0 && img[b.y()][b.x()] != 0);
        }
    };

    struct connected_if_equal
    {
        template <typename image_type>
        bool operator() (
            const image_type& img,
            const point& a,
            const point& b
        ) const
        {
            return (img[a.y()][a.x()] == img[b.y()][b.x()]);
        }
    };

// ----------------------------------------------------------------------------------------

    struct zero_pixels_are_background
    {
        template <typename image_type>
        bool operator() (
            const image_type& img,
            const point& p
        ) const
        {
            return img[p.y()][p.x()] == 0;
        }

    };

    struct nothing_is_background
    {
        template <typename image_type>
        bool operator() (
            const image_type&,
            const point&
        ) const
        {
            return false;
        }

    };

// ----------------------------------------------------------------------------------------

    template <
        typename image_type,
        typename label_image_type,
        typename background_functor_type,
        typename neighbors_functor_type,
        typename connected_functor_type
        >
    unsigned long label_connected_blobs (
        const image_type& img_,
        const background_functor_type& is_background,
        const neighbors_functor_type&  get_neighbors,
        const connected_functor_type&  is_connected,
        label_image_type& label_img_
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(is_same_object(img_, label_img_) == false,
            "\t unsigned long label_connected_blobs()"
            << "\n\t The input image and output label image can't be the same object."
            );

        const_image_view<image_type> img(img_);
        image_view<label_image_type> label_img(label_img_);

        std::stack<point> neighbors;
        label_img.set_size(img.nr(), img.nc());
        assign_all_pixels(label_img, 0);
        unsigned long next = 1;

        if (img.size() == 0)
            return 0;

        const rectangle area = get_rect(img);

        std::vector<point> window;

        for (long r = 0; r < img.nr(); ++r)
        {
            for (long c = 0; c < img.nc(); ++c)
            {
                // skip already labeled pixels or background pixels
                if (label_img[r][c] != 0 || is_background(img,point(c,r)))
                    continue;

                label_img[r][c] = next;

                // label all the neighbors of this point
                neighbors.push(point(c,r));
                while (neighbors.size() > 0)
                {
                    const point p = neighbors.top();
                    neighbors.pop();

                    window.clear();
                    get_neighbors(p, window);

                    for (unsigned long i = 0; i < window.size(); ++i)
                    {
                        if (area.contains(window[i]) &&                     // point in image.
                            !is_background(img,window[i]) &&                // isn't background.
                            label_img[window[i].y()][window[i].x()] == 0 && // haven't already labeled it.
                            is_connected(img, p, window[i]))                // it's connected.
                        {
                            label_img[window[i].y()][window[i].x()] = next;
                            neighbors.push(window[i]);
                        }
                    }
                }

                ++next;
            }
        }

        return next;
    }
// ----------------------------------------------------------------------------------------

}

#endif // DLIB_LABEL_CONNeCTED_BLOBS_H_


dlib C++ Library - lbp.h

// Copyright (C) 2014  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_LBP_Hh_
#define DLIB_LBP_Hh_

#include "lbp_abstract.h"
#include "../image_processing/generic_image.h"
#include "assign_image.h"
#include "../pixel.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename image_type,
        typename image_type2
        >
    void make_uniform_lbp_image (
        const image_type& img_,
        image_type2& lbp_
    )
    {
        const static unsigned char uniform_lbps[] = {
            0, 1, 2, 3, 4, 58, 5, 6, 7, 58, 58, 58, 8, 58, 9, 10, 11, 58, 58, 58, 58, 58,
            58, 58, 12, 58, 58, 58, 13, 58, 14, 15, 16, 58, 58, 58, 58, 58, 58, 58, 58, 58,
            58, 58, 58, 58, 58, 58, 17, 58, 58, 58, 58, 58, 58, 58, 18, 58, 58, 58, 19, 58,
            20, 21, 22, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
            58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 23, 58, 58, 58, 58, 58,
            58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 24, 58, 58, 58, 58, 58, 58, 58, 25, 58,
            58, 58, 26, 58, 27, 28, 29, 30, 58, 31, 58, 58, 58, 32, 58, 58, 58, 58, 58, 58,
            58, 33, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 34, 58, 58,
            58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
            58, 58, 58, 58, 58, 58, 58, 58, 58, 35, 36, 37, 58, 38, 58, 58, 58, 39, 58, 58,
            58, 58, 58, 58, 58, 40, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
            58, 41, 42, 43, 58, 44, 58, 58, 58, 45, 58, 58, 58, 58, 58, 58, 58, 46, 47, 48,
            58, 49, 58, 58, 58, 50, 51, 52, 58, 53, 54, 55, 56, 57
        };

        COMPILE_TIME_ASSERT(sizeof(uniform_lbps) == 256);

        const_image_view<image_type> img(img_);
        image_view<image_type2> lbp(lbp_);

        lbp.set_size(img.nr(), img.nc());

        // set all the border pixels to the "non-uniform LBP value".
        assign_border_pixels(lbp, 1, 1, 58);

        typedef typename image_traits<image_type>::pixel_type pixel_type;
        typedef typename pixel_traits<pixel_type>::basic_pixel_type basic_pixel_type;

        for (long r = 1; r+1 < img.nr(); ++r)
        {
            for (long c = 1; c+1 < img.nc(); ++c)
            {
                const basic_pixel_type pix = get_pixel_intensity(img[r][c]);
                unsigned char b1 = 0;
                unsigned char b2 = 0;
                unsigned char b3 = 0;
                unsigned char b4 = 0;
                unsigned char b5 = 0;
                unsigned char b6 = 0;
                unsigned char b7 = 0;
                unsigned char b8 = 0;

                unsigned char x = 0;
                if (get_pixel_intensity(img[r-1][c-1]) > pix) b1 = 0x80;
                if (get_pixel_intensity(img[r-1][c  ]) > pix) b2 = 0x40;
                if (get_pixel_intensity(img[r-1][c+1]) > pix) b3 = 0x20;
                x |= b1;
                if (get_pixel_intensity(img[r  ][c-1]) > pix) b4 = 0x10;
                x |= b2;
                if (get_pixel_intensity(img[r  ][c+1]) > pix) b5 = 0x08;
                x |= b3;
                if (get_pixel_intensity(img[r+1][c-1]) > pix) b6 = 0x04;
                x |= b4;
                if (get_pixel_intensity(img[r+1][c  ]) > pix) b7 = 0x02;
                x |= b5;
                if (get_pixel_intensity(img[r+1][c+1]) > pix) b8 = 0x01;

                x |= b6;
                x |= b7;
                x |= b8;

                lbp[r][c] = uniform_lbps[x];
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_type,
        typename T
        >
    void extract_histogram_descriptors (
        const image_type& img_,
        const point& loc,
        std::vector<T>& histograms,
        const unsigned int cell_size = 10,
        const unsigned int block_size = 4,
        const unsigned int max_val = 58
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(cell_size >= 1 && block_size >= 1 && max_val < 256 &&
                    (unsigned int)max(mat(img_)) <= max_val,
            "\t void extract_histogram_descriptors()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t cell_size:      " << cell_size
            << "\n\t block_size:     " << block_size
            << "\n\t max_val:        " << max_val
            << "\n\t max(mat(img_)): " << max(mat(img_))
            );

        typedef typename image_traits<image_type>::pixel_type pixel_type;
        COMPILE_TIME_ASSERT((is_same_type<pixel_type, unsigned char>::value));

        const_image_view<image_type> img(img_);

        const rectangle area = get_rect(img);
        const rectangle window = centered_rect(loc, block_size*cell_size, block_size*cell_size);
        unsigned int cell_top = window.top();
        for (unsigned int br = 0; br < block_size; ++br)
        {
            unsigned int cell_left = window.left();
            for (unsigned int bc = 0; bc < block_size; ++bc)
            {
                // figure out the cell boundaries
                rectangle cell(cell_left, cell_top, cell_left+cell_size-1, cell_top+cell_size-1);
                cell = cell.intersect(area);

                // make the actual histogram for this cell
                unsigned int hist[256] = {0};
                for (long r = cell.top(); r <= cell.bottom(); ++r)
                {
                    for (long c = cell.left(); c <= cell.right(); ++c)
                    {
                        hist[img[r][c]]++;
                    }
                }

                // copy histogram into the output.
                histograms.insert(histograms.end(), hist, hist + max_val+1);

                cell_left += cell_size;
            }
            cell_top += cell_size;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_type,
        typename T
        >
    void extract_uniform_lbp_descriptors (
        const image_type& img,
        std::vector<T>& feats,
        const unsigned int cell_size = 10
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(cell_size >= 1,
            "\t void extract_uniform_lbp_descriptors()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t cell_size:      " << cell_size
            );

        feats.clear();
        array2d<unsigned char> lbp;
        make_uniform_lbp_image(img, lbp);
        for (long r = 0; r < lbp.nr(); r+=cell_size)
        {
            for (long c = 0; c < lbp.nc(); c+=cell_size)
            {
                const rectangle cell = rectangle(c,r,c+cell_size-1,r+cell_size-1).intersect(get_rect(lbp));
                // make the actual histogram for this cell
                unsigned int hist[59] = {0};
                for (long r = cell.top(); r <= cell.bottom(); ++r)
                {
                    for (long c = cell.left(); c <= cell.right(); ++c)
                    {
                        hist[lbp[r][c]]++;
                    }
                }

                // copy histogram into the output.
                feats.insert(feats.end(), hist, hist + 59);
            }
        }

        for (unsigned long i = 0; i < feats.size(); ++i)
            feats[i] = std::sqrt(feats[i]);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_type,
        typename T
        >
    void extract_highdim_face_lbp_descriptors (
        const image_type& img,
        const full_object_detection& det,
        std::vector<T>& feats
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(det.num_parts() == 68,
            "\t void extract_highdim_face_lbp_descriptors()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t det.num_parts(): " << det.num_parts()
            );

        const unsigned long num_scales = 5;
        feats.clear();
        dlib::vector<double,2> l, r;
        double cnt = 0;
        // Find the center of the left eye by averaging the points around
        // the eye.
        for (unsigned long i = 36; i <= 41; ++i)
        {
            l += det.part(i);
            ++cnt;
        }
        l /= cnt;

        // Find the center of the right eye by averaging the points around
        // the eye.
        cnt = 0;
        for (unsigned long i = 42; i <= 47; ++i)
        {
            r += det.part(i);
            ++cnt;
        }
        r /= cnt;

        // We only do feature extraction from these face parts.  These are things like the
        // corners of the eyes and mouth and stuff like that.
        std::vector<point> parts;
        parts.reserve(30);
        parts.push_back(l);
        parts.push_back(r);
        parts.push_back(det.part(17));
        parts.push_back(det.part(21));
        parts.push_back(det.part(22));
        parts.push_back(det.part(26));
        parts.push_back(det.part(36));
        parts.push_back(det.part(39));
        parts.push_back(det.part(42));
        parts.push_back(det.part(45));
        parts.push_back(det.part(27));
        parts.push_back(det.part(28));
        parts.push_back(det.part(29));
        parts.push_back(det.part(30));
        parts.push_back(det.part(31));
        parts.push_back(det.part(35));
        parts.push_back(det.part(33));
        parts.push_back(det.part(48));
        parts.push_back(det.part(54));
        parts.push_back(det.part(51));
        parts.push_back(det.part(57));

        array2d<unsigned char> lbp;
        make_uniform_lbp_image(img, lbp);
        for (unsigned long i = 0; i < parts.size(); ++i)
            extract_histogram_descriptors(lbp, parts[i], feats);

        if (num_scales > 1)
        {
            pyramid_down<4> pyr;
            image_type img_temp;
            pyr(img, img_temp);
            unsigned long num_pyr_calls = 1;

            // now pull the features out at coarser scales
            for (unsigned long iter = 1; iter < num_scales; ++iter)
            {
                // now do the feature extraction
                make_uniform_lbp_image(img_temp, lbp);
                for (unsigned long i = 0; i < parts.size(); ++i)
                    extract_histogram_descriptors(lbp, pyr.point_down(parts[i],num_pyr_calls), feats);

                if (iter+1 < num_scales)
                {
                    pyr(img_temp);
                    ++num_pyr_calls;
                }
            }
        }

        for (unsigned long i = 0; i < feats.size(); ++i)
            feats[i] = std::sqrt(feats[i]);

        DLIB_ASSERT(feats.size() == 99120, feats.size());
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_LBP_Hh_


dlib C++ Library - morphological_operations.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MORPHOLOGICAL_OPERATIONs_
#define DLIB_MORPHOLOGICAL_OPERATIONs_

#include "../pixel.h"
#include "thresholding.h"
#include "morphological_operations_abstract.h"
#include "assign_image.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    namespace morphological_operations_helpers
    {
        template <typename image_type>
        bool is_binary_image (
            const image_type& img_
        )
        /*!
            ensures
                - returns true if img_ contains only on_pixel and off_pixel values.
                - returns false otherwise
        !*/
        {
            const_image_view<image_type> img(img_);
            for (long r = 0; r < img.nr(); ++r)
            {
                for (long c = 0; c < img.nc(); ++c)
                {
                    if (img[r][c] != on_pixel && img[r][c] != off_pixel)
                    {
                        return false;
                    }
                }
            }
            return true;
        }

        template <
            long M,
            long N
            >
        bool is_binary_image (
            const unsigned char (&structuring_element)[M][N]
        )
        /*!
            ensures
                - returns true if structuring_element contains only on_pixel and off_pixel values.
                - returns false otherwise
        !*/
        {
            for (long m = 0; m < M; ++m)
            {
                for (long n = 0; n < N; ++n)
                {
                    if (structuring_element[m][n] != on_pixel &&
                        structuring_element[m][n] != off_pixel)
                    {
                        return false;
                    }
                }
            }
            return true;
        }

    }

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type,
        long M,
        long N
        >
    void binary_dilation (
        const in_image_type& in_img_,
        out_image_type& out_img_,
        const unsigned char (&structuring_element)[M][N]
    )
    {
        typedef typename image_traits<in_image_type>::pixel_type in_pixel_type;
        typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;
        COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type>::has_alpha == false );
        COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::has_alpha == false );

        using namespace morphological_operations_helpers;
        COMPILE_TIME_ASSERT(M%2 == 1);
        COMPILE_TIME_ASSERT(N%2 == 1);
        DLIB_ASSERT(is_same_object(in_img_,out_img_) == false,
            "\tvoid binary_dilation()"
            << "\n\tYou must give two different image objects"
            );
        COMPILE_TIME_ASSERT(pixel_traits<in_pixel_type>::grayscale);
        DLIB_ASSERT(is_binary_image(in_img_) ,
            "\tvoid binary_dilation()"
            << "\n\tin_img must be a binary image"
            );
        DLIB_ASSERT(is_binary_image(structuring_element) ,
            "\tvoid binary_dilation()"
            << "\n\tthe structuring_element must be a binary image"
            );

        const_image_view<in_image_type> in_img(in_img_);
        image_view<out_image_type> out_img(out_img_);

        // if there isn't any input image then don't do anything
        if (in_img.size() == 0)
        {
            out_img.clear();
            return;
        }

        out_img.set_size(in_img.nr(),in_img.nc());

        // apply the filter to the image
        for (long r = 0; r < in_img.nr(); ++r)
        {
            for (long c = 0; c < in_img.nc(); ++c)
            {
                unsigned char out_pixel = off_pixel;
                for (long m = 0; m < M && out_pixel == off_pixel; ++m)
                {
                    for (long n = 0; n < N && out_pixel == off_pixel; ++n)
                    {
                        if (structuring_element[m][n] == on_pixel)
                        {
                            // if this pixel is inside the image then get it from the image
                            // but if it isn't just pretend it was an off_pixel value
                            if (r+m >= M/2 && c+n >= N/2 &&
                                r+m-M/2 < in_img.nr() && c+n-N/2 < in_img.nc())
                            {
                                out_pixel = in_img[r+m-M/2][c+n-N/2];
                            }
                        }
                    }
                }
                assign_pixel(out_img[r][c], out_pixel);
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type,
        long M,
        long N
        >
    void binary_erosion (
        const in_image_type& in_img_,
        out_image_type& out_img_,
        const unsigned char (&structuring_element)[M][N]
    )
    {
        typedef typename image_traits<in_image_type>::pixel_type in_pixel_type;
        typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;
        COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type>::has_alpha == false );
        COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::has_alpha == false );

        using namespace morphological_operations_helpers;
        COMPILE_TIME_ASSERT(M%2 == 1);
        COMPILE_TIME_ASSERT(N%2 == 1);
        DLIB_ASSERT(is_same_object(in_img_,out_img_) == false,
            "\tvoid binary_erosion()"
            << "\n\tYou must give two different image objects"
            );
        COMPILE_TIME_ASSERT(pixel_traits<in_pixel_type>::grayscale);
        DLIB_ASSERT(is_binary_image(in_img_) ,
            "\tvoid binary_erosion()"
            << "\n\tin_img must be a binary image"
            );
        DLIB_ASSERT(is_binary_image(structuring_element) ,
            "\tvoid binary_erosion()"
            << "\n\tthe structuring_element must be a binary image"
            );

        const_image_view<in_image_type> in_img(in_img_);
        image_view<out_image_type> out_img(out_img_);

        // if there isn't any input image then don't do anything
        if (in_img.size() == 0)
        {
            out_img.clear();
            return;
        }

        out_img.set_size(in_img.nr(),in_img.nc());

        // apply the filter to the image
        for (long r = 0; r < in_img.nr(); ++r)
        {
            for (long c = 0; c < in_img.nc(); ++c)
            {
                unsigned char out_pixel = on_pixel;
                for (long m = 0; m < M && out_pixel == on_pixel; ++m)
                {
                    for (long n = 0; n < N && out_pixel == on_pixel; ++n)
                    {
                        if (structuring_element[m][n] == on_pixel)
                        {
                            // if this pixel is inside the image then get it from the image
                            // but if it isn't just pretend it was an off_pixel value
                            if (r+m >= M/2 && c+n >= N/2 &&
                                r+m-M/2 < in_img.nr() && c+n-N/2 < in_img.nc())
                            {
                                out_pixel = in_img[r+m-M/2][c+n-N/2];
                            }
                            else
                            {
                                out_pixel = off_pixel;
                            }
                        }
                    }
                }
                assign_pixel(out_img[r][c], out_pixel);
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type,
        long M,
        long N
        >
    void binary_open (
        const in_image_type& in_img,
        out_image_type& out_img,
        const unsigned char (&structuring_element)[M][N],
        const unsigned long iter = 1
    )
    {
        typedef typename image_traits<in_image_type>::pixel_type in_pixel_type;
        typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;
        COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type>::has_alpha == false );
        COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::has_alpha == false );

        using namespace morphological_operations_helpers;
        COMPILE_TIME_ASSERT(M%2 == 1);
        COMPILE_TIME_ASSERT(N%2 == 1);
        DLIB_ASSERT(is_same_object(in_img,out_img) == false,
            "\tvoid binary_open()"
            << "\n\tYou must give two different image objects"
            );
        COMPILE_TIME_ASSERT(pixel_traits<in_pixel_type>::grayscale);
        DLIB_ASSERT(is_binary_image(in_img) ,
            "\tvoid binary_open()"
            << "\n\tin_img must be a binary image"
            );
        DLIB_ASSERT(is_binary_image(structuring_element) ,
            "\tvoid binary_open()"
            << "\n\tthe structuring_element must be a binary image"
            );

        // if there isn't any input image then don't do anything
        if (num_rows(in_img)*num_columns(in_img) == 0)
        {
            set_image_size(out_img, 0,0);
            return;
        }

        set_image_size(out_img, num_rows(in_img), num_columns(in_img));

        if (iter == 0)
        {
            // just copy the image over
            assign_image(out_img, in_img);
        }
        else if (iter == 1)
        {
            in_image_type temp;
            binary_erosion(in_img,temp,structuring_element);
            binary_dilation(temp,out_img,structuring_element);
        }
        else
        {
            in_image_type temp1, temp2;
            binary_erosion(in_img,temp1,structuring_element);

            // do the extra erosions
            for (unsigned long i = 1; i < iter; ++i)
            {
                swap(temp1, temp2);
                binary_erosion(temp2,temp1,structuring_element);
            }

            // do the extra dilations
            for (unsigned long i = 1; i < iter; ++i)
            {
                swap(temp1, temp2);
                binary_dilation(temp2,temp1,structuring_element);
            }

            binary_dilation(temp1,out_img,structuring_element);
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type,
        long M,
        long N
        >
    void binary_close (
        const in_image_type& in_img,
        out_image_type& out_img,
        const unsigned char (&structuring_element)[M][N],
        const unsigned long iter = 1
    )
    {
        typedef typename image_traits<in_image_type>::pixel_type in_pixel_type;
        typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;
        COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type>::has_alpha == false );
        COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::has_alpha == false );

        using namespace morphological_operations_helpers;
        COMPILE_TIME_ASSERT(M%2 == 1);
        COMPILE_TIME_ASSERT(N%2 == 1);
        DLIB_ASSERT(is_same_object(in_img,out_img) == false,
            "\tvoid binary_close()"
            << "\n\tYou must give two different image objects"
            );
        COMPILE_TIME_ASSERT(pixel_traits<in_pixel_type>::grayscale);
        DLIB_ASSERT(is_binary_image(in_img) ,
            "\tvoid binary_close()"
            << "\n\tin_img must be a binary image"
            );
        DLIB_ASSERT(is_binary_image(structuring_element) ,
            "\tvoid binary_close()"
            << "\n\tthe structuring_element must be a binary image"
            );

        // if there isn't any input image then don't do anything
        if (num_rows(in_img)*num_columns(in_img) == 0)
        {
            set_image_size(out_img, 0,0);
            return;
        }

        set_image_size(out_img, num_rows(in_img), num_columns(in_img));

        if (iter == 0)
        {
            // just copy the image over
            assign_image(out_img, in_img);
        }
        else if (iter == 1)
        {
            in_image_type temp;
            binary_dilation(in_img,temp,structuring_element);
            binary_erosion(temp,out_img,structuring_element);
        }
        else
        {
            in_image_type temp1, temp2;
            binary_dilation(in_img,temp1,structuring_element);

            // do the extra dilations
            for (unsigned long i = 1; i < iter; ++i)
            {
                swap(temp1, temp2);
                binary_dilation(temp2,temp1,structuring_element);
            }

            // do the extra erosions
            for (unsigned long i = 1; i < iter; ++i)
            {
                swap(temp1, temp2);
                binary_erosion(temp2,temp1,structuring_element);
            }

            binary_erosion(temp1,out_img,structuring_element);
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type1,
        typename in_image_type2,
        typename out_image_type
        >
    void binary_intersection (
        const in_image_type1& in_img1_,
        const in_image_type2& in_img2_,
        out_image_type& out_img_
    )
    {
        typedef typename image_traits<in_image_type1>::pixel_type in_pixel_type1;
        typedef typename image_traits<in_image_type2>::pixel_type in_pixel_type2;
        typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;
        COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type1>::has_alpha == false );
        COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type2>::has_alpha == false );
        COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::has_alpha == false );

        using namespace morphological_operations_helpers;
        COMPILE_TIME_ASSERT(pixel_traits<in_pixel_type1>::grayscale);
        COMPILE_TIME_ASSERT(pixel_traits<in_pixel_type2>::grayscale);
        DLIB_ASSERT(is_binary_image(in_img1_) ,
            "\tvoid binary_intersection()"
            << "\n\tin_img1 must be a binary image"
            );
        DLIB_ASSERT(is_binary_image(in_img2_) ,
            "\tvoid binary_intersection()"
            << "\n\tin_img2 must be a binary image"
            );

        const_image_view<in_image_type1> in_img1(in_img1_);
        const_image_view<in_image_type2> in_img2(in_img2_);
        image_view<out_image_type> out_img(out_img_);

        DLIB_ASSERT(in_img1.nc() == in_img2.nc(),
            "\tvoid binary_intersection()"
            << "\n\tin_img1 and in_img2 must have the same ncs."
            << "\n\tin_img1.nc(): " << in_img1.nc()
            << "\n\tin_img2.nc(): " << in_img2.nc()
            );
        DLIB_ASSERT(in_img1.nr() == in_img2.nr(),
            "\tvoid binary_intersection()"
            << "\n\tin_img1 and in_img2 must have the same nrs."
            << "\n\tin_img1.nr(): " << in_img1.nr()
            << "\n\tin_img2.nr(): " << in_img2.nr()
            );

        // if there isn't any input image then don't do anything
        if (in_img1.size() == 0)
        {
            out_img.clear();
            return;
        }

        out_img.set_size(in_img1.nr(),in_img1.nc());

        for (long r = 0; r < in_img1.nr(); ++r)
        {
            for (long c = 0; c < in_img1.nc(); ++c)
            {
                if (in_img1[r][c] == on_pixel && in_img2[r][c] == on_pixel)
                    assign_pixel(out_img[r][c], on_pixel);
                else
                    assign_pixel(out_img[r][c], off_pixel);
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type1,
        typename in_image_type2,
        typename out_image_type
        >
    void binary_union (
        const in_image_type1& in_img1_,
        const in_image_type2& in_img2_,
        out_image_type& out_img_
    )
    {
        typedef typename image_traits<in_image_type1>::pixel_type in_pixel_type1;
        typedef typename image_traits<in_image_type2>::pixel_type in_pixel_type2;
        typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;
        COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type1>::has_alpha == false );
        COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type2>::has_alpha == false );
        COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::has_alpha == false );

        using namespace morphological_operations_helpers;
        COMPILE_TIME_ASSERT(pixel_traits<in_pixel_type1>::grayscale);
        COMPILE_TIME_ASSERT(pixel_traits<in_pixel_type2>::grayscale);
        DLIB_ASSERT(is_binary_image(in_img1_) ,
            "\tvoid binary_intersection()"
            << "\n\tin_img1 must be a binary image"
            );
        DLIB_ASSERT(is_binary_image(in_img2_) ,
            "\tvoid binary_intersection()"
            << "\n\tin_img2 must be a binary image"
            );

        const_image_view<in_image_type1> in_img1(in_img1_);
        const_image_view<in_image_type2> in_img2(in_img2_);
        image_view<out_image_type> out_img(out_img_);

        DLIB_ASSERT(in_img1.nc() == in_img2.nc(),
            "\tvoid binary_intersection()"
            << "\n\tin_img1 and in_img2 must have the same ncs."
            << "\n\tin_img1.nc(): " << in_img1.nc()
            << "\n\tin_img2.nc(): " << in_img2.nc()
            );
        DLIB_ASSERT(in_img1.nr() == in_img2.nr(),
            "\tvoid binary_intersection()"
            << "\n\tin_img1 and in_img2 must have the same nrs."
            << "\n\tin_img1.nr(): " << in_img1.nr()
            << "\n\tin_img2.nr(): " << in_img2.nr()
            );

        // if there isn't any input image then don't do anything
        if (in_img1.size() == 0)
        {
            out_img.clear();
            return;
        }

        out_img.set_size(in_img1.nr(),in_img1.nc());

        for (long r = 0; r < in_img1.nr(); ++r)
        {
            for (long c = 0; c < in_img1.nc(); ++c)
            {
                if (in_img1[r][c] == on_pixel || in_img2[r][c] == on_pixel)
                    assign_pixel(out_img[r][c], on_pixel);
                else
                    assign_pixel(out_img[r][c], off_pixel);
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type1,
        typename in_image_type2,
        typename out_image_type
        >
    void binary_difference (
        const in_image_type1& in_img1_,
        const in_image_type2& in_img2_,
        out_image_type& out_img_
    )
    {
        typedef typename image_traits<in_image_type1>::pixel_type in_pixel_type1;
        typedef typename image_traits<in_image_type2>::pixel_type in_pixel_type2;
        typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;
        COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type1>::has_alpha == false );
        COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type2>::has_alpha == false );
        COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::has_alpha == false );

        using namespace morphological_operations_helpers;
        COMPILE_TIME_ASSERT(pixel_traits<in_pixel_type1>::grayscale);
        COMPILE_TIME_ASSERT(pixel_traits<in_pixel_type2>::grayscale);
        DLIB_ASSERT(is_binary_image(in_img1_) ,
            "\tvoid binary_difference()"
            << "\n\tin_img1 must be a binary image"
            );
        DLIB_ASSERT(is_binary_image(in_img2_) ,
            "\tvoid binary_difference()"
            << "\n\tin_img2 must be a binary image"
            );

        const_image_view<in_image_type1> in_img1(in_img1_);
        const_image_view<in_image_type2> in_img2(in_img2_);
        image_view<out_image_type> out_img(out_img_);

        DLIB_ASSERT(in_img1.nc() == in_img2.nc(),
            "\tvoid binary_difference()"
            << "\n\tin_img1 and in_img2 must have the same ncs."
            << "\n\tin_img1.nc(): " << in_img1.nc()
            << "\n\tin_img2.nc(): " << in_img2.nc()
            );
        DLIB_ASSERT(in_img1.nr() == in_img2.nr(),
            "\tvoid binary_difference()"
            << "\n\tin_img1 and in_img2 must have the same nrs."
            << "\n\tin_img1.nr(): " << in_img1.nr()
            << "\n\tin_img2.nr(): " << in_img2.nr()
            );

        // if there isn't any input image then don't do anything
        if (in_img1.size() == 0)
        {
            out_img.clear();
            return;
        }

        out_img.set_size(in_img1.nr(),in_img1.nc());

        for (long r = 0; r < in_img1.nr(); ++r)
        {
            for (long c = 0; c < in_img1.nc(); ++c)
            {
                if (in_img1[r][c] == on_pixel && in_img2[r][c] == off_pixel)
                    assign_pixel(out_img[r][c], on_pixel);
                else
                    assign_pixel(out_img[r][c], off_pixel);
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type
        >
    void binary_complement (
        const in_image_type& in_img_,
        out_image_type& out_img_
    )
    {
        typedef typename image_traits<in_image_type>::pixel_type in_pixel_type;
        typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;
        COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type>::has_alpha == false );
        COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::has_alpha == false );

        using namespace morphological_operations_helpers;
        COMPILE_TIME_ASSERT(pixel_traits<in_pixel_type>::grayscale);
        DLIB_ASSERT(is_binary_image(in_img_) ,
            "\tvoid binary_complement()"
            << "\n\tin_img must be a binary image"
            );

        const_image_view<in_image_type> in_img(in_img_);
        image_view<out_image_type> out_img(out_img_);

        // if there isn't any input image then don't do anything
        if (in_img.size() == 0)
        {
            out_img.clear();
            return;
        }

        out_img.set_size(in_img.nr(),in_img.nc());

        for (long r = 0; r < in_img.nr(); ++r)
        {
            for (long c = 0; c < in_img.nc(); ++c)
            {
                if (in_img[r][c] == on_pixel)
                    assign_pixel(out_img[r][c], off_pixel);
                else
                    assign_pixel(out_img[r][c], on_pixel);
            }
        }
    }

    template <
        typename image_type
        >
    void binary_complement (
        image_type& img
    )
    {
        binary_complement(img,img);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    namespace impl
    {
        template <typename image_type>
        inline bool should_remove_pixel (
            const image_type& img,
            long r,
            long c,
            int iter
        )
        {
            unsigned int p2 = img[r-1][c];
            unsigned int p3 = img[r-1][c+1];
            unsigned int p4 = img[r][c+1];
            unsigned int p5 = img[r+1][c+1];
            unsigned int p6 = img[r+1][c];
            unsigned int p7 = img[r+1][c-1];
            unsigned int p8 = img[r][c-1];
            unsigned int p9 = img[r-1][c-1];

            int A  = (p2 == 0 && p3 == 255) + (p3 == 0 && p4 == 255) +
                (p4 == 0 && p5 == 255) + (p5 == 0 && p6 == 255) +
                (p6 == 0 && p7 == 255) + (p7 == 0 && p8 == 255) +
                (p8 == 0 && p9 == 255) + (p9 == 0 && p2 == 255);
            int B  = p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9;
            int m1 = iter == 0 ? (p2 * p4 * p6) : (p2 * p4 * p8);
            int m2 = iter == 0 ? (p4 * p6 * p8) : (p2 * p6 * p8);
            // Decide if we should remove the pixel img[r][c].
            return (A == 1 && (B >= 2*255 && B <= 6*255) && m1 == 0 && m2 == 0);
        }

        template <typename image_type>
        inline void add_to_remove (
            std::vector<point>& to_remove,
            array2d<unsigned char>& marker,
            const image_type& img,
            long r,
            long c,
            int iter
        )
        {
            if (marker[r][c]&&should_remove_pixel(img,r,c,iter))
            {
                to_remove.push_back(point(c,r));
                marker[r][c] = 0;
            }
        }

        template <typename image_type>
        inline bool is_bw_border_pixel(
            const image_type& img,
            long r,
            long c
        )
        {
            unsigned int p2 = img[r-1][c];
            unsigned int p3 = img[r-1][c+1];
            unsigned int p4 = img[r][c+1];
            unsigned int p5 = img[r+1][c+1];
            unsigned int p6 = img[r+1][c];
            unsigned int p7 = img[r+1][c-1];
            unsigned int p8 = img[r][c-1];
            unsigned int p9 = img[r-1][c-1];

            int B  = p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9;
            // If you are on but at least one of your neighbors isn't.
            return B<8*255 && img[r][c];

        }

        inline void add_if(
            std::vector<point>& to_check2,
            const array2d<unsigned char>& marker,
            long c,
            long r
        )
        {
            if (marker[r][c])
                to_check2.push_back(point(c,r));
        }

    } // end namespace impl

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    void skeleton(
        image_type& img_
    )
    {
        /*
            The implementation of this function is based on the paper
            "A fast parallel algorithm for thinning digital patterns” by T.Y. Zhang and C.Y. Suen.
            and also the excellent discussion of it at:
            http://opencv-code.com/quick-tips/implementation-of-thinning-algorithm-in-opencv/
        */

        typedef typename image_traits<image_type>::pixel_type pixel_type;

        // This function only works on grayscale images
        COMPILE_TIME_ASSERT(pixel_traits<pixel_type>::grayscale);

        using namespace impl;
        // Note that it's important to zero the border for 2 reasons. First, it allows
        // thinning to being at the border of the image.  But more importantly, it causes
        // the mask to have a border of 0 pixels as well which we use later to avoid
        // indexing outside the image inside add_to_remove().
        zero_border_pixels(img_,1,1);
        image_view<image_type> img(img_);

        // We use the marker to keep track of pixels we have committed to removing but
        // haven't yet removed from img.
        array2d<unsigned char> marker(img.nr(), img.nc());
        assign_image(marker, img);

        // Begin by making a list of the pixels on the borders of binary blobs.
        std::vector<point> to_remove, to_check, to_check2;
        for (int r = 1; r < img.nr()-1; r++)
        {
            for (int c = 1; c < img.nc()-1; c++)
            {
                if (is_bw_border_pixel(img, r, c))
                {
                    to_check.push_back(point(c,r));
                }
            }
        }

        // Now start iteratively looking at the border pixels and removing them.
        while(to_check.size() != 0)
        {
            for (int iter = 0; iter <= 1; ++iter)
            {
                // Check which pixels we should remove
                to_remove.clear();
                for (unsigned long i = 0; i < to_check.size(); ++i)
                {
                    long r = to_check[i].y();
                    long c = to_check[i].x();
                    add_to_remove(to_remove, marker, img, r, c, iter);
                }
                for (unsigned long i = 0; i < to_check2.size(); ++i)
                {
                    long r = to_check2[i].y();
                    long c = to_check2[i].x();
                    add_to_remove(to_remove, marker, img, r, c, iter);
                }
                // Now remove those pixels.  Also add their neighbors into the "to check"
                // pixel list for the next iteration.
                for (unsigned long i = 0; i < to_remove.size(); ++i)
                {
                    long r = to_remove[i].y();
                    long c = to_remove[i].x();
                    // remove the pixel
                    img[r][c] = 0;
                    add_if(to_check2, marker, c-1, r-1);
                    add_if(to_check2, marker, c,   r-1);
                    add_if(to_check2, marker, c+1, r-1);
                    add_if(to_check2, marker, c-1, r);
                    add_if(to_check2, marker, c+1, r);
                    add_if(to_check2, marker, c-1, r+1);
                    add_if(to_check2, marker, c,   r+1);
                    add_if(to_check2, marker, c+1, r+1);
                }
            }
            to_check.clear();
            to_check.swap(to_check2);
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MORPHOLOGICAL_OPERATIONs_


dlib C++ Library - segment_image.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SEGMENT_ImAGE_Hh_
#define DLIB_SEGMENT_ImAGE_Hh_

#include "segment_image_abstract.h"
#include "../algs.h"
#include <vector>
#include "../geometry.h"
#include "../disjoint_subsets.h"
#include "../set.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    namespace impl
    {
        template <typename T>
        inline T edge_diff_uint(
            const T& a,
            const T& b
        )
        {
            if (a > b)
                return a - b;
            else
                return b - a;
        }

    // ----------------------------------------

        template <typename T, typename enabled = void>
        struct edge_diff_funct
        {
            typedef double diff_type;

            template <typename pixel_type>
            double operator()(
                const pixel_type& a,
                const pixel_type& b
            ) const
            {
                return length(pixel_to_vector<double>(a) - pixel_to_vector<double>(b));
            }
        };

        template <>
        struct edge_diff_funct<uint8,void>
        {
            typedef uint8 diff_type;
            uint8 operator()( const uint8& a, const uint8& b) const { return edge_diff_uint(a,b); }
        };

        template <>
        struct edge_diff_funct<uint16,void>
        {
            typedef uint16 diff_type;
            uint16 operator()( const uint16& a, const uint16& b) const { return edge_diff_uint(a,b); }
        };

        template <>
        struct edge_diff_funct<uint32,void>
        {
            typedef uint32 diff_type;
            uint32 operator()( const uint32& a, const uint32& b) const { return edge_diff_uint(a,b); }
        };

        template <>
        struct edge_diff_funct<double,void>
        {
            typedef double diff_type;
            double operator()( const double& a, const double& b) const { return std::abs(a-b); }
        };

        template <typename T>
        struct edge_diff_funct<T, typename enable_if<is_matrix<T> >::type>
        {
            typedef double diff_type;
            double operator()(
                const T& a,
                const T& b
            ) const
            {
                return length(a-b);
            }
        };

    // ------------------------------------------------------------------------------------

        template <typename T>
        struct graph_image_segmentation_data_T
        {
            graph_image_segmentation_data_T() : component_size(1), internal_diff(0) {}
            unsigned long component_size;
            T internal_diff;
        };

    // ------------------------------------------------------------------------------------

        template <typename T>
        struct segment_image_edge_data_T
        {
            segment_image_edge_data_T (){}

            segment_image_edge_data_T (
                const rectangle& rect,
                const point& p1,
                const point& p2,
                const T& diff_
            ) :
                idx1(p1.y()*rect.width() + p1.x()),
                idx2(p2.y()*rect.width() + p2.x()),
                diff(diff_)
            {}

            bool operator<(const segment_image_edge_data_T& item) const
            { return diff < item.diff; }

            unsigned long idx1;
            unsigned long idx2;
            T diff;
        };

    // ------------------------------------------------------------------------------------

        template <typename image_view_type>
        struct uint8_or_uint16_pixels
        {
            typedef typename image_view_type::pixel_type pixel_type;
            const static bool value = is_same_type<pixel_type,uint8>::value ||
                is_same_type<pixel_type,uint16>::value;
        };

        // This is an overload of get_pixel_edges() that is optimized to segment images
        // with 8bit or 16bit  pixels very quickly.  We do this by using a radix sort
        // instead of quicksort.
        template <typename in_image_type, typename T>
        typename enable_if<uint8_or_uint16_pixels<in_image_type> >::type
        get_pixel_edges (
            const in_image_type& in_img,
            std::vector<segment_image_edge_data_T<T> >& sorted_edges
        )
        {
            typedef typename in_image_type::pixel_type ptype;
            typedef T diff_type;
            std::vector<unsigned long> counts(std::numeric_limits<ptype>::max()+1, 0);

            edge_diff_funct<ptype> edge_diff;

            border_enumerator be(get_rect(in_img), 1);
            // we are going to do a radix sort on the edge weights.  So the first step
            // is to accumulate them into count.
            const rectangle area = get_rect(in_img);
            while (be.move_next())
            {
                const long r = be.element().y();
                const long c = be.element().x();
                const ptype pix = in_img[r][c];
                if (area.contains(c-1,r))   counts[edge_diff(pix, in_img[r  ][c-1])] += 1;
                if (area.contains(c+1,r))   counts[edge_diff(pix, in_img[r  ][c+1])] += 1;
                if (area.contains(c  ,r-1)) counts[edge_diff(pix, in_img[r-1][c  ])] += 1;
                if (area.contains(c  ,r+1)) counts[edge_diff(pix, in_img[r+1][c  ])] += 1;
            }
            for (long r = 1; r+1 < in_img.nr(); ++r)
            {
                for (long c = 1; c+1 < in_img.nc(); ++c)
                {
                    const ptype pix = in_img[r][c];
                    counts[edge_diff(pix, in_img[r-1][c+1])] += 1;
                    counts[edge_diff(pix, in_img[r  ][c+1])] += 1;
                    counts[edge_diff(pix, in_img[r+1][c  ])] += 1;
                    counts[edge_diff(pix, in_img[r+1][c+1])] += 1;
                }
            }

            const unsigned long num_edges = shrink_rect(area,1).area()*4 + in_img.nr()*2*3 - 4 + (in_img.nc()-2)*2*3;
            typedef segment_image_edge_data_T<T> segment_image_edge_data;
            sorted_edges.resize(num_edges);

            // integrate counts.  The idea is to have sorted_edges[counts[i]] be the location that edges
            // with an edge_diff of i go.  So counts[0] == 0, counts[1] == number of 0 edge diff edges, etc.
            unsigned long prev = counts[0];
            for (unsigned long i = 1; i < counts.size(); ++i)
            {
                const unsigned long temp = counts[i];
                counts[i] += counts[i-1];
                counts[i-1] -= prev;
                prev = temp;
            }
            counts[counts.size()-1] -= prev;

            // now build a sorted list of all the edges
            be.reset();
            while(be.move_next())
            {
                const point p = be.element();
                const long r = p.y();
                const long c = p.x();
                const ptype pix = in_img[r][c];
                if (area.contains(c-1,r))
                {
                    const diff_type diff = edge_diff(pix, in_img[r  ][c-1]);
                    sorted_edges[counts[diff]++] = segment_image_edge_data(area,p,point(c-1,r),diff);
                }

                if (area.contains(c+1,r))
                {
                    const diff_type diff = edge_diff(pix, in_img[r  ][c+1]);
                    sorted_edges[counts[diff]++] = segment_image_edge_data(area,p,point(c+1,r),diff);
                }

                if (area.contains(c  ,r-1))
                {
                    const diff_type diff = edge_diff(pix, in_img[r-1][c  ]);
                    sorted_edges[counts[diff]++] = segment_image_edge_data(area,p,point(c  ,r-1),diff);
                }

                if (area.contains(c  ,r+1))
                {
                    const diff_type diff = edge_diff(pix, in_img[r+1][c  ]);
                    sorted_edges[counts[diff]++] = segment_image_edge_data(area,p,point(c  ,r+1),diff);
                }
            }
            // same thing as the above loop but now we do it on the interior of the image and therefore
            // don't have to include the boundary checking if statements used above.
            for (long r = 1; r+1 < in_img.nr(); ++r)
            {
                for (long c = 1; c+1 < in_img.nc(); ++c)
                {
                    const point p(c,r);
                    const ptype pix = in_img[r][c];
                    diff_type diff;

                    diff = edge_diff(pix, in_img[r  ][c+1]);
                    sorted_edges[counts[diff]++] = segment_image_edge_data(area,p,point(c+1,r),diff);
                    diff = edge_diff(pix, in_img[r-1][c+1]);
                    sorted_edges[counts[diff]++] = segment_image_edge_data(area,p,point(c+1,r-1),diff);
                    diff = edge_diff(pix, in_img[r+1][c+1]);
                    sorted_edges[counts[diff]++] = segment_image_edge_data(area,p,point(c+1,r+1),diff);
                    diff = edge_diff(pix, in_img[r+1][c  ]);
                    sorted_edges[counts[diff]++] = segment_image_edge_data(area,p,point(c  ,r+1),diff);
                }
            }
        }

    // ----------------------------------------------------------------------------------------

        // This is the general purpose version of get_pixel_edges().  It handles all pixel types.
        template <typename in_image_type, typename T>
        typename disable_if<uint8_or_uint16_pixels<in_image_type> >::type
        get_pixel_edges (
            const in_image_type& in_img,
            std::vector<segment_image_edge_data_T<T> >& sorted_edges
        )
        {
            const rectangle area = get_rect(in_img);
            sorted_edges.reserve(area.area()*4);

            typedef typename in_image_type::pixel_type ptype;
            edge_diff_funct<ptype> edge_diff;
            typedef T diff_type;
            typedef segment_image_edge_data_T<T> segment_image_edge_data;

            border_enumerator be(get_rect(in_img), 1);

            // now build a sorted list of all the edges
            be.reset();
            while(be.move_next())
            {
                const point p = be.element();
                const long r = p.y();
                const long c = p.x();
                const ptype& pix = in_img[r][c];
                if (area.contains(c-1,r))
                {
                    const diff_type diff = edge_diff(pix, in_img[r  ][c-1]);
                    sorted_edges.push_back(segment_image_edge_data(area,p,point(c-1,r),diff));
                }

                if (area.contains(c+1,r))
                {
                    const diff_type diff = edge_diff(pix, in_img[r  ][c+1]);
                    sorted_edges.push_back(segment_image_edge_data(area,p,point(c+1,r),diff));
                }

                if (area.contains(c  ,r-1))
                {
                    const diff_type diff = edge_diff(pix, in_img[r-1][c  ]);
                    sorted_edges.push_back( segment_image_edge_data(area,p,point(c  ,r-1),diff));
                }
                if (area.contains(c  ,r+1))
                {
                    const diff_type diff = edge_diff(pix, in_img[r+1][c  ]);
                    sorted_edges.push_back( segment_image_edge_data(area,p,point(c  ,r+1),diff));
                }
            }
            // same thing as the above loop but now we do it on the interior of the image and therefore
            // don't have to include the boundary checking if statements used above.
            for (long r = 1; r+1 < in_img.nr(); ++r)
            {
                for (long c = 1; c+1 < in_img.nc(); ++c)
                {
                    const point p(c,r);
                    const ptype& pix = in_img[r][c];
                    diff_type diff;

                    diff = edge_diff(pix, in_img[r  ][c+1]);
                    sorted_edges.push_back( segment_image_edge_data(area,p,point(c+1,r),diff));
                    diff = edge_diff(pix, in_img[r+1][c+1]);
                    sorted_edges.push_back( segment_image_edge_data(area,p,point(c+1,r+1),diff));
                    diff = edge_diff(pix, in_img[r+1][c  ]);
                    sorted_edges.push_back( segment_image_edge_data(area,p,point(c  ,r+1),diff));
                    diff = edge_diff(pix, in_img[r-1][c+1]);
                    sorted_edges.push_back( segment_image_edge_data(area,p,point(c+1,r-1),diff));
                }
            }

            std::sort(sorted_edges.begin(), sorted_edges.end());

        }

    // ------------------------------------------------------------------------------------

    } // end of namespace impl

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type
        >
    void segment_image (
        const in_image_type& in_img_,
        out_image_type& out_img_,
        const double k = 200,
        const unsigned long min_size = 10
    )
    {
        using namespace dlib::impl;
        typedef typename image_traits<in_image_type>::pixel_type ptype;
        typedef typename edge_diff_funct<ptype>::diff_type diff_type;

        // make sure requires clause is not broken
        DLIB_ASSERT(is_same_object(in_img_, out_img_) == false,
            "\t void segment_image()"
            << "\n\t The input images can't be the same object."
            );

        COMPILE_TIME_ASSERT(is_unsigned_type<typename image_traits<out_image_type>::pixel_type>::value);

        const_image_view<in_image_type> in_img(in_img_);
        image_view<out_image_type> out_img(out_img_);

        out_img.set_size(in_img.nr(), in_img.nc());
        // don't bother doing anything if the image is too small
        if (in_img.nr() < 2 || in_img.nc() < 2)
        {
            assign_all_pixels(out_img,0);
            return;
        }

        disjoint_subsets sets;
        sets.set_size(in_img.size());

        std::vector<segment_image_edge_data_T<diff_type> > sorted_edges;
        get_pixel_edges(in_img, sorted_edges);

        std::vector<graph_image_segmentation_data_T<diff_type> > data(in_img.size());

        // now start connecting blobs together to make a minimum spanning tree.
        for (unsigned long i = 0; i < sorted_edges.size(); ++i)
        {
            const unsigned long idx1 = sorted_edges[i].idx1;
            const unsigned long idx2 = sorted_edges[i].idx2;

            unsigned long set1 = sets.find_set(idx1);
            unsigned long set2 = sets.find_set(idx2);
            if (set1 != set2)
            {
                const diff_type diff = sorted_edges[i].diff;
                const diff_type tau1 = static_cast<diff_type>(k/data[set1].component_size);
                const diff_type tau2 = static_cast<diff_type>(k/data[set2].component_size);

                const diff_type mint = std::min(data[set1].internal_diff + tau1,
                                                data[set2].internal_diff + tau2);
                if (diff <= mint)
                {
                    const unsigned long new_set = sets.merge_sets(set1, set2);
                    data[new_set].component_size = data[set1].component_size + data[set2].component_size;
                    data[new_set].internal_diff = diff;
                }
            }
        }

        // now merge any really small blobs
        if (min_size != 0)
        {
            for (unsigned long i = 0; i < sorted_edges.size(); ++i)
            {
                const unsigned long idx1 = sorted_edges[i].idx1;
                const unsigned long idx2 = sorted_edges[i].idx2;

                unsigned long set1 = sets.find_set(idx1);
                unsigned long set2 = sets.find_set(idx2);
                if (set1 != set2 && (data[set1].component_size < min_size || data[set2].component_size < min_size))
                {
                    const unsigned long new_set = sets.merge_sets(set1, set2);
                    data[new_set].component_size = data[set1].component_size + data[set2].component_size;
                    //data[new_set].internal_diff = sorted_edges[i].diff;
                }
            }
        }

        unsigned long idx = 0;
        for (long r = 0; r < out_img.nr(); ++r)
        {
            for (long c = 0; c < out_img.nc(); ++c)
            {
                out_img[r][c] = sets.find_set(idx++);
            }
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                     Candidate object location generation code.
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    namespace impl
    {
        struct edge_data
        {
            double edge_diff;
            unsigned long set1;
            unsigned long set2;
            bool operator<(const edge_data& item) const
            {
                return edge_diff < item.edge_diff;
            }
        };

        template <
            typename in_image_type,
            typename diff_type
            >
        void find_basic_candidate_object_locations (
            const in_image_type& in_img,
            const std::vector<dlib::impl::segment_image_edge_data_T<diff_type> >& sorted_edges,
            std::vector<rectangle>& out_rects,
            std::vector<edge_data>& edges,
            const double k,
            const unsigned long min_size
        )
        {
            using namespace dlib::impl;

            std::vector<dlib::impl::segment_image_edge_data_T<diff_type> > rejected_edges;
            rejected_edges.reserve(sorted_edges.size());

            out_rects.clear();
            edges.clear();

            // don't bother doing anything if the image is too small
            if (in_img.nr() < 2 || in_img.nc() < 2)
            {
                return;
            }

            disjoint_subsets sets;
            sets.set_size(in_img.size());

            std::vector<graph_image_segmentation_data_T<diff_type> > data(in_img.size());

            std::pair<unsigned long,unsigned long> last_blob_edge(std::numeric_limits<unsigned long>::max(),
                                                                  std::numeric_limits<unsigned long>::max());;
            // now start connecting blobs together to make a minimum spanning tree.
            for (unsigned long i = 0; i < sorted_edges.size(); ++i)
            {
                const unsigned long idx1 = sorted_edges[i].idx1;
                const unsigned long idx2 = sorted_edges[i].idx2;

                unsigned long set1 = sets.find_set(idx1);
                unsigned long set2 = sets.find_set(idx2);
                if (set1 != set2)
                {
                    const diff_type diff = sorted_edges[i].diff;
                    const diff_type tau1 = static_cast<diff_type>(k/data[set1].component_size);
                    const diff_type tau2 = static_cast<diff_type>(k/data[set2].component_size);

                    const diff_type mint = std::min(data[set1].internal_diff + tau1,
                        data[set2].internal_diff + tau2);
                    if (diff <= mint)
                    {
                        const unsigned long new_set = sets.merge_sets(set1, set2);
                        data[new_set].component_size = data[set1].component_size + data[set2].component_size;
                        data[new_set].internal_diff = diff;
                    }
                    else
                    {
                        // Don't bother keeping multiple edges from the same pair of blobs, we
                        // only need one for what we will do later.
                        if (std::make_pair(set1,set2) != last_blob_edge)
                        {
                            segment_image_edge_data_T<diff_type> temp = sorted_edges[i];
                            temp.idx1 = set1;
                            temp.idx2 = set2;
                            rejected_edges.push_back(temp);
                            last_blob_edge = std::make_pair(set1,set2);
                        }
                    }
                }
            }

            // merge small blobs
            for (unsigned long i = 0; i < rejected_edges.size(); ++i)
            {
                const unsigned long idx1 = rejected_edges[i].idx1;
                const unsigned long idx2 = rejected_edges[i].idx2;

                unsigned long set1 = sets.find_set(idx1);
                unsigned long set2 = sets.find_set(idx2);
                rejected_edges[i].idx1 = set1;
                rejected_edges[i].idx2 = set2;
                if (set1 != set2 && (data[set1].component_size < min_size || data[set2].component_size < min_size))
                {
                    const unsigned long new_set = sets.merge_sets(set1, set2);
                    data[new_set].component_size = data[set1].component_size + data[set2].component_size;
                    data[new_set].internal_diff = rejected_edges[i].diff;
                }
            }

            // find bounding boxes of each blob
            std::map<unsigned long, rectangle> boxes;
            std::map<unsigned long, unsigned long> box_id_map;
            unsigned long idx = 0;
            for (long r = 0; r < in_img.nr(); ++r)
            {
                for (long c = 0; c < in_img.nc(); ++c)
                {
                    const unsigned long id = sets.find_set(idx++);
                    // Accumulate the current point into its box and if it is the first point
                    // in the box then also record the id number for this box.
                    if ((boxes[id] += point(c,r)).area() == 1)
                        box_id_map[id] = boxes.size()-1;
                }
            }

            // copy boxes into out_rects
            out_rects.resize(boxes.size());
            for (std::map<unsigned long,rectangle>::iterator i = boxes.begin(); i != boxes.end(); ++i)
            {
                out_rects[box_id_map[i->first]] = i->second;
            }

            // Now find the edges between the boxes
            typedef dlib::memory_manager<char>::kernel_2c mm_type;
            dlib::set<std::pair<unsigned long, unsigned long>, mm_type>::kernel_1a neighbors_final;
            for (unsigned long i = 0; i < rejected_edges.size(); ++i)
            {
                const unsigned long idx1 = rejected_edges[i].idx1;
                const unsigned long idx2 = rejected_edges[i].idx2;

                unsigned long set1 = sets.find_set(idx1);
                unsigned long set2 = sets.find_set(idx2);
                if (set1 != set2)
                {
                    std::pair<unsigned long, unsigned long> p = std::make_pair(set1,set2);
                    if (!neighbors_final.is_member(p))
                    {
                        neighbors_final.add(p);

                        edge_data temp;
                        const diff_type mint = std::min(data[set1].internal_diff ,
                                                        data[set2].internal_diff );
                        temp.edge_diff = rejected_edges[i].diff - mint;
                        temp.set1 = box_id_map[set1];
                        temp.set2 = box_id_map[set2];
                        edges.push_back(temp);
                    }
                }
            }

            std::sort(edges.begin(), edges.end());
        }
    } // end namespace impl

// ----------------------------------------------------------------------------------------

    template <typename alloc>
    void remove_duplicates (
        std::vector<rectangle,alloc>& rects
    )
    {
        std::sort(rects.begin(), rects.end(), std::less<rectangle>());
        unsigned long num_unique = 1;
        for (unsigned long i = 1; i < rects.size(); ++i)
        {
            if (rects[i] != rects[i-1])
            {
                rects[num_unique++] = rects[i];
            }
        }
        if (rects.size() != 0)
            rects.resize(num_unique);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename EXP
        >
    void find_candidate_object_locations (
        const in_image_type& in_img_,
        std::vector<rectangle>& rects,
        const matrix_exp<EXP>& kvals,
        const unsigned long min_size = 20,
        const unsigned long max_merging_iterations = 50
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(is_vector(kvals) && kvals.size() > 0,
            "\t void find_candidate_object_locations()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t is_vector(kvals): " << is_vector(kvals)
            << "\n\t kvals.size():     " << kvals.size()
            );

        typedef dlib::memory_manager<char>::kernel_2c mm_type;
        typedef dlib::set<rectangle, mm_type>::kernel_1a set_of_rects;

        using namespace dlib::impl;
        typedef typename image_traits<in_image_type>::pixel_type ptype;
        typedef typename edge_diff_funct<ptype>::diff_type diff_type;

        const_image_view<in_image_type> in_img(in_img_);

        // don't bother doing anything if the image is too small
        if (in_img.nr() < 2 || in_img.nc() < 2)
        {
            return;
        }

        std::vector<edge_data> edges;
        std::vector<rectangle> working_rects;
        std::vector<segment_image_edge_data_T<diff_type> > sorted_edges;
        get_pixel_edges(in_img, sorted_edges);

        disjoint_subsets sets;

        for (long j = 0; j < kvals.size(); ++j)
        {
            const double k = kvals(j);

            find_basic_candidate_object_locations(in_img, sorted_edges, working_rects, edges, k, min_size);
            rects.insert(rects.end(), working_rects.begin(), working_rects.end());

            // Now iteratively merge all the rectangles we have and record the results.
            // Note that, unlike what is described in the paper
            //    Segmentation as Selective Search for Object Recognition" by Koen E. A. van de Sande, et al.
            // we don't use any kind of histogram/SIFT like thing to order the edges
            // between the blobs.  Here we simply order by the pixel difference value.
            // Additionally, note that we keep progressively merging boxes in the outer
            // loop rather than performing just a single iteration as indicated in the
            // paper.
            set_of_rects detected_rects;
            bool did_merge = true;
            for (unsigned long iter = 0; did_merge && iter < max_merging_iterations; ++iter)
            {
                did_merge = false;
                sets.clear();
                sets.set_size(working_rects.size());

                // recursively merge neighboring blobs until we have merged everything
                for (unsigned long i = 0; i < edges.size(); ++i)
                {
                    edge_data temp = edges[i];

                    temp.set1 = sets.find_set(temp.set1);
                    temp.set2 = sets.find_set(temp.set2);
                    if (temp.set1 != temp.set2)
                    {
                        rectangle merged_rect = working_rects[temp.set1] + working_rects[temp.set2];
                        // Skip merging this pair of blobs if it was merged in a previous
                        // iteration.  Doing this lets us consider other possible blob
                        // merges.
                        if (!detected_rects.is_member(merged_rect))
                        {
                            const unsigned long new_set = sets.merge_sets(temp.set1, temp.set2);
                            rects.push_back(merged_rect);
                            working_rects[new_set] = merged_rect;
                            did_merge = true;
                            detected_rects.add(merged_rect);
                        }
                    }
                }
            }
        }

        remove_duplicates(rects);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type
        >
    void find_candidate_object_locations (
        const in_image_type& in_img,
        std::vector<rectangle>& rects
    )
    {
        find_candidate_object_locations(in_img, rects, linspace(50, 200, 3));
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SEGMENT_ImAGE_Hh_


dlib C++ Library - spatial_filtering.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SPATIAL_FILTERINg_H_
#define DLIB_SPATIAL_FILTERINg_H_

#include "../pixel.h"
#include "spatial_filtering_abstract.h"
#include "../algs.h"
#include "../assert.h"
#include "../array2d.h"
#include "../matrix.h"
#include "../geometry/border_enumerator.h"
#include "../simd.h"
#include <limits>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    namespace impl
    {
        template <
            typename in_image_type,
            typename out_image_type,
            typename EXP,
            typename T
            >
        rectangle grayscale_spatially_filter_image (
            const in_image_type& in_img_,
            out_image_type& out_img_,
            const matrix_exp<EXP>& filter_,
            T scale,
            bool use_abs,
            bool add_to
        )
        {
            const_temp_matrix<EXP> filter(filter_);
            COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<in_image_type>::pixel_type>::has_alpha == false );
            COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<out_image_type>::pixel_type>::has_alpha == false );

            DLIB_ASSERT(scale != 0 && filter.size() != 0,
                "\trectangle spatially_filter_image()"
                << "\n\t You can't give a scale of zero or an empty filter."
                << "\n\t scale: "<< scale
                << "\n\t filter.nr(): "<< filter.nr()
                << "\n\t filter.nc(): "<< filter.nc()
            );
            DLIB_ASSERT(is_same_object(in_img_, out_img_) == false,
                "\trectangle spatially_filter_image()"
                << "\n\tYou must give two different image objects"
            );

            const_image_view<in_image_type> in_img(in_img_);
            image_view<out_image_type> out_img(out_img_);

            // if there isn't any input image then don't do anything
            if (in_img.size() == 0)
            {
                out_img.clear();
                return rectangle();
            }

            out_img.set_size(in_img.nr(),in_img.nc());

            // figure out the range that we should apply the filter to
            const long first_row = filter.nr()/2;
            const long first_col = filter.nc()/2;
            const long last_row = in_img.nr() - ((filter.nr()-1)/2);
            const long last_col = in_img.nc() - ((filter.nc()-1)/2);

            const rectangle non_border = rectangle(first_col, first_row, last_col-1, last_row-1);
            if (!add_to)
                zero_border_pixels(out_img_, non_border);

            // apply the filter to the image
            for (long r = first_row; r < last_row; ++r)
            {
                for (long c = first_col; c < last_col; ++c)
                {
                    typedef typename EXP::type ptype;
                    ptype p;
                    ptype temp = 0;
                    for (long m = 0; m < filter.nr(); ++m)
                    {
                        for (long n = 0; n < filter.nc(); ++n)
                        {
                            // pull out the current pixel and put it into p
                            p = get_pixel_intensity(in_img[r-first_row+m][c-first_col+n]);
                            temp += p*filter(m,n);
                        }
                    }

                    temp /= scale;

                    if (use_abs && temp < 0)
                    {
                        temp = -temp;
                    }

                    // save this pixel to the output image
                    if (add_to == false)
                    {
                        assign_pixel(out_img[r][c], temp);
                    }
                    else
                    {
                        assign_pixel(out_img[r][c], temp + out_img[r][c]);
                    }
                }
            }

            return non_border;
        }

    // ------------------------------------------------------------------------------------

        template <
            typename in_image_type,
            typename out_image_type,
            typename EXP
            >
        rectangle float_spatially_filter_image (
            const in_image_type& in_img_,
            out_image_type& out_img_,
            const matrix_exp<EXP>& filter_,
            bool add_to
        )
        {

            const_temp_matrix<EXP> filter(filter_);
            DLIB_ASSERT(filter.size() != 0,
                "\trectangle spatially_filter_image()"
                << "\n\t You can't give an empty filter."
                << "\n\t filter.nr(): "<< filter.nr()
                << "\n\t filter.nc(): "<< filter.nc()
            );
            DLIB_ASSERT(is_same_object(in_img_, out_img_) == false,
                "\trectangle spatially_filter_image()"
                << "\n\tYou must give two different image objects"
            );

            const_image_view<in_image_type> in_img(in_img_);
            image_view<out_image_type> out_img(out_img_);

            // if there isn't any input image then don't do anything
            if (in_img.size() == 0)
            {
                out_img.clear();
                return rectangle();
            }

            out_img.set_size(in_img.nr(),in_img.nc());

            // figure out the range that we should apply the filter to
            const long first_row = filter.nr()/2;
            const long first_col = filter.nc()/2;
            const long last_row = in_img.nr() - ((filter.nr()-1)/2);
            const long last_col = in_img.nc() - ((filter.nc()-1)/2);

            const rectangle non_border = rectangle(first_col, first_row, last_col-1, last_row-1);
            if (!add_to)
                zero_border_pixels(out_img_, non_border);

            // apply the filter to the image
            for (long r = first_row; r < last_row; ++r)
            {
                long c = first_col;
                for (; c < last_col-7; c+=8)
                {
                    simd8f p,p2,p3;
                    simd8f temp = 0, temp2=0, temp3=0;
                    for (long m = 0; m < filter.nr(); ++m)
                    {
                        long n = 0;
                        for (; n < filter.nc()-2; n+=3)
                        {
                            // pull out the current pixel and put it into p
                            p.load(&in_img[r-first_row+m][c-first_col+n]);
                            p2.load(&in_img[r-first_row+m][c-first_col+n+1]);
                            p3.load(&in_img[r-first_row+m][c-first_col+n+2]);
                            temp += p*filter(m,n);
                            temp2 += p2*filter(m,n+1);
                            temp3 += p3*filter(m,n+2);
                        }
                        for (; n < filter.nc(); ++n)
                        {
                            // pull out the current pixel and put it into p
                            p.load(&in_img[r-first_row+m][c-first_col+n]);
                            temp += p*filter(m,n);
                        }
                    }
                    temp += temp2+temp3;

                    // save this pixel to the output image
                    if (add_to == false)
                    {
                        temp.store(&out_img[r][c]);
                    }
                    else
                    {
                        p.load(&out_img[r][c]);
                        temp += p;
                        temp.store(&out_img[r][c]);
                    }
                }
                for (; c < last_col; ++c)
                {
                    float p;
                    float temp = 0;
                    for (long m = 0; m < filter.nr(); ++m)
                    {
                        for (long n = 0; n < filter.nc(); ++n)
                        {
                            // pull out the current pixel and put it into p
                            p = in_img[r-first_row+m][c-first_col+n];
                            temp += p*filter(m,n);
                        }
                    }

                    // save this pixel to the output image
                    if (add_to == false)
                    {
                        out_img[r][c] = temp;
                    }
                    else
                    {
                        out_img[r][c] += temp;
                    }
                }
            }

            return non_border;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type,
        typename EXP
        >
    struct is_float_filtering2
    {
        const static bool value = is_same_type<typename image_traits<in_image_type>::pixel_type,float>::value &&
                                  is_same_type<typename image_traits<out_image_type>::pixel_type,float>::value &&
                                  is_same_type<typename EXP::type,float>::value;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type,
        typename EXP,
        typename T
        >
    typename enable_if_c<pixel_traits<typename image_traits<out_image_type>::pixel_type>::grayscale &&
                         is_float_filtering2<in_image_type,out_image_type,EXP>::value,rectangle>::type
    spatially_filter_image (
        const in_image_type& in_img,
        out_image_type& out_img,
        const matrix_exp<EXP>& filter,
        T scale,
        bool use_abs = false,
        bool add_to = false
    )
    {
        if (use_abs == false)
        {
            if (scale == 1)
                return impl::float_spatially_filter_image(in_img, out_img, filter, add_to);
            else
                return impl::float_spatially_filter_image(in_img, out_img, filter/scale, add_to);
        }
        else
        {
            return impl::grayscale_spatially_filter_image(in_img, out_img, filter, scale, true, add_to);
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type,
        typename EXP,
        typename T
        >
    typename enable_if_c<pixel_traits<typename image_traits<out_image_type>::pixel_type>::grayscale &&
                         !is_float_filtering2<in_image_type,out_image_type,EXP>::value,rectangle>::type
    spatially_filter_image (
        const in_image_type& in_img,
        out_image_type& out_img,
        const matrix_exp<EXP>& filter,
        T scale,
        bool use_abs = false,
        bool add_to = false
    )
    {
        return impl::grayscale_spatially_filter_image(in_img,out_img,filter,scale,use_abs,add_to);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type,
        typename EXP,
        typename T
        >
    typename disable_if_c<pixel_traits<typename image_traits<out_image_type>::pixel_type>::grayscale,rectangle>::type
    spatially_filter_image (
        const in_image_type& in_img_,
        out_image_type& out_img_,
        const matrix_exp<EXP>& filter_,
        T scale
    )
    {
        const_temp_matrix<EXP> filter(filter_);
        COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<in_image_type>::pixel_type>::has_alpha == false );
        COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<out_image_type>::pixel_type>::has_alpha == false );

        DLIB_ASSERT(scale != 0 && filter.size() != 0,
            "\trectangle spatially_filter_image()"
            << "\n\t You can't give a scale of zero or an empty filter."
            << "\n\t scale: "<< scale
            << "\n\t filter.nr(): "<< filter.nr()
            << "\n\t filter.nc(): "<< filter.nc()
            );
        DLIB_ASSERT(is_same_object(in_img_, out_img_) == false,
            "\trectangle spatially_filter_image()"
            << "\n\tYou must give two different image objects"
            );

        const_image_view<in_image_type> in_img(in_img_);
        image_view<out_image_type> out_img(out_img_);

        // if there isn't any input image then don't do anything
        if (in_img.size() == 0)
        {
            out_img.clear();
            return rectangle();
        }

        out_img.set_size(in_img.nr(),in_img.nc());

        // figure out the range that we should apply the filter to
        const long first_row = filter.nr()/2;
        const long first_col = filter.nc()/2;
        const long last_row = in_img.nr() - ((filter.nr()-1)/2);
        const long last_col = in_img.nc() - ((filter.nc()-1)/2);

        const rectangle non_border = rectangle(first_col, first_row, last_col-1, last_row-1);
        zero_border_pixels(out_img, non_border);

        // apply the filter to the image
        for (long r = first_row; r < last_row; ++r)
        {
            for (long c = first_col; c < last_col; ++c)
            {
                typedef typename image_traits<in_image_type>::pixel_type pixel_type;
                typedef matrix<typename EXP::type,pixel_traits<pixel_type>::num,1> ptype;
                ptype p;
                ptype temp;
                temp = 0;
                for (long m = 0; m < filter.nr(); ++m)
                {
                    for (long n = 0; n < filter.nc(); ++n)
                    {
                        // pull out the current pixel and put it into p
                        p = pixel_to_vector<typename EXP::type>(in_img[r-first_row+m][c-first_col+n]);
                        temp += p*filter(m,n);
                    }
                }

                temp /= scale;

                pixel_type pp;
                vector_to_pixel(pp, temp);
                assign_pixel(out_img[r][c], pp);
            }
        }

        return non_border;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type,
        typename EXP
        >
    rectangle spatially_filter_image (
        const in_image_type& in_img,
        out_image_type& out_img,
        const matrix_exp<EXP>& filter
    )
    {
        return spatially_filter_image(in_img,out_img,filter,1);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    namespace impl
    {
        template <
            typename in_image_type,
            typename out_image_type,
            typename EXP1,
            typename EXP2,
            typename T
            >
        rectangle grayscale_spatially_filter_image_separable (
            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,
            bool add_to
        )
        {
            const_temp_matrix<EXP1> row_filter(_row_filter);
            const_temp_matrix<EXP2> col_filter(_col_filter);
            COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<in_image_type>::pixel_type>::has_alpha == false );
            COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<out_image_type>::pixel_type>::has_alpha == false );

            DLIB_ASSERT(scale != 0 && row_filter.size() != 0 && col_filter.size() != 0 &&
                is_vector(row_filter) &&
                is_vector(col_filter),
                "\trectangle spatially_filter_image_separable()"
                << "\n\t Invalid inputs were given to this function."
                << "\n\t scale: "<< scale
                << "\n\t row_filter.size(): "<< row_filter.size()
                << "\n\t col_filter.size(): "<< col_filter.size()
                << "\n\t is_vector(row_filter): "<< is_vector(row_filter)
                << "\n\t is_vector(col_filter): "<< is_vector(col_filter)
            );
            DLIB_ASSERT(is_same_object(in_img_, out_img_) == false,
                "\trectangle spatially_filter_image_separable()"
                << "\n\tYou must give two different image objects"
            );

            const_image_view<in_image_type> in_img(in_img_);
            image_view<out_image_type> out_img(out_img_);

            // if there isn't any input image then don't do anything
            if (in_img.size() == 0)
            {
                out_img.clear();
                return rectangle();
            }

            out_img.set_size(in_img.nr(),in_img.nc());

            // figure out the range that we should apply the filter to
            const long first_row = col_filter.size()/2;
            const long first_col = row_filter.size()/2;
            const long last_row = in_img.nr() - ((col_filter.size()-1)/2);
            const long last_col = in_img.nc() - ((row_filter.size()-1)/2);

            const rectangle non_border = rectangle(first_col, first_row, last_col-1, last_row-1);
            if (!add_to)
                zero_border_pixels(out_img, non_border);

            typedef typename EXP1::type ptype;

            array2d<ptype> temp_img;
            temp_img.set_size(in_img.nr(), in_img.nc());

            // apply the row filter
            for (long r = 0; r < in_img.nr(); ++r)
            {
                for (long c = first_col; c < last_col; ++c)
                {
                    ptype p;
                    ptype temp = 0;
                    for (long n = 0; n < row_filter.size(); ++n)
                    {
                        // pull out the current pixel and put it into p
                        p = get_pixel_intensity(in_img[r][c-first_col+n]);
                        temp += p*row_filter(n);
                    }
                    temp_img[r][c] = temp;
                }
            }

            // apply the column filter
            for (long r = first_row; r < last_row; ++r)
            {
                for (long c = first_col; c < last_col; ++c)
                {
                    ptype temp = 0;
                    for (long m = 0; m < col_filter.size(); ++m)
                    {
                        temp += temp_img[r-first_row+m][c]*col_filter(m);
                    }

                    temp /= scale;

                    if (use_abs && temp < 0)
                    {
                        temp = -temp;
                    }

                    // save this pixel to the output image
                    if (add_to == false)
                    {
                        assign_pixel(out_img[r][c], temp);
                    }
                    else
                    {
                        assign_pixel(out_img[r][c], temp + out_img[r][c]);
                    }
                }
            }
            return non_border;
        }

    } // namespace impl

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type,
        typename EXP1,
        typename EXP2
        >
    struct is_float_filtering
    {
        const static bool value = is_same_type<typename image_traits<in_image_type>::pixel_type,float>::value &&
                                  is_same_type<typename image_traits<out_image_type>::pixel_type,float>::value &&
                                  is_same_type<typename EXP1::type,float>::value &&
                                  is_same_type<typename EXP2::type,float>::value;
    };

// ----------------------------------------------------------------------------------------

    // This overload is optimized to use SIMD instructions when filtering float images with
    // float filters.
    template <
        typename in_image_type,
        typename out_image_type,
        typename EXP1,
        typename EXP2
        >
    rectangle float_spatially_filter_image_separable (
        const in_image_type& in_img_,
        out_image_type& out_img_,
        const matrix_exp<EXP1>& _row_filter,
        const matrix_exp<EXP2>& _col_filter,
        out_image_type& scratch_,
        bool add_to = false
    )
    {
        // You can only use this function with images and filters containing float
        // variables.
        COMPILE_TIME_ASSERT((is_float_filtering<in_image_type,out_image_type,EXP1,EXP2>::value == true));

        const_temp_matrix<EXP1> row_filter(_row_filter);
        const_temp_matrix<EXP2> col_filter(_col_filter);
        DLIB_ASSERT(row_filter.size() != 0 && col_filter.size() != 0 &&
            is_vector(row_filter) &&
            is_vector(col_filter),
            "\trectangle float_spatially_filter_image_separable()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t row_filter.size(): "<< row_filter.size()
            << "\n\t col_filter.size(): "<< col_filter.size()
            << "\n\t is_vector(row_filter): "<< is_vector(row_filter)
            << "\n\t is_vector(col_filter): "<< is_vector(col_filter)
        );
        DLIB_ASSERT(is_same_object(in_img_, out_img_) == false,
            "\trectangle float_spatially_filter_image_separable()"
            << "\n\tYou must give two different image objects"
        );

        const_image_view<in_image_type> in_img(in_img_);
        image_view<out_image_type> out_img(out_img_);

        // if there isn't any input image then don't do anything
        if (in_img.size() == 0)
        {
            out_img.clear();
            return rectangle();
        }

        out_img.set_size(in_img.nr(),in_img.nc());

        // figure out the range that we should apply the filter to
        const long first_row = col_filter.size()/2;
        const long first_col = row_filter.size()/2;
        const long last_row = in_img.nr() - ((col_filter.size()-1)/2);
        const long last_col = in_img.nc() - ((row_filter.size()-1)/2);

        const rectangle non_border = rectangle(first_col, first_row, last_col-1, last_row-1);
        if (!add_to)
            zero_border_pixels(out_img, non_border);

        image_view<out_image_type> scratch(scratch_);
        scratch.set_size(in_img.nr(), in_img.nc());

        // apply the row filter
        for (long r = 0; r < in_img.nr(); ++r)
        {
            long c = first_col;
            for (; c < last_col-7; c+=8)
            {
                simd8f p,p2,p3, temp = 0, temp2=0, temp3=0;
                long n = 0;
                for (; n < row_filter.size()-2; n+=3)
                {
                    // pull out the current pixel and put it into p
                    p.load(&in_img[r][c-first_col+n]);
                    p2.load(&in_img[r][c-first_col+n+1]);
                    p3.load(&in_img[r][c-first_col+n+2]);
                    temp += p*row_filter(n);
                    temp2 += p2*row_filter(n+1);
                    temp3 += p3*row_filter(n+2);
                }
                for (; n < row_filter.size(); ++n)
                {
                    // pull out the current pixel and put it into p
                    p.load(&in_img[r][c-first_col+n]);
                    temp += p*row_filter(n);
                }
                temp += temp2 + temp3;
                temp.store(&scratch[r][c]);
            }
            for (; c < last_col; ++c)
            {
                float p;
                float temp = 0;
                for (long n = 0; n < row_filter.size(); ++n)
                {
                    // pull out the current pixel and put it into p
                    p = in_img[r][c-first_col+n];
                    temp += p*row_filter(n);
                }
                scratch[r][c] = temp;
            }
        }

        // apply the column filter
        for (long r = first_row; r < last_row; ++r)
        {
            long c = first_col;
            for (; c < last_col-7; c+=8)
            {
                simd8f p, p2, p3, temp = 0, temp2 = 0, temp3 = 0;
                long m = 0;
                for (; m < col_filter.size()-2; m+=3)
                {
                    p.load(&scratch[r-first_row+m][c]);
                    p2.load(&scratch[r-first_row+m+1][c]);
                    p3.load(&scratch[r-first_row+m+2][c]);
                    temp += p*col_filter(m);
                    temp2 += p2*col_filter(m+1);
                    temp3 += p3*col_filter(m+2);
                }
                for (; m < col_filter.size(); ++m)
                {
                    p.load(&scratch[r-first_row+m][c]);
                    temp += p*col_filter(m);
                }
                temp += temp2+temp3;

                // save this pixel to the output image
                if (add_to == false)
                {
                    temp.store(&out_img[r][c]);
                }
                else
                {
                    p.load(&out_img[r][c]);
                    temp += p;
                    temp.store(&out_img[r][c]);
                }
            }
            for (; c < last_col; ++c)
            {
                float temp = 0;
                for (long m = 0; m < col_filter.size(); ++m)
                {
                    temp += scratch[r-first_row+m][c]*col_filter(m);
                }

                // save this pixel to the output image
                if (add_to == false)
                {
                    out_img[r][c] = temp;
                }
                else
                {
                    out_img[r][c] += temp;
                }
            }
        }
        return non_border;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type,
        typename EXP1,
        typename EXP2,
        typename T
        >
    typename enable_if_c<pixel_traits<typename image_traits<out_image_type>::pixel_type>::grayscale &&
                         is_float_filtering<in_image_type,out_image_type,EXP1,EXP2>::value,rectangle>::type
    spatially_filter_image_separable (
        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
    )
    {
        if (use_abs == false)
        {
            out_image_type scratch;
            if (scale == 1)
                return float_spatially_filter_image_separable(in_img, out_img, row_filter, col_filter, scratch, add_to);
            else
                return float_spatially_filter_image_separable(in_img, out_img, row_filter/scale, col_filter, scratch,  add_to);
        }
        else
        {
            return impl::grayscale_spatially_filter_image_separable(in_img, out_img, row_filter, col_filter, scale, true, add_to);
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type,
        typename EXP1,
        typename EXP2,
        typename T
        >
    typename enable_if_c<pixel_traits<typename image_traits<out_image_type>::pixel_type>::grayscale &&
                         !is_float_filtering<in_image_type,out_image_type,EXP1,EXP2>::value,rectangle>::type
    spatially_filter_image_separable (
        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
    )
    {
        return impl::grayscale_spatially_filter_image_separable(in_img,out_img, row_filter, col_filter, scale, use_abs, add_to);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type,
        typename EXP1,
        typename EXP2,
        typename T
        >
    typename disable_if_c<pixel_traits<typename image_traits<out_image_type>::pixel_type>::grayscale,rectangle>::type
    spatially_filter_image_separable (
        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
    )
    {
        const_temp_matrix<EXP1> row_filter(_row_filter);
        const_temp_matrix<EXP2> col_filter(_col_filter);
        COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<in_image_type>::pixel_type>::has_alpha == false );
        COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<out_image_type>::pixel_type>::has_alpha == false );

        DLIB_ASSERT(scale != 0 && row_filter.size() != 0 && col_filter.size() != 0 &&
                    is_vector(row_filter) &&
                    is_vector(col_filter),
            "\trectangle spatially_filter_image_separable()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t scale: "<< scale
            << "\n\t row_filter.size(): "<< row_filter.size()
            << "\n\t col_filter.size(): "<< col_filter.size()
            << "\n\t is_vector(row_filter): "<< is_vector(row_filter)
            << "\n\t is_vector(col_filter): "<< is_vector(col_filter)
            );
        DLIB_ASSERT(is_same_object(in_img_, out_img_) == false,
            "\trectangle spatially_filter_image_separable()"
            << "\n\tYou must give two different image objects"
            );

        const_image_view<in_image_type> in_img(in_img_);
        image_view<out_image_type> out_img(out_img_);

        // if there isn't any input image then don't do anything
        if (in_img.size() == 0)
        {
            out_img.clear();
            return rectangle();
        }

        out_img.set_size(in_img.nr(),in_img.nc());

        // figure out the range that we should apply the filter to
        const long first_row = col_filter.size()/2;
        const long first_col = row_filter.size()/2;
        const long last_row = in_img.nr() - ((col_filter.size()-1)/2);
        const long last_col = in_img.nc() - ((row_filter.size()-1)/2);

        const rectangle non_border = rectangle(first_col, first_row, last_col-1, last_row-1);
        zero_border_pixels(out_img, non_border);

        typedef typename image_traits<in_image_type>::pixel_type pixel_type;
        typedef matrix<typename EXP1::type,pixel_traits<pixel_type>::num,1> ptype;

        array2d<ptype> temp_img;
        temp_img.set_size(in_img.nr(), in_img.nc());

        // apply the row filter
        for (long r = 0; r < in_img.nr(); ++r)
        {
            for (long c = first_col; c < last_col; ++c)
            {
                ptype p;
                ptype temp;
                temp = 0;
                for (long n = 0; n < row_filter.size(); ++n)
                {
                    // pull out the current pixel and put it into p
                    p = pixel_to_vector<typename EXP1::type>(in_img[r][c-first_col+n]);
                    temp += p*row_filter(n);
                }
                temp_img[r][c] = temp;
            }
        }

        // apply the column filter
        for (long r = first_row; r < last_row; ++r)
        {
            for (long c = first_col; c < last_col; ++c)
            {
                ptype temp;
                temp = 0;
                for (long m = 0; m < col_filter.size(); ++m)
                {
                    temp += temp_img[r-first_row+m][c]*col_filter(m);
                }

                temp /= scale;

                // save this pixel to the output image
                pixel_type p;
                vector_to_pixel(p, temp);
                assign_pixel(out_img[r][c], p);
            }
        }
        return non_border;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type,
        typename EXP1,
        typename EXP2
        >
    rectangle spatially_filter_image_separable (
        const in_image_type& in_img,
        out_image_type& out_img,
        const matrix_exp<EXP1>& row_filter,
        const matrix_exp<EXP2>& col_filter
    )
    {
        return spatially_filter_image_separable(in_img,out_img,row_filter,col_filter,1);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type,
        typename EXP1,
        typename EXP2,
        typename T
        >
    rectangle spatially_filter_image_separable_down (
        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
    )
    {
        COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<in_image_type>::pixel_type>::has_alpha == false );
        COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<out_image_type>::pixel_type>::has_alpha == false );
        COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<out_image_type>::pixel_type>::grayscale == true );

        DLIB_ASSERT(downsample > 0 &&
                    scale != 0 &&
                    row_filter.size()%2 == 1 &&
                    col_filter.size()%2 == 1 &&
                    is_vector(row_filter) &&
                    is_vector(col_filter),
            "\trectangle spatially_filter_image_separable_down()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t downsample: "<< downsample
            << "\n\t scale: "<< scale
            << "\n\t row_filter.size(): "<< row_filter.size()
            << "\n\t col_filter.size(): "<< col_filter.size()
            << "\n\t is_vector(row_filter): "<< is_vector(row_filter)
            << "\n\t is_vector(col_filter): "<< is_vector(col_filter)
            );
        DLIB_ASSERT(is_same_object(in_img_, out_img_) == false,
            "\trectangle spatially_filter_image_separable_down()"
            << "\n\tYou must give two different image objects"
            );

        const_image_view<in_image_type> in_img(in_img_);
        image_view<out_image_type> out_img(out_img_);

        // if there isn't any input image then don't do anything
        if (in_img.size() == 0)
        {
            out_img.clear();
            return rectangle();
        }

        out_img.set_size((long)(std::ceil((double)in_img.nr()/downsample)),
                         (long)(std::ceil((double)in_img.nc()/downsample)));

        const double col_border = std::floor(col_filter.size()/2.0);
        const double row_border = std::floor(row_filter.size()/2.0);

        // figure out the range that we should apply the filter to
        const long first_row = (long)std::ceil(col_border/downsample);
        const long first_col = (long)std::ceil(row_border/downsample);
        const long last_row  = (long)std::ceil((in_img.nr() - col_border)/downsample) - 1;
        const long last_col  = (long)std::ceil((in_img.nc() - row_border)/downsample) - 1;

        // zero border pixels
        const rectangle non_border = rectangle(first_col, first_row, last_col, last_row);
        zero_border_pixels(out_img,non_border);

        typedef typename EXP1::type ptype;

        array2d<ptype> temp_img;
        temp_img.set_size(in_img.nr(), out_img.nc());

        // apply the row filter
        for (long r = 0; r < temp_img.nr(); ++r)
        {
            for (long c = non_border.left(); c <= non_border.right(); ++c)
            {
                ptype p;
                ptype temp = 0;
                for (long n = 0; n < row_filter.size(); ++n)
                {
                    // pull out the current pixel and put it into p
                    p = get_pixel_intensity(in_img[r][c*downsample-row_filter.size()/2+n]);
                    temp += p*row_filter(n);
                }
                temp_img[r][c] = temp;
            }
        }

        // apply the column filter
        for (long r = non_border.top(); r <= non_border.bottom(); ++r)
        {
            for (long c = non_border.left(); c <= non_border.right(); ++c)
            {
                ptype temp = 0;
                for (long m = 0; m < col_filter.size(); ++m)
                {
                    temp += temp_img[r*downsample-col_filter.size()/2+m][c]*col_filter(m);
                }

                temp /= scale;

                if (use_abs && temp < 0)
                {
                    temp = -temp;
                }

                // save this pixel to the output image
                if (add_to == false)
                {
                    assign_pixel(out_img[r][c], temp);
                }
                else
                {
                    assign_pixel(out_img[r][c], temp + out_img[r][c]);
                }
            }
        }

        return non_border;
    }

    template <
        typename in_image_type,
        typename out_image_type,
        typename EXP1,
        typename EXP2
        >
    rectangle spatially_filter_image_separable_down (
        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
    )
    {
        return spatially_filter_image_separable_down(downsample,in_img,out_img,row_filter,col_filter,1);
    }

// ----------------------------------------------------------------------------------------

    template <
        long NR,
        long NC,
        typename T,
        typename U,
        typename in_image_type
        >
    inline void separable_3x3_filter_block_grayscale (
        T (&block)[NR][NC],
        const in_image_type& img_,
        const long& r,
        const long& c,
        const U& fe1, // separable filter end
        const U& fm,  // separable filter middle
        const U& fe2 // separable filter end 2
    )
    {
        const_image_view<in_image_type> img(img_);
        // make sure requires clause is not broken
        DLIB_ASSERT(shrink_rect(get_rect(img),1).contains(c,r) &&
                    shrink_rect(get_rect(img),1).contains(c+NC-1,r+NR-1),
            "\t void separable_3x3_filter_block_grayscale()"
            << "\n\t The sub-window doesn't fit inside the given image."
            << "\n\t get_rect(img):       " << get_rect(img)
            << "\n\t (c,r):               " << point(c,r)
            << "\n\t (c+NC-1,r+NR-1): " << point(c+NC-1,r+NR-1)
            );

        T row_filt[NR+2][NC];
        for (long rr = 0; rr < NR+2; ++rr)
        {
            for (long cc = 0; cc < NC; ++cc)
            {
                row_filt[rr][cc] = get_pixel_intensity(img[r+rr-1][c+cc-1])*fe1 +
                                   get_pixel_intensity(img[r+rr-1][c+cc])*fm +
                                   get_pixel_intensity(img[r+rr-1][c+cc+1])*fe2;
            }
        }

        for (long rr = 0; rr < NR; ++rr)
        {
            for (long cc = 0; cc < NC; ++cc)
            {
                block[rr][cc] = (row_filt[rr][cc]*fe1 +
                                row_filt[rr+1][cc]*fm +
                                row_filt[rr+2][cc]*fe2);
            }
        }

    }

// ----------------------------------------------------------------------------------------

    template <
        long NR,
        long NC,
        typename T,
        typename U,
        typename in_image_type
        >
    inline void separable_3x3_filter_block_rgb (
        T (&block)[NR][NC],
        const in_image_type& img_,
        const long& r,
        const long& c,
        const U& fe1, // separable filter end
        const U& fm,  // separable filter middle
        const U& fe2  // separable filter end 2
    )
    {
        const_image_view<in_image_type> img(img_);
        // make sure requires clause is not broken
        DLIB_ASSERT(shrink_rect(get_rect(img),1).contains(c,r) &&
                    shrink_rect(get_rect(img),1).contains(c+NC-1,r+NR-1),
            "\t void separable_3x3_filter_block_rgb()"
            << "\n\t The sub-window doesn't fit inside the given image."
            << "\n\t get_rect(img):       " << get_rect(img)
            << "\n\t (c,r):               " << point(c,r)
            << "\n\t (c+NC-1,r+NR-1): " << point(c+NC-1,r+NR-1)
            );

        T row_filt[NR+2][NC];
        for (long rr = 0; rr < NR+2; ++rr)
        {
            for (long cc = 0; cc < NC; ++cc)
            {
                row_filt[rr][cc].red   = img[r+rr-1][c+cc-1].red*fe1   + img[r+rr-1][c+cc].red*fm   + img[r+rr-1][c+cc+1].red*fe2;
                row_filt[rr][cc].green = img[r+rr-1][c+cc-1].green*fe1 + img[r+rr-1][c+cc].green*fm + img[r+rr-1][c+cc+1].green*fe2;
                row_filt[rr][cc].blue  = img[r+rr-1][c+cc-1].blue*fe1  + img[r+rr-1][c+cc].blue*fm  + img[r+rr-1][c+cc+1].blue*fe2;
            }
        }

        for (long rr = 0; rr < NR; ++rr)
        {
            for (long cc = 0; cc < NC; ++cc)
            {
                block[rr][cc].red   = row_filt[rr][cc].red*fe1   + row_filt[rr+1][cc].red*fm   + row_filt[rr+2][cc].red*fe2;
                block[rr][cc].green = row_filt[rr][cc].green*fe1 + row_filt[rr+1][cc].green*fm + row_filt[rr+2][cc].green*fe2;
                block[rr][cc].blue  = row_filt[rr][cc].blue*fe1  + row_filt[rr+1][cc].blue*fm  + row_filt[rr+2][cc].blue*fe2;
            }
        }

    }

// ----------------------------------------------------------------------------------------

    inline double gaussian (
        double x,
        double sigma
    )
    {
        DLIB_ASSERT(sigma > 0,
            "\tdouble gaussian(x)"
            << "\n\t sigma must be bigger than 0"
            << "\n\t sigma: " << sigma
        );
        const double sqrt_2_pi = 2.5066282746310002416123552393401041626930;
        return 1.0/(sigma*sqrt_2_pi) * std::exp( -(x*x)/(2*sigma*sigma));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    matrix<T,0,1> create_gaussian_filter (
        double sigma,
        int max_size
    )
    {
        DLIB_ASSERT(sigma > 0 && max_size > 0 && (max_size%2)==1,
            "\t matrix<T,0,1> create_gaussian_filter()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t sigma: " << sigma
            << "\n\t max_size:  " << max_size
        );

        // Adjust the size so that the ratio of the gaussian values isn't huge.
        // This only matters when T is an integer type.  However, we do it for
        // all types so that the behavior of this function is always relatively
        // the same.
        while (gaussian(0,sigma)/gaussian(max_size/2,sigma) > 50)
            --max_size;

        matrix<double,0,1> f(max_size);
        for (long i = 0; i < f.size(); ++i)
        {
            f(i) = gaussian(i-max_size/2, sigma);
        }

        if (is_float_type<T>::value == false)
        {
            f /= f(0);
            return matrix_cast<T>(round(f));
        }
        else
        {
            return matrix_cast<T>(f);
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type
        >
    rectangle gaussian_blur (
        const in_image_type& in_img,
        out_image_type& out_img,
        double sigma = 1,
        int max_size = 1001
    )
    {
        DLIB_ASSERT(sigma > 0 && max_size > 0 && (max_size%2)==1 &&
                    is_same_object(in_img, out_img) == false,
            "\t void gaussian_blur()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t sigma: " << sigma
            << "\n\t max_size:  " << max_size
            << "\n\t is_same_object(in_img,out_img): " << is_same_object(in_img,out_img)
        );

        typedef typename pixel_traits<typename image_traits<out_image_type>::pixel_type>::basic_pixel_type type;
        typedef typename promote<type>::type ptype;

        const matrix<ptype,0,1>& filt = create_gaussian_filter<ptype>(sigma, max_size);

        ptype scale = sum(filt);
        scale = scale*scale;

        return spatially_filter_image_separable(in_img, out_img, filt, filt, scale);

    }

// ----------------------------------------------------------------------------------------

    namespace impl
    {
    template <
        bool add_to,
        typename image_type1,
        typename image_type2
        >
    void sum_filter (
        const image_type1& img_,
        image_type2& out_,
        const rectangle& rect
    )
    {
        const_image_view<image_type1> img(img_);
        image_view<image_type2> out(out_);
        DLIB_ASSERT(img.nr() == out.nr() &&
                    img.nc() == out.nc() &&
                    is_same_object(img_,out_) == false,
            "\t void sum_filter()"
            << "\n\t Invalid arguments given to this function."
            << "\n\t img.nr(): " << img.nr()
            << "\n\t img.nc(): " << img.nc()
            << "\n\t out.nr(): " << out.nr()
            << "\n\t out.nc(): " << out.nc()
            << "\n\t is_same_object(img_,out_): " << is_same_object(img_,out_)
        );

        typedef typename image_traits<image_type1>::pixel_type pixel_type;
        typedef typename promote<pixel_type>::type ptype;

        std::vector<ptype> column_sum;
        column_sum.resize(img.nc() + rect.width(),0);

        const long top    = -1 + rect.top();
        const long bottom = -1 + rect.bottom();
        long left = rect.left()-1;

        // initialize column_sum at row -1
        for (unsigned long j = 0; j < column_sum.size(); ++j)
        {
            rectangle strip(left,top,left,bottom);
            strip = strip.intersect(get_rect(img));
            if (!strip.is_empty())
            {
                column_sum[j] = sum(matrix_cast<ptype>(subm(mat(img),strip)));
            }

            ++left;
        }

        const rectangle area = get_rect(img);

        // Save width to avoid computing it over and over.
        const long width = rect.width();

        // Now do the bulk of the filtering work.
        for (long r = 0; r < img.nr(); ++r)
        {
            // set to sum at point(-1,r). i.e. should be equal to sum(mat(img), translate_rect(rect, point(-1,r)))
            // We compute it's value in the next loop.
            ptype cur_sum = 0;

            // Update the first part of column_sum since we only work on the c+width part of column_sum
            // in the main loop.
            const long top    = r + rect.top() - 1;
            const long bottom = r + rect.bottom();
            for (long k = 0; k < width; ++k)
            {
                const long right  = k-width + rect.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_sum[k] = column_sum[k] + br_corner - tr_corner;
                cur_sum += column_sum[k];
            }

            for (long c = 0; c < img.nc(); ++c)
            {
                const long top    = r + rect.top() - 1;
                const long bottom = r + rect.bottom();
                const long right  = c + rect.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_sum[c+width] = column_sum[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_sum[c+width] - column_sum[c];

                if (add_to)
                    out[r][c] += static_cast<typename image_traits<image_type2>::pixel_type>(cur_sum);
                else
                    out[r][c] = static_cast<typename image_traits<image_type2>::pixel_type>(cur_sum);
            }
        }
    }
    }

    template <
        typename image_type1,
        typename image_type2
        >
    void sum_filter (
        const image_type1& img,
        image_type2& out,
        const rectangle& rect
    )
    {
        impl::sum_filter<true>(img,out,rect);
    }

    template <
        typename image_type1,
        typename image_type2
        >
    void sum_filter_assign (
        const image_type1& img,
        image_type2& out,
        const rectangle& rect
    )
    {
        set_image_size(out, num_rows(img), num_columns(img));
        impl::sum_filter<false>(img,out,rect);
    }

// ----------------------------------------------------------------------------------------

    namespace impl
    {
        template <typename T>
        class fast_deque
        {
        /*
            This is a fast and minimal implementation of std::deque for
            use with the max_filter.

            This object assumes that no more than max_size elements
            will ever be pushed into it at a time.
        */
        public:

            explicit fast_deque(unsigned long max_size)
            {
                // find a power of two that upper bounds max_size
                mask = 2;
                while (mask < max_size)
                    mask *= 2;

                clear();

                data.resize(mask);
                --mask;  // make into bit mask
            }

            void clear()
            {
                first = 1;
                last = 0;
                size = 0;
            }

            bool empty() const
            {
                return size == 0;
            }

            void pop_back()
            {
                last = (last-1)&mask;
                --size;
            }

            void push_back(const T& item)
            {
                last = (last+1)&mask;
                ++size;
                data[last] = item;
            }

            void pop_front()
            {
                first = (first+1)&mask;
                --size;
            }

            const T& front() const
            {
                return data[first];
            }

            const T& back() const
            {
                return data[last];
            }

        private:

            std::vector<T> data;
            unsigned long mask;
            unsigned long first;
            unsigned long last;
            unsigned long size;
        };
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_type1,
        typename image_type2
        >
    void max_filter (
        image_type1& img_,
        image_type2& out_,
        const long width,
        const long height,
        const typename image_traits<image_type1>::pixel_type& thresh
    )
    {
        image_view<image_type1> img(img_);
        image_view<image_type2> out(out_);
        DLIB_ASSERT( width > 0 &&
                     height > 0 &&
                     out.nr() == img.nr() &&
                     out.nc() == img.nc() &&
                     is_same_object(img_,out_) == false,
                "\t void max_filter()"
                << "\n\t Invalid arguments given to this function."
                << "\n\t img.nr(): " << img.nr()
                << "\n\t img.nc(): " << img.nc()
                << "\n\t out.nr(): " << out.nr()
                << "\n\t out.nc(): " << out.nc()
                << "\n\t width:    " << width
                << "\n\t height:   " << height
                << "\n\t is_same_object(img_,out_): " << is_same_object(img_,out_)
                     );

        typedef typename image_traits<image_type1>::pixel_type pixel_type;

        dlib::impl::fast_deque<std::pair<long,pixel_type> > Q(std::max(width,height));

        const long last_col = std::max(img.nc(), ((width-1)/2));
        const long last_row = std::max(img.nr(), ((height-1)/2));

        // run max filter along rows of img
        for (long r = 0; r < img.nr(); ++r)
        {
            Q.clear();
            for (long c = 0; c < (width-1)/2 && c < img.nc(); ++c)
            {
                while (!Q.empty() && img[r][c] >= Q.back().second)
                    Q.pop_back();
                Q.push_back(std::make_pair(c,img[r][c]));
            }

            for (long c = (width-1)/2; c < img.nc(); ++c)
            {
                while (!Q.empty() && img[r][c] >= Q.back().second)
                    Q.pop_back();
                while (!Q.empty() && Q.front().first <= c-width)
                    Q.pop_front();
                Q.push_back(std::make_pair(c,img[r][c]));

                img[r][c-((width-1)/2)] = Q.front().second;
            }

            for (long c = last_col; c < img.nc() + ((width-1)/2); ++c)
            {
                while (!Q.empty() && Q.front().first <= c-width)
                    Q.pop_front();

                img[r][c-((width-1)/2)] = Q.front().second;
            }
        }

        // run max filter along columns of img.  Store result in out.
        for (long cc = 0; cc < img.nc(); ++cc)
        {
            Q.clear();
            for (long rr = 0; rr < (height-1)/2 && rr < img.nr(); ++rr)
            {
                while (!Q.empty() && img[rr][cc] >= Q.back().second)
                    Q.pop_back();
                Q.push_back(std::make_pair(rr,img[rr][cc]));
            }

            for (long rr = (height-1)/2; rr < img.nr(); ++rr)
            {
                while (!Q.empty() && img[rr][cc] >= Q.back().second)
                    Q.pop_back();
                while (!Q.empty() && Q.front().first <= rr-height)
                    Q.pop_front();
                Q.push_back(std::make_pair(rr,img[rr][cc]));

                out[rr-((height-1)/2)][cc] += std::max(Q.front().second, thresh);
            }

            for (long rr = last_row; rr < img.nr() + ((height-1)/2); ++rr)
            {
                while (!Q.empty() && Q.front().first <= rr-height)
                    Q.pop_front();

                out[rr-((height-1)/2)][cc] += std::max(Q.front().second, thresh);
            }
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SPATIAL_FILTERINg_H_


dlib C++ Library - thresholding.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_THRESHOLDINg_
#define DLIB_THRESHOLDINg_

#include "../pixel.h"
#include "thresholding_abstract.h"
#include "equalize_histogram.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    const unsigned char on_pixel = 255;
    const unsigned char off_pixel = 0;

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type
        >
    void threshold_image (
        const in_image_type& in_img_,
        out_image_type& out_img_,
        typename pixel_traits<typename image_traits<in_image_type>::pixel_type>::basic_pixel_type thresh
    )
    {
        COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<in_image_type>::pixel_type>::has_alpha == false );
        COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<out_image_type>::pixel_type>::has_alpha == false );

        COMPILE_TIME_ASSERT(pixel_traits<typename image_traits<out_image_type>::pixel_type>::grayscale);

        const_image_view<in_image_type> in_img(in_img_);
        image_view<out_image_type> out_img(out_img_);

        // if there isn't any input image then don't do anything
        if (in_img.size() == 0)
        {
            out_img.clear();
            return;
        }

        out_img.set_size(in_img.nr(),in_img.nc());

        for (long r = 0; r < in_img.nr(); ++r)
        {
            for (long c = 0; c < in_img.nc(); ++c)
            {
                if (get_pixel_intensity(in_img[r][c]) >= thresh)
                    assign_pixel(out_img[r][c], on_pixel);
                else
                    assign_pixel(out_img[r][c], off_pixel);
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        >
    void threshold_image (
        image_type& img,
        typename pixel_traits<typename image_traits<image_type>::pixel_type>::basic_pixel_type thresh
    )
    {
        threshold_image(img,img,thresh);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type
        >
    void auto_threshold_image (
        const in_image_type& in_img_,
        out_image_type& out_img_
    )
    {
        COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<in_image_type>::pixel_type>::has_alpha == false );
        COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<out_image_type>::pixel_type>::has_alpha == false );
        COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<in_image_type>::pixel_type>::is_unsigned == true );
        COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<out_image_type>::pixel_type>::is_unsigned == true );

        COMPILE_TIME_ASSERT(pixel_traits<typename image_traits<out_image_type>::pixel_type>::grayscale);

        image_view<out_image_type> out_img(out_img_);

        // if there isn't any input image then don't do anything
        if (image_size(in_img_) == 0)
        {
            out_img.clear();
            return;
        }

        unsigned long thresh;
        // find the threshold we should use
        matrix<unsigned long,1> hist;
        get_histogram(in_img_,hist);

        const_image_view<in_image_type> in_img(in_img_);

        // Start our two means (a and b) out at the ends of the histogram
        long a = 0;
        long b = hist.size()-1;
        bool moved_a = true;
        bool moved_b = true;
        while (moved_a || moved_b)
        {
            moved_a = false;
            moved_b = false;

            // catch the degenerate case where the histogram is empty
            if (a >= b)
                break;

            if (hist(a) == 0)
            {
                ++a;
                moved_a = true;
            }

            if (hist(b) == 0)
            {
                --b;
                moved_b = true;
            }
        }

        // now do k-means clustering with k = 2 on the histogram.
        moved_a = true;
        moved_b = true;
        while (moved_a || moved_b)
        {
            moved_a = false;
            moved_b = false;

            int64 a_hits = 0;
            int64 b_hits = 0;
            int64 a_mass = 0;
            int64 b_mass = 0;

            for (long i = 0; i < hist.size(); ++i)
            {
                // if i is closer to a
                if (std::abs(i-a) < std::abs(i-b))
                {
                    a_mass += hist(i)*i;
                    a_hits += hist(i);
                }
                else // if i is closer to b
                {
                    b_mass += hist(i)*i;
                    b_hits += hist(i);
                }
            }

            long new_a = (a_mass + a_hits/2)/a_hits;
            long new_b = (b_mass + b_hits/2)/b_hits;

            if (new_a != a)
            {
                moved_a = true;
                a = new_a;
            }

            if (new_b != b)
            {
                moved_b = true;
                b = new_b;
            }
        }

        // put the threshold between the two means we found
        thresh = (a + b)/2;

        // now actually apply the threshold
        threshold_image(in_img_,out_img_,thresh);
    }

    template <
        typename image_type
        >
    void auto_threshold_image (
        image_type& img
    )
    {
        auto_threshold_image(img,img);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename in_image_type,
        typename out_image_type
        >
    void hysteresis_threshold (
        const in_image_type& in_img_,
        out_image_type& out_img_,
        typename pixel_traits<typename image_traits<in_image_type>::pixel_type>::basic_pixel_type lower_thresh,
        typename pixel_traits<typename image_traits<in_image_type>::pixel_type>::basic_pixel_type upper_thresh
    )
    {
        COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<in_image_type>::pixel_type>::has_alpha == false );
        COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<out_image_type>::pixel_type>::has_alpha == false );

        COMPILE_TIME_ASSERT(pixel_traits<typename image_traits<out_image_type>::pixel_type>::grayscale);

        DLIB_ASSERT( lower_thresh <= upper_thresh && is_same_object(in_img_, out_img_) == false,
            "\tvoid hysteresis_threshold(in_img_, out_img_, lower_thresh, upper_thresh)"
            << "\n\tYou can't use an upper_thresh that is less than your lower_thresh"
            << "\n\tlower_thresh: " << lower_thresh
            << "\n\tupper_thresh: " << upper_thresh
            << "\n\tis_same_object(in_img_,out_img_): " << is_same_object(in_img_,out_img_)
            );

        const_image_view<in_image_type> in_img(in_img_);
        image_view<out_image_type> out_img(out_img_);

        // if there isn't any input image then don't do anything
        if (in_img.size() == 0)
        {
            out_img.clear();
            return;
        }

        out_img.set_size(in_img.nr(),in_img.nc());
        assign_all_pixels(out_img, off_pixel);

        const long size = 1000;
        long rstack[size];
        long cstack[size];

        // now do the thresholding
        for (long r = 0; r < in_img.nr(); ++r)
        {
            for (long c = 0; c < in_img.nc(); ++c)
            {
                typename pixel_traits<typename image_traits<in_image_type>::pixel_type>::basic_pixel_type p;
                assign_pixel(p,in_img[r][c]);
                if (p >= upper_thresh)
                {
                    // now do line following for pixels >= lower_thresh.
                    // set the stack position to 0.
                    long pos = 1;
                    rstack[0] = r;
                    cstack[0] = c;

                    while (pos > 0)
                    {
                        --pos;
                        const long r = rstack[pos];
                        const long c = cstack[pos];

                        // This is the base case of our recursion.  We want to stop if we hit a
                        // pixel we have already visited.
                        if (out_img[r][c] == on_pixel)
                            continue;

                        out_img[r][c] = on_pixel;

                        // put the neighbors of this pixel on the stack if they are bright enough
                        if (r-1 >= 0)
                        {
                            if (pos < size && get_pixel_intensity(in_img[r-1][c]) >= lower_thresh)
                            {
                                rstack[pos] = r-1;
                                cstack[pos] = c;
                                ++pos;
                            }
                            if (pos < size && c-1 >= 0 && get_pixel_intensity(in_img[r-1][c-1]) >= lower_thresh)
                            {
                                rstack[pos] = r-1;
                                cstack[pos] = c-1;
                                ++pos;
                            }
                            if (pos < size && c+1 < in_img.nc() && get_pixel_intensity(in_img[r-1][c+1]) >= lower_thresh)
                            {
                                rstack[pos] = r-1;
                                cstack[pos] = c+1;
                                ++pos;
                            }
                        }

                        if (pos < size && c-1 >= 0 && get_pixel_intensity(in_img[r][c-1]) >= lower_thresh)
                        {
                            rstack[pos] = r;
                            cstack[pos] = c-1;
                            ++pos;
                        }
                        if (pos < size && c+1 < in_img.nc() && get_pixel_intensity(in_img[r][c+1]) >= lower_thresh)
                        {
                            rstack[pos] = r;
                            cstack[pos] = c+1;
                            ++pos;
                        }

                        if (r+1 < in_img.nr())
                        {
                            if (pos < size && get_pixel_intensity(in_img[r+1][c]) >= lower_thresh)
                            {
                                rstack[pos] = r+1;
                                cstack[pos] = c;
                                ++pos;
                            }
                            if (pos < size && c-1 >= 0 && get_pixel_intensity(in_img[r+1][c-1]) >= lower_thresh)
                            {
                                rstack[pos] = r+1;
                                cstack[pos] = c-1;
                                ++pos;
                            }
                            if (pos < size && c+1 < in_img.nc() && get_pixel_intensity(in_img[r+1][c+1]) >= lower_thresh)
                            {
                                rstack[pos] = r+1;
                                cstack[pos] = c+1;
                                ++pos;
                            }
                        }

                    } // end while (pos >= 0)

                }
                else
                {
                    out_img[r][c] = off_pixel;
                }

            }
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_THRESHOLDINg_


dlib C++ Library - cmd_line_parser_option.h

// 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_OPTIOn_
#define DLIB_CMD_LINE_PARSER_OPTIOn_

#include <string>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename charT
        >
    class cmd_line_parser_option
    {
        /*!
            POINTERS AND REFERENCES TO INTERNAL DATA
                None of the functions in cmd_line_parser_option will invalidate
                pointers or references to internal data when called.

            WHAT THIS OBJECT REPRESENTS
                This object represents a command line option.
        !*/

    public:

        typedef charT char_type;
        typedef std::basic_string<charT> string_type;

        virtual ~cmd_line_parser_option (
        ) = 0;

        virtual const string_type& name (
        ) const = 0;
        /*!
            ensures
                - returns the name of this option
        !*/

        virtual const string_type& group_name (
        ) const = 0;
        /*!
            ensures
                - returns the name of the group this option is in.  If no group was set for
                  this option then this function returns "".
        !*/

        virtual const string_type& description (
        ) const = 0;
        /*!
            ensures
                - returns the description for this option
        !*/

        virtual unsigned long number_of_arguments(
        ) const = 0;
        /*!
            ensures
                - returns the number of arguments for this option
        !*/

        virtual unsigned long count(
        ) const = 0;
        /*!
            ensures
                - returns the number of times this option appears on the command line.
        !*/

        virtual const string_type& argument (
            unsigned long arg = 0,
            unsigned long N = 0
        ) const = 0;
        /*!
            requires
                - arg < number_of_arguments()
                - N < count()
            ensures
                - returns the arg-th argument to the Nth occurrence of this
                  option on the command line.
        !*/

        inline operator bool (
        ) const { return count() > 0; }
        /*!
            ensures
                - returns true if this option appears on the command line at all
        !*/

    protected:

        // restricted functions
        cmd_line_parser_option& operator=(const cmd_line_parser_option&){return *this;}

    };

    // destructor does nothing
    template < typename charT >
    cmd_line_parser_option<charT>::~cmd_line_parser_option() {}

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_CMD_LINE_PARSER_OPTIOn_


dlib C++ Library - linker_kernel_1.cpp

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_LINKER_KERNEL_1_CPp_
#define DLIB_LINKER_KERNEL_1_CPp_
#include "linker_kernel_1.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    linker::
    linker (
    ) :
        running(false),
        running_signaler(running_mutex),
        A(0),
        B(0),
        service_connection_running_signaler(service_connection_running_mutex)
    {
    }

// ----------------------------------------------------------------------------------------

    linker::
    linker (
        connection& a,
        connection& b
    ) :
        running(false),
        running_signaler(running_mutex),
        A(0),
        B(0),
        service_connection_running_signaler(service_connection_running_mutex)
    {
        link(a,b);
    }

// ----------------------------------------------------------------------------------------

    linker::
    ~linker (
    )
    {
        clear();
    }

// ----------------------------------------------------------------------------------------

    void linker::
    clear (
    )
    {

        // shutdown the connections
        cons_mutex.lock();
        if (A != 0 )
        {
            A->shutdown();
            A = 0;
        }
        if (B != 0)
        {
            B->shutdown();
            B = 0;
        }
        cons_mutex.unlock();

        // wait for the other threads to signal that they have ended
        running_mutex.lock();
        while (running == true)
        {
            running_signaler.wait();
        }
        running_mutex.unlock();

    }

// ----------------------------------------------------------------------------------------

    bool linker::
    is_running (
    ) const
    {
        running_mutex.lock();
        bool temp = running;
        running_mutex.unlock();
        return temp;
    }

// ----------------------------------------------------------------------------------------

    void linker::
    link (
        connection& a,
        connection& b
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(
            this->is_running() == false ,
            "\tvoid linker::link"
            << "\n\tis_running() == " << this->is_running()
            << "\n\tthis: " << this
            );

        running_mutex.lock();
        running = true;
        running_mutex.unlock();

        cons_mutex.lock();
        A = &a;
        B = &b;
        cons_mutex.unlock();

        service_connection_running_mutex.lock();
        service_connection_running = true;
        service_connection_running_mutex.unlock();

        service_connection_error_mutex.lock();
        service_connection_error = false;
        service_connection_error_mutex.unlock();

        // if we fail to make the thread
        if (!create_new_thread(service_connection,this))
        {
            a.shutdown();
            b.shutdown();

            service_connection_running_mutex.lock();
            service_connection_running = false;
            service_connection_running_mutex.unlock();

            cons_mutex.lock();
            A = 0;
            B = 0;
            cons_mutex.unlock();

            running_mutex.lock();
            running = false;
            running_mutex.unlock();

            throw dlib::thread_error (
                ECREATE_THREAD,
                "failed to make new thread in linker::link()"
                );
        }

        // forward data from a to b
        char buf[200];
        int status;
        bool error = false; // becomes true if one of the connections returns an error
        while (true)
        {
            status = a.read(buf,sizeof(buf));
            // if there was an error reading from the socket
            if (status == OTHER_ERROR)
            {
                error = true;
                break;
            }
            else if (status == SHUTDOWN)
            {
                b.shutdown();
            }

            if (status <= 0)
            {
                // if a has closed normally
                if (status == 0)
                    b.shutdown_outgoing();
                break;
            }

            status = b.write(buf,status);
            // if there was an error writing to the socket then break
            if (status == OTHER_ERROR)
            {
                error = true;
                break;
            }

            if (status <= 0)
                break;
        }

        // if there was an error then shutdown both connections
        if (error)
        {
            a.shutdown();
            b.shutdown();
        }

        // wait for the other thread to end
        service_connection_running_mutex.lock();
        while(service_connection_running)
        {
            service_connection_running_signaler.wait();
        }
        service_connection_running_mutex.unlock();

        // make sure connections are shutdown
        a.shutdown();
        b.shutdown();

        // both threads have ended so the connections are no longer needed
        cons_mutex.lock();
        A = 0;
        B = 0;
        cons_mutex.unlock();

        // if service_connection terminated due to an error then set error to true
        service_connection_error_mutex.lock();
        if (service_connection_error)
            error = true;
        service_connection_error_mutex.unlock();

        // if we are ending because of an error
        if (error)
        {

            // signal that the link() function is ending
            running_mutex.lock();
            running = false;
            running_signaler.broadcast();
            running_mutex.unlock();

            // throw the exception for this error
            throw dlib::socket_error (
                ECONNECTION,
                "a connection returned an error in linker::link()"
                );

        }

        // signal that the link() function is ending
        running_mutex.lock();
        running = false;
        running_signaler.broadcast();
        running_mutex.unlock();
    }

// ----------------------------------------------------------------------------------------

    void linker::
    service_connection (
        void* param
    )
    {
        linker& p = *static_cast<linker*>(param);

        p.cons_mutex.lock();
        // if the connections are gone for whatever reason then return
        if (p.A == 0 || p.B == 0)
        {
            // signal that this function is ending
            p.service_connection_running_mutex.lock();
            p.service_connection_running = false;
            p.service_connection_running_signaler.broadcast();
            p.service_connection_running_mutex.unlock();
            return;
        }
        connection& a = *p.A;
        connection& b = *p.B;
        p.cons_mutex.unlock();

        // forward data from b to a
        char buf[200];
        int status;
        bool error = false;
        while (true)
        {
            status = b.read(buf,sizeof(buf));
            // if there was an error reading from the socket
            if (status == OTHER_ERROR)
            {
                error = true;
                break;
            }
            else if (status == SHUTDOWN)
            {
                a.shutdown();
            }

            if (status <= 0)
            {
                // if b has closed normally
                if (status == 0)
                    a.shutdown_outgoing();
                break;
            }

            status = a.write(buf,status);
            // if there was an error writing to the socket then break
            if (status == OTHER_ERROR)
            {
                error = true;
                break;
            }

            if (status <= 0)
                break;
        }

        // if there was an error then shutdown both connections
        if (error)
        {
            a.shutdown();
            b.shutdown();
        }

        // if there was an error then signal that
        if (error)
        {
            p.service_connection_error_mutex.lock();
            p.service_connection_error = true;
            p.service_connection_error_mutex.unlock();
        }

        // signal that this function is ending
        p.service_connection_running_mutex.lock();
        p.service_connection_running = false;
        p.service_connection_running_signaler.broadcast();
        p.service_connection_running_mutex.unlock();

    }

// ----------------------------------------------------------------------------------------

}
#endif // DLIB_LINKER_KERNEL_1_CPp_


dlib C++ Library - linker_kernel_1.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_LINKER_KERNEl_1_
#define DLIB_LINKER_KERNEl_1_

#include "linker_kernel_abstract.h"
#include "../threads.h"
#include "../sockets.h"
#include "../algs.h"

namespace dlib
{

    class linker
    {

        /*!
            INITIAL VALUE
                running             == false
                A                   == 0
                B                   == 0
                running_mutex       == a mutex
                running_signaler    == a signaler associated with running_mutex
                cons_mutex          == a mutex
                service_connection_running          == false
                service_connection_running_mutex    == a mutex
                service_connection_running_signaler == a signaler associated with
                                                       service_connection_running_mutex

                service_connection_error        == false
                service_connection_error_mutex  == a mutex

            CONVENTION
                running             == is_running()
                running_mutex       == a mutex for running
                running_signaler    == a signaler for signaling when
                                       running becomes false and is associated with
                                       running_mutex
                cons_mutex          == a mutex for A and B

                service_connection_running          == true when service_connection() is
                                                       running or is about to run else
                                                       false
                service_connection_running_mutex    == a mutex for service_connection_running
                service_connection_running_signaler == a signaler associated with
                                                       service_connection_running_mutex

                if (running) then
                    A               == address of a from link()
                    B               == address of b from link()
                else
                    A               == 0
                    B               == 0

                service_connection_error        == service_connection uses this bool
                                                   to indicate if it terminated due to
                                                   an error or not
                service_connection_error_mutex  == a mutex for service_connection_error

        !*/

        public:

            // These two typedefs are here for backwards compatibility with previous
            // versions of dlib.
            typedef linker kernel_1a;
            typedef linker kernel_1a_c;

            linker(
            );

            linker (
                connection& a,
                connection& b
            );

            virtual ~linker(
            );

            void clear(
            );

            bool is_running(
            ) const;

            void link (
                connection& a,
                connection& b
            );

        private:

            static void service_connection (
                void* param
            );
            /*!
                requires
                    param == pointer to a linker object
                ensures
                    waits for data from b and forwards it to a and
                    if (b closes normally or is shutdown()) service_connection ends and
                    if (b closes normally) then a.shutdown_outgoing() is called and
                    if (a or b returns an error) then a and b are shutdown()
            !*/

            // data members
            bool running;
            mutex running_mutex;
            signaler running_signaler;
            connection* A;
            connection* B;
            mutex cons_mutex;

            bool service_connection_running;
            mutex service_connection_running_mutex;
            signaler service_connection_running_signaler;

            bool service_connection_error;
            mutex service_connection_error_mutex;

            // restricted functions
            linker(linker&);        // copy constructor
            linker& operator=(linker&);    // assignment operator
    };

}

#ifdef NO_MAKEFILE
#include "linker_kernel_1.cpp"
#endif

#endif // DLIB_LINKER_KERNEl_1_


dlib C++ Library - extra_logger_headers.cpp

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_EXTRA_LOGGER_HEADERs_CPP_
#define DLIB_EXTRA_LOGGER_HEADERs_CPP_

#include "extra_logger_headers.h"
#include <ctime>
#include <cstring>

// ----------------------------------------------------------------------------------------

namespace dlib
{

    void print_datetime_logger_header (
        std::ostream& out,
        const std::string& logger_name,
        const log_level& l,
        const uint64 thread_id
    )
    {
        using namespace std;
        char* buf;

        time_t t = time(0);
        buf = ctime(&t);
        // remove the trailing '\n'
        size_t size = strlen(buf);
        buf[size-1] = '\0';

        out << l.name << " (" << buf << ") [" << thread_id << "] " << logger_name << ": ";
    }

}

// ----------------------------------------------------------------------------------------

#endif // DLIB_EXTRA_LOGGER_HEADERs_CPP_


dlib C++ Library - logger_config_file.cpp

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_LOGGER_CONFIg_FILE_CPP
#define DLIB_LOGGER_CONFIg_FILE_CPP

#include "logger_config_file.h"
#include <string>
#include "../config_reader.h"
#include <fstream>
#include <sstream>
#include "../error.h"
#include "../map.h"
#include "../string.h"

// ----------------------------------------------------------------------------------------

namespace dlib
{

    namespace logger_config_file_helpers
    {

// ----------------------------------------------------------------------------------------

        std::ostream& get_file_stream (
            const std::string& file_name
        )
        {
            using namespace std;
            static dlib::mutex m;
            auto_mutex M(m);
            static dlib::map<string,ostream*>::kernel_1a_c file_map;

            if (file_map.is_in_domain(file_name) == false)
            {
                // We won't ever delete this output stream.  It should be around for the
                // entire life of the program so just let the OS take care of it.
                ostream* fout = new ofstream(file_name.c_str());
                if (!(*fout))
                {
                    delete fout;
                    throw error("logger_config: unable to open output file " + file_name);
                }

                // add this file to our file map
                string temp(file_name);
                file_map.add(temp,fout);
            }

            return *file_map[file_name];
        }

// ----------------------------------------------------------------------------------------

        log_level string_to_log_level (
            const std::string& level
        )
        {
            using namespace std;
            if (level == "LALL" || level == "ALL" || level == "all")
                return LALL;
            else if (level == "LNONE" || level == "NONE" || level == "none")
                return LNONE;
            else if (level == "LTRACE" || level == "TRACE" || level == "trace")
                return LTRACE;
            else if (level == "LDEBUG" || level == "DEBUG" || level == "debug")
                return LDEBUG;
            else if (level == "LINFO" || level == "INFO" || level == "info")
                return LINFO;
            else if (level == "LWARN" || level == "WARN" || level == "warn")
                return LWARN;
            else if (level == "LERROR" || level == "ERROR" || level == "error")
                return LERROR;
            else if (level == "LFATAL" || level == "FATAL" || level == "fatal")
                return LFATAL;
            else
            {
                const int priority = string_cast<int>(level);
                return log_level(priority,"CONFIG_FILE_DEFINED");
            }
        }

// ----------------------------------------------------------------------------------------

        void configure_sub_blocks (
            const config_reader& cr,
            const std::string& name
        )
        {
            using namespace std;

            logger dlog(name.c_str());

            if (cr.is_key_defined("logging_level"))
            {
                dlog.set_level(string_to_log_level(cr["logging_level"]));
            }

            if (cr.is_key_defined("output"))
            {
                string output = cr["output"];
                if (output == "cout")
                    dlog.set_output_stream(cout);
                else if (output == "cerr")
                    dlog.set_output_stream(cerr);
                else if (output == "clog")
                    dlog.set_output_stream(clog);
                else
                {
                    istringstream sin(output);
                    string one, two, three;
                    sin >> one;
                    sin >> two;
                    sin >> three;
                    if (one == "file" && three.size() == 0)
                        dlog.set_output_stream(get_file_stream(two));
                    else
                        throw error("logger_config: invalid argument to output option: " + output);
                }

            } // if (cr.is_key_defined("output"))

            // now configure all the sub-blocks
            std_vector_c<std::string> blocks;
            cr.get_blocks(blocks);
            for (unsigned long i = 0; i < blocks.size(); ++i)
            {
                configure_sub_blocks(cr.block(blocks[i]), name + "." + blocks[i]);
            }

        }

// ----------------------------------------------------------------------------------------

    } // namespace

// ----------------------------------------------------------------------------------------

    void configure_loggers_from_file (
        const std::string& file_name
    )
    {
        std::ifstream fin(file_name.c_str());

        if (!fin)
            throw logger_config_file_error("logger_config: unable to open config file " + file_name);

        config_reader temp(fin);
        configure_loggers_from_file(temp);
    }

// ----------------------------------------------------------------------------------------

    void configure_loggers_from_file (
        const config_reader& main_cr
    )
    {
        using namespace logger_config_file_helpers;
        using namespace std;

        if (main_cr.is_block_defined("logger_config"))
        {
            const config_reader& cr = main_cr.block("logger_config");

            if (cr.is_key_defined("logging_level"))
            {
                set_all_logging_levels(string_to_log_level(cr["logging_level"]));
            }

            if (cr.is_key_defined("output"))
            {
                string output = cr["output"];
                if (output == "cout")
                    set_all_logging_output_streams(cout);
                else if (output == "cerr")
                    set_all_logging_output_streams(cerr);
                else if (output == "clog")
                    set_all_logging_output_streams(clog);
                else
                {
                    istringstream sin(output);
                    string one, two, three;
                    sin >> one;
                    sin >> two;
                    sin >> three;
                    if (one == "file" && three.size() == 0)
                        set_all_logging_output_streams(get_file_stream(two));
                    else
                        throw logger_config_file_error("logger_config: invalid argument to output option: " + output);
                }

            } // if (cr.is_key_defined("output"))

            // now configure all the sub-blocks
            std_vector_c<std::string> blocks;
            cr.get_blocks(blocks);
            for (unsigned long i = 0; i < blocks.size(); ++i)
            {
                configure_sub_blocks(cr.block(blocks[i]), blocks[i]);
            }

        }
    }

// ----------------------------------------------------------------------------------------

}

// ----------------------------------------------------------------------------------------

#endif // DLIB_LOGGER_CONFIg_FILE_CPP


dlib C++ Library - logger_kernel_1.cpp

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_LOGGER_KERNEL_1_CPp_
#define DLIB_LOGGER_KERNEL_1_CPp_

#include "logger_kernel_1.h"
#include <iostream>
#include <sstream>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    void set_all_logging_output_streams (
        std::ostream& out_
    )
    {
        logger::global_data& gd = logger::get_global_data();
        auto_mutex M(gd.m);
        gd.loggers.reset();
        while (gd.loggers.move_next())
        {
            gd.loggers.element()->out.rdbuf(out_.rdbuf());
            gd.loggers.element()->hook.clear();
        }

        gd.set_output_stream("",out_);

        // set the default hook to be an empty member function pointer
        logger::hook_mfp hook;
        gd.set_output_hook("",hook);
    }

    void set_all_logging_levels (
        const log_level& new_level
    )
    {
        logger::global_data& gd = logger::get_global_data();
        auto_mutex M(gd.m);
        gd.loggers.reset();
        while (gd.loggers.move_next())
        {
            gd.loggers.element()->cur_level = new_level;
        }

        gd.set_level("",new_level);
    }

    void set_all_logging_headers (
        const print_header_type& new_header
    )
    {
        logger::global_data& gd = logger::get_global_data();
        auto_mutex M(gd.m);
        gd.loggers.reset();
        while (gd.loggers.move_next())
        {
            gd.loggers.element()->print_header = new_header;
        }

        gd.set_logger_header("",new_header);
    }

// ----------------------------------------------------------------------------------------

    namespace logger_helper_stuff
    {
        class helper
        {
        public:
            helper()
            {
                std::ostringstream sout;
                print_default_logger_header(sout,"some_name",LDEBUG,0);
            }
        };
        // do this to make sure all the static members of print_default_logger_header get
        // initialized when the program turns on.
        static helper a;
        // make a logger to make extra sure the static global_data object gets
        // initialized before any threads start up.  Also do this so that there is always
        // at least one logger so that the global data won't be deleted until the
        // program is terminating.
        static logger log("dlib");
    }

// ----------------------------------------------------------------------------------------

    void print_default_logger_header (
        std::ostream& out,
        const std::string& logger_name,
        const log_level& l,
        const uint64 thread_id
    )
    {
        using namespace std;
        static timestamper ts;
        static const uint64 first_time = ts.get_timestamp();

        const uint64 cur_time = (ts.get_timestamp() - first_time)/1000;
        streamsize old_width = out.width(); out.width(5);
        out << cur_time << " " << l.name;
        out.width(old_width);

        out << " [" << thread_id << "] " << logger_name << ": ";
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                 global_data stuff
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    logger::global_data::
    ~global_data (
    )
    {
        unregister_thread_end_handler(*this,&global_data::thread_end_handler);
    }

// ----------------------------------------------------------------------------------------

    logger::global_data::
    global_data(
    ) :
        next_thread_name(1)
    {
        // make sure the main program thread always has id 0.  Since there is
        // a global logger object declared in this file we should expect that
        // the global_data object will be initialized in the main program thread
        // so if we call get_thread_id() now we should get the main thread id.
        thread_id_type main_id = get_thread_id();
        uint64 id_zero = 0;
        thread_names.add(main_id,id_zero);

        // set up the defaults
        auto_flush_table.val = true;
        streambuf_table.val = std::cout.rdbuf();
        header_table.val = print_default_logger_header;

        // also allocate an initial buffer for hook based logging
        hookbuf.buffer.reserve(1000);
    }

    logger::global_data::level_container::
    level_container (
    ) : val(300,"ERROR") {}

// ----------------------------------------------------------------------------------------

    template <typename T>
    const T& search_tables (
        const T& c,
        const std::string& name
    )
    {
        if (c.table.size() == 0 || name.size() == 0)
            return c;

        const std::string::size_type pos = name.find_first_of(".");
        const std::string first = name.substr(0,pos);
        std::string last;
        if (pos != std::string::npos)
            last = name.substr(pos+1);

        if (c.table.is_in_domain(first))
        {
            return search_tables(*c.table[first], last);
        }
        else
        {
            return c;
        }
    }

// ----------------------------------------------------------------------------------------

    template <typename T, typename U>
    void assign_tables (
        T& c,
        const std::string& name,
        const U& val
    )
    {
        if (name.size() == 0)
        {
            c.val = val;
            c.table.clear();
            return;
        }

        const std::string::size_type pos = name.find_first_of(".");
        std::string first = name.substr(0,pos);
        std::string last;
        if (pos != std::string::npos)
            last = name.substr(pos+1);

        if (c.table.is_in_domain(first))
        {
            assign_tables(*c.table[first], last, val);
        }
        else
        {
            scoped_ptr<T> temp (new T);
            temp->val = c.val;
            assign_tables(*temp, last, val);
            c.table.add(first,temp);
        }
    }

// ----------------------------------------------------------------------------------------

    const log_level logger::global_data::
    level (
        const std::string& name
    ) const
    {
        auto_mutex M(m);
        return search_tables(level_table, name).val;
    }

// ----------------------------------------------------------------------------------------

    void logger::global_data::
    set_level (
        const std::string& name,
        const log_level& new_level
    )
    {
        auto_mutex M(m);
        assign_tables(level_table, name, new_level);
    }

// ----------------------------------------------------------------------------------------

    bool logger::global_data::
    auto_flush (
        const std::string& name
    ) const
    {
        auto_mutex M(m);
        return search_tables(auto_flush_table, name).val;
    }

// ----------------------------------------------------------------------------------------

    void logger::global_data::
    set_auto_flush (
        const std::string& name,
        bool enabled
    )
    {
        auto_mutex M(m);
        assign_tables(auto_flush_table, name, enabled);
    }

// ----------------------------------------------------------------------------------------

    std::streambuf* logger::global_data::
    output_streambuf (
        const std::string& name
    )
    {
        auto_mutex M(m);
        return search_tables(streambuf_table, name).val;
    }

// ----------------------------------------------------------------------------------------

    void logger::global_data::
    set_output_stream (
        const std::string& name,
        std::ostream& out_
    )
    {
        auto_mutex M(m);
        assign_tables( streambuf_table, name, out_.rdbuf());
    }

// ----------------------------------------------------------------------------------------

    void logger::global_data::
    set_output_stream (
        const std::string& name,
        std::streambuf& buf
    )
    {
        auto_mutex M(m);
        assign_tables( streambuf_table, name, &buf);
    }

// ----------------------------------------------------------------------------------------

    logger::hook_mfp logger::global_data::
    output_hook (
        const std::string& name
    )
    {
        auto_mutex M(m);
        return search_tables(hook_table, name).val;
    }

// ----------------------------------------------------------------------------------------

    void logger::global_data::
    set_output_hook (
        const std::string& name,
        const hook_mfp& hook
    )
    {
        auto_mutex M(m);
        assign_tables( hook_table, name, hook);
    }

// ----------------------------------------------------------------------------------------

    print_header_type logger::global_data::
    logger_header (
        const std::string& name
    )
    {
        auto_mutex M(m);
        return search_tables(header_table, name).val;
    }

// ----------------------------------------------------------------------------------------

    void logger::global_data::
    set_logger_header (
        const std::string& name,
        print_header_type ph
    )
    {
        auto_mutex M(m);
        assign_tables(header_table, name, ph);
    }

// ----------------------------------------------------------------------------------------

    logger::global_data& logger::get_global_data()
    {
        // Allocate the global_data on the heap rather than on the stack because
        // we want to guard against the case where this static object would be destroyed
        // during program termination BEFORE all logger objects are destroyed.
        static global_data* gd = new global_data;
        return *gd;
    }

// ----------------------------------------------------------------------------------------

    void logger::global_data::
    thread_end_handler (
    )
    {
        auto_mutex M(m);
        thread_id_type id = get_thread_id();
        thread_id_type junkd;
        uint64 junkr;
        thread_names.remove(id,junkd,junkr);
    }

// ----------------------------------------------------------------------------------------

    uint64 logger::global_data::
    get_thread_name (
    )
    {
        thread_id_type id = get_thread_id();
        uint64 thread_name;
        if (thread_names.is_in_domain(id))
        {
            thread_name = thread_names[id];
        }
        else
        {
            if (is_dlib_thread(id))
                register_thread_end_handler(*this,&global_data::thread_end_handler);
            thread_name = next_thread_name;
            thread_names.add(id,thread_name);
            thread_name = next_thread_name;
            ++next_thread_name;
        }
        return thread_name;
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//               logger_stream stuff
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    void logger::logger_stream::
    print_header_and_stuff (
    )
    {
        if (!been_used)
        {
            log.gd.m.lock();

            // Check if the output hook is setup.  If it isn't then we print the logger
            // header like normal.  Otherwise we need to remember to clear out the output
            // stringstream we always write to.
            if (log.hook.is_set() == false)
            {
                log.logger_header()(log.out,log.name(),l,log.gd.get_thread_name());
            }
            else
            {
                // Make sure the hook buffer doesn't have any old data in it before we start
                // logging a new message into it.
                log.gd.hookbuf.buffer.resize(0);
            }
            been_used = true;
        }
    }

// ----------------------------------------------------------------------------------------

    void logger::logger_stream::
    print_end_of_line (
    )
    {
        auto_unlock M(log.gd.m);

        if (log.hook.is_set() == false)
        {
            if (log.auto_flush_enabled)
                log.out << std::endl;
            else
                log.out << "\n";
        }
        else
        {
            // Make sure the buffer is a proper C-string
            log.gd.hookbuf.buffer.push_back('\0');
            // call the output hook with all the info regarding this log message.
            log.hook(log.name(), l, log.gd.get_thread_name(), &log.gd.hookbuf.buffer[0]);
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//         logger stuff
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    logger::
    logger (
        const std::string& name_
    ) :
        gd(get_global_data()),
        logger_name(name_),
        out(gd.output_streambuf(logger_name)),
        cur_level(gd.level(logger_name))
    {
        DLIB_ASSERT(name_[0] != '\0',
                    "\tlogger::logger()"
                    << "\n\tYou can't make a logger with an empty name"
                    << "\n\tthis: " << this
        );

        auto_mutex M(gd.m);
        logger* temp = this;
        gd.loggers.add(temp);

        // load the appropriate settings
        print_header        = gd.logger_header(logger_name);
        auto_flush_enabled  = gd.auto_flush(logger_name);
        hook                = gd.output_hook(logger_name);
    }

// ----------------------------------------------------------------------------------------

    logger::
    ~logger (
    )
    {
        gd.m.lock();
        gd.loggers.destroy(this);
        // if this was the last logger then delete the global data
        if (gd.loggers.size() == 0)
        {
            gd.m.unlock();
            delete &gd;
        }
        else
        {
            gd.m.unlock();
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_LOGGER_KERNEL_1_CPp_


dlib C++ Library - logger_kernel_1.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_LOGGER_KERNEl_1_
#define DLIB_LOGGER_KERNEl_1_

#include "../threads.h"
#include "../misc_api.h"
#include "../set.h"
#include "logger_kernel_abstract.h"
#include <limits>
#include <cstring>
#include "../algs.h"
#include "../assert.h"
#include "../uintn.h"
#include "../map.h"
#include "../smart_pointers.h"
#include "../member_function_pointer.h"
#include <streambuf>
#include <vector>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class log_level
    {
    public:
        log_level(
            int priority_,
            const char* name_
        ) :
            priority(priority_)
        {
            strncpy(name,name_,19);
            name[19] = '\0';
        }

        bool operator< (const log_level& rhs) const { return priority <  rhs.priority; }
        bool operator<=(const log_level& rhs) const { return priority <= rhs.priority; }
        bool operator> (const log_level& rhs) const { return priority >  rhs.priority; }
        bool operator>=(const log_level& rhs) const { return priority >= rhs.priority; }

        int priority;
        char name[20];
    };

    inline std::ostream& operator<< (std::ostream& out, const log_level& item)
    {
        out << item.name;
        return out;
    }

    const log_level LALL  (std::numeric_limits<int>::min(),"ALL");
    const log_level LNONE (std::numeric_limits<int>::max(),"NONE");
    const log_level LTRACE(-100,"TRACE");
    const log_level LDEBUG(0  ,"DEBUG");
    const log_level LINFO (100,"INFO ");
    const log_level LWARN (200,"WARN ");
    const log_level LERROR(300,"ERROR");
    const log_level LFATAL(400,"FATAL");

// ----------------------------------------------------------------------------------------

    void set_all_logging_output_streams (
        std::ostream& out
    );

    void set_all_logging_levels (
        const log_level& new_level
    );

    typedef void (*print_header_type)(
        std::ostream& out,
        const std::string& logger_name,
        const log_level& l,
        const uint64 thread_id
    );

    void set_all_logging_headers (
        const print_header_type& new_header
    );

// ----------------------------------------------------------------------------------------

    void print_default_logger_header (
        std::ostream& out,
        const std::string& logger_name,
        const log_level& l,
        const uint64 thread_id
    );

    template <
        typename T
        >
    void set_all_logging_output_hooks (
        T& object,
        void (T::*hook_)(const std::string& logger_name,
                         const log_level& l,
                         const uint64 thread_id,
                         const char* message_to_log)
    );

    template <
        typename T
        >
    void set_all_logging_output_hooks (
        T& object
    )
    {
        set_all_logging_output_hooks(object, &T::log);
    }

// ----------------------------------------------------------------------------------------

    class logger
    {
        /*!
            INITIAL VALUE
                - print_header == print_default_logger_header
                - out.rdbuf() == std::cout.rdbuf()
                - cur_level == LERROR
                - auto_flush_enabled == true
                - hook.is_set() == false

            CONVENTION
                - print_header == logger_header()
                - if (hook.is_set() == false) then
                    - out.rdbuf() == output_streambuf()
                - else
                    - out.rdbuf() == &gd.hookbuf
                    - output_streambuf() == 0

                - cur_level == level()
                - logger_name == name()
                - auto_flush_enabled == auto_flush()

                - logger::gd::loggers == a set containing all currently existing loggers.
                - logger::gd::m == the mutex used to lock everything in the logger
                - logger::gd::thread_names == a map of thread ids to thread names.
                - logger::gd::next_thread_name == the next thread name that will be given out
                  to a thread when we find that it isn't already in thread_names.
        !*/

    // ------------------------------------------------------------------------------------
    // ------------------------------------------------------------------------------------

        class logger_stream
        {
            /*!
                INITIAL VALUE
                    - been_used == false

                CONVENTION
                    - enabled == is_enabled()
                    - if (been_used) then
                        - logger::gd::m is locked
                        - someone has used the << operator to write something to the
                          output stream.
            !*/
        public:
            logger_stream (
                const log_level& l_,
                logger& log_
            ) :
                l(l_),
                log(log_),
                been_used(false),
                enabled (l.priority >= log.cur_level.priority)
            {}

            inline ~logger_stream(
            )
            {
                if (!been_used)
                {
                    return;
                }
                else
                {
                    print_end_of_line();
                }
            }

            bool is_enabled (
            ) const { return enabled; }

            template <typename T>
            inline logger_stream& operator << (
                const T& item
            )
            {
                if (!enabled)
                {
                    return *this;
                }
                else
                {
                    print_header_and_stuff();
                    log.out << item;
                    return *this;
                }
            }

        private:

            void print_header_and_stuff (
            );
            /*!
                ensures
                    - if (!been_used) then
                        - prints the logger header
                        - locks log.gd.m
                        - #been_used == true
            !*/

            void print_end_of_line (
            );
            /*!
                ensures
                    - prints a newline to log.out
                    - unlocks log.gd.m
            !*/

            const log_level& l;
            logger& log;
            bool been_used;
            const bool enabled;
        }; // end of class logger_stream

    // ------------------------------------------------------------------------------------
    // ------------------------------------------------------------------------------------

        friend class logger_stream;
    public:

        typedef member_function_pointer<const std::string&, const log_level&,
                                        const uint64, const char*> hook_mfp;

        logger (
            const std::string& name_
        );

        virtual ~logger (
        );

        const std::string& name (
        ) const { return logger_name; }

        logger_stream operator << (
            const log_level& l
        ) const { return logger_stream(l,const_cast<logger&>(*this)); }

        bool is_child_of (
            const logger& log
        ) const
        {
            return (name().find(log.name() + ".") == 0) || (log.name() == name());
        }

        const log_level level (
        ) const
        {
            auto_mutex M(gd.m);
            return log_level(cur_level);
        };

        void set_level (
            const log_level& new_level
        )
        {
            auto_mutex M(gd.m);
            gd.loggers.reset();
            while (gd.loggers.move_next())
            {
                if (gd.loggers.element()->is_child_of(*this))
                    gd.loggers.element()->cur_level = new_level;
            }

            gd.set_level(logger_name, new_level);
        }

        bool auto_flush (
        ) const
        {
            auto_mutex M(gd.m);
            return auto_flush_enabled;
        };

        void set_auto_flush (
            bool enabled
        )
        {
            auto_mutex M(gd.m);
            gd.loggers.reset();
            while (gd.loggers.move_next())
            {
                if (gd.loggers.element()->is_child_of(*this))
                    gd.loggers.element()->auto_flush_enabled = enabled;
            }

            gd.set_auto_flush(logger_name, enabled);
        }

        std::streambuf* output_streambuf (
        )
        {
            auto_mutex M(gd.m);

            // if there is an output hook set then we are supposed to return 0.
            if (hook)
                return 0;
            else
                return out.rdbuf();
        }

        template <
            typename T
            >
        void set_output_hook (
            T& object,
            void (T::*hook_)(const std::string& logger_name,
                            const log_level& l,
                            const uint64 thread_id,
                            const char* message_to_log)
        )
        {
            auto_mutex M(gd.m);
            hook.set(object, hook_);

            gd.loggers.reset();
            while (gd.loggers.move_next())
            {
                if (gd.loggers.element()->is_child_of(*this))
                {
                    gd.loggers.element()->out.rdbuf(&gd.hookbuf);
                    gd.loggers.element()->hook = hook;
                }
            }

            gd.set_output_hook(logger_name, hook);
            gd.set_output_stream(logger_name, gd.hookbuf);
        }

        void set_output_stream (
            std::ostream& out_
        )
        {
            auto_mutex M(gd.m);
            gd.loggers.reset();
            while (gd.loggers.move_next())
            {
                if (gd.loggers.element()->is_child_of(*this))
                {
                    gd.loggers.element()->out.rdbuf(out_.rdbuf());
                    gd.loggers.element()->hook.clear();
                }
            }

            gd.set_output_stream(logger_name, out_);

            hook.clear();
            gd.set_output_hook(logger_name, hook);
        }

        print_header_type logger_header (
        ) const { return print_header; }

        void set_logger_header (
            print_header_type ph
        )
        {
            auto_mutex M(gd.m);
            gd.loggers.reset();
            while (gd.loggers.move_next())
            {
                if (gd.loggers.element()->is_child_of(*this))
                    gd.loggers.element()->print_header = ph;
            }

            gd.set_logger_header(logger_name, ph);
        }

    private:

    // ------------------------------------------------------------------------------------
    // ------------------------------------------------------------------------------------

        struct global_data
        {
            rmutex m;
            set<logger*>::kernel_1b loggers;
            map<thread_id_type,uint64>::kernel_1b thread_names;
            uint64 next_thread_name;

            // Make a very simple streambuf that writes characters into a std::vector<char>.  We can
            // use this as the output target for hooks.  The reason we don't just use a std::ostringstream
            // instead is that this way we can be guaranteed that logging doesn't perform memory allocations.
            // This is because a std::vector never frees memory.  I.e. its capacity() doesn't go down when
            // you resize it back to 0.  It just stays the same.
            class hook_streambuf : public std::streambuf
            {
            public:
                std::vector<char> buffer;
                int_type overflow ( int_type c)
                {
                    if (c != EOF) buffer.push_back(static_cast<char>(c));
                    return c;
                }

                std::streamsize xsputn ( const char* s, std::streamsize num)
                {
                    buffer.insert(buffer.end(), s, s+num);
                    return num;
                }
            };

            hook_streambuf hookbuf;

            global_data (
            );

            ~global_data(
            );

            uint64 get_thread_name (
            );
            /*!
                requires
                    - m is locked
                ensures
                    - returns a unique id for the calling thread.  also makes the number
                      small and nice unlike what you get from get_thread_id()
            !*/

            void thread_end_handler (
            );
            /*!
                ensures
                    - removes the terminated thread from thread_names
            !*/

            struct level_container
            {
                level_container ();

                log_level val;
                map<std::string,scoped_ptr<level_container> >::kernel_1b_c table;
            } level_table;

            const log_level level (
                const std::string& name
            ) const;
            /*!
                ensures
                    - returns the level loggers with the given name are supposed
                      to have
            !*/

            void set_level (
                const std::string& name,
                const log_level& new_level
            );
            /*!
                ensures
                    - for all children C of name:
                        - #level(C) == new_level
                    - if name == "" then
                        - for all loggers L:
                            - #level(L) == new_level
            !*/

            struct auto_flush_container
            {
                bool val;
                map<std::string,scoped_ptr<auto_flush_container> >::kernel_1b_c table;
            } auto_flush_table;

            bool auto_flush (
                const std::string& name
            ) const;
            /*!
                ensures
                    - returns the auto_flush value loggers with the given name are supposed
                      to have
            !*/

            void set_auto_flush (
                const std::string& name,
                bool enabled
            );
            /*!
                ensures
                    - for all children C of name:
                        - #auto_flush_enabled(C) == enabled
                    - if name == "" then
                        - for all loggers L:
                            - #auto_flush_enabled(L) == enabled
            !*/

            struct output_streambuf_container
            {
                std::streambuf* val;
                map<std::string,scoped_ptr<output_streambuf_container> >::kernel_1b_c table;
            } streambuf_table;

            std::streambuf* output_streambuf (
                const std::string& name
            );
            /*!
                ensures
                    - returns the streambuf loggers with the given name are supposed
                      to have
            !*/

            void set_output_stream (
                const std::string& name,
                std::ostream& out_
            );
            /*!
                ensures
                    - for all children C of name:
                        - #output_streambuf(C) == out_.rdbuf()
                    - if name == "" then
                        - for all loggers L:
                            - #output_streambuf(L) == out_.rdbuf()
            !*/

            void set_output_stream (
                const std::string& name,
                std::streambuf& buf
            );
            /*!
                ensures
                    - for all children C of name:
                        - #output_streambuf(C) == &buf
                    - if name == "" then
                        - for all loggers L:
                            - #output_streambuf(L) == &buf
            !*/

            struct output_hook_container
            {
                hook_mfp val;
                map<std::string,scoped_ptr<output_hook_container> >::kernel_1b_c table;
            } hook_table;

            hook_mfp output_hook (
                const std::string& name
            );
            /*!
                ensures
                    - returns the hook loggers with the given name are supposed
                      to have
            !*/

            void set_output_hook (
                const std::string& name,
                const hook_mfp& hook
            );
            /*!
                ensures
                    - for all children C of name:
                        - #output_hook(C) == hook
                    - if name == "" then
                        - for all loggers L:
                            - #output_hook(L) == hook
            !*/

            struct logger_header_container
            {
                print_header_type val;
                map<std::string,scoped_ptr<logger_header_container> >::kernel_1b_c table;
            } header_table;

            print_header_type logger_header (
                const std::string& name
            );
            /*!
                ensures
                    - returns the header function loggers with the given name are supposed
                      to have
            !*/

            void set_logger_header (
                const std::string& name,
                print_header_type ph
            );
            /*!
                ensures
                    - for all children C of name:
                        - #logger_header(C) == ph
                    - if name == "" then
                        - for all loggers L:
                            - #logger_header(L) == ph
            !*/

        }; // end of struct global_data

        static global_data& get_global_data();

    // ------------------------------------------------------------------------------------
    // ------------------------------------------------------------------------------------

        friend void set_all_logging_levels (
            const log_level& new_level
        );

        friend void set_all_logging_headers (
            const print_header_type& new_header
        );

        friend void set_all_logging_output_streams (
            std::ostream& out
        );

        template <
            typename T
            >
        friend void set_all_logging_output_hooks (
            T& object,
            void (T::*hook_)(const std::string& logger_name,
                            const log_level& l,
                            const uint64 thread_id,
                            const char* message_to_log)
        )
        {
            logger::hook_mfp hook;

            // There is a bug in one of the versions (but not all apparently) of
            // Visual studio 2005 that causes it to error out if <T> isn't in the
            // following line of code.  However, there is also a bug in gcc-3.3
            // that causes it to error out if <T> is present.  So this works around
            // this problem.
#if defined(_MSC_VER) && _MSC_VER == 1400
            hook.set<T>(object, hook_);
#else
            hook.set(object, hook_);
#endif

            logger::global_data& gd = logger::get_global_data();
            auto_mutex M(gd.m);
            gd.loggers.reset();
            while (gd.loggers.move_next())
            {
                gd.loggers.element()->out.rdbuf(&gd.hookbuf);
                gd.loggers.element()->hook = hook;
            }

            gd.set_output_stream("",gd.hookbuf);
            gd.set_output_hook("",hook);
        }

    // ------------------------------------------------------------------------------------

        global_data& gd;

        const std::string logger_name;

        print_header_type print_header;
        bool auto_flush_enabled;
        std::ostream out;
        log_level cur_level;

        hook_mfp hook;

        // restricted functions
        logger(const logger&);        // copy constructor
        logger& operator=(const logger&);    // assignment operator

    };

// ----------------------------------------------------------------------------------------

}

#ifdef NO_MAKEFILE
#include "logger_kernel_1.cpp"
#endif

#endif // DLIB_LOGGER_KERNEl_1_


dlib C++ Library - create_random_projection_hash.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_CREATE_RANDOM_PROJECTION_HAsH_Hh_
#define DLIB_CREATE_RANDOM_PROJECTION_HAsH_Hh_

#include "create_random_projection_hash_abstract.h"
#include "projection_hash.h"
#include "../matrix.h"
#include "../rand.h"
#include "../statistics.h"
#include "../svm.h"
#include <vector>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type
        >
    projection_hash create_random_projection_hash (
        const vector_type& v,
        const int bits,
        dlib::rand& rnd
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(0 < bits && bits <= 32 &&
                    v.size() > 1,
            "\t projection_hash create_random_projection_hash()"
            << "\n\t Invalid arguments were given to this function."
            << "\n\t bits: " << bits
            << "\n\t v.size(): " << v.size()
            );

#ifdef ENABLE_ASSERTS
        for (unsigned long i = 0; i < v.size(); ++i)
        {
            DLIB_ASSERT(v[0].size() == v[i].size() && v[i].size() > 0 && is_col_vector(v[i]),
                    "\t projection_hash create_random_projection_hash()"
                   << "\n\t Invalid arguments were given to this function."
                   << "\n\t m(0).size(): " << v[0].size()
                   << "\n\t m("<<i<<").size(): " << v[i].size()
                   << "\n\t is_col_vector(v["<<i<<"]): " << is_col_vector(v[i])
                );
        }
#endif

        running_covariance<matrix<double> > rc;
        for (unsigned long i = 0; i < v.size(); ++i)
            rc.add(matrix_cast<double>(v[i]));

        // compute a whitening matrix
        matrix<double> whiten = trans(chol(pinv(rc.covariance())));

        // hashes
        std::vector<unsigned long> h(v.size(),0);

        std::vector<double> vals(v.size(),0);

        // number of hits for each hash value
        std::vector<unsigned long> counts;

        std::vector<double> temp;

        // build a random projection matrix
        matrix<double> proj(bits, v[0].size());
        for (long r = 0; r < proj.nr(); ++r)
            for (long c = 0; c < proj.nc(); ++c)
                proj(r,c) = rnd.get_random_gaussian();

        // merge whitening matrix with projection matrix
        proj = proj*whiten;

        matrix<double,0,1> offset(bits);

        // figure out what the offset values should be
        for (int itr = 0; itr < offset.size(); ++itr)
        {
            counts.assign(static_cast<unsigned long>(std::pow(2.0,bits)), 0);
            // count the popularity of each hash value
            for (unsigned long i = 0; i < h.size(); ++i)
            {
                h[i] <<= 1;
                counts[h[i]] += 1;
            }

            const unsigned long max_h = index_of_max(mat(counts));

            temp.clear();
            for (unsigned long i = 0; i < v.size(); ++i)
            {
                vals[i] = dot(rowm(proj,itr), matrix_cast<double>(v[i]));
                if (h[i] == max_h)
                    temp.push_back(vals[i]);
            }

            // split down the middle
            std::sort(temp.begin(), temp.end());
            const double split = temp[temp.size()/2];
            offset(itr) = -split;

            for (unsigned long i = 0; i < vals.size(); ++i)
            {
                if (vals[i] - split > 0)
                    h[i] |= 1;
            }
        }

        return projection_hash(proj, offset);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type
        >
    projection_hash create_random_projection_hash (
        const vector_type& v,
        const int bits
    )
    {
        dlib::rand rnd;
        return create_random_projection_hash(v,bits,rnd);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type
        >
    projection_hash create_max_margin_projection_hash (
        const vector_type& v,
        const int bits,
        const double C,
        dlib::rand& rnd
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(0 < bits && bits <= 32 &&
                    v.size() > 1,
            "\t projection_hash create_max_margin_projection_hash()"
            << "\n\t Invalid arguments were given to this function."
            << "\n\t bits: " << bits
            << "\n\t v.size(): " << v.size()
            );

#ifdef ENABLE_ASSERTS
        for (unsigned long i = 0; i < v.size(); ++i)
        {
            DLIB_ASSERT(v[0].size() == v[i].size() && v[i].size() > 0 && is_col_vector(v[i]),
                    "\t projection_hash create_max_margin_projection_hash()"
                   << "\n\t Invalid arguments were given to this function."
                   << "\n\t m(0).size(): " << v[0].size()
                   << "\n\t m("<<i<<").size(): " << v[i].size()
                   << "\n\t is_col_vector(v["<<i<<"]): " << is_col_vector(v[i])
                );
        }
#endif

        running_covariance<matrix<double> > rc;
        for (unsigned long i = 0; i < v.size(); ++i)
            rc.add(matrix_cast<double>(v[i]));

        // compute a whitening matrix
        matrix<double> whiten = trans(chol(pinv(rc.covariance())));
        const matrix<double,0,1> meanval = whiten*rc.mean();

        typedef matrix<double,0,1> sample_type;
        random_subset_selector<sample_type> training_samples;
        random_subset_selector<double> training_labels;
        // We set this up to use enough samples to cover the vector space used by elements
        // of v.
        training_samples.set_max_size(v[0].size()*10);
        training_labels.set_max_size(v[0].size()*10);

        matrix<double> proj(bits, v[0].size());
        matrix<double,0,1> offset(bits);

        // learn the random planes and put them into proj and offset.
        for (int itr = 0; itr < offset.size(); ++itr)
        {
            training_samples.make_empty();
            training_labels.make_empty();
            // pick random training data and give each sample a random label.
            for (unsigned long i = 0; i < v.size(); ++i)
            {
                training_samples.add(whiten*v[i]-meanval);
                if (rnd.get_random_double() > 0.5)
                    training_labels.add(+1);
                else
                    training_labels.add(-1);
            }

            svm_c_linear_dcd_trainer<linear_kernel<sample_type> > trainer;
            trainer.set_c(C);
            decision_function<linear_kernel<sample_type> > df = trainer.train(training_samples, training_labels);
            offset(itr) = -df.b;
            set_rowm(proj,itr) = trans(df.basis_vectors(0));
        }

        return projection_hash(proj*whiten, offset-proj*meanval);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type
        >
    projection_hash create_max_margin_projection_hash (
        const vector_type& v,
        const int bits,
        const double C = 10
    )
    {
        dlib::rand rnd;
        return create_max_margin_projection_hash(v,bits,C,rnd);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_CREATE_RANDOM_PROJECTION_HAsH_Hh_


dlib C++ Library - hashes.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_LSH_HAShES_Hh_
#define DLIB_LSH_HAShES_Hh_

#include "hashes_abstract.h"
#include "../hash.h"
#include "../matrix.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class hash_similar_angles_64
    {
    public:
        hash_similar_angles_64 (
        ) : seed(0) {}

        hash_similar_angles_64 (
            const uint64 seed_
        ) : seed(seed_) {}

        uint64 get_seed (
        ) const { return seed; }

        typedef uint64 result_type;

        template <
            typename sparse_vector_type
            >
        typename disable_if<is_matrix<sparse_vector_type>,uint64>::type operator() (
            const sparse_vector_type& v
        ) const
        {
            typedef typename sparse_vector_type::value_type::second_type scalar_type;

            uint64 temp = 0;
            for (int i = 0; i < 64; ++i)
            {
                // compute the dot product between v and a Gaussian random vector.
                scalar_type val = 0;
                for (typename sparse_vector_type::const_iterator j = v.begin(); j != v.end(); ++j)
                    val += j->second*gaussian_random_hash(j->first, i, seed);

                if (val > 0)
                    temp |= 1;
                temp <<= 1;
            }
            return temp;
        }

        template <typename EXP>
        uint64 operator() (
            const matrix_exp<EXP>& v
        ) const
        {
            typedef typename EXP::type T;
            uint64 temp = 0;
            for (unsigned long i = 0; i < 64; ++i)
            {
                if (dot(matrix_cast<T>(gaussian_randm(v.size(),1,i+seed*64)), v) > 0)
                    temp |= 1;
                temp <<= 1;
            }
            return temp;
        }

        unsigned int distance (
            const result_type& a,
            const result_type& b
        ) const
        {
            return hamming_distance(a,b);
        }

    private:
        const uint64 seed;
    };

// ----------------------------------------------------------------------------------------

    class hash_similar_angles_128
    {
    public:
        hash_similar_angles_128 (
        ) : seed(0),hasher1(0), hasher2(1) {}

        hash_similar_angles_128 (
            const uint64 seed_
        ) : seed(seed_),hasher1(2*seed),hasher2(2*seed+1) {}

        uint64 get_seed (
        ) const { return seed; }

        typedef std::pair<uint64,uint64> result_type;

        template <
            typename vector_type
            >
        result_type operator() (
            const vector_type& v
        ) const
        {
            return std::make_pair(hasher1(v), hasher2(v));
        }

        unsigned int distance (
            const result_type& a,
            const result_type& b
        ) const
        {
            return hamming_distance(a.first,b.first) +
                   hamming_distance(a.second,b.second);
        }

    private:
        const uint64 seed;
        hash_similar_angles_64 hasher1;
        hash_similar_angles_64 hasher2;

    };

// ----------------------------------------------------------------------------------------

    class hash_similar_angles_256
    {
    public:
        hash_similar_angles_256 (
        ) : seed(0), hasher1(0), hasher2(1) {}

        hash_similar_angles_256 (
            const uint64 seed_
        ) : seed(seed_),hasher1(2*seed),hasher2(2*seed+1) {}

        uint64 get_seed (
        ) const { return seed; }

        typedef std::pair<uint64,uint64> hash128_type;
        typedef std::pair<hash128_type,hash128_type> result_type;

        template <
            typename vector_type
            >
        result_type operator() (
            const vector_type& v
        ) const
        {
            return std::make_pair(hasher1(v), hasher2(v));
        }

        unsigned int distance (
            const result_type& a,
            const result_type& b
        ) const
        {
            return hasher1.distance(a.first,b.first) +
                   hasher1.distance(a.second,b.second);
        }

    private:
        const uint64 seed;
        hash_similar_angles_128 hasher1;
        hash_similar_angles_128 hasher2;

    };

// ----------------------------------------------------------------------------------------

    class hash_similar_angles_512
    {
    public:
        hash_similar_angles_512 (
        ) : seed(0), hasher1(0), hasher2(1) {}

        hash_similar_angles_512 (
            const uint64 seed_
        ) : seed(seed_),hasher1(2*seed),hasher2(2*seed+1) {}

        uint64 get_seed (
        ) const { return seed; }

        typedef hash_similar_angles_256::result_type hash256_type;
        typedef std::pair<hash256_type,hash256_type> result_type;

        template <
            typename vector_type
            >
        result_type operator() (
            const vector_type& v
        ) const
        {
            return std::make_pair(hasher1(v), hasher2(v));
        }

        unsigned int distance (
            const result_type& a,
            const result_type& b
        ) const
        {
            return hasher1.distance(a.first,b.first) +
                   hasher1.distance(a.second,b.second);
        }

    private:
        const uint64 seed;
        hash_similar_angles_256 hasher1;
        hash_similar_angles_256 hasher2;
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_LSH_HAShES_Hh_


dlib C++ Library - projection_hash.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_PROJECTION_HASh_Hh_
#define DLIB_PROJECTION_HASh_Hh_

#include "projection_hash_abstract.h"
#include "../matrix.h"
#include "../rand.h"
#include <vector>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class projection_hash
    {
    public:

        projection_hash() {}

        template <typename EXP1, typename EXP2>
        projection_hash(
            const matrix_exp<EXP1>& proj_,
            const matrix_exp<EXP2>& offset_
        ) : proj(proj_), offset(offset_)
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(proj.nr() == offset.nr(),
                "\t projection_hash::projection_hash()"
                << "\n\t Invalid arguments were given to this function."
                << "\n\t proj.nr():   " << proj.nr()
                << "\n\t offset.nr(): " << offset.nr()
                );

        }

        const matrix<double>& get_projection_matrix (
        ) const { return proj; }

        const matrix<double,0,1>& get_offset_matrix (
        ) const { return offset; }

        unsigned long num_hash_bins (
        ) const
        {
            return static_cast<unsigned long>(std::pow(2.0, (double)offset.size()));
        }

        template <typename EXP>
        unsigned long operator() (
            const matrix_exp<EXP>& v
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(is_col_vector(v) &&
                        v.size() == get_projection_matrix().nc() &&
                        v.size() > 0,
                "\t unsigned long projection_hash::operator()(v)"
                << "\n\t Invalid arguments were given to this function."
                << "\n\t is_col_vector(v):             " << is_col_vector(v)
                << "\n\t get_projection_matrix().nc(): " << get_projection_matrix().nc()
                << "\n\t v.size():                     " << v.size()
                );

            return do_hash(proj*matrix_cast<double>(v) + offset);
        }

    private:

        template <typename EXP>
        unsigned long do_hash (
            const matrix_exp<EXP>& v
        ) const
        {
            unsigned long h = 0;
            for (long i = 0; i < v.size(); ++i)
            {
                h <<= 1;
                if (v(i) > 0)
                    h |= 1;
            }
            return h;
        }

        matrix<double> proj;
        matrix<double,0,1> offset;
    };

// ----------------------------------------------------------------------------------------

    inline void serialize (
        const projection_hash& item,
        std::ostream& out
    )
    {
        serialize(item.get_projection_matrix(), out);
        serialize(item.get_offset_matrix(), out);
    }

    inline void deserialize (
        projection_hash& item,
        std::istream& in
    )
    {
        matrix<double> proj;
        matrix<double,0,1> offset;
        deserialize(proj, in);
        deserialize(offset, in);
        item = projection_hash(proj, offset);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_PROJECTION_HASh_Hh_


dlib C++ Library - lz77_buffer_kernel_1.h

// Copyright (C) 2004  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_LZ77_BUFFER_KERNEl_1_
#define DLIB_LZ77_BUFFER_KERNEl_1_

#include "lz77_buffer_kernel_abstract.h"
#include "../algs.h"

namespace dlib
{

    template <
        typename sliding_buffer
        >
    class lz77_buffer_kernel_1
    {
        /*!
            REQUIREMENTS ON sliding_buffer
                sliding_buffer must be an implementation of sliding_buffer/sliding_buffer_kernel_abstract.h

            INITIAL VALUE
                history_limit == defined by constructor arguments
                lookahead_limit == defined by constructor arguments
                history_size == 0
                lookahead_size == 0
                buffer.size() == history_limit + lookahead_limit

            CONVENTION
                history_limit == get_history_buffer_limit()
                lookahead_limit == get_lookahead_buffer_limit()
                history_size == get_history_buffer_size()
                lookahead_limit == get_lookahead_buffer_size()

                buffer.size() == history_limit + lookahead_limit

                lookahead_buffer(i) == buffer[lookahead_limit-1-i]
                history_buffer(i) == buffer[lookahead_limit+i]
        !*/

    public:

        lz77_buffer_kernel_1 (
            unsigned long total_limit_,
            unsigned long lookahead_limit_
        );

        virtual ~lz77_buffer_kernel_1 (
        ) {}

        void clear(
        );

        void add (
            unsigned char symbol
        );

        void find_match (
            unsigned long& index,
            unsigned long& length,
            unsigned long min_match_length
        );

        inline unsigned long get_history_buffer_limit (
        ) const { return history_limit; }

        inline unsigned long get_lookahead_buffer_limit (
        ) const { return lookahead_limit; }

        inline unsigned long get_history_buffer_size (
        ) const { return history_size; }

        inline unsigned long get_lookahead_buffer_size (
        ) const { return lookahead_size; }

        inline unsigned char lookahead_buffer (
            unsigned long index
        ) const { return buffer[lookahead_limit-1-index]; }

        inline unsigned char history_buffer (
            unsigned long index
        ) const { return buffer[lookahead_limit+index]; }

        inline void shift_buffers (
            unsigned long N
        ) { shift_buffer(N); }

    private:

        inline void shift_buffer (
            unsigned long N
        )
        /*!
            requires
                - N <= lookahead_size
            ensuers
                - #lookahead_size == lookahead_size - N
                - if (history_size+N < history_limit) then
                    - #history_size == history_size+N
                - else
                    - #history_size == history_limit
                - for all i where 0 <= i < N:
                  #history_buffer(N-1-i) == lookahead_buffer(i)
                - for all i where 0 <= i < #history_size-N:
                  #history_buffer(N+i) == history_buffer(i)
                - for all i where 0 <= i < #lookahead_size
                  #lookahead_buffer(i) == lookahead_buffer(N+i)
        !*/
        {
            unsigned long temp = history_size+N;
            buffer.rotate_left(N);
            lookahead_size -= N;
            if (temp < history_limit)
                history_size = temp;
            else
                history_size = history_limit;
        }

        // member data
        sliding_buffer buffer;
        unsigned long lookahead_limit;
        unsigned long history_limit;

        unsigned long lookahead_size;
        unsigned long history_size;

        // restricted functions
        lz77_buffer_kernel_1(lz77_buffer_kernel_1<sliding_buffer>&);        // copy constructor
        lz77_buffer_kernel_1<sliding_buffer>& operator=(lz77_buffer_kernel_1<sliding_buffer>&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename sliding_buffer
        >
    lz77_buffer_kernel_1<sliding_buffer>::
    lz77_buffer_kernel_1 (
        unsigned long total_limit_,
        unsigned long lookahead_limit_
    ) :
        lookahead_size(0),
        history_size(0)
    {
        buffer.set_size(total_limit_);
        lookahead_limit = lookahead_limit_;
        history_limit = buffer.size() - lookahead_limit_;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename sliding_buffer
        >
    void lz77_buffer_kernel_1<sliding_buffer>::
    clear(
    )
    {
        lookahead_size = 0;
        history_size = 0;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename sliding_buffer
        >
    void lz77_buffer_kernel_1<sliding_buffer>::
    add (
        unsigned char symbol
    )
    {
        if (lookahead_size == lookahead_limit)
        {
            shift_buffer(1);
        }
        buffer[lookahead_limit-1-lookahead_size] = symbol;
        ++lookahead_size;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename sliding_buffer
        >
    void lz77_buffer_kernel_1<sliding_buffer>::
    find_match (
        unsigned long& index,
        unsigned long& length,
        unsigned long min_match_length
    )
    {
        unsigned long hpos = history_size;  // current position in the history buffer
        unsigned long lpos = 0;             // current position in the lookahead buffer

        unsigned long match_length = 0;   // the length of the longest match we find
        unsigned long match_index = 0;    // the index of the longest match we find

        // try to find a match
        while (hpos != 0)
        {
            --hpos;
            // if we are finding a match
            if (history_buffer(hpos) == lookahead_buffer(lpos))
            {
                ++lpos;
                // if we have found a match that is as long as the lookahead buffer
                // then we are done
                if (lpos == lookahead_size)
                    break;
            }
            // else if we found the end of a match
            else if (lpos > 0)
            {
                // if this match is longer than the last match we saw
                if (lpos > match_length)
                {
                    match_length = lpos;
                    match_index = hpos + lpos;
                }
                lpos = 0;
            }
        } // while (hpos != 0)

        // if we found a match at the end of the loop that is greater than
        // the match in match_index
        if (lpos > match_length)
        {
            match_length = lpos;
            match_index = hpos + lpos - 1;
        }

        // if we found a match that was long enough then report it
        if (match_length >= min_match_length)
        {
            shift_buffer(match_length);
            index = match_index;
            length = match_length;
        }
        else
        {
            length = 0;
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_LZ77_BUFFER_KERNEl_1_


dlib C++ Library - lz77_buffer_kernel_2.h

// Copyright (C) 2004  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_LZ77_BUFFER_KERNEl_2_
#define DLIB_LZ77_BUFFER_KERNEl_2_

#include "lz77_buffer_kernel_abstract.h"
#include "../algs.h"

namespace dlib
{

    template <
        typename sliding_buffer
        >
    class lz77_buffer_kernel_2
    {
        /*!
            REQUIREMENTS ON sliding_buffer
                sliding_buffer must be an implementation of sliding_buffer/sliding_buffer_kernel_abstract.h
                and must be instantiated to contain unsigned char data

            INITIAL VALUE
                history_limit == defined by constructor arguments
                lookahead_limit == defined by constructor arguments
                history_size == 0
                lookahead_size == 0
                buffer.size() == history_limit + lookahead_limit
                buffer[i] == 0 for all valid i

                nodes == an array of history_limit-3 nodes
                id_table == an array of buffer.size() pointers
                hash_table == an array of buffer.size() pointers and all are set to 0
                mask == buffer.size() - 1
                next_free_node == 0

            CONVENTION
                history_limit == get_history_buffer_limit()
                lookahead_limit == get_lookahead_buffer_limit()
                history_size == get_history_buffer_size()
                lookahead_limit == get_lookahead_buffer_size()

                buffer.size() == history_limit + lookahead_limit

                lookahead_buffer(i) == buffer[lookahead_limit-1-i]
                history_buffer(i) == buffer[lookahead_limit+i]

                hash_table[hash(a,b,c,d)] points to the head of a linked list.
                    Each node in this linked list tells the location in the buffer
                    of a string that begins with abcd or a string who's first four
                    letters have the same hash.  The linked list is terminated by a
                    node with a null next pointer.

                hash_table[i] == 0 if there is no linked list for this element of the hash
                    table.

                each node in the hash table is allocated from the array nodes.
                When adding a node to hash_table:
                    if (if all nodes aren't already in the hash_table) then
                    {
                        the next node to use is nodes[next_free_node].
                    }
                    else
                    {
                        recycle nodes from the hash_table itself.  This works because
                        when we add new nodes we also have to remove nodes.
                    }

                if (there is a node defined with an id of i) then
                {
                    if (id_table[i] != 0) then
                        id_table[i]->next->id == i
                    else
                        hash_table[some_hash]->id == i
                }
        !*/

    public:

        lz77_buffer_kernel_2 (
            unsigned long total_limit_,
            unsigned long lookahead_limit_
        );

        virtual ~lz77_buffer_kernel_2 (
        );

        void clear(
        );

        void add (
            unsigned char symbol
        );

        void find_match (
            unsigned long& index,
            unsigned long& length,
            unsigned long min_match_length
        );

        inline unsigned long get_history_buffer_limit (
        ) const { return history_limit; }

        inline unsigned long get_lookahead_buffer_limit (
        ) const { return lookahead_limit; }

        inline unsigned long get_history_buffer_size (
        ) const { return history_size; }

        inline unsigned long get_lookahead_buffer_size (
        ) const { return lookahead_size; }

        inline unsigned char lookahead_buffer (
            unsigned long index
        ) const { return buffer[lookahead_limit-1-index]; }

        inline unsigned char history_buffer (
            unsigned long index
        ) const { return buffer[lookahead_limit+index]; }

        inline void shift_buffers (
            unsigned long N
        ) { shift_buffer(N); }

    private:

        inline unsigned long hash (
            unsigned char a,
            unsigned char b,
            unsigned char c,
            unsigned char d
        ) const
        /*!
            ensures
                - returns a hash of the 4 arguments and the hash is in the range
        !*/
        {
            unsigned long B = b << 3;
            unsigned long C = c << 6;
            unsigned long D = d << 9;

            unsigned long temp = a + B;
            temp += C;
            temp += D;

            return (temp&mask); /**/
        }

        void shift_buffer (
            unsigned long N
        );
        /*!
            requires
                - N <= lookahead_size
            ensuers
                - #lookahead_size == lookahead_size - N
                - if (history_size+N < history_limit) then
                    - #history_size == history_size+N
                - else
                    - #history_size == history_limit
                - for all i where 0 <= i < N:
                  #history_buffer(N-1-i) == lookahead_buffer(i)
                - for all i where 0 <= i < #history_size-N:
                  #history_buffer(N+i) == history_buffer(i)
                - for all i where 0 <= i < #lookahead_size
                  #lookahead_buffer(i) == lookahead_buffer(N+i)
        !*/

        // member data
        sliding_buffer buffer;
        unsigned long lookahead_limit;
        unsigned long history_limit;

        struct node
        {
            unsigned long id;
            node* next;
        };

        node** hash_table;
        node* nodes;
        node** id_table;
        unsigned long next_free_node;
        unsigned long mask;

        unsigned long lookahead_size;
        unsigned long history_size;

        // restricted functions
        lz77_buffer_kernel_2(lz77_buffer_kernel_2<sliding_buffer>&);        // copy constructor
        lz77_buffer_kernel_2<sliding_buffer>& operator=(lz77_buffer_kernel_2<sliding_buffer>&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename sliding_buffer
        >
    lz77_buffer_kernel_2<sliding_buffer>::
    lz77_buffer_kernel_2 (
        unsigned long total_limit_,
        unsigned long lookahead_limit_
    ) :
        lookahead_size(0),
        history_size(0)
    {
        buffer.set_size(total_limit_);
        lookahead_limit = lookahead_limit_;
        history_limit = buffer.size() - lookahead_limit_;

        nodes = new node[history_limit-3];

        try { id_table = new node*[buffer.size()]; }
        catch (...) { delete [] nodes; throw; }

        try { hash_table = new node*[buffer.size()]; }
        catch (...) { delete [] id_table; delete [] nodes; throw; }

        mask = buffer.size()-1;
        next_free_node = 0;

        node** start = hash_table;
        node** end = hash_table + buffer.size();
        while (start != end)
        {
            *start = 0;
            ++start;
        }

        for (unsigned long i = 0; i < buffer.size(); ++i)
            buffer[i] = 0;

    }

// ----------------------------------------------------------------------------------------

    template <
        typename sliding_buffer
        >
    lz77_buffer_kernel_2<sliding_buffer>::
    ~lz77_buffer_kernel_2 (
    )
    {
        delete [] nodes;
        delete [] hash_table;
        delete [] id_table;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename sliding_buffer
        >
    void lz77_buffer_kernel_2<sliding_buffer>::
    clear(
    )
    {
        lookahead_size = 0;
        history_size = 0;
        next_free_node = 0;

        node** start = hash_table;
        node** end = hash_table + buffer.size();
        while (start != end)
        {
            *start = 0;
            ++start;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename sliding_buffer
        >
    void lz77_buffer_kernel_2<sliding_buffer>::
    shift_buffer (
        unsigned long N
    )
    {
        unsigned long old_history_size = history_size;
        unsigned long temp = history_size+N;
        unsigned long new_nodes; // the number of nodes to pull from the nodes array
        unsigned long recycled_nodes; // the number of nodes to pull from hash_table
        lookahead_size -= N;
        if (temp <= history_limit)
        {
            if (history_size <= 3)
            {
                if ((3-history_size) >= N)
                    new_nodes = 0;
                else
                    new_nodes = N - (3-history_size);
            }
            else
            {
                new_nodes = N;
            }

            recycled_nodes = 0;
            history_size = temp;
        }
        else
        {
            if (history_size != history_limit)
            {
                new_nodes = history_limit - history_size;
                recycled_nodes = temp - history_limit;
                history_size = history_limit;
            }
            else
            {
                new_nodes = 0;
                recycled_nodes = N;
            }
        }

        unsigned long i = lookahead_limit + 2;

        // if there are any "new" nodes to add to the hash table
        if (new_nodes != 0)
        {
            unsigned long stop = i - new_nodes;
            for (; i > stop; --i)
            {
                nodes[next_free_node].next = 0;
                nodes[next_free_node].id = buffer.get_element_id(i);
                id_table[nodes[next_free_node].id] = 0;

                unsigned long new_hash = hash(buffer[i],buffer[i-1],buffer[i-2],buffer[i-3]);

                if (hash_table[new_hash] != 0)
                    id_table[hash_table[new_hash]->id] = &nodes[next_free_node];
                nodes[next_free_node].next = hash_table[new_hash];
                hash_table[new_hash] = &nodes[next_free_node];

                ++next_free_node;
            }
        } // if (new_nodes != 0)

        unsigned long stop = i - recycled_nodes;
        unsigned long old = old_history_size-1+lookahead_limit;
        for (; i > stop; --i)
        {
            // find the next node to recycle in hash_table
            node* recycled_node;

            unsigned long old_id = buffer.get_element_id(old);

            // find the node with id old_id
            if (id_table[old_id] == 0)
            {
                unsigned long old_hash = hash(buffer[old],buffer[old-1],buffer[old-2],buffer[old-3]);
                recycled_node = hash_table[old_hash];

                // fill the gap left by removing this node
                hash_table[old_hash] = recycled_node->next;
            }
            else
            {
                recycled_node = id_table[old_id]->next;

                // fill the gap left by removing this node
                id_table[old_id]->next = recycled_node->next;
            }

            --old;

            recycled_node->next = 0;
            recycled_node->id = buffer.get_element_id(i);
            id_table[recycled_node->id] = 0;

            unsigned long new_hash = hash(buffer[i],buffer[i-1],buffer[i-2],buffer[i-3]);

            if (hash_table[new_hash] != 0)
                id_table[hash_table[new_hash]->id] = recycled_node;

            recycled_node->next = hash_table[new_hash];
            hash_table[new_hash] = recycled_node;

        } // for (; i > stop; --i)

        buffer.rotate_left(N);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename sliding_buffer
        >
    void lz77_buffer_kernel_2<sliding_buffer>::
    add (
        unsigned char symbol
    )
    {
        if (lookahead_size == lookahead_limit)
        {
            shift_buffer(1);
        }
        buffer[lookahead_limit-1-lookahead_size] = symbol;
        ++lookahead_size;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename sliding_buffer
        >
    void lz77_buffer_kernel_2<sliding_buffer>::
    find_match (
        unsigned long& index,
        unsigned long& length,
        unsigned long min_match_length
    )
    {
        unsigned long match_length = 0;   // the length of the longest match we find
        unsigned long match_index = 0;    // the index of the longest match we find

        const unsigned long hash_value = hash(lookahead_buffer(0),
                                              lookahead_buffer(1),
                                              lookahead_buffer(2),
                                              lookahead_buffer(3)
                                              );

        node* temp = hash_table[hash_value];
        while (temp != 0)
        {
            // current position in the history buffer
            unsigned long hpos = buffer.get_element_index(temp->id)-lookahead_limit;
            // current position in the lookahead buffer
            unsigned long lpos = 0;

            // find length of this match
            while (history_buffer(hpos) == lookahead_buffer(lpos))
            {
                ++lpos;
                if (hpos == 0)
                    break;
                --hpos;
                if (lpos == lookahead_size)
                    break;
            }

            if (lpos > match_length)
            {
                match_length = lpos;
                match_index = buffer.get_element_index(temp->id)-lookahead_limit;
                // if this is the longest possible match then stop looking
                if (lpos == lookahead_limit)
                    break;
            }

            temp = temp->next;
        } // while (temp != 0)

        // if we found a match that was long enough then report it
        if (match_length >= min_match_length)
        {
            shift_buffer(match_length);
            index = match_index;
            length = match_length;
        }
        else
        {
            length = 0;
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_LZ77_BUFFER_KERNEl_2_


dlib C++ Library - lz77_buffer_kernel_c.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_LZ77_BUFFER_KERNEl_C_
#define DLIB_LZ77_BUFFER_KERNEl_C_

#include "lz77_buffer_kernel_abstract.h"
#include "../algs.h"
#include "../assert.h"
#include <iostream>

namespace dlib
{

    template <
        typename lz77_base
        >
    class lz77_buffer_kernel_c : public lz77_base
    {

        public:
        lz77_buffer_kernel_c (
            unsigned long total_limit,
            unsigned long lookahead_limit
        );

        unsigned char lookahead_buffer (
            unsigned long index
        ) const;

        unsigned char history_buffer (
            unsigned long index
        ) const;

        void shift_buffers (
            unsigned long N
        );

        unsigned long make_safe (
            unsigned long total_limit,
            unsigned long lookahead_limit
        )
        /*!
            ensures
                - if ( 6 < total_limit < 32 &&
                       15 < lookahead_limit <= 2^(total_limit-2)
                       ) then
                    - returns total_limit
                - else
                    - throws due to failed CASSERT
        !*/
        {
            unsigned long exp_size = (total_limit!=0)?total_limit-2:0;
            unsigned long two_pow_total_limit_minus_2 = 1;
            while (exp_size != 0)
            {
                --exp_size;
                two_pow_total_limit_minus_2 <<= 1;
            }

            // make sure requires clause is not broken
            DLIB_CASSERT( 6 < total_limit && total_limit < 32 &&
                    15 < lookahead_limit && lookahead_limit <= two_pow_total_limit_minus_2,
                "\tlz77_buffer::lz77_buffer(unsigned long,unsigned long)"
                << "\n\ttotal_limit must be in the range 7 to 31 and \n\tlookahead_limit in the range 15 to 2^(total_limit-2)"
                << "\n\tthis:            " << this
                << "\n\ttotal_limit:     " << total_limit
                << "\n\tlookahead_limit: " << lookahead_limit
                );

            return total_limit;
        }

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename lz77_base
        >
    void lz77_buffer_kernel_c<lz77_base>::
    shift_buffers (
            unsigned long N
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT( N <= this->get_lookahead_buffer_size(),
            "\tvoid lz77_buffer::shift_buffers(unsigned long)"
            << "\n\tN must be <= the number of chars in the lookahead buffer"
            << "\n\tthis:                        " << this
            << "\n\tget_lookahead_buffer_size(): " << this->get_lookahead_buffer_size()
            << "\n\tN:                           " << N
            );

        // call the real function
        lz77_base::shift_buffers(N);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename lz77_base
        >
    unsigned char lz77_buffer_kernel_c<lz77_base>::
    history_buffer (
            unsigned long index
    ) const
    {
        // make sure requires clause is not broken
        DLIB_CASSERT( index < this->get_history_buffer_size(),
            "\tunsigned char lz77_buffer::history_buffer(unsigned long) const"
            << "\n\tindex must be in the range 0 to get_history_buffer_size()-1"
            << "\n\tthis:                      " << this
            << "\n\tget_history_buffer_size(): " << this->get_history_buffer_size()
            << "\n\tindex:                     " << index
            );

        // call the real function
        return lz77_base::history_buffer(index);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename lz77_base
        >
    unsigned char lz77_buffer_kernel_c<lz77_base>::
    lookahead_buffer (
            unsigned long index
    ) const
    {
        // make sure requires clause is not broken
        DLIB_CASSERT( index < this->get_lookahead_buffer_size(),
            "\tunsigned char lz77_buffer::lookahead_buffer(unsigned long) const"
            << "\n\tindex must be in the range 0 to get_lookahead_buffer_size()-1"
            << "\n\tthis:                        " << this
            << "\n\tget_lookahead_buffer_size(): " << this->get_lookahead_buffer_size()
            << "\n\tindex:                       " << index
            );

        // call the real function
        return lz77_base::lookahead_buffer(index);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename lz77_base
        >
    lz77_buffer_kernel_c<lz77_base>::
    lz77_buffer_kernel_c (
        unsigned long total_limit,
        unsigned long lookahead_limit
    ) :
        lz77_base(make_safe(total_limit,lookahead_limit),lookahead_limit)
    {
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_LZ77_BUFFER_KERNEl_C_


dlib C++ Library - lzp_buffer_kernel_1.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_LZP_BUFFER_KERNEl_1_
#define DLIB_LZP_BUFFER_KERNEl_1_

#include "../algs.h"
#include "lzp_buffer_kernel_abstract.h"

namespace dlib
{

    template <
        typename sbuf
        >
    class lzp_buffer_kernel_1
    {
        /*!
            REQUIREMENTS ON sbuf
                sbuf is an implementation of sliding_buffer/sliding_buffer_kernel_abstract.h
                T == unsigned char

            INITIAL VALUE
                - buffer.size() == the size as defined by the constructor
                - table_size == the number of elements in the table array
                - for all i: buffer[i] == 0
                - for all i: table[i] == buffer.size()

            CONVENTION
                - table_size == the number of elements in the table array
                - size() == buffer.size()
                - operator[](i) == buffer[i]

                - if (table[hash()] != buffer.size()) then
                    - buffer.get_element_index(table[hash()]) == the index we will
                      predict for the current context
                - else
                    - there is no prediction for the current context

                - last_element == buffer.size()-1

                This is LZP with just an order-3 model without context confirmation.

        !*/

    public:

        explicit lzp_buffer_kernel_1 (
            unsigned long buffer_size
        );

        virtual ~lzp_buffer_kernel_1 (
        );

        void clear(
        );

        inline void add (
            unsigned char symbol
        );

        inline unsigned long predict_match (
            unsigned long& index
        );

        inline unsigned long size (
        ) const;

        inline unsigned char operator[] (
            unsigned long index
        ) const;

    private:

        inline unsigned long hash (
        ) const
        /*!
            ensures
                - returns a hash computed from the current context.  This hash
                  is always in the range for table.
        !*/
        {
            unsigned long temp = buffer[0];
            temp <<= 16;
            unsigned long temp2 = buffer[1];
            temp2 <<= 8;
            unsigned long temp3 = buffer[2];
            temp = temp|temp2|temp3;

            temp = ((temp>>11)^temp)&0xFFFF;

            return temp;
        }

        sbuf buffer;
        const unsigned long table_size;
        unsigned long* const table;
        unsigned long last_element;

        // restricted functions
        lzp_buffer_kernel_1(const lzp_buffer_kernel_1<sbuf>&);        // copy constructor
        lzp_buffer_kernel_1<sbuf>& operator=(const lzp_buffer_kernel_1<sbuf>&);    // assignment operator

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename sbuf
        >
    lzp_buffer_kernel_1<sbuf>::
    lzp_buffer_kernel_1 (
        unsigned long buffer_size
    ) :
        table_size(65536),
        table(new unsigned long[table_size])
    {
        buffer.set_size(buffer_size);

        for (unsigned long i = 0; i < buffer.size(); ++i)
            buffer[i] = 0;

        for (unsigned long i = 0; i < table_size; ++i)
            table[i] = buffer.size();

        last_element = buffer.size()-1;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename sbuf
        >
    lzp_buffer_kernel_1<sbuf>::
    ~lzp_buffer_kernel_1 (
    )
    {
        delete [] table;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename sbuf
        >
    void lzp_buffer_kernel_1<sbuf>::
    clear(
    )
    {
        for (unsigned long i = 0; i < buffer.size(); ++i)
            buffer[i] = 0;

        for (unsigned long i = 0; i < table_size; ++i)
            table[i] = buffer.size();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename sbuf
        >
    void lzp_buffer_kernel_1<sbuf>::
    add (
        unsigned char symbol
    )
    {
        buffer.rotate_left(1);
        buffer[0] = symbol;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename sbuf
        >
    unsigned long lzp_buffer_kernel_1<sbuf>::
    predict_match (
        unsigned long& index
    )
    {
        const unsigned long i = hash();

        if (table[i] != buffer.size())
        {
            index = buffer.get_element_index(table[i]);

            if (index > 20)
            {
                // update the prediction for this context
                table[i] = buffer.get_element_id(last_element);
            }
            return 3;
        }
        else
        {
            // update the prediction for this context
            table[i] = buffer.get_element_id(last_element);
            return 0;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename sbuf
        >
    unsigned long lzp_buffer_kernel_1<sbuf>::
    size (
    ) const
    {
        return buffer.size();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename sbuf
        >
    unsigned char lzp_buffer_kernel_1<sbuf>::
    operator[] (
        unsigned long index
    ) const
    {
        return buffer[index];
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_LZP_BUFFER_KERNEl_1_


dlib C++ Library - lzp_buffer_kernel_2.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_LZP_BUFFER_KERNEl_2_
#define DLIB_LZP_BUFFER_KERNEl_2_

#include "../algs.h"
#include "lzp_buffer_kernel_abstract.h"
#include <new>

namespace dlib
{

    template <
        typename sbuf
        >
    class lzp_buffer_kernel_2
    {
        /*!
            REQUIREMENTS ON sbuf
                sbuf is an implementation of sliding_buffer/sliding_buffer_kernel_abstract.h
                T == unsigned char

            INITIAL VALUE
                - buffer.size() == the size as defined by the constructor
                - table_size == the number of elements in the table3 and table4 arrays
                - for all i: buffer[i] == 0
                - for all i: table3[i] == buffer.size()
                - for all i: table4[i] == buffer.size()

            CONVENTION
                - table_size == the number of elements in the table3 and table4 arrays
                - size() == buffer.size()
                - operator[](i) == buffer[i]

                - last_element == buffer.size()-1

                This is LZP with an order-5-4-3 model with context confirmation.
                To save memory the order5 and order3 predictions exist in the same
                table, that is, table3.

        !*/

    public:

        explicit lzp_buffer_kernel_2 (
            unsigned long buffer_size
        );

        virtual ~lzp_buffer_kernel_2 (
        );

        void clear(
        );

        inline void add (
            unsigned char symbol
        );

        inline unsigned long predict_match (
            unsigned long& index
        );

        inline unsigned long size (
        ) const;

        inline unsigned char operator[] (
            unsigned long index
        ) const;

    private:

        inline bool verify (
            unsigned long index
        ) const
        /*!
            ensures
                - returns true if buffer[index]'s context matches the current context
        !*/
        {
            if (index+3 < buffer.size())
            {
                if (buffer[0] != buffer[index+1])
                    return false;
                if (buffer[1] != buffer[index+2])
                    return false;
                if (buffer[2] != buffer[index+3])
                    return false;
                return true;
            }
            else
            {
                // just call this a match
                return true;
            }
        }

        sbuf buffer;
        unsigned long* table3;
        unsigned long* table4;
        unsigned long last_element;
        const unsigned long table_size;

        // restricted functions
        lzp_buffer_kernel_2(const lzp_buffer_kernel_2<sbuf>&);        // copy constructor
        lzp_buffer_kernel_2<sbuf>& operator=(const lzp_buffer_kernel_2<sbuf>&);    // assignment operator

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename sbuf
        >
    lzp_buffer_kernel_2<sbuf>::
    lzp_buffer_kernel_2 (
        unsigned long buffer_size
    ) :
        table3(0),
        table4(0),
        table_size(65536)
    {
        buffer.set_size(buffer_size);

        table3 = new (std::nothrow) unsigned long[table_size];
        table4 = new (std::nothrow) unsigned long[table_size];

        if (!table3 || !table4)
        {
            if (!table3)
                delete [] table3;
            if (!table4)
                delete [] table4;

            throw std::bad_alloc();
        }

        for (unsigned long i = 0; i < buffer.size(); ++i)
            buffer[i] = 0;

        for (unsigned long i = 0; i < table_size; ++i)
        {
            table3[i] = buffer.size();
            table4[i] = buffer.size();
        }

        last_element = buffer.size()-1;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename sbuf
        >
    lzp_buffer_kernel_2<sbuf>::
    ~lzp_buffer_kernel_2 (
    )
    {
        delete [] table3;
        delete [] table4;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename sbuf
        >
    void lzp_buffer_kernel_2<sbuf>::
    clear(
    )
    {
        for (unsigned long i = 0; i < buffer.size(); ++i)
            buffer[i] = 0;

        for (unsigned long i = 0; i < table_size; ++i)
        {
            table3[i] = buffer.size();
            table4[i] = buffer.size();
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename sbuf
        >
    void lzp_buffer_kernel_2<sbuf>::
    add (
        unsigned char symbol
    )
    {
        buffer.rotate_left(1);
        buffer[0] = symbol;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename sbuf
        >
    unsigned long lzp_buffer_kernel_2<sbuf>::
    predict_match (
        unsigned long& index
    )
    {
        unsigned long temp1 = buffer[0];
        unsigned long temp2 = buffer[1];
        temp2 <<= 8;
        unsigned long temp3 = buffer[2];
        temp3 <<= 16;
        unsigned long temp4 = buffer[3];
        temp4 <<= 24;
        unsigned long temp5 = buffer[4];
        temp5 <<= 12;

        unsigned long context1 = temp1|temp2|temp3;
        unsigned long context2 = context1|temp4;

        const unsigned long i5 = ((temp5|(context2>>20))^context2)&0xFFFF;
        const unsigned long i4 = ((context2>>15)^context2)&0xFFFF;
        const unsigned long i3 = ((context1>>11)^context1)&0xFFFF;

        // check the 5-order context's prediction
        if (table3[i5] != buffer.size() &&
            verify(buffer.get_element_index(table3[i5])) )
        {
            index = buffer.get_element_index(table3[i5]);
            if (index > 20)
            {
                // update the prediction for this context
                table3[i3] = buffer.get_element_id(last_element);
                table4[i4] = table3[i3];
                table3[i5] = table3[i3];
            }
            return 5;
        }
        // check the 4-order context's prediction
        else if (table4[i4] != buffer.size() &&
            verify(buffer.get_element_index(table4[i4])) )
        {
            index = buffer.get_element_index(table4[i4]);
            if (index > 20)
            {
                // update the prediction for this context
                table3[i3] = buffer.get_element_id(last_element);
                table4[i4] = table3[i3];
                table3[i5] = table3[i3];
            }
            return 4;
        }
        // check the 3-order context's prediction
        else if (table3[i3] != buffer.size() &&
            verify(buffer.get_element_index(table3[i3])))
        {
            index = buffer.get_element_index(table3[i3]);

            if (index > 20)
            {
                // update the prediction for this context
                table3[i3] = buffer.get_element_id(last_element);
                table4[i4] = table3[i3];
                table3[i5] = table3[i3];
            }
            return 3;
        }
        else
        {
            // update the prediction for this context
            table3[i3] = buffer.get_element_id(last_element);
            table4[i4] = table3[i3];
            table3[i5] = table3[i3];

            return 0;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename sbuf
        >
    unsigned long lzp_buffer_kernel_2<sbuf>::
    size (
    ) const
    {
        return buffer.size();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename sbuf
        >
    unsigned char lzp_buffer_kernel_2<sbuf>::
    operator[] (
        unsigned long index
    ) const
    {
        return buffer[index];
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_LZP_BUFFER_KERNEl_2_


dlib C++ Library - lzp_buffer_kernel_c.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_LZP_BUFFER_KERNEl_C_
#define DLIB_LZP_BUFFER_KERNEl_C_

#include "lzp_buffer_kernel_abstract.h"
#include "../algs.h"
#include "../assert.h"
#include <iostream>

namespace dlib
{

    template <
        typename lzp_base
        >
    class lzp_buffer_kernel_c : public lzp_base
    {

        public:
        lzp_buffer_kernel_c (
            unsigned long buffer_size
        );

        unsigned char operator[] (
            unsigned long index
        ) const;

        unsigned long make_safe (
            unsigned long buffer_size
        )
        /*!
            ensures
                - if ( 10 < buffer_size < 32) then
                    - returns buffer_size
                - else
                    - throws due to failed CASSERT
        !*/
        {

            // make sure requires clause is not broken
            DLIB_CASSERT( 10 < buffer_size && buffer_size < 32,
                "\tlzp_buffer::lzp_buffer(unsigned long)"
                << "\n\tbuffer_size must be in the range 11 to 31."
                << "\n\tthis:         " << this
                << "\n\tbuffer_size:  " << buffer_size
                );

            return buffer_size;
        }

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename lzp_base
        >
    unsigned char lzp_buffer_kernel_c<lzp_base>::
    operator[] (
            unsigned long index
    ) const
    {
        // make sure requires clause is not broken
        DLIB_CASSERT( index < this->size(),
            "\tunsigned char lzp_buffer::operator[](unsigned long) const"
            << "\n\tindex must be in the range 0 to size()()-1"
            << "\n\tthis:    " << this
            << "\n\tsize():  " << this->size()
            << "\n\tindex:   " << index
            );

        // call the real function
        return lzp_base::operator[](index);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename lzp_base
        >
    lzp_buffer_kernel_c<lzp_base>::
    lzp_buffer_kernel_c (
        unsigned long buffer_size
    ) :
        lzp_base(make_safe(buffer_size))
    {
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_LZP_BUFFER_KERNEl_C_


dlib C++ Library - map_kernel_1.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MAP_KERNEl_1_
#define DLIB_MAP_KERNEl_1_

#include "map_kernel_abstract.h"
#include "../algs.h"
#include "../interfaces/enumerable.h"
#include "../interfaces/map_pair.h"
#include "../interfaces/remover.h"
#include "../serialize.h"

namespace dlib
{

    template <
        typename domain,
        typename range,
        typename bst_base,
        typename mem_manager = default_memory_manager
        >
    class map_kernel_1 : public enumerable<map_pair<domain,range> >,
                         public asc_pair_remover<domain,range,typename bst_base::compare_type>
    {

        /*!
            REQUIREMENTS ON BST_BASE
                bst_base is instantiated with domain and range and
                implements binary_search_tree/binary_search_tree_kernel_abstract.h

            INITIAL VALUE
                bst has its initial value

            CONVENTION
                bst.size() == the number of elements in the map and
                the elements in map are stored in bst_base
        !*/

        public:

            typedef domain domain_type;
            typedef range range_type;
            typedef typename bst_base::compare_type compare_type;
            typedef mem_manager mem_manager_type;

            map_kernel_1(
            )
            {}

            virtual ~map_kernel_1(
            )
            {}

            inline void clear(
            );

            inline void add (
                domain& d,
                range& r
            );

            inline bool is_in_domain (
                const domain& d
            ) const;

            inline void remove_any (
                domain& d,
                range& r
            );

            inline void remove (
                const domain& d,
                domain& d_copy,
                range& r
            );

            inline void destroy (
                const domain& d
            );

            inline range& operator[] (
                const domain& d
            );

            inline const range& operator[] (
                const domain& d
            ) const;

            inline void swap (
                map_kernel_1& item
            );

            // functions from the enumerable interface
            inline unsigned long size (
            ) const;

            inline bool at_start (
            ) const;

            inline void reset (
            ) const;

            inline bool current_element_valid (
            ) const;

            inline const map_pair<domain,range>& element (
            ) const;

            inline map_pair<domain,range>& element (
            );

            inline bool move_next (
            ) const;

        private:

            bst_base bst;

            // restricted functions
            map_kernel_1(map_kernel_1&);
            map_kernel_1& operator= ( map_kernel_1&);
    };

    template <
        typename domain,
        typename range,
        typename bst_base,
        typename mem_manager
        >
    inline void swap (
        map_kernel_1<domain,range,bst_base,mem_manager>& a,
        map_kernel_1<domain,range,bst_base,mem_manager>& b
    ) { a.swap(b); }

    template <
        typename domain,
        typename range,
        typename bst_base,
        typename mem_manager
        >
    void deserialize (
        map_kernel_1<domain,range,bst_base,mem_manager>& item,
        std::istream& in
    )
    {
        try
        {
            item.clear();
            unsigned long size;
            deserialize(size,in);
            domain d;
            range r;
            for (unsigned long i = 0; i < size; ++i)
            {
                deserialize(d,in);
                deserialize(r,in);
                item.add(d,r);
            }
        }
        catch (serialization_error e)
        {
            item.clear();
            throw serialization_error(e.info + "\n   while deserializing object of type map_kernel_1");
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename bst_base,
        typename mem_manager
        >
    void map_kernel_1<domain,range,bst_base,mem_manager>::
    clear (
    )
    {
        bst.clear();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename bst_base,
        typename mem_manager
        >
    void map_kernel_1<domain,range,bst_base,mem_manager>::
    add(
        domain& d,
        range& r
    )
    {
        // try to add pair to bst_base
        bst.add(d,r);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename bst_base,
        typename mem_manager
        >
    bool map_kernel_1<domain,range,bst_base,mem_manager>::
    is_in_domain(
        const domain& d
    ) const
    {
        return (bst[d] != 0);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename bst_base,
        typename mem_manager
        >
    void map_kernel_1<domain,range,bst_base,mem_manager>::
    remove_any(
        domain& d,
        range& r
    )
    {
        bst.remove_any(d,r);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename bst_base,
        typename mem_manager
        >
    void map_kernel_1<domain,range,bst_base,mem_manager>::
    remove (
        const domain& d,
        domain& d_copy,
        range& r
    )
    {
        bst.remove(d,d_copy,r);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename bst_base,
        typename mem_manager
        >
    void map_kernel_1<domain,range,bst_base,mem_manager>::
    destroy (
        const domain& d
    )
    {
        bst.destroy(d);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename bst_base,
        typename mem_manager
        >
    range& map_kernel_1<domain,range,bst_base,mem_manager>::
    operator[](
        const domain& d
    )
    {
        return *bst[d];
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename bst_base,
        typename mem_manager
        >
    const range& map_kernel_1<domain,range,bst_base,mem_manager>::
    operator[](
        const domain& d
    ) const
    {
        return *bst[d];
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename bst_base,
        typename mem_manager
        >
    unsigned long map_kernel_1<domain,range,bst_base,mem_manager>::
    size (
    ) const
    {
        return bst.size();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename bst_base,
        typename mem_manager
        >
    void map_kernel_1<domain,range,bst_base,mem_manager>::
    swap (
        map_kernel_1<domain,range,bst_base,mem_manager>& item
    )
    {
        bst.swap(item.bst);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // enumerable function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename bst_base,
        typename mem_manager
        >
    bool map_kernel_1<domain,range,bst_base,mem_manager>::
    at_start (
    ) const
    {
        return bst.at_start();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename bst_base,
        typename mem_manager
        >
    void map_kernel_1<domain,range,bst_base,mem_manager>::
    reset (
    ) const
    {
        bst.reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename bst_base,
        typename mem_manager
        >
    bool map_kernel_1<domain,range,bst_base,mem_manager>::
    current_element_valid (
    ) const
    {
        return bst.current_element_valid();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename bst_base,
        typename mem_manager
        >
    const map_pair<domain,range>& map_kernel_1<domain,range,bst_base,mem_manager>::
    element (
    ) const
    {
        return bst.element();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename bst_base,
        typename mem_manager
        >
    map_pair<domain,range>& map_kernel_1<domain,range,bst_base,mem_manager>::
    element (
    )
    {
        return bst.element();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename bst_base,
        typename mem_manager
        >
    bool map_kernel_1<domain,range,bst_base,mem_manager>::
    move_next (
    ) const
    {
        return bst.move_next();
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MAP_KERNEl_1_


dlib C++ Library - map_kernel_c.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MAP_KERNEl_C_
#define DLIB_MAP_KERNEl_C_

#include "map_kernel_abstract.h"
#include "../algs.h"
#include "../assert.h"
#include "../interfaces/map_pair.h"

namespace dlib
{

    template <
        typename map_base
        >
    class map_kernel_c : public map_base
    {

        typedef typename map_base::domain_type domain;
        typedef typename map_base::range_type range;

        public:
            void add (
                domain& d,
                range& r
            );

            void remove_any (
                domain& d,
                range& r
            );

            void remove (
                const domain& d,
                domain& d_copy,
                range& r
            );

            void destroy (
                const domain& d
            );

            range& operator[] (
                const domain& d
            );

            const range& operator[] (
                const domain& d
            ) const;

            const map_pair<domain,range>& element (
            ) const
            {
                // make sure requires clause is not broken
                DLIB_CASSERT(this->current_element_valid() == true,
                    "\tconst map_pair<domain,range>& map::element"
                    << "\n\tyou can't access the current element if it doesn't exist"
                    << "\n\tthis: " << this
                    );

                // call the real function
                return map_base::element();
            }

            map_pair<domain,range>& element (
            )
            {
                // make sure requires clause is not broken
                DLIB_CASSERT(this->current_element_valid() == true,
                    "\tmap_pair<domain,range>& map::element"
                    << "\n\tyou can't access the current element if it doesn't exist"
                    << "\n\tthis: " << this
                    );

                // call the real function
                return map_base::element();
            }

    };

    template <
        typename map_base
        >
    inline void swap (
        map_kernel_c<map_base>& a,
        map_kernel_c<map_base>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename map_base
        >
    void map_kernel_c<map_base>::
    add (
        domain& d,
        range& r
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT( (!this->is_in_domain(d)) &&
                (static_cast<void*>(&d) != static_cast<void*>(&r)),
            "\tvoid map::add"
            << "\n\tdomain element being added must not already be in the map"
            << "\n\tand d and r must not be the same variable"
            << "\n\tis_in_domain(d): " << (this->is_in_domain(d) ? "true" : "false")
            << "\n\tthis: " << this
            << "\n\t&d:   " << static_cast<void*>(&d)
            << "\n\t&r:   " << static_cast<void*>(&r)
            );

        // call the real function
        map_base::add(d,r);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename map_base
        >
    void map_kernel_c<map_base>::
    remove_any (
        domain& d,
        range& r
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT( (this->size() > 0)  &&
                (static_cast<void*>(&d) != static_cast<void*>(&r)),
            "\tvoid map::remove_any"
            << "\n\tsize() must be greater than zero if something is going to be removed"
            << "\n\tand d and r must not be the same variable."
            << "\n\tsize(): " << this->size()
            << "\n\tthis:   " << this
            << "\n\t&d:     " << static_cast<void*>(&d)
            << "\n\t&r:     " << static_cast<void*>(&r)
            );

        // call the real function
        map_base::remove_any(d,r);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename map_base
        >
    void map_kernel_c<map_base>::
    remove (
        const domain& d,
        domain& d_copy,
        range& r
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT( (this->is_in_domain(d)) &&
                (static_cast<const void*>(&d) != static_cast<void*>(&r)) &&
                (static_cast<void*>(&r) != static_cast<void*>(&d_copy)) &&
                (static_cast<const void*>(&d) != static_cast<void*>(&d_copy)),
            "\tvoid map::remove"
            << "\n\tcan't remove something that isn't in the map or if the paremeters actually"
            << "\n\tare the same variable.  Either way can't remove."
            << "\n\tis_in_domain(d): " << (this->is_in_domain(d) ? "true" : "false")
            << "\n\tthis:      " << this
            << "\n\t&d:        " << static_cast<const void*>(&d)
            << "\n\t&r:        " << static_cast<void*>(&r)
            << "\n\t&d_copy:   " << static_cast<void*>(&d_copy)
            );

        // call the real function
        map_base::remove(d,d_copy,r);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename map_base
        >
    void map_kernel_c<map_base>::
    destroy (
        const domain& d
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(this->is_in_domain(d),
            "\tvoid map::destroy"
            << "\n\tcan't remove something that isn't in the map"
            << "\n\tthis:      " << this
            << "\n\t&d:        " << static_cast<const void*>(&d)
            );

        // call the real function
        map_base::destroy(d);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename map_base
        >
    typename map_base::range_type& map_kernel_c<map_base>::
    operator[] (
        const domain& d
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT( this->is_in_domain(d),
            "\trange& map::operator[]"
            << "\n\td must be in the domain of the map"
            << "\n\tthis: " << this
            );

        // call the real function
        return map_base::operator[](d);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename map_base
        >
    const typename map_base::range_type& map_kernel_c<map_base>::
    operator[] (
        const domain& d
    ) const
    {
        // make sure requires clause is not broken
        DLIB_CASSERT( this->is_in_domain(d),
            "\tconst range& map::operator[]"
            << "\n\td must be in the domain of the map"
            << "\n\tthis: " << this
            );

        // call the real function
        return map_base::operator[](d);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MAP_KERNEl_C_


dlib C++ Library - call_matlab.h

// Copyright (C) 2012 Massachusetts Institute of Technology, Lincoln Laboratory
// License: Boost Software License   See LICENSE.txt for the full license.
// Authors: Davis E. King (davis@dlib.net)
#ifndef MIT_LL_CALL_MATLAB_H__
#define MIT_LL_CALL_MATLAB_H__

#include <string>

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

template <typename T>
struct output_decorator
{
    output_decorator(T& item_):item(item_){}
    T& item;
};

template <typename T>
output_decorator<T> returns(T& item) { return output_decorator<T>(item); }
/*!
    ensures
        - decorates item as an output type.  This stuff is used by the call_matlab()
          functions to tell if an argument is an input to the function or is supposed
          to be bound to one of the return arguments.
!*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

struct function_handle
{
    /*!
        WHAT THIS OBJECT REPRESENTS
            This type is used to represent function handles passed from MATLAB into a
            mex function.  You can call the function referenced by the handle by
            saying:
                call_matlab(my_handle);
    !*/

    // These two lines are just implementation details, ignore them.
    function_handle():h(0){}
    void* const h;
};

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

void call_matlab (
    const std::string& function_name
);
/*!
    ensures
        - Calls MATLAB's function of the given name
!*/

// ----------------------------------------------------------------------------------------

void call_matlab (
    const function_handle& funct
);
/*!
    ensures
        - Calls MATLAB's function represented by the handle funct
!*/

// ----------------------------------------------------------------------------------------

template <
    typename T1
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1
);
/*!
    ensures
        - calls MATLAB's function of the given name.
        - if (A1 is not decorated as an output by returns()) then
            - A1 is passed as an argument into the MATLAB function
        - else
            - A1 is treated as the first return value from the MATLAB function.
!*/

template <
    typename T1
    >
void call_matlab (
    const function_handle& funct,
    const T1& A1
) { call_matlab("feval", funct, A1); }
/*!
    ensures
        - Calls MATLAB's function represented by the handle funct
        - if (A1 is not decorated as an output by returns()) then
            - A1 is passed as an argument into the MATLAB function
        - else
            - A1 is treated as the first return value from the MATLAB function.
!*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
/*
    The rest of this file is just overloads of call_matlab() for up to 10 arguments (or
    just 9 arguments if function_handle is used).  They all do the same thing as the above
    version of call_matlab().  Generally, any argument not decorated by returns() is an
    input to the MATLAB function.  On the other hand, all arguments decorated by returns()
    are treated as outputs.
*/
// ----------------------------------------------------------------------------------------

template <
    typename T1,
    typename T2
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1,
    const T2& A2
);

// ----------------------------------------------------------------------------------------

template <
    typename T1,
    typename T2,
    typename T3
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1,
    const T2& A2,
    const T3& A3
);

// ----------------------------------------------------------------------------------------

template <
    typename T1,
    typename T2,
    typename T3,
    typename T4
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1,
    const T2& A2,
    const T3& A3,
    const T4& A4
);

// ----------------------------------------------------------------------------------------

template <
    typename T1,
    typename T2,
    typename T3,
    typename T4,
    typename T5
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1,
    const T2& A2,
    const T3& A3,
    const T4& A4,
    const T5& A5
);

// ----------------------------------------------------------------------------------------

template <
    typename T1,
    typename T2,
    typename T3,
    typename T4,
    typename T5,
    typename T6
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1,
    const T2& A2,
    const T3& A3,
    const T4& A4,
    const T5& A5,
    const T6& A6
);

// ----------------------------------------------------------------------------------------

template <
    typename T1,
    typename T2,
    typename T3,
    typename T4,
    typename T5,
    typename T6,
    typename T7
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1,
    const T2& A2,
    const T3& A3,
    const T4& A4,
    const T5& A5,
    const T6& A6,
    const T7& A7
);

// ----------------------------------------------------------------------------------------

template <
    typename T1,
    typename T2,
    typename T3,
    typename T4,
    typename T5,
    typename T6,
    typename T7,
    typename T8
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1,
    const T2& A2,
    const T3& A3,
    const T4& A4,
    const T5& A5,
    const T6& A6,
    const T7& A7,
    const T8& A8
);

// ----------------------------------------------------------------------------------------

template <
    typename T1,
    typename T2,
    typename T3,
    typename T4,
    typename T5,
    typename T6,
    typename T7,
    typename T8,
    typename T9
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1,
    const T2& A2,
    const T3& A3,
    const T4& A4,
    const T5& A5,
    const T6& A6,
    const T7& A7,
    const T8& A8,
    const T9& A9
);

// ----------------------------------------------------------------------------------------

template <
    typename T1,
    typename T2,
    typename T3,
    typename T4,
    typename T5,
    typename T6,
    typename T7,
    typename T8,
    typename T9,
    typename T10
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1,
    const T2& A2,
    const T3& A3,
    const T4& A4,
    const T5& A5,
    const T6& A6,
    const T7& A7,
    const T8& A8,
    const T9& A9,
    const T10& A10
);

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

template <
    typename T1,
    typename T2
    >
void call_matlab (
    const function_handle& funct,
    const T1& A1,
    const T2& A2
)
{
    call_matlab("feval", funct, A1, A2);
}

template <
    typename T1,
    typename T2,
    typename T3
    >
void call_matlab (
    const function_handle& funct,
    const T1& A1,
    const T2& A2,
    const T3& A3
)
{
    call_matlab("feval", funct, A1, A2, A3);
}

template <
    typename T1,
    typename T2,
    typename T3,
    typename T4
    >
void call_matlab (
    const function_handle& funct,
    const T1& A1,
    const T2& A2,
    const T3& A3,
    const T4& A4
)
{
    call_matlab("feval", funct, A1, A2, A3, A4);
}

template <
    typename T1,
    typename T2,
    typename T3,
    typename T4,
    typename T5
    >
void call_matlab (
    const function_handle& funct,
    const T1& A1,
    const T2& A2,
    const T3& A3,
    const T4& A4,
    const T5& A5
)
{
    call_matlab("feval", funct, A1, A2, A3, A4, A5);
}

template <
    typename T1,
    typename T2,
    typename T3,
    typename T4,
    typename T5,
    typename T6
    >
void call_matlab (
    const function_handle& funct,
    const T1& A1,
    const T2& A2,
    const T3& A3,
    const T4& A4,
    const T5& A5,
    const T6& A6
)
{
    call_matlab("feval", funct, A1, A2, A3, A4, A5, A6);
}

template <
    typename T1,
    typename T2,
    typename T3,
    typename T4,
    typename T5,
    typename T6,
    typename T7
    >
void call_matlab (
    const function_handle& funct,
    const T1& A1,
    const T2& A2,
    const T3& A3,
    const T4& A4,
    const T5& A5,
    const T6& A6,
    const T7& A7
)
{
    call_matlab("feval", funct, A1, A2, A3, A4, A5, A6, A7);
}

template <
    typename T1,
    typename T2,
    typename T3,
    typename T4,
    typename T5,
    typename T6,
    typename T7,
    typename T8
    >
void call_matlab (
    const function_handle& funct,
    const T1& A1,
    const T2& A2,
    const T3& A3,
    const T4& A4,
    const T5& A5,
    const T6& A6,
    const T7& A7,
    const T8& A8
)
{
    call_matlab("feval", funct, A1, A2, A3, A4, A5, A6, A7, A8);
}

template <
    typename T1,
    typename T2,
    typename T3,
    typename T4,
    typename T5,
    typename T6,
    typename T7,
    typename T8,
    typename T9
    >
void call_matlab (
    const function_handle& funct,
    const T1& A1,
    const T2& A2,
    const T3& A3,
    const T4& A4,
    const T5& A5,
    const T6& A6,
    const T7& A7,
    const T8& A8,
    const T9& A9
)
{
    call_matlab("feval", funct, A1, A2, A3, A4, A5, A6, A7, A8, A9);
}

// ----------------------------------------------------------------------------------------

#endif // MIT_LL_CALL_MATLAB_H__


dlib C++ Library - example_mex_callback.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt

#include "call_matlab.h"
#include "dlib/matrix.h"

using namespace dlib;
using namespace std;

/*
    This mex function takes a MATLAB function handle, calls it, and
    returns the results.

    For example, you can call this function in MATLAB like so:
        A = magic(3)
        y = example_mex_callback(A, @(x)x+x)

    This will result in y containing the value 2*A.
*/

void mex_function (
    const matrix<double>& A,
    const function_handle& f,
    matrix<double>& result
)
{
    // The f argument to this function is a function handle passed from MATLAB.  To
    // call it we use the following syntax:
    call_matlab(f, A, returns(result));
    // This is equivalent to result = f(A). Therefore, the returns(variable) syntax
    // is used to indicate which variables are outputs of the function.

    // Another thing we can do is call MATLAB functions based on their string name
    // rather than a function_handle.  Here is an example of calling eigs().
    matrix<double> m(2,2);
    m = 1,2,
        3,4;
    matrix<double> v,d;

    // This is equivalent to [v,d] = eigs(m);
    call_matlab("eigs", m, returns(v), returns(d));
    cout << "eigenvectors: \n" << v << endl;
    cout << "eigenvalues:  \n" << d << endl;
}

// #including this brings in all the mex boiler plate needed by MATLAB.
#include "mex_wrapper.cpp"


dlib C++ Library - example_mex_function.cpp

// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt

#include "dlib/matrix.h"
using namespace dlib;
using namespace std;

/*!
    This file defines a function callable from MATLAB once you mex it.

    It computes the same thing as the following MATLAB function:

        function [A, B] = example_mex_function(x, y, some_number)
            A = x+y;
            B = sum(sum(x+y));
            disp(['some_number: ' num2str(some_number)])
        end

    VALID INPUT AND OUTPUT ARGUMENTS
        The mex wrapper can handle the following kinds of input and output arguments:
            - Types corresponding to a MATLAB matrix
                - a dlib::matrix containing any kind of scalar value.
                - a dlib::array2d containing any kind of scalar value.
                - a dlib::vector containing any kind of scalar value.
                - a dlib::point

            - RGB color images
                - dlib::array2d<dlib::rgb_pixel> can be used to represent
                  MATLAB uint8 MxNx3 images.

            - Types corresponding to a MATLAB scalar
                - any kind of scalar value, e.g. double, int, etc.

            - Types corresponding to a MATLAB string
                - std::string

            - Types corresponding to a MATLAB cell array
                - a std::vector or dlib::array containing any of the above
                  types of objects or std::vector or dlib::array objects.
!*/

// You can also define default values for your input arguments.  So
// here we say that if the user in MATLAB doesn't provide the "some_number"
// then it will get a value of 3.141.
#define ARG_5_DEFAULT 3.141

// Make a function named mex_function() and put your code inside it.
// Note that the return type should be void.  Use non-const reference
// arguments to return outputs.  Finally, mex_function() must have no
// more than 10 arguments.
void mex_function (
    const matrix<double>& x,
    const matrix<double>& y,
    matrix<double>& out1,
    double& out2,
    double some_number
)
{
    out1 = x + y;
    out2 = sum(x+y);

    // we can also use cout to print things as usual:
    cout << "some_number: "<< some_number << endl;
}

// #including this brings in all the mex boiler plate needed by MATLAB.
#include "mex_wrapper.cpp"


dlib C++ Library - mex_wrapper.cpp

// Copyright (C) 2012 Massachusetts Institute of Technology, Lincoln Laboratory
// License: Boost Software License   See LICENSE.txt for the full license.
// Authors: Davis E. King (davis@dlib.net)
/*
                               READ THIS FIRST
                                   ######
                                   ######
                                   ######
                                   ######
                                   ######
                                   ######
                                   ######
                                   ######
                                   ######
                                   ######
                                   ######
                                   ######
                                   ######
                               \############/
                                \##########/
                                 \########/
                                  \######/
                                   \####/
                                    \##/
                                     \/

    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

    See example_mex_function.cpp for a discussion of how to use the mex wrapper.

    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

                                     /\
                                    /##\
                                   /####\
                                  /######\
                                 /########\
                                /##########\
                               /############\
                                   ######
                                   ######
                                   ######
                                   ######
                                   ######
                                   ######
                                   ######
                                   ######
                                   ######
                                   ######
                                   ######
                                   ######
                                   ######
                               READ THIS FIRST
*/

// Copyright (C) 2012 Massachusetts Institute of Technology, Lincoln Laboratory
// License: Boost Software License   See LICENSE.txt for the full license.
// Authors: Davis E. King (davis@dlib.net)

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                            BEGIN IMPLEMENTATION DETAILS
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

#include "../matrix.h"
#include "../array2d.h"
#include "../array.h"
#include "../image_transforms.h"
#include "../is_kind.h"
#include "../any.h" // for sig_traits

#if defined(_MSC_VER)
#define DLL_EXPORT_SYM __declspec(dllexport)
#endif
#include "mex.h"
#include <sstream>
#include "call_matlab.h"

// ----------------------------------------------------------------------------------------

#ifdef ARG_1_DEFAULT
#define ELSE_ASSIGN_ARG_1 else A1 = ARG_1_DEFAULT;
#else
#define ELSE_ASSIGN_ARG_1
#endif

#ifdef ARG_2_DEFAULT
#define ELSE_ASSIGN_ARG_2 else A2 = ARG_2_DEFAULT;
#else
#define ELSE_ASSIGN_ARG_2
#endif

#ifdef ARG_3_DEFAULT
#define ELSE_ASSIGN_ARG_3 else A3 = ARG_3_DEFAULT;
#else
#define ELSE_ASSIGN_ARG_3
#endif

#ifdef ARG_4_DEFAULT
#define ELSE_ASSIGN_ARG_4 else A4 = ARG_4_DEFAULT;
#else
#define ELSE_ASSIGN_ARG_4
#endif

#ifdef ARG_5_DEFAULT
#define ELSE_ASSIGN_ARG_5 else A5 = ARG_5_DEFAULT;
#else
#define ELSE_ASSIGN_ARG_5
#endif

#ifdef ARG_6_DEFAULT
#define ELSE_ASSIGN_ARG_6 else A6 = ARG_6_DEFAULT;
#else
#define ELSE_ASSIGN_ARG_6
#endif

#ifdef ARG_7_DEFAULT
#define ELSE_ASSIGN_ARG_7 else A7 = ARG_7_DEFAULT;
#else
#define ELSE_ASSIGN_ARG_7
#endif

#ifdef ARG_8_DEFAULT
#define ELSE_ASSIGN_ARG_8 else A8 = ARG_8_DEFAULT;
#else
#define ELSE_ASSIGN_ARG_8
#endif

#ifdef ARG_9_DEFAULT
#define ELSE_ASSIGN_ARG_9 else A9 = ARG_9_DEFAULT;
#else
#define ELSE_ASSIGN_ARG_9
#endif

#ifdef ARG_10_DEFAULT
#define ELSE_ASSIGN_ARG_10 else A10 = ARG_10_DEFAULT;
#else
#define ELSE_ASSIGN_ARG_10
#endif

// ----------------------------------------------------------------------------------------

namespace mex_binding
{
    using namespace dlib;

    template <typename T>
    struct is_input_type
    {
        const static unsigned long value = (!is_same_type<void,T>::value && (!is_reference_type<T>::value || is_const_type<T>::value )) ? 1 : 0;
    };
    template <typename T>
    struct is_output_type
    {
        const static unsigned long value = (!is_same_type<void,T>::value && is_reference_type<T>::value && !is_const_type<T>::value) ? 1 : 0;
    };

    template <typename funct>
    struct funct_traits
    {
        const static unsigned long num_inputs = is_input_type<typename sig_traits<funct>::arg1_type>::value +
            is_input_type<typename sig_traits<funct>::arg2_type>::value +
            is_input_type<typename sig_traits<funct>::arg3_type>::value +
            is_input_type<typename sig_traits<funct>::arg4_type>::value +
            is_input_type<typename sig_traits<funct>::arg5_type>::value +
            is_input_type<typename sig_traits<funct>::arg6_type>::value +
            is_input_type<typename sig_traits<funct>::arg7_type>::value +
            is_input_type<typename sig_traits<funct>::arg8_type>::value +
            is_input_type<typename sig_traits<funct>::arg9_type>::value +
            is_input_type<typename sig_traits<funct>::arg10_type>::value;

        const static unsigned long num_outputs= is_output_type<typename sig_traits<funct>::arg1_type>::value +
            is_output_type<typename sig_traits<funct>::arg2_type>::value +
            is_output_type<typename sig_traits<funct>::arg3_type>::value +
            is_output_type<typename sig_traits<funct>::arg4_type>::value +
            is_output_type<typename sig_traits<funct>::arg5_type>::value +
            is_output_type<typename sig_traits<funct>::arg6_type>::value +
            is_output_type<typename sig_traits<funct>::arg7_type>::value +
            is_output_type<typename sig_traits<funct>::arg8_type>::value +
            is_output_type<typename sig_traits<funct>::arg9_type>::value +
            is_output_type<typename sig_traits<funct>::arg10_type>::value;
    };

// ----------------------------------------------------------------------------------------

    template <typename T>
    struct is_array_type
    {
        // true if T is std::vector or dlib::array
        const static bool value = is_std_vector<T>::value || dlib::is_array<T>::value;

    };

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename enabled = void
        >
    struct inner_type
    {
        typedef T type;
    };

    template < typename T>
    struct inner_type<T, typename dlib::enable_if_c<is_matrix<T>::value || is_array2d<T>::value || dlib::is_array<T>::value >::type>
    {
        typedef typename T::type type;
    };

    template < typename T>
    struct inner_type<T, typename dlib::enable_if<is_std_vector<T> >::type>
    {
        typedef typename T::value_type type;
    };

// -------------------------------------------------------

    struct invalid_args_exception
    {
        invalid_args_exception(const std::string& msg_): msg(msg_) {}
        std::string msg;
    };

// -------------------------------------------------------

    template <
        typename matrix_type,
        typename EXP
        >
    typename dlib::enable_if_c<is_matrix<matrix_type>::value && is_same_type<typename inner_type<matrix_type>::type,typename EXP::type>::value >::type
    assign_mat (
        const long arg_idx,
        matrix_type& m,
        const matrix_exp<EXP>& src
    )
    {
        if (matrix_type::NR != 0 && matrix_type::NR != src.nc())
        {
            std::ostringstream sout;
            sout << "Argument " << arg_idx+1 << " expects a matrix with " << matrix_type::NR << " rows but got one with " << src.nc();
            mexErrMsgIdAndTxt("mex_function:validate_and_populate_arg",
                              sout.str().c_str());
        }
        if (matrix_type::NC != 0 && matrix_type::NC != src.nr())
        {
            std::ostringstream sout;
            sout << "Argument " << arg_idx+1 << " expects a matrix with " << matrix_type::NC << " columns but got one with " << src.nr();
            mexErrMsgIdAndTxt("mex_function:validate_and_populate_arg",
                              sout.str().c_str());
        }

        m = trans(src);
    }

    template <
        typename matrix_type,
        typename EXP
        >
    typename dlib::enable_if_c<is_array2d<matrix_type>::value && is_same_type<typename inner_type<matrix_type>::type,typename EXP::type>::value >::type
    assign_mat (
        const long arg_idx,
        matrix_type& m,
        const matrix_exp<EXP>& src
    )
    {
        assign_image(m , trans(src));
    }

    template <
        typename matrix_type,
        typename EXP
        >
    typename disable_if_c<(is_array2d<matrix_type>::value || is_matrix<matrix_type>::value) &&
    is_same_type<typename inner_type<matrix_type>::type,typename EXP::type>::value >::type
    assign_mat (
        const long arg_idx,
        matrix_type& ,
        const matrix_exp<EXP>&
    )
    {
        std::ostringstream sout;
        sout << "mex_function has some bug in it related to processing input argument " << arg_idx+1;
        mexErrMsgIdAndTxt("mex_function:validate_and_populate_arg",
                          sout.str().c_str());
    }

// -------------------------------------------------------

    template <
        typename T,
        typename U
        >
    typename dlib::enable_if_c<is_built_in_scalar_type<T>::value || is_same_type<T,bool>::value >::type
    assign_scalar (
        const long arg_idx,
        T& dest,
        const U& src
    )
    {
        if (is_signed_type<U>::value && src < 0 && is_unsigned_type<T>::value)
        {
            std::ostringstream sout;
            sout << "Error, input argument " << arg_idx+1 << " must be a non-negative number.";
            mexErrMsgIdAndTxt("mex_function:validate_and_populate_arg",
                              sout.str().c_str());
        }
        else
        {
            dest = src;
        }
    }

    template <
        typename T,
        typename U
        >
    typename dlib::disable_if_c<is_built_in_scalar_type<T>::value || is_same_type<T,bool>::value >::type
    assign_scalar (
        const long arg_idx,
        T& ,
        const U&
    )
    {
        std::ostringstream sout;
        sout << "mex_function has some bug in it related to processing input argument " << arg_idx+1;
        mexErrMsgIdAndTxt("mex_function:validate_and_populate_arg",
                          sout.str().c_str());
    }

// -------------------------------------------------------

    void assign_function_handle (
        const long arg_idx,
        function_handle& dest,
        const mxArray* src
    )
    {
        const_cast<void*&>(dest.h) = (void*)src;
    }

    template <
        typename T
        >
    void assign_function_handle (
        const long arg_idx,
        T& ,
        const mxArray*
    )
    {
        std::ostringstream sout;
        sout << "mex_function has some bug in it related to processing input argument " << arg_idx+1;
        mexErrMsgIdAndTxt("mex_function:validate_and_populate_arg",
                          sout.str().c_str());
    }

// -------------------------------------------------------

    template <
        typename T
        >
    typename dlib::enable_if<is_array_type<T> >::type
    assign_std_vector (
        const long arg_idx,
        T& dest,
        const mxArray* src
    )
    {
        const long nr = mxGetM(src);
        const long nc = mxGetN(src);

        typedef typename inner_type<T>::type type;

        if (!mxIsCell(src))
        {
            std::ostringstream sout;
            sout << " argument " << arg_idx+1 << " must be a cell array";
            throw invalid_args_exception(sout.str());
        }
        if (nr != 1 && nc != 1)
        {
            std::ostringstream sout;
            sout << " argument " << arg_idx+1 << " must be a cell array with exactly 1 row or 1 column (i.e. a row or column vector)";
            throw invalid_args_exception(sout.str());
        }

        const long size = nr*nc;
        dest.resize(size);

        for (unsigned long i = 0; i < dest.size(); ++i)
        {
            try
            {
                validate_and_populate_arg(i, mxGetCell(src, i), dest[i]);
            }
            catch (invalid_args_exception& e)
            {
                std::ostringstream sout;
                sout << "Error in argument " << arg_idx+1 << ": element " << i+1 << " of cell array not the expected type.\n";
                sout << "\t" << e.msg;
                throw invalid_args_exception(sout.str());
            }
        }

    }

    template <
        typename T
        >
    typename disable_if<is_array_type<T> >::type
    assign_std_vector (
        const long arg_idx,
        T& ,
        const mxArray*
    )
    {
        std::ostringstream sout;
        sout << "mex_function has some bug in it related to processing input argument " << arg_idx+1;
        mexErrMsgIdAndTxt("mex_function:validate_and_populate_arg",
                          sout.str().c_str());
    }

// -------------------------------------------------------

    template <typename T>
    void assign_image (
        const long arg_idx,
        T&,
        const dlib::uint8* data,
        long nr,
        long nc
    )
    {
        std::ostringstream sout;
        sout << "mex_function has some bug in it related to processing input argument " << arg_idx+1;
        mexErrMsgIdAndTxt("mex_function:validate_and_populate_arg",
                          sout.str().c_str());
    }

    template <typename MM>
    void assign_image(
        const long ,
        array2d<dlib::rgb_pixel,MM>& img,
        const dlib::uint8* data,
        long nr,
        long nc
    )
    {
        img.set_size(nr, nc);
        for (long c = 0; c < img.nc(); ++c)
            for (long r = 0; r < img.nr(); ++r)
                img[r][c].red = *data++;
        for (long c = 0; c < img.nc(); ++c)
            for (long r = 0; r < img.nr(); ++r)
                img[r][c].green = *data++;
        for (long c = 0; c < img.nc(); ++c)
            for (long r = 0; r < img.nr(); ++r)
                img[r][c].blue = *data++;
    }

// -------------------------------------------------------

    template <typename T>
    void validate_and_populate_arg (
        long arg_idx,
        const mxArray *prhs,
        T& arg
    )
    {
        using namespace mex_binding;
        if (is_built_in_scalar_type<T>::value || is_same_type<T,bool>::value)
        {
            if( !(mxIsDouble(prhs) || mxIsSingle(prhs) || mxIsLogical(prhs) ) ||
                mxIsComplex(prhs) ||
                mxGetNumberOfElements(prhs)!=1 )
            {
                std::ostringstream sout;
                sout << " argument " << arg_idx+1 << " must be a scalar";
                throw invalid_args_exception(sout.str());
            }

            assign_scalar(arg_idx, arg , mxGetScalar(prhs));
        }
        else if (is_matrix<T>::value || is_array2d<T>::value)
        {
            typedef typename inner_type<T>::type type;

            const int num_dims = mxGetNumberOfDimensions(prhs);
            const long nr = mxGetM(prhs);
            const long nc = mxGetN(prhs);

            if (is_same_type<type,dlib::rgb_pixel>::value)
            {
                if (!(num_dims == 3 && mxGetDimensions(prhs)[2] == 3 && mxIsUint8(prhs)))
                {
                    std::ostringstream sout;
                    sout << " argument " << arg_idx+1 << " must be a 3-D NxMx3 image matrix of uint8";
                    throw invalid_args_exception(sout.str());
                }

                const long rows = mxGetDimensions(prhs)[0];
                const long cols = mxGetDimensions(prhs)[1];
                assign_image(arg_idx, arg , (const dlib::uint8*)mxGetData(prhs), rows, cols);
                return;
            }

            if (num_dims != 2)
            {
                std::ostringstream sout;
                sout << " argument " << arg_idx+1 << " must be a 2-D matrix (got a " << num_dims << "-D matrix)";
                throw invalid_args_exception(sout.str());
            }

            if (is_same_type<type,double>::value)
            {
                if (!mxIsDouble(prhs) || mxIsComplex(prhs))
                {
                    std::ostringstream sout;
                    sout << " argument " << arg_idx+1 << " must be a matrix of doubles";
                    throw invalid_args_exception(sout.str());
                }
                assign_mat(arg_idx, arg , pointer_to_matrix(mxGetPr(prhs), nc, nr));
            }
            else if (is_same_type<type, float>::value)
            {
                if (!mxIsSingle(prhs) || mxIsComplex(prhs))
                {
                    std::ostringstream sout;
                    sout << " argument " << arg_idx+1 << " must be a matrix of single/float";
                    throw invalid_args_exception(sout.str());
                }

                assign_mat(arg_idx, arg , pointer_to_matrix((const float*)mxGetData(prhs), nc, nr));
            }
            else if (is_same_type<type, bool>::value)
            {
                if (!mxIsLogical(prhs))
                {
                    std::ostringstream sout;
                    sout << " argument " << arg_idx+1 << " must be a matrix of logical elements.";
                    throw invalid_args_exception(sout.str());
                }

                assign_mat(arg_idx, arg , pointer_to_matrix((const bool*)mxGetData(prhs), nc, nr));
            }
            else if (is_same_type<type, dlib::uint8>::value)
            {
                if (!mxIsUint8(prhs) || mxIsComplex(prhs))
                {
                    std::ostringstream sout;
                    sout << " argument " << arg_idx+1 << " must be a matrix of uint8";
                    throw invalid_args_exception(sout.str());
                }

                assign_mat(arg_idx, arg , pointer_to_matrix((const dlib::uint8*)mxGetData(prhs), nc, nr));
            }
            else if (is_same_type<type, dlib::int8>::value)
            {
                if (!mxIsInt8(prhs) || mxIsComplex(prhs))
                {
                    std::ostringstream sout;
                    sout << " argument " << arg_idx+1 << " must be a matrix of int8";
                    throw invalid_args_exception(sout.str());
                }

                assign_mat(arg_idx, arg , pointer_to_matrix((const dlib::int8*)mxGetData(prhs), nc, nr));
            }
            else if (is_same_type<type, dlib::int16>::value ||
                    (is_same_type<type, short>::value && sizeof(short) == sizeof(dlib::int16)))
            {
                if (!mxIsInt16(prhs) || mxIsComplex(prhs))
                {
                    std::ostringstream sout;
                    sout << " argument " << arg_idx+1 << " must be a matrix of int16";
                    throw invalid_args_exception(sout.str());
                }

                assign_mat(arg_idx, arg , pointer_to_matrix((const type*)mxGetData(prhs), nc, nr));
            }
            else if (is_same_type<type, dlib::uint16>::value ||
                    (is_same_type<type, unsigned short>::value && sizeof(unsigned short) == sizeof(dlib::uint16)))
            {
                if (!mxIsUint16(prhs) || mxIsComplex(prhs))
                {
                    std::ostringstream sout;
                    sout << " argument " << arg_idx+1 << " must be a matrix of uint16";
                    throw invalid_args_exception(sout.str());
                }

                assign_mat(arg_idx, arg , pointer_to_matrix((const type*)mxGetData(prhs), nc, nr));
            }
            else if (is_same_type<type, dlib::int32>::value ||
                    (is_same_type<type, int>::value && sizeof(int) == sizeof(dlib::int32)) ||
                    (is_same_type<type, long>::value && sizeof(long) == sizeof(dlib::int32)))
            {
                if (!mxIsInt32(prhs) || mxIsComplex(prhs))
                {
                    std::ostringstream sout;
                    sout << " argument " << arg_idx+1 << " must be a matrix of int32";
                    throw invalid_args_exception(sout.str());
                }

                assign_mat(arg_idx, arg , pointer_to_matrix((const type*)mxGetData(prhs), nc, nr));
            }
            else if (is_same_type<type, dlib::uint32>::value ||
                    (is_same_type<type, unsigned int>::value && sizeof(unsigned int) == sizeof(dlib::uint32)) ||
                    (is_same_type<type, unsigned long>::value && sizeof(unsigned long) == sizeof(dlib::uint32)))
            {
                if (!mxIsUint32(prhs) || mxIsComplex(prhs))
                {
                    std::ostringstream sout;
                    sout << " argument " << arg_idx+1 << " must be a matrix of uint32";
                    throw invalid_args_exception(sout.str());
                }

                assign_mat(arg_idx, arg , pointer_to_matrix((const type*)mxGetData(prhs), nc, nr));
            }
            else if (is_same_type<type, dlib::uint64>::value ||
                    (is_same_type<type, unsigned int>::value && sizeof(unsigned int) == sizeof(dlib::uint64)) ||
                    (is_same_type<type, unsigned long>::value && sizeof(unsigned long) == sizeof(dlib::uint64)))
            {
                if (!mxIsUint64(prhs) || mxIsComplex(prhs))
                {
                    std::ostringstream sout;
                    sout << " argument " << arg_idx+1 << " must be a matrix of uint64";
                    throw invalid_args_exception(sout.str());
                }

                assign_mat(arg_idx, arg , pointer_to_matrix((const type*)mxGetData(prhs), nc, nr));
            }
            else if (is_same_type<type, dlib::int64>::value ||
                    (is_same_type<type, int>::value && sizeof(int) == sizeof(dlib::int64)) ||
                    (is_same_type<type, long>::value && sizeof(long) == sizeof(dlib::int64)))
            {
                if (!mxIsInt64(prhs) || mxIsComplex(prhs))
                {
                    std::ostringstream sout;
                    sout << " argument " << arg_idx+1 << " must be a matrix of int64";
                    throw invalid_args_exception(sout.str());
                }

                assign_mat(arg_idx, arg , pointer_to_matrix((const type*)mxGetData(prhs), nc, nr));
            }
            else
            {
                mexErrMsgIdAndTxt("mex_function:validate_and_populate_arg",
                                  "mex_function uses unsupported matrix type");
            }
        }
        else if (is_array_type<T>::value)
        {
            assign_std_vector(arg_idx, arg, prhs);

        }
        else if (is_same_type<T,function_handle>::value)
        {
            if (!mxIsClass(prhs, "function_handle"))
            {
                std::ostringstream sout;
                sout << " argument " << arg_idx+1 << " must be a function handle.";
                throw invalid_args_exception(sout.str());
            }
            assign_function_handle(arg_idx, arg, prhs);
        }
        else
        {
            mexErrMsgIdAndTxt("mex_function:validate_and_populate_arg",
                              "mex_function uses unsupported input argument type");
        }
    }

    void validate_and_populate_arg(
        long arg_idx,
        const mxArray *prhs,
        std::string& arg
    )
    {
        if (!mxIsChar(prhs))
        {
            std::ostringstream sout;
            sout << " argument " << arg_idx+1 << " must be a char string";
            throw invalid_args_exception(sout.str());
        }

        const long nr = mxGetM(prhs);
        const long nc = mxGetN(prhs);
        const long size = nr*nc;
        arg.resize(size+1);
        if (mxGetString(prhs, &arg[0], arg.size()))
        {
            std::ostringstream sout;
            sout << " argument " << arg_idx+1 << " encountered an error while calling mxGetString()";
            throw invalid_args_exception(sout.str());
        }
        arg.resize(size);
    }

// ----------------------------------------------------------------------------------------

    template <typename EXP>
    typename dlib::enable_if<is_same_type<dlib::rgb_pixel,typename EXP::type> >::type assign_image_to_matlab (
        dlib::uint8* mat,
        const matrix_exp<EXP>& item
    )
    {
        for (long c = 0; c < item.nc(); ++c)
            for (long r = 0; r < item.nr(); ++r)
                *mat++ = item(r,c).red;
        for (long c = 0; c < item.nc(); ++c)
            for (long r = 0; r < item.nr(); ++r)
                *mat++ = item(r,c).green;
        for (long c = 0; c < item.nc(); ++c)
            for (long r = 0; r < item.nr(); ++r)
                *mat++ = item(r,c).blue;
    }

    template <typename T, typename EXP>
    typename disable_if<is_same_type<dlib::rgb_pixel,typename EXP::type> >::type assign_image_to_matlab (
        T* mat,
        const matrix_exp<EXP>&
    )
    {
        mexErrMsgIdAndTxt("mex_function:validate_and_populate_arg",
                          "mex_function uses unsupported output image argument type");
    }

    template <typename T>
    typename dlib::enable_if<is_matrix<T> >::type assign_to_matlab(
        mxArray*& plhs,
        const T& item
    )
    {
        typedef typename T::type type;

        type* mat = 0;

        if (is_same_type<double, type>::value)
        {
            plhs = mxCreateDoubleMatrix(item.nr(),
                                        item.nc(),
                                        mxREAL);

            mat = (type*)mxGetPr(plhs);
        }
        else if (is_same_type<float, type>::value )
        {
            plhs = mxCreateNumericMatrix(item.nr(),
                                         item.nc(),
                                         mxSINGLE_CLASS,
                                         mxREAL);

            mat = (type*)mxGetData(plhs);
        }
        else if (is_same_type<bool, type>::value )
        {
            plhs = mxCreateLogicalMatrix(item.nr(),
                                         item.nc());

            mat = (type*)mxGetData(plhs);
        }
        else if (is_same_type<dlib::uint8, type>::value )
        {
            plhs = mxCreateNumericMatrix(item.nr(),
                                         item.nc(),
                                         mxUINT8_CLASS,
                                         mxREAL);

            mat = (type*)mxGetData(plhs);
        }
        else if (is_same_type<dlib::int8, type>::value )
        {
            plhs = mxCreateNumericMatrix(item.nr(),
                                         item.nc(),
                                         mxINT8_CLASS,
                                         mxREAL);

            mat = (type*)mxGetData(plhs);
        }
        else if (is_same_type<dlib::int16, type>::value ||
                 (is_same_type<short,type>::value && sizeof(short) == sizeof(dlib::int16)))
        {
            plhs = mxCreateNumericMatrix(item.nr(),
                                         item.nc(),
                                         mxINT16_CLASS,
                                         mxREAL);

            mat = (type*)mxGetData(plhs);
        }
        else if (is_same_type<dlib::uint16, type>::value ||
                 (is_same_type<unsigned short,type>::value && sizeof(unsigned short) == sizeof(dlib::uint16)))
        {
            plhs = mxCreateNumericMatrix(item.nr(),
                                         item.nc(),
                                         mxUINT16_CLASS,
                                         mxREAL);

            mat = (type*)mxGetData(plhs);
        }
        else if (is_same_type<dlib::int32, type>::value ||
                 (is_same_type<long,type>::value && sizeof(long) == sizeof(dlib::int32)))
        {
            plhs = mxCreateNumericMatrix(item.nr(),
                                         item.nc(),
                                         mxINT32_CLASS,
                                         mxREAL);

            mat = (type*)mxGetData(plhs);
        }
        else if (is_same_type<dlib::uint32, type>::value ||
                 (is_same_type<unsigned long,type>::value && sizeof(unsigned long) == sizeof(dlib::uint32)))
        {
            plhs = mxCreateNumericMatrix(item.nr(),
                                         item.nc(),
                                         mxUINT32_CLASS,
                                         mxREAL);

            mat = (type*)mxGetData(plhs);
        }
        else if (is_same_type<dlib::uint64, type>::value ||
                 (is_same_type<unsigned long,type>::value && sizeof(unsigned long) == sizeof(dlib::uint64)))
        {
            plhs = mxCreateNumericMatrix(item.nr(),
                                         item.nc(),
                                         mxUINT64_CLASS,
                                         mxREAL);

            mat = (type*)mxGetData(plhs);
        }
        else if (is_same_type<dlib::int64, type>::value  ||
                 (is_same_type<long,type>::value && sizeof(long) == sizeof(dlib::int64)))
        {
            plhs = mxCreateNumericMatrix(item.nr(),
                                         item.nc(),
                                         mxINT64_CLASS,
                                         mxREAL);

            mat = (type*)mxGetData(plhs);
        }
        else if (is_same_type<dlib::rgb_pixel, type>::value)
        {
            mwSize dims[3] = {item.nr(), item.nc(), 3};
            plhs = mxCreateNumericArray(3, dims, mxUINT8_CLASS, mxREAL);

            assign_image_to_matlab((dlib::uint8*)mxGetData(plhs), item);
            return;
        }
        else
        {
            mexErrMsgIdAndTxt("mex_function:validate_and_populate_arg",
                              "mex_function uses unsupported output argument type");
        }

        for (long c = 0; c < item.nc(); ++c)
        {
            for ( long  r= 0; r < item.nr(); ++r)
            {
                *mat++ = item(r,c);
            }
        }
    }

    void assign_to_matlab(
        mxArray*& plhs,
        const std::string& item
    )
    {
        plhs = mxCreateString(item.c_str());
    }

    template <typename T, typename MM>
    void assign_to_matlab(
        mxArray*& plhs,
        const array2d<T,MM>& item
    )
    {
        assign_to_matlab(plhs,array_to_matrix(item));
    }

    template <typename T>
    typename dlib::enable_if<is_array_type<T> >::type assign_to_matlab(
        mxArray*& plhs,
        const T& item
    )
    {
        mwSize dims[1] = {item.size()};
        plhs = mxCreateCellArray(1,dims);
        for (unsigned long i = 0; i < item.size(); ++i)
        {
            mxArray* next = 0;
            assign_to_matlab(next, item[i]);
            mxSetCell(plhs, i, next);
        }
    }

    template <typename T>
    typename dlib::disable_if_c<is_matrix<T>::value || is_array_type<T>::value ||
                                is_same_type<T,function_handle>::value>::type assign_to_matlab(
        mxArray*& plhs,
        const T& item
    )
    {
        plhs = mxCreateDoubleScalar(item);
    }

    void assign_to_matlab (
        mxArray*& plhs,
        const char* str
    )
    {
        assign_to_matlab(plhs, std::string(str));
    }

    void assign_to_matlab(
        mxArray*& plhs,
        const function_handle& h
    )
    {
    }

// ----------------------------------------------------------------------------------------

    template <
        unsigned long num_args
        >
    struct call_mex_function_helper;

    template <>
    struct call_mex_function_helper<1>
    {
        template <typename funct>
        void callit(
            const funct& ,
            int nlhs, mxArray *plhs[],
            int nrhs, const mxArray *prhs[]
        ) const
        {
            typedef typename sig_traits<funct>::arg1_type arg1_type;

            typename basic_type<arg1_type>::type A1;

            int i = 0;
            if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1;

            mex_function(A1);

            i = 0;
            if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;}
        }
    };

    template <>
    struct call_mex_function_helper<2>
    {
        template <typename funct>
        void callit(
            const funct& ,
            int nlhs, mxArray *plhs[],
            int nrhs, const mxArray *prhs[]
        ) const
        {
            typedef typename sig_traits<funct>::arg1_type arg1_type;
            typedef typename sig_traits<funct>::arg2_type arg2_type;

            typename basic_type<arg1_type>::type A1;
            typename basic_type<arg2_type>::type A2;

            int i = 0;
            if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1;
            if (i < nrhs && is_input_type<arg2_type>::value) {validate_and_populate_arg(i,prhs[i],A2); ++i;} ELSE_ASSIGN_ARG_2;

            mex_function(A1,A2);

            i = 0;
            if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;}
            if (is_output_type<arg2_type>::value) {assign_to_matlab(plhs[i],A2); ++i;}
        }
    };

    template <>
    struct call_mex_function_helper<3>
    {
        template <typename funct>
        void callit(
            const funct& ,
            int nlhs, mxArray *plhs[],
            int nrhs, const mxArray *prhs[]
        ) const
        {
            typedef typename sig_traits<funct>::arg1_type arg1_type;
            typedef typename sig_traits<funct>::arg2_type arg2_type;
            typedef typename sig_traits<funct>::arg3_type arg3_type;

            typename basic_type<arg1_type>::type A1;
            typename basic_type<arg2_type>::type A2;
            typename basic_type<arg3_type>::type A3;

            int i = 0;
            if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1;
            if (i < nrhs && is_input_type<arg2_type>::value) {validate_and_populate_arg(i,prhs[i],A2); ++i;} ELSE_ASSIGN_ARG_2;
            if (i < nrhs && is_input_type<arg3_type>::value) {validate_and_populate_arg(i,prhs[i],A3); ++i;} ELSE_ASSIGN_ARG_3;

            mex_function(A1,A2,A3);

            i = 0;
            if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;}
            if (is_output_type<arg2_type>::value) {assign_to_matlab(plhs[i],A2); ++i;}
            if (is_output_type<arg3_type>::value) {assign_to_matlab(plhs[i],A3); ++i;}
        }
    };

    template <>
    struct call_mex_function_helper<4>
    {
        template <typename funct>
        void callit(
            const funct& ,
            int nlhs, mxArray *plhs[],
            int nrhs, const mxArray *prhs[]
        ) const
        {
            typedef typename sig_traits<funct>::arg1_type arg1_type;
            typedef typename sig_traits<funct>::arg2_type arg2_type;
            typedef typename sig_traits<funct>::arg3_type arg3_type;
            typedef typename sig_traits<funct>::arg4_type arg4_type;

            typename basic_type<arg1_type>::type A1;
            typename basic_type<arg2_type>::type A2;
            typename basic_type<arg3_type>::type A3;
            typename basic_type<arg4_type>::type A4;

            int i = 0;
            if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1;
            if (i < nrhs && is_input_type<arg2_type>::value) {validate_and_populate_arg(i,prhs[i],A2); ++i;} ELSE_ASSIGN_ARG_2;
            if (i < nrhs && is_input_type<arg3_type>::value) {validate_and_populate_arg(i,prhs[i],A3); ++i;} ELSE_ASSIGN_ARG_3;
            if (i < nrhs && is_input_type<arg4_type>::value) {validate_and_populate_arg(i,prhs[i],A4); ++i;} ELSE_ASSIGN_ARG_4;

            mex_function(A1,A2,A3,A4);

            i = 0;
            if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;}
            if (is_output_type<arg2_type>::value) {assign_to_matlab(plhs[i],A2); ++i;}
            if (is_output_type<arg3_type>::value) {assign_to_matlab(plhs[i],A3); ++i;}
            if (is_output_type<arg4_type>::value) {assign_to_matlab(plhs[i],A4); ++i;}
        }
    };

    template <>
    struct call_mex_function_helper<5>
    {
        template <typename funct>
        void callit(
            const funct& ,
            int nlhs, mxArray *plhs[],
            int nrhs, const mxArray *prhs[]
        ) const
        {
            typedef typename sig_traits<funct>::arg1_type arg1_type;
            typedef typename sig_traits<funct>::arg2_type arg2_type;
            typedef typename sig_traits<funct>::arg3_type arg3_type;
            typedef typename sig_traits<funct>::arg4_type arg4_type;
            typedef typename sig_traits<funct>::arg5_type arg5_type;

            typename basic_type<arg1_type>::type A1;
            typename basic_type<arg2_type>::type A2;
            typename basic_type<arg3_type>::type A3;
            typename basic_type<arg4_type>::type A4;
            typename basic_type<arg5_type>::type A5;

            int i = 0;
            if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1;
            if (i < nrhs && is_input_type<arg2_type>::value) {validate_and_populate_arg(i,prhs[i],A2); ++i;} ELSE_ASSIGN_ARG_2;
            if (i < nrhs && is_input_type<arg3_type>::value) {validate_and_populate_arg(i,prhs[i],A3); ++i;} ELSE_ASSIGN_ARG_3;
            if (i < nrhs && is_input_type<arg4_type>::value) {validate_and_populate_arg(i,prhs[i],A4); ++i;} ELSE_ASSIGN_ARG_4;
            if (i < nrhs && is_input_type<arg5_type>::value) {validate_and_populate_arg(i,prhs[i],A5); ++i;} ELSE_ASSIGN_ARG_5;

            mex_function(A1,A2,A3,A4,A5);

            i = 0;
            if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;}
            if (is_output_type<arg2_type>::value) {assign_to_matlab(plhs[i],A2); ++i;}
            if (is_output_type<arg3_type>::value) {assign_to_matlab(plhs[i],A3); ++i;}
            if (is_output_type<arg4_type>::value) {assign_to_matlab(plhs[i],A4); ++i;}
            if (is_output_type<arg5_type>::value) {assign_to_matlab(plhs[i],A5); ++i;}
        }
    };

    template <>
    struct call_mex_function_helper<6>
    {
        template <typename funct>
        void callit(
            const funct& ,
            int nlhs, mxArray *plhs[],
            int nrhs, const mxArray *prhs[]
        ) const
        {
            typedef typename sig_traits<funct>::arg1_type arg1_type;
            typedef typename sig_traits<funct>::arg2_type arg2_type;
            typedef typename sig_traits<funct>::arg3_type arg3_type;
            typedef typename sig_traits<funct>::arg4_type arg4_type;
            typedef typename sig_traits<funct>::arg5_type arg5_type;
            typedef typename sig_traits<funct>::arg6_type arg6_type;

            typename basic_type<arg1_type>::type A1;
            typename basic_type<arg2_type>::type A2;
            typename basic_type<arg3_type>::type A3;
            typename basic_type<arg4_type>::type A4;
            typename basic_type<arg5_type>::type A5;
            typename basic_type<arg6_type>::type A6;

            int i = 0;
            if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1;
            if (i < nrhs && is_input_type<arg2_type>::value) {validate_and_populate_arg(i,prhs[i],A2); ++i;} ELSE_ASSIGN_ARG_2;
            if (i < nrhs && is_input_type<arg3_type>::value) {validate_and_populate_arg(i,prhs[i],A3); ++i;} ELSE_ASSIGN_ARG_3;
            if (i < nrhs && is_input_type<arg4_type>::value) {validate_and_populate_arg(i,prhs[i],A4); ++i;} ELSE_ASSIGN_ARG_4;
            if (i < nrhs && is_input_type<arg5_type>::value) {validate_and_populate_arg(i,prhs[i],A5); ++i;} ELSE_ASSIGN_ARG_5;
            if (i < nrhs && is_input_type<arg6_type>::value) {validate_and_populate_arg(i,prhs[i],A6); ++i;} ELSE_ASSIGN_ARG_6;

            mex_function(A1,A2,A3,A4,A5,A6);

            i = 0;
            if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;}
            if (is_output_type<arg2_type>::value) {assign_to_matlab(plhs[i],A2); ++i;}
            if (is_output_type<arg3_type>::value) {assign_to_matlab(plhs[i],A3); ++i;}
            if (is_output_type<arg4_type>::value) {assign_to_matlab(plhs[i],A4); ++i;}
            if (is_output_type<arg5_type>::value) {assign_to_matlab(plhs[i],A5); ++i;}
            if (is_output_type<arg6_type>::value) {assign_to_matlab(plhs[i],A6); ++i;}
        }
    };

    template <>
    struct call_mex_function_helper<7>
    {
        template <typename funct>
        void callit(
            const funct& ,
            int nlhs, mxArray *plhs[],
            int nrhs, const mxArray *prhs[]
        ) const
        {
            typedef typename sig_traits<funct>::arg1_type arg1_type;
            typedef typename sig_traits<funct>::arg2_type arg2_type;
            typedef typename sig_traits<funct>::arg3_type arg3_type;
            typedef typename sig_traits<funct>::arg4_type arg4_type;
            typedef typename sig_traits<funct>::arg5_type arg5_type;
            typedef typename sig_traits<funct>::arg6_type arg6_type;
            typedef typename sig_traits<funct>::arg7_type arg7_type;

            typename basic_type<arg1_type>::type A1;
            typename basic_type<arg2_type>::type A2;
            typename basic_type<arg3_type>::type A3;
            typename basic_type<arg4_type>::type A4;
            typename basic_type<arg5_type>::type A5;
            typename basic_type<arg6_type>::type A6;
            typename basic_type<arg7_type>::type A7;

            int i = 0;
            if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1;
            if (i < nrhs && is_input_type<arg2_type>::value) {validate_and_populate_arg(i,prhs[i],A2); ++i;} ELSE_ASSIGN_ARG_2;
            if (i < nrhs && is_input_type<arg3_type>::value) {validate_and_populate_arg(i,prhs[i],A3); ++i;} ELSE_ASSIGN_ARG_3;
            if (i < nrhs && is_input_type<arg4_type>::value) {validate_and_populate_arg(i,prhs[i],A4); ++i;} ELSE_ASSIGN_ARG_4;
            if (i < nrhs && is_input_type<arg5_type>::value) {validate_and_populate_arg(i,prhs[i],A5); ++i;} ELSE_ASSIGN_ARG_5;
            if (i < nrhs && is_input_type<arg6_type>::value) {validate_and_populate_arg(i,prhs[i],A6); ++i;} ELSE_ASSIGN_ARG_6;
            if (i < nrhs && is_input_type<arg7_type>::value) {validate_and_populate_arg(i,prhs[i],A7); ++i;} ELSE_ASSIGN_ARG_7;

            mex_function(A1,A2,A3,A4,A5,A6,A7);

            i = 0;
            if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;}
            if (is_output_type<arg2_type>::value) {assign_to_matlab(plhs[i],A2); ++i;}
            if (is_output_type<arg3_type>::value) {assign_to_matlab(plhs[i],A3); ++i;}
            if (is_output_type<arg4_type>::value) {assign_to_matlab(plhs[i],A4); ++i;}
            if (is_output_type<arg5_type>::value) {assign_to_matlab(plhs[i],A5); ++i;}
            if (is_output_type<arg6_type>::value) {assign_to_matlab(plhs[i],A6); ++i;}
            if (is_output_type<arg7_type>::value) {assign_to_matlab(plhs[i],A7); ++i;}
        }
    };

    template <>
    struct call_mex_function_helper<8>
    {
        template <typename funct>
        void callit(
            const funct& ,
            int nlhs, mxArray *plhs[],
            int nrhs, const mxArray *prhs[]
        ) const
        {
            typedef typename sig_traits<funct>::arg1_type arg1_type;
            typedef typename sig_traits<funct>::arg2_type arg2_type;
            typedef typename sig_traits<funct>::arg3_type arg3_type;
            typedef typename sig_traits<funct>::arg4_type arg4_type;
            typedef typename sig_traits<funct>::arg5_type arg5_type;
            typedef typename sig_traits<funct>::arg6_type arg6_type;
            typedef typename sig_traits<funct>::arg7_type arg7_type;
            typedef typename sig_traits<funct>::arg8_type arg8_type;

            typename basic_type<arg1_type>::type A1;
            typename basic_type<arg2_type>::type A2;
            typename basic_type<arg3_type>::type A3;
            typename basic_type<arg4_type>::type A4;
            typename basic_type<arg5_type>::type A5;
            typename basic_type<arg6_type>::type A6;
            typename basic_type<arg7_type>::type A7;
            typename basic_type<arg8_type>::type A8;

            int i = 0;
            if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1;
            if (i < nrhs && is_input_type<arg2_type>::value) {validate_and_populate_arg(i,prhs[i],A2); ++i;} ELSE_ASSIGN_ARG_2;
            if (i < nrhs && is_input_type<arg3_type>::value) {validate_and_populate_arg(i,prhs[i],A3); ++i;} ELSE_ASSIGN_ARG_3;
            if (i < nrhs && is_input_type<arg4_type>::value) {validate_and_populate_arg(i,prhs[i],A4); ++i;} ELSE_ASSIGN_ARG_4;
            if (i < nrhs && is_input_type<arg5_type>::value) {validate_and_populate_arg(i,prhs[i],A5); ++i;} ELSE_ASSIGN_ARG_5;
            if (i < nrhs && is_input_type<arg6_type>::value) {validate_and_populate_arg(i,prhs[i],A6); ++i;} ELSE_ASSIGN_ARG_6;
            if (i < nrhs && is_input_type<arg7_type>::value) {validate_and_populate_arg(i,prhs[i],A7); ++i;} ELSE_ASSIGN_ARG_7;
            if (i < nrhs && is_input_type<arg8_type>::value) {validate_and_populate_arg(i,prhs[i],A8); ++i;} ELSE_ASSIGN_ARG_8;

            mex_function(A1,A2,A3,A4,A5,A6,A7,A8);

            i = 0;
            if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;}
            if (is_output_type<arg2_type>::value) {assign_to_matlab(plhs[i],A2); ++i;}
            if (is_output_type<arg3_type>::value) {assign_to_matlab(plhs[i],A3); ++i;}
            if (is_output_type<arg4_type>::value) {assign_to_matlab(plhs[i],A4); ++i;}
            if (is_output_type<arg5_type>::value) {assign_to_matlab(plhs[i],A5); ++i;}
            if (is_output_type<arg6_type>::value) {assign_to_matlab(plhs[i],A6); ++i;}
            if (is_output_type<arg7_type>::value) {assign_to_matlab(plhs[i],A7); ++i;}
            if (is_output_type<arg8_type>::value) {assign_to_matlab(plhs[i],A8); ++i;}
        }
    };

    template <>
    struct call_mex_function_helper<9>
    {
        template <typename funct>
        void callit(
            const funct& ,
            int nlhs, mxArray *plhs[],
            int nrhs, const mxArray *prhs[]
        ) const
        {
            typedef typename sig_traits<funct>::arg1_type arg1_type;
            typedef typename sig_traits<funct>::arg2_type arg2_type;
            typedef typename sig_traits<funct>::arg3_type arg3_type;
            typedef typename sig_traits<funct>::arg4_type arg4_type;
            typedef typename sig_traits<funct>::arg5_type arg5_type;
            typedef typename sig_traits<funct>::arg6_type arg6_type;
            typedef typename sig_traits<funct>::arg7_type arg7_type;
            typedef typename sig_traits<funct>::arg8_type arg8_type;
            typedef typename sig_traits<funct>::arg9_type arg9_type;

            typename basic_type<arg1_type>::type A1;
            typename basic_type<arg2_type>::type A2;
            typename basic_type<arg3_type>::type A3;
            typename basic_type<arg4_type>::type A4;
            typename basic_type<arg5_type>::type A5;
            typename basic_type<arg6_type>::type A6;
            typename basic_type<arg7_type>::type A7;
            typename basic_type<arg8_type>::type A8;
            typename basic_type<arg9_type>::type A9;

            int i = 0;
            if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1;
            if (i < nrhs && is_input_type<arg2_type>::value) {validate_and_populate_arg(i,prhs[i],A2); ++i;} ELSE_ASSIGN_ARG_2;
            if (i < nrhs && is_input_type<arg3_type>::value) {validate_and_populate_arg(i,prhs[i],A3); ++i;} ELSE_ASSIGN_ARG_3;
            if (i < nrhs && is_input_type<arg4_type>::value) {validate_and_populate_arg(i,prhs[i],A4); ++i;} ELSE_ASSIGN_ARG_4;
            if (i < nrhs && is_input_type<arg5_type>::value) {validate_and_populate_arg(i,prhs[i],A5); ++i;} ELSE_ASSIGN_ARG_5;
            if (i < nrhs && is_input_type<arg6_type>::value) {validate_and_populate_arg(i,prhs[i],A6); ++i;} ELSE_ASSIGN_ARG_6;
            if (i < nrhs && is_input_type<arg7_type>::value) {validate_and_populate_arg(i,prhs[i],A7); ++i;} ELSE_ASSIGN_ARG_7;
            if (i < nrhs && is_input_type<arg8_type>::value) {validate_and_populate_arg(i,prhs[i],A8); ++i;} ELSE_ASSIGN_ARG_8;
            if (i < nrhs && is_input_type<arg9_type>::value) {validate_and_populate_arg(i,prhs[i],A9); ++i;} ELSE_ASSIGN_ARG_9;

            mex_function(A1,A2,A3,A4,A5,A6,A7,A8,A9);

            i = 0;
            if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;}
            if (is_output_type<arg2_type>::value) {assign_to_matlab(plhs[i],A2); ++i;}
            if (is_output_type<arg3_type>::value) {assign_to_matlab(plhs[i],A3); ++i;}
            if (is_output_type<arg4_type>::value) {assign_to_matlab(plhs[i],A4); ++i;}
            if (is_output_type<arg5_type>::value) {assign_to_matlab(plhs[i],A5); ++i;}
            if (is_output_type<arg6_type>::value) {assign_to_matlab(plhs[i],A6); ++i;}
            if (is_output_type<arg7_type>::value) {assign_to_matlab(plhs[i],A7); ++i;}
            if (is_output_type<arg8_type>::value) {assign_to_matlab(plhs[i],A8); ++i;}
            if (is_output_type<arg9_type>::value) {assign_to_matlab(plhs[i],A9); ++i;}
        }
    };

    template <>
    struct call_mex_function_helper<10>
    {
        template <typename funct>
        void callit(
            const funct& ,
            int nlhs, mxArray *plhs[],
            int nrhs, const mxArray *prhs[]
        ) const
        {
            typedef typename sig_traits<funct>::arg1_type arg1_type;
            typedef typename sig_traits<funct>::arg2_type arg2_type;
            typedef typename sig_traits<funct>::arg3_type arg3_type;
            typedef typename sig_traits<funct>::arg4_type arg4_type;
            typedef typename sig_traits<funct>::arg5_type arg5_type;
            typedef typename sig_traits<funct>::arg6_type arg6_type;
            typedef typename sig_traits<funct>::arg7_type arg7_type;
            typedef typename sig_traits<funct>::arg8_type arg8_type;
            typedef typename sig_traits<funct>::arg9_type arg9_type;
            typedef typename sig_traits<funct>::arg10_type arg10_type;

            typename basic_type<arg1_type>::type A1;
            typename basic_type<arg2_type>::type A2;
            typename basic_type<arg3_type>::type A3;
            typename basic_type<arg4_type>::type A4;
            typename basic_type<arg5_type>::type A5;
            typename basic_type<arg6_type>::type A6;
            typename basic_type<arg7_type>::type A7;
            typename basic_type<arg8_type>::type A8;
            typename basic_type<arg9_type>::type A9;
            typename basic_type<arg10_type>::type A10;

            int i = 0;
            if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1;
            if (i < nrhs && is_input_type<arg2_type>::value) {validate_and_populate_arg(i,prhs[i],A2); ++i;} ELSE_ASSIGN_ARG_2;
            if (i < nrhs && is_input_type<arg3_type>::value) {validate_and_populate_arg(i,prhs[i],A3); ++i;} ELSE_ASSIGN_ARG_3;
            if (i < nrhs && is_input_type<arg4_type>::value) {validate_and_populate_arg(i,prhs[i],A4); ++i;} ELSE_ASSIGN_ARG_4;
            if (i < nrhs && is_input_type<arg5_type>::value) {validate_and_populate_arg(i,prhs[i],A5); ++i;} ELSE_ASSIGN_ARG_5;
            if (i < nrhs && is_input_type<arg6_type>::value) {validate_and_populate_arg(i,prhs[i],A6); ++i;} ELSE_ASSIGN_ARG_6;
            if (i < nrhs && is_input_type<arg7_type>::value) {validate_and_populate_arg(i,prhs[i],A7); ++i;} ELSE_ASSIGN_ARG_7;
            if (i < nrhs && is_input_type<arg8_type>::value) {validate_and_populate_arg(i,prhs[i],A8); ++i;} ELSE_ASSIGN_ARG_8;
            if (i < nrhs && is_input_type<arg9_type>::value) {validate_and_populate_arg(i,prhs[i],A9); ++i;} ELSE_ASSIGN_ARG_9;
            if (i < nrhs && is_input_type<arg10_type>::value) {validate_and_populate_arg(i,prhs[i],A10); ++i;} ELSE_ASSIGN_ARG_10;

            mex_function(A1,A2,A3,A4,A5,A6,A7,A8,A9,A10);

            i = 0;
            if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;}
            if (is_output_type<arg2_type>::value) {assign_to_matlab(plhs[i],A2); ++i;}
            if (is_output_type<arg3_type>::value) {assign_to_matlab(plhs[i],A3); ++i;}
            if (is_output_type<arg4_type>::value) {assign_to_matlab(plhs[i],A4); ++i;}
            if (is_output_type<arg5_type>::value) {assign_to_matlab(plhs[i],A5); ++i;}
            if (is_output_type<arg6_type>::value) {assign_to_matlab(plhs[i],A6); ++i;}
            if (is_output_type<arg7_type>::value) {assign_to_matlab(plhs[i],A7); ++i;}
            if (is_output_type<arg8_type>::value) {assign_to_matlab(plhs[i],A8); ++i;}
            if (is_output_type<arg9_type>::value) {assign_to_matlab(plhs[i],A9); ++i;}
            if (is_output_type<arg10_type>::value) {assign_to_matlab(plhs[i],A10); ++i;}
        }
    };

// ----------------------------------------------------------------------------------------

    template <
        typename funct
        >
    void call_mex_function (
        const funct& f,
        int nlhs, mxArray *plhs[],
        int nrhs, const mxArray *prhs[]
    )
    {
        const long expected_nrhs = funct_traits<funct>::num_inputs;
        const long expected_nlhs = funct_traits<funct>::num_outputs;
        const long expected_args = expected_nrhs + expected_nlhs;

        long defaulted_args = 0;

        #ifdef ARG_1_DEFAULT
            ++defaulted_args;
            // You can only set an argument's default value if it is an input argument.
            COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg1_type>::value);
            #ifndef ARG_2_DEFAULT
                // You can't define a default for argument 1 if you don't define one for argument 2 also.
                COMPILE_TIME_ASSERT(expected_args < 2);
            #endif
            COMPILE_TIME_ASSERT(1 <= expected_args); // You can't define a default for an argument that doesn't exist.
        #endif
        #ifdef ARG_2_DEFAULT
            ++defaulted_args;
            // You can only set an argument's default value if it is an input argument.
            COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg2_type>::value);
            #ifndef ARG_3_DEFAULT
                // You can't define a default for argument 2 if you don't define one for argument 3 also.
                COMPILE_TIME_ASSERT(expected_args < 3);
            #endif
            COMPILE_TIME_ASSERT(2 <= expected_args); // You can't define a default for an argument that doesn't exist.
        #endif
        #ifdef ARG_3_DEFAULT
            ++defaulted_args;
            // You can only set an argument's default value if it is an input argument.
            COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg3_type>::value);
            #ifndef ARG_4_DEFAULT
                // You can't define a default for argument 3 if you don't define one for argument 4 also.
                COMPILE_TIME_ASSERT(expected_args < 4);
            #endif
            COMPILE_TIME_ASSERT(3 <= expected_args); // You can't define a default for an argument that doesn't exist.
        #endif
        #ifdef ARG_4_DEFAULT
            ++defaulted_args;
            // You can only set an argument's default value if it is an input argument.
            COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg4_type>::value);
            #ifndef ARG_5_DEFAULT
                // You can't define a default for argument 4 if you don't define one for argument 5 also.
                COMPILE_TIME_ASSERT(expected_args < 5);
            #endif
            COMPILE_TIME_ASSERT(4 <= expected_args); // You can't define a default for an argument that doesn't exist.
        #endif
        #ifdef ARG_5_DEFAULT
            ++defaulted_args;
            // You can only set an argument's default value if it is an input argument.
            COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg5_type>::value);
            #ifndef ARG_6_DEFAULT
                // You can't define a default for argument 5 if you don't define one for argument 6 also.
                COMPILE_TIME_ASSERT(expected_args < 6);
            #endif
            COMPILE_TIME_ASSERT(5 <= expected_args); // You can't define a default for an argument that doesn't exist.
        #endif
        #ifdef ARG_6_DEFAULT
            ++defaulted_args;
            // You can only set an argument's default value if it is an input argument.
            COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg6_type>::value);
            #ifndef ARG_7_DEFAULT
                // You can't define a default for argument 6 if you don't define one for argument 7 also.
                COMPILE_TIME_ASSERT(expected_args < 7);
            #endif
            COMPILE_TIME_ASSERT(6 <= expected_args); // You can't define a default for an argument that doesn't exist.
        #endif
        #ifdef ARG_7_DEFAULT
            ++defaulted_args;
            // You can only set an argument's default value if it is an input argument.
            COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg7_type>::value);
            #ifndef ARG_8_DEFAULT
                // You can't define a default for argument 7 if you don't define one for argument 8 also.
                COMPILE_TIME_ASSERT(expected_args < 8);
            #endif
            COMPILE_TIME_ASSERT(7 <= expected_args); // You can't define a default for an argument that doesn't exist.
        #endif
        #ifdef ARG_8_DEFAULT
            ++defaulted_args;
            // You can only set an argument's default value if it is an input argument.
            COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg8_type>::value);
            #ifndef ARG_9_DEFAULT
                // You can't define a default for argument 8 if you don't define one for argument 9 also.
                COMPILE_TIME_ASSERT(expected_args < 9);
            #endif
            COMPILE_TIME_ASSERT(8 <= expected_args); // You can't define a default for an argument that doesn't exist.
        #endif
        #ifdef ARG_9_DEFAULT
            ++defaulted_args;
            // You can only set an argument's default value if it is an input argument.
            COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg9_type>::value);
            #ifndef ARG_10_DEFAULT
                // You can't define a default for argument 9 if you don't define one for argument 10 also.
                COMPILE_TIME_ASSERT(expected_args < 10);
            #endif
            COMPILE_TIME_ASSERT(9 <= expected_args); // You can't define a default for an argument that doesn't exist.
        #endif
        #ifdef ARG_10_DEFAULT
            ++defaulted_args;
            // You can only set an argument's default value if it is an input argument.
            COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg10_type>::value);
            COMPILE_TIME_ASSERT(10 <= expected_args); // You can't define a default for an argument that doesn't exist.
        #endif

        /* check for proper number of arguments */
        if(nrhs > expected_nrhs || nrhs < expected_nrhs - defaulted_args)
        {
            std::ostringstream sout;
            sout << "Expected between " << expected_nrhs-defaulted_args
                << " and " << expected_nrhs << " input arguments, got " << nrhs << ".";

            mexErrMsgIdAndTxt("mex_function:nrhs",
                              sout.str().c_str());
        }

        if (nlhs > expected_nlhs)
        {
            std::ostringstream sout;
            sout << "Expected at most " << expected_nlhs << " output arguments, got " << nlhs << ".";

            mexErrMsgIdAndTxt("mex_function:nlhs",
                              sout.str().c_str());
        }

        try
        {
            call_mex_function_helper<sig_traits<funct>::num_args> helper;
            helper.callit(f, nlhs, plhs, nrhs, prhs);
        }
        catch (invalid_args_exception& e)
        {
            mexErrMsgIdAndTxt("mex_function:validate_and_populate_arg",
                              ("Input" + e.msg).c_str());
        }
        catch (dlib::error& e)
        {
            mexErrMsgIdAndTxt("mex_function:error",
                              e.what());
        }

    }

// ----------------------------------------------------------------------------------------

    class mex_streambuf : public std::streambuf
    {

    public:
        mex_streambuf (
        )
        {
            buf.resize(1000);
            setp(&buf[0], &buf[0] + buf.size()-2);

            // make cout send data to mex_streambuf
            std::cout.rdbuf(this);
        }

    protected:

        int sync (
        )
        {
            int num = static_cast<int>(pptr()-pbase());
            if (num != 0)
            {
                buf[num] = 0; // null terminate the string
                mexPrintf("%s",&buf[0]);
                mexEvalString("drawnow"); // flush print to screen
                pbump(-num);
            }
            return 0;
        }

        int_type overflow (
            int_type c
        )
        {
            if (c != EOF)
            {
                *pptr() = c;
                pbump(1);
            }
            sync();
            return c;
        }

    private:
        std::vector<char> buf;

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <typename T>
    void setup_input_args (
        mxArray*& array,
        const T& item,
        int& nrhs
    )
    {
        assign_to_matlab(array, item);
        ++nrhs;
    }

    void setup_input_args (
        mxArray*& array,
        const function_handle& item,
        int& nrhs
    )
    {
        array = static_cast<mxArray*>(item.h);
        ++nrhs;
    }

    template <typename T>
    void setup_input_args (
        mxArray*& array,
        const output_decorator<T>& item,
        int& nrhs
    )
    {
    }

    template <typename T>
    void setup_output_args (
        const std::string& function_name,
        mxArray* array,
        const T& item,
        int& nrhs
    )
    {
    }

    template <typename T>
    void setup_output_args (
        const std::string& function_name,
        mxArray* array,
        const output_decorator<T>& item,
        int& i
    )
    {
        try
        {
            validate_and_populate_arg(i,array,const_cast<T&>(item.item));
            ++i;
        }
        catch (invalid_args_exception& e)
        {
            throw dlib::error("Error occurred calling MATLAB function '" + function_name + "' from mex file. \n"
                              "The MATLAB function didn't return what we expected it to.  \nIn particular, return" + e.msg);
        }
    }

    void call_matlab_for_real (
        int nlhs,
        mxArray* plhs[],
        int nrhs,
        mxArray* prhs[],
        const std::string& function_name
    )
    {
        int status = mexCallMATLAB(nlhs, plhs, nrhs, prhs, function_name.c_str());
        if (status)
        {
            throw dlib::error("Error, an exception was thrown when we tried to call the MATLAB function '" + function_name + "'.");
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

}

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

void call_matlab (
    const std::string& function_name
)
{
    using namespace mex_binding;

    call_matlab_for_real(0,NULL,0,NULL, function_name);
}

template <typename T1>
void free_callback_resources (
    int nlhs,
    mxArray* plhs[],
    int nrhs,
    mxArray* prhs[]
)
{
    // free resources
    for (int i = 0; i < nlhs; ++i)
        mxDestroyArray(plhs[i]);

    for (int i = 0; i < nrhs; ++i)
    {
        // don't call mxDestroyArray() on function handles (which should only ever be in prhs[0])
        if (i == 0 && dlib::is_same_type<T1,function_handle>::value)
            continue;
        mxDestroyArray(prhs[i]);
    }
}

template <
    typename T1
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1
)
{
    using namespace mex_binding;
    const int num_args = 1;
    mxArray* plhs[num_args] = {0};
    mxArray* prhs[num_args] = {0};

    int nrhs = 0;
    setup_input_args(prhs[nrhs], A1, nrhs);

    const int nlhs = num_args - nrhs;
    call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name);

    int i = 0;
    setup_output_args(function_name, plhs[i], A1, i);

    free_callback_resources<T1>(nlhs,plhs,nrhs,prhs);
}

template <
    typename T1,
    typename T2
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1,
    const T2& A2
)
{
    using namespace mex_binding;
    const int num_args = 2;
    mxArray* plhs[num_args] = {0};
    mxArray* prhs[num_args] = {0};

    int nrhs = 0;
    setup_input_args(prhs[nrhs], A1, nrhs);
    setup_input_args(prhs[nrhs], A2, nrhs);

    const int nlhs = num_args - nrhs;
    call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name);

    int i = 0;
    setup_output_args(function_name, plhs[i], A1, i);
    setup_output_args(function_name, plhs[i], A2, i);

    free_callback_resources<T1>(nlhs,plhs,nrhs,prhs);
}

template <
    typename T1,
    typename T2,
    typename T3
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1,
    const T2& A2,
    const T3& A3
)
{
    using namespace mex_binding;
    const int num_args = 3;
    mxArray* plhs[num_args] = {0};
    mxArray* prhs[num_args] = {0};

    int nrhs = 0;
    setup_input_args(prhs[nrhs], A1, nrhs);
    setup_input_args(prhs[nrhs], A2, nrhs);
    setup_input_args(prhs[nrhs], A3, nrhs);

    const int nlhs = num_args - nrhs;
    call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name);

    int i = 0;
    setup_output_args(function_name, plhs[i], A1, i);
    setup_output_args(function_name, plhs[i], A2, i);
    setup_output_args(function_name, plhs[i], A3, i);

    free_callback_resources<T1>(nlhs,plhs,nrhs,prhs);
}

template <
    typename T1,
    typename T2,
    typename T3,
    typename T4
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1,
    const T2& A2,
    const T3& A3,
    const T4& A4
)
{
    using namespace mex_binding;
    const int num_args = 4;
    mxArray* plhs[num_args] = {0};
    mxArray* prhs[num_args] = {0};

    int nrhs = 0;
    setup_input_args(prhs[nrhs], A1, nrhs);
    setup_input_args(prhs[nrhs], A2, nrhs);
    setup_input_args(prhs[nrhs], A3, nrhs);
    setup_input_args(prhs[nrhs], A4, nrhs);

    const int nlhs = num_args - nrhs;
    call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name);

    int i = 0;
    setup_output_args(function_name, plhs[i], A1, i);
    setup_output_args(function_name, plhs[i], A2, i);
    setup_output_args(function_name, plhs[i], A3, i);
    setup_output_args(function_name, plhs[i], A4, i);

    free_callback_resources<T1>(nlhs,plhs,nrhs,prhs);
}

template <
    typename T1,
    typename T2,
    typename T3,
    typename T4,
    typename T5
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1,
    const T2& A2,
    const T3& A3,
    const T4& A4,
    const T5& A5
)
{
    using namespace mex_binding;
    const int num_args = 5;
    mxArray* plhs[num_args] = {0};
    mxArray* prhs[num_args] = {0};

    int nrhs = 0;
    setup_input_args(prhs[nrhs], A1, nrhs);
    setup_input_args(prhs[nrhs], A2, nrhs);
    setup_input_args(prhs[nrhs], A3, nrhs);
    setup_input_args(prhs[nrhs], A4, nrhs);
    setup_input_args(prhs[nrhs], A5, nrhs);

    const int nlhs = num_args - nrhs;
    call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name);

    int i = 0;
    setup_output_args(function_name, plhs[i], A1, i);
    setup_output_args(function_name, plhs[i], A2, i);
    setup_output_args(function_name, plhs[i], A3, i);
    setup_output_args(function_name, plhs[i], A4, i);
    setup_output_args(function_name, plhs[i], A5, i);

    free_callback_resources<T1>(nlhs,plhs,nrhs,prhs);
}

template <
    typename T1,
    typename T2,
    typename T3,
    typename T4,
    typename T5,
    typename T6
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1,
    const T2& A2,
    const T3& A3,
    const T4& A4,
    const T5& A5,
    const T6& A6
)
{
    using namespace mex_binding;
    const int num_args = 6;
    mxArray* plhs[num_args] = {0};
    mxArray* prhs[num_args] = {0};

    int nrhs = 0;
    setup_input_args(prhs[nrhs], A1, nrhs);
    setup_input_args(prhs[nrhs], A2, nrhs);
    setup_input_args(prhs[nrhs], A3, nrhs);
    setup_input_args(prhs[nrhs], A4, nrhs);
    setup_input_args(prhs[nrhs], A5, nrhs);
    setup_input_args(prhs[nrhs], A6, nrhs);

    const int nlhs = num_args - nrhs;
    call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name);

    int i = 0;
    setup_output_args(function_name, plhs[i], A1, i);
    setup_output_args(function_name, plhs[i], A2, i);
    setup_output_args(function_name, plhs[i], A3, i);
    setup_output_args(function_name, plhs[i], A4, i);
    setup_output_args(function_name, plhs[i], A5, i);
    setup_output_args(function_name, plhs[i], A6, i);

    free_callback_resources<T1>(nlhs,plhs,nrhs,prhs);
}

template <
    typename T1,
    typename T2,
    typename T3,
    typename T4,
    typename T5,
    typename T6,
    typename T7
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1,
    const T2& A2,
    const T3& A3,
    const T4& A4,
    const T5& A5,
    const T6& A6,
    const T7& A7
)
{
    using namespace mex_binding;
    const int num_args = 7;
    mxArray* plhs[num_args] = {0};
    mxArray* prhs[num_args] = {0};

    int nrhs = 0;
    setup_input_args(prhs[nrhs], A1, nrhs);
    setup_input_args(prhs[nrhs], A2, nrhs);
    setup_input_args(prhs[nrhs], A3, nrhs);
    setup_input_args(prhs[nrhs], A4, nrhs);
    setup_input_args(prhs[nrhs], A5, nrhs);
    setup_input_args(prhs[nrhs], A6, nrhs);
    setup_input_args(prhs[nrhs], A7, nrhs);

    const int nlhs = num_args - nrhs;
    call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name);

    int i = 0;
    setup_output_args(function_name, plhs[i], A1, i);
    setup_output_args(function_name, plhs[i], A2, i);
    setup_output_args(function_name, plhs[i], A3, i);
    setup_output_args(function_name, plhs[i], A4, i);
    setup_output_args(function_name, plhs[i], A5, i);
    setup_output_args(function_name, plhs[i], A6, i);
    setup_output_args(function_name, plhs[i], A7, i);

    free_callback_resources<T1>(nlhs,plhs,nrhs,prhs);
}

template <
    typename T1,
    typename T2,
    typename T3,
    typename T4,
    typename T5,
    typename T6,
    typename T7,
    typename T8
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1,
    const T2& A2,
    const T3& A3,
    const T4& A4,
    const T5& A5,
    const T6& A6,
    const T7& A7,
    const T8& A8
)
{
    using namespace mex_binding;
    const int num_args = 8;
    mxArray* plhs[num_args] = {0};
    mxArray* prhs[num_args] = {0};

    int nrhs = 0;
    setup_input_args(prhs[nrhs], A1, nrhs);
    setup_input_args(prhs[nrhs], A2, nrhs);
    setup_input_args(prhs[nrhs], A3, nrhs);
    setup_input_args(prhs[nrhs], A4, nrhs);
    setup_input_args(prhs[nrhs], A5, nrhs);
    setup_input_args(prhs[nrhs], A6, nrhs);
    setup_input_args(prhs[nrhs], A7, nrhs);
    setup_input_args(prhs[nrhs], A8, nrhs);

    const int nlhs = num_args - nrhs;
    call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name);

    int i = 0;
    setup_output_args(function_name, plhs[i], A1, i);
    setup_output_args(function_name, plhs[i], A2, i);
    setup_output_args(function_name, plhs[i], A3, i);
    setup_output_args(function_name, plhs[i], A4, i);
    setup_output_args(function_name, plhs[i], A5, i);
    setup_output_args(function_name, plhs[i], A6, i);
    setup_output_args(function_name, plhs[i], A7, i);
    setup_output_args(function_name, plhs[i], A8, i);

    free_callback_resources<T1>(nlhs,plhs,nrhs,prhs);
}

template <
    typename T1,
    typename T2,
    typename T3,
    typename T4,
    typename T5,
    typename T6,
    typename T7,
    typename T8,
    typename T9
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1,
    const T2& A2,
    const T3& A3,
    const T4& A4,
    const T5& A5,
    const T6& A6,
    const T7& A7,
    const T8& A8,
    const T9& A9
)
{
    using namespace mex_binding;
    const int num_args = 9;
    mxArray* plhs[num_args] = {0};
    mxArray* prhs[num_args] = {0};

    int nrhs = 0;
    setup_input_args(prhs[nrhs], A1, nrhs);
    setup_input_args(prhs[nrhs], A2, nrhs);
    setup_input_args(prhs[nrhs], A3, nrhs);
    setup_input_args(prhs[nrhs], A4, nrhs);
    setup_input_args(prhs[nrhs], A5, nrhs);
    setup_input_args(prhs[nrhs], A6, nrhs);
    setup_input_args(prhs[nrhs], A7, nrhs);
    setup_input_args(prhs[nrhs], A8, nrhs);
    setup_input_args(prhs[nrhs], A9, nrhs);

    const int nlhs = num_args - nrhs;
    call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name);

    int i = 0;
    setup_output_args(function_name, plhs[i], A1, i);
    setup_output_args(function_name, plhs[i], A2, i);
    setup_output_args(function_name, plhs[i], A3, i);
    setup_output_args(function_name, plhs[i], A4, i);
    setup_output_args(function_name, plhs[i], A5, i);
    setup_output_args(function_name, plhs[i], A6, i);
    setup_output_args(function_name, plhs[i], A7, i);
    setup_output_args(function_name, plhs[i], A8, i);
    setup_output_args(function_name, plhs[i], A9, i);

    free_callback_resources<T1>(nlhs,plhs,nrhs,prhs);
}

template <
    typename T1,
    typename T2,
    typename T3,
    typename T4,
    typename T5,
    typename T6,
    typename T7,
    typename T8,
    typename T9,
    typename T10
    >
void call_matlab (
    const std::string& function_name,
    const T1& A1,
    const T2& A2,
    const T3& A3,
    const T4& A4,
    const T5& A5,
    const T6& A6,
    const T7& A7,
    const T8& A8,
    const T9& A9,
    const T10& A10
)
{
    using namespace mex_binding;
    const int num_args = 10;
    mxArray* plhs[num_args] = {0};
    mxArray* prhs[num_args] = {0};

    int nrhs = 0;
    setup_input_args(prhs[nrhs], A1, nrhs);
    setup_input_args(prhs[nrhs], A2, nrhs);
    setup_input_args(prhs[nrhs], A3, nrhs);
    setup_input_args(prhs[nrhs], A4, nrhs);
    setup_input_args(prhs[nrhs], A5, nrhs);
    setup_input_args(prhs[nrhs], A6, nrhs);
    setup_input_args(prhs[nrhs], A7, nrhs);
    setup_input_args(prhs[nrhs], A8, nrhs);
    setup_input_args(prhs[nrhs], A10, nrhs);

    const int nlhs = num_args - nrhs;
    call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name);

    int i = 0;
    setup_output_args(function_name, plhs[i], A1, i);
    setup_output_args(function_name, plhs[i], A2, i);
    setup_output_args(function_name, plhs[i], A3, i);
    setup_output_args(function_name, plhs[i], A4, i);
    setup_output_args(function_name, plhs[i], A5, i);
    setup_output_args(function_name, plhs[i], A6, i);
    setup_output_args(function_name, plhs[i], A7, i);
    setup_output_args(function_name, plhs[i], A8, i);
    setup_output_args(function_name, plhs[i], A10, i);

    free_callback_resources<T1>(nlhs,plhs,nrhs,prhs);
}

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

void call_matlab (
    const function_handle& funct
)
{
    call_matlab("feval", funct);
}

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

/* The gateway function called by MATLAB*/
void mexFunction( int nlhs, mxArray *plhs[],
                  int nrhs, const mxArray *prhs[])
{
    // Only remap cout if we aren't using octave since octave already does this.
#if !defined(OCTAVE_IMPORT) && !defined(OCTAVE_API)
    // make it so cout prints to mexPrintf()
    static mex_binding::mex_streambuf sb;
#endif

    mex_binding::call_mex_function(mex_function, nlhs, plhs, nrhs, prhs);
}

// ----------------------------------------------------------------------------------------


dlib C++ Library - cblas_constants.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_CBLAS_CONSTAnTS_Hh_
#define DLIB_CBLAS_CONSTAnTS_Hh_

namespace dlib
{
    namespace blas_bindings
    {
        enum CBLAS_ORDER {CblasRowMajor=101, CblasColMajor=102};
        enum CBLAS_TRANSPOSE {CblasNoTrans=111, CblasTrans=112, CblasConjTrans=113};
        enum CBLAS_UPLO {CblasUpper=121, CblasLower=122};
        enum CBLAS_DIAG {CblasNonUnit=131, CblasUnit=132};
        enum CBLAS_SIDE {CblasLeft=141, CblasRight=142};

    }
}

#endif // DLIB_CBLAS_CONSTAnTS_Hh_


dlib C++ Library - matrix.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MATRIx_
#define DLIB_MATRIx_

#include "matrix_exp.h"
#include "matrix_abstract.h"
#include "../algs.h"
#include "../serialize.h"
#include "../enable_if.h"
#include <sstream>
#include <algorithm>
#include "../memory_manager.h"
#include "../is_kind.h"
#include "matrix_data_layout.h"
#include "matrix_assign_fwd.h"
#include "matrix_op.h"

#ifdef _MSC_VER
// Disable the following warnings for Visual Studio

// This warning is:
//    "warning C4355: 'this' : used in base member initializer list"
// Which we get from this code but it is not an error so I'm turning this
// warning off and then turning it back on at the end of the file.
#pragma warning(disable : 4355)

#endif

namespace dlib
{

// ----------------------------------------------------------------------------------------

    // This template will perform the needed loop for element multiplication using whichever
    // dimension is provided as a compile time constant (if one is at all).
    template <
        typename LHS,
        typename RHS,
        long lhs_nc = LHS::NC,
        long rhs_nr = RHS::NR
        >
    struct matrix_multiply_helper
    {
        typedef typename LHS::type type;
        template <typename RHS_, typename LHS_>
        inline const static type  eval (
            const RHS_& rhs,
            const LHS_& lhs,
            const long r,
            const long c
        )
        {
            type temp = lhs(r,0)*rhs(0,c);
            for (long i = 1; i < rhs.nr(); ++i)
            {
                temp += lhs(r,i)*rhs(i,c);
            }
            return temp;
        }
    };

    template <
        typename LHS,
        typename RHS,
        long lhs_nc
        >
    struct matrix_multiply_helper <LHS,RHS,lhs_nc,0>
    {
        typedef typename LHS::type type;
        template <typename RHS_, typename LHS_>
        inline const static type  eval (
            const RHS_& rhs,
            const LHS_& lhs,
            const long r,
            const long c
        )
        {
            type temp = lhs(r,0)*rhs(0,c);
            for (long i = 1; i < lhs.nc(); ++i)
            {
                temp += lhs(r,i)*rhs(i,c);
            }
            return temp;
        }
    };

    template <typename LHS, typename RHS>
    class matrix_multiply_exp;

    template <typename LHS, typename RHS>
    struct matrix_traits<matrix_multiply_exp<LHS,RHS> >
    {
        typedef typename LHS::type type;
        typedef typename LHS::type const_ret_type;
        typedef typename LHS::mem_manager_type mem_manager_type;
        typedef typename LHS::layout_type layout_type;
        const static long NR = LHS::NR;
        const static long NC = RHS::NC;

#ifdef DLIB_USE_BLAS
        // if there are BLAS functions to be called then we want to make sure we
        // always evaluate any complex expressions so that the BLAS bindings can happen.
        const static bool lhs_is_costly = (LHS::cost > 2)&&(RHS::NC != 1 || LHS::cost >= 10000);
        const static bool rhs_is_costly = (RHS::cost > 2)&&(LHS::NR != 1 || RHS::cost >= 10000);
#else
        const static bool lhs_is_costly = (LHS::cost > 4)&&(RHS::NC != 1);
        const static bool rhs_is_costly = (RHS::cost > 4)&&(LHS::NR != 1);
#endif

        // Note that if we decide that one of the matrices is too costly we will evaluate it
        // into a temporary.  Doing this resets its cost back to 1.
        const static long lhs_cost = ((lhs_is_costly==true)? 1 : (LHS::cost));
        const static long rhs_cost = ((rhs_is_costly==true)? 1 : (RHS::cost));

        // The cost of evaluating an element of a matrix multiply is the cost of evaluating elements from
        // RHS and LHS times the number of rows/columns in the RHS/LHS matrix.  If we don't know the matrix
        // dimensions then just assume it is really large.
        const static long cost = ((tmax<LHS::NC,RHS::NR>::value!=0)? ((lhs_cost+rhs_cost)*tmax<LHS::NC,RHS::NR>::value):(10000));
    };

    template <typename T, bool is_ref> struct conditional_matrix_temp { typedef typename T::matrix_type type; };
    template <typename T> struct conditional_matrix_temp<T,true>      { typedef T& type; };

    template <
        typename LHS,
        typename RHS
        >
    class matrix_multiply_exp : public matrix_exp<matrix_multiply_exp<LHS,RHS> >
    {
        /*!
            REQUIREMENTS ON LHS AND RHS
                - must be matrix_exp objects.
        !*/
    public:

        typedef typename matrix_traits<matrix_multiply_exp>::type type;
        typedef typename matrix_traits<matrix_multiply_exp>::const_ret_type const_ret_type;
        typedef typename matrix_traits<matrix_multiply_exp>::mem_manager_type mem_manager_type;
        const static long NR = matrix_traits<matrix_multiply_exp>::NR;
        const static long NC = matrix_traits<matrix_multiply_exp>::NC;
        const static long cost = matrix_traits<matrix_multiply_exp>::cost;
        typedef typename matrix_traits<matrix_multiply_exp>::layout_type layout_type;

        const static bool lhs_is_costly = matrix_traits<matrix_multiply_exp>::lhs_is_costly;
        const static bool rhs_is_costly = matrix_traits<matrix_multiply_exp>::rhs_is_costly;
        const static bool either_is_costly = lhs_is_costly || rhs_is_costly;
        const static bool both_are_costly = lhs_is_costly && rhs_is_costly;

        typedef typename conditional_matrix_temp<const LHS,lhs_is_costly == false>::type LHS_ref_type;
        typedef typename conditional_matrix_temp<const RHS,rhs_is_costly == false>::type RHS_ref_type;

        // This constructor exists simply for the purpose of causing a compile time error if
        // someone tries to create an instance of this object with the wrong kind of objects.
        template <typename T1, typename T2>
        matrix_multiply_exp (T1,T2);

        inline matrix_multiply_exp (
            const LHS& lhs_,
            const RHS& rhs_
        ) :
            lhs(lhs_),
            rhs(rhs_)
        {
            // You are trying to multiply two incompatible matrices together.  The number of columns
            // in the matrix on the left must match the number of rows in the matrix on the right.
            COMPILE_TIME_ASSERT(LHS::NC == RHS::NR || LHS::NC*RHS::NR == 0);
            DLIB_ASSERT(lhs.nc() == rhs.nr() && lhs.size() > 0 && rhs.size() > 0,
                "\tconst matrix_exp operator*(const matrix_exp& lhs, const matrix_exp& rhs)"
                << "\n\tYou are trying to multiply two incompatible matrices together"
                << "\n\tlhs.nr(): " << lhs.nr()
                << "\n\tlhs.nc(): " << lhs.nc()
                << "\n\trhs.nr(): " << rhs.nr()
                << "\n\trhs.nc(): " << rhs.nc()
                << "\n\t&lhs: " << &lhs
                << "\n\t&rhs: " << &rhs
                );

            // You can't multiply matrices together if they don't both contain the same type of elements.
            COMPILE_TIME_ASSERT((is_same_type<typename LHS::type, typename RHS::type>::value == true));
        }

        inline const type operator() (
            const long r,
            const long c
        ) const
        {
            return matrix_multiply_helper<LHS,RHS>::eval(rhs,lhs,r,c);
        }

        inline const type operator() ( long i ) const
        { return matrix_exp<matrix_multiply_exp>::operator()(i); }

        long nr (
        ) const { return lhs.nr(); }

        long nc (
        ) const { return rhs.nc(); }

        template <typename U>
        bool aliases (
            const matrix_exp<U>& item
        ) const { return lhs.aliases(item) || rhs.aliases(item); }

        template <typename U>
        bool destructively_aliases (
            const matrix_exp<U>& item
        ) const { return aliases(item); }

        LHS_ref_type lhs;
        RHS_ref_type rhs;
    };

    template < typename EXP1, typename EXP2 >
    inline const matrix_multiply_exp<EXP1, EXP2> operator* (
        const matrix_exp<EXP1>& m1,
        const matrix_exp<EXP2>& m2
    )
    {
        return matrix_multiply_exp<EXP1, EXP2>(m1.ref(), m2.ref());
    }

    template <typename M, bool use_reference = true>
    class matrix_mul_scal_exp;

    // -------------------------

    // Now we declare some overloads that cause any scalar multiplications to percolate
    // up and outside of any matrix multiplies.  Note that we are using the non-reference containing
    // mode of the matrix_mul_scal_exp object since we are passing in locally constructed matrix_multiply_exp
    // objects.  So the matrix_mul_scal_exp object will contain copies of matrix_multiply_exp objects
    // rather than references to them.  This could result in extra matrix copies if the matrix_multiply_exp
    // decided it should evaluate any of its arguments.  So we also try to not apply this percolating operation
    // if the matrix_multiply_exp would contain a fully evaluated copy of the original matrix_mul_scal_exp
    // expression.
    //
    // Also, the reason we want to apply this transformation in the first place is because it (1) makes
    // the expressions going into matrix multiply expressions simpler and (2) it makes it a lot more
    // straightforward to bind BLAS calls to matrix expressions involving scalar multiplies.
    template < typename EXP1, typename EXP2 >
    inline const typename disable_if_c< matrix_multiply_exp<matrix_mul_scal_exp<EXP1>, matrix_mul_scal_exp<EXP2> >::both_are_costly ,
                                        matrix_mul_scal_exp<matrix_multiply_exp<EXP1, EXP2>,false> >::type operator* (
        const matrix_mul_scal_exp<EXP1>& m1,
        const matrix_mul_scal_exp<EXP2>& m2
    )
    {
        typedef matrix_multiply_exp<EXP1, EXP2> exp1;
        typedef matrix_mul_scal_exp<exp1,false> exp2;
        return exp2(exp1(m1.m, m2.m), m1.s*m2.s);
    }

    template < typename EXP1, typename EXP2 >
    inline const typename disable_if_c< matrix_multiply_exp<matrix_mul_scal_exp<EXP1>, EXP2 >::lhs_is_costly ,
                                      matrix_mul_scal_exp<matrix_multiply_exp<EXP1, EXP2>,false> >::type operator* (
        const matrix_mul_scal_exp<EXP1>& m1,
        const matrix_exp<EXP2>& m2
    )
    {
        typedef matrix_multiply_exp<EXP1, EXP2> exp1;
        typedef matrix_mul_scal_exp<exp1,false> exp2;
        return exp2(exp1(m1.m, m2.ref()), m1.s);
    }

    template < typename EXP1, typename EXP2 >
    inline const typename disable_if_c< matrix_multiply_exp<EXP1, matrix_mul_scal_exp<EXP2> >::rhs_is_costly ,
                                      matrix_mul_scal_exp<matrix_multiply_exp<EXP1, EXP2>,false> >::type operator* (
        const matrix_exp<EXP1>& m1,
        const matrix_mul_scal_exp<EXP2>& m2
    )
    {
        typedef matrix_multiply_exp<EXP1, EXP2> exp1;
        typedef matrix_mul_scal_exp<exp1,false> exp2;
        return exp2(exp1(m1.ref(), m2.m), m2.s);
    }

// ----------------------------------------------------------------------------------------

    template <typename LHS, typename RHS>
    class matrix_add_exp;

    template <typename LHS, typename RHS>
    struct matrix_traits<matrix_add_exp<LHS,RHS> >
    {
        typedef typename LHS::type type;
        typedef typename LHS::type const_ret_type;
        typedef typename LHS::mem_manager_type mem_manager_type;
        typedef typename LHS::layout_type layout_type;
        const static long NR = (RHS::NR > LHS::NR) ? RHS::NR : LHS::NR;
        const static long NC = (RHS::NC > LHS::NC) ? RHS::NC : LHS::NC;
        const static long cost = LHS::cost+RHS::cost+1;
    };

    template <
        typename LHS,
        typename RHS
        >
    class matrix_add_exp : public matrix_exp<matrix_add_exp<LHS,RHS> >
    {
        /*!
            REQUIREMENTS ON LHS AND RHS
                - must be matrix_exp objects.
        !*/
    public:
        typedef typename matrix_traits<matrix_add_exp>::type type;
        typedef typename matrix_traits<matrix_add_exp>::const_ret_type const_ret_type;
        typedef typename matrix_traits<matrix_add_exp>::mem_manager_type mem_manager_type;
        const static long NR = matrix_traits<matrix_add_exp>::NR;
        const static long NC = matrix_traits<matrix_add_exp>::NC;
        const static long cost = matrix_traits<matrix_add_exp>::cost;
        typedef typename matrix_traits<matrix_add_exp>::layout_type layout_type;

        // This constructor exists simply for the purpose of causing a compile time error if
        // someone tries to create an instance of this object with the wrong kind of objects.
        template <typename T1, typename T2>
        matrix_add_exp (T1,T2);

        matrix_add_exp (
            const LHS& lhs_,
            const RHS& rhs_
        ) :
            lhs(lhs_),
            rhs(rhs_)
        {
            // You can only add matrices together if they both have the same number of rows and columns.
            COMPILE_TIME_ASSERT(LHS::NR == RHS::NR || LHS::NR == 0 || RHS::NR == 0);
            COMPILE_TIME_ASSERT(LHS::NC == RHS::NC || LHS::NC == 0 || RHS::NC == 0);
            DLIB_ASSERT(lhs.nc() == rhs.nc() &&
                   lhs.nr() == rhs.nr(),
                "\tconst matrix_exp operator+(const matrix_exp& lhs, const matrix_exp& rhs)"
                << "\n\tYou are trying to add two incompatible matrices together"
                << "\n\tlhs.nr(): " << lhs.nr()
                << "\n\tlhs.nc(): " << lhs.nc()
                << "\n\trhs.nr(): " << rhs.nr()
                << "\n\trhs.nc(): " << rhs.nc()
                << "\n\t&lhs: " << &lhs
                << "\n\t&rhs: " << &rhs
                );

            // You can only add matrices together if they both contain the same types of elements.
            COMPILE_TIME_ASSERT((is_same_type<typename LHS::type, typename RHS::type>::value == true));
        }

        const type operator() (
            long r,
            long c
        ) const { return lhs(r,c) + rhs(r,c); }

        inline const type operator() ( long i ) const
        { return matrix_exp<matrix_add_exp>::operator()(i); }

        template <typename U>
        bool aliases (
            const matrix_exp<U>& item
        ) const { return lhs.aliases(item) || rhs.aliases(item); }

        template <typename U>
        bool destructively_aliases (
            const matrix_exp<U>& item
        ) const { return lhs.destructively_aliases(item) || rhs.destructively_aliases(item); }

        long nr (
        ) const { return lhs.nr(); }

        long nc (
        ) const { return lhs.nc(); }

        const LHS& lhs;
        const RHS& rhs;
    };

    template <
        typename EXP1,
        typename EXP2
        >
    inline const matrix_add_exp<EXP1, EXP2> operator+ (
        const matrix_exp<EXP1>& m1,
        const matrix_exp<EXP2>& m2
    )
    {
        return matrix_add_exp<EXP1, EXP2>(m1.ref(),m2.ref());
    }

// ----------------------------------------------------------------------------------------

    template <typename LHS, typename RHS>
    class matrix_subtract_exp;

    template <typename LHS, typename RHS>
    struct matrix_traits<matrix_subtract_exp<LHS,RHS> >
    {
        typedef typename LHS::type type;
        typedef typename LHS::type const_ret_type;
        typedef typename LHS::mem_manager_type mem_manager_type;
        typedef typename LHS::layout_type layout_type;
        const static long NR = (RHS::NR > LHS::NR) ? RHS::NR : LHS::NR;
        const static long NC = (RHS::NC > LHS::NC) ? RHS::NC : LHS::NC;
        const static long cost = LHS::cost+RHS::cost+1;
    };

    template <
        typename LHS,
        typename RHS
        >
    class matrix_subtract_exp : public matrix_exp<matrix_subtract_exp<LHS,RHS> >
    {
        /*!
            REQUIREMENTS ON LHS AND RHS
                - must be matrix_exp objects.
        !*/
    public:
        typedef typename matrix_traits<matrix_subtract_exp>::type type;
        typedef typename matrix_traits<matrix_subtract_exp>::const_ret_type const_ret_type;
        typedef typename matrix_traits<matrix_subtract_exp>::mem_manager_type mem_manager_type;
        const static long NR = matrix_traits<matrix_subtract_exp>::NR;
        const static long NC = matrix_traits<matrix_subtract_exp>::NC;
        const static long cost = matrix_traits<matrix_subtract_exp>::cost;
        typedef typename matrix_traits<matrix_subtract_exp>::layout_type layout_type;

        // This constructor exists simply for the purpose of causing a compile time error if
        // someone tries to create an instance of this object with the wrong kind of objects.
        template <typename T1, typename T2>
        matrix_subtract_exp (T1,T2);

        matrix_subtract_exp (
            const LHS& lhs_,
            const RHS& rhs_
        ) :
            lhs(lhs_),
            rhs(rhs_)
        {
            // You can only subtract one matrix from another if they both have the same number of rows and columns.
            COMPILE_TIME_ASSERT(LHS::NR == RHS::NR || LHS::NR == 0 || RHS::NR == 0);
            COMPILE_TIME_ASSERT(LHS::NC == RHS::NC || LHS::NC == 0 || RHS::NC == 0);
            DLIB_ASSERT(lhs.nc() == rhs.nc() &&
                   lhs.nr() == rhs.nr(),
                "\tconst matrix_exp operator-(const matrix_exp& lhs, const matrix_exp& rhs)"
                << "\n\tYou are trying to subtract two incompatible matrices"
                << "\n\tlhs.nr(): " << lhs.nr()
                << "\n\tlhs.nc(): " << lhs.nc()
                << "\n\trhs.nr(): " << rhs.nr()
                << "\n\trhs.nc(): " << rhs.nc()
                << "\n\t&lhs: " << &lhs
                << "\n\t&rhs: " << &rhs
                );

            // You can only subtract one matrix from another if they both contain elements of the same type.
            COMPILE_TIME_ASSERT((is_same_type<typename LHS::type, typename RHS::type>::value == true));
        }

        const type operator() (
            long r,
            long c
        ) const { return lhs(r,c) - rhs(r,c); }

        inline const type operator() ( long i ) const
        { return matrix_exp<matrix_subtract_exp>::operator()(i); }

        template <typename U>
        bool aliases (
            const matrix_exp<U>& item
        ) const { return lhs.aliases(item) || rhs.aliases(item); }

        template <typename U>
        bool destructively_aliases (
            const matrix_exp<U>& item
        ) const { return lhs.destructively_aliases(item) || rhs.destructively_aliases(item); }

        long nr (
        ) const { return lhs.nr(); }

        long nc (
        ) const { return lhs.nc(); }

        const LHS& lhs;
        const RHS& rhs;
    };

    template <
        typename EXP1,
        typename EXP2
        >
    inline const matrix_subtract_exp<EXP1, EXP2> operator- (
        const matrix_exp<EXP1>& m1,
        const matrix_exp<EXP2>& m2
    )
    {
        return matrix_subtract_exp<EXP1, EXP2>(m1.ref(),m2.ref());
    }

// ----------------------------------------------------------------------------------------

    template <typename M>
    class matrix_div_scal_exp;

    template <typename M>
    struct matrix_traits<matrix_div_scal_exp<M> >
    {
        typedef typename M::type type;
        typedef typename M::type const_ret_type;
        typedef typename M::mem_manager_type mem_manager_type;
        typedef typename M::layout_type layout_type;
        const static long NR = M::NR;
        const static long NC = M::NC;
        const static long cost = M::cost+1;
    };

    template <
        typename M
        >
    class matrix_div_scal_exp : public matrix_exp<matrix_div_scal_exp<M> >
    {
        /*!
            REQUIREMENTS ON M
                - must be a matrix_exp object.
        !*/
    public:
        typedef typename matrix_traits<matrix_div_scal_exp>::type type;
        typedef typename matrix_traits<matrix_div_scal_exp>::const_ret_type const_ret_type;
        typedef typename matrix_traits<matrix_div_scal_exp>::mem_manager_type mem_manager_type;
        const static long NR = matrix_traits<matrix_div_scal_exp>::NR;
        const static long NC = matrix_traits<matrix_div_scal_exp>::NC;
        const static long cost = matrix_traits<matrix_div_scal_exp>::cost;
        typedef typename matrix_traits<matrix_div_scal_exp>::layout_type layout_type;

        // This constructor exists simply for the purpose of causing a compile time error if
        // someone tries to create an instance of this object with the wrong kind of objects.
        template <typename T1>
        matrix_div_scal_exp (T1, const type&);

        matrix_div_scal_exp (
            const M& m_,
            const type& s_
        ) :
            m(m_),
            s(s_)
        {}

        const type operator() (
            long r,
            long c
        ) const { return m(r,c)/s; }

        inline const type operator() ( long i ) const
        { return matrix_exp<matrix_div_scal_exp>::operator()(i); }

        template <typename U>
        bool aliases (
            const matrix_exp<U>& item
        ) const { return m.aliases(item); }

        template <typename U>
        bool destructively_aliases (
            const matrix_exp<U>& item
        ) const { return m.destructively_aliases(item); }

        long nr (
        ) const { return m.nr(); }

        long nc (
        ) const { return m.nc(); }

        const M& m;
        const type s;
    };

    template <
        typename EXP,
        typename S
        >
    inline const typename enable_if_c<std::numeric_limits<typename EXP::type>::is_integer, matrix_div_scal_exp<EXP> >::type operator/ (
        const matrix_exp<EXP>& m,
        const S& s
    )
    {
        return matrix_div_scal_exp<EXP>(m.ref(),static_cast<typename EXP::type>(s));
    }

// ----------------------------------------------------------------------------------------

    template <typename M, bool use_reference >
    struct matrix_traits<matrix_mul_scal_exp<M,use_reference> >
    {
        typedef typename M::type type;
        typedef typename M::type const_ret_type;
        typedef typename M::mem_manager_type mem_manager_type;
        typedef typename M::layout_type layout_type;
        const static long NR = M::NR;
        const static long NC = M::NC;
        const static long cost = M::cost+1;
    };

    template <typename T, bool is_ref> struct conditional_reference { typedef T type; };
    template <typename T> struct conditional_reference<T,true>      { typedef T& type; };

    template <
        typename M,
        bool use_reference
        >
    class matrix_mul_scal_exp : public matrix_exp<matrix_mul_scal_exp<M,use_reference> >
    {
        /*!
            REQUIREMENTS ON M
                - must be a matrix_exp object.

        !*/
    public:
        typedef typename matrix_traits<matrix_mul_scal_exp>::type type;
        typedef typename matrix_traits<matrix_mul_scal_exp>::const_ret_type const_ret_type;
        typedef typename matrix_traits<matrix_mul_scal_exp>::mem_manager_type mem_manager_type;
        const static long NR = matrix_traits<matrix_mul_scal_exp>::NR;
        const static long NC = matrix_traits<matrix_mul_scal_exp>::NC;
        const static long cost = matrix_traits<matrix_mul_scal_exp>::cost;
        typedef typename matrix_traits<matrix_mul_scal_exp>::layout_type layout_type;

        // You aren't allowed to multiply a matrix of matrices by a scalar.
        COMPILE_TIME_ASSERT(is_matrix<type>::value == false);

        // This constructor exists simply for the purpose of causing a compile time error if
        // someone tries to create an instance of this object with the wrong kind of objects.
        template <typename T1>
        matrix_mul_scal_exp (T1, const type&);

        matrix_mul_scal_exp (
            const M& m_,
            const type& s_
        ) :
            m(m_),
            s(s_)
        {}

        const type operator() (
            long r,
            long c
        ) const { return m(r,c)*s; }

        inline const type operator() ( long i ) const
        { return matrix_exp<matrix_mul_scal_exp>::operator()(i); }

        template <typename U>
        bool aliases (
            const matrix_exp<U>& item
        ) const { return m.aliases(item); }

        template <typename U>
        bool destructively_aliases (
            const matrix_exp<U>& item
        ) const { return m.destructively_aliases(item); }

        long nr (
        ) const { return m.nr(); }

        long nc (
        ) const { return m.nc(); }

        typedef typename conditional_reference<const M,use_reference>::type M_ref_type;

        M_ref_type m;
        const type s;
    };

    template <
        typename EXP,
        typename S
        >
    inline typename disable_if<is_matrix<S>, const matrix_mul_scal_exp<EXP> >::type operator* (
        const matrix_exp<EXP>& m,
        const S& s
    )
    {
        typedef typename EXP::type type;
        return matrix_mul_scal_exp<EXP>(m.ref(),static_cast<type>(s));
    }

    template <
        typename EXP,
        typename S,
        bool B
        >
    inline typename disable_if<is_matrix<S>, const matrix_mul_scal_exp<EXP> >::type operator* (
        const matrix_mul_scal_exp<EXP,B>& m,
        const S& s
    )
    {
        typedef typename EXP::type type;
        return matrix_mul_scal_exp<EXP>(m.m,static_cast<type>(s)*m.s);
    }

    template <
        typename EXP,
        typename S
        >
    inline typename disable_if<is_matrix<S>, const matrix_mul_scal_exp<EXP> >::type operator* (
        const S& s,
        const matrix_exp<EXP>& m
    )
    {
        typedef typename EXP::type type;
        return matrix_mul_scal_exp<EXP>(m.ref(),static_cast<type>(s));
    }

    template <
        typename EXP,
        typename S,
        bool B
        >
    inline typename disable_if<is_matrix<S>, const matrix_mul_scal_exp<EXP> >::type operator* (
        const S& s,
        const matrix_mul_scal_exp<EXP,B>& m
    )
    {
        typedef typename EXP::type type;
        return matrix_mul_scal_exp<EXP>(m.m,static_cast<type>(s)*m.s);
    }

    template <
        typename EXP ,
        typename S
        >
    inline const typename disable_if_c<std::numeric_limits<typename EXP::type>::is_integer, matrix_mul_scal_exp<EXP> >::type operator/ (
        const matrix_exp<EXP>& m,
        const S& s
    )
    {
        typedef typename EXP::type type;
        const type one = 1;
        return matrix_mul_scal_exp<EXP>(m.ref(),one/static_cast<type>(s));
    }

    template <
        typename EXP,
        bool B,
        typename S
        >
    inline const typename disable_if_c<std::numeric_limits<typename EXP::type>::is_integer, matrix_mul_scal_exp<EXP> >::type operator/ (
        const matrix_mul_scal_exp<EXP,B>& m,
        const S& s
    )
    {
        typedef typename EXP::type type;
        return matrix_mul_scal_exp<EXP>(m.m,m.s/static_cast<type>(s));
    }

// ----------------------------------------------------------------------------------------

    template <typename M>
    struct op_s_div_m : basic_op_m<M>
    {
        typedef typename M::type type;

        op_s_div_m( const M& m_, const type& s_) : basic_op_m<M>(m_), s(s_){}

        const type s;

        const static long cost = M::cost+1;
        typedef const typename M::type const_ret_type;
        const_ret_type apply (long r, long c) const
        {
            return s/this->m(r,c);
        }
    };

    template <
        typename EXP,
        typename S
        >
    const typename disable_if<is_matrix<S>, matrix_op<op_s_div_m<EXP> > >::type operator/ (
        const S& val,
        const matrix_exp<EXP>& m
    )
    {
        typedef typename EXP::type type;

        typedef op_s_div_m<EXP> op;
        return matrix_op<op>(op(m.ref(), static_cast<type>(val)));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP
        >
    inline const matrix_mul_scal_exp<EXP> operator- (
        const matrix_exp<EXP>& m
    )
    {
        return matrix_mul_scal_exp<EXP>(m.ref(),-1);
    }

    template <
        typename EXP,
        bool B
        >
    inline const matrix_mul_scal_exp<EXP> operator- (
        const matrix_mul_scal_exp<EXP,B>& m
    )
    {
        return matrix_mul_scal_exp<EXP>(m.m,-1*m.s);
    }

// ----------------------------------------------------------------------------------------

    template <typename M>
    struct op_add_scalar : basic_op_m<M>
    {
        typedef typename M::type type;

        op_add_scalar( const M& m_, const type& s_) : basic_op_m<M>(m_), s(s_){}

        const type s;

        const static long cost = M::cost+1;
        typedef const typename M::type const_ret_type;
        const_ret_type apply (long r, long c) const
        {
            return this->m(r,c) + s;
        }
    };

    template <
        typename EXP,
        typename T
        >
    const typename disable_if<is_matrix<T>, matrix_op<op_add_scalar<EXP> > >::type operator+ (
        const matrix_exp<EXP>& m,
        const T& val
    )
    {
        typedef typename EXP::type type;

        typedef op_add_scalar<EXP> op;
        return matrix_op<op>(op(m.ref(), static_cast<type>(val)));
    }

    template <
        typename EXP,
        typename T
        >
    const typename disable_if<is_matrix<T>, matrix_op<op_add_scalar<EXP> > >::type operator+ (
        const T& val,
        const matrix_exp<EXP>& m
    )
    {
        typedef typename EXP::type type;

        typedef op_add_scalar<EXP> op;
        return matrix_op<op>(op(m.ref(), static_cast<type>(val)));
    }

// ----------------------------------------------------------------------------------------

    template <typename M>
    struct op_subl_scalar : basic_op_m<M>
    {
        typedef typename M::type type;

        op_subl_scalar( const M& m_, const type& s_) : basic_op_m<M>(m_), s(s_){}

        const type s;

        const static long cost = M::cost+1;
        typedef const typename M::type const_ret_type;
        const_ret_type apply (long r, long c) const
        {
            return s - this->m(r,c) ;
        }
    };

    template <
        typename EXP,
        typename T
        >
    const typename disable_if<is_matrix<T>, matrix_op<op_subl_scalar<EXP> > >::type operator- (
        const T& val,
        const matrix_exp<EXP>& m
    )
    {
        typedef typename EXP::type type;

        typedef op_subl_scalar<EXP> op;
        return matrix_op<op>(op(m.ref(), static_cast<type>(val)));
    }

// ----------------------------------------------------------------------------------------

    template <typename M>
    struct op_subr_scalar : basic_op_m<M>
    {
        typedef typename M::type type;

        op_subr_scalar( const M& m_, const type& s_) : basic_op_m<M>(m_), s(s_){}

        const type s;

        const static long cost = M::cost+1;
        typedef const typename M::type const_ret_type;
        const_ret_type apply (long r, long c) const
        {
            return this->m(r,c) - s;
        }
    };

    template <
        typename EXP,
        typename T
        >
    const typename disable_if<is_matrix<T>, matrix_op<op_subr_scalar<EXP> > >::type operator- (
        const matrix_exp<EXP>& m,
        const T& val
    )
    {
        typedef typename EXP::type type;

        typedef op_subr_scalar<EXP> op;
        return matrix_op<op>(op(m.ref(), static_cast<type>(val)));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP1,
        typename EXP2
        >
    bool operator== (
        const matrix_exp<EXP1>& m1,
        const matrix_exp<EXP2>& m2
    )
    {
        if (m1.nr() == m2.nr() && m1.nc() == m2.nc())
        {
            for (long r = 0; r < m1.nr(); ++r)
            {
                for (long c = 0; c < m1.nc(); ++c)
                {
                    if (m1(r,c) != m2(r,c))
                        return false;
                }
            }
            return true;
        }
        return false;
    }

    template <
        typename EXP1,
        typename EXP2
        >
    inline bool operator!= (
        const matrix_exp<EXP1>& m1,
        const matrix_exp<EXP2>& m2
    ) { return !(m1 == m2); }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <typename T>
    struct op_pointer_to_mat;
    template <typename T>
    struct op_pointer_to_col_vect;

    template <
        typename T,
        long num_rows,
        long num_cols,
        typename mem_manager,
        typename layout
        >
    struct matrix_traits<matrix<T,num_rows, num_cols, mem_manager, layout> >
    {
        typedef T type;
        typedef const T& const_ret_type;
        typedef mem_manager mem_manager_type;
        typedef layout layout_type;
        const static long NR = num_rows;
        const static long NC = num_cols;
        const static long cost = 1;

    };

    template <
        typename T,
        long num_rows,
        long num_cols,
        typename mem_manager,
        typename layout
        >
    class matrix : public matrix_exp<matrix<T,num_rows,num_cols, mem_manager,layout> >
    {

        COMPILE_TIME_ASSERT(num_rows >= 0 && num_cols >= 0);

    public:
        typedef typename matrix_traits<matrix>::type type;
        typedef typename matrix_traits<matrix>::const_ret_type const_ret_type;
        typedef typename matrix_traits<matrix>::mem_manager_type mem_manager_type;
        typedef typename matrix_traits<matrix>::layout_type layout_type;
        const static long NR = matrix_traits<matrix>::NR;
        const static long NC = matrix_traits<matrix>::NC;
        const static long cost = matrix_traits<matrix>::cost;
        typedef T*          iterator;
        typedef const T*    const_iterator;

        matrix ()
        {
        }

        explicit matrix (
            long length
        )
        {
            // This object you are trying to call matrix(length) on is not a column or
            // row vector.
            COMPILE_TIME_ASSERT(NR == 1 || NC == 1);
            DLIB_ASSERT( length >= 0,
                "\tmatrix::matrix(length)"
                << "\n\tlength must be at least 0"
                << "\n\tlength: " << length
                << "\n\tNR:     " << NR
                << "\n\tNC:     " << NC
                << "\n\tthis:   " << this
                );

            if (NR == 1)
            {
                DLIB_ASSERT(NC == 0 || NC == length,
                    "\tmatrix::matrix(length)"
                    << "\n\tSince this is a statically sized matrix length must equal NC"
                    << "\n\tlength: " << length
                    << "\n\tNR:     " << NR
                    << "\n\tNC:     " << NC
                    << "\n\tthis:   " << this
                    );

                data.set_size(1,length);
            }
            else
            {
                DLIB_ASSERT(NR == 0 || NR == length,
                    "\tvoid matrix::set_size(length)"
                    << "\n\tSince this is a statically sized matrix length must equal NR"
                    << "\n\tlength: " << length
                    << "\n\tNR:     " << NR
                    << "\n\tNC:     " << NC
                    << "\n\tthis:   " << this
                    );

                data.set_size(length,1);
            }
        }

        matrix (
            long rows,
            long cols
        )
        {
            DLIB_ASSERT( (NR == 0 || NR == rows) && ( NC == 0 || NC == cols) &&
                    rows >= 0 && cols >= 0,
                "\tvoid matrix::matrix(rows, cols)"
                << "\n\tYou have supplied conflicting matrix dimensions"
                << "\n\trows: " << rows
                << "\n\tcols: " << cols
                << "\n\tNR:   " << NR
                << "\n\tNC:   " << NC
                );
            data.set_size(rows,cols);
        }

        template <typename EXP>
        matrix (
            const matrix_exp<EXP>& m
        )
        {
            // You get an error on this line if the matrix m contains a type that isn't
            // the same as the type contained in the target matrix.
            COMPILE_TIME_ASSERT((is_same_type<typename EXP::type,type>::value == true) ||
                                (is_matrix<typename EXP::type>::value == true));

            // The matrix you are trying to assign m to is a statically sized matrix and
            // m's dimensions don't match that of *this.
            COMPILE_TIME_ASSERT(EXP::NR == NR || NR == 0 || EXP::NR == 0);
            COMPILE_TIME_ASSERT(EXP::NC == NC || NC == 0 || EXP::NC == 0);
            DLIB_ASSERT((NR == 0 || NR == m.nr()) && (NC == 0 || NC == m.nc()),
                "\tmatrix& matrix::matrix(const matrix_exp& m)"
                << "\n\tYou are trying to assign a dynamically sized matrix to a statically sized matrix with the wrong size"
                << "\n\tNR:     " << NR
                << "\n\tNC:     " << NC
                << "\n\tm.nr(): " << m.nr()
                << "\n\tm.nc(): " << m.nc()
                << "\n\tthis:   " << this
                );

            data.set_size(m.nr(),m.nc());

            matrix_assign(*this, m);
        }

        matrix (
            const matrix& m
        ) : matrix_exp<matrix>(*this)
        {
            data.set_size(m.nr(),m.nc());
            matrix_assign(*this, m);
        }

        template <typename U, size_t len>
        explicit matrix (
            U (&array)[len]
        )
        {
            COMPILE_TIME_ASSERT(NR*NC == len && len > 0);
            size_t idx = 0;
            for (long r = 0; r < NR; ++r)
            {
                for (long c = 0; c < NC; ++c)
                {
                    data(r,c) = static_cast<T>(array[idx]);
                    ++idx;
                }
            }
        }

        T& operator() (
            long r,
            long c
        )
        {
            DLIB_ASSERT(r < nr() && c < nc() &&
                   r >= 0 && c >= 0,
                "\tT& matrix::operator(r,c)"
                << "\n\tYou must give a valid row and column"
                << "\n\tr:    " << r
                << "\n\tc:    " << c
                << "\n\tnr(): " << nr()
                << "\n\tnc(): " << nc()
                << "\n\tthis: " << this
                );
            return data(r,c);
        }

        const T& operator() (
            long r,
            long c
        ) const
        {
            DLIB_ASSERT(r < nr() && c < nc() &&
                   r >= 0 && c >= 0,
                "\tconst T& matrix::operator(r,c)"
                << "\n\tYou must give a valid row and column"
                << "\n\tr:    " << r
                << "\n\tc:    " << c
                << "\n\tnr(): " << nr()
                << "\n\tnc(): " << nc()
                << "\n\tthis: " << this
                );
            return data(r,c);
        }

        T& operator() (
            long i
        )
        {
            // You can only use this operator on column vectors.
            COMPILE_TIME_ASSERT(NC == 1 || NC == 0 || NR == 1 || NR == 0);
            DLIB_ASSERT(nc() == 1 || nr() == 1,
                "\tconst type matrix::operator(i)"
                << "\n\tYou can only use this operator on column or row vectors"
                << "\n\ti:    " << i
                << "\n\tnr(): " << nr()
                << "\n\tnc(): " << nc()
                << "\n\tthis: " << this
                );
            DLIB_ASSERT( 0 <= i && i < size(),
                "\tconst type matrix::operator(i)"
                << "\n\tYou must give a valid row/column number"
                << "\n\ti:      " << i
                << "\n\tsize(): " << size()
                << "\n\tthis:   " << this
                );
            return data(i);
        }

        const T& operator() (
            long i
        ) const
        {
            // You can only use this operator on column vectors.
            COMPILE_TIME_ASSERT(NC == 1 || NC == 0 || NR == 1 || NR == 0);
            DLIB_ASSERT(nc() == 1 || nr() == 1,
                "\tconst type matrix::operator(i)"
                << "\n\tYou can only use this operator on column or row vectors"
                << "\n\ti:    " << i
                << "\n\tnr(): " << nr()
                << "\n\tnc(): " << nc()
                << "\n\tthis: " << this
                );
            DLIB_ASSERT( 0 <= i && i < size(),
                "\tconst type matrix::operator(i)"
                << "\n\tYou must give a valid row/column number"
                << "\n\ti:      " << i
                << "\n\tsize(): " << size()
                << "\n\tthis:   " << this
                );
            return data(i);
        }

        inline operator const type (
        ) const
        {
            COMPILE_TIME_ASSERT(NC == 1 || NC == 0);
            COMPILE_TIME_ASSERT(NR == 1 || NR == 0);
            DLIB_ASSERT( nr() == 1 && nc() == 1 ,
                "\tmatrix::operator const type"
                << "\n\tYou can only attempt to implicit convert a matrix to a scalar if"
                << "\n\tthe matrix is a 1x1 matrix"
                << "\n\tnr(): " << nr()
                << "\n\tnc(): " << nc()
                << "\n\tthis: " << this
                );
            return data(0);
        }

        void set_size (
            long rows,
            long cols
        )
        {
            DLIB_ASSERT( (NR == 0 || NR == rows) && ( NC == 0 || NC == cols) &&
                    rows >= 0 && cols >= 0,
                "\tvoid matrix::set_size(rows, cols)"
                << "\n\tYou have supplied conflicting matrix dimensions"
                << "\n\trows: " << rows
                << "\n\tcols: " << cols
                << "\n\tNR:   " << NR
                << "\n\tNC:   " << NC
                << "\n\tthis: " << this
                );
            if (nr() != rows || nc() != cols)
                data.set_size(rows,cols);
        }

        void set_size (
            long length
        )
        {
            // This object you are trying to call set_size(length) on is not a column or
            // row vector.
            COMPILE_TIME_ASSERT(NR == 1 || NC == 1);
            DLIB_ASSERT( length >= 0,
                "\tvoid matrix::set_size(length)"
                << "\n\tlength must be at least 0"
                << "\n\tlength: " << length
                << "\n\tNR:     " << NR
                << "\n\tNC:     " << NC
                << "\n\tthis:   " << this
                );

            if (NR == 1)
            {
                DLIB_ASSERT(NC == 0 || NC == length,
                    "\tvoid matrix::set_size(length)"
                    << "\n\tSince this is a statically sized matrix length must equal NC"
                    << "\n\tlength: " << length
                    << "\n\tNR:     " << NR
                    << "\n\tNC:     " << NC
                    << "\n\tthis:   " << this
                    );

                if (nc() != length)
                    data.set_size(1,length);
            }
            else
            {
                DLIB_ASSERT(NR == 0 || NR == length,
                    "\tvoid matrix::set_size(length)"
                    << "\n\tSince this is a statically sized matrix length must equal NR"
                    << "\n\tlength: " << length
                    << "\n\tNR:     " << NR
                    << "\n\tNC:     " << NC
                    << "\n\tthis:   " << this
                    );

                if (nr() != length)
                    data.set_size(length,1);
            }
        }

        long nr (
        ) const { return data.nr(); }

        long nc (
        ) const { return data.nc(); }

        long size (
        ) const { return data.nr()*data.nc(); }

        template <typename U, size_t len>
        matrix& operator= (
            U (&array)[len]
        )
        {
            COMPILE_TIME_ASSERT(NR*NC == len && len > 0);
            size_t idx = 0;
            for (long r = 0; r < NR; ++r)
            {
                for (long c = 0; c < NC; ++c)
                {
                    data(r,c) = static_cast<T>(array[idx]);
                    ++idx;
                }
            }
            return *this;
        }

        template <typename EXP>
        matrix& operator= (
            const matrix_exp<EXP>& m
        )
        {
            // You get an error on this line if the matrix you are trying to
            // assign m to is a statically sized matrix and  m's dimensions don't
            // match that of *this.
            COMPILE_TIME_ASSERT(EXP::NR == NR || NR == 0 || EXP::NR == 0);
            COMPILE_TIME_ASSERT(EXP::NC == NC || NC == 0 || EXP::NC == 0);
            DLIB_ASSERT((NR == 0 || nr() == m.nr()) &&
                   (NC == 0 || nc() == m.nc()),
                "\tmatrix& matrix::operator=(const matrix_exp& m)"
                << "\n\tYou are trying to assign a dynamically sized matrix to a statically sized matrix with the wrong size"
                << "\n\tnr():   " << nr()
                << "\n\tnc():   " << nc()
                << "\n\tm.nr(): " << m.nr()
                << "\n\tm.nc(): " << m.nc()
                << "\n\tthis:   " << this
                );

            // You get an error on this line if the matrix m contains a type that isn't
            // the same as the type contained in the target matrix.
            COMPILE_TIME_ASSERT((is_same_type<typename EXP::type,type>::value == true) ||
                                (is_matrix<typename EXP::type>::value == true));
            if (m.destructively_aliases(*this) == false)
            {
                // This if statement is seemingly unnecessary since set_size() contains this
                // exact same if statement.  However, structuring the code this way causes
                // gcc to handle the way it inlines this function in a much more favorable way.
                if (data.nr() == m.nr() && data.nc() == m.nc())
                {
                    matrix_assign(*this, m);
                }
                else
                {
                    set_size(m.nr(),m.nc());
                    matrix_assign(*this, m);
                }
            }
            else
            {
                // we have to use a temporary matrix object here because
                // *this is aliased inside the matrix_exp m somewhere.
                matrix temp;
                temp.set_size(m.nr(),m.nc());
                matrix_assign(temp, m);
                temp.swap(*this);
            }
            return *this;
        }

        template <typename EXP>
        matrix& operator += (
            const matrix_exp<EXP>& m
        )
        {
            // The matrix you are trying to assign m to is a statically sized matrix and
            // m's dimensions don't match that of *this.
            COMPILE_TIME_ASSERT(EXP::NR == NR || NR == 0 || EXP::NR == 0);
            COMPILE_TIME_ASSERT(EXP::NC == NC || NC == 0 || EXP::NC == 0);
            COMPILE_TIME_ASSERT((is_same_type<typename EXP::type,type>::value == true));
            if (nr() == m.nr() && nc() == m.nc())
            {
                if (m.destructively_aliases(*this) == false)
                {
                    matrix_assign(*this, *this + m);
                }
                else
                {
                    // we have to use a temporary matrix object here because
                    // this->data is aliased inside the matrix_exp m somewhere.
                    matrix temp;
                    temp.set_size(m.nr(),m.nc());
                    matrix_assign(temp, *this + m);
                    temp.swap(*this);
                }
            }
            else
            {
                *this = m;
            }
            return *this;
        }

        template <typename EXP>
        matrix& operator -= (
            const matrix_exp<EXP>& m
        )
        {
            // The matrix you are trying to assign m to is a statically sized matrix and
            // m's dimensions don't match that of *this.
            COMPILE_TIME_ASSERT(EXP::NR == NR || NR == 0 || EXP::NR == 0);
            COMPILE_TIME_ASSERT(EXP::NC == NC || NC == 0 || EXP::NC == 0);
            COMPILE_TIME_ASSERT((is_same_type<typename EXP::type,type>::value == true));
            if (nr() == m.nr() && nc() == m.nc())
            {
                if (m.destructively_aliases(*this) == false)
                {
                    matrix_assign(*this, *this - m);
                }
                else
                {
                    // we have to use a temporary matrix object here because
                    // this->data is aliased inside the matrix_exp m somewhere.
                    matrix temp;
                    temp.set_size(m.nr(),m.nc());
                    matrix_assign(temp, *this - m);
                    temp.swap(*this);
                }
            }
            else
            {
                *this = -m;
            }
            return *this;
        }

        template <typename EXP>
        matrix& operator *= (
            const matrix_exp<EXP>& m
        )
        {
            *this = *this * m;
            return *this;
        }

        matrix& operator += (
            const matrix& m
        )
        {
            const long size = m.nr()*m.nc();
            if (nr() == m.nr() && nc() == m.nc())
            {
                for (long i = 0; i < size; ++i)
                    data(i) += m.data(i);
            }
            else
            {
                set_size(m.nr(), m.nc());
                for (long i = 0; i < size; ++i)
                    data(i) = m.data(i);
            }
            return *this;
        }

        matrix& operator -= (
            const matrix& m
        )
        {
            const long size = m.nr()*m.nc();
            if (nr() == m.nr() && nc() == m.nc())
            {
                for (long i = 0; i < size; ++i)
                    data(i) -= m.data(i);
            }
            else
            {
                set_size(m.nr(), m.nc());
                for (long i = 0; i < size; ++i)
                    data(i) = -m.data(i);
            }
            return *this;
        }

        matrix& operator += (
            const T val
        )
        {
            const long size = nr()*nc();
            for (long i = 0; i < size; ++i)
                data(i) += val;

            return *this;
        }

        matrix& operator -= (
            const T val
        )
        {
            const long size = nr()*nc();
            for (long i = 0; i < size; ++i)
                data(i) -= val;

            return *this;
        }

        matrix& operator *= (
            const T a
        )
        {
            *this = *this * a;
            return *this;
        }

        matrix& operator /= (
            const T a
        )
        {
            *this = *this / a;
            return *this;
        }

        matrix& operator= (
            const matrix& m
        )
        {
            if (this != &m)
            {
                set_size(m.nr(),m.nc());
                const long size = m.nr()*m.nc();
                for (long i = 0; i < size; ++i)
                    data(i) = m.data(i);
            }
            return *this;
        }

        void swap (
            matrix& item
        )
        {
            data.swap(item.data);
        }

        template <typename U>
        bool aliases (
            const matrix_exp<U>&
        ) const { return false; }

        bool aliases (
            const matrix_exp<matrix<T,num_rows,num_cols, mem_manager,layout> >& item
        ) const { return (this == &item); }

        template <typename U>
        bool destructively_aliases (
            const matrix_exp<U>&
        ) const { return false; }

        // These two aliases() routines are defined in matrix_mat.h
        bool aliases (
            const matrix_exp<matrix_op<op_pointer_to_mat<T> > >& item
        ) const;
        bool aliases (
            const matrix_exp<matrix_op<op_pointer_to_col_vect<T> > >& item
        ) const;

        iterator begin()
        {
            if (size() != 0)
                return &data(0,0);
            else
                return 0;
        }

        iterator end()
        {
            if (size() != 0)
                return &data(0,0)+size();
            else
                return 0;
        }

        const_iterator begin()  const
        {
            if (size() != 0)
                return &data(0,0);
            else
                return 0;
        }

        const_iterator end() const
        {
            if (size() != 0)
                return &data(0,0)+size();
            else
                return 0;
        }

    private:
        struct literal_assign_helper
        {
            /*
                This struct is a helper struct returned by the operator<<() function below.  It is
                used primarily to enable us to put DLIB_CASSERT statements on the usage of the
                operator<< form of matrix assignment.
            */

            literal_assign_helper(const literal_assign_helper& item) : m(item.m), r(item.r), c(item.c), has_been_used(false) {}
            explicit literal_assign_helper(matrix* m_): m(m_), r(0), c(0),has_been_used(false) {next();}
            ~literal_assign_helper() throw (std::exception)
            {
                DLIB_CASSERT(!has_been_used || r == m->nr(),
                             "You have used the matrix comma based assignment incorrectly by failing to\n"
                             "supply a full set of values for every element of a matrix object.\n");
            }

            const literal_assign_helper& operator, (
                const T& val
            ) const
            {
                DLIB_CASSERT(r < m->nr() && c < m->nc(),
                             "You have used the matrix comma based assignment incorrectly by attempting to\n" <<
                             "supply more values than there are elements in the matrix object being assigned to.\n\n" <<
                             "Did you forget to call set_size()?"
                             << "\n\t r: " << r
                             << "\n\t c: " << c
                             << "\n\t m->nr(): " << m->nr()
                             << "\n\t m->nc(): " << m->nc());
                (*m)(r,c) = val;
                next();
                has_been_used = true;
                return *this;
            }

        private:

            friend class matrix;

            void next (
            ) const
            {
                ++c;
                if (c == m->nc())
                {
                    c = 0;
                    ++r;
                }
            }

            matrix* m;
            mutable long r;
            mutable long c;
            mutable bool has_been_used;
        };

    public:

        matrix& operator = (
            const literal_assign_helper& val
        )
        {
            *this = *val.m;
            return *this;
        }

        const literal_assign_helper operator = (
            const T& val
        )
        {
            // assign the given value to every spot in this matrix
            for (long r = 0; r < nr(); ++r)
            {
                for (long c = 0; c < nc(); ++c)
                {
                    data(r,c) = val;
                }
            }

            // Now return the literal_assign_helper so that the user
            // can use the overloaded comma notation to initialize
            // the matrix if they want to.
            return literal_assign_helper(this);
        }

    private:

        typename layout::template layout<T,NR,NC,mem_manager> data;
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        long NR,
        long NC,
        typename mm,
        typename l
        >
    void swap(
        matrix<T,NR,NC,mm,l>& a,
        matrix<T,NR,NC,mm,l>& b
    ) { a.swap(b); }

    template <
        typename T,
        long NR,
        long NC,
        typename mm,
        typename l
        >
    void serialize (
        const matrix<T,NR,NC,mm,l>& item,
        std::ostream& out
    )
    {
        try
        {
            // The reason the serialization is a little funny is because we are trying to
            // maintain backwards compatibility with an older serialization format used by
            // dlib while also encoding things in a way that lets the array2d and matrix
            // objects have compatible serialization formats.
            serialize(-item.nr(),out);
            serialize(-item.nc(),out);
            for (long r = 0; r < item.nr(); ++r)
            {
                for (long c = 0; c < item.nc(); ++c)
                {
                    serialize(item(r,c),out);
                }
            }
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while serializing dlib::matrix");
        }
    }

    template <
        typename T,
        long NR,
        long NC,
        typename mm,
        typename l
        >
    void deserialize (
        matrix<T,NR,NC,mm,l>& item,
        std::istream& in
    )
    {
        try
        {
            long nr, nc;
            deserialize(nr,in);
            deserialize(nc,in);

            // this is the newer serialization format
            if (nr < 0 || nc < 0)
            {
                nr *= -1;
                nc *= -1;
            }

            if (NR != 0 && nr != NR)
                throw serialization_error("Error while deserializing a dlib::matrix.  Invalid rows");
            if (NC != 0 && nc != NC)
                throw serialization_error("Error while deserializing a dlib::matrix.  Invalid columns");

            item.set_size(nr,nc);
            for (long r = 0; r < nr; ++r)
            {
                for (long c = 0; c < nc; ++c)
                {
                    deserialize(item(r,c),in);
                }
            }
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while deserializing a dlib::matrix");
        }
    }

    template <
        typename EXP
        >
    std::ostream& operator<< (
        std::ostream& out,
        const matrix_exp<EXP>& m
    )
    {
        using namespace std;
        const streamsize old = out.width();

        // first figure out how wide we should make each field
        string::size_type w = 0;
        ostringstream sout;
        for (long r = 0; r < m.nr(); ++r)
        {
            for (long c = 0; c < m.nc(); ++c)
            {
                sout << m(r,c);
                w = std::max(sout.str().size(),w);
                sout.str("");
            }
        }

        // now actually print it
        for (long r = 0; r < m.nr(); ++r)
        {
            for (long c = 0; c < m.nc(); ++c)
            {
                out.width(static_cast<streamsize>(w));
                out << m(r,c) << " ";
            }
            out << "\n";
        }
        out.width(old);
        return out;
    }

    /*
    template <
        typename T,
        long NR,
        long NC,
        typename MM,
        typename L
        >
    std::istream& operator>> (
        std::istream& in,
        matrix<T,NR,NC,MM,L>& m
    );

    This function is defined inside the matrix_read_from_istream.h file.
    */

// ----------------------------------------------------------------------------------------

    class print_matrix_as_csv_helper
    {
        /*!
            This object is used to define an io manipulator for matrix expressions.
            In particular, this code allows you to write statements like:
                cout << csv << yourmatrix;
            and have it print the matrix with commas separating each element.
        !*/
    public:
        print_matrix_as_csv_helper (std::ostream& out_) : out(out_) {}

        template <typename EXP>
        std::ostream& operator<< (
            const matrix_exp<EXP>& m
        )
        {
            for (long r = 0; r < m.nr(); ++r)
            {
                for (long c = 0; c < m.nc(); ++c)
                {
                    if (c+1 == m.nc())
                        out << m(r,c) << "\n";
                    else
                        out << m(r,c) << ", ";
                }
            }
            return out;
        }

    private:
        std::ostream& out;
    };

    class print_matrix_as_csv {};
    const print_matrix_as_csv csv = print_matrix_as_csv();
    inline print_matrix_as_csv_helper operator<< (
        std::ostream& out,
        const print_matrix_as_csv&
    )
    {
        return print_matrix_as_csv_helper(out);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <typename EXP>
    class const_temp_matrix;

    template <
        typename EXP
        >
    struct matrix_traits<const_temp_matrix<EXP> >
    {
        typedef typename EXP::type type;
        typedef typename EXP::const_ret_type const_ret_type;
        typedef typename EXP::mem_manager_type mem_manager_type;
        typedef typename EXP::layout_type layout_type;
        const static long NR = EXP::NR;
        const static long NC = EXP::NC;
        const static long cost = 1;
    };

    template <typename EXP>
    class const_temp_matrix : public matrix_exp<const_temp_matrix<EXP> >, noncopyable
    {
    public:
        typedef typename matrix_traits<const_temp_matrix>::type type;
        typedef typename matrix_traits<const_temp_matrix>::const_ret_type const_ret_type;
        typedef typename matrix_traits<const_temp_matrix>::mem_manager_type mem_manager_type;
        typedef typename matrix_traits<const_temp_matrix>::layout_type layout_type;
        const static long NR = matrix_traits<const_temp_matrix>::NR;
        const static long NC = matrix_traits<const_temp_matrix>::NC;
        const static long cost = matrix_traits<const_temp_matrix>::cost;

        const_temp_matrix (
            const matrix_exp<EXP>& item
        ) :
            ref_(item.ref())
        {}
        const_temp_matrix (
            const EXP& item
        ) :
            ref_(item)
        {}

        const_ret_type operator() (
            long r,
            long c
        ) const { return ref_(r,c); }

        const_ret_type operator() ( long i ) const
        { return ref_(i); }

        template <typename U>
        bool aliases (
            const matrix_exp<U>& item
        ) const { return ref_.aliases(item); }

        template <typename U>
        bool destructively_aliases (
            const matrix_exp<U>& item
        ) const { return ref_.destructively_aliases(item); }

        long nr (
        ) const { return ref_.nr(); }

        long nc (
        ) const { return ref_.nc(); }

    private:

        typename conditional_matrix_temp<const EXP, (EXP::cost <= 1)>::type ref_;
    };

// ----------------------------------------------------------------------------------------

}

#ifdef _MSC_VER
// put that warning back to its default setting
#pragma warning(default : 4355)
#endif

#endif // DLIB_MATRIx_


dlib C++ Library - matrix_assign.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MATRIx_ASSIGn_
#define DLIB_MATRIx_ASSIGn_

#include "matrix.h"
#include "matrix_utilities.h"
#include "matrix_subexp.h"
#include "../enable_if.h"
#include "matrix_assign_fwd.h"
#include "matrix_default_mul.h"
#include "matrix_conj_trans.h"
#include "matrix_mat.h"

namespace dlib
{
    /*
        This file contains some templates that are used inside the matrix_blas_bindings.h
        file to bind various matrix expressions to optimized code for carrying them out.
    */

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    namespace blas_bindings
    {

    // ------------------------------------------------------------------------------------

        template <typename T>
        void zero_matrix (
            T& m
        )
        {
            for (long r = 0; r < m.nr(); ++r)
            {
                for (long c = 0; c < m.nc(); ++c)
                {
                    m(r,c) = 0;
                }
            }
        }

    // ------------------------------------------------------------------------------------

    // This template struct is used to tell us if a matrix expression contains a matrix multiply.
        template <typename T>
        struct has_matrix_multiply
        {
            const static bool value = false;
        };

        template <typename T, typename U>
        struct has_matrix_multiply<matrix_multiply_exp<T,U> >
        { const static bool value = true; };

        template <typename T, typename U>
        struct has_matrix_multiply<matrix_add_exp<T,U> >
        { const static bool value = has_matrix_multiply<T>::value || has_matrix_multiply<U>::value; };

        template <typename T, typename U>
        struct has_matrix_multiply<matrix_subtract_exp<T,U> >
        { const static bool value = has_matrix_multiply<T>::value || has_matrix_multiply<U>::value; };

        template <typename T, bool Tb>
        struct has_matrix_multiply<matrix_mul_scal_exp<T,Tb> >
        { const static bool value = true; };

        template <typename T>
        struct has_matrix_multiply<matrix_div_scal_exp<T> >
        { const static bool value = has_matrix_multiply<T>::value; };

        template <typename T>
        struct has_matrix_multiply<matrix_op<T> >
        { const static bool value = has_matrix_multiply<T>::value; };

        template <typename T>
        struct has_matrix_multiply<op_trans<T> >
        { const static bool value = has_matrix_multiply<T>::value; };

        template <typename T>
        struct has_matrix_multiply<op_conj_trans<T> >
        { const static bool value = has_matrix_multiply<T>::value; };

        template <typename T>
        struct has_matrix_multiply<op_conj<T> >
        { const static bool value = has_matrix_multiply<T>::value; };

    // ------------------------------------------------------------------------------------
    // ------------------------------------------------------------------------------------
    // ------------------------------------------------------------------------------------

        const int unknown_matrix = 0;
        const int general_matrix = 1;
        const int row_matrix = 2;
        const int column_matrix = 3;

    // ------------------------------------------------------------------------------------

        template <typename T>
        struct matrix_type_id
        {
            const static int value = unknown_matrix;
        };

        template <typename T, long NR, long NC, typename MM, typename L>
        struct matrix_type_id<matrix<T,NR,NC,MM,L> >
        {
            const static int value = general_matrix;
        };

        template <typename T, long NR, typename MM, typename L>
        struct matrix_type_id<matrix<T,NR,1,MM,L> >
        {
            const static int value = column_matrix;
        };

        template <typename T, typename MM, typename L>
        struct matrix_type_id<matrix<T,1,1,MM,L> >
        {
            const static int value = column_matrix;
        };

        template <typename T, long NC, typename MM, typename L>
        struct matrix_type_id<matrix<T,1,NC,MM,L> >
        {
            const static int value = row_matrix;
        };

    // ------------------------------------------------------------------------------------

        template <typename T, long NR, long NC, typename MM, typename L>
        struct matrix_type_id<matrix_op<op_colm<matrix<T,NR,NC,MM,L> > > >
        {
            const static int value = column_matrix;
        };

        template <typename T, long NR, long NC, typename MM, typename L>
        struct matrix_type_id<matrix_op<op_rowm<matrix<T,NR,NC,MM,L> > > >
        {
            const static int value = row_matrix;
        };

        template <typename T, long NR, long NC, typename MM, typename L>
        struct matrix_type_id<matrix_op<op_colm2<matrix<T,NR,NC,MM,L> > > >
        {
            const static int value = column_matrix;
        };

        template <typename T, long NR, long NC, typename MM, typename L>
        struct matrix_type_id<matrix_op<op_rowm2<matrix<T,NR,NC,MM,L> > > >
        {
            const static int value = row_matrix;
        };

        template <typename T, long NR, long NC, typename MM, typename L>
        struct matrix_type_id<matrix_op<op_subm<matrix<T,NR,NC,MM,L> > > >
        {
            const static int value = general_matrix;
        };

        template < typename T, typename MM >
        struct matrix_type_id<matrix_op<op_array2d_to_mat<array2d<T,MM> > > >
        { const static int value = general_matrix; };

        template < typename T, typename MM >
        struct matrix_type_id<matrix_op<op_array_to_mat<array<T,MM> > > >
        { const static int value = column_matrix; };

        template < typename value_type, typename alloc >
        struct matrix_type_id<matrix_op<op_std_vect_to_mat<std::vector<value_type,alloc> > > >
        { const static int value = column_matrix; };

        template < typename value_type, typename alloc >
        struct matrix_type_id<matrix_op<op_std_vect_to_mat<std_vector_c<value_type,alloc> > > >
        { const static int value = column_matrix; };

        template < typename T >
        struct matrix_type_id<matrix_op<op_pointer_to_col_vect<T> > >
        { const static int value = column_matrix; };
        template < typename T >
        struct matrix_type_id<matrix_op<op_pointer_to_mat<T> > >
        { const static int value = general_matrix; };

    // ------------------------------------------------------------------------------------

        template <typename T, typename U>
        struct same_matrix
        {
            const static int T_id = matrix_type_id<T>::value;
            const static int U_id = matrix_type_id<U>::value;
            // The check for unknown_matrix is here so that we can be sure that matrix types
            // other than the ones specifically enumerated above never get pushed into
            // any of the BLAS bindings.  So saying they are never the same as anything
            // else prevents them from matching any of the BLAS bindings.
            const static bool value = (T_id == U_id) && (T_id != unknown_matrix);
        };

    // ------------------------------------------------------------------------------------
    // ------------------------------------------------------------------------------------
    // ------------------------------------------------------------------------------------

    // This template struct is used to tell us if two matrix expressions both contain the same
    // sequence of operators, expressions.    It also only has a value of true if the T expression
    // contains only matrices with the given layout.
        template <typename T, typename U, typename layout>
        struct same_exp
        {
            const static bool value = (is_same_type<typename T::exp_type, typename U::exp_type>::value ||
                                       same_matrix<typename T::exp_type, typename U::exp_type>::value) &&
                                is_same_type<typename T::layout_type,layout>::value;

        };

        // Used only below.  They help strip off the const and & qualifiers that can show up
        // in the LHS_ref_type and RHS_ref_type typedefs.
        template <typename T> struct noref{ typedef T type;};
        template <typename T> struct noref<T&>{ typedef T type;};
        template <typename T> struct noref<const T&>{ typedef T type;};
        template <typename T> struct noref<const T>{ typedef T type;};

        template <typename Tlhs, typename Ulhs, typename Trhs, typename Urhs, typename layout>
        struct same_exp<matrix_multiply_exp<Tlhs,Trhs>, matrix_multiply_exp<Ulhs,Urhs>,layout >
        {
            // The reason this case is more complex than the others is because the matrix_multiply_exp
            // will use a temporary matrix instead of Tlhs or Trhs in the event that one of these
            // types corresponds to an expensive expression.  So we have to use the type that really
            // gets used.  The following typedefs are here to pick out that true type.
            typedef typename matrix_multiply_exp<Tlhs,Trhs>::LHS_ref_type T_LHS_ref_type;
            typedef typename matrix_multiply_exp<Tlhs,Trhs>::RHS_ref_type T_RHS_ref_type;
            typedef typename noref<T_LHS_ref_type>::type T_lhs_type;
            typedef typename noref<T_RHS_ref_type>::type T_rhs_type;

            typedef typename matrix_multiply_exp<Ulhs,Urhs>::LHS_ref_type U_LHS_ref_type;
            typedef typename matrix_multiply_exp<Ulhs,Urhs>::RHS_ref_type U_RHS_ref_type;
            typedef typename noref<U_LHS_ref_type>::type U_lhs_type;
            typedef typename noref<U_RHS_ref_type>::type U_rhs_type;

            const static bool value = same_exp<T_lhs_type,U_lhs_type,layout>::value &&
                                      same_exp<T_rhs_type,U_rhs_type,layout>::value;
        };

        template <typename Tlhs, typename Ulhs, typename Trhs, typename Urhs, typename layout>
        struct same_exp<matrix_add_exp<Tlhs,Trhs>, matrix_add_exp<Ulhs,Urhs>, layout >
        { const static bool value = same_exp<Tlhs,Ulhs,layout>::value && same_exp<Trhs,Urhs,layout>::value; };

        template <typename Tlhs, typename Ulhs, typename Trhs, typename Urhs, typename layout>
        struct same_exp<matrix_subtract_exp<Tlhs,Trhs>, matrix_subtract_exp<Ulhs,Urhs>, layout >
        { const static bool value = same_exp<Tlhs,Ulhs,layout>::value && same_exp<Trhs,Urhs,layout>::value; };

        template <typename T, typename U, bool Tb, bool Ub, typename layout>
        struct same_exp<matrix_mul_scal_exp<T,Tb>, matrix_mul_scal_exp<U,Ub>, layout >
        { const static bool value = same_exp<T,U,layout>::value; };

        template <typename T, typename U, typename layout>
        struct same_exp<matrix_div_scal_exp<T>, matrix_div_scal_exp<U>, layout >
        { const static bool value = same_exp<T,U,layout>::value; };

        template <typename T, typename U, typename layout>
        struct same_exp<matrix_op<op_trans<T> >, matrix_op<op_trans<U> >, layout >
        { const static bool value = same_exp<T,U,layout>::value; };

        template <typename T, typename U, typename layout>
        struct same_exp<matrix_op<op_conj<T> >, matrix_op<op_conj<U> >, layout >
        { const static bool value = same_exp<T,U,layout>::value; };

        template <typename T, typename U, typename layout>
        struct same_exp<matrix_op<op_conj_trans<T> >, matrix_op<op_conj_trans<U> >, layout >
        { const static bool value = same_exp<T,U,layout>::value; };

    // ------------------------------------------------------------------------------------

        struct yes_type
        {
            char ch;
        };
        struct no_type
        {
            yes_type a, b;
        };

        // This is a helper that is used below to apply the same_exp template to matrix expressions.
        template <typename T, typename layout, typename U>
        typename enable_if<same_exp<T,U,layout>,yes_type>::type test(U);
        template <typename T, typename layout, typename U>
        typename disable_if<same_exp<T,U,layout>,no_type>::type test(U);

    // ------------------------------------------------------------------------------------

        template <
            typename dest_exp,
            typename src_exp,
            typename enabled = void
            >
        struct matrix_assign_blas_helper
        {
            // We are in the default version of the blas helper so this
            // means there wasn't any more specific overload.  So just
            // let the default matrix assignment happen.
            template <typename EXP>
            static void assign (
                dest_exp& dest,
                const EXP& src,
                typename src_exp::type alpha,
                bool add_to,
                bool transpose
            )
            {
                if (transpose == false)
                    matrix_assign_default(dest,src,alpha,add_to);
                else
                    matrix_assign_default(dest,trans(src),alpha,add_to);
            }

            // If we know this is a matrix multiply then apply the
            // default dlib matrix multiply to speed things up a bit more
            // than the above default function would.
            template <typename EXP1, typename EXP2>
            static void assign (
                dest_exp& dest,
                const matrix_multiply_exp<EXP1,EXP2>& src,
                typename src_exp::type alpha,
                bool add_to,
                bool transpose
            )
            {
                // At some point I need to improve the default (i.e. non BLAS) matrix
                // multiplication algorithm...

                if (alpha == static_cast<typename src_exp::type>(1))
                {
                    if (add_to == false)
                    {
                        zero_matrix(dest);
                    }

                    if (transpose == false)
                        default_matrix_multiply(dest, src.lhs, src.rhs);
                    else
                        default_matrix_multiply(dest, trans(src.rhs), trans(src.lhs));
                }
                else
                {
                    if (add_to)
                    {
                        typename dest_exp::matrix_type temp(dest.nr(),dest.nc());
                        zero_matrix(temp);

                        if (transpose == false)
                            default_matrix_multiply(temp, src.lhs, src.rhs);
                        else
                            default_matrix_multiply(temp, trans(src.rhs), trans(src.lhs));

                        matrix_assign_default(dest,temp, alpha,true);
                    }
                    else
                    {
                        zero_matrix(dest);

                        if (transpose == false)
                            default_matrix_multiply(dest, src.lhs, src.rhs);
                        else
                            default_matrix_multiply(dest, trans(src.rhs), trans(src.lhs));

                        matrix_assign_default(dest,dest, alpha, false);
                    }
                }
            }
        };

        // This is a macro to help us add overloads for the matrix_assign_blas_helper template.
        // Using this macro it is easy to add overloads for arbitrary matrix expressions.
#define DLIB_ADD_BLAS_BINDING(src_expression)                                               \
    template <typename T, typename L> struct BOOST_JOIN(blas,__LINE__)                      \
    { const static bool value = sizeof(yes_type) == sizeof(test<T,L>(src_expression)); };   \
                                                                                \
    template < typename dest_exp, typename src_exp >                                       \
    struct matrix_assign_blas_helper<dest_exp, src_exp,                                    \
    typename enable_if<BOOST_JOIN(blas,__LINE__)<src_exp,typename dest_exp::layout_type> >::type > {   \
        static void assign (                                                                \
            dest_exp& dest,                                                                \
            const src_exp& src,                                                             \
            typename src_exp::type alpha,                                                   \
            bool add_to,                                                                    \
            bool DLIB_NO_WARN_UNUSED transpose                      \
        ) {                                                                                 \
            DLIB_NO_WARN_UNUSED typedef typename dest_exp::type T;

#define DLIB_END_BLAS_BINDING }};

    // ------------------------------------------------------------------------------------
    // ------------------------------------------------------------------------------------
    // ------------------------------------------------------------------------------------

    // ------------------- Forward Declarations -------------------

        template <
            typename dest_exp,
            typename src_exp
            >
        void matrix_assign_blas_proxy (
            dest_exp& dest,
            const src_exp& src,
            typename src_exp::type alpha,
            bool add_to,
            bool transpose
        );
        /*!
            requires
                - src.aliases(dest) == false
                - dest.nr() == src.nr()
                - dest.nc() == src.nc()
        !*/

        template <
            typename dest_exp,
            typename src_exp, typename src_exp2
            >
        void matrix_assign_blas_proxy (
            dest_exp& dest,
            const matrix_add_exp<src_exp, src_exp2>& src,
            typename src_exp::type alpha,
            bool add_to,
            bool transpose
        );
        /*!
            requires
                - src.aliases(dest) == false
                - dest.nr() == src.nr()
                - dest.nc() == src.nc()
        !*/

        template <
            typename dest_exp,
            typename src_exp, bool Sb
            >
        void matrix_assign_blas_proxy (
            dest_exp& dest,
            const matrix_mul_scal_exp<src_exp,Sb>& src,
            typename src_exp::type alpha,
            bool add_to,
            bool transpose
        );
        /*!
            requires
                - src.aliases(dest) == false
                - dest.nr() == src.nr()
                - dest.nc() == src.nc()
        !*/

        template <
            typename dest_exp,
            typename src_exp
            >
        void matrix_assign_blas_proxy (
            dest_exp& dest,
            const matrix_op<op_trans<src_exp> >& src,
            typename src_exp::type alpha,
            bool add_to,
            bool transpose
        );
        /*!
            requires
                - src.aliases(dest) == false
                - dest.nr() == src.nr()
                - dest.nc() == src.nc()
        !*/

        template <
            typename dest_exp,
            typename src_exp, typename src_exp2
            >
        void matrix_assign_blas_proxy (
            dest_exp& dest,
            const matrix_subtract_exp<src_exp, src_exp2>& src,
            typename src_exp::type alpha,
            bool add_to,
            bool transpose
        );
        /*!
            requires
                - src.aliases(dest) == false
                - dest.nr() == src.nr()
                - dest.nc() == src.nc()
        !*/

    // ------------------------------------------------------------------------------------

        template <
            typename T, long NR, long NC, typename MM, typename L,
            typename src_exp
            >
        void matrix_assign_blas (
            matrix<T,NR,NC,MM,L>& dest,
            const src_exp& src
        );

        template <
            typename T, long NR, long NC, typename MM, typename L,
            typename src_exp
            >
        void matrix_assign_blas (
            matrix<T,NR,NC,MM,L>& dest,
            const matrix_add_exp<matrix<T,NR,NC,MM,L> ,src_exp>& src
        );
        /*!
            This function catches the expressions of the form:
                M = M + exp;
            and converts them into the appropriate matrix_assign_blas() call.
            This is an important case to catch because it is the expression used
            to represent the += matrix operator.
        !*/

        template <
            typename T, long NR, long NC, typename MM, typename L,
            typename src_exp
            >
        void matrix_assign_blas (
            matrix<T,NR,NC,MM,L>& dest,
            const matrix_add_exp<src_exp, matrix<T,NR,NC,MM,L> >& src
        );
        /*!
            This function catches the expressions of the form:
                M = exp + M;
            and converts them into the appropriate matrix_assign_blas() call.
            This is an important case to catch because it is the expression used
            to represent the += matrix operator.
        !*/

        template <
            typename T, long NR, long NC, typename MM, typename L,
            typename src_exp
            >
        void matrix_assign_blas (
            matrix<T,NR,NC,MM,L>& dest,
            const matrix_subtract_exp<matrix<T,NR,NC,MM,L> ,src_exp>& src
        );
        /*!
            This function catches the expressions of the form:
                M = M - exp;
            and converts them into the appropriate matrix_assign_blas() call.
            This is an important case to catch because it is the expression used
            to represent the -= matrix operator.
        !*/

        //   End of forward declarations for overloaded matrix_assign_blas functions

    // ------------------------------------------------------------------------------------
    // ------------------------------------------------------------------------------------
    // ------------------------------------------------------------------------------------

        template <
            typename dest_exp,
            typename src_exp
            >
        void matrix_assign_blas_proxy (
            dest_exp& dest,
            const src_exp& src,
            typename src_exp::type alpha,
            bool add_to,
            bool transpose
        )
        {
            matrix_assign_blas_helper<dest_exp,src_exp>::assign(dest,src,alpha,add_to, transpose);
        }

    // ------------------------------------------------------------------------------------

        template <
            typename dest_exp,
            typename src_exp, typename src_exp2
            >
        void matrix_assign_blas_proxy (
            dest_exp& dest,
            const matrix_add_exp<src_exp, src_exp2>& src,
            typename src_exp::type alpha,
            bool add_to,
            bool transpose
        )
        {
            if (has_matrix_multiply<src_exp>::value || has_matrix_multiply<src_exp2>::value)
            {
                matrix_assign_blas_proxy(dest, src.lhs, alpha, add_to, transpose);
                matrix_assign_blas_proxy(dest, src.rhs, alpha, true, transpose);
            }
            else
            {
                if (transpose == false)
                    matrix_assign_default(dest, src, alpha, add_to);
                else
                    matrix_assign_default(dest, trans(src), alpha, add_to);
            }
        }

    // ------------------------------------------------------------------------------------

        template <
            typename dest_exp,
            typename src_exp, bool Sb
            >
        void matrix_assign_blas_proxy (
            dest_exp& dest,
            const matrix_mul_scal_exp<src_exp,Sb>& src,
            typename src_exp::type alpha,
            bool add_to,
            bool transpose
        )
        {
            matrix_assign_blas_proxy(dest, src.m, alpha*src.s, add_to, transpose);
        }

    // ------------------------------------------------------------------------------------

        template <
            typename dest_exp,
            typename src_exp
            >
        void matrix_assign_blas_proxy (
            dest_exp& dest,
            const matrix_op<op_trans<src_exp> >& src,
            typename src_exp::type alpha,
            bool add_to,
            bool transpose
        )
        {
            matrix_assign_blas_proxy(dest, src.op.m, alpha, add_to, !transpose);
        }

    // ------------------------------------------------------------------------------------

        template <
            typename dest_exp,
            typename src_exp, typename src_exp2
            >
        void matrix_assign_blas_proxy (
            dest_exp& dest,
            const matrix_subtract_exp<src_exp, src_exp2>& src,
            typename src_exp::type alpha,
            bool add_to,
            bool transpose
        )
        {

            if (has_matrix_multiply<src_exp>::value || has_matrix_multiply<src_exp2>::value)
            {
                matrix_assign_blas_proxy(dest, src.lhs, alpha, add_to, transpose);
                matrix_assign_blas_proxy(dest, src.rhs, -alpha, true, transpose);
            }
            else
            {
                if (transpose == false)
                    matrix_assign_default(dest, src, alpha, add_to);
                else
                    matrix_assign_default(dest, trans(src), alpha, add_to);
            }
        }

    // ------------------------------------------------------------------------------------
    // ------------------------------------------------------------------------------------

    // Once we get into this function it means that we are dealing with a matrix of float,
    // double, complex<float>, or complex<double> and the src_exp contains at least one
    // matrix multiply.

        template <
            typename T, long NR, long NC, typename MM, typename L,
            long NR2, long NC2, bool Sb
            >
        void matrix_assign_blas (
            matrix<T,NR,NC,MM,L>& dest,
            const matrix_mul_scal_exp<matrix<T,NR2,NC2,MM,L>,Sb>& src
        )
        {
            // It's ok that we don't check for aliasing in this case because there isn't
            // any complex unrolling of successive + or - operators in this expression.
            matrix_assign_blas_proxy(dest,src.m,src.s,false, false);
        }

    // ------------------------------------------------------------------------------------

        template <
            typename T, long NR, long NC, typename MM, typename L,
            typename src_exp
            >
        void matrix_assign_blas (
            matrix<T,NR,NC,MM,L>& dest,
            const src_exp& src
        )
        {
            if (src.aliases(dest))
            {
                matrix<T,NR,NC,MM,L> temp(dest.nr(),dest.nc());
                matrix_assign_blas_proxy(temp,src,1,false, false);
                temp.swap(dest);
            }
            else
            {
                matrix_assign_blas_proxy(dest,src,1,false, false);
            }
        }

    // ------------------------------------------------------------------------------------

        template <
            typename T, long NR, long NC, typename MM, typename L,
            typename src_exp
            >
        void matrix_assign_blas (
            assignable_sub_matrix<T,NR,NC,MM,L>& dest,
            const src_exp& src
        )
        {
            if (src.aliases(dest.m))
            {
                matrix<T,NR,NC,MM,L> temp(dest.nr(),dest.nc());
                matrix_assign_blas_proxy(temp,src,1,false, false);
                matrix_assign_default(dest,temp);
            }
            else
            {
                matrix_assign_blas_proxy(dest,src,1,false, false);
            }
        }

    // ------------------------------------------------------------------------------------

        template <
            typename T,
            typename src_exp
            >
        void matrix_assign_blas (
            assignable_ptr_matrix<T>& dest,
            const src_exp& src
        )
        {
            if (src.aliases(mat(dest.ptr,dest.height,dest.width)))
            {
                matrix<T> temp(dest.nr(),dest.nc());
                matrix_assign_blas_proxy(temp,src,1,false, false);
                matrix_assign_default(dest,temp);
            }
            else
            {
                matrix_assign_blas_proxy(dest,src,1,false, false);
            }
        }

    // ------------------------------------------------------------------------------------

        template <
            typename T, long NR, long NC, typename MM, typename L,
            typename src_exp
            >
        void matrix_assign_blas (
            assignable_row_matrix<T,NR,NC,MM,L>& dest,
            const src_exp& src
        )
        {
            if (src.aliases(dest.m))
            {
                matrix<T,NR,NC,MM,L> temp(dest.nr(),dest.nc());
                matrix_assign_blas_proxy(temp,src,1,false, false);
                matrix_assign_default(dest,temp);
            }
            else
            {
                matrix_assign_blas_proxy(dest,src,1,false, false);
            }
        }

    // ------------------------------------------------------------------------------------

        template <
            typename T, long NR, long NC, typename MM, typename L,
            typename src_exp
            >
        void matrix_assign_blas (
            assignable_col_matrix<T,NR,NC,MM,L>& dest,
            const src_exp& src
        )
        {
            if (src.aliases(dest.m))
            {
                matrix<T,NR,NC,MM,L> temp(dest.nr(),dest.nc());
                matrix_assign_blas_proxy(temp,src,1,false, false);
                matrix_assign_default(dest,temp);
            }
            else
            {
                matrix_assign_blas_proxy(dest,src,1,false, false);
            }
        }

    // ------------------------------------------------------------------------------------

        template <
            typename T, long NR, long NC, typename MM, typename L,
            typename src_exp
            >
        void matrix_assign_blas (
            matrix<T,NR,NC,MM,L>& dest,
            const matrix_add_exp<matrix<T,NR,NC,MM,L> ,src_exp>& src
        )
        {
            if (src.rhs.aliases(dest) == false)
            {
                if (&src.lhs != &dest)
                {
                    dest = src.lhs;
                }

                matrix_assign_blas_proxy(dest, src.rhs, 1, true, false);
            }
            else
            {
                matrix<T,NR,NC,MM,L> temp(src.lhs);
                matrix_assign_blas_proxy(temp, src.rhs, 1, true, false);
                temp.swap(dest);
            }
        }

    // ------------------------------------------------------------------------------------

        template <
            typename T, long NR, long NC, typename MM, typename L,
            typename src_exp
            >
        void matrix_assign_blas (
            matrix<T,NR,NC,MM,L>& dest,
            const matrix_add_exp<src_exp, matrix<T,NR,NC,MM,L> >& src
        )
        {
            // Just switch around the left and right hand sides of the incoming
            // add expression and pass it back into matrix_assign_blas() so that
            // the above function will be called.
            typedef matrix_add_exp<matrix<T,NR,NC,MM,L> ,src_exp> swapped_add_exp;
            matrix_assign_blas(dest, swapped_add_exp(src.rhs, src.lhs));
        }

    // ------------------------------------------------------------------------------------

        template <
            typename T, long NR, long NC, typename MM, typename L,
            typename src_exp
            >
        void matrix_assign_blas (
            matrix<T,NR,NC,MM,L>& dest,
            const matrix_subtract_exp<matrix<T,NR,NC,MM,L> ,src_exp>& src
        )
        {
            if (src.rhs.aliases(dest) == false)
            {
                if (&src.lhs != &dest)
                {
                    dest = src.lhs;
                }

                matrix_assign_blas_proxy(dest, src.rhs, -1, true, false);
            }
            else
            {
                matrix<T,NR,NC,MM,L> temp(src.lhs);
                matrix_assign_blas_proxy(temp, src.rhs, -1, true, false);
                temp.swap(dest);
            }
        }

    // ------------------------------------------------------------------------------------
    // ------------------------------------------------------------------------------------
    // ------------------------------------------------------------------------------------

    } // end of namespace blas_bindings

    // ------------------------------------------------------------------------------------

    template <
        typename T, long NR, long NC, typename MM, typename L,
        typename src_exp
        >
    inline typename enable_if_c<(is_same_type<T,float>::value ||
                                is_same_type<T,double>::value ||
                                is_same_type<T,std::complex<float> >::value ||
                                is_same_type<T,std::complex<double> >::value) &&
                                blas_bindings::has_matrix_multiply<src_exp>::value
    >::type matrix_assign_big (
        matrix<T,NR,NC,MM,L>& dest,
        const src_exp& src
    )
    {
        blas_bindings::matrix_assign_blas(dest,src);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T, long NR, long NC, typename MM, typename L,
        typename src_exp
        >
    inline typename enable_if_c<(is_same_type<T,float>::value ||
                                is_same_type<T,double>::value ||
                                is_same_type<T,std::complex<float> >::value ||
                                is_same_type<T,std::complex<double> >::value) &&
                                blas_bindings::has_matrix_multiply<src_exp>::value
    >::type matrix_assign_big (
        assignable_sub_matrix<T,NR,NC,MM,L>& dest,
        const src_exp& src
    )
    {
        blas_bindings::matrix_assign_blas(dest,src);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename src_exp
        >
    inline typename enable_if_c<(is_same_type<T,float>::value ||
                                is_same_type<T,double>::value ||
                                is_same_type<T,std::complex<float> >::value ||
                                is_same_type<T,std::complex<double> >::value) &&
                                blas_bindings::has_matrix_multiply<src_exp>::value
    >::type matrix_assign_big (
        assignable_ptr_matrix<T>& dest,
        const src_exp& src
    )
    {
        blas_bindings::matrix_assign_blas(dest,src);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T, long NR, long NC, typename MM, typename L,
        typename src_exp
        >
    inline typename enable_if_c<(is_same_type<T,float>::value ||
                                is_same_type<T,double>::value ||
                                is_same_type<T,std::complex<float> >::value ||
                                is_same_type<T,std::complex<double> >::value) &&
                                blas_bindings::has_matrix_multiply<src_exp>::value
    >::type matrix_assign_big (
        assignable_row_matrix<T,NR,NC,MM,L>& dest,
        const src_exp& src
    )
    {
        blas_bindings::matrix_assign_blas(dest,src);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T, long NR, long NC, typename MM, typename L,
        typename src_exp
        >
    inline typename enable_if_c<(is_same_type<T,float>::value ||
                                is_same_type<T,double>::value ||
                                is_same_type<T,std::complex<float> >::value ||
                                is_same_type<T,std::complex<double> >::value) &&
                                blas_bindings::has_matrix_multiply<src_exp>::value
    >::type matrix_assign_big (
        assignable_col_matrix<T,NR,NC,MM,L>& dest,
        const src_exp& src
    )
    {
        blas_bindings::matrix_assign_blas(dest,src);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MATRIx_ASSIGn_


dlib C++ Library - matrix_assign_fwd.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MATRIx_ASSIGn_FWD_
#define DLIB_MATRIx_ASSIGn_FWD_

// 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

#include "../enable_if.h"
#include "matrix_data_layout.h"
#include "../algs.h"

namespace dlib
{

    /*
        The point of the matrix_assign() functions is to contain all the various
        optimizations that help the matrix assign a matrix_exp to an actual matrix
        object quickly.
    */

// ----------------------------------------------------------------------------------------

    namespace ma
    {
        // This template here controls how big a compile time sized matrix needs
        // to be for it to get passed into the optimized versions of the
        // matrix_assign() function.  So small matrices are evaluated with a simple
        // loop like the ones in this file and bigger matrices may get sent to BLAS
        // routines or some other kind of optimized thing.
        template < typename EXP, typename enable = void >
        struct is_small_matrix { static const bool value = false; };
        template < typename EXP >
        struct is_small_matrix<EXP, typename enable_if_c<EXP::NR>=1 && EXP::NC>=1 &&
        EXP::NR<=17 && EXP::NC<=17 && (EXP::cost <= 70)>::type> { static const bool value = true; };

        // I wouldn't use this mul object to do the multiply but visual studio 7.1 wouldn't
        // compile otherwise.
        template <long a, long b>
        struct mul { const static long value = a*b; };

        template < typename EXP, typename enable = void >
        struct is_very_small_matrix { static const bool value = false; };
        template < typename EXP >
        struct is_very_small_matrix<EXP, typename enable_if_c<EXP::NR>=1 && EXP::NC>=1 &&
        (mul<EXP::NR,EXP::NC>::value <= 16) && (EXP::cost <= 70)>::type> { static const bool value = true; };

        template < typename EXP, typename enable = void >
        struct has_column_major_layout { static const bool value = false; };
        template < typename EXP >
        struct has_column_major_layout<EXP, typename enable_if<is_same_type<typename EXP::layout_type, column_major_layout> >::type >
        { static const bool value = true; };

    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP
        >
    class matrix_exp;

// ----------------------------------------------------------------------------------------

    template <typename EXP1, typename EXP2>
    inline typename disable_if<ma::has_column_major_layout<EXP1> >::type
    matrix_assign_default (
        EXP1& dest,
        const EXP2& src
    )
    /*!
        requires
            - src.destructively_aliases(dest) == false
            - dest.nr() == src.nr()
            - dest.nc() == src.nc()
        ensures
            - #dest == src
    !*/
    {
        for (long r = 0; r < src.nr(); ++r)
        {
            for (long c = 0; c < src.nc(); ++c)
            {
                dest(r,c) = src(r,c);
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <typename EXP1, typename EXP2>
    inline typename enable_if<ma::has_column_major_layout<EXP1> >::type
    matrix_assign_default (
        EXP1& dest,
        const EXP2& src
    )
    /*!
        requires
            - src.destructively_aliases(dest) == false
            - dest.nr() == src.nr()
            - dest.nc() == src.nc()
        ensures
            - #dest == src
    !*/
    {
        for (long c = 0; c < src.nc(); ++c)
        {
            for (long r = 0; r < src.nr(); ++r)
            {
                dest(r,c) = src(r,c);
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <typename EXP1, typename EXP2>
    inline typename disable_if<ma::has_column_major_layout<EXP1> >::type
    matrix_assign_default (
        EXP1& dest,
        const EXP2& src,
        typename EXP2::type alpha,
        bool add_to
    )
    /*!
        requires
            - src.destructively_aliases(dest) == false
            - dest.nr() == src.nr()
            - dest.nc() == src.nc()
        ensures
            - if (add_to == false) then
                - #dest == alpha*src
            - else
                - #dest == dest + alpha*src
    !*/
    {
        if (add_to)
        {
            if (alpha == static_cast<typename EXP2::type>(1))
            {
                for (long r = 0; r < src.nr(); ++r)
                {
                    for (long c = 0; c < src.nc(); ++c)
                    {
                        dest(r,c) += src(r,c);
                    }
                }
            }
            else if (alpha == static_cast<typename EXP2::type>(-1))
            {
                for (long r = 0; r < src.nr(); ++r)
                {
                    for (long c = 0; c < src.nc(); ++c)
                    {
                        dest(r,c) -= src(r,c);
                    }
                }
            }
            else
            {
                for (long r = 0; r < src.nr(); ++r)
                {
                    for (long c = 0; c < src.nc(); ++c)
                    {
                        dest(r,c) += alpha*src(r,c);
                    }
                }
            }
        }
        else
        {
            if (alpha == static_cast<typename EXP2::type>(1))
            {
                for (long r = 0; r < src.nr(); ++r)
                {
                    for (long c = 0; c < src.nc(); ++c)
                    {
                        dest(r,c) = src(r,c);
                    }
                }
            }
            else
            {
                for (long r = 0; r < src.nr(); ++r)
                {
                    for (long c = 0; c < src.nc(); ++c)
                    {
                        dest(r,c) = alpha*src(r,c);
                    }
                }
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <typename EXP1, typename EXP2>
    inline typename enable_if<ma::has_column_major_layout<EXP1> >::type
    matrix_assign_default (
        EXP1& dest,
        const EXP2& src,
        typename EXP2::type alpha,
        bool add_to
    )
    /*!
        requires
            - src.destructively_aliases(dest) == false
            - dest.nr() == src.nr()
            - dest.nc() == src.nc()
        ensures
            - if (add_to == false) then
                - #dest == alpha*src
            - else
                - #dest == dest + alpha*src
    !*/
    {
        if (add_to)
        {
            if (alpha == static_cast<typename EXP2::type>(1))
            {
                for (long c = 0; c < src.nc(); ++c)
                {
                    for (long r = 0; r < src.nr(); ++r)
                    {
                        dest(r,c) += src(r,c);
                    }
                }
            }
            else if (alpha == static_cast<typename EXP2::type>(-1))
            {
                for (long c = 0; c < src.nc(); ++c)
                {
                    for (long r = 0; r < src.nr(); ++r)
                    {
                        dest(r,c) -= src(r,c);
                    }
                }
            }
            else
            {
                for (long c = 0; c < src.nc(); ++c)
                {
                    for (long r = 0; r < src.nr(); ++r)
                    {
                        dest(r,c) += alpha*src(r,c);
                    }
                }
            }
        }
        else
        {
            if (alpha == static_cast<typename EXP2::type>(1))
            {
                for (long c = 0; c < src.nc(); ++c)
                {
                    for (long r = 0; r < src.nr(); ++r)
                    {
                        dest(r,c) = src(r,c);
                    }
                }
            }
            else
            {
                for (long c = 0; c < src.nc(); ++c)
                {
                    for (long r = 0; r < src.nr(); ++r)
                    {
                        dest(r,c) = alpha*src(r,c);
                    }
                }
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_dest_type,
        typename src_exp
        >
    void matrix_assign_big (
        matrix_dest_type& dest,
        const matrix_exp<src_exp>& src
    )
    {
        matrix_assign_default(dest,src);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_dest_type,
        typename src_exp
        >
    inline typename disable_if<ma::is_small_matrix<src_exp> >::type matrix_assign (
        matrix_dest_type& dest,
        const matrix_exp<src_exp>& src
    )
    /*!
        requires
            - src.destructively_aliases(dest) == false
            - dest.nr() == src.nr()
            - dest.nc() == src.nc()
        ensures
            - #dest == src
    !*/
    {
        // Call src.ref() here so that the derived type of the matrix_exp shows
        // up so we can overload matrix_assign_big() based on various matrix expression
        // types.
        matrix_assign_big(dest,src.ref());
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

// this code is here to perform an unrolled version of the matrix_assign() function
    template < typename DEST, typename SRC, long NR, long NC,
    long R = 0, long C = 0, bool base_case = (R==NR) >
    struct matrix_unroll_helper
    {
        inline static void go ( DEST& dest, const SRC& src)
        {
            dest(R,C) = src(R,C);
            matrix_unroll_helper<DEST,SRC,NR,NC, R + (C+1)/NC,  (C+1)%NC>::go(dest,src);
        }
    };

    template < typename DEST, typename SRC, long NR, long NC, long R, long C >
    struct matrix_unroll_helper<DEST,SRC,NR,NC,R,C,true>
    { inline static void go ( DEST& , const SRC& ) {} };

    template <typename DEST, typename SRC>
    inline void matrix_assign_unrolled (
        DEST& dest,
        const SRC& src
    )
    /*!
        requires
            - src.destructively_aliases(dest) == false
            - dest.nr() == src.nr()
            - dest.nc() == src.nc()
        ensures
            - #dest == src
    !*/
    {
        COMPILE_TIME_ASSERT(SRC::NR*SRC::NC != 0);
        matrix_unroll_helper<DEST,SRC, SRC::NR, SRC::NC>::go(dest,src);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename matrix_dest_type,
        typename src_exp
        >
    inline typename enable_if_c<ma::is_small_matrix<src_exp>::value && ma::is_very_small_matrix<src_exp>::value==false >::type matrix_assign (
        matrix_dest_type& dest,
        const matrix_exp<src_exp>& src
    )
    /*!
        requires
            - src.destructively_aliases(dest) == false
            - dest.nr() == src.nr()
            - dest.nc() == src.nc()
        ensures
            - #dest == src
    !*/
    {
        matrix_assign_default(dest,src.ref());
    }

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_dest_type,
        typename src_exp
        >
    inline typename enable_if_c<ma::is_small_matrix<src_exp>::value && ma::is_very_small_matrix<src_exp>::value==true >::type matrix_assign (
        matrix_dest_type& dest,
        const matrix_exp<src_exp>& src
    )
    /*!
        requires
            - src.destructively_aliases(dest) == false
            - dest.nr() == src.nr()
            - dest.nc() == src.nc()
        ensures
            - #dest == src
    !*/
    {
        matrix_assign_unrolled(dest,src.ref());
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MATRIx_ASSIGn_FWD_


dlib C++ Library - matrix_blas_bindings.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MATRIx_BLAS_BINDINGS_
#define DLIB_MATRIx_BLAS_BINDINGS_

#ifndef DLIB_USE_BLAS
#error "DLIB_USE_BLAS should be defined if you want to use the BLAS bindings"
#endif

#include "matrix_assign.h"
#include "matrix_conj_trans.h"
#include "cblas_constants.h"

//#include <iostream>
//using namespace std;

namespace dlib
{

    namespace blas_bindings
    {

#ifdef DLIB_TEST_BLAS_BINDINGS
        int& counter_gemm();
        int& counter_gemv();
        int& counter_ger();
        int& counter_dot();
        int& counter_axpy();
        int& counter_scal();

        #define DLIB_TEST_BLAS_BINDING_GEMM ++counter_gemm();
        #define DLIB_TEST_BLAS_BINDING_GEMV ++counter_gemv();
        #define DLIB_TEST_BLAS_BINDING_GER ++counter_ger();
        #define DLIB_TEST_BLAS_BINDING_DOT ++counter_dot();
        #define DLIB_TEST_BLAS_BINDING_AXPY ++counter_axpy();
        #define DLIB_TEST_BLAS_BINDING_SCAL ++counter_scal();
#else
        #define DLIB_TEST_BLAS_BINDING_GEMM
        #define DLIB_TEST_BLAS_BINDING_GEMV
        #define DLIB_TEST_BLAS_BINDING_GER
        #define DLIB_TEST_BLAS_BINDING_DOT
        #define DLIB_TEST_BLAS_BINDING_AXPY
        #define DLIB_TEST_BLAS_BINDING_SCAL
#endif

        extern "C"
        {
            // Here we declare the prototypes for the CBLAS calls used by the BLAS bindings below

            void cblas_saxpy(const int N, const float alpha, const float *X,
                            const int incX, float *Y, const int incY);
            void cblas_daxpy(const int N, const double alpha, const double *X,
                            const int incX, double *Y, const int incY);
            void cblas_caxpy(const int N, const void *alpha, const void *X,
                            const int incX, void *Y, const int incY);
            void cblas_zaxpy(const int N, const void *alpha, const void *X,
                            const int incX, void *Y, const int incY);

            void cblas_sscal(const int N, const float alpha, float *X, const int incX);
            void cblas_dscal(const int N, const double alpha, double *X, const int incX);
            void cblas_cscal(const int N, const void *alpha, void *X, const int incX);
            void cblas_zscal(const int N, const void *alpha, void *X, const int incX);

            void cblas_sgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA,
                             const enum CBLAS_TRANSPOSE TransB, const int M, const int N,
                             const int K, const float alpha, const float *A,
                             const int lda, const float *B, const int ldb,
                             const float beta, float *C, const int ldc);
            void cblas_dgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA,
                             const enum CBLAS_TRANSPOSE TransB, const int M, const int N,
                             const int K, const double alpha, const double *A,
                             const int lda, const double *B, const int ldb,
                             const double beta, double *C, const int ldc);
            void cblas_cgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA,
                             const enum CBLAS_TRANSPOSE TransB, const int M, const int N,
                             const int K, const void *alpha, const void *A,
                             const int lda, const void *B, const int ldb,
                             const void *beta, void *C, const int ldc);
            void cblas_zgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA,
                             const enum CBLAS_TRANSPOSE TransB, const int M, const int N,
                             const int K, const void *alpha, const void *A,
                             const int lda, const void *B, const int ldb,
                             const void *beta, void *C, const int ldc);
            void cblas_sgemv(const enum CBLAS_ORDER order,
                             const enum CBLAS_TRANSPOSE TransA, const int M, const int N,
                             const float alpha, const float *A, const int lda,
                             const float *X, const int incX, const float beta,
                             float *Y, const int incY);
            void cblas_dgemv(const enum CBLAS_ORDER order,
                             const enum CBLAS_TRANSPOSE TransA, const int M, const int N,
                             const double alpha, const double *A, const int lda,
                             const double *X, const int incX, const double beta,
                             double *Y, const int incY);
            void cblas_cgemv(const enum CBLAS_ORDER order,
                             const enum CBLAS_TRANSPOSE TransA, const int M, const int N,
                             const void *alpha, const void *A, const int lda,
                             const void *X, const int incX, const void *beta,
                             void *Y, const int incY);
            void cblas_zgemv(const enum CBLAS_ORDER order,
                             const enum CBLAS_TRANSPOSE TransA, const int M, const int N,
                             const void *alpha, const void *A, const int lda,
                             const void *X, const int incX, const void *beta,
                             void *Y, const int incY);
            void cblas_sger(const enum CBLAS_ORDER order, const int M, const int N,
                            const float alpha, const float *X, const int incX,
                            const float *Y, const int incY, float *A, const int lda);
            void cblas_dger(const enum CBLAS_ORDER order, const int M, const int N,
                            const double alpha, const double *X, const int incX,
                            const double *Y, const int incY, double *A, const int lda);
            void cblas_cgerc(const enum CBLAS_ORDER order, const int M, const int N,
                             const void *alpha, const void *X, const int incX,
                             const void *Y, const int incY, void *A, const int lda);
            void cblas_zgerc(const enum CBLAS_ORDER order, const int M, const int N,
                             const void *alpha, const void *X, const int incX,
                             const void *Y, const int incY, void *A, const int lda);
            float  cblas_sdot(const int N, const float  *X, const int incX,
                              const float  *Y, const int incY);
            double cblas_ddot(const int N, const double *X, const int incX,
                              const double *Y, const int incY);
            void   cblas_cdotu_sub(const int N, const void *X, const int incX,
                                   const void *Y, const int incY, void *dotu);
            void   cblas_zdotu_sub(const int N, const void *X, const int incX,
                                   const void *Y, const int incY, void *dotu);
            void   cblas_cdotc_sub(const int N, const void *X, const int incX,
                                   const void *Y, const int incY, void *dotc);
            void   cblas_zdotc_sub(const int N, const void *X, const int incX,
                                   const void *Y, const int incY, void *dotc);
            void cblas_cgeru(const enum CBLAS_ORDER order, const int M, const int N,
                             const void *alpha, const void *X, const int incX,
                             const void *Y, const int incY, void *A, const int lda);
            void cblas_zgeru(const enum CBLAS_ORDER order, const int M, const int N,
                             const void *alpha, const void *X, const int incX,
                             const void *Y, const int incY, void *A, const int lda);
        }

    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------

        inline void cblas_axpy(const int N, const float alpha, const float *X,
                        const int incX, float *Y, const int incY)
        {
            DLIB_TEST_BLAS_BINDING_AXPY;
            cblas_saxpy(N, alpha, X, incX, Y, incY);
        }

        inline void cblas_axpy(const int N, const double alpha, const double *X,
                        const int incX, double *Y, const int incY)
        {
            DLIB_TEST_BLAS_BINDING_AXPY;
            cblas_daxpy(N, alpha, X, incX, Y, incY);
        }

        inline void cblas_axpy(const int N, const std::complex<float>& alpha, const std::complex<float> *X,
                        const int incX, std::complex<float> *Y, const int incY)
        {
            DLIB_TEST_BLAS_BINDING_AXPY;
            cblas_caxpy(N, &alpha, X, incX, Y, incY);
        }

        inline void cblas_axpy(const int N, const std::complex<double>& alpha, const std::complex<double> *X,
                        const int incX, std::complex<double> *Y, const int incY)
        {
            DLIB_TEST_BLAS_BINDING_AXPY;
            cblas_zaxpy(N, &alpha, X, incX, Y, incY);
        }

    // ----------------------------------------------------------------------------------------

        inline void cblas_scal(const int N, const float alpha, float *X)
        {
            DLIB_TEST_BLAS_BINDING_SCAL;
            cblas_sscal(N, alpha, X, 1);
        }

        inline void cblas_scal(const int N, const double alpha, double *X)
        {
            DLIB_TEST_BLAS_BINDING_SCAL;
            cblas_dscal(N, alpha, X, 1);
        }

        inline void cblas_scal(const int N, const std::complex<float>& alpha, std::complex<float> *X)
        {
            DLIB_TEST_BLAS_BINDING_SCAL;
            cblas_cscal(N, &alpha, X, 1);
        }

        inline void cblas_scal(const int N, const std::complex<double>& alpha, std::complex<double> *X)
        {
            DLIB_TEST_BLAS_BINDING_SCAL;
            cblas_zscal(N, &alpha, X, 1);
        }

    // ----------------------------------------------------------------------------------------

        inline void cblas_gemm( const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA,
                                const enum CBLAS_TRANSPOSE TransB, const int M, const int N,
                                const int K, const float alpha, const float *A,
                                const int lda, const float *B, const int ldb,
                                const float beta, float *C, const int ldc)
        {
            DLIB_TEST_BLAS_BINDING_GEMM;
            cblas_sgemm( Order, TransA, TransB,  M,  N,
                          K,  alpha, A, lda, B,  ldb, beta, C,  ldc);
        }

        inline void cblas_gemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA,
                         const enum CBLAS_TRANSPOSE TransB, const int M, const int N,
                         const int K, const double alpha, const double *A,
                         const int lda, const double *B, const int ldb,
                         const double beta, double *C, const int ldc)
        {
            DLIB_TEST_BLAS_BINDING_GEMM;
            cblas_dgemm( Order, TransA, TransB,  M,  N,
                          K,  alpha, A, lda, B,  ldb, beta, C,  ldc);
        }

        inline void cblas_gemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA,
                         const enum CBLAS_TRANSPOSE TransB, const int M, const int N,
                         const int K, const std::complex<float>& alpha, const std::complex<float> *A,
                         const int lda, const std::complex<float> *B, const int ldb,
                         const std::complex<float>& beta, std::complex<float> *C, const int ldc)
        {
            DLIB_TEST_BLAS_BINDING_GEMM;
            cblas_cgemm( Order, TransA, TransB,  M,  N,
                          K,  &alpha, A, lda, B,  ldb, &beta, C,  ldc);
        }

        inline void cblas_gemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA,
                         const enum CBLAS_TRANSPOSE TransB, const int M, const int N,
                         const int K, const std::complex<double>& alpha, const std::complex<double> *A,
                         const int lda, const std::complex<double> *B, const int ldb,
                         const std::complex<double>& beta, std::complex<double> *C, const int ldc)
        {
            DLIB_TEST_BLAS_BINDING_GEMM;
            cblas_zgemm( Order, TransA, TransB,  M,  N,
                          K,  &alpha, A, lda, B,  ldb, &beta, C,  ldc);
        }

    // ----------------------------------------------------------------------------------------

        inline void cblas_gemv(const enum CBLAS_ORDER order,
                        const enum CBLAS_TRANSPOSE TransA, const int M, const int N,
                        const float alpha, const float *A, const int lda,
                        const float *X, const int incX, const float beta,
                        float *Y, const int incY)
        {
            DLIB_TEST_BLAS_BINDING_GEMV;
            cblas_sgemv(order, TransA, M, N, alpha, A, lda, X, incX, beta, Y, incY);
        }

        inline void cblas_gemv(const enum CBLAS_ORDER order,
                        const enum CBLAS_TRANSPOSE TransA, const int M, const int N,
                        const double alpha, const double *A, const int lda,
                        const double *X, const int incX, const double beta,
                        double *Y, const int incY)
        {
            DLIB_TEST_BLAS_BINDING_GEMV;
            cblas_dgemv(order, TransA, M, N, alpha, A, lda, X, incX, beta, Y, incY);
        }

        inline void cblas_gemv(const enum CBLAS_ORDER order,
                        const enum CBLAS_TRANSPOSE TransA, const int M, const int N,
                        const std::complex<float>& alpha, const std::complex<float> *A, const int lda,
                        const std::complex<float> *X, const int incX, const std::complex<float>& beta,
                        std::complex<float> *Y, const int incY)
        {
            DLIB_TEST_BLAS_BINDING_GEMV;
            cblas_cgemv(order, TransA, M, N, &alpha, A, lda, X, incX, &beta, Y, incY);
        }

        inline void cblas_gemv(const enum CBLAS_ORDER order,
                        const enum CBLAS_TRANSPOSE TransA, const int M, const int N,
                        const std::complex<double>& alpha, const std::complex<double> *A, const int lda,
                        const std::complex<double> *X, const int incX, const std::complex<double>& beta,
                        std::complex<double> *Y, const int incY)
        {
            DLIB_TEST_BLAS_BINDING_GEMV;
            cblas_zgemv(order, TransA, M, N, &alpha, A, lda, X, incX, &beta, Y, incY);
        }

    // ----------------------------------------------------------------------------------------

        inline void cblas_ger(const enum CBLAS_ORDER order, const int M, const int N,
                        const std::complex<float>& alpha, const std::complex<float> *X, const int incX,
                        const std::complex<float> *Y, const int incY, std::complex<float> *A, const int lda)
        {
            DLIB_TEST_BLAS_BINDING_GER;
            cblas_cgeru (order,  M, N, &alpha, X, incX, Y, incY, A, lda);
        }

        inline void cblas_ger(const enum CBLAS_ORDER order, const int M, const int N,
                        const std::complex<double>& alpha, const std::complex<double> *X, const int incX,
                        const std::complex<double> *Y, const int incY, std::complex<double> *A, const int lda)
        {
            DLIB_TEST_BLAS_BINDING_GER;
            cblas_zgeru (order,  M, N, &alpha, X, incX, Y, incY, A, lda);
        }

        inline void cblas_ger(const enum CBLAS_ORDER order, const int M, const int N,
                        const float alpha, const float *X, const int incX,
                        const float *Y, const int incY, float *A, const int lda)
        {
            DLIB_TEST_BLAS_BINDING_GER;
            cblas_sger (order,  M, N, alpha, X, incX, Y, incY, A, lda);
        }

        inline void cblas_ger(const enum CBLAS_ORDER order, const int M, const int N,
                        const double alpha, const double *X, const int incX,
                        const double *Y, const int incY, double *A, const int lda)
        {
            DLIB_TEST_BLAS_BINDING_GER;
            cblas_dger (order,  M, N, alpha, X, incX, Y, incY, A, lda);
        }

    // ----------------------------------------------------------------------------------------

        inline void cblas_gerc(const enum CBLAS_ORDER order, const int M, const int N,
                        const std::complex<float>& alpha, const std::complex<float> *X, const int incX,
                        const std::complex<float> *Y, const int incY, std::complex<float> *A, const int lda)
        {
            DLIB_TEST_BLAS_BINDING_GER;
            cblas_cgerc (order,  M, N, &alpha, X, incX, Y, incY, A, lda);
        }

        inline void cblas_gerc(const enum CBLAS_ORDER order, const int M, const int N,
                        const std::complex<double>& alpha, const std::complex<double> *X, const int incX,
                        const std::complex<double> *Y, const int incY, std::complex<double> *A, const int lda)
        {
            DLIB_TEST_BLAS_BINDING_GER;
            cblas_zgerc (order,  M, N, &alpha, X, incX, Y, incY, A, lda);
        }

    // ----------------------------------------------------------------------------------------

        inline float cblas_dot(const int N, const float  *X, const int incX,
                        const float  *Y, const int incY)
        {
            DLIB_TEST_BLAS_BINDING_DOT;
            return cblas_sdot(N, X, incX, Y, incY);
        }

        inline double cblas_dot(const int N, const double *X, const int incX,
                        const double *Y, const int incY)
        {
            DLIB_TEST_BLAS_BINDING_DOT;
            return cblas_ddot(N, X, incX, Y, incY);
        }

        inline std::complex<float> cblas_dot(const int N, const std::complex<float> *X, const int incX,
                            const std::complex<float> *Y, const int incY)
        {
            DLIB_TEST_BLAS_BINDING_DOT;
            std::complex<float> result;
            cblas_cdotu_sub(N, X, incX, Y, incY, &result);
            return result;
        }

        inline std::complex<double> cblas_dot(const int N, const std::complex<double> *X, const int incX,
                            const std::complex<double> *Y, const int incY)
        {
            DLIB_TEST_BLAS_BINDING_DOT;
            std::complex<double> result;
            cblas_zdotu_sub(N, X, incX, Y, incY, &result);
            return result;
        }

    // ----------------------------------------------------------------------------------------

        inline std::complex<float> cblas_dotc(const int N, const std::complex<float> *X, const int incX,
                            const std::complex<float> *Y, const int incY)
        {
            DLIB_TEST_BLAS_BINDING_DOT;
            std::complex<float> result;
            cblas_cdotc_sub(N, X, incX, Y, incY, &result);
            return result;
        }

        inline std::complex<double> cblas_dotc(const int N, const std::complex<double> *X, const int incX,
                            const std::complex<double> *Y, const int incY)
        {
            DLIB_TEST_BLAS_BINDING_DOT;
            std::complex<double> result;
            cblas_zdotc_sub(N, X, incX, Y, incY, &result);
            return result;
        }

    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------
    // Helpers for determining the data pointer, LDA, and incX arguments to BLAS functions.

        template <typename T, long NR, long NC, typename MM>
        int get_ld (const matrix<T,NR,NC,MM,row_major_layout>& m) { return m.nc(); }

        template <typename T, long NR, long NC, typename MM>
        int get_ld (const matrix<T,NR,NC,MM,column_major_layout>& m) { return m.nr(); }

        template <typename T, long NR, long NC, typename MM>
        int get_ld (const matrix_op<op_subm<matrix<T,NR,NC,MM,row_major_layout> > >& m) { return m.op.m.nc(); }

        template <typename T, long NR, long NC, typename MM>
        int get_ld (const matrix_op<op_subm<matrix<T,NR,NC,MM,column_major_layout> > >& m) { return m.op.m.nr(); }

        template <typename T, long NR, long NC, typename MM>
        int get_ld (const assignable_sub_matrix<T,NR,NC,MM,row_major_layout>& m) { return m.m.nc(); }

        template <typename T, long NR, long NC, typename MM>
        int get_ld (const assignable_sub_matrix<T,NR,NC,MM,column_major_layout>& m) { return m.m.nr(); }

        template <typename T>
        int get_ld (const assignable_ptr_matrix<T>& m) { return m.nc(); }

        template <typename T, typename MM>
        int get_ld (const matrix_op<op_array2d_to_mat<array2d<T,MM> > >& m) { return m.nc(); }
        template <typename T, typename MM>
        int get_ld (const matrix_op<op_array_to_mat<array<T,MM> > >& m) { return m.nc(); }
        template < typename value_type, typename alloc >
        int get_ld (const matrix_op<op_std_vect_to_mat<std::vector<value_type,alloc> > >& m) { return m.nc(); }
        template < typename value_type, typename alloc >
        int get_ld (const matrix_op<op_std_vect_to_mat<std_vector_c<value_type,alloc> > >& m) { return m.nc(); }
        template <typename T>
        int get_ld (const matrix_op<op_pointer_to_col_vect<T> >& m) { return m.nc(); }
        template <typename T>
        int get_ld (const matrix_op<op_pointer_to_mat<T> >& m) { return m.nc(); }

        // --------

        // get_inc() returns the offset from one element to another.  If an object has a
        // non-uniform offset between elements then returns 0 (e.g. a subm() view could
        // have a non-uniform offset between elements).

        template <typename T, typename MM>
        int get_inc (const matrix_op<op_array2d_to_mat<array2d<T,MM> > >& ) { return 1; }
        template <typename T, typename MM>
        int get_inc (const matrix_op<op_array_to_mat<array<T,MM> > >& ) { return 1; }
        template < typename value_type, typename alloc >
        int get_inc (const matrix_op<op_std_vect_to_mat<std::vector<value_type,alloc> > >& ) { return 1; }
        template < typename value_type, typename alloc >
        int get_inc (const matrix_op<op_std_vect_to_mat<std_vector_c<value_type,alloc> > >& ) { return 1; }
        template <typename T>
        int get_inc (const matrix_op<op_pointer_to_col_vect<T> >& ) { return 1; }
        template <typename T>
        int get_inc (const matrix_op<op_pointer_to_mat<T> >& ) { return 1; }

        template <typename T, long NR, long NC, typename MM, typename L>
        int get_inc (const matrix<T,NR,NC,MM,L>& ) { return 1; }

        template <typename T, long NR, long NC, typename MM>
        int get_inc (const matrix_op<op_subm<matrix<T,NR,NC,MM,row_major_layout> > >& m)
        {
            // if the sub-view doesn't cover all the columns then it can't have a uniform
            // layout.
            if (m.nc() < m.op.m.nc())
                return 0;
            else
                return 1;
        }

        template <typename T, long NR, long NC, typename MM>
        int get_inc (const matrix_op<op_subm<matrix<T,NR,NC,MM,column_major_layout> > >& m)
        {
            if (m.nr() < m.op.m.nr())
                return 0;
            else
                return 1;
        }

        template <typename T, long NR, long NC, typename MM>
        int get_inc (const assignable_sub_matrix<T,NR,NC,MM,row_major_layout>& m)
        {
            if (m.nc() < m.m.nc())
                return 0;
            else
                return 1;
        }
        template <typename T, long NR, long NC, typename MM>
        int get_inc (const assignable_sub_matrix<T,NR,NC,MM,column_major_layout>& m)
        {
            if (m.nr() < m.m.nr())
                return 0;
            else
                return 1;
        }

        template <typename T>
        int get_inc (const assignable_ptr_matrix<T>& ) { return 1; }

        template <typename T, long NR, long NC, typename MM>
        int get_inc(const matrix_op<op_colm<matrix<T,NR,NC,MM,row_major_layout> > >& m)
        {
            return m.op.m.nc();
        }

        template <typename T, long NR, long NC, typename MM>
        int get_inc(const matrix_op<op_rowm<matrix<T,NR,NC,MM,row_major_layout> > >& )
        {
            return 1;
        }

        template <typename T, long NR, long NC, typename MM>
        int get_inc(const matrix_op<op_colm2<matrix<T,NR,NC,MM,row_major_layout> > >& m)
        {
            return m.op.m.nc();
        }

        template <typename T, long NR, long NC, typename MM>
        int get_inc(const matrix_op<op_rowm2<matrix<T,NR,NC,MM,row_major_layout> > >& )
        {
            return 1;
        }

        template <typename T, long NR, long NC, typename MM>
        int get_inc(const matrix_op<op_colm<matrix<T,NR,NC,MM,column_major_layout> > >& )
        {
            return 1;
        }

        template <typename T, long NR, long NC, typename MM>
        int get_inc(const matrix_op<op_rowm<matrix<T,NR,NC,MM,column_major_layout> > >& m)
        {
            return m.op.m.nr();
        }

        template <typename T, long NR, long NC, typename MM>
        int get_inc(const matrix_op<op_colm2<matrix<T,NR,NC,MM,column_major_layout> > >& )
        {
            return 1;
        }

        template <typename T, long NR, long NC, typename MM>
        int get_inc(const matrix_op<op_rowm2<matrix<T,NR,NC,MM,column_major_layout> > >& m)
        {
            return m.op.m.nr();
        }

        template <typename T, long NR, long NC, typename MM>
        int get_inc(const assignable_row_matrix<T,NR,NC,MM,row_major_layout>& )
        {
            return 1;
        }

        template <typename T, long NR, long NC, typename MM>
        int get_inc(const assignable_row_matrix<T,NR,NC,MM,column_major_layout>& m)
        {
            return m.m.nr();
        }

        template <typename T, long NR, long NC, typename MM>
        int get_inc(const assignable_col_matrix<T,NR,NC,MM,row_major_layout>& m)
        {
            return m.m.nc();
        }

        template <typename T, long NR, long NC, typename MM>
        int get_inc(const assignable_col_matrix<T,NR,NC,MM,column_major_layout>& )
        {
            return 1;
        }

        // --------

        template <typename T, long NR, long NC, typename MM, typename L>
        const T* get_ptr (const matrix<T,NR,NC,MM,L>& m) { return &m(0,0); }

        template <typename T, long NR, long NC, typename MM, typename L>
        T* get_ptr (matrix<T,NR,NC,MM,L>& m) { return &m(0,0); }

        template <typename T, long NR, long NC, typename MM, typename L>
        const T* get_ptr (const matrix_op<op_subm<matrix<T,NR,NC,MM,L> > >& m) { return &m.op.m(m.op.r_,m.op.c_); }

        template <typename T, long NR, long NC, typename MM, typename L>
        const T* get_ptr (const matrix_op<op_colm<matrix<T,NR,NC,MM,L> > >& m) { return &m.op.m(0,m.op.col); }

        template <typename T, long NR, long NC, typename MM, typename L>
        const T* get_ptr (const matrix_op<op_rowm<matrix<T,NR,NC,MM,L> > >& m) { return &m.op.m(m.op.row,0); }

        template <typename T, long NR, long NC, typename MM, typename L>
        const T* get_ptr (const matrix_op<op_colm2<matrix<T,NR,NC,MM,L> > >& m) { return &m.op.m(0,m.op.col); }

        template <typename T, long NR, long NC, typename MM, typename L>
        const T* get_ptr (const matrix_op<op_rowm2<matrix<T,NR,NC,MM,L> > >& m) { return &m.op.m(m.op.row,0); }

        template <typename T, long NR, long NC, typename MM, typename L>
        T* get_ptr (assignable_col_matrix<T,NR,NC,MM,L>& m) { return &m(0,0); }

        template <typename T, long NR, long NC, typename MM, typename L>
        T* get_ptr (assignable_row_matrix<T,NR,NC,MM,L>& m) { return &m(0,0); }

        template <typename T, long NR, long NC, typename MM, typename L>
        T* get_ptr (assignable_sub_matrix<T,NR,NC,MM,L>& m) { return &m(0,0); }

        template <typename T>
        T* get_ptr (assignable_ptr_matrix<T>& m) { return m.ptr; }

        template <typename T, typename MM>
        const T* get_ptr (const matrix_op<op_array2d_to_mat<array2d<T,MM> > >& m) { return &m.op.array[0][0]; }
        template <typename T, typename MM>
        const T* get_ptr (const matrix_op<op_array_to_mat<array<T,MM> > >& m) { return &m.op.vect[0]; }
        template < typename T, typename alloc >
        const T* get_ptr (const matrix_op<op_std_vect_to_mat<std::vector<T,alloc> > >& m) { return &m.op.vect[0]; }
        template < typename T, typename alloc >
        const T* get_ptr (const matrix_op<op_std_vect_to_mat<std_vector_c<T,alloc> > >& m) { return &m.op.vect[0]; }
        template <typename T>
        const T* get_ptr (const matrix_op<op_pointer_to_col_vect<T> >& m) { return m.op.ptr; }
        template <typename T>
        const T* get_ptr (const matrix_op<op_pointer_to_mat<T> >& m) { return m.op.ptr; }

    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------

        // Here we declare some matrix objects for use in the DLIB_ADD_BLAS_BINDING macro.  These
        // extern declarations don't actually correspond to any real matrix objects.  They are
        // simply here so we can build matrix expressions with the DLIB_ADD_BLAS_BINDING marco.

        // Note that the fact that these are double matrices isn't important, it is just a placeholder in this case.
        extern matrix<double> m;     // general matrix
        extern matrix<double,1,0> rv;  // general row vector
        extern matrix<double,0,1> cv;  // general column vector
        extern const double s;

    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------
    //                       AXPY/SCAL overloads
    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------

        DLIB_ADD_BLAS_BINDING(m)
        {

            const int N = static_cast<int>(src.size());
            if (transpose == false && N != 0)
            {
                if (add_to)
                {
                    if (get_inc(src) && get_inc(dest))
                        cblas_axpy(N, alpha, get_ptr(src), get_inc(src), get_ptr(dest), get_inc(dest));
                    else
                        matrix_assign_default(dest, src, alpha, add_to);
                }
                else
                {
                    if (get_ptr(src) == get_ptr(dest))
                        cblas_scal(N, alpha, get_ptr(dest));
                    else
                        matrix_assign_default(dest, src, alpha, add_to);
                }
            }
            else
            {
                matrix_assign_default(dest, trans(src), alpha, add_to);
            }

        } DLIB_END_BLAS_BINDING

        DLIB_ADD_BLAS_BINDING(rv)
        {

            const int N = static_cast<int>(src.size());
            if (transpose == false && N != 0)
            {
                if (add_to)
                {
                    if (get_inc(src) && get_inc(dest))
                        cblas_axpy(N, alpha, get_ptr(src), get_inc(src), get_ptr(dest), get_inc(dest));
                    else
                        matrix_assign_default(dest, src, alpha, add_to);
                }
                else
                {
                    if (get_ptr(src) == get_ptr(dest))
                        cblas_scal(N, alpha, get_ptr(dest));
                    else
                        matrix_assign_default(dest, src, alpha, add_to);
                }
            }
            else
            {
                matrix_assign_default(dest, trans(src), alpha, add_to);
            }

        } DLIB_END_BLAS_BINDING

        DLIB_ADD_BLAS_BINDING(cv)
        {

            const int N = static_cast<int>(src.size());
            if (transpose == false && N != 0)
            {
                if (add_to)
                {
                    if (get_inc(src) && get_inc(dest))
                        cblas_axpy(N, alpha, get_ptr(src), get_inc(src), get_ptr(dest), get_inc(dest));
                    else
                        matrix_assign_default(dest, src, alpha, add_to);
                }
                else
                {
                    if (get_ptr(src) == get_ptr(dest))
                        cblas_scal(N, alpha, get_ptr(dest));
                    else
                        matrix_assign_default(dest, src, alpha, add_to);
                }
            }
            else
            {
                matrix_assign_default(dest, trans(src), alpha, add_to);
            }

        } DLIB_END_BLAS_BINDING

    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------
    //                       GEMM overloads
    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------

        DLIB_ADD_BLAS_BINDING(m*m)
        {
            //cout << "BLAS GEMM: m*m" << endl;
            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;
            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;
            const int M = static_cast<int>(src.nr());
            const int N = static_cast<int>(src.nc());
            const int K = static_cast<int>(src.lhs.nc());
            const T* A = get_ptr(src.lhs);
            const int lda = get_ld(src.lhs);
            const T* B = get_ptr(src.rhs);
            const int ldb = get_ld(src.rhs);

            const T beta = static_cast<T>(add_to?1:0);
            T* C = get_ptr(dest);
            const int ldc = get_ld(dest);

            if (transpose == false)
                cblas_gemm(Order, CblasNoTrans, CblasNoTrans, M, N, K, alpha, A, lda, B, ldb, beta, C, ldc);
            else
                cblas_gemm(Order, CblasTrans, CblasTrans, N, M, K, alpha, B, ldb, A, lda, beta, C, ldc);

        } DLIB_END_BLAS_BINDING

        // --------------------------------------

        DLIB_ADD_BLAS_BINDING(trans(m)*m)
        {
            //cout << "BLAS GEMM: trans(m)*m" << endl;
            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;
            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;
            const CBLAS_TRANSPOSE TransA = CblasTrans;
            const CBLAS_TRANSPOSE TransB = CblasNoTrans;
            const int M = static_cast<int>(src.nr());
            const int N = static_cast<int>(src.nc());
            const int K = static_cast<int>(src.lhs.nc());
            const T* A = get_ptr(src.lhs.op.m);
            const int lda = get_ld(src.lhs.op.m);
            const T* B = get_ptr(src.rhs);
            const int ldb = get_ld(src.rhs);

            const T beta = static_cast<T>(add_to?1:0);
            T* C = get_ptr(dest);
            const int ldc = get_ld(dest);

            if (transpose == false)
                cblas_gemm(Order, TransA, TransB, M, N, K, alpha, A, lda, B, ldb, beta, C, ldc);
            else
                cblas_gemm(Order, TransA, TransB, N, M, K, alpha, B, ldb, A, lda, beta, C, ldc);

        } DLIB_END_BLAS_BINDING

        // --------------------------------------

        DLIB_ADD_BLAS_BINDING(m*trans(m))
        {
            //cout << "BLAS GEMM: m*trans(m)" << endl;
            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;
            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;
            const CBLAS_TRANSPOSE TransA = CblasNoTrans;
            const CBLAS_TRANSPOSE TransB = CblasTrans;
            const int M = static_cast<int>(src.nr());
            const int N = static_cast<int>(src.nc());
            const int K = static_cast<int>(src.lhs.nc());
            const T* A = get_ptr(src.lhs);
            const int lda = get_ld(src.lhs);
            const T* B = get_ptr(src.rhs.op.m);
            const int ldb = get_ld(src.rhs.op.m);

            const T beta = static_cast<T>(add_to?1:0);
            T* C = get_ptr(dest);
            const int ldc = get_ld(dest);

            if (transpose == false)
                cblas_gemm(Order, TransA, TransB, M, N, K, alpha, A, lda, B, ldb, beta, C, ldc);
            else
                cblas_gemm(Order, TransA, TransB, N, M, K, alpha, B, ldb, A, lda, beta, C, ldc);

        } DLIB_END_BLAS_BINDING

        // --------------------------------------

        DLIB_ADD_BLAS_BINDING(trans(m)*trans(m))
        {
            //cout << "BLAS GEMM: trans(m)*trans(m)" << endl;
            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;
            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;
            const int M = static_cast<int>(src.nr());
            const int N = static_cast<int>(src.nc());
            const int K = static_cast<int>(src.lhs.nc());
            const T* A = get_ptr(src.lhs.op.m);
            const int lda = get_ld(src.lhs.op.m);
            const T* B = get_ptr(src.rhs.op.m);
            const int ldb = get_ld(src.rhs.op.m);

            const T beta = static_cast<T>(add_to?1:0);
            T* C = get_ptr(dest);
            const int ldc = get_ld(dest);

            if (transpose == false)
                cblas_gemm(Order, CblasTrans, CblasTrans, M, N, K, alpha, A, lda, B, ldb, beta, C, ldc);
            else
                cblas_gemm(Order, CblasNoTrans, CblasNoTrans, N, M, K, alpha, B, ldb, A, lda, beta, C, ldc);
        } DLIB_END_BLAS_BINDING

        // --------------------------------------
        // --------------------------------------
        // --------------------------------------

        DLIB_ADD_BLAS_BINDING(trans(conj(m))*m)
        {
            //cout << "BLAS GEMM: trans(conj(m))*m" << endl;
            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;
            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;
            const CBLAS_TRANSPOSE TransA = CblasConjTrans;
            const CBLAS_TRANSPOSE TransB = CblasNoTrans;
            const int M = static_cast<int>(src.nr());
            const int N = static_cast<int>(src.nc());
            const int K = static_cast<int>(src.lhs.nc());
            const T* A = get_ptr(src.lhs.op.m);
            const int lda = get_ld(src.lhs.op.m);
            const T* B = get_ptr(src.rhs);
            const int ldb = get_ld(src.rhs);

            const T beta = static_cast<T>(add_to?1:0);
            T* C = get_ptr(dest);
            const int ldc = get_ld(dest);

            if (transpose == false)
                cblas_gemm(Order, TransA, TransB, M, N, K, alpha, A, lda, B, ldb, beta, C, ldc);
            else
                matrix_assign_default(dest, trans(src), alpha, add_to);

        } DLIB_END_BLAS_BINDING

        // --------------------------------------

        DLIB_ADD_BLAS_BINDING(trans(conj(m))*trans(m))
        {
            //cout << "BLAS GEMM: trans(conj(m))*trans(m)" << endl;
            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;
            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;
            const CBLAS_TRANSPOSE TransA = CblasConjTrans;
            const CBLAS_TRANSPOSE TransB = CblasTrans;
            const int M = static_cast<int>(src.nr());
            const int N = static_cast<int>(src.nc());
            const int K = static_cast<int>(src.lhs.nc());
            const T* A = get_ptr(src.lhs.op.m);
            const int lda = get_ld(src.lhs.op.m);
            const T* B = get_ptr(src.rhs.op.m);
            const int ldb = get_ld(src.rhs.op.m);

            const T beta = static_cast<T>(add_to?1:0);
            T* C = get_ptr(dest);
            const int ldc = get_ld(dest);

            if (transpose == false)
                cblas_gemm(Order, TransA, TransB, M, N, K, alpha, A, lda, B, ldb, beta, C, ldc);
            else
                matrix_assign_default(dest, trans(src), alpha, add_to);

        } DLIB_END_BLAS_BINDING

        // --------------------------------------

        DLIB_ADD_BLAS_BINDING(m*trans(conj(m)))
        {
            //cout << "BLAS GEMM: m*trans(conj(m))" << endl;
            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;
            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;
            const CBLAS_TRANSPOSE TransA = CblasNoTrans;
            const CBLAS_TRANSPOSE TransB = CblasConjTrans;
            const int M = static_cast<int>(src.nr());
            const int N = static_cast<int>(src.nc());
            const int K = static_cast<int>(src.lhs.nc());
            const T* A = get_ptr(src.lhs);
            const int lda = get_ld(src.lhs);
            const T* B = get_ptr(src.rhs.op.m);
            const int ldb = get_ld(src.rhs.op.m);

            const T beta = static_cast<T>(add_to?1:0);
            T* C = get_ptr(dest);
            const int ldc = get_ld(dest);

            if (transpose == false)
                cblas_gemm(Order, TransA, TransB, M, N, K, alpha, A, lda, B, ldb, beta, C, ldc);
            else
                matrix_assign_default(dest, trans(src), alpha, add_to);
        } DLIB_END_BLAS_BINDING

        // --------------------------------------

        DLIB_ADD_BLAS_BINDING(trans(m)*trans(conj(m)))
        {
            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;
            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;
            const CBLAS_TRANSPOSE TransA = CblasTrans;
            const CBLAS_TRANSPOSE TransB = CblasConjTrans;
            const int M = static_cast<int>(src.nr());
            const int N = static_cast<int>(src.nc());
            const int K = static_cast<int>(src.lhs.nc());
            const T* A = get_ptr(src.lhs.op.m);
            const int lda = get_ld(src.lhs.op.m);
            const T* B = get_ptr(src.rhs.op.m);
            const int ldb = get_ld(src.rhs.op.m);

            const T beta = static_cast<T>(add_to?1:0);
            T* C = get_ptr(dest);
            const int ldc = get_ld(dest);

            if (transpose == false)
                cblas_gemm(Order, TransA, TransB, M, N, K, alpha, A, lda, B, ldb, beta, C, ldc);
            else
                matrix_assign_default(dest, trans(src), alpha, add_to);
        } DLIB_END_BLAS_BINDING

        // --------------------------------------

        DLIB_ADD_BLAS_BINDING(trans(conj(m))*trans(conj(m)))
        {
            //cout << "BLAS GEMM: trans(conj(m))*trans(conj(m))" << endl;
            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;
            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;
            const CBLAS_TRANSPOSE TransA = CblasConjTrans;
            const CBLAS_TRANSPOSE TransB = CblasConjTrans;
            const int M = static_cast<int>(src.nr());
            const int N = static_cast<int>(src.nc());
            const int K = static_cast<int>(src.lhs.nc());
            const T* A = get_ptr(src.lhs.op.m);
            const int lda = get_ld(src.lhs.op.m);
            const T* B = get_ptr(src.rhs.op.m);
            const int ldb = get_ld(src.rhs.op.m);

            const T beta = static_cast<T>(add_to?1:0);
            T* C = get_ptr(dest);
            const int ldc = get_ld(dest);

            if (transpose == false)
                cblas_gemm(Order, TransA, TransB, M, N, K, alpha, A, lda, B, ldb, beta, C, ldc);
            else
                matrix_assign_default(dest, trans(src), alpha, add_to);
        } DLIB_END_BLAS_BINDING

    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------
    //                       GEMV overloads
    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------

        DLIB_ADD_BLAS_BINDING(m*cv)
        {
            //cout << "BLAS GEMV: m*cv" << endl;
            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;
            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;
            const CBLAS_TRANSPOSE TransA = CblasNoTrans;
            const int M = static_cast<int>(src.lhs.nr());
            const int N = static_cast<int>(src.lhs.nc());
            const T* A = get_ptr(src.lhs);
            const int lda = get_ld(src.lhs);
            const T* X = get_ptr(src.rhs);
            const int incX = get_inc(src.rhs);

            const T beta = static_cast<T>(add_to?1:0);
            T* Y = get_ptr(dest);
            const int incY = get_inc(dest);

            cblas_gemv(Order, TransA, M, N, alpha, A, lda, X, incX, beta, Y, incY);
        } DLIB_END_BLAS_BINDING

        // --------------------------------------

        DLIB_ADD_BLAS_BINDING(rv*m)
        {
            // Note that rv*m is the same as trans(m)*trans(rv)

            //cout << "BLAS GEMV: rv*m" << endl;
            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;
            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;
            const CBLAS_TRANSPOSE TransA = CblasTrans;
            const int M = static_cast<int>(src.rhs.nr());
            const int N = static_cast<int>(src.rhs.nc());
            const T* A = get_ptr(src.rhs);
            const int lda = get_ld(src.rhs);
            const T* X = get_ptr(src.lhs);
            const int incX = get_inc(src.lhs);

            const T beta = static_cast<T>(add_to?1:0);
            T* Y = get_ptr(dest);
            const int incY = get_inc(dest);

            cblas_gemv(Order, TransA, M, N, alpha, A, lda, X, incX, beta, Y, incY);
        } DLIB_END_BLAS_BINDING

        // --------------------------------------

        DLIB_ADD_BLAS_BINDING(trans(cv)*m)
        {
            // Note that trans(cv)*m is the same as trans(m)*cv

            //cout << "BLAS GEMV: trans(cv)*m" << endl;
            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;
            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;
            const CBLAS_TRANSPOSE TransA = CblasTrans;
            const int M = static_cast<int>(src.rhs.nr());
            const int N = static_cast<int>(src.rhs.nc());
            const T* A = get_ptr(src.rhs);
            const int lda = get_ld(src.rhs);
            const T* X = get_ptr(src.lhs.op.m);
            const int incX = get_inc(src.lhs.op.m);

            const T beta = static_cast<T>(add_to?1:0);
            T* Y = get_ptr(dest);
            const int incY = get_inc(dest);

            cblas_gemv(Order, TransA, M, N, alpha, A, lda, X, incX, beta, Y, incY);
        } DLIB_END_BLAS_BINDING

        // --------------------------------------

        DLIB_ADD_BLAS_BINDING(m*trans(rv))
        {
            //cout << "BLAS GEMV: m*trans(rv)" << endl;
            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;
            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;
            const CBLAS_TRANSPOSE TransA = CblasNoTrans;
            const int M = static_cast<int>(src.lhs.nr());
            const int N = static_cast<int>(src.lhs.nc());
            const T* A = get_ptr(src.lhs);
            const int lda = get_ld(src.lhs);
            const T* X = get_ptr(src.rhs.op.m);
            const int incX = get_inc(src.rhs.op.m);

            const T beta = static_cast<T>(add_to?1:0);
            T* Y = get_ptr(dest);
            const int incY = get_inc(dest);

            cblas_gemv(Order, TransA, M, N, alpha, A, lda, X, incX, beta, Y, incY);
        } DLIB_END_BLAS_BINDING

        // --------------------------------------
        // --------------------------------------
        // --------------------------------------

        DLIB_ADD_BLAS_BINDING(trans(m)*cv)
        {
            //cout << "BLAS GEMV: trans(m)*cv" << endl;
            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;
            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;
            const CBLAS_TRANSPOSE TransA = CblasTrans;
            const int M = static_cast<int>(src.lhs.op.m.nr());
            const int N = static_cast<int>(src.lhs.op.m.nc());
            const T* A = get_ptr(src.lhs.op.m);
            const int lda = get_ld(src.lhs.op.m);
            const T* X = get_ptr(src.rhs);
            const int incX = get_inc(src.rhs);

            const T beta = static_cast<T>(add_to?1:0);
            T* Y = get_ptr(dest);
            const int incY = get_inc(dest);

            cblas_gemv(Order, TransA, M, N, alpha, A, lda, X, incX, beta, Y, incY);
        } DLIB_END_BLAS_BINDING

        // --------------------------------------

        DLIB_ADD_BLAS_BINDING(rv*trans(m))
        {
            // Note that rv*trans(m) is the same as m*trans(rv)

            //cout << "BLAS GEMV: rv*trans(m)" << endl;
            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;
            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;
            const CBLAS_TRANSPOSE TransA = CblasNoTrans;
            const int M = static_cast<int>(src.rhs.op.m.nr());
            const int N = static_cast<int>(src.rhs.op.m.nc());
            const T* A = get_ptr(src.rhs.op.m);
            const int lda = get_ld(src.rhs.op.m);
            const T* X = get_ptr(src.lhs);
            const int incX = get_inc(src.lhs);

            const T beta = static_cast<T>(add_to?1:0);
            T* Y = get_ptr(dest);
            const int incY = get_inc(dest);

            cblas_gemv(Order, TransA, M, N, alpha, A, lda, X, incX, beta, Y, incY);
        } DLIB_END_BLAS_BINDING

        // --------------------------------------

        DLIB_ADD_BLAS_BINDING(trans(cv)*trans(m))
        {
            // Note that trans(cv)*trans(m) is the same as m*cv

            //cout << "BLAS GEMV: trans(cv)*trans(m)" << endl;
            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;
            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;
            const CBLAS_TRANSPOSE TransA = CblasNoTrans;
            const int M = static_cast<int>(src.rhs.op.m.nr());
            const int N = static_cast<int>(src.rhs.op.m.nc());
            const T* A = get_ptr(src.rhs.op.m);
            const int lda = get_ld(src.rhs.op.m);
            const T* X = get_ptr(src.lhs.op.m);
            const int incX = get_inc(src.lhs.op.m);

            const T beta = static_cast<T>(add_to?1:0);
            T* Y = get_ptr(dest);
            const int incY = get_inc(dest);

            cblas_gemv(Order, TransA, M, N, alpha, A, lda, X, incX, beta, Y, incY);
        } DLIB_END_BLAS_BINDING

        // --------------------------------------

        DLIB_ADD_BLAS_BINDING(trans(m)*trans(rv))
        {
            //cout << "BLAS GEMV: trans(m)*trans(rv)" << endl;
            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;
            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;
            const CBLAS_TRANSPOSE TransA = CblasTrans;
            const int M = static_cast<int>(src.lhs.op.m.nr());
            const int N = static_cast<int>(src.lhs.op.m.nc());
            const T* A = get_ptr(src.lhs.op.m);
            const int lda = get_ld(src.lhs.op.m);
            const T* X = get_ptr(src.rhs.op.m);
            const int incX = get_inc(src.rhs.op.m);

            const T beta = static_cast<T>(add_to?1:0);
            T* Y = get_ptr(dest);
            const int incY = get_inc(dest);

            cblas_gemv(Order, TransA, M, N, alpha, A, lda, X, incX, beta, Y, incY);
        } DLIB_END_BLAS_BINDING

        // --------------------------------------
        // --------------------------------------
        // --------------------------------------

        DLIB_ADD_BLAS_BINDING(trans(cv)*conj(m))
        {
            // Note that trans(cv)*conj(m) == conj(trans(m))*cv
            //cout << "BLAS GEMV: trans(cv)*conj(m)" << endl;
            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;
            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;
            const CBLAS_TRANSPOSE TransA = CblasConjTrans;
            const int M = static_cast<int>(src.rhs.op.m.nr());
            const int N = static_cast<int>(src.rhs.op.m.nc());
            const T* A = get_ptr(src.rhs.op.m);
            const int lda = get_ld(src.rhs.op.m);
            const T* X = get_ptr(src.lhs.op.m);
            const int incX = get_inc(src.lhs.op.m);

            const T beta = static_cast<T>(add_to?1:0);
            T* Y = get_ptr(dest);
            const int incY = get_inc(dest);

            cblas_gemv(Order, TransA, M, N, alpha, A, lda, X, incX, beta, Y, incY);
        } DLIB_END_BLAS_BINDING

        // --------------------------------------

        DLIB_ADD_BLAS_BINDING(rv*conj(m))
        {
            // Note that rv*conj(m) == conj(trans(m))*cv
            //cout << "BLAS GEMV: rv*conj(m)" << endl;
            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;
            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;
            const CBLAS_TRANSPOSE TransA = CblasConjTrans;
            const int M = static_cast<int>(src.rhs.op.m.nr());
            const int N = static_cast<int>(src.rhs.op.m.nc());
            const T* A = get_ptr(src.rhs.op.m);
            const int lda = get_ld(src.rhs.op.m);
            const T* X = get_ptr(src.lhs);
            const int incX = get_inc(src.lhs);

            const T beta = static_cast<T>(add_to?1:0);
            T* Y = get_ptr(dest);
            const int incY = get_inc(dest);

            cblas_gemv(Order, TransA, M, N, alpha, A, lda, X, incX, beta, Y, incY);
        } DLIB_END_BLAS_BINDING

        // --------------------------------------

        DLIB_ADD_BLAS_BINDING(trans(conj(m))*cv)
        {
            //cout << "BLAS GEMV: trans(conj(m))*cv" << endl;
            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;
            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;
            const CBLAS_TRANSPOSE TransA = CblasConjTrans;
            const int M = static_cast<int>(src.lhs.op.m.nr());
            const int N = static_cast<int>(src.lhs.op.m.nc());
            const T* A = get_ptr(src.lhs.op.m);
            const int lda = get_ld(src.lhs.op.m);
            const T* X = get_ptr(src.rhs);
            const int incX = get_inc(src.rhs);

            const T beta = static_cast<T>(add_to?1:0);
            T* Y = get_ptr(dest);
            const int incY = get_inc(dest);

            cblas_gemv(Order, TransA, M, N, alpha, A, lda, X, incX, beta, Y, incY);
        } DLIB_END_BLAS_BINDING

        // --------------------------------------

        DLIB_ADD_BLAS_BINDING(trans(conj(m))*trans(rv))
        {
            //cout << "BLAS GEMV: trans(conj(m))*trans(rv)" << endl;
            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;
            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;
            const CBLAS_TRANSPOSE TransA = CblasConjTrans;
            const int M = static_cast<int>(src.lhs.op.m.nr());
            const int N = static_cast<int>(src.lhs.op.m.nc());
            const T* A = get_ptr(src.lhs.op.m);
            const int lda = get_ld(src.lhs.op.m);
            const T* X = get_ptr(src.rhs.op.m);
            const int incX = get_inc(src.rhs.op.m);

            const T beta = static_cast<T>(add_to?1:0);
            T* Y = get_ptr(dest);
            const int incY = get_inc(dest);

            cblas_gemv(Order, TransA, M, N, alpha, A, lda, X, incX, beta, Y, incY);
        } DLIB_END_BLAS_BINDING

    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------
    //                       GER overloads
    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------

        DLIB_ADD_BLAS_BINDING(cv*rv)
        {
            //cout << "BLAS GER: cv*rv" << endl;
            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;
            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;
            const int M = static_cast<int>(dest.nr());
            const int N = static_cast<int>(dest.nc());
            const T* X = get_ptr(src.lhs);
            const int incX = get_inc(src.lhs);
            const T* Y = get_ptr(src.rhs);
            const int incY = get_inc(src.rhs);

            if (add_to == false)
                zero_matrix(dest);

            T* A = get_ptr(dest);
            const int lda = get_ld(dest);

            if (transpose == false)
                cblas_ger(Order, M, N, alpha, X, incX, Y, incY, A, lda);
            else
                cblas_ger(Order, M, N, alpha, Y, incY, X, incX, A, lda);

        } DLIB_END_BLAS_BINDING

        // --------------------------------------

        DLIB_ADD_BLAS_BINDING(trans(rv)*rv)
        {
            //cout << "BLAS GER: trans(rv)*rv" << endl;
            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;
            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;
            const int M = static_cast<int>(dest.nr());
            const int N = static_cast<int>(dest.nc());
            const T* X = get_ptr(src.lhs.op.m);
            const int incX = get_inc(src.lhs.op.m);
            const T* Y = get_ptr(src.rhs);
            const int incY = get_inc(src.rhs);

            if (add_to == false)
                zero_matrix(dest);

            T* A = get_ptr(dest);
            const int lda = get_ld(dest);

            if (transpose == false)
                cblas_ger(Order, M, N, alpha, X, incX, Y, incY, A, lda);
            else
                cblas_ger(Order, M, N, alpha, Y, incY, X, incX, A, lda);
        } DLIB_END_BLAS_BINDING

        // --------------------------------------

        DLIB_ADD_BLAS_BINDING(cv*trans(cv))
        {
            //cout << "BLAS GER: cv*trans(cv)" << endl;
            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;
            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;
            const int M = static_cast<int>(dest.nr());
            const int N = static_cast<int>(dest.nc());
            const T* X = get_ptr(src.lhs);
            const int incX = get_inc(src.lhs);
            const T* Y = get_ptr(src.rhs.op.m);
            const int incY = get_inc(src.rhs.op.m);

            if (add_to == false)
                zero_matrix(dest);

            T* A = get_ptr(dest);
            const int lda = get_ld(dest);

            if (transpose == false)
                cblas_ger(Order, M, N, alpha, X, incX, Y, incY, A, lda);
            else
                cblas_ger(Order, M, N, alpha, Y, incY, X, incX, A, lda);
        } DLIB_END_BLAS_BINDING

        // --------------------------------------

        DLIB_ADD_BLAS_BINDING(trans(rv)*trans(cv))
        {
            //cout << "BLAS GER: trans(rv)*trans(cv)" << endl;
            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;
            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;
            const int M = static_cast<int>(dest.nr());
            const int N = static_cast<int>(dest.nc());
            const T* X = get_ptr(src.lhs.op.m);
            const int incX = get_inc(src.lhs.op.m);
            const T* Y = get_ptr(src.rhs.op.m);
            const int incY = get_inc(src.rhs.op.m);

            if (add_to == false)
                zero_matrix(dest);

            T* A = get_ptr(dest);
            const int lda = get_ld(dest);

            if (transpose == false)
                cblas_ger(Order, M, N, alpha, X, incX, Y, incY, A, lda);
            else
                cblas_ger(Order, M, N, alpha, Y, incY, X, incX, A, lda);
        } DLIB_END_BLAS_BINDING

    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------
    //                       GERC overloads
    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------

        /*
        DLIB_ADD_BLAS_BINDING(cv*conj(rv))
        {
            //cout << "BLAS GERC: cv*conj(rv)" << endl;
            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;
            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;
            const int M = static_cast<int>(dest.nr());
            const int N = static_cast<int>(dest.nc());
            const T* X = get_ptr(src.lhs);
            const int incX = get_inc(src.lhs);
            const T* Y = get_ptr(src.rhs.op.m);
            const int incY = get_inc(src.rhs.op.m);

            if (add_to == false)
                zero_matrix(dest);

            T* A = get_ptr(dest);
            const int lda = get_ld(dest);

            if (transpose == false)
                cblas_gerc(Order, M, N, alpha, X, incX, Y, incY, A, lda);
            else
                cblas_gerc(Order, M, N, alpha, Y, incY, X, incX, A, lda);
        } DLIB_END_BLAS_BINDING
        */

        // --------------------------------------

        DLIB_ADD_BLAS_BINDING(cv*conj(trans(cv)))
        {
            //cout << "BLAS GERC: cv*conj(trans(cv))" << endl;
            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;
            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;
            const int M = static_cast<int>(dest.nr());
            const int N = static_cast<int>(dest.nc());
            const T* X = get_ptr(src.lhs);
            const int incX = get_inc(src.lhs);
            const T* Y = get_ptr(src.rhs.op.m);
            const int incY = get_inc(src.rhs.op.m);

            if (transpose == false)
            {
                T* A = get_ptr(dest);
                const int lda = get_ld(dest);

                if (add_to == false)
                    zero_matrix(dest);

                cblas_gerc(Order, M, N, alpha, X, incX, Y, incY, A, lda);
            }
            else
            {
                matrix_assign_default(dest,trans(src),alpha,add_to);
                //cblas_gerc(Order, M, N, alpha, Y, incY, X, incX, A, lda);
            }
        } DLIB_END_BLAS_BINDING

        // --------------------------------------

        DLIB_ADD_BLAS_BINDING(trans(rv)*conj(trans(cv)))
        {
            //cout << "BLAS GERC: trans(rv)*conj(trans(cv))" << endl;
            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;
            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;
            const int M = static_cast<int>(dest.nr());
            const int N = static_cast<int>(dest.nc());
            const T* X = get_ptr(src.lhs.op.m);
            const int incX = get_inc(src.lhs.op.m);
            const T* Y = get_ptr(src.rhs.op.m);
            const int incY = get_inc(src.rhs.op.m);

            if (transpose == false)
            {
                if (add_to == false)
                    zero_matrix(dest);

                T* A = get_ptr(dest);
                const int lda = get_ld(dest);

                cblas_gerc(Order, M, N, alpha, X, incX, Y, incY, A, lda);
            }
            else
            {
                matrix_assign_default(dest,trans(src),alpha,add_to);
                //cblas_gerc(Order, M, N, alpha, Y, incY, X, incX, A, lda);
            }
        } DLIB_END_BLAS_BINDING

        // --------------------------------------

        /*
        DLIB_ADD_BLAS_BINDING(trans(rv)*conj(rv))
        {
            //cout << "BLAS GERC: trans(rv)*conj(rv)" << endl;
            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;
            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;
            const int M = static_cast<int>(dest.nr());
            const int N = static_cast<int>(dest.nc());
            const T* X = get_ptr(src.lhs.op.m);
            const int incX = get_inc(src.lhs.op.m);
            const T* Y = get_ptr(src.rhs.op.m);
            const int incY = get_inc(src.rhs.op.m);

            if (add_to == false)
                zero_matrix(dest);

            T* A = get_ptr(dest);
            const int lda = get_ld(dest);

            if (transpose == false)
                cblas_gerc(Order, M, N, alpha, X, incX, Y, incY, A, lda);
            else
                cblas_gerc(Order, M, N, alpha, Y, incY, X, incX, A, lda);
        } DLIB_END_BLAS_BINDING
        */

    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------
    //                       DOT overloads
    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------

        DLIB_ADD_BLAS_BINDING(rv*cv)
        {
            //cout << "BLAS DOT: rv*cv" << endl;
            const int N = static_cast<int>(src.lhs.size());
            const T* X = get_ptr(src.lhs);
            const int incX = get_inc(src.lhs);
            const T* Y = get_ptr(src.rhs);
            const int incY = get_inc(src.rhs);

            if (add_to == false)
                dest(0) = alpha*cblas_dot(N, X, incX, Y, incY);
            else
                dest(0) += alpha*cblas_dot(N, X, incX, Y, incY);

        } DLIB_END_BLAS_BINDING

        // --------------------------------------

        DLIB_ADD_BLAS_BINDING(trans(cv)*cv)
        {
            //cout << "BLAS DOT: trans(cv)*cv" << endl;
            const int N = static_cast<int>(src.lhs.size());
            const T* X = get_ptr(src.lhs.op.m);
            const int incX = get_inc(src.lhs.op.m);
            const T* Y = get_ptr(src.rhs);
            const int incY = get_inc(src.rhs);

            if (add_to == false)
                dest(0) = alpha*cblas_dot(N, X, incX, Y, incY);
            else
                dest(0) += alpha*cblas_dot(N, X, incX, Y, incY);

        } DLIB_END_BLAS_BINDING

        // --------------------------------------

        DLIB_ADD_BLAS_BINDING(rv*trans(rv))
        {
            //cout << "BLAS DOT: rv*trans(rv)" << endl;
            const int N = static_cast<int>(src.lhs.size());
            const T* X = get_ptr(src.lhs);
            const int incX = get_inc(src.lhs);
            const T* Y = get_ptr(src.rhs.op.m);
            const int incY = get_inc(src.rhs.op.m);

            if (add_to == false)
                dest(0) = alpha*cblas_dot(N, X, incX, Y, incY);
            else
                dest(0) += alpha*cblas_dot(N, X, incX, Y, incY);

        } DLIB_END_BLAS_BINDING

        // --------------------------------------

        DLIB_ADD_BLAS_BINDING(trans(cv)*trans(rv))
        {
            //cout << "BLAS DOT: trans(cv)*trans(rv)" << endl;
            const int N = static_cast<int>(src.lhs.op.m.size());
            const T* X = get_ptr(src.lhs.op.m);
            const int incX = get_inc(src.lhs.op.m);
            const T* Y = get_ptr(src.rhs.op.m);
            const int incY = get_inc(src.rhs.op.m);

            if (add_to == false)
                dest(0) = alpha*cblas_dot(N, X, incX, Y, incY);
            else
                dest(0) += alpha*cblas_dot(N, X, incX, Y, incY);

        } DLIB_END_BLAS_BINDING

    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------
    //                       DOTC overloads
    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------

        DLIB_ADD_BLAS_BINDING(conj(rv)*cv)
        {
            //cout << "BLAS DOTC: conj(rv)*cv" << endl;
            const int N = static_cast<int>(src.lhs.op.m.size());
            const T* X = get_ptr(src.lhs.op.m);
            const int incX = get_inc(src.lhs.op.m);
            const T* Y = get_ptr(src.rhs);
            const int incY = get_inc(src.rhs);

            if (add_to == false)
                dest(0) = alpha*cblas_dotc(N, X, incX, Y, incY);
            else
                dest(0) += alpha*cblas_dotc(N, X, incX, Y, incY);

        } DLIB_END_BLAS_BINDING

        // --------------------------------------

        DLIB_ADD_BLAS_BINDING(conj(trans(cv))*cv)
        {
            //cout << "BLAS DOTC: conj(trans(cv))*cv" << endl;
            const int N = static_cast<int>(src.lhs.op.m.size());
            const T* X = get_ptr(src.lhs.op.m);
            const int incX = get_inc(src.lhs.op.m);
            const T* Y = get_ptr(src.rhs);
            const int incY = get_inc(src.rhs);

            if (add_to == false)
                dest(0) = alpha*cblas_dotc(N, X, incX, Y, incY);
            else
                dest(0) += alpha*cblas_dotc(N, X, incX, Y, incY);

        } DLIB_END_BLAS_BINDING

        // --------------------------------------

        DLIB_ADD_BLAS_BINDING(trans(conj(cv))*trans(rv))
        {
            //cout << "BLAS DOTC: trans(conj(cv))*trans(rv)" << endl;
            const int N = static_cast<int>(src.lhs.op.m.size());
            const T* X = get_ptr(src.lhs.op.m);
            const int incX = get_inc(src.lhs.op.m);
            const T* Y = get_ptr(src.rhs.op.m);
            const int incY = get_inc(src.rhs.op.m);

            if (add_to == false)
                dest(0) = alpha*cblas_dotc(N, X, incX, Y, incY);
            else
                dest(0) += alpha*cblas_dotc(N, X, incX, Y, incY);

        } DLIB_END_BLAS_BINDING

    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MATRIx_BLAS_BINDINGS_


dlib C++ Library - matrix_cholesky.h

// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
// This code was adapted from code from the JAMA part of NIST's TNT library.
//    See: http://math.nist.gov/tnt/
#ifndef DLIB_MATRIX_CHOLESKY_DECOMPOSITION_H
#define DLIB_MATRIX_CHOLESKY_DECOMPOSITION_H

#include "matrix.h"
#include "matrix_utilities.h"
#include "matrix_subexp.h"
#include <cmath>

#ifdef DLIB_USE_LAPACK
#include "lapack/potrf.h"
#endif

#include "matrix_trsm.h"

namespace dlib
{

    template <
        typename matrix_exp_type
        >
    class cholesky_decomposition
    {

    public:

        const static long NR = matrix_exp_type::NR;
        const static long NC = matrix_exp_type::NC;
        typedef typename matrix_exp_type::type type;
        typedef typename matrix_exp_type::mem_manager_type mem_manager_type;
        typedef typename matrix_exp_type::layout_type layout_type;

        typedef matrix<type,0,0,mem_manager_type,layout_type>  matrix_type;
        typedef matrix<type,NR,1,mem_manager_type,layout_type> column_vector_type;

        // You have supplied an invalid type of matrix_exp_type.  You have
        // to use this object with matrices that contain float or double type data.
        COMPILE_TIME_ASSERT((is_same_type<float, type>::value ||
                             is_same_type<double, type>::value ));

        template <typename EXP>
        cholesky_decomposition(
            const matrix_exp<EXP>& A
        );

        bool is_spd(
        ) const;

        const matrix_type& get_l(
        ) const;

        template <typename EXP>
        const typename EXP::matrix_type solve (
            const matrix_exp<EXP>& B
        ) const;

    private:

        matrix_type L_;     // lower triangular factor
        bool isspd;         // true if matrix to be factored was SPD
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                                      Member functions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <typename matrix_exp_type>
    bool cholesky_decomposition<matrix_exp_type>::
    is_spd(
    ) const
    {
        return isspd;
    }

// ----------------------------------------------------------------------------------------

    template <typename matrix_exp_type>
    const typename cholesky_decomposition<matrix_exp_type>::matrix_type& cholesky_decomposition<matrix_exp_type>::
    get_l(
    ) const
    {
        return L_;
    }

// ----------------------------------------------------------------------------------------

    template <typename matrix_exp_type>
    template <typename EXP>
    cholesky_decomposition<matrix_exp_type>::
    cholesky_decomposition(
        const matrix_exp<EXP>& A_
    )
    {
        using std::sqrt;
        COMPILE_TIME_ASSERT((is_same_type<type, typename EXP::type>::value));

        // make sure requires clause is not broken
        DLIB_ASSERT(A_.nr() == A_.nc() && A_.size() > 0,
            "\tcholesky_decomposition::cholesky_decomposition(A_)"
            << "\n\tYou can only use this on square matrices"
            << "\n\tA_.nr():   " << A_.nr()
            << "\n\tA_.nc():   " << A_.nc()
            << "\n\tA_.size(): " << A_.size()
            << "\n\tthis:      " << this
            );

#ifdef DLIB_USE_LAPACK
        L_ = A_;
        const type eps = max(abs(diag(L_)))*std::sqrt(std::numeric_limits<type>::epsilon())/100;

        // check if the matrix is actually symmetric
        bool is_symmetric = true;
        for (long r = 0; r < L_.nr() && is_symmetric; ++r)
        {
            for (long c = r+1; c < L_.nc() && is_symmetric; ++c)
            {
                // this is approximately doing: is_symmetric = is_symmetric && ( L_(k,j) == L_(j,k))
                is_symmetric = is_symmetric && (std::abs(L_(r,c) - L_(c,r)) < eps );
            }
        }

        // now compute the actual cholesky decomposition
        int info = lapack::potrf('L', L_);

        // check if it's really SPD
        if (info == 0 && is_symmetric && min(abs(diag(L_))) > eps*100)
            isspd = true;
        else
            isspd = false;

        L_ = lowerm(L_);
#else
        const_temp_matrix<EXP> A(A_);

        isspd = true;

        const long n = A.nc();
        L_.set_size(n,n);

        const type eps = max(abs(diag(A)))*std::sqrt(std::numeric_limits<type>::epsilon())/100;

        // Main loop.
        for (long j = 0; j < n; j++)
        {
            type d(0.0);
            for (long k = 0; k < j; k++)
            {
                type s(0.0);
                for (long i = 0; i < k; i++)
                {
                    s += L_(k,i)*L_(j,i);
                }

                // if L_(k,k) != 0
                if (std::abs(L_(k,k)) > eps)
                {
                    s = (A(j,k) - s)/L_(k,k);
                }
                else
                {
                    s = (A(j,k) - s);
                    isspd = false;
                }

                L_(j,k) = s;

                d = d + s*s;

                // this is approximately doing: isspd = isspd && ( A(k,j) == A(j,k))
                isspd = isspd && (std::abs(A(k,j) - A(j,k)) < eps );
            }
            d = A(j,j) - d;
            isspd = isspd && (d > eps);
            L_(j,j) = sqrt(d > 0.0 ? d : 0.0);
            for (long k = j+1; k < n; k++)
            {
                L_(j,k) = 0.0;
            }
        }
#endif
    }

// ----------------------------------------------------------------------------------------

    template <typename matrix_exp_type>
    template <typename EXP>
    const typename EXP::matrix_type cholesky_decomposition<matrix_exp_type>::
    solve(
        const matrix_exp<EXP>& B
    ) const
    {
        COMPILE_TIME_ASSERT((is_same_type<type, typename EXP::type>::value));

        // make sure requires clause is not broken
        DLIB_ASSERT(L_.nr() == B.nr(),
            "\tconst matrix cholesky_decomposition::solve(B)"
            << "\n\tInvalid arguments were given to this function."
            << "\n\tL_.nr():  " << L_.nr()
            << "\n\tB.nr():   " << B.nr()
            << "\n\tthis:     " << this
            );

        matrix<type, NR, EXP::NC, mem_manager_type, layout_type>  X(B);

        using namespace blas_bindings;
        // Solve L*y = b;
        triangular_solver(CblasLeft, CblasLower, CblasNoTrans, CblasNonUnit, L_, X);
        // Solve L'*X = Y;
        triangular_solver(CblasLeft, CblasLower, CblasTrans, CblasNonUnit, L_, X);
        return X;
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MATRIX_CHOLESKY_DECOMPOSITION_H


dlib C++ Library - matrix_conj_trans.h

// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MATRIx_CONJ_TRANS_FUNCTIONS
#define DLIB_MATRIx_CONJ_TRANS_FUNCTIONS

#include "matrix_utilities.h"
#include "matrix_math_functions.h"
#include "matrix.h"
#include "../algs.h"
#include <cmath>
#include <complex>
#include <limits>

namespace dlib
{
    /*!
        The point of the two functions defined in this file is to make statements
        of the form conj(trans(m)) and trans(conj(m)) look the same so that it is
        easier to map them to BLAS functions later on.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename M>
    struct op_conj_trans
    {
        op_conj_trans( const M& m_) : m(m_){}
        const M& m;

        const static long cost = M::cost+1;
        const static long NR = M::NC;
        const static long NC = M::NR;
        typedef typename M::type type;
        typedef typename M::type const_ret_type;
        typedef typename M::mem_manager_type mem_manager_type;
        typedef typename M::layout_type layout_type;
        const_ret_type apply (long r, long c) const { return std::conj(m(c,r)); }

        long nr () const { return m.nc(); }
        long nc () const { return m.nr(); }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }
    };

    template <typename EXP>
    const matrix_op<op_conj_trans<EXP> > trans (
        const matrix_op<op_conj<EXP> >& m
    )
    {
        typedef op_conj_trans<EXP> op;
        return matrix_op<op>(op(m.op.m));
    }

    template <typename EXP>
    const matrix_op<op_conj_trans<EXP> > conj (
        const matrix_op<op_trans<EXP> >& m
    )
    {
        typedef op_conj_trans<EXP> op;
        return matrix_op<op>(op(m.op.m));
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MATRIx_CONJ_TRANS_FUNCTIONS


dlib C++ Library - matrix_conv.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MATRIx_CONV_Hh_
#define DLIB_MATRIx_CONV_Hh_

#include "matrix_conv_abstract.h"
#include "matrix.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    namespace impl
    {
        template <typename T>
        const T& conj(const T& item) { return item; }
        template <typename T>
        std::complex<T> conj(const std::complex<T>& item) { return std::conj(item); }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <typename M1, typename M2, bool flip_m2 = false>
    struct op_conv
    {
        op_conv( const M1& m1_, const M2& m2_) :
            m1(m1_),
            m2(m2_),
            nr_(m1.nr()+m2.nr()-1),
            nc_(m1.nc()+m2.nc()-1)
        {
            if (nr_ < 0 || m1.size() == 0 || m2.size() == 0)
                nr_ = 0;
            if (nc_ < 0 || m1.size() == 0 || m2.size() == 0)
                nc_ = 0;
        }

        const M1& m1;
        const M2& m2;
        long nr_;
        long nc_;

        const static long cost = (M1::cost+M2::cost)*10;
        const static long NR = (M1::NR*M2::NR==0) ? (0) : (M1::NR+M2::NR-1);
        const static long NC = (M1::NC*M2::NC==0) ? (0) : (M1::NC+M2::NC-1);
        typedef typename M1::type type;
        typedef type const_ret_type;
        typedef typename M1::mem_manager_type mem_manager_type;
        typedef typename M1::layout_type layout_type;

        const_ret_type apply (long r, long c) const
        {
            type temp = 0;

            const long min_rr = std::max<long>(r-m2.nr()+1, 0);
            const long max_rr = std::min<long>(m1.nr()-1, r);

            const long min_cc = std::max<long>(c-m2.nc()+1, 0);
            const long max_cc = std::min<long>(m1.nc()-1, c);

            for (long rr = min_rr; rr <= max_rr; ++rr)
            {
                for (long cc = min_cc; cc <= max_cc; ++cc)
                {
                    if (flip_m2)
                        temp += m1(rr,cc)*dlib::impl::conj(m2(m2.nr()-r+rr-1, m2.nc()-c+cc-1));
                    else
                        temp += m1(rr,cc)*m2(r-rr,c-cc);
                }
            }

            return temp;
        }

        long nr () const { return nr_; }
        long nc () const { return nc_; }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m1.aliases(item) || m2.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m1.aliases(item) || m2.aliases(item); }

    };

    template <
        typename M1,
        typename M2
        >
    const matrix_op<op_conv<M1,M2> > conv (
        const matrix_exp<M1>& m1,
        const matrix_exp<M2>& m2
    )
    {
        COMPILE_TIME_ASSERT((is_same_type<typename M1::type,typename M2::type>::value == true));

        typedef op_conv<M1,M2> op;
        return matrix_op<op>(op(m1.ref(),m2.ref()));
    }

    template <
        typename M1,
        typename M2
        >
    const matrix_op<op_conv<M1,M2,true> > xcorr (
        const matrix_exp<M1>& m1,
        const matrix_exp<M2>& m2
    )
    {
        COMPILE_TIME_ASSERT((is_same_type<typename M1::type,typename M2::type>::value == true));

        typedef op_conv<M1,M2,true> op;
        return matrix_op<op>(op(m1.ref(),m2.ref()));
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <typename M1, typename M2, bool flip_m2 = false>
    struct op_conv_same
    {
        op_conv_same( const M1& m1_, const M2& m2_) : m1(m1_),m2(m2_),nr_(m1.nr()),nc_(m1.nc())
        {
            if (m1.size() == 0 || m2.size() == 0)
                nr_ = 0;
            if (m1.size() == 0 || m2.size() == 0)
                nc_ = 0;
        }

        const M1& m1;
        const M2& m2;
        long nr_;
        long nc_;

        const static long cost = (M1::cost+M2::cost)*10;
        const static long NR = M1::NR;
        const static long NC = M1::NC;
        typedef typename M1::type type;
        typedef type const_ret_type;
        typedef typename M1::mem_manager_type mem_manager_type;
        typedef typename M1::layout_type layout_type;

        const_ret_type apply (long r, long c) const
        {
            r += m2.nr()/2;
            c += m2.nc()/2;

            type temp = 0;

            const long min_rr = std::max<long>(r-m2.nr()+1, 0);
            const long max_rr = std::min<long>(m1.nr()-1, r);

            const long min_cc = std::max<long>(c-m2.nc()+1, 0);
            const long max_cc = std::min<long>(m1.nc()-1, c);

            for (long rr = min_rr; rr <= max_rr; ++rr)
            {
                for (long cc = min_cc; cc <= max_cc; ++cc)
                {
                    if (flip_m2)
                        temp += m1(rr,cc)*dlib::impl::conj(m2(m2.nr()-r+rr-1, m2.nc()-c+cc-1));
                    else
                        temp += m1(rr,cc)*m2(r-rr,c-cc);
                }
            }

            return temp;
        }

        long nr () const { return nr_; }
        long nc () const { return nc_; }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m1.aliases(item) || m2.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m1.aliases(item) || m2.aliases(item); }

    };

    template <
        typename M1,
        typename M2
        >
    const matrix_op<op_conv_same<M1,M2> > conv_same (
        const matrix_exp<M1>& m1,
        const matrix_exp<M2>& m2
    )
    {
        COMPILE_TIME_ASSERT((is_same_type<typename M1::type,typename M2::type>::value == true));

        typedef op_conv_same<M1,M2> op;
        return matrix_op<op>(op(m1.ref(),m2.ref()));
    }

    template <
        typename M1,
        typename M2
        >
    const matrix_op<op_conv_same<M1,M2,true> > xcorr_same (
        const matrix_exp<M1>& m1,
        const matrix_exp<M2>& m2
    )
    {
        COMPILE_TIME_ASSERT((is_same_type<typename M1::type,typename M2::type>::value == true));

        typedef op_conv_same<M1,M2,true> op;
        return matrix_op<op>(op(m1.ref(),m2.ref()));
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <typename M1, typename M2, bool flip_m2 = false>
    struct op_conv_valid
    {
        op_conv_valid( const M1& m1_, const M2& m2_) :
            m1(m1_),m2(m2_),
            nr_(m1.nr()-m2.nr()+1),
            nc_(m1.nc()-m2.nc()+1)
        {
            if (nr_ < 0 || nc_ <= 0 || m1.size() == 0 || m2.size() == 0)
                nr_ = 0;
            if (nc_ < 0 || nr_ <= 0 || m1.size() == 0 || m2.size() == 0)
                nc_ = 0;
        }

        const M1& m1;
        const M2& m2;
        long nr_;
        long nc_;

        const static long cost = (M1::cost+M2::cost)*10;
        const static long NR = (M1::NR*M2::NR==0) ? (0) : (M1::NR-M2::NR+1);
        const static long NC = (M1::NC*M2::NC==0) ? (0) : (M1::NC-M2::NC+1);
        typedef typename M1::type type;
        typedef type const_ret_type;
        typedef typename M1::mem_manager_type mem_manager_type;
        typedef typename M1::layout_type layout_type;

        const_ret_type apply (long r, long c) const
        {
            r += m2.nr()-1;
            c += m2.nc()-1;

            type temp = 0;

            const long min_rr = std::max<long>(r-m2.nr()+1, 0);
            const long max_rr = std::min<long>(m1.nr()-1, r);

            const long min_cc = std::max<long>(c-m2.nc()+1, 0);
            const long max_cc = std::min<long>(m1.nc()-1, c);

            for (long rr = min_rr; rr <= max_rr; ++rr)
            {
                for (long cc = min_cc; cc <= max_cc; ++cc)
                {
                    if (flip_m2)
                        temp += m1(rr,cc)*dlib::impl::conj(m2(m2.nr()-r+rr-1, m2.nc()-c+cc-1));
                    else
                        temp += m1(rr,cc)*m2(r-rr,c-cc);
                }
            }

            return temp;
        }

        long nr () const { return nr_; }
        long nc () const { return nc_; }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m1.aliases(item) || m2.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m1.aliases(item) || m2.aliases(item); }

    };

    template <
        typename M1,
        typename M2
        >
    const matrix_op<op_conv_valid<M1,M2> > conv_valid (
        const matrix_exp<M1>& m1,
        const matrix_exp<M2>& m2
    )
    {
        COMPILE_TIME_ASSERT((is_same_type<typename M1::type,typename M2::type>::value == true));

        typedef op_conv_valid<M1,M2> op;
        return matrix_op<op>(op(m1.ref(),m2.ref()));
    }

    template <
        typename M1,
        typename M2
        >
    const matrix_op<op_conv_valid<M1,M2,true> > xcorr_valid (
        const matrix_exp<M1>& m1,
        const matrix_exp<M2>& m2
    )
    {
        COMPILE_TIME_ASSERT((is_same_type<typename M1::type,typename M2::type>::value == true));

        typedef op_conv_valid<M1,M2,true> op;
        return matrix_op<op>(op(m1.ref(),m2.ref()));
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MATRIx_CONV_Hh_


dlib C++ Library - matrix_data_layout.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MATRIx_DATA_LAYOUT_
#define DLIB_MATRIx_DATA_LAYOUT_

#include "../algs.h"
#include "matrix_fwd.h"
#include "matrix_data_layout_abstract.h"

// GCC 4.8 gives false alarms about some matrix operations going out of bounds.  Disable
// these false warnings.
#if ( defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 8)
    #pragma GCC diagnostic ignored "-Warray-bounds"
#endif

namespace dlib
{

// ----------------------------------------------------------------------------------------

    /*!
        A matrix layout object is any object that contains a templated class called "layout"
        with an interface identical to one below:
        (Note that all the template arguments are just the template arguments from the dlib::matrix
        object and the member functions are defined identically to the ones with the same
        signatures inside the matrix object.)

        struct matrix_layout
        {
            template <
                typename T,
                long num_rows,
                long num_cols,
                typename mem_manager
                >
            class layout
            {
            public:

                T& operator() (
                    long r,
                    long c
                );

                const T& operator() (
                    long r,
                    long c
                );

                T& operator() (
                    long i
                );

                const T& operator() (
                    long i
                ) const;

                void swap(
                    layout& item
                );

                long nr (
                ) const;

                long nc (
                ) const;

                void set_size (
                    long nr_,
                    long nc_
                );
            };
        };
    !*/

// ----------------------------------------------------------------------------------------

    struct row_major_layout
    {
        // if a matrix is bigger than this many bytes then don't put it on the stack
        const static size_t max_stack_based_size = 256;

        // this is a hack to avoid a compile time error in visual studio 8.  I would just
        // use sizeof(T) and be done with it but that won't compile.  The idea here
        // is to avoid using the stack allocation of the layout object if it
        // is going to contain another matrix and also avoid asking for the sizeof()
        // the contained matrix.
        template <typename T>
        struct get_sizeof_helper
        {
            const static std::size_t val = sizeof(T);
        };

        template <typename T, long NR, long NC, typename mm, typename l>
        struct get_sizeof_helper<matrix<T,NR,NC,mm,l> >
        {
            const static std::size_t val = 1000000;
        };

        template <
            typename T,
            long num_rows,
            long num_cols,
            typename mem_manager,
            int val = static_switch <
                // when the sizes are all non zero and small
                (num_rows*num_cols*get_sizeof_helper<T>::val <= max_stack_based_size) && (num_rows != 0 && num_cols != 0),
            // when the sizes are all non zero and big
            (num_rows*num_cols*get_sizeof_helper<T>::val >  max_stack_based_size) && (num_rows != 0 && num_cols != 0),
            num_rows == 0 && num_cols != 0,
            num_rows != 0 && num_cols == 0,
            num_rows == 0 && num_cols == 0
            >::value
            >
        class layout ;
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object represents the actual allocation of space for a matrix.
                Small matrices allocate all their data on the stack and bigger ones
                use a memory_manager to get their memory.
        !*/

    // ------------------------------------------------------------------------------------

        template <
            typename T,
            long num_rows,
            long num_cols,
            typename mem_manager
            >
        class layout<T,num_rows,num_cols,mem_manager,1> : noncopyable // when the sizes are all non zero and small
        {
        public:
            const static long NR = num_rows;
            const static long NC = num_cols;

            layout() {}

            T& operator() (
                long r,
                long c
            ) { return *(data+r*num_cols + c); }

            const T& operator() (
                long r,
                long c
            ) const { return *(data+r*num_cols + c); }

            T& operator() (
                long i
            ) { return data[i]; }

            const T& operator() (
                long i
            ) const { return data[i]; }

            void swap(
                layout& item
            )
            {
                for (long r = 0; r < num_rows; ++r)
                {
                    for (long c = 0; c < num_cols; ++c)
                    {
                        exchange((*this)(r,c),item(r,c));
                    }
                }
            }

            long nr (
            ) const { return num_rows; }

            long nc (
            ) const { return num_cols; }

            void set_size (
                long ,
                long
            )
            {
            }

        private:
            T data[num_rows*num_cols];
        };

    // ------------------------------------------------------------------------------------

        template <
            typename T,
            long num_rows,
            long num_cols,
            typename mem_manager
            >
        class layout<T,num_rows,num_cols,mem_manager,2> : noncopyable // when the sizes are all non zero and big
        {
        public:
            const static long NR = num_rows;
            const static long NC = num_cols;

            layout (
            ) { data = pool.allocate_array(num_rows*num_cols); }

            ~layout ()
            { pool.deallocate_array(data); }

            T& operator() (
                long r,
                long c
            ) { return data[r*num_cols + c]; }

            const T& operator() (
                long r,
                long c
            ) const { return data[r*num_cols + c]; }

            T& operator() (
                long i
            ) { return data[i]; }

            const T& operator() (
                long i
            ) const { return data[i]; }

            void swap(
                layout& item
            )
            {
                std::swap(item.data,data);
                pool.swap(item.pool);
            }

            long nr (
            ) const { return num_rows; }

            long nc (
            ) const { return num_cols; }

            void set_size (
                long ,
                long
            )
            {
            }

        private:

            T* data;
            typename mem_manager::template rebind<T>::other pool;
            };

    // ------------------------------------------------------------------------------------

        template <
            typename T,
            long num_rows,
            long num_cols,
            typename mem_manager
            >
        class layout<T,num_rows,num_cols,mem_manager,3> : noncopyable // when num_rows == 0 && num_cols != 0,
        {
        public:
            const static long NR = num_rows;
            const static long NC = num_cols;

            layout (
            ):data(0), nr_(0) { }

            ~layout ()
            {
                if (data)
                    pool.deallocate_array(data);
            }

            T& operator() (
                long r,
                long c
            ) { return data[r*num_cols + c]; }

            const T& operator() (
                long r,
                long c
            ) const { return data[r*num_cols + c]; }

            T& operator() (
                long i
            ) { return data[i]; }

            const T& operator() (
                long i
            ) const { return data[i]; }

            void swap(
                layout& item
            )
            {
                std::swap(item.data,data);
                std::swap(item.nr_,nr_);
                pool.swap(item.pool);
            }

            long nr (
            ) const { return nr_; }

            long nc (
            ) const { return num_cols; }

            void set_size (
                long nr,
                long nc
            )
            {
                if (data)
                {
                    pool.deallocate_array(data);
                }
                data = pool.allocate_array(nr*nc);
                nr_ = nr;
            }

        private:

            T* data;
            long nr_;
            typename mem_manager::template rebind<T>::other pool;
            };

    // ------------------------------------------------------------------------------------

        template <
            typename T,
            long num_rows,
            long num_cols,
            typename mem_manager
            >
        class layout<T,num_rows,num_cols,mem_manager,4> : noncopyable // when num_rows != 0 && num_cols == 0
        {
        public:
            const static long NR = num_rows;
            const static long NC = num_cols;

            layout (
            ):data(0), nc_(0) { }

            ~layout ()
            {
                if (data)
                {
                    pool.deallocate_array(data);
                }
            }

            T& operator() (
                long r,
                long c
            ) { return data[r*nc_ + c]; }

            const T& operator() (
                long r,
                long c
            ) const { return data[r*nc_ + c]; }

            T& operator() (
                long i
            ) { return data[i]; }

            const T& operator() (
                long i
            ) const { return data[i]; }

            void swap(
                layout& item
            )
            {
                std::swap(item.data,data);
                std::swap(item.nc_,nc_);
                pool.swap(item.pool);
            }

            long nr (
            ) const { return num_rows; }

            long nc (
            ) const { return nc_; }

            void set_size (
                long nr,
                long nc
            )
            {
                if (data)
                {
                    pool.deallocate_array(data);
                }
                data = pool.allocate_array(nr*nc);
                nc_ = nc;
            }

        private:

            T* data;
            long nc_;
            typename mem_manager::template rebind<T>::other pool;
            };

    // ------------------------------------------------------------------------------------

        template <
            typename T,
            long num_rows,
            long num_cols,
            typename mem_manager
            >
        class layout<T,num_rows,num_cols,mem_manager,5> : noncopyable // when num_rows == 0 && num_cols == 0
        {
        public:
            const static long NR = num_rows;
            const static long NC = num_cols;

            layout (
            ):data(0), nr_(0), nc_(0) { }

            ~layout ()
            {
                if (data)
                {
                    pool.deallocate_array(data);
                }
            }

            T& operator() (
                long r,
                long c
            ) { return data[r*nc_ + c]; }

            const T& operator() (
                long r,
                long c
            ) const { return data[r*nc_ + c]; }

            T& operator() (
                long i
            ) { return data[i]; }

            const T& operator() (
                long i
            ) const { return data[i]; }

            void swap(
                layout& item
            )
            {
                std::swap(item.data,data);
                std::swap(item.nc_,nc_);
                std::swap(item.nr_,nr_);
                pool.swap(item.pool);
            }

            long nr (
            ) const { return nr_; }

            long nc (
            ) const { return nc_; }

            void set_size (
                long nr,
                long nc
            )
            {
                if (data)
                {
                    pool.deallocate_array(data);
                }
                data = pool.allocate_array(nr*nc);
                nr_ = nr;
                nc_ = nc;
            }

        private:
            T* data;
            long nr_;
            long nc_;
            typename mem_manager::template rebind<T>::other pool;
            };

    };

// ----------------------------------------------------------------------------------------

    struct column_major_layout
    {
        // if a matrix is bigger than this many bytes then don't put it on the stack
        const static size_t max_stack_based_size = 256;

        // this is a hack to avoid a compile time error in visual studio 8.  I would just
        // use sizeof(T) and be done with it but that won't compile.  The idea here
        // is to avoid using the stack allocation of the layout object if it
        // is going to contain another matrix and also avoid asking for the sizeof()
        // the contained matrix.
        template <typename T>
        struct get_sizeof_helper
        {
            const static std::size_t val = sizeof(T);
        };

        template <typename T, long NR, long NC, typename mm, typename l>
        struct get_sizeof_helper<matrix<T,NR,NC,mm,l> >
        {
            const static std::size_t val = 1000000;
        };

        template <
            typename T,
            long num_rows,
            long num_cols,
            typename mem_manager,
            int val = static_switch <
                // when the sizes are all non zero and small
                (num_rows*num_cols*get_sizeof_helper<T>::val <= max_stack_based_size) && (num_rows != 0 && num_cols != 0),
            // when the sizes are all non zero and big
            (num_rows*num_cols*get_sizeof_helper<T>::val > max_stack_based_size) && (num_rows != 0 && num_cols != 0),
            num_rows == 0 && num_cols != 0,
            num_rows != 0 && num_cols == 0,
            num_rows == 0 && num_cols == 0
            >::value
            >
        class layout ;
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object represents the actual allocation of space for a matrix.
                Small matrices allocate all their data on the stack and bigger ones
                use a memory_manager to get their memory.
        !*/

    // ------------------------------------------------------------------------------------

        template <
            typename T,
            long num_rows,
            long num_cols,
            typename mem_manager
            >
        class layout<T,num_rows,num_cols,mem_manager,1> : noncopyable // when the sizes are all non zero and small
        {
        public:
            const static long NR = num_rows;
            const static long NC = num_cols;

            layout() {}

            T& operator() (
                long r,
                long c
            ) { return *(data+c*num_rows + r); }

            const T& operator() (
                long r,
                long c
            ) const { return *(data+c*num_rows + r); }

            T& operator() (
                long i
            ) { return data[i]; }

            const T& operator() (
                long i
            ) const { return data[i]; }

            void swap(
                layout& item
            )
            {
                for (long r = 0; r < num_rows; ++r)
                {
                    for (long c = 0; c < num_cols; ++c)
                    {
                        exchange((*this)(r,c),item(r,c));
                    }
                }
            }

            long nr (
            ) const { return num_rows; }

            long nc (
            ) const { return num_cols; }

            void set_size (
                long,
                long
            )
            {
            }

        private:
            T data[num_cols*num_rows];
        };

    // ------------------------------------------------------------------------------------

        template <
            typename T,
            long num_rows,
            long num_cols,
            typename mem_manager
            >
        class layout<T,num_rows,num_cols,mem_manager,2> : noncopyable // when the sizes are all non zero and big
        {
        public:
            const static long NR = num_rows;
            const static long NC = num_cols;

            layout (
            ) { data = pool.allocate_array(num_rows*num_cols); }

            ~layout ()
            { pool.deallocate_array(data); }

            T& operator() (
                long r,
                long c
            ) { return data[c*num_rows + r]; }

            const T& operator() (
                long r,
                long c
            ) const { return data[c*num_rows + r]; }

            T& operator() (
                long i
            ) { return data[i]; }

            const T& operator() (
                long i
            ) const { return data[i]; }

            void swap(
                layout& item
            )
            {
                std::swap(item.data,data);
                pool.swap(item.pool);
            }

            long nr (
            ) const { return num_rows; }

            long nc (
            ) const { return num_cols; }

            void set_size (
                long ,
                long
            )
            {
            }

        private:

            T* data;
            typename mem_manager::template rebind<T>::other pool;
            };

    // ------------------------------------------------------------------------------------

        template <
            typename T,
            long num_rows,
            long num_cols,
            typename mem_manager
            >
        class layout<T,num_rows,num_cols,mem_manager,3> : noncopyable // when num_rows == 0 && num_cols != 0,
        {
        public:
            const static long NR = num_rows;
            const static long NC = num_cols;

            layout (
            ):data(0), nr_(0) { }

            ~layout ()
            {
                if (data)
                    pool.deallocate_array(data);
            }

            T& operator() (
                long r,
                long c
            ) { return data[c*nr_ + r]; }

            const T& operator() (
                long r,
                long c
            ) const { return data[c*nr_ + r]; }

            T& operator() (
                long i
            ) { return data[i]; }

            const T& operator() (
                long i
            ) const { return data[i]; }

            void swap(
                layout& item
            )
            {
                std::swap(item.data,data);
                std::swap(item.nr_,nr_);
                pool.swap(item.pool);
            }

            long nr (
            ) const { return nr_; }

            long nc (
            ) const { return num_cols; }

            void set_size (
                long nr,
                long nc
            )
            {
                if (data)
                {
                    pool.deallocate_array(data);
                }
                data = pool.allocate_array(nr*nc);
                nr_ = nr;
            }

        private:

            T* data;
            long nr_;
            typename mem_manager::template rebind<T>::other pool;
            };

    // ------------------------------------------------------------------------------------

        template <
            typename T,
            long num_rows,
            long num_cols,
            typename mem_manager
            >
        class layout<T,num_rows,num_cols,mem_manager,4> : noncopyable // when num_rows != 0 && num_cols == 0
        {
        public:
            const static long NR = num_rows;
            const static long NC = num_cols;

            layout (
            ):data(0), nc_(0) { }

            ~layout ()
            {
                if (data)
                {
                    pool.deallocate_array(data);
                }
            }

            T& operator() (
                long r,
                long c
            ) { return data[c*num_rows + r]; }

            const T& operator() (
                long r,
                long c
            ) const { return data[c*num_rows + r]; }

            T& operator() (
                long i
            ) { return data[i]; }

            const T& operator() (
                long i
            ) const { return data[i]; }

            void swap(
                layout& item
            )
            {
                std::swap(item.data,data);
                std::swap(item.nc_,nc_);
                pool.swap(item.pool);
            }

            long nr (
            ) const { return num_rows; }

            long nc (
            ) const { return nc_; }

            void set_size (
                long nr,
                long nc
            )
            {
                if (data)
                {
                    pool.deallocate_array(data);
                }
                data = pool.allocate_array(nr*nc);
                nc_ = nc;
            }

        private:

            T* data;
            long nc_;
            typename mem_manager::template rebind<T>::other pool;
            };

    // ------------------------------------------------------------------------------------

        template <
            typename T,
            long num_rows,
            long num_cols,
            typename mem_manager
            >
        class layout<T,num_rows,num_cols,mem_manager,5> : noncopyable // when num_rows == 0 && num_cols == 0
        {
        public:
            const static long NR = num_rows;
            const static long NC = num_cols;

            layout (
            ):data(0), nr_(0), nc_(0) { }

            ~layout ()
            {
                if (data)
                {
                    pool.deallocate_array(data);
                }
            }

            T& operator() (
                long r,
                long c
            ) { return data[c*nr_ + r]; }

            const T& operator() (
                long r,
                long c
            ) const { return data[c*nr_ + r]; }

            T& operator() (
                long i
            ) { return data[i]; }

            const T& operator() (
                long i
            ) const { return data[i]; }

            void swap(
                layout& item
            )
            {
                std::swap(item.data,data);
                std::swap(item.nc_,nc_);
                std::swap(item.nr_,nr_);
                pool.swap(item.pool);
            }

            long nr (
            ) const { return nr_; }

            long nc (
            ) const { return nc_; }

            void set_size (
                long nr,
                long nc
            )
            {
                if (data)
                {
                    pool.deallocate_array(data);
                }
                data = pool.allocate_array(nr*nc);
                nr_ = nr;
                nc_ = nc;
            }

        private:
            T* data;
            long nr_;
            long nc_;
            typename mem_manager::template rebind<T>::other pool;
            };

    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MATRIx_DATA_LAYOUT_


dlib C++ Library - matrix_data_layout_abstract.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_MATRIx_DATA_LAYOUT_ABSTRACT_
#ifdef DLIB_MATRIx_DATA_LAYOUT_ABSTRACT_

#include "../algs.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    struct row_major_layout
    {
        /*!
            This is the default matrix layout.  Any matrix object that uses this
            layout will be laid out in memory in row major order.  Additionally,
            all elements are contiguous (e.g. there isn't any padding at the ends of
            rows or anything like that)
        !*/
    };

// ----------------------------------------------------------------------------------------

    struct column_major_layout
    {
        /*!
            Any matrix object that uses this layout will be laid out in memory in
            column major order.  Additionally, all elements are contiguous (e.g.
            there isn't any padding at the ends of rows or anything like that)
        !*/
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MATRIx_DATA_LAYOUT_ABSTRACT_


dlib C++ Library - matrix_default_mul.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MATRIx_DEFAULT_MULTIPLY_
#define DLIB_MATRIx_DEFAULT_MULTIPLY_

#include "../geometry/rectangle.h"
#include "matrix.h"
#include "matrix_utilities.h"
#include "../enable_if.h"

namespace dlib
{

// ------------------------------------------------------------------------------------

    namespace ma
    {
        template < typename EXP, typename enable = void >
        struct matrix_is_vector { static const bool value = false; };
        template < typename EXP >
        struct matrix_is_vector<EXP, typename enable_if_c<EXP::NR==1 || EXP::NC==1>::type > { static const bool value = true; };
    }

// ------------------------------------------------------------------------------------

    /*!  This file defines the default_matrix_multiply() function.  It is a function
         that conforms to the following definition:

        template <
            typename matrix_dest_type,
            typename EXP1,
            typename EXP2
            >
        void default_matrix_multiply (
            matrix_dest_type& dest,
            const EXP1& lhs,
            const EXP2& rhs
        );
            requires
                - (lhs*rhs).destructively_aliases(dest) == false
                - dest.nr() == (lhs*rhs).nr()
                - dest.nc() == (lhs*rhs).nc()
            ensures
                - #dest == dest + lhs*rhs
    !*/

// ------------------------------------------------------------------------------------

    template <
        typename matrix_dest_type,
        typename EXP1,
        typename EXP2
        >
    typename enable_if_c<ma::matrix_is_vector<EXP1>::value == true || ma::matrix_is_vector<EXP2>::value == true>::type
    default_matrix_multiply (
        matrix_dest_type& dest,
        const EXP1& lhs,
        const EXP2& rhs
    )
    {
        matrix_assign_default(dest, lhs*rhs, 1, true);
    }

// ------------------------------------------------------------------------------------

    template <
        typename matrix_dest_type,
        typename EXP1,
        typename EXP2
        >
    typename enable_if_c<ma::matrix_is_vector<EXP1>::value == false && ma::matrix_is_vector<EXP2>::value == false>::type
    default_matrix_multiply (
        matrix_dest_type& dest,
        const EXP1& lhs,
        const EXP2& rhs
    )
    {
        const long bs = 90;

        // if the matrices are small enough then just use the simple multiply algorithm
        if (lhs.nc() <= 2 || rhs.nc() <= 2 || lhs.nr() <= 2 || rhs.nr() <= 2 || (lhs.size() <= bs*10 && rhs.size() <= bs*10) )
        {
            matrix_assign_default(dest, lhs*rhs, 1, true);
        }
        else
        {
            // if the lhs and rhs matrices are big enough we should use a cache friendly
            // algorithm that computes the matrix multiply in blocks.

            // Loop over all the blocks in the lhs matrix
            for (long r = 0; r < lhs.nr(); r+=bs)
            {
                for (long c = 0; c < lhs.nc(); c+=bs)
                {
                    // make a rect for the block from lhs
                    rectangle lhs_block(c, r, std::min(c+bs-1,lhs.nc()-1), std::min(r+bs-1,lhs.nr()-1));

                    // now loop over all the rhs blocks we have to multiply with the current lhs block
                    for (long i = 0; i < rhs.nc(); i += bs)
                    {
                        // make a rect for the block from rhs
                        rectangle rhs_block(i, c, std::min(i+bs-1,rhs.nc()-1), std::min(c+bs-1,rhs.nr()-1));

                        // make a target rect in res
                        rectangle res_block(rhs_block.left(),lhs_block.top(), rhs_block.right(), lhs_block.bottom());

                        // This loop is optimized assuming that the data is laid out in
                        // row major order in memory.
                        for (long r = lhs_block.top(); r <= lhs_block.bottom(); ++r)
                        {
                            for (long c = lhs_block.left(); c<= lhs_block.right(); ++c)
                            {
                                const typename EXP2::type temp = lhs(r,c);
                                for (long i = rhs_block.left(); i <= rhs_block.right(); ++i)
                                {
                                    dest(r,i) += rhs(c,i)*temp;
                                }
                            }
                        }
                    }
                }
            }
        }

    }

// ------------------------------------------------------------------------------------

}

#endif // DLIB_MATRIx_DEFAULT_MULTIPLY_


dlib C++ Library - matrix_eigenvalue.h

// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
// This code was adapted from code from the JAMA part of NIST's TNT library.
//    See: http://math.nist.gov/tnt/
#ifndef DLIB_MATRIX_EIGENVALUE_DECOMPOSITION_H
#define DLIB_MATRIX_EIGENVALUE_DECOMPOSITION_H

#include "matrix.h"
#include "matrix_utilities.h"
#include "matrix_subexp.h"
#include <algorithm>
#include <complex>
#include <cmath>

#ifdef DLIB_USE_LAPACK
#include "lapack/geev.h"
#include "lapack/syev.h"
#include "lapack/syevr.h"
#endif

#define DLIB_LAPACK_EIGENVALUE_DECOMP_SIZE_THRESH 4

namespace dlib
{

    template <
        typename matrix_exp_type
        >
    class eigenvalue_decomposition
    {

    public:

        const static long NR = matrix_exp_type::NR;
        const static long NC = matrix_exp_type::NC;
        typedef typename matrix_exp_type::type type;
        typedef typename matrix_exp_type::mem_manager_type mem_manager_type;
        typedef typename matrix_exp_type::layout_type layout_type;

        typedef typename matrix_exp_type::matrix_type matrix_type;
        typedef matrix<type,NR,1,mem_manager_type,layout_type> column_vector_type;

        typedef matrix<std::complex<type>,0,0,mem_manager_type,layout_type> complex_matrix_type;
        typedef matrix<std::complex<type>,NR,1,mem_manager_type,layout_type> complex_column_vector_type;

        // You have supplied an invalid type of matrix_exp_type.  You have
        // to use this object with matrices that contain float or double type data.
        COMPILE_TIME_ASSERT((is_same_type<float, type>::value ||
                             is_same_type<double, type>::value ));

        template <typename EXP>
        eigenvalue_decomposition(
            const matrix_exp<EXP>& A
        );

        template <typename EXP>
        eigenvalue_decomposition(
            const matrix_op<op_make_symmetric<EXP> >& A
        );

        long dim (
        ) const;

        const complex_column_vector_type get_eigenvalues (
        ) const;

        const column_vector_type& get_real_eigenvalues (
        ) const;

        const column_vector_type& get_imag_eigenvalues (
        ) const;

        const complex_matrix_type get_v (
        ) const;

        const complex_matrix_type get_d (
        ) const;

        const matrix_type& get_pseudo_v (
        ) const;

        const matrix_type get_pseudo_d (
        ) const;

    private:

        /** Row and column dimension (square matrix).  */
        long n;

        bool issymmetric;

        /** Arrays for internal storage of eigenvalues. */

        column_vector_type d;         /* real part */
        column_vector_type e;         /* img part */

        /** Array for internal storage of eigenvectors. */
        matrix_type V;

        /** Array for internal storage of nonsymmetric Hessenberg form.
        @serial internal storage of nonsymmetric Hessenberg form.
        */
        matrix_type H;

        /** Working storage for nonsymmetric algorithm.
        @serial working storage for nonsymmetric algorithm.
        */
        column_vector_type ort;

        // Symmetric Householder reduction to tridiagonal form.
        void tred2();

        // Symmetric tridiagonal QL algorithm.
        void tql2 ();

        // Nonsymmetric reduction to Hessenberg form.
        void orthes ();

        // Complex scalar division.
        type cdivr, cdivi;
        void cdiv_(type xr, type xi, type yr, type yi);

        // Nonsymmetric reduction from Hessenberg to real Schur form.
        void hqr2 ();
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                        Public member functions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <typename matrix_exp_type>
    template <typename EXP>
    eigenvalue_decomposition<matrix_exp_type>::
    eigenvalue_decomposition(
        const matrix_exp<EXP>& A_
    )
    {
        COMPILE_TIME_ASSERT((is_same_type<type, typename EXP::type>::value));

        const_temp_matrix<EXP> A(A_);

        // make sure requires clause is not broken
        DLIB_ASSERT(A.nr() == A.nc() && A.size() > 0,
            "\teigenvalue_decomposition::eigenvalue_decomposition(A)"
            << "\n\tYou can only use this on square matrices"
            << "\n\tA.nr():   " << A.nr()
            << "\n\tA.nc():   " << A.nc()
            << "\n\tA.size(): " << A.size()
            << "\n\tthis:     " << this
            );

        n = A.nc();
        V.set_size(n,n);
        d.set_size(n);
        e.set_size(n);

        issymmetric = true;
        for (long j = 0; (j < n) && issymmetric; j++)
        {
            for (long i = 0; (i < n) && issymmetric; i++)
            {
                issymmetric = (A(i,j) == A(j,i));
            }
        }

        if (issymmetric)
        {
            V = A;

#ifdef DLIB_USE_LAPACK
            if (A.nr() > DLIB_LAPACK_EIGENVALUE_DECOMP_SIZE_THRESH)
            {
                e = 0;

                // We could compute the result using syev()
                //lapack::syev('V', 'L', V,  d);

                // Instead, we use syevr because its faster and maybe more stable.
                matrix_type tempA(A);
                matrix<lapack::integer,0,0,mem_manager_type,layout_type> isupz;

                lapack::integer temp;
                lapack::syevr('V','A','L',tempA,0,0,0,0,-1,temp,d,V,isupz);
                return;
            }
#endif
            // Tridiagonalize.
            tred2();

            // Diagonalize.
            tql2();

        }
        else
        {

#ifdef DLIB_USE_LAPACK
            if (A.nr() > DLIB_LAPACK_EIGENVALUE_DECOMP_SIZE_THRESH)
            {
                matrix<type,0,0,mem_manager_type, column_major_layout> temp, vl, vr;
                temp = A;
                lapack::geev('N', 'V', temp, d, e, vl, vr);
                V = vr;
                return;
            }
#endif
            H = A;

            ort.set_size(n);

            // Reduce to Hessenberg form.
            orthes();

            // Reduce Hessenberg to real Schur form.
            hqr2();
        }
    }

// ----------------------------------------------------------------------------------------

    template <typename matrix_exp_type>
    template <typename EXP>
    eigenvalue_decomposition<matrix_exp_type>::
    eigenvalue_decomposition(
        const matrix_op<op_make_symmetric<EXP> >& A
    )
    {
        COMPILE_TIME_ASSERT((is_same_type<type, typename EXP::type>::value));

        // make sure requires clause is not broken
        DLIB_ASSERT(A.nr() == A.nc() && A.size() > 0,
            "\teigenvalue_decomposition::eigenvalue_decomposition(A)"
            << "\n\tYou can only use this on square matrices"
            << "\n\tA.nr():   " << A.nr()
            << "\n\tA.nc():   " << A.nc()
            << "\n\tA.size(): " << A.size()
            << "\n\tthis:     " << this
            );

        n = A.nc();
        V.set_size(n,n);
        d.set_size(n);
        e.set_size(n);

        V = A;

#ifdef DLIB_USE_LAPACK
        if (A.nr() > DLIB_LAPACK_EIGENVALUE_DECOMP_SIZE_THRESH)
        {
            e = 0;

            // We could compute the result using syev()
            //lapack::syev('V', 'L', V,  d);

            // Instead, we use syevr because its faster and maybe more stable.
            matrix_type tempA(A);
            matrix<lapack::integer,0,0,mem_manager_type,layout_type> isupz;

            lapack::integer temp;
            lapack::syevr('V','A','L',tempA,0,0,0,0,-1,temp,d,V,isupz);
            return;
        }
#endif
        // Tridiagonalize.
        tred2();

        // Diagonalize.
        tql2();

    }

// ----------------------------------------------------------------------------------------

    template <typename matrix_exp_type>
    const typename eigenvalue_decomposition<matrix_exp_type>::matrix_type& eigenvalue_decomposition<matrix_exp_type>::
    get_pseudo_v (
    ) const
    {
        return V;
    }

// ----------------------------------------------------------------------------------------

    template <typename matrix_exp_type>
    long eigenvalue_decomposition<matrix_exp_type>::
    dim (
    ) const
    {
        return V.nr();
    }

// ----------------------------------------------------------------------------------------

    template <typename matrix_exp_type>
    const typename eigenvalue_decomposition<matrix_exp_type>::complex_column_vector_type eigenvalue_decomposition<matrix_exp_type>::
    get_eigenvalues (
    ) const
    {
        return complex_matrix(get_real_eigenvalues(), get_imag_eigenvalues());
    }

// ----------------------------------------------------------------------------------------

    template <typename matrix_exp_type>
    const typename eigenvalue_decomposition<matrix_exp_type>::column_vector_type& eigenvalue_decomposition<matrix_exp_type>::
    get_real_eigenvalues (
    ) const
    {
        return d;
    }

// ----------------------------------------------------------------------------------------

    template <typename matrix_exp_type>
    const typename eigenvalue_decomposition<matrix_exp_type>::column_vector_type& eigenvalue_decomposition<matrix_exp_type>::
    get_imag_eigenvalues (
    ) const
    {
        return e;
    }

// ----------------------------------------------------------------------------------------

    template <typename matrix_exp_type>
    const typename eigenvalue_decomposition<matrix_exp_type>::complex_matrix_type eigenvalue_decomposition<matrix_exp_type>::
    get_d (
    ) const
    {
        return diagm(complex_matrix(get_real_eigenvalues(), get_imag_eigenvalues()));
    }

// ----------------------------------------------------------------------------------------

    template <typename matrix_exp_type>
    const typename eigenvalue_decomposition<matrix_exp_type>::complex_matrix_type eigenvalue_decomposition<matrix_exp_type>::
    get_v (
    ) const
    {
        complex_matrix_type CV(n,n);

        for (long i = 0; i < n; i++)
        {
            if (e(i) > 0)
            {
                set_colm(CV,i) = complex_matrix(colm(V,i), colm(V,i+1));
            }
            else if (e(i) < 0)
            {
                set_colm(CV,i) = complex_matrix(colm(V,i), colm(V,i-1));
            }
            else
            {
                set_colm(CV,i) = complex_matrix(colm(V,i), uniform_matrix<type>(n,1,0));
            }
        }

        return CV;
    }

// ----------------------------------------------------------------------------------------

    template <typename matrix_exp_type>
    const typename eigenvalue_decomposition<matrix_exp_type>::matrix_type eigenvalue_decomposition<matrix_exp_type>::
    get_pseudo_d (
    ) const
    {
        matrix_type D(n,n);

        for (long i = 0; i < n; i++)
        {
            for (long j = 0; j < n; j++)
            {
                D(i,j) = 0.0;
            }
            D(i,i) = d(i);
            if (e(i) > 0)
            {
                D(i,i+1) = e(i);
            }
            else if (e(i) < 0)
            {
                D(i,i-1) = e(i);
            }
        }

        return D;
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                        Private member functions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

// Symmetric Householder reduction to tridiagonal form.
    template <typename matrix_exp_type>
    void eigenvalue_decomposition<matrix_exp_type>::
    tred2()
    {
        using std::abs;
        using std::sqrt;

        //  This is derived from the Algol procedures tred2 by
        //  Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
        //  Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
        //  Fortran subroutine in EISPACK.

        for (long j = 0; j < n; j++)
        {
            d(j) = V(n-1,j);
        }

        // Householder reduction to tridiagonal form.

        for (long i = n-1; i > 0; i--)
        {

            // Scale to avoid under/overflow.

            type scale = 0.0;
            type h = 0.0;
            for (long k = 0; k < i; k++)
            {
                scale = scale + abs(d(k));
            }
            if (scale == 0.0)
            {
                e(i) = d(i-1);
                for (long j = 0; j < i; j++)
                {
                    d(j) = V(i-1,j);
                    V(i,j) = 0.0;
                    V(j,i) = 0.0;
                }
            }
            else
            {

                // Generate Householder vector.

                for (long k = 0; k < i; k++)
                {
                    d(k) /= scale;
                    h += d(k) * d(k);
                }
                type f = d(i-1);
                type g = sqrt(h);
                if (f > 0)
                {
                    g = -g;
                }
                e(i) = scale * g;
                h = h - f * g;
                d(i-1) = f - g;
                for (long j = 0; j < i; j++)
                {
                    e(j) = 0.0;
                }

                // Apply similarity transformation to remaining columns.

                for (long j = 0; j < i; j++)
                {
                    f = d(j);
                    V(j,i) = f;
                    g = e(j) + V(j,j) * f;
                    for (long k = j+1; k <= i-1; k++)
                    {
                        g += V(k,j) * d(k);
                        e(k) += V(k,j) * f;
                    }
                    e(j) = g;
                }
                f = 0.0;
                for (long j = 0; j < i; j++)
                {
                    e(j) /= h;
                    f += e(j) * d(j);
                }
                type hh = f / (h + h);
                for (long j = 0; j < i; j++)
                {
                    e(j) -= hh * d(j);
                }
                for (long j = 0; j < i; j++)
                {
                    f = d(j);
                    g = e(j);
                    for (long k = j; k <= i-1; k++)
                    {
                        V(k,j) -= (f * e(k) + g * d(k));
                    }
                    d(j) = V(i-1,j);
                    V(i,j) = 0.0;
                }
            }
            d(i) = h;
        }

        // Accumulate transformations.

        for (long i = 0; i < n-1; i++)
        {
            V(n-1,i) = V(i,i);
            V(i,i) = 1.0;
            type h = d(i+1);
            if (h != 0.0)
            {
                for (long k = 0; k <= i; k++)
                {
                    d(k) = V(k,i+1) / h;
                }
                for (long j = 0; j <= i; j++)
                {
                    type g = 0.0;
                    for (long k = 0; k <= i; k++)
                    {
                        g += V(k,i+1) * V(k,j);
                    }
                    for (long k = 0; k <= i; k++)
                    {
                        V(k,j) -= g * d(k);
                    }
                }
            }
            for (long k = 0; k <= i; k++)
            {
                V(k,i+1) = 0.0;
            }
        }
        for (long j = 0; j < n; j++)
        {
            d(j) = V(n-1,j);
            V(n-1,j) = 0.0;
        }
        V(n-1,n-1) = 1.0;
        e(0) = 0.0;
    }

// ----------------------------------------------------------------------------------------

    template <typename matrix_exp_type>
    void eigenvalue_decomposition<matrix_exp_type>::
    tql2 ()
    {
        using std::pow;
        using std::min;
        using std::max;
        using std::abs;

        //  This is derived from the Algol procedures tql2, by
        //  Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
        //  Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
        //  Fortran subroutine in EISPACK.

        for (long i = 1; i < n; i++)
        {
            e(i-1) = e(i);
        }
        e(n-1) = 0.0;

        type f = 0.0;
        type tst1 = 0.0;
        const type eps = std::numeric_limits<type>::epsilon();
        for (long l = 0; l < n; l++)
        {

            // Find small subdiagonal element

            tst1 = max(tst1,abs(d(l)) + abs(e(l)));
            long m = l;

            // Original while-loop from Java code
            while (m < n)
            {
                if (abs(e(m)) <= eps*tst1)
                {
                    break;
                }
                m++;
            }
            if (m == n)
                --m;

            // If m == l, d(l) is an eigenvalue,
            // otherwise, iterate.

            if (m > l)
            {
                long iter = 0;
                do
                {
                    iter = iter + 1;  // (Could check iteration count here.)

                    // Compute implicit shift

                    type g = d(l);
                    type p = (d(l+1) - g) / (2.0 * e(l));
                    type r = hypot(p,1.0);
                    if (p < 0)
                    {
                        r = -r;
                    }
                    d(l) = e(l) / (p + r);
                    d(l+1) = e(l) * (p + r);
                    type dl1 = d(l+1);
                    type h = g - d(l);
                    for (long i = l+2; i < n; i++)
                    {
                        d(i) -= h;
                    }
                    f = f + h;

                    // Implicit QL transformation.

                    p = d(m);
                    type c = 1.0;
                    type c2 = c;
                    type c3 = c;
                    type el1 = e(l+1);
                    type s = 0.0;
                    type s2 = 0.0;
                    for (long i = m-1; i >= l; i--)
                    {
                        c3 = c2;
                        c2 = c;
                        s2 = s;
                        g = c * e(i);
                        h = c * p;
                        r = hypot(p,e(i));
                        e(i+1) = s * r;
                        s = e(i) / r;
                        c = p / r;
                        p = c * d(i) - s * g;
                        d(i+1) = h + s * (c * g + s * d(i));

                        // Accumulate transformation.

                        for (long k = 0; k < n; k++)
                        {
                            h = V(k,i+1);
                            V(k,i+1) = s * V(k,i) + c * h;
                            V(k,i) = c * V(k,i) - s * h;
                        }
                    }
                    p = -s * s2 * c3 * el1 * e(l) / dl1;
                    e(l) = s * p;
                    d(l) = c * p;

                    // Check for convergence.

                } while (abs(e(l)) > eps*tst1);
            }
            d(l) = d(l) + f;
            e(l) = 0.0;
        }

        /*
            The code to sort the eigenvalues and eigenvectors
            has been removed from here since, in the non-symmetric case,
            we can't sort the eigenvalues in a meaningful way.  If we left this
            code in here then the user might supply what they thought was a symmetric
            matrix but was actually slightly non-symmetric due to rounding error
            and then they would end up in the non-symmetric eigenvalue solver
            where the eigenvalues don't end up getting sorted.  So to avoid
            any possible user confusion I'm just removing this.
        */
    }

// ----------------------------------------------------------------------------------------

    template <typename matrix_exp_type>
    void eigenvalue_decomposition<matrix_exp_type>::
    orthes ()
    {
        using std::abs;
        using std::sqrt;

        //  This is derived from the Algol procedures orthes and ortran,
        //  by Martin and Wilkinson, Handbook for Auto. Comp.,
        //  Vol.ii-Linear Algebra, and the corresponding
        //  Fortran subroutines in EISPACK.

        long low = 0;
        long high = n-1;

        for (long m = low+1; m <= high-1; m++)
        {

            // Scale column.

            type scale = 0.0;
            for (long i = m; i <= high; i++)
            {
                scale = scale + abs(H(i,m-1));
            }
            if (scale != 0.0)
            {

                // Compute Householder transformation.

                type h = 0.0;
                for (long i = high; i >= m; i--)
                {
                    ort(i) = H(i,m-1)/scale;
                    h += ort(i) * ort(i);
                }
                type g = sqrt(h);
                if (ort(m) > 0)
                {
                    g = -g;
                }
                h = h - ort(m) * g;
                ort(m) = ort(m) - g;

                // Apply Householder similarity transformation
                // H = (I-u*u'/h)*H*(I-u*u')/h)

                for (long j = m; j < n; j++)
                {
                    type f = 0.0;
                    for (long i = high; i >= m; i--)
                    {
                        f += ort(i)*H(i,j);
                    }
                    f = f/h;
                    for (long i = m; i <= high; i++)
                    {
                        H(i,j) -= f*ort(i);
                    }
                }

                for (long i = 0; i <= high; i++)
                {
                    type f = 0.0;
                    for (long j = high; j >= m; j--)
                    {
                        f += ort(j)*H(i,j);
                    }
                    f = f/h;
                    for (long j = m; j <= high; j++)
                    {
                        H(i,j) -= f*ort(j);
                    }
                }
                ort(m) = scale*ort(m);
                H(m,m-1) = scale*g;
            }
        }

        // Accumulate transformations (Algol's ortran).

        for (long i = 0; i < n; i++)
        {
            for (long j = 0; j < n; j++)
            {
                V(i,j) = (i == j ? 1.0 : 0.0);
            }
        }

        for (long m = high-1; m >= low+1; m--)
        {
            if (H(m,m-1) != 0.0)
            {
                for (long i = m+1; i <= high; i++)
                {
                    ort(i) = H(i,m-1);
                }
                for (long j = m; j <= high; j++)
                {
                    type g = 0.0;
                    for (long i = m; i <= high; i++)
                    {
                        g += ort(i) * V(i,j);
                    }
                    // Double division avoids possible underflow
                    g = (g / ort(m)) / H(m,m-1);
                    for (long i = m; i <= high; i++)
                    {
                        V(i,j) += g * ort(i);
                    }
                }
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <typename matrix_exp_type>
    void eigenvalue_decomposition<matrix_exp_type>::
    cdiv_(type xr, type xi, type yr, type yi)
    {
        using std::abs;
        type r,d;
        if (abs(yr) > abs(yi))
        {
            r = yi/yr;
            d = yr + r*yi;
            cdivr = (xr + r*xi)/d;
            cdivi = (xi - r*xr)/d;
        }
        else
        {
            r = yr/yi;
            d = yi + r*yr;
            cdivr = (r*xr + xi)/d;
            cdivi = (r*xi - xr)/d;
        }
    }

// ----------------------------------------------------------------------------------------

    template <typename matrix_exp_type>
    void eigenvalue_decomposition<matrix_exp_type>::
    hqr2 ()
    {
        using std::pow;
        using std::min;
        using std::max;
        using std::abs;
        using std::sqrt;

        //  This is derived from the Algol procedure hqr2,
        //  by Martin and Wilkinson, Handbook for Auto. Comp.,
        //  Vol.ii-Linear Algebra, and the corresponding
        //  Fortran subroutine in EISPACK.

        // Initialize

        long nn = this->n;
        long n = nn-1;
        long low = 0;
        long high = nn-1;
        const type eps = std::numeric_limits<type>::epsilon();
        type exshift = 0.0;
        type p=0,q=0,r=0,s=0,z=0,t,w,x,y;

        // Store roots isolated by balanc and compute matrix norm

        type norm = 0.0;
        for (long i = 0; i < nn; i++)
        {
            if ((i < low) || (i > high))
            {
                d(i) = H(i,i);
                e(i) = 0.0;
            }
            for (long j = max(i-1,0L); j < nn; j++)
            {
                norm = norm + abs(H(i,j));
            }
        }

        // Outer loop over eigenvalue index

        long iter = 0;
        while (n >= low)
        {

            // Look for single small sub-diagonal element

            long l = n;
            while (l > low)
            {
                s = abs(H(l-1,l-1)) + abs(H(l,l));
                if (s == 0.0)
                {
                    s = norm;
                }
                if (abs(H(l,l-1)) < eps * s)
                {
                    break;
                }
                l--;
            }

            // Check for convergence
            // One root found

            if (l == n)
            {
                H(n,n) = H(n,n) + exshift;
                d(n) = H(n,n);
                e(n) = 0.0;
                n--;
                iter = 0;

                // Two roots found

            }
            else if (l == n-1)
            {
                w = H(n,n-1) * H(n-1,n);
                p = (H(n-1,n-1) - H(n,n)) / 2.0;
                q = p * p + w;
                z = sqrt(abs(q));
                H(n,n) = H(n,n) + exshift;
                H(n-1,n-1) = H(n-1,n-1) + exshift;
                x = H(n,n);

                // type pair

                if (q >= 0)
                {
                    if (p >= 0)
                    {
                        z = p + z;
                    }
                    else
                    {
                        z = p - z;
                    }
                    d(n-1) = x + z;
                    d(n) = d(n-1);
                    if (z != 0.0)
                    {
                        d(n) = x - w / z;
                    }
                    e(n-1) = 0.0;
                    e(n) = 0.0;
                    x = H(n,n-1);
                    s = abs(x) + abs(z);
                    p = x / s;
                    q = z / s;
                    r = sqrt(p * p+q * q);
                    p = p / r;
                    q = q / r;

                    // Row modification

                    for (long j = n-1; j < nn; j++)
                    {
                        z = H(n-1,j);
                        H(n-1,j) = q * z + p * H(n,j);
                        H(n,j) = q * H(n,j) - p * z;
                    }

                    // Column modification

                    for (long i = 0; i <= n; i++)
                    {
                        z = H(i,n-1);
                        H(i,n-1) = q * z + p * H(i,n);
                        H(i,n) = q * H(i,n) - p * z;
                    }

                    // Accumulate transformations

                    for (long i = low; i <= high; i++)
                    {
                        z = V(i,n-1);
                        V(i,n-1) = q * z + p * V(i,n);
                        V(i,n) = q * V(i,n) - p * z;
                    }

                    // Complex pair

                }
                else
                {
                    d(n-1) = x + p;
                    d(n) = x + p;
                    e(n-1) = z;
                    e(n) = -z;
                }
                n = n - 2;
                iter = 0;

                // No convergence yet

            }
            else
            {

                // Form shift

                x = H(n,n);
                y = 0.0;
                w = 0.0;
                if (l < n)
                {
                    y = H(n-1,n-1);
                    w = H(n,n-1) * H(n-1,n);
                }

                // Wilkinson's original ad hoc shift

                if (iter == 10)
                {
                    exshift += x;
                    for (long i = low; i <= n; i++)
                    {
                        H(i,i) -= x;
                    }
                    s = abs(H(n,n-1)) + abs(H(n-1,n-2));
                    x = y = 0.75 * s;
                    w = -0.4375 * s * s;
                }

                // MATLAB's new ad hoc shift

                if (iter == 30)
                {
                    s = (y - x) / 2.0;
                    s = s * s + w;
                    if (s > 0)
                    {
                        s = sqrt(s);
                        if (y < x)
                        {
                            s = -s;
                        }
                        s = x - w / ((y - x) / 2.0 + s);
                        for (long i = low; i <= n; i++)
                        {
                            H(i,i) -= s;
                        }
                        exshift += s;
                        x = y = w = 0.964;
                    }
                }

                iter = iter + 1;   // (Could check iteration count here.)

                // Look for two consecutive small sub-diagonal elements

                long m = n-2;
                while (m >= l)
                {
                    z = H(m,m);
                    r = x - z;
                    s = y - z;
                    p = (r * s - w) / H(m+1,m) + H(m,m+1);
                    q = H(m+1,m+1) - z - r - s;
                    r = H(m+2,m+1);
                    s = abs(p) + abs(q) + abs(r);
                    p = p / s;
                    q = q / s;
                    r = r / s;
                    if (m == l)
                    {
                        break;
                    }
                    if (abs(H(m,m-1)) * (abs(q) + abs(r)) <
                        eps * (abs(p) * (abs(H(m-1,m-1)) + abs(z) +
                                         abs(H(m+1,m+1)))))
                    {
                        break;
                    }
                    m--;
                }

                for (long i = m+2; i <= n; i++)
                {
                    H(i,i-2) = 0.0;
                    if (i > m+2)
                    {
                        H(i,i-3) = 0.0;
                    }
                }

                // Double QR step involving rows l:n and columns m:n

                for (long k = m; k <= n-1; k++)
                {
                    long notlast = (k != n-1);
                    if (k != m)
                    {
                        p = H(k,k-1);
                        q = H(k+1,k-1);
                        r = (notlast ? H(k+2,k-1) : 0.0);
                        x = abs(p) + abs(q) + abs(r);
                        if (x != 0.0)
                        {
                            p = p / x;
                            q = q / x;
                            r = r / x;
                        }
                    }
                    if (x == 0.0)
                    {
                        break;
                    }
                    s = sqrt(p * p + q * q + r * r);
                    if (p < 0)
                    {
                        s = -s;
                    }
                    if (s != 0)
                    {
                        if (k != m)
                        {
                            H(k,k-1) = -s * x;
                        }
                        else if (l != m)
                        {
                            H(k,k-1) = -H(k,k-1);
                        }
                        p = p + s;
                        x = p / s;
                        y = q / s;
                        z = r / s;
                        q = q / p;
                        r = r / p;

                        // Row modification

                        for (long j = k; j < nn; j++)
                        {
                            p = H(k,j) + q * H(k+1,j);
                            if (notlast)
                            {
                                p = p + r * H(k+2,j);
                                H(k+2,j) = H(k+2,j) - p * z;
                            }
                            H(k,j) = H(k,j) - p * x;
                            H(k+1,j) = H(k+1,j) - p * y;
                        }

                        // Column modification

                        for (long i = 0; i <= min(n,k+3); i++)
                        {
                            p = x * H(i,k) + y * H(i,k+1);
                            if (notlast)
                            {
                                p = p + z * H(i,k+2);
                                H(i,k+2) = H(i,k+2) - p * r;
                            }
                            H(i,k) = H(i,k) - p;
                            H(i,k+1) = H(i,k+1) - p * q;
                        }

                        // Accumulate transformations

                        for (long i = low; i <= high; i++)
                        {
                            p = x * V(i,k) + y * V(i,k+1);
                            if (notlast)
                            {
                                p = p + z * V(i,k+2);
                                V(i,k+2) = V(i,k+2) - p * r;
                            }
                            V(i,k) = V(i,k) - p;
                            V(i,k+1) = V(i,k+1) - p * q;
                        }
                    }  // (s != 0)
                }  // k loop
            }  // check convergence
        }  // while (n >= low)

        // Backsubstitute to find vectors of upper triangular form

        if (norm == 0.0)
        {
            return;
        }

        for (n = nn-1; n >= 0; n--)
        {
            p = d(n);
            q = e(n);

            // Real vector

            if (q == 0)
            {
                long l = n;
                H(n,n) = 1.0;
                for (long i = n-1; i >= 0; i--)
                {
                    w = H(i,i) - p;
                    r = 0.0;
                    for (long j = l; j <= n; j++)
                    {
                        r = r + H(i,j) * H(j,n);
                    }
                    if (e(i) < 0.0)
                    {
                        z = w;
                        s = r;
                    }
                    else
                    {
                        l = i;
                        if (e(i) == 0.0)
                        {
                            if (w != 0.0)
                            {
                                H(i,n) = -r / w;
                            }
                            else
                            {
                                H(i,n) = -r / (eps * norm);
                            }

                            // Solve real equations

                        }
                        else
                        {
                            x = H(i,i+1);
                            y = H(i+1,i);
                            q = (d(i) - p) * (d(i) - p) + e(i) * e(i);
                            t = (x * s - z * r) / q;
                            H(i,n) = t;
                            if (abs(x) > abs(z))
                            {
                                H(i+1,n) = (-r - w * t) / x;
                            }
                            else
                            {
                                H(i+1,n) = (-s - y * t) / z;
                            }
                        }

                        // Overflow control

                        t = abs(H(i,n));
                        if ((eps * t) * t > 1)
                        {
                            for (long j = i; j <= n; j++)
                            {
                                H(j,n) = H(j,n) / t;
                            }
                        }
                    }
                }

                // Complex vector

            }
            else if (q < 0)
            {
                long l = n-1;

                // Last vector component imaginary so matrix is triangular

                if (abs(H(n,n-1)) > abs(H(n-1,n)))
                {
                    H(n-1,n-1) = q / H(n,n-1);
                    H(n-1,n) = -(H(n,n) - p) / H(n,n-1);
                }
                else
                {
                    cdiv_(0.0,-H(n-1,n),H(n-1,n-1)-p,q);
                    H(n-1,n-1) = cdivr;
                    H(n-1,n) = cdivi;
                }
                H(n,n-1) = 0.0;
                H(n,n) = 1.0;
                for (long i = n-2; i >= 0; i--)
                {
                    type ra,sa,vr,vi;
                    ra = 0.0;
                    sa = 0.0;
                    for (long j = l; j <= n; j++)
                    {
                        ra = ra + H(i,j) * H(j,n-1);
                        sa = sa + H(i,j) * H(j,n);
                    }
                    w = H(i,i) - p;

                    if (e(i) < 0.0)
                    {
                        z = w;
                        r = ra;
                        s = sa;
                    }
                    else
                    {
                        l = i;
                        if (e(i) == 0)
                        {
                            cdiv_(-ra,-sa,w,q);
                            H(i,n-1) = cdivr;
                            H(i,n) = cdivi;
                        }
                        else
                        {

                            // Solve complex equations

                            x = H(i,i+1);
                            y = H(i+1,i);
                            vr = (d(i) - p) * (d(i) - p) + e(i) * e(i) - q * q;
                            vi = (d(i) - p) * 2.0 * q;
                            if ((vr == 0.0) && (vi == 0.0))
                            {
                                vr = eps * norm * (abs(w) + abs(q) +
                                                   abs(x) + abs(y) + abs(z));
                            }
                            cdiv_(x*r-z*ra+q*sa,x*s-z*sa-q*ra,vr,vi);
                            H(i,n-1) = cdivr;
                            H(i,n) = cdivi;
                            if (abs(x) > (abs(z) + abs(q)))
                            {
                                H(i+1,n-1) = (-ra - w * H(i,n-1) + q * H(i,n)) / x;
                                H(i+1,n) = (-sa - w * H(i,n) - q * H(i,n-1)) / x;
                            }
                            else
                            {
                                cdiv_(-r-y*H(i,n-1),-s-y*H(i,n),z,q);
                                H(i+1,n-1) = cdivr;
                                H(i+1,n) = cdivi;
                            }
                        }

                        // Overflow control

                        t = max(abs(H(i,n-1)),abs(H(i,n)));
                        if ((eps * t) * t > 1)
                        {
                            for (long j = i; j <= n; j++)
                            {
                                H(j,n-1) = H(j,n-1) / t;
                                H(j,n) = H(j,n) / t;
                            }
                        }
                    }
                }
            }
        }

        // Vectors of isolated roots

        for (long i = 0; i < nn; i++)
        {
            if (i < low || i > high)
            {
                for (long j = i; j < nn; j++)
                {
                    V(i,j) = H(i,j);
                }
            }
        }

        // Back transformation to get eigenvectors of original matrix

        for (long j = nn-1; j >= low; j--)
        {
            for (long i = low; i <= high; i++)
            {
                z = 0.0;
                for (long k = low; k <= min(j,high); k++)
                {
                    z = z + V(i,k) * H(k,j);
                }
                V(i,j) = z;
            }
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MATRIX_EIGENVALUE_DECOMPOSITION_H


dlib C++ Library - matrix_exp.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MATRIx_EXP_h_
#define DLIB_MATRIx_EXP_h_

#include "../algs.h"
#include "../is_kind.h"
#include "matrix_fwd.h"
#include "matrix_exp_abstract.h"
#include <iterator>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    // We want to return the compile time constant if our NR and NC dimensions
    // aren't zero but if they are then we want to call ref_.nx() and return
    // the correct values.
    template < typename exp_type, long NR >
    struct get_nr_helper
    {
        static inline long get(const exp_type&) { return NR; }
    };

    template < typename exp_type >
    struct get_nr_helper<exp_type,0>
    {
        static inline long get(const exp_type& m) { return m.nr(); }
    };

    template < typename exp_type, long NC >
    struct get_nc_helper
    {
        static inline long get(const exp_type&) { return NC; }
    };

    template < typename exp_type >
    struct get_nc_helper<exp_type,0>
    {
        static inline long get(const exp_type& m) { return m.nc(); }
    };

    template <typename EXP>
    struct matrix_traits
    {
        typedef typename EXP::type type;
        typedef typename EXP::const_ret_type const_ret_type;
        typedef typename EXP::mem_manager_type mem_manager_type;
        typedef typename EXP::layout_type layout_type;
        const static long NR = EXP::NR;
        const static long NC = EXP::NC;
        const static long cost = EXP::cost;
    };

// ----------------------------------------------------------------------------------------

    template <typename EXP> class matrix_exp;
    template <typename EXP>
    class matrix_exp_iterator : public std::iterator<std::forward_iterator_tag, typename matrix_traits<EXP>::type>
    {
        friend class matrix_exp<EXP>;
        matrix_exp_iterator(const EXP& m_, long r_, long c_)
        {
            r = r_;
            c = c_;
            nc = m_.nc();
            m = &m_;
        }

    public:

        matrix_exp_iterator() : r(0), c(0), nc(0), m(0) {}

        typedef typename matrix_traits<EXP>::type type;
        typedef type value_type;
        typedef typename matrix_traits<EXP>::const_ret_type const_ret_type;

        bool operator == ( const matrix_exp_iterator& itr) const
        { return r == itr.r && c == itr.c; }

        bool operator != ( const matrix_exp_iterator& itr) const
        { return !(*this == itr); }

        matrix_exp_iterator& operator++()
        {
            ++c;
            if (c==nc)
            {
                c = 0;
                ++r;
            }
            return *this;
        }

        matrix_exp_iterator operator++(int)
        {
            matrix_exp_iterator temp(*this);
            ++(*this);
            return temp;
        }

        const_ret_type operator* () const { return (*m)(r,c); }

    private:
        long r, c;
        long nc;
        const EXP* m;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename EXP
        >
    class matrix_exp
    {
        /*!
            REQUIREMENTS ON EXP
                EXP should be something convertible to a matrix_exp.  That is,
                it should inherit from matrix_exp
        !*/

    public:
        typedef typename matrix_traits<EXP>::type type;
        typedef type value_type;
        typedef typename matrix_traits<EXP>::const_ret_type const_ret_type;
        typedef typename matrix_traits<EXP>::mem_manager_type mem_manager_type;
        typedef typename matrix_traits<EXP>::layout_type layout_type;
        const static long NR = matrix_traits<EXP>::NR;
        const static long NC = matrix_traits<EXP>::NC;
        const static long cost = matrix_traits<EXP>::cost;

        typedef matrix<type,NR,NC,mem_manager_type,layout_type> matrix_type;
        typedef EXP exp_type;
        typedef matrix_exp_iterator<EXP> iterator;
        typedef matrix_exp_iterator<EXP> const_iterator;

        inline const_ret_type operator() (
            long r,
            long c
        ) const
        {
            DLIB_ASSERT(r < nr() && c < nc() && r >= 0 && c >= 0,
                "\tconst type matrix_exp::operator(r,c)"
                << "\n\tYou must give a valid row and column"
                << "\n\tr:    " << r
                << "\n\tc:    " << c
                << "\n\tnr(): " << nr()
                << "\n\tnc(): " << nc()
                << "\n\tthis: " << this
                );
            return ref()(r,c);
        }

        const_ret_type operator() (
            long i
        ) const
        {
            COMPILE_TIME_ASSERT(NC == 1 || NC == 0 || NR == 1 || NR == 0);
            DLIB_ASSERT(nc() == 1 || nr() == 1,
                "\tconst type matrix_exp::operator(i)"
                << "\n\tYou can only use this operator on column or row vectors"
                << "\n\ti:    " << i
                << "\n\tnr(): " << nr()
                << "\n\tnc(): " << nc()
                << "\n\tthis: " << this
                );
            DLIB_ASSERT( ((nc() == 1 && i < nr()) || (nr() == 1 && i < nc())) && i >= 0,
                "\tconst type matrix_exp::operator(i)"
                << "\n\tYou must give a valid row/column number"
                << "\n\ti:    " << i
                << "\n\tnr(): " << nr()
                << "\n\tnc(): " << nc()
                << "\n\tthis: " << this
                );
            if (nc() == 1)
                return ref()(i,0);
            else
                return ref()(0,i);
        }

        long size (
        ) const { return nr()*nc(); }

        long nr (
        ) const { return get_nr_helper<exp_type,NR>::get(ref()); }

        long nc (
        ) const { return get_nc_helper<exp_type,NC>::get(ref()); }

        template <typename U>
        bool aliases (
            const matrix_exp<U>& item
        ) const { return ref().aliases(item); }

        template <typename U>
        bool destructively_aliases (
            const matrix_exp<U>& item
        ) const { return ref().destructively_aliases(item); }

        inline const exp_type& ref (
        ) const { return *static_cast<const exp_type*>(this); }

        inline operator const type (
        ) const
        {
            COMPILE_TIME_ASSERT(NC == 1 || NC == 0);
            COMPILE_TIME_ASSERT(NR == 1 || NR == 0);
            DLIB_ASSERT(nr() == 1 && nc() == 1,
                "\tmatrix_exp::operator const type() const"
                << "\n\tYou can only use this operator on a 1x1 matrix"
                << "\n\tnr(): " << nr()
                << "\n\tnc(): " << nc()
                << "\n\tthis: " << this
                );

            // Put the expression contained in this matrix_exp into
            // a temporary 1x1 matrix so that the expression will encounter
            // all the overloads of matrix_assign() and have the chance to
            // go through any applicable optimizations.
            matrix<type,1,1,mem_manager_type,layout_type> temp(ref());
            return temp(0);
        }

        const_iterator begin() const { return matrix_exp_iterator<EXP>(ref(),0,0); }
        const_iterator end()   const { return matrix_exp_iterator<EXP>(ref(),nr(),0); }

    protected:
        matrix_exp() {}
        matrix_exp(const matrix_exp& ) {}

    private:

        matrix_exp& operator= (const matrix_exp&);
    };

// ----------------------------------------------------------------------------------------

    // something is a matrix if it is convertible to a matrix_exp object
    template <typename T>
    struct is_matrix<T, typename enable_if<is_convertible<T, const matrix_exp<typename T::exp_type>& > >::type >
    { static const bool value = true; };
    /*
        is_matrix<T>::value == 1 if T is a matrix type else 0
    */

// ----------------------------------------------------------------------------------------

    template <
        typename EXP
        >
    class matrix_diag_exp : public matrix_exp<EXP>
    {
        /*!
            This is a matrix expression type used to represent diagonal matrices.
            That is, square matrices with all off diagonal elements equal to 0.
        !*/

    protected:
        matrix_diag_exp() {}
        matrix_diag_exp(const matrix_diag_exp& item ):matrix_exp<EXP>(item) {}
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MATRIx_EXP_h_


dlib C++ Library - matrix_exp_abstract.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_MATRIx_EXP_ABSTRACT_
#ifdef DLIB_MATRIx_EXP_ABSTRACT_

#include "matrix_fwd.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename EXP
        >
    class matrix_exp
    {
        /*!
            REQUIREMENTS ON EXP
                - must be an object that inherits publicly from matrix_exp (this class).

            WHAT THIS OBJECT REPRESENTS
                This object represents an expression that evaluates to a matrix
                of nr() rows and nc() columns.

                The reason for having an object that represents an expression is that it
                allows us to use the "expression templates" technique to eliminate the
                temporary matrix objects that would normally be returned from expressions
                such as M = A+B+C+D;  Normally each invocation of the + operator would
                construct and return a temporary matrix object but using this technique we
                can avoid creating all of these temporary objects and receive a large
                speed boost.

                Note that every time you invoke operator() on this object it recomputes
                its result which may not be what you want to do.  For example, if you
                are going to be accessing the same element over and over it might
                be faster to assign the matrix_exp to a temporary matrix and then
                use that temporary.

                const_ret_type typedef (defined below)
                    The purpose of the const_ret_type typedef is to allow matrix expressions
                    to return their elements by reference when appropriate.  So const_ret_type
                    should be one of the following types:
                        - const type
                        - const type&
        !*/

    public:
        typedef typename EXP::type type;
        typedef type value_type; // Redefined for compatibility with the STL
        typedef typename EXP::const_ret_type const_ret_type;
        typedef typename EXP::mem_manager_type mem_manager_type;
        typedef typename EXP::layout_type layout_type;
        const static long cost = EXP::cost;
        const static long NR = EXP::NR;
        const static long NC = EXP::NC;
        typedef matrix<type,NR,NC, mem_manager_type,layout_type> matrix_type;
        typedef EXP exp_type;
        typedef matrix_exp_iterator<EXP> iterator;
        typedef matrix_exp_iterator<EXP> const_iterator;

        const_ret_type operator() (
            long r,
            long c
        ) const;
        /*!
            requires
                - 0 <= r < nr()
                - 0 <= c < nc()
            ensures
                - returns ref()(r,c)
                  (i.e. returns the value at the given row and column that would be in
                  the matrix represented by this matrix expression)
        !*/

        const_ret_type operator() (
            long i
        ) const;
        /*!
            requires
                - nc() == 1 || nr() == 1 (i.e. this must be a column or row vector)
                - if (nc() == 1) then
                    - 0 <= i < nr()
                - else
                    - 0 <= i < nc()
            ensures
                - if (nc() == 1) then
                    - returns (*this)(i,0)
                - else
                    - returns (*this)(0,i)
        !*/

        operator const type (
        ) const;
        /*!
            requires
                - nr() == 1
                - nc() == 1
            ensures
                - returns (*this)(0,0)
        !*/

        long nr (
        ) const;
        /*!
            ensures
                - returns the number of rows in this matrix expression.
        !*/

        long nc (
        ) const;
        /*!
            ensures
                - returns the number of columns in this matrix expression.
        !*/

        long size (
        ) const;
        /*!
            ensures
                - returns nr()*nc()
        !*/

        template <typename U>
        bool aliases (
            const matrix_exp<U>& item
        ) const;
        /*!
            ensures
                - if (A change to the state of item could cause a change to the state of *this
                      matrix_exp object.  ) then
                    - returns true
                    - This happens when this matrix_exp contains item in some way.
                - else
                    - returns false
        !*/

        template <typename U>
        bool destructively_aliases (
            const matrix_exp<U>& item
        ) const;
        /*!
            ensures
                - if (aliases(item)) then
                    - if (nr() != item.nr() || nc() != item.nc()
                        - returns true
                          (i.e. if this expression has different dimensions than item then
                          we have destructive aliasing)

                    - returns true if the following assignment would evaluate incorrectly:
                      for (long r = 0; r < nr(); ++r)
                        for (long c = 0; c < nc(); ++c)
                          item(r,c) = (*this)(r,c)
                    - That is, if this matrix expression aliases item in such a way that a modification
                      to element item(r,c) causes a change in the value of something other than
                      (*this)(r,c) then this function returns true.

                    - returns false if none of the above conditions say we should return true
                - else
                    - returns false
        !*/

        inline const exp_type& ref (
        ) const;
        /*!
            ensures
                - returns a reference to the expression contained in *this.
                  (i.e. returns *static_cast<const exp_type*>(this) )
        !*/

        const_iterator begin(
        ) const;
        /*!
            ensures
                - returns a forward access iterator pointing to the first element in this
                  matrix expression.
                - Since matrix_exp objects represent immutable views of a matrix, the
                  returned iterator does not allow the user to modify the matrix
                  expression's elements.
                - The iterator will iterate over the elements of the matrix in row major
                  order.
        !*/

        const_iterator end(
        ) const;
        /*!
            ensures
                - returns a forward access iterator pointing to one past the end of the
                  last element in this matrix expression.
        !*/

    protected:

        // Only derived classes of matrix_exp may call the matrix_exp constructors.
        matrix_exp(const matrix_exp&);
        matrix_exp();

    private:
        // no one may ever use the assignment operator on a matrix_exp
        matrix_exp& operator= (const matrix_exp&);
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MATRIx_EXP_ABSTRACT_


dlib C++ Library - matrix_expressions.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MATRIx_EXPRESSIONS_H_
#define DLIB_MATRIx_EXPRESSIONS_H_

#include "matrix_fwd.h"

#ifdef _MSC_VER
// This #pragma directive is also located in the algs.h file but for whatever
// reason visual studio 9 just ignores it when it is only there.

// this is to disable the "'this' : used in base member initializer list"
// warning you get from some of the GUI objects since all the objects
// require that their parent class be passed into their constructor.
// In this case though it is totally safe so it is ok to disable this warning.
#pragma warning(disable : 4355)
#endif

namespace dlib
{

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//            Helper templates for making operators used by expression objects
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <typename T>
    class matrix_range_exp;

    template <typename T>
    struct matrix_traits<matrix_range_exp<T> >
    {
        typedef T type;
        typedef const T const_ret_type;
        typedef default_memory_manager mem_manager_type;
        typedef row_major_layout layout_type;
        const static long NR = 1;
        const static long NC = 0;
        const static long cost = 1;
    };

    template <typename T>
    class matrix_range_exp : public matrix_exp<matrix_range_exp<T> >
    {
    public:
        typedef typename matrix_traits<matrix_range_exp>::type type;
        typedef typename matrix_traits<matrix_range_exp>::const_ret_type const_ret_type;
        typedef typename matrix_traits<matrix_range_exp>::mem_manager_type mem_manager_type;
        const static long NR = matrix_traits<matrix_range_exp>::NR;
        const static long NC = matrix_traits<matrix_range_exp>::NC;
        const static long cost = matrix_traits<matrix_range_exp>::cost;
        typedef typename matrix_traits<matrix_range_exp>::layout_type layout_type;

        matrix_range_exp (
            T start_,
            T end_
        )
        {
            start = start_;
            if (start_ <= end_)
                inc = 1;
            else
                inc = -1;
            nc_ = std::abs(end_ - start_) + 1;
        }
        matrix_range_exp (
            T start_,
            T inc_,
            T end_
        )
        {
            start = start_;
            nc_ = std::abs(end_ - start_)/inc_ + 1;
            if (start_ <= end_)
                inc = inc_;
            else
                inc = -inc_;
        }

        matrix_range_exp (
            T start_,
            T end_,
            long num,
            bool
        )
        {
            start = start_;
            nc_ = num;
            if (num > 1)
            {
                inc = (end_-start_)/(num-1);
            }
            else
            {
                inc = 0;
                start = end_;
            }

        }

        const_ret_type operator() (
            long,
            long c
        ) const { return start + c*inc;  }

        const_ret_type operator() (
            long c
        ) const { return start + c*inc;  }

        template <typename U>
        bool aliases (
            const matrix_exp<U>&
        ) const { return false; }

        template <typename U>
        bool destructively_aliases (
            const matrix_exp<U>&
        ) const { return false; }

        long nr (
        ) const { return NR; }

        long nc (
        ) const { return nc_; }

        long nc_;
        T start;
        T inc;
    };

// ----------------------------------------------------------------------------------------

    template <typename T>
    class matrix_log_range_exp;

    template <typename T>
    struct matrix_traits<matrix_log_range_exp<T> >
    {
        typedef T type;
        typedef const T const_ret_type;
        typedef default_memory_manager mem_manager_type;
        typedef row_major_layout layout_type;
        const static long NR = 1;
        const static long NC = 0;
        const static long cost = 1;
    };

    template <typename T>
    class matrix_log_range_exp : public matrix_exp<matrix_log_range_exp<T> >
    {
    public:
        typedef typename matrix_traits<matrix_log_range_exp>::type type;
        typedef typename matrix_traits<matrix_log_range_exp>::const_ret_type const_ret_type;
        typedef typename matrix_traits<matrix_log_range_exp>::mem_manager_type mem_manager_type;
        const static long NR = matrix_traits<matrix_log_range_exp>::NR;
        const static long NC = matrix_traits<matrix_log_range_exp>::NC;
        const static long cost = matrix_traits<matrix_log_range_exp>::cost;
        typedef typename matrix_traits<matrix_log_range_exp>::layout_type layout_type;

        matrix_log_range_exp (
            T start_,
            T end_,
            long num
        )
        {
            start = start_;
            nc_ = num;
            if (num > 1)
            {
                inc = (end_-start_)/(num-1);
            }
            else
            {
                inc = 0;
                start = end_;
            }

        }

        const_ret_type operator() (
            long,
            long c
        ) const { return std::pow((T)10,start + c*inc);  }

        const_ret_type operator() (
            long c
        ) const { return std::pow((T)10,start + c*inc);  }

        template <typename U>
        bool aliases (
            const matrix_exp<U>&
        ) const { return false; }

        template <typename U>
        bool destructively_aliases (
            const matrix_exp<U>&
        ) const { return false; }

        long nr (
        ) const { return NR; }

        long nc (
        ) const { return nc_; }

        long nc_;
        T start;
        T inc;
    };

// ----------------------------------------------------------------------------------------

    template <long start, long inc_, long end>
    class matrix_range_static_exp;

    template <long start, long inc_, long end>
    struct matrix_traits<matrix_range_static_exp<start,inc_,end> >
    {
        typedef long type;
        typedef const long const_ret_type;
        typedef default_memory_manager mem_manager_type;
        const static long NR = 1;
        const static long NC = tabs<(end - start)>::value/inc_ + 1;
        const static long cost = 1;
        typedef row_major_layout layout_type;
    };

    template <long start, long inc_, long end_>
    class matrix_range_static_exp : public matrix_exp<matrix_range_static_exp<start,inc_,end_> >
    {
    public:
        typedef typename matrix_traits<matrix_range_static_exp>::type type;
        typedef typename matrix_traits<matrix_range_static_exp>::const_ret_type const_ret_type;
        typedef typename matrix_traits<matrix_range_static_exp>::mem_manager_type mem_manager_type;
        const static long NR = matrix_traits<matrix_range_static_exp>::NR;
        const static long NC = matrix_traits<matrix_range_static_exp>::NC;
        const static long cost = matrix_traits<matrix_range_static_exp>::cost;
        typedef typename matrix_traits<matrix_range_static_exp>::layout_type layout_type;

        const static long inc = (start <= end_)?inc_:-inc_;

        matrix_range_static_exp (
        ) {}

        const_ret_type operator() (
            long ,
            long c
        ) const { return start + c*inc;  }

        const_ret_type operator() (
            long c
        ) const { return start + c*inc;  }

        template <typename U>
        bool aliases (
            const matrix_exp<U>&
        ) const { return false; }

        template <typename U>
        bool destructively_aliases (
            const matrix_exp<U>&
        ) const { return false; }

        long nr (
        ) const { return NR; }

        long nc (
        ) const { return NC; }

    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MATRIx_EXPRESSIONS_H_


dlib C++ Library - matrix_fft.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_FFt_Hh_
#define DLIB_FFt_Hh_

#include "matrix_fft_abstract.h"
#include "matrix_utilities.h"
#include "../hash.h"
#include "../algs.h"

// No using FFTW until it becomes thread safe!
#if 0
#ifdef DLIB_USE_FFTW
#include <fftw3.h>
#endif // DLIB_USE_FFTW
#endif

namespace dlib
{

// ----------------------------------------------------------------------------------------

    inline bool is_power_of_two (
        const unsigned long& value
    )
    {
        if (value == 0)
            return true;
        else
            return count_bits(value) == 1;
    }

// ----------------------------------------------------------------------------------------

    namespace impl
    {

    // ------------------------------------------------------------------------------------

        /*
            The next few functions related to doing FFTs are derived from Stefan
            Gustavson's (stegu@itn.liu.se) public domain 2D Fourier transformation code.
            The code has a long history, originally a FORTRAN implementation published in:
            Programming for Digital Signal Processing, IEEE Press 1979, Section 1, by G. D.
            Bergland and M. T. Dolan.  In 2003 it was cleaned up and turned into modern C
            by Steven Gustavson.  Davis King then rewrote it in modern C++ in 2014 and also
            changed the transform so that the outputs are identical to those given from FFTW.
        */

    // ------------------------------------------------------------------------------------

        /* Get binary log of integer argument - exact if n is a power of 2 */
        inline long fastlog2(long n)
        {
            long log = -1;
            while(n) {
                log++;
                n >>= 1;
            }
            return log ;
        }

    // ------------------------------------------------------------------------------------

        /* Radix-2 iteration subroutine */
        template <typename T>
        void R2TX(int nthpo, std::complex<T> *c0, std::complex<T> *c1)
        {
            for(int k=0; k<nthpo; k+=2)
            {
                std::complex<T> temp = c0[k] + c1[k];
                c1[k] = c0[k] - c1[k];
                c0[k] = temp;
            }
        }

    // ------------------------------------------------------------------------------------

        /* Radix-4 iteration subroutine */
        template <typename T>
        void R4TX(int nthpo, std::complex<T> *c0, std::complex<T> *c1,
            std::complex<T> *c2, std::complex<T> *c3)
        {
            for(int k=0;k<nthpo;k+=4)
            {
                std::complex<T> t1, t2, t3, t4;
                t1 = c0[k] + c2[k];
                t2 = c0[k] - c2[k];
                t3 = c1[k] + c3[k];
                t4 = c1[k] - c3[k];

                c0[k] = t1 + t3;
                c1[k] = t1 - t3;
                c2[k] = std::complex<T>(t2.real()-t4.imag(), t2.imag()+t4.real());
                c3[k] = std::complex<T>(t2.real()+t4.imag(), t2.imag()-t4.real());
            }
        }

    // ------------------------------------------------------------------------------------

        template <typename T>
        class twiddles
        {
            /*!
                The point of this object is to cache the twiddle values so we don't
                recompute them over and over inside R8TX().
            !*/
        public:

            twiddles()
            {
                data.resize(64);
            }

            const std::complex<T>* get_twiddles (
                int p
            )
            /*!
                requires
                    - 0 <= p <= 64
                ensures
                    - returns a pointer to the twiddle factors needed by R8TX if nxtlt == 2^p
            !*/
            {
                // Compute the twiddle factors for this p value if we haven't done so
                // already.
                if (data[p].size() == 0)
                {
                    const int nxtlt = 0x1 << p;
                    data[p].reserve(nxtlt*7);
                    const T twopi = 6.2831853071795865; /* 2.0 * pi */
                    const T scale = twopi/(nxtlt*8.0);
                    std::complex<T> cs[7];
                    for (int j = 0; j < nxtlt; ++j)
                    {
                        const T arg = j*scale;
                        cs[0] = std::complex<T>(std::cos(arg),std::sin(arg));
                        cs[1] = cs[0]*cs[0];
                        cs[2] = cs[1]*cs[0];
                        cs[3] = cs[1]*cs[1];
                        cs[4] = cs[2]*cs[1];
                        cs[5] = cs[2]*cs[2];
                        cs[6] = cs[3]*cs[2];
                        data[p].insert(data[p].end(), cs, cs+7);
                    }
                }

                return &data[p][0];
            }

        private:
            std::vector<std::vector<std::complex<T> > > data;
        };

    // ----------------------------------------------------------------------------------------

        /* Radix-8 iteration subroutine */
        template <typename T>
        void R8TX(int nxtlt, int nthpo, int length, const std::complex<T>* cs,
            std::complex<T> *cc0, std::complex<T> *cc1, std::complex<T> *cc2, std::complex<T> *cc3,
            std::complex<T> *cc4, std::complex<T> *cc5, std::complex<T> *cc6, std::complex<T> *cc7)
        {
            const T irt2 = 0.707106781186548;  /* 1.0/sqrt(2.0) */

            for(int j=0; j<nxtlt; j++)
            {
                for(int k=j;k<nthpo;k+=length)
                {
                    std::complex<T> a0, a1, a2, a3, a4, a5, a6, a7;
                    std::complex<T> b0, b1, b2, b3, b4, b5, b6, b7;
                    a0 = cc0[k] + cc4[k];
                    a1 = cc1[k] + cc5[k];
                    a2 = cc2[k] + cc6[k];
                    a3 = cc3[k] + cc7[k];
                    a4 = cc0[k] - cc4[k];
                    a5 = cc1[k] - cc5[k];
                    a6 = cc2[k] - cc6[k];
                    a7 = cc3[k] - cc7[k];

                    b0 = a0 + a2;
                    b1 = a1 + a3;
                    b2 = a0 - a2;
                    b3 = a1 - a3;

                    b4 = std::complex<T>(a4.real()-a6.imag(), a4.imag()+a6.real());
                    b5 = std::complex<T>(a5.real()-a7.imag(), a5.imag()+a7.real());
                    b6 = std::complex<T>(a4.real()+a6.imag(), a4.imag()-a6.real());
                    b7 = std::complex<T>(a5.real()+a7.imag(), a5.imag()-a7.real());

                    const std::complex<T> tmp0(-b3.imag(), b3.real());
                    const std::complex<T> tmp1(irt2*(b5.real()-b5.imag()), irt2*(b5.real()+b5.imag()));
                    const std::complex<T> tmp2(-irt2*(b7.real()+b7.imag()), irt2*(b7.real()-b7.imag()));

                    cc0[k] = b0 + b1;
                    cc1[k] = b0 - b1;
                    cc2[k] = b2 + tmp0;
                    cc3[k] = b2 - tmp0;
                    cc4[k] = b4 + tmp1;
                    cc5[k] = b4 - tmp1;
                    cc6[k] = b6 + tmp2;
                    cc7[k] = b6 - tmp2;
                    if(j>0)
                    {
                        cc1[k] *= cs[3];
                        cc2[k] *= cs[1];
                        cc3[k] *= cs[5];
                        cc4[k] *= cs[0];
                        cc5[k] *= cs[4];
                        cc6[k] *= cs[2];
                        cc7[k] *= cs[6];
                    }
                }

                cs += 7;
            }
        }

    // ------------------------------------------------------------------------------------

        template <typename T, long NR, long NC, typename MM, typename layout>
        void fft1d_inplace(matrix<std::complex<T>,NR,NC,MM,layout>& data, bool do_backward_fft, twiddles<T>& cs)
        /*!
            requires
                - is_vector(data) == true
                - is_power_of_two(data.size()) == true
            ensures
                - This routine replaces the input std::complex<double> vector by its finite
                  discrete complex fourier transform if do_backward_fft==true.  It replaces
                  the input std::complex<double> vector by its finite discrete complex
                  inverse fourier transform if do_backward_fft==false.

                  The implementation is a radix-2 FFT, but with faster shortcuts for
                  radix-4 and radix-8. It performs as many radix-8 iterations as possible,
                  and then finishes with a radix-2 or -4 iteration if needed.
        !*/
        {
            if (data.size() == 0)
                return;

            std::complex<T>* const b = &data(0);
            int L[16],L1,L2,L3,L4,L5,L6,L7,L8,L9,L10,L11,L12,L13,L14,L15;
            int j1,j2,j3,j4,j5,j6,j7,j8,j9,j10,j11,j12,j13,j14;
            int j, ij, ji;
            int n2pow, n8pow, nthpo, ipass, nxtlt, length;

            n2pow = fastlog2(data.size());
            nthpo = data.size();

            n8pow = n2pow/3;

            if(n8pow)
            {
                /* Radix 8 iterations */
                for(ipass=1;ipass<=n8pow;ipass++)
                {
                    const int p = n2pow - 3*ipass;
                    nxtlt = 0x1 << p;
                    length = 8*nxtlt;
                    R8TX(nxtlt, nthpo, length, cs.get_twiddles(p),
                        b, b+nxtlt, b+2*nxtlt, b+3*nxtlt,
                        b+4*nxtlt, b+5*nxtlt, b+6*nxtlt, b+7*nxtlt);
                }
            }

            if(n2pow%3 == 1)
            {
                /* A final radix 2 iteration is needed */
                R2TX(nthpo, b, b+1);
            }

            if(n2pow%3 == 2)
            {
                /* A final radix 4 iteration is needed */
                R4TX(nthpo, b, b+1, b+2, b+3);
            }

            for(j=1;j<=15;j++)
            {
                L[j] = 1;
                if(j-n2pow <= 0) L[j] = 0x1 << (n2pow + 1 - j);
            }

            L15=L[1];L14=L[2];L13=L[3];L12=L[4];L11=L[5];L10=L[6];L9=L[7];
            L8=L[8];L7=L[9];L6=L[10];L5=L[11];L4=L[12];L3=L[13];L2=L[14];L1=L[15];

            ij = 0;

            for(j1=0;j1<L1;j1++)
                for(j2=j1;j2<L2;j2+=L1)
                    for(j3=j2;j3<L3;j3+=L2)
                        for(j4=j3;j4<L4;j4+=L3)
                            for(j5=j4;j5<L5;j5+=L4)
                                for(j6=j5;j6<L6;j6+=L5)
                                    for(j7=j6;j7<L7;j7+=L6)
                                        for(j8=j7;j8<L8;j8+=L7)
                                            for(j9=j8;j9<L9;j9+=L8)
                                                for(j10=j9;j10<L10;j10+=L9)
                                                    for(j11=j10;j11<L11;j11+=L10)
                                                        for(j12=j11;j12<L12;j12+=L11)
                                                            for(j13=j12;j13<L13;j13+=L12)
                                                                for(j14=j13;j14<L14;j14+=L13)
                                                                    for(ji=j14;ji<L15;ji+=L14)
                                                                    {
                                                                        if(ij<ji)
                                                                            swap(b[ij], b[ji]);
                                                                        ij++;
                                                                    }

            // unscramble outputs
            if(!do_backward_fft)
            {
                for(long i=1, j=data.size()-1; i<data.size()/2; i++,j--)
                {
                    swap(b[j], b[i]);
                }
            }
        }

    // ------------------------------------------------------------------------------------

        template < typename T, long NR, long NC, typename MM, typename L >
        void fft2d_inplace(
            matrix<std::complex<T>,NR,NC,MM,L>& data,
            bool do_backward_fft
        )
        {
            if (data.size() == 0)
                return;

            matrix<std::complex<double> > buff;
            twiddles<double> cs;

            // Compute transform row by row
            for(long r=0; r<data.nr(); ++r)
            {
                buff = matrix_cast<std::complex<double> >(rowm(data,r));
                fft1d_inplace(buff, do_backward_fft, cs);
                set_rowm(data,r) = matrix_cast<std::complex<T> >(buff);
            }

            // Compute transform column by column
            for(long c=0; c<data.nc(); ++c)
            {
                buff = matrix_cast<std::complex<double> >(colm(data,c));
                fft1d_inplace(buff, do_backward_fft, cs);
                set_colm(data,c) = matrix_cast<std::complex<T> >(buff);
            }
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename EXP,
            typename T
            >
        void fft2d(
            const matrix_exp<EXP>& data,
            matrix<std::complex<T> >& data_out,
            bool do_backward_fft
        )
        {
            // make sure requires clause is not broken
            DLIB_CASSERT(is_power_of_two(data.nr()) && is_power_of_two(data.nc()),
                "\t matrix fft(data)"
                << "\n\t The number of rows and columns must be powers of two."
                << "\n\t data.nr(): "<< data.nr()
                << "\n\t data.nc(): "<< data.nc()
                << "\n\t is_power_of_two(data.nr()): " << is_power_of_two(data.nr())
                << "\n\t is_power_of_two(data.nc()): " << is_power_of_two(data.nc())
            );

            if (data.size() == 0)
                return;

            matrix<std::complex<double> > buff;
            data_out.set_size(data.nr(), data.nc());
            twiddles<double> cs;

            // Compute transform row by row
            for(long r=0; r<data.nr(); ++r)
            {
                buff = matrix_cast<std::complex<double> >(rowm(data,r));
                fft1d_inplace(buff, do_backward_fft, cs);
                set_rowm(data_out,r) = matrix_cast<std::complex<T> >(buff);
            }

            // Compute transform column by column
            for(long c=0; c<data_out.nc(); ++c)
            {
                buff = matrix_cast<std::complex<double> >(colm(data_out,c));
                fft1d_inplace(buff, do_backward_fft, cs);
                set_colm(data_out,c) = matrix_cast<std::complex<T> >(buff);
            }
        }

    // ------------------------------------------------------------------------------------

    } // end namespace impl

// ----------------------------------------------------------------------------------------

    template <typename EXP>
    matrix<typename EXP::type> fft (const matrix_exp<EXP>& data)
    {
        // You have to give a complex matrix
        COMPILE_TIME_ASSERT(is_complex<typename EXP::type>::value);
        // make sure requires clause is not broken
        DLIB_CASSERT(is_power_of_two(data.nr()) && is_power_of_two(data.nc()),
            "\t matrix fft(data)"
            << "\n\t The number of rows and columns must be powers of two."
            << "\n\t data.nr(): "<< data.nr()
            << "\n\t data.nc(): "<< data.nc()
            << "\n\t is_power_of_two(data.nr()): " << is_power_of_two(data.nr())
            << "\n\t is_power_of_two(data.nc()): " << is_power_of_two(data.nc())
            );

        if (data.nr() == 1 || data.nc() == 1)
        {
            matrix<typename EXP::type> temp(data);
            impl::twiddles<typename EXP::type::value_type> cs;
            impl::fft1d_inplace(temp, false, cs);
            return temp;
        }
        else
        {
            matrix<typename EXP::type> temp;
            impl::fft2d(data, temp, false);
            return temp;
        }
    }

    template <typename EXP>
    matrix<typename EXP::type> ifft (const matrix_exp<EXP>& data)
    {
        // You have to give a complex matrix
        COMPILE_TIME_ASSERT(is_complex<typename EXP::type>::value);
        // make sure requires clause is not broken
        DLIB_CASSERT(is_power_of_two(data.nr()) && is_power_of_two(data.nc()),
            "\t matrix ifft(data)"
            << "\n\t The number of rows and columns must be powers of two."
            << "\n\t data.nr(): "<< data.nr()
            << "\n\t data.nc(): "<< data.nc()
            << "\n\t is_power_of_two(data.nr()): " << is_power_of_two(data.nr())
            << "\n\t is_power_of_two(data.nc()): " << is_power_of_two(data.nc())
            );

        matrix<typename EXP::type> temp;
        if (data.size() == 0)
            return temp;

        if (data.nr() == 1 || data.nc() == 1)
        {
            temp = data;
            impl::twiddles<typename EXP::type::value_type> cs;
            impl::fft1d_inplace(temp, true, cs);
        }
        else
        {
            impl::fft2d(data, temp, true);
        }
        temp /= data.size();
        return temp;
    }

// ----------------------------------------------------------------------------------------

    template < typename T, long NR, long NC, typename MM, typename L >
    void fft_inplace (matrix<std::complex<T>,NR,NC,MM,L>& data)
    // Note that we don't divide the outputs by data.size() so this isn't quite the inverse.
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(is_power_of_two(data.nr()) && is_power_of_two(data.nc()),
            "\t void fft_inplace(data)"
            << "\n\t The number of rows and columns must be powers of two."
            << "\n\t data.nr(): "<< data.nr()
            << "\n\t data.nc(): "<< data.nc()
            << "\n\t is_power_of_two(data.nr()): " << is_power_of_two(data.nr())
            << "\n\t is_power_of_two(data.nc()): " << is_power_of_two(data.nc())
            );

        if (data.nr() == 1 || data.nc() == 1)
        {
            impl::twiddles<T> cs;
            impl::fft1d_inplace(data, false, cs);
        }
        else
        {
            impl::fft2d_inplace(data, false);
        }
    }

    template < typename T, long NR, long NC, typename MM, typename L >
    void ifft_inplace (matrix<std::complex<T>,NR,NC,MM,L>& data)
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(is_power_of_two(data.nr()) && is_power_of_two(data.nc()),
            "\t void ifft_inplace(data)"
            << "\n\t The number of rows and columns must be powers of two."
            << "\n\t data.nr(): "<< data.nr()
            << "\n\t data.nc(): "<< data.nc()
            << "\n\t is_power_of_two(data.nr()): " << is_power_of_two(data.nr())
            << "\n\t is_power_of_two(data.nc()): " << is_power_of_two(data.nc())
            );

        if (data.nr() == 1 || data.nc() == 1)
        {
            impl::twiddles<T> cs;
            impl::fft1d_inplace(data, true, cs);
        }
        else
        {
            impl::fft2d_inplace(data, true);
        }
    }

// ----------------------------------------------------------------------------------------

    /*
        I'm disabling any use of the FFTW bindings because FFTW is, as of this writing, not
        threadsafe as a library.  This means that if multiple threads were to make
        concurrent calls to these fft routines then the program could crash.  If at some
        point FFTW is fixed I'll turn these bindings back on.

        See https://github.com/FFTW/fftw3/issues/16
    */
#if 0
#ifdef DLIB_USE_FFTW

    template <long NR, long NC, typename MM, typename L>
    matrix<std::complex<double>,NR,NC,MM,L> call_fftw_fft(
        const matrix<std::complex<double>,NR,NC,MM,L>& data
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(is_power_of_two(data.nr()) && is_power_of_two(data.nc()),
            "\t matrix fft(data)"
            << "\n\t The number of rows and columns must be powers of two."
            << "\n\t data.nr(): "<< data.nr()
            << "\n\t data.nc(): "<< data.nc()
            << "\n\t is_power_of_two(data.nr()): " << is_power_of_two(data.nr())
            << "\n\t is_power_of_two(data.nc()): " << is_power_of_two(data.nc())
            );

        if (data.size() == 0)
            return data;

        matrix<std::complex<double>,NR,NC,MM,L> m2(data.nr(),data.nc());
        fftw_complex *in, *out;
        fftw_plan p;
        in = (fftw_complex*)&data(0,0);
        out = (fftw_complex*)&m2(0,0);
        if (data.nr() == 1 || data.nc() == 1)
            p = fftw_plan_dft_1d(data.size(), in, out, FFTW_FORWARD, FFTW_ESTIMATE);
        else
            p = fftw_plan_dft_2d(data.nr(), data.nc(), in, out, FFTW_FORWARD, FFTW_ESTIMATE);
        fftw_execute(p);
        fftw_destroy_plan(p);
        return m2;
    }

    template <long NR, long NC, typename MM, typename L>
    matrix<std::complex<double>,NR,NC,MM,L> call_fftw_ifft(
        const matrix<std::complex<double>,NR,NC,MM,L>& data
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(is_power_of_two(data.nr()) && is_power_of_two(data.nc()),
            "\t matrix ifft(data)"
            << "\n\t The number of rows and columns must be powers of two."
            << "\n\t data.nr(): "<< data.nr()
            << "\n\t data.nc(): "<< data.nc()
            << "\n\t is_power_of_two(data.nr()): " << is_power_of_two(data.nr())
            << "\n\t is_power_of_two(data.nc()): " << is_power_of_two(data.nc())
            );

        if (data.size() == 0)
            return data;

        matrix<std::complex<double>,NR,NC,MM,L> m2(data.nr(),data.nc());
        fftw_complex *in, *out;
        fftw_plan p;
        in = (fftw_complex*)&data(0,0);
        out = (fftw_complex*)&m2(0,0);
        if (data.nr() == 1 || data.nc() == 1)
            p = fftw_plan_dft_1d(data.size(), in, out, FFTW_BACKWARD, FFTW_ESTIMATE);
        else
            p = fftw_plan_dft_2d(data.nr(), data.nc(), in, out, FFTW_BACKWARD, FFTW_ESTIMATE);
        fftw_execute(p);
        fftw_destroy_plan(p);
        return m2;
    }

// ----------------------------------------------------------------------------------------

// call FFTW for these cases:
    inline matrix<std::complex<double>,0,1> fft (const matrix<std::complex<double>,0,1>& data) {return call_fftw_fft(data);}
    inline matrix<std::complex<double>,0,1> ifft(const matrix<std::complex<double>,0,1>& data) {return call_fftw_ifft(data)/data.size();}
    inline matrix<std::complex<double>,1,0> fft (const matrix<std::complex<double>,1,0>& data) {return call_fftw_fft(data);}
    inline matrix<std::complex<double>,1,0> ifft(const matrix<std::complex<double>,1,0>& data) {return call_fftw_ifft(data)/data.size();}
    inline matrix<std::complex<double> > fft (const matrix<std::complex<double> >& data) {return call_fftw_fft(data);}
    inline matrix<std::complex<double> > ifft(const matrix<std::complex<double> >& data) {return call_fftw_ifft(data)/data.size();}

    inline void fft_inplace (matrix<std::complex<double>,0,1>& data) {data = call_fftw_fft(data);}
    inline void ifft_inplace(matrix<std::complex<double>,0,1>& data) {data = call_fftw_ifft(data);}
    inline void fft_inplace (matrix<std::complex<double>,1,0>& data) {data = call_fftw_fft(data);}
    inline void ifft_inplace(matrix<std::complex<double>,1,0>& data) {data = call_fftw_ifft(data);}
    inline void fft_inplace (matrix<std::complex<double> >& data) {data = call_fftw_fft(data);}
    inline void ifft_inplace(matrix<std::complex<double> >& data) {data = call_fftw_ifft(data);}

#endif // DLIB_USE_FFTW
#endif // end of #if 0

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_FFt_Hh_


dlib C++ Library - matrix_fwd.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MATRIx_FWD
#define DLIB_MATRIx_FWD

#include "../algs.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    struct row_major_layout;

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        long num_rows = 0,
        long num_cols = 0,
        typename mem_manager = default_memory_manager,
        typename layout = row_major_layout
        >
    class matrix;

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MATRIx_FWD


dlib C++ Library - matrix_generic_image.h

// Copyright (C) 2014  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MATRIX_GENERIC_iMAGE_Hh_
#define DLIB_MATRIX_GENERIC_iMAGE_Hh_

#include "matrix.h"
#include "../image_processing/generic_image.h"

namespace dlib
{
    template <
        typename T,
        long NR,
        long NC,
        typename MM
        >
    struct image_traits<matrix<T,NR,NC,MM> >
    {
        typedef T pixel_type;
    };

    template <
        typename T,
        long NR,
        long NC,
        typename MM
        >
    struct image_traits<const matrix<T,NR,NC,MM> >
    {
        typedef T pixel_type;
    };

    template <
        typename T,
        long NR,
        long NC,
        typename MM
        >
    inline long num_rows( const matrix<T,NR,NC,MM>& img) { return img.nr(); }

    template <
        typename T,
        long NR,
        long NC,
        typename MM
        >
    inline long num_columns( const matrix<T,NR,NC,MM>& img) { return img.nc(); }

    template <
        typename T,
        long NR,
        long NC,
        typename MM
        >
    inline void set_image_size(
        matrix<T,NR,NC,MM>& img,
        long rows,
        long cols
    ) { img.set_size(rows,cols); }

    template <
        typename T,
        long NR,
        long NC,
        typename MM
        >
    inline void* image_data(
        matrix<T,NR,NC,MM>& img
    )
    {
        if (img.size() != 0)
            return &img(0,0);
        else
            return 0;
    }

    template <
        typename T,
        long NR,
        long NC,
        typename MM
        >
    inline const void* image_data(
        const matrix<T,NR,NC,MM>& img
    )
    {
        if (img.size() != 0)
            return &img(0,0);
        else
            return 0;
    }

    template <
        typename T,
        long NR,
        long NC,
        typename MM
        >
    inline long width_step(
        const matrix<T,NR,NC,MM>& img
    )
    {
        return img.nc()*sizeof(T);
    }

}

#endif // DLIB_MATRIX_GENERIC_iMAGE_Hh_


dlib C++ Library - matrix_la.h

// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MATRIx_LA_FUNCTS_
#define DLIB_MATRIx_LA_FUNCTS_

#include "matrix_la_abstract.h"
#include "matrix_utilities.h"
#include "../sparse_vector.h"
#include "../optimization/optimization_line_search.h"

// The 4 decomposition objects described in the matrix_la_abstract.h file are
// actually implemented in the following 4 files.
#include "matrix_lu.h"
#include "matrix_qr.h"
#include "matrix_cholesky.h"
#include "matrix_eigenvalue.h"

#ifdef DLIB_USE_LAPACK
#include "lapack/potrf.h"
#include "lapack/gesdd.h"
#include "lapack/gesvd.h"
#endif

namespace dlib
{

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    namespace nric
    {
        // This namespace contains stuff adapted from the algorithms
        // described in the book Numerical Recipes in C

        template <typename T>
        inline T pythag(const T& a, const T& b)
        {
            T absa,absb;
            absa=std::abs(a);
            absb=std::abs(b);
            if (absa > absb)
            {
                T val = absb/absa;
                val *= val;
                return absa*std::sqrt(1.0+val);
            }
            else
            {
                if (absb == 0.0)
                {
                    return 0.0;
                }
                else
                {
                    T val = absa/absb;
                    val *= val;
                    return  absb*std::sqrt(1.0+val);
                }
            }
        }

        template <typename T>
        inline T sign(const T& a, const T& b)
        {
            if (b < 0)
            {
                return -std::abs(a);
            }
            else
            {
                return std::abs(a);
            }
        }

        template <
            typename T,
            long M, long N,
            long wN, long wX,
            long vN,
            long rN, long rX,
            typename MM1,
            typename MM2,
            typename MM3,
            typename MM4,
            typename L1,
            typename L2,
            typename L3,
            typename L4
            >
        bool svdcmp(
            matrix<T,M,N,MM1,L1>& a,
            matrix<T,wN,wX,MM2,L2>& w,
            matrix<T,vN,vN,MM3,L3>& v,
            matrix<T,rN,rX,MM4,L4>& rv1
        )
        /*!  ( this function is derived from the one in numerical recipes in C chapter 2.6)
            requires
                - w.nr() == a.nc()
                - w.nc() == 1
                - v.nr() == a.nc()
                - v.nc() == a.nc()
                - rv1.nr() == a.nc()
                - rv1.nc() == 1
            ensures
                - computes the singular value decomposition of a
                - let W be the matrix such that diag(W) == #w then:
                    - a == #a*W*trans(#v)
                - trans(#a)*#a == identity matrix
                - trans(#v)*#v == identity matrix
                - #rv1 == some undefined value
                - returns true for success and false for failure
        !*/
        {

            DLIB_ASSERT(
                 w.nr() == a.nc() &&
                 w.nc() == 1 &&
                 v.nr() == a.nc() &&
                 v.nc() == a.nc() &&
                 rv1.nr() == a.nc() &&
                 rv1.nc() == 1, "");

            COMPILE_TIME_ASSERT(wX == 0 || wX == 1);
            COMPILE_TIME_ASSERT(rX == 0 || rX == 1);

            const T one = 1.0;
            const long max_iter = 300;
            const long n = a.nc();
            const long m = a.nr();
            const T eps = std::numeric_limits<T>::epsilon();
            long nm = 0, l = 0;
            bool flag;
            T anorm,c,f,g,h,s,scale,x,y,z;
            g = 0.0;
            scale = 0.0;
            anorm = 0.0;

            for (long i = 0; i < n; ++i)
            {
                l = i+1;
                rv1(i) = scale*g;
                g = s = scale = 0.0;
                if (i < m)
                {
                    for (long k = i; k < m; ++k)
                        scale += std::abs(a(k,i));

                    if (scale)
                    {
                        for (long k = i; k < m; ++k)
                        {
                            a(k,i) /= scale;
                            s += a(k,i)*a(k,i);
                        }
                        f = a(i,i);
                        g = -sign(std::sqrt(s),f);
                        h = f*g - s;
                        a(i,i) = f - g;
                        for (long j = l; j < n; ++j)
                        {
                            s = 0.0;
                            for (long k = i; k < m; ++k)
                                s += a(k,i)*a(k,j);

                            f = s/h;

                            for (long k = i; k < m; ++k)
                                a(k,j) += f*a(k,i);
                        }
                        for (long k = i; k < m; ++k)
                            a(k,i) *= scale;
                    }
                }

                w(i) = scale *g;

                g=s=scale=0.0;

                if (i < m && i < n-1)
                {
                    for (long k = l; k < n; ++k)
                        scale += std::abs(a(i,k));

                    if (scale)
                    {
                        for (long k = l; k < n; ++k)
                        {
                            a(i,k) /= scale;
                            s += a(i,k)*a(i,k);
                        }
                        f = a(i,l);
                        g = -sign(std::sqrt(s),f);
                        h = f*g - s;
                        a(i,l) = f - g;

                        for (long k = l; k < n; ++k)
                            rv1(k) = a(i,k)/h;

                        for (long j = l; j < m; ++j)
                        {
                            s = 0.0;
                            for (long k = l; k < n; ++k)
                                s += a(j,k)*a(i,k);

                            for (long k = l; k < n; ++k)
                                a(j,k) += s*rv1(k);
                        }
                        for (long k = l; k < n; ++k)
                            a(i,k) *= scale;
                    }
                }
                anorm = std::max(anorm,(std::abs(w(i))+std::abs(rv1(i))));
            }
            for (long i = n-1; i >= 0; --i)
            {
                if (i < n-1)
                {
                    if (g != 0)
                    {
                        for (long j = l; j < n ; ++j)
                            v(j,i) = (a(i,j)/a(i,l))/g;

                        for (long j = l; j < n; ++j)
                        {
                            s = 0.0;
                            for (long k = l; k < n; ++k)
                                s += a(i,k)*v(k,j);

                            for (long k = l; k < n; ++k)
                                v(k,j) += s*v(k,i);
                        }
                    }

                    for (long j = l; j < n; ++j)
                        v(i,j) = v(j,i) = 0.0;
                }

                v(i,i) = 1.0;
                g = rv1(i);
                l = i;
            }

            for (long i = std::min(m,n)-1; i >= 0; --i)
            {
                l = i + 1;
                g = w(i);

                for (long j = l; j < n; ++j)
                    a(i,j) = 0.0;

                if (g != 0)
                {
                    g = 1.0/g;

                    for (long j = l; j < n; ++j)
                    {
                        s = 0.0;
                        for (long k = l; k < m; ++k)
                            s += a(k,i)*a(k,j);

                        f=(s/a(i,i))*g;

                        for (long k = i; k < m; ++k)
                            a(k,j) += f*a(k,i);
                    }
                    for (long j = i; j < m; ++j)
                        a(j,i) *= g;
                }
                else
                {
                    for (long j = i; j < m; ++j)
                        a(j,i) = 0.0;
                }

                ++a(i,i);
            }

            for (long k = n-1; k >= 0; --k)
            {
                for (long its = 1; its <= max_iter; ++its)
                {
                    flag = true;
                    for (l = k; l >= 1; --l)
                    {
                        nm = l - 1;
                        if (std::abs(rv1(l)) <= eps*anorm)
                        {
                            flag = false;
                            break;
                        }
                        if (std::abs(w(nm)) <= eps*anorm)
                        {
                            break;
                        }
                    }

                    if (flag)
                    {
                        c = 0.0;
                        s = 1.0;
                        for (long i = l; i <= k; ++i)
                        {
                            f = s*rv1(i);
                            rv1(i) = c*rv1(i);
                            if (std::abs(f) <= eps*anorm)
                                break;

                            g = w(i);
                            h = pythag(f,g);
                            w(i) = h;
                            h = 1.0/h;
                            c = g*h;
                            s = -f*h;
                            for (long j = 0; j < m; ++j)
                            {
                                y = a(j,nm);
                                z = a(j,i);
                                a(j,nm) = y*c + z*s;
                                a(j,i) = z*c - y*s;
                            }
                        }
                    }

                    z = w(k);
                    if (l == k)
                    {
                        if (z < 0.0)
                        {
                            w(k) = -z;
                            for (long j = 0; j < n; ++j)
                                v(j,k) = -v(j,k);
                        }
                        break;
                    }

                    if (its == max_iter)
                        return false;

                    x = w(l);
                    nm = k - 1;
                    y = w(nm);
                    g = rv1(nm);
                    h = rv1(k);
                    f = ((y-z)*(y+z) + (g-h)*(g+h))/(2.0*h*y);
                    g = pythag(f,one);
                    f = ((x-z)*(x+z) + h*((y/(f+sign(g,f)))-h))/x;
                    c = s = 1.0;
                    for (long j = l; j <= nm; ++j)
                    {
                        long i = j + 1;
                        g = rv1(i);
                        y = w(i);
                        h = s*g;
                        g = c*g;
                        z = pythag(f,h);
                        rv1(j) = z;
                        c = f/z;
                        s = h/z;
                        f = x*c + g*s;
                        g = g*c - x*s;
                        h = y*s;
                        y *= c;
                        for (long jj = 0; jj < n; ++jj)
                        {
                            x = v(jj,j);
                            z = v(jj,i);
                            v(jj,j) = x*c + z*s;
                            v(jj,i) = z*c - x*s;
                        }
                        z = pythag(f,h);
                        w(j) = z;
                        if (z != 0)
                        {
                            z = 1.0/z;
                            c = f*z;
                            s = h*z;
                        }
                        f = c*g + s*y;
                        x = c*y - s*g;
                        for (long jj = 0; jj < m; ++jj)
                        {
                            y = a(jj,j);
                            z = a(jj,i);
                            a(jj,j) = y*c + z*s;
                            a(jj,i) = z*c - y*s;
                        }
                    }
                    rv1(l) = 0.0;
                    rv1(k) = f;
                    w(k) = x;
                }
            }
            return true;
        }

    // ------------------------------------------------------------------------------------

    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename EXP,
        long qN, long qX,
        long uM,
        long vN,
        typename MM1,
        typename MM2,
        typename MM3,
        typename L1
        >
    long svd2 (
        bool withu,
        bool withv,
        const matrix_exp<EXP>& a,
        matrix<typename EXP::type,uM,uM,MM1,L1>& u,
        matrix<typename EXP::type,qN,qX,MM2,L1>& q,
        matrix<typename EXP::type,vN,vN,MM3,L1>& v
    )
    {
        /*
            Singular value decomposition. Translated to 'C' from the
            original Algol code in "Handbook for Automatic Computation,
            vol. II, Linear Algebra", Springer-Verlag.  Note that this
            published algorithm is considered to be the best and numerically
            stable approach to computing the real-valued svd and is referenced
            repeatedly in ieee journal papers, etc where the svd is used.

            This is almost an exact translation from the original, except that
            an iteration counter is added to prevent stalls. This corresponds
            to similar changes in other translations.

            Returns an error code = 0, if no errors and 'k' if a failure to
            converge at the 'kth' singular value.

            USAGE: given the singular value decomposition a = u * diagm(q) * trans(v) for an m*n
                    matrix a with m >= n ...
                    After the svd call u is an m x m matrix which is columnwise
                    orthogonal. q will be an n element vector consisting of singular values
                    and v an n x n orthogonal matrix. eps and tol are tolerance constants.
                    Suitable values are eps=1e-16 and tol=(1e-300)/eps if T == double.

                    If withu == false then u won't be computed and similarly if withv == false
                    then v won't be computed.
        */

        const long NR = matrix_exp<EXP>::NR;
        const long NC = matrix_exp<EXP>::NC;

        // make sure the output matrices have valid dimensions if they are statically dimensioned
        COMPILE_TIME_ASSERT(qX == 0 || qX == 1);
        COMPILE_TIME_ASSERT(NR == 0 || uM == 0 || NR == uM);
        COMPILE_TIME_ASSERT(NC == 0 || vN == 0 || NC == vN);

        DLIB_ASSERT(a.nr() >= a.nc(),
            "\tconst matrix_exp svd2()"
            << "\n\tYou have given an invalidly sized matrix"
            << "\n\ta.nr(): " << a.nr()
            << "\n\ta.nc(): " << a.nc()
            );

        typedef typename EXP::type T;

#ifdef DLIB_USE_LAPACK
        matrix<typename EXP::type,0,0,MM1,L1> temp(a);

        char jobu = 'A';
        char jobvt = 'A';
        if (withu == false)
            jobu = 'N';
        if (withv == false)
            jobvt = 'N';

        int info;
        if (withu == withv)
        {
            info = lapack::gesdd(jobu, temp, q, u, v);
        }
        else
        {
            info = lapack::gesvd(jobu, jobvt, temp, q, u, v);
        }

        // pad q with zeros if it isn't the length we want
        if (q.nr() < a.nc())
            q = join_cols(q, zeros_matrix<T>(a.nc()-q.nr(),1));

        v = trans(v);

        return info;
#else
        using std::abs;
        using std::sqrt;

        T eps = std::numeric_limits<T>::epsilon();
        T tol = std::numeric_limits<T>::min()/eps;

        const long m = a.nr();
        const long n = a.nc();
        long i, j, k, l = 0, l1, iter, retval;
        T c, f, g, h, s, x, y, z;

        matrix<T,qN,1,MM2> e(n,1);
        q.set_size(n,1);
        u.set_size(m,m);
        retval = 0;

        if (withv)
        {
            v.set_size(n,n);
        }

        /* Copy 'a' to 'u' */
        for (i=0; i<m; i++)
        {
            for (j=0; j<n; j++)
                u(i,j) = a(i,j);
        }

        /* Householder's reduction to bidiagonal form. */
        g = x = 0.0;
        for (i=0; i<n; i++)
        {
            e(i) = g;
            s = 0.0;
            l = i + 1;

            for (j=i; j<m; j++)
                s += (u(j,i) * u(j,i));

            if (s < tol)
                g = 0.0;
            else
            {
                f = u(i,i);
                g = (f < 0) ? sqrt(s) : -sqrt(s);
                h = f * g - s;
                u(i,i) = f - g;

                for (j=l; j<n; j++)
                {
                    s = 0.0;

                    for (k=i; k<m; k++)
                        s += (u(k,i) * u(k,j));

                    f = s / h;

                    for (k=i; k<m; k++)
                        u(k,j) += (f * u(k,i));
                } /* end j */
            } /* end s */

            q(i) = g;
            s = 0.0;

            for (j=l; j<n; j++)
                s += (u(i,j) * u(i,j));

            if (s < tol)
                g = 0.0;
            else
            {
                f = u(i,i+1);
                g = (f < 0) ? sqrt(s) : -sqrt(s);
                h = f * g - s;
                u(i,i+1) = f - g;

                for (j=l; j<n; j++)
                    e(j) = u(i,j) / h;

                for (j=l; j<m; j++)
                {
                    s = 0.0;

                    for (k=l; k<n; k++)
                        s += (u(j,k) * u(i,k));

                    for (k=l; k<n; k++)
                        u(j,k) += (s * e(k));
                } /* end j */
            } /* end s */

            y = abs(q(i)) + abs(e(i));
            if (y > x)
                x = y;
        } /* end i */

        /* accumulation of right-hand transformations */
        if (withv)
        {
            for (i=n-1; i>=0; i--)
            {
                if (g != 0.0)
                {
                    h = u(i,i+1) * g;

                    for (j=l; j<n; j++)
                        v(j,i) = u(i,j)/h;

                    for (j=l; j<n; j++)
                    {
                        s = 0.0;

                        for (k=l; k<n; k++)
                            s += (u(i,k) * v(k,j));

                        for (k=l; k<n; k++)
                            v(k,j) += (s * v(k,i));
                    } /* end j */
                } /* end g */

                for (j=l; j<n; j++)
                    v(i,j) = v(j,i) = 0.0;

                v(i,i) = 1.0;
                g = e(i);
                l = i;
            } /* end i */
        } /* end withv, parens added for clarity */

        /* accumulation of left-hand transformations */
        if (withu)
        {
            for (i=n; i<m; i++)
            {
                for (j=n;j<m;j++)
                    u(i,j) = 0.0;

                u(i,i) = 1.0;
            }
        }

        if (withu)
        {
            for (i=n-1; i>=0; i--)
            {
                l = i + 1;
                g = q(i);

                for (j=l; j<m; j++)  /* upper limit was 'n' */
                    u(i,j) = 0.0;

                if (g != 0.0)
                {
                    h = u(i,i) * g;

                    for (j=l; j<m; j++)
                    { /* upper limit was 'n' */
                        s = 0.0;

                        for (k=l; k<m; k++)
                            s += (u(k,i) * u(k,j));

                        f = s / h;

                        for (k=i; k<m; k++)
                            u(k,j) += (f * u(k,i));
                    } /* end j */

                    for (j=i; j<m; j++)
                        u(j,i) /= g;
                } /* end g */
                else
                {
                    for (j=i; j<m; j++)
                        u(j,i) = 0.0;
                }

                u(i,i) += 1.0;
            } /* end i*/
        } /* end withu, parens added for clarity */

        /* diagonalization of the bidiagonal form */
        eps *= x;

        for (k=n-1; k>=0; k--)
        {
            iter = 0;

test_f_splitting:

            for (l=k; l>=0; l--)
            {
                if (abs(e(l)) <= eps)
                    goto test_f_convergence;

                if (abs(q(l-1)) <= eps)
                    goto cancellation;
            } /* end l */

            /* cancellation of e(l) if l > 0 */

cancellation:

            c = 0.0;
            s = 1.0;
            l1 = l - 1;

            for (i=l; i<=k; i++)
            {
                f = s * e(i);
                e(i) *= c;

                if (abs(f) <= eps)
                    goto test_f_convergence;

                g = q(i);
                h = q(i) = sqrt(f*f + g*g);
                c = g / h;
                s = -f / h;

                if (withu)
                {
                    for (j=0; j<m; j++)
                    {
                        y = u(j,l1);
                        z = u(j,i);
                        u(j,l1) = y * c + z * s;
                        u(j,i) = -y * s + z * c;
                    } /* end j */
                } /* end withu, parens added for clarity */
            } /* end i */

test_f_convergence:

            z = q(k);
            if (l == k)
                goto convergence;

            /* shift from bottom 2x2 minor */
            iter++;
            if (iter > 300)
            {
                retval = k;
                break;
            }
            x = q(l);
            y = q(k-1);
            g = e(k-1);
            h = e(k);
            f = ((y - z) * (y + z) + (g - h) * (g + h)) / (2 * h * y);
            g = sqrt(f * f + 1.0);
            f = ((x - z) * (x + z) + h * (y / ((f < 0)?(f - g) : (f + g)) - h)) / x;

            /* next QR transformation */
            c = s = 1.0;

            for (i=l+1; i<=k; i++)
            {
                g = e(i);
                y = q(i);
                h = s * g;
                g *= c;
                e(i-1) = z = sqrt(f * f + h * h);
                c = f / z;
                s = h / z;
                f = x * c + g * s;
                g = -x * s + g * c;
                h = y * s;
                y *= c;

                if (withv)
                {
                    for (j=0;j<n;j++)
                    {
                        x = v(j,i-1);
                        z = v(j,i);
                        v(j,i-1) = x * c + z * s;
                        v(j,i) = -x * s + z * c;
                    } /* end j */
                } /* end withv, parens added for clarity */

                q(i-1) = z = sqrt(f * f + h * h);
                c = f / z;
                s = h / z;
                f = c * g + s * y;
                x = -s * g + c * y;
                if (withu)
                {
                    for (j=0; j<m; j++)
                    {
                        y = u(j,i-1);
                        z = u(j,i);
                        u(j,i-1) = y * c + z * s;
                        u(j,i) = -y * s + z * c;
                    } /* end j */
                } /* end withu, parens added for clarity */
            } /* end i */

            e(l) = 0.0;
            e(k) = f;
            q(k) = x;

            goto test_f_splitting;

convergence:

            if (z < 0.0)
            {
                /* q(k) is made non-negative */
                q(k) = -z;
                if (withv)
                {
                    for (j=0; j<n; j++)
                        v(j,k) = -v(j,k);
                } /* end withv, parens added for clarity */
            } /* end z */
        } /* end k */

        return retval;
#endif
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        long NR,
        long NC,
        typename MM,
        typename L
        >
    void orthogonalize (
        matrix<T,NR,NC,MM,L>& m
    )
    {
        qr_decomposition<matrix<T,NR,NC,MM,L> >(m).get_q(m);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        long Anr, long Anc,
        typename MM,
        typename L
        >
    void find_matrix_range (
        const matrix<T,Anr,Anc,MM,L>& A,
        unsigned long l,
        matrix<T,Anr,0,MM,L>& Q,
        unsigned long q
    )
    /*!
        requires
            - A.nr() >= l
        ensures
            - #Q.nr() == A.nr()
            - #Q.nc() == l
            - #Q == an orthonormal matrix whose range approximates the range of the
              matrix A.
            - This function implements the randomized subspace iteration defined
              in the algorithm 4.4 box of the paper:
                Finding Structure with Randomness: Probabilistic Algorithms for
                Constructing Approximate Matrix Decompositions by Halko et al.
            - q defines the number of extra subspace iterations this algorithm will
              perform.  Often q == 0 is fine, but performing more iterations can lead to a
              more accurate approximation of the range of A if A has slowly decaying
              singular values.  In these cases, using a q of 1 or 2 is good.
    !*/
    {
        DLIB_ASSERT(A.nr() >= (long)l, "Invalid inputs were given to this function.");
        Q = A*matrix_cast<T>(gaussian_randm(A.nc(), l));

        orthogonalize(Q);

        // Do some extra iterations of the power method to make sure we get Q into the
        // span of the most important singular vectors of A.
        if (q != 0)
        {
            for (unsigned long itr = 0; itr < q; ++itr)
            {
                Q = trans(A)*Q;
                orthogonalize(Q);

                Q = A*Q;
                orthogonalize(Q);
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        long Anr, long Anc,
        long Unr, long Unc,
        long Wnr, long Wnc,
        long Vnr, long Vnc,
        typename MM,
        typename L
        >
    void svd_fast (
        const matrix<T,Anr,Anc,MM,L>& A,
        matrix<T,Unr,Unc,MM,L>& u,
        matrix<T,Wnr,Wnc,MM,L>& w,
        matrix<T,Vnr,Vnc,MM,L>& v,
        unsigned long l,
        unsigned long q = 1
    )
    {
        const unsigned long k = std::min(l, std::min<unsigned long>(A.nr(),A.nc()));

        DLIB_ASSERT(l > 0 && A.size() > 0,
            "\t void svd_fast()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t l: " << l
            << "\n\t A.size(): " << A.size()
            );

        matrix<T,Anr,0,MM,L> Q;
        find_matrix_range(A, k, Q, q);

        // Compute trans(B) = trans(Q)*A.   The reason we store B transposed
        // is so that when we take its SVD later using svd3() it doesn't consume
        // a whole lot of RAM.  That is, we make sure the square matrix coming out
        // of svd3() has size lxl rather than the potentially much larger nxn.
        matrix<T,0,0,MM,L> B = trans(A)*Q;
        svd3(B, v,w,u);
        u = Q*u;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename sparse_vector_type,
        typename T,
        typename MM,
        typename L
        >
    void find_matrix_range (
        const std::vector<sparse_vector_type>& A,
        unsigned long l,
        matrix<T,0,0,MM,L>& Q,
        unsigned long q
    )
    /*!
        requires
            - A.size() >= l
        ensures
            - #Q.nr() == A.size()
            - #Q.nc() == l
            - #Q == an orthonormal matrix whose range approximates the range of the
              matrix A.  In this case, we interpret A as a matrix of A.size() rows,
              where each row is defined by a sparse vector.
            - This function implements the randomized subspace iteration defined
              in the algorithm 4.4 box of the paper:
                Finding Structure with Randomness: Probabilistic Algorithms for
                Constructing Approximate Matrix Decompositions by Halko et al.
            - q defines the number of extra subspace iterations this algorithm will
              perform.  Often q == 0 is fine, but performing more iterations can lead to a
              more accurate approximation of the range of A if A has slowly decaying
              singular values.  In these cases, using a q of 1 or 2 is good.
    !*/
    {
        DLIB_ASSERT(A.size() >= l, "Invalid inputs were given to this function.");
        Q.set_size(A.size(), l);

        // Compute Q = A*gaussian_randm()
        for (long r = 0; r < Q.nr(); ++r)
        {
            for (long c = 0; c < Q.nc(); ++c)
            {
                Q(r,c) = dot(A[r], gaussian_randm(std::numeric_limits<long>::max(), 1, c));
            }
        }

        orthogonalize(Q);

        // Do some extra iterations of the power method to make sure we get Q into the
        // span of the most important singular vectors of A.
        if (q != 0)
        {
            const unsigned long n = max_index_plus_one(A);
            for (unsigned long itr = 0; itr < q; ++itr)
            {
                matrix<T,0,0,MM,L> Z(n, l);
                // Compute Z = trans(A)*Q
                Z = 0;
                for (unsigned long m = 0; m < A.size(); ++m)
                {
                    for (unsigned long r = 0; r < l; ++r)
                    {
                        typename sparse_vector_type::const_iterator i;
                        for (i = A[m].begin(); i != A[m].end(); ++i)
                        {
                            const unsigned long c = i->first;
                            const T val = i->second;

                            Z(c,r) += Q(m,r)*val;
                        }
                    }
                }

                Q.set_size(0,0); // free RAM
                orthogonalize(Z);

                // Compute Q = A*Z
                Q.set_size(A.size(), l);
                for (long r = 0; r < Q.nr(); ++r)
                {
                    for (long c = 0; c < Q.nc(); ++c)
                    {
                        Q(r,c) = dot(A[r], colm(Z,c));
                    }
                }

                Z.set_size(0,0); // free RAM
                orthogonalize(Q);
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename sparse_vector_type,
        typename T,
        long Unr, long Unc,
        long Wnr, long Wnc,
        long Vnr, long Vnc,
        typename MM,
        typename L
        >
    void svd_fast (
        const std::vector<sparse_vector_type>& A,
        matrix<T,Unr,Unc,MM,L>& u,
        matrix<T,Wnr,Wnc,MM,L>& w,
        matrix<T,Vnr,Vnc,MM,L>& v,
        unsigned long l,
        unsigned long q = 1
    )
    {
        const long n = max_index_plus_one(A);
        const unsigned long k = std::min(l, std::min<unsigned long>(A.size(),n));

        DLIB_ASSERT(l > 0 && A.size() > 0 && n > 0,
            "\t void svd_fast()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t l: " << l
            << "\n\t n (i.e. max_index_plus_one(A)): " << n
            << "\n\t A.size(): " << A.size()
            );

        matrix<T,0,0,MM,L> Q;
        find_matrix_range(A, k, Q, q);

        // Compute trans(B) = trans(Q)*A.   The reason we store B transposed
        // is so that when we take its SVD later using svd3() it doesn't consume
        // a whole lot of RAM.  That is, we make sure the square matrix coming out
        // of svd3() has size lxl rather than the potentially much larger nxn.
        matrix<T,0,0,MM,L> B(n,k);
        B = 0;
        for (unsigned long m = 0; m < A.size(); ++m)
        {
            for (unsigned long r = 0; r < k; ++r)
            {
                typename sparse_vector_type::const_iterator i;
                for (i = A[m].begin(); i != A[m].end(); ++i)
                {
                    const unsigned long c = i->first;
                    const T val = i->second;

                    B(c,r) += Q(m,r)*val;
                }
            }
        }

        svd3(B, v,w,u);
        u = Q*u;
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename EXP,
        long N
        >
    struct inv_helper
    {
        static const typename matrix_exp<EXP>::matrix_type inv (
            const matrix_exp<EXP>& m
        )
        {
            using namespace nric;
            // you can't invert a non-square matrix
            COMPILE_TIME_ASSERT(matrix_exp<EXP>::NR == matrix_exp<EXP>::NC ||
                                matrix_exp<EXP>::NR == 0 ||
                                matrix_exp<EXP>::NC == 0);
            DLIB_ASSERT(m.nr() == m.nc(),
                "\tconst matrix_exp::type inv(const matrix_exp& m)"
                << "\n\tYou can only apply inv() to a square matrix"
                << "\n\tm.nr(): " << m.nr()
                << "\n\tm.nc(): " << m.nc()
                );
            typedef typename matrix_exp<EXP>::type type;

            lu_decomposition<EXP> lu(m);
            return lu.solve(identity_matrix<type>(m.nr()));
        }
    };

    template <
        typename EXP
        >
    struct inv_helper<EXP,1>
    {
        static const typename matrix_exp<EXP>::matrix_type inv (
            const matrix_exp<EXP>& m
        )
        {
            COMPILE_TIME_ASSERT(matrix_exp<EXP>::NR == matrix_exp<EXP>::NC);
            typedef typename matrix_exp<EXP>::type type;

            matrix<type, 1, 1, typename EXP::mem_manager_type> a;
            // if m is invertible
            if (m(0) != 0)
                a(0) = 1/m(0);
            else
                a(0) = 1;
            return a;
        }
    };

    template <
        typename EXP
        >
    struct inv_helper<EXP,2>
    {
        static const typename matrix_exp<EXP>::matrix_type inv (
            const matrix_exp<EXP>& m
        )
        {
            COMPILE_TIME_ASSERT(matrix_exp<EXP>::NR == matrix_exp<EXP>::NC);
            typedef typename matrix_exp<EXP>::type type;

            matrix<type, 2, 2, typename EXP::mem_manager_type> a;
            type d = det(m);
            if (d != 0)
            {
                d = static_cast<type>(1.0/d);
                a(0,0) = m(1,1)*d;
                a(0,1) = m(0,1)*-d;
                a(1,0) = m(1,0)*-d;
                a(1,1) = m(0,0)*d;
            }
            else
            {
                // Matrix isn't invertible so just return the identity matrix.
                a = identity_matrix<type,2>();
            }
            return a;
        }
    };

    template <
        typename EXP
        >
    struct inv_helper<EXP,3>
    {
        static const typename matrix_exp<EXP>::matrix_type inv (
            const matrix_exp<EXP>& m
        )
        {
            COMPILE_TIME_ASSERT(matrix_exp<EXP>::NR == matrix_exp<EXP>::NC);
            typedef typename matrix_exp<EXP>::type type;

            matrix<type, 3, 3, typename EXP::mem_manager_type> ret;
            type de = det(m);
            if (de != 0)
            {
                de = static_cast<type>(1.0/de);
                const type a = m(0,0);
                const type b = m(0,1);
                const type c = m(0,2);
                const type d = m(1,0);
                const type e = m(1,1);
                const type f = m(1,2);
                const type g = m(2,0);
                const type h = m(2,1);
                const type i = m(2,2);

                ret(0,0) = (e*i - f*h)*de;
                ret(1,0) = (f*g - d*i)*de;
                ret(2,0) = (d*h - e*g)*de;

                ret(0,1) = (c*h - b*i)*de;
                ret(1,1) = (a*i - c*g)*de;
                ret(2,1) = (b*g - a*h)*de;

                ret(0,2) = (b*f - c*e)*de;
                ret(1,2) = (c*d - a*f)*de;
                ret(2,2) = (a*e - b*d)*de;
            }
            else
            {
                ret = identity_matrix<type,3>();
            }

            return ret;
        }
    };

    template <
        typename EXP
        >
    struct inv_helper<EXP,4>
    {
        static const typename matrix_exp<EXP>::matrix_type inv (
            const matrix_exp<EXP>& m
        )
        {
            COMPILE_TIME_ASSERT(matrix_exp<EXP>::NR == matrix_exp<EXP>::NC);
            typedef typename matrix_exp<EXP>::type type;

            matrix<type, 4, 4, typename EXP::mem_manager_type> ret;
            type de = det(m);
            if (de != 0)
            {
                de = static_cast<type>(1.0/de);
                ret(0,0) =  det(removerc<0,0>(m));
                ret(0,1) = -det(removerc<0,1>(m));
                ret(0,2) =  det(removerc<0,2>(m));
                ret(0,3) = -det(removerc<0,3>(m));

                ret(1,0) = -det(removerc<1,0>(m));
                ret(1,1) =  det(removerc<1,1>(m));
                ret(1,2) = -det(removerc<1,2>(m));
                ret(1,3) =  det(removerc<1,3>(m));

                ret(2,0) =  det(removerc<2,0>(m));
                ret(2,1) = -det(removerc<2,1>(m));
                ret(2,2) =  det(removerc<2,2>(m));
                ret(2,3) = -det(removerc<2,3>(m));

                ret(3,0) = -det(removerc<3,0>(m));
                ret(3,1) =  det(removerc<3,1>(m));
                ret(3,2) = -det(removerc<3,2>(m));
                ret(3,3) =  det(removerc<3,3>(m));

                return trans(ret)*de;
            }
            else
            {
                return identity_matrix<type,4>();
            }
        }
    };

    template <
        typename EXP
        >
    inline const typename matrix_exp<EXP>::matrix_type inv (
        const matrix_exp<EXP>& m
    ) { return inv_helper<EXP,matrix_exp<EXP>::NR>::inv(m); }

// ----------------------------------------------------------------------------------------

    template <typename M>
    struct op_diag_inv
    {
        template <typename EXP>
        op_diag_inv( const matrix_exp<EXP>& m_) : m(m_){}

        const static long cost = 1;
        const static long NR = ((M::NC!=0)&&(M::NR!=0))? (tmax<M::NR,M::NC>::value) : (0);
        const static long NC = NR;
        typedef typename M::type type;
        typedef const type const_ret_type;
        typedef typename M::mem_manager_type mem_manager_type;
        typedef typename M::layout_type layout_type;

        // hold the matrix by value
        const matrix<type,NR,1,mem_manager_type,layout_type> m;

        const_ret_type apply ( long r, long c) const
        {
            if (r==c)
                return m(r);
            else
                return 0;
        }

        long nr () const { return m.size(); }
        long nc () const { return m.size(); }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }
    };

    template <
        typename EXP
        >
    const matrix_diag_op<op_diag_inv<EXP> > inv (
        const matrix_diag_exp<EXP>& m
    )
    {
        typedef op_diag_inv<EXP> op;
        return matrix_diag_op<op>(op(reciprocal(diag(m))));
    }

    template <
        typename EXP
        >
    const matrix_diag_op<op_diag_inv<EXP> > pinv (
        const matrix_diag_exp<EXP>& m
    )
    {
        typedef op_diag_inv<EXP> op;
        return matrix_diag_op<op>(op(reciprocal(diag(m))));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP
        >
    const matrix_diag_op<op_diag_inv<EXP> > pinv (
        const matrix_diag_exp<EXP>& m,
        double tol
    )
    {
        DLIB_ASSERT(tol >= 0,
            "\tconst matrix_exp::type pinv(const matrix_exp& m)"
            << "\n\t tol can't be negative"
            << "\n\t tol: "<<tol
            );
        typedef op_diag_inv<EXP> op;
        return matrix_diag_op<op>(op(reciprocal(round_zeros(diag(m),tol))));
    }

// ----------------------------------------------------------------------------------------

    template <typename EXP>
    const typename matrix_exp<EXP>::matrix_type  inv_lower_triangular (
        const matrix_exp<EXP>& A
    )
    {
        DLIB_ASSERT(A.nr() == A.nc(),
            "\tconst matrix inv_lower_triangular(const matrix_exp& A)"
            << "\n\tA must be a square matrix"
            << "\n\tA.nr(): " << A.nr()
            << "\n\tA.nc(): " << A.nc()
            );

        typedef typename matrix_exp<EXP>::matrix_type matrix_type;

        matrix_type m(A);

        for(long c = 0; c < m.nc(); ++c)
        {
            if( m(c,c) == 0 )
            {
                // there isn't an inverse so just give up
                return m;
            }

            // compute m(c,c)
            m(c,c) = 1/m(c,c);

            // compute the values in column c that are below m(c,c).
            // We do this by just doing the same thing we do for upper triangular
            // matrices because we take the transpose of m which turns m into an
            // upper triangular matrix.
            for(long r = 0; r < c; ++r)
            {
                const long n = c-r;
                m(c,r) = -m(c,c)*subm(trans(m),r,r,1,n)*subm(trans(m),r,c,n,1);
            }
        }

        return m;

    }

// ----------------------------------------------------------------------------------------

    template <typename EXP>
    const typename matrix_exp<EXP>::matrix_type  inv_upper_triangular (
        const matrix_exp<EXP>& A
    )
    {
        DLIB_ASSERT(A.nr() == A.nc(),
            "\tconst matrix inv_upper_triangular(const matrix_exp& A)"
            << "\n\tA must be a square matrix"
            << "\n\tA.nr(): " << A.nr()
            << "\n\tA.nc(): " << A.nc()
            );

        typedef typename matrix_exp<EXP>::matrix_type matrix_type;

        matrix_type m(A);

        for(long c = 0; c < m.nc(); ++c)
        {
            if( m(c,c) == 0 )
            {
                // there isn't an inverse so just give up
                return m;
            }

            // compute m(c,c)
            m(c,c) = 1/m(c,c);

            // compute the values in column c that are above m(c,c)
            for(long r = 0; r < c; ++r)
            {
                const long n = c-r;
                m(r,c) = -m(c,c)*subm(m,r,r,1,n)*subm(m,r,c,n,1);
            }
        }

        return m;

    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP
        >
    inline const typename matrix_exp<EXP>::matrix_type chol (
        const matrix_exp<EXP>& A
    )
    {
        DLIB_ASSERT(A.nr() == A.nc(),
            "\tconst matrix chol(const matrix_exp& A)"
            << "\n\tYou can only apply the chol to a square matrix"
            << "\n\tA.nr(): " << A.nr()
            << "\n\tA.nc(): " << A.nc()
            );
        typename matrix_exp<EXP>::matrix_type L(A.nr(),A.nc());

#ifdef DLIB_USE_LAPACK
        // Only call LAPACK if the matrix is big enough.  Otherwise,
        // our own code is faster, especially for statically dimensioned
        // matrices.
        if (A.nr() > 4)
        {
            L = A;
            lapack::potrf('L', L);
            // mask out upper triangular area
            return lowerm(L);
        }
#endif
        typedef typename EXP::type T;
        set_all_elements(L,0);

        // do nothing if the matrix is empty
        if (A.size() == 0)
            return L;

        const T eps = std::numeric_limits<T>::epsilon();

        // compute the upper left corner
        if (A(0,0) > 0)
            L(0,0) = std::sqrt(A(0,0));

        // compute the first column
        for (long r = 1; r < A.nr(); ++r)
        {
            // if (L(0,0) > 0)
            if (L(0,0) > eps*std::abs(A(r,0)))
                L(r,0) = A(r,0)/L(0,0);
            else
                return L;
        }

        // now compute all the other columns
        for (long c = 1; c < A.nc(); ++c)
        {
            // compute the diagonal element
            T temp = A(c,c);
            for (long i = 0; i < c; ++i)
            {
                temp -= L(c,i)*L(c,i);
            }
            if (temp > 0)
                L(c,c) = std::sqrt(temp);

            // compute the non diagonal elements
            for (long r = c+1; r < A.nr(); ++r)
            {
                temp = A(r,c);
                for (long i = 0; i < c; ++i)
                {
                    temp -= L(r,i)*L(c,i);
                }

                // if (L(c,c) > 0)
                if (L(c,c) > eps*std::abs(temp))
                    L(r,c) = temp/L(c,c);
                else
                    return L;
            }
        }

        return L;

    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP,
        long uNR,
        long uNC,
        long wN,
        long vN,
        long wX,
        typename MM1,
        typename MM2,
        typename MM3,
        typename L1
        >
    inline void svd3 (
        const matrix_exp<EXP>& m,
        matrix<typename matrix_exp<EXP>::type, uNR, uNC,MM1,L1>& u,
        matrix<typename matrix_exp<EXP>::type, wN, wX,MM2,L1>& w,
        matrix<typename matrix_exp<EXP>::type, vN, vN,MM3,L1>& v
    )
    {
        typedef typename matrix_exp<EXP>::type T;
        const long NR = matrix_exp<EXP>::NR;
        const long NC = matrix_exp<EXP>::NC;

        // make sure the output matrices have valid dimensions if they are statically dimensioned
        COMPILE_TIME_ASSERT(NR == 0 || uNR == 0 || NR == uNR);
        COMPILE_TIME_ASSERT(NC == 0 || uNC == 0 || NC == uNC);
        COMPILE_TIME_ASSERT(NC == 0 || wN == 0 || NC == wN);
        COMPILE_TIME_ASSERT(NC == 0 || vN == 0 || NC == vN);
        COMPILE_TIME_ASSERT(wX == 0 || wX == 1);

#ifdef DLIB_USE_LAPACK
        // use LAPACK but only if it isn't a really small matrix we are taking the SVD of.
        if (NR*NC == 0 || NR*NC > 3*3)
        {
            matrix<typename matrix_exp<EXP>::type, uNR, uNC,MM1,L1> temp(m);
            lapack::gesvd('S','A', temp, w, u, v);
            v = trans(v);
            // if u isn't the size we want then pad it (and v) with zeros
            if (u.nc() < m.nc())
            {
                w = join_cols(w, zeros_matrix<T>(m.nc()-u.nc(),1));
                u = join_rows(u, zeros_matrix<T>(u.nr(), m.nc()-u.nc()));
            }
            return;
        }
#endif
        v.set_size(m.nc(),m.nc());

        u = m;

        w.set_size(m.nc(),1);
        matrix<T,matrix_exp<EXP>::NC,1,MM1> rv1(m.nc(),1);
        nric::svdcmp(u,w,v,rv1);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP
        >
    const matrix<typename EXP::type,EXP::NC,EXP::NR,typename EXP::mem_manager_type> pinv_helper (
        const matrix_exp<EXP>& m,
        double tol
    )
    /*!
        ensures
            - computes the results of pinv(m) but does so using a method that is fastest
              when m.nc() <= m.nr().  So if m.nc() > m.nr() then it is best to use
              trans(pinv_helper(trans(m))) to compute pinv(m).
    !*/
    {
        typename matrix_exp<EXP>::matrix_type u;
        typedef typename EXP::mem_manager_type MM1;
        typedef typename EXP::layout_type layout_type;
        matrix<typename EXP::type, EXP::NC, EXP::NC,MM1, layout_type > v;

        typedef typename matrix_exp<EXP>::type T;

        matrix<T,matrix_exp<EXP>::NC,1,MM1, layout_type> w;

        svd3(m, u,w,v);

        const double machine_eps = std::numeric_limits<typename EXP::type>::epsilon();
        // compute a reasonable epsilon below which we round to zero before doing the
        // reciprocal.  Unless a non-zero tol is given then we just use tol.
        const double eps = (tol!=0) ? tol :  machine_eps*std::max(m.nr(),m.nc())*max(w);

        // now compute the pseudoinverse
        return tmp(scale_columns(v,reciprocal(round_zeros(w,eps))))*trans(u);
    }

    template <
        typename EXP
        >
    const matrix<typename EXP::type,EXP::NC,EXP::NR,typename EXP::mem_manager_type> pinv (
        const matrix_exp<EXP>& m,
        double tol = 0
    )
    {
        DLIB_ASSERT(tol >= 0,
            "\tconst matrix_exp::type pinv(const matrix_exp& m)"
            << "\n\t tol can't be negative"
            << "\n\t tol: "<<tol
            );
        // if m has more columns then rows then it is more efficient to
        // compute the pseudo-inverse of its transpose (given the way I'm doing it below).
        if (m.nc() > m.nr())
            return trans(pinv_helper(trans(m),tol));
        else
            return pinv_helper(m,tol);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP,
        long uNR,
        long uNC,
        long wN,
        long vN,
        typename MM1,
        typename MM2,
        typename MM3,
        typename L1
        >
    inline void svd (
        const matrix_exp<EXP>& m,
        matrix<typename matrix_exp<EXP>::type, uNR, uNC,MM1,L1>& u,
        matrix<typename matrix_exp<EXP>::type, wN, wN,MM2,L1>& w,
        matrix<typename matrix_exp<EXP>::type, vN, vN,MM3,L1>& v
    )
    {
        typedef typename matrix_exp<EXP>::type T;
        const long NR = matrix_exp<EXP>::NR;
        const long NC = matrix_exp<EXP>::NC;

        // make sure the output matrices have valid dimensions if they are statically dimensioned
        COMPILE_TIME_ASSERT(NR == 0 || uNR == 0 || NR == uNR);
        COMPILE_TIME_ASSERT(NC == 0 || uNC == 0 || NC == uNC);
        COMPILE_TIME_ASSERT(NC == 0 || wN == 0 || NC == wN);
        COMPILE_TIME_ASSERT(NC == 0 || vN == 0 || NC == vN);

        matrix<T,matrix_exp<EXP>::NC,1,MM1, L1> W;
        svd3(m,u,W,v);
        w = diagm(W);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP
        >
    const typename matrix_exp<EXP>::type trace (
        const matrix_exp<EXP>& m
    )
    {
        COMPILE_TIME_ASSERT(matrix_exp<EXP>::NR == matrix_exp<EXP>::NC ||
                            matrix_exp<EXP>::NR == 0 ||
                            matrix_exp<EXP>::NC == 0
                            );
        DLIB_ASSERT(m.nr() == m.nc(),
            "\tconst matrix_exp::type trace(const matrix_exp& m)"
            << "\n\tYou can only apply trace() to a square matrix"
            << "\n\tm.nr(): " << m.nr()
            << "\n\tm.nc(): " << m.nc()
            );
        return sum(diag(m));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP,
        long N = EXP::NR
        >
    struct det_helper
    {
        static const typename matrix_exp<EXP>::type det (
            const matrix_exp<EXP>& m
        )
        {
            using namespace nric;
            COMPILE_TIME_ASSERT(matrix_exp<EXP>::NR == matrix_exp<EXP>::NC ||
                                matrix_exp<EXP>::NR == 0 ||
                                matrix_exp<EXP>::NC == 0
                                );
            DLIB_ASSERT(m.nr() == m.nc(),
                "\tconst matrix_exp::type det(const matrix_exp& m)"
                << "\n\tYou can only apply det() to a square matrix"
                << "\n\tm.nr(): " << m.nr()
                << "\n\tm.nc(): " << m.nc()
                );

            return lu_decomposition<EXP>(m).det();
        }
    };

    template <
        typename EXP
        >
    struct det_helper<EXP,1>
    {
        static const typename matrix_exp<EXP>::type det (
            const matrix_exp<EXP>& m
        )
        {
            COMPILE_TIME_ASSERT(matrix_exp<EXP>::NR == matrix_exp<EXP>::NC);

            return m(0);
        }
    };

    template <
        typename EXP
        >
    struct det_helper<EXP,2>
    {
        static const typename matrix_exp<EXP>::type det (
            const matrix_exp<EXP>& m
        )
        {
            COMPILE_TIME_ASSERT(matrix_exp<EXP>::NR == matrix_exp<EXP>::NC);

            return m(0,0)*m(1,1) - m(0,1)*m(1,0);
        }
    };

    template <
        typename EXP
        >
    struct det_helper<EXP,3>
    {
        static const typename matrix_exp<EXP>::type det (
            const matrix_exp<EXP>& m
        )
        {
            COMPILE_TIME_ASSERT(matrix_exp<EXP>::NR == matrix_exp<EXP>::NC);
            typedef typename matrix_exp<EXP>::type type;

            type temp = m(0,0)*(m(1,1)*m(2,2) - m(1,2)*m(2,1)) -
                        m(0,1)*(m(1,0)*m(2,2) - m(1,2)*m(2,0)) +
                        m(0,2)*(m(1,0)*m(2,1) - m(1,1)*m(2,0));
            return temp;
        }
    };

    template <
        typename EXP
        >
    inline const typename matrix_exp<EXP>::type det (
        const matrix_exp<EXP>& m
    ) { return det_helper<EXP>::det(m); }

    template <
        typename EXP
        >
    struct det_helper<EXP,4>
    {
        static const typename matrix_exp<EXP>::type det (
            const matrix_exp<EXP>& m
        )
        {
            COMPILE_TIME_ASSERT(matrix_exp<EXP>::NR == matrix_exp<EXP>::NC);
            typedef typename matrix_exp<EXP>::type type;

            type temp = m(0,0)*(dlib::det(removerc<0,0>(m))) -
                        m(0,1)*(dlib::det(removerc<0,1>(m))) +
                        m(0,2)*(dlib::det(removerc<0,2>(m))) -
                        m(0,3)*(dlib::det(removerc<0,3>(m)));
            return temp;
        }
    };

// ----------------------------------------------------------------------------------------

    template <typename EXP>
    const matrix<typename EXP::type, EXP::NR, 1, typename EXP::mem_manager_type, typename EXP::layout_type> real_eigenvalues (
        const matrix_exp<EXP>& m
    )
    {
        // You can only use this function with matrices that contain float or double values
        COMPILE_TIME_ASSERT((is_same_type<typename EXP::type, float>::value ||
                             is_same_type<typename EXP::type, double>::value));

        DLIB_ASSERT(m.nr() == m.nc(),
            "\tconst matrix real_eigenvalues()"
            << "\n\tYou have given an invalidly sized matrix"
            << "\n\tm.nr(): " << m.nr()
            << "\n\tm.nc(): " << m.nc()
            );

        if (m.nr() == 2)
        {
            typedef typename EXP::type T;
            const T m00 = m(0,0);
            const T m01 = m(0,1);
            const T m10 = m(1,0);
            const T m11 = m(1,1);

            const T b = -(m00 + m11);
            const T c = m00*m11 - m01*m10;
            matrix<T,EXP::NR,1, typename EXP::mem_manager_type, typename EXP::layout_type> v(2);

            T disc = b*b - 4*c;
            if (disc >= 0)
                disc = std::sqrt(disc);
            else
                disc = 0;

            v(0) = (-b + disc)/2;
            v(1) = (-b - disc)/2;
            return v;
        }
        else
        {
            // Call .ref() so that the symmetric matrix overload can take effect if m
            // has the appropriate type.
            return eigenvalue_decomposition<EXP>(m.ref()).get_real_eigenvalues();
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP
        >
    dlib::vector<double,2> max_point_interpolated (
        const matrix_exp<EXP>& m
    )
    {
        DLIB_ASSERT(m.size() > 0,
            "\tdlib::vector<double,2> point max_point_interpolated(const matrix_exp& m)"
            << "\n\tm can't be empty"
            << "\n\tm.size():   " << m.size()
            << "\n\tm.nr():     " << m.nr()
            << "\n\tm.nc():     " << m.nc()
            );
        const point p = max_point(m);

        // If this is a column vector then just do interpolation along a line.
        if (m.nc()==1)
        {
            const long pos = p.y();
            if (0 < pos && pos+1 < m.nr())
            {
                double v1 = dlib::impl::magnitude(m(pos-1));
                double v2 = dlib::impl::magnitude(m(pos));
                double v3 = dlib::impl::magnitude(m(pos+1));
                double y = lagrange_poly_min_extrap(pos-1,pos,pos+1, -v1, -v2, -v3);
                return vector<double,2>(0,y);
            }
        }
        // If this is a row vector then just do interpolation along a line.
        if (m.nr()==1)
        {
            const long pos = p.x();
            if (0 < pos && pos+1 < m.nc())
            {
                double v1 = dlib::impl::magnitude(m(pos-1));
                double v2 = dlib::impl::magnitude(m(pos));
                double v3 = dlib::impl::magnitude(m(pos+1));
                double x = lagrange_poly_min_extrap(pos-1,pos,pos+1, -v1, -v2, -v3);
                return vector<double,2>(x,0);
            }
        }

        // If it's on the border then just return the regular max point.
        if (shrink_rect(get_rect(m),1).contains(p) == false)
            return p;

        //matrix<double> A(9,6);
        //matrix<double,0,1> G(9);

        matrix<double,9,1> pix;
        long i = 0;
        for (long r = -1; r <= +1; ++r)
        {
            for (long c = -1; c <= +1; ++c)
            {
                pix(i) = dlib::impl::magnitude(m(p.y()+r,p.y()+c));
                /*
                A(i,0) = c*c;
                A(i,1) = c*r;
                A(i,2) = r*r;
                A(i,3) = c;
                A(i,4) = r;
                A(i,5) = 1;
                G(i) = std::exp(-1*(r*r+c*c)/2.0); // Use a gaussian windowing function around p.
                */
                ++i;
            }
        }

        // This bit of code is how we generated the derivative_filters matrix below.
        //A = diagm(G)*A;
        //std::cout << std::setprecision(20) << inv(trans(A)*A)*trans(A)*diagm(G) << std::endl; exit(1);

        const double m10 = 0.10597077880854270659;
        const double m21 = 0.21194155761708535768;
        const double m28 = 0.28805844238291455905;
        const double m57 = 0.57611688476582878504;
        // So this derivative_filters finds the parameters of the quadratic surface that best fits
        // the 3x3 region around p.  Then we find the maximizer of that surface within that
        // small region and return that as the maximum location.
        const double derivative_filters[] = {
                // xx
                m10,-m21,m10,
                m28,-m57,m28,
                m10,-m21,m10,

                // xy
                0.25 ,0,-0.25,
                0    ,0, 0,
                -0.25,0,0.25,

                // yy
                m10,  m28, m10,
                -m21,-m57,-m21,
                m10,  m28, m10,

                // x
                -m10,0,m10,
                -m28,0,m28,
                -m10,0,m10,

                // y
                -m10,-m28,-m10,
                0,   0,   0,
                m10, m28, m10
            };
        const matrix<double,5,9> filt(derivative_filters);
        // Now w contains the parameters of the quadratic surface
        const matrix<double,5,1> w = filt*pix;

        // Now newton step to the max point on the surface
        matrix<double,2,2> H;
        matrix<double,2,1> g;
        H = 2*w(0), w(1),
              w(1), 2*w(2);
        g = w(3),
            w(4);
        const dlib::vector<double,2> delta = -inv(H)*g;

        // if delta isn't in an ascent direction then just use the normal max point.
        if (dot(delta, g) < 0)
            return p;
        else
            return vector<double,2>(p)+clamp(delta, -1, 1);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MATRIx_LA_FUNCTS_


dlib C++ Library - matrix_lu.h

// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
// This code was adapted from code from the JAMA part of NIST's TNT library.
//    See: http://math.nist.gov/tnt/
#ifndef DLIB_MATRIX_LU_DECOMPOSITION_H
#define DLIB_MATRIX_LU_DECOMPOSITION_H

#include "matrix.h"
#include "matrix_utilities.h"
#include "matrix_subexp.h"
#include "matrix_trsm.h"
#include <algorithm>

#ifdef DLIB_USE_LAPACK
#include "lapack/getrf.h"
#endif

namespace dlib
{

    template <
        typename matrix_exp_type
        >
    class lu_decomposition
    {
    public:

        const static long NR = matrix_exp_type::NR;
        const static long NC = matrix_exp_type::NC;
        typedef typename matrix_exp_type::type type;
        typedef typename matrix_exp_type::mem_manager_type mem_manager_type;
        typedef typename matrix_exp_type::layout_type layout_type;

        typedef matrix<type,0,0,mem_manager_type,layout_type>  matrix_type;
        typedef matrix<type,NR,1,mem_manager_type,layout_type> column_vector_type;
        typedef matrix<long,NR,1,mem_manager_type,layout_type> pivot_column_vector_type;

        // You have supplied an invalid type of matrix_exp_type.  You have
        // to use this object with matrices that contain float or double type data.
        COMPILE_TIME_ASSERT((is_same_type<float, type>::value ||
                             is_same_type<double, type>::value ));

        template <typename EXP>
        lu_decomposition (
            const matrix_exp<EXP> &A
        );

        bool is_square (
        ) const;

        bool is_singular (
        ) const;

        long nr(
        ) const;

        long nc(
        ) const;

        const matrix_type get_l (
        ) const;

        const matrix_type get_u (
        ) const;

        const pivot_column_vector_type& get_pivot (
        ) const;

        type det (
        ) const;

        template <typename EXP>
        const matrix_type solve (
            const matrix_exp<EXP> &B
        ) const;

    private:

        /* Array for internal storage of decomposition.  */
        matrix<type,0,0,mem_manager_type,column_major_layout>  LU;
        long m, n, pivsign;
        pivot_column_vector_type piv;

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                              Public member functions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <typename matrix_exp_type>
    template <typename EXP>
    lu_decomposition<matrix_exp_type>::
    lu_decomposition (
        const matrix_exp<EXP>& A
    ) :
        LU(A),
        m(A.nr()),
        n(A.nc())
    {
        using namespace std;
        using std::abs;

        COMPILE_TIME_ASSERT((is_same_type<type, typename EXP::type>::value));

        // make sure requires clause is not broken
        DLIB_ASSERT(A.size() > 0,
            "\tlu_decomposition::lu_decomposition(A)"
            << "\n\tInvalid inputs were given to this function"
            << "\n\tA.size(): " << A.size()
            << "\n\tthis:     " << this
            );

#ifdef DLIB_USE_LAPACK
        matrix<lapack::integer,0,1,mem_manager_type,layout_type> piv_temp;
        lapack::getrf(LU, piv_temp);

        pivsign = 1;

        // Turn the piv_temp vector into a more useful form.  This way we will have the identity
        // rowm(A,piv) == L*U.  The permutation vector that comes out of LAPACK is somewhat
        // different.
        piv = trans(range(0,m-1));
        for (long i = 0; i < piv_temp.size(); ++i)
        {
            // -1 because FORTRAN is indexed starting with 1 instead of 0
            if (piv(piv_temp(i)-1) != piv(i))
            {
                std::swap(piv(i), piv(piv_temp(i)-1));
                pivsign = -pivsign;
            }
        }

#else

        // Use a "left-looking", dot-product, Crout/Doolittle algorithm.

        piv = trans(range(0,m-1));
        pivsign = 1;

        column_vector_type LUcolj(m);

        // Outer loop.
        for (long j = 0; j < n; j++)
        {

            // Make a copy of the j-th column to localize references.
            LUcolj = colm(LU,j);

            // Apply previous transformations.
            for (long i = 0; i < m; i++)
            {
                // Most of the time is spent in the following dot product.
                const long kmax = std::min(i,j);
                type s;
                if (kmax > 0)
                    s = rowm(LU,i, kmax)*colm(LUcolj,0,kmax);
                else
                    s = 0;

                LU(i,j) = LUcolj(i) -= s;
            }

            // Find pivot and exchange if necessary.
            long p = j;
            for (long i = j+1; i < m; i++)
            {
                if (abs(LUcolj(i)) > abs(LUcolj(p)))
                {
                    p = i;
                }
            }
            if (p != j)
            {
                long k=0;
                for (k = 0; k < n; k++)
                {
                    type t = LU(p,k);
                    LU(p,k) = LU(j,k);
                    LU(j,k) = t;
                }
                k = piv(p);
                piv(p) = piv(j);
                piv(j) = k;
                pivsign = -pivsign;
            }

            // Compute multipliers.
            if ((j < m) && (LU(j,j) != 0.0))
            {
                for (long i = j+1; i < m; i++)
                {
                    LU(i,j) /= LU(j,j);
                }
            }
        }

#endif
    }

// ----------------------------------------------------------------------------------------

    template <typename matrix_exp_type>
    bool lu_decomposition<matrix_exp_type>::
    is_square (
    ) const
    {
        return m == n;
    }

// ----------------------------------------------------------------------------------------

    template <typename matrix_exp_type>
    long lu_decomposition<matrix_exp_type>::
    nr (
    ) const
    {
        return m;
    }

// ----------------------------------------------------------------------------------------

    template <typename matrix_exp_type>
    long lu_decomposition<matrix_exp_type>::
    nc (
    ) const
    {
        return n;
    }

// ----------------------------------------------------------------------------------------

    template <typename matrix_exp_type>
    bool lu_decomposition<matrix_exp_type>::
    is_singular (
    ) const
    {
        /* Is the matrix singular?
          if upper triangular factor U (and hence A) is singular, false otherwise.
        */
        // make sure requires clause is not broken
        DLIB_ASSERT(is_square() == true,
            "\tbool lu_decomposition::is_singular()"
            << "\n\tYou can only use this on square matrices"
            << "\n\tthis: " << this
            );

        type max_val, min_val;
        find_min_and_max (abs(diag(LU)), min_val, max_val);
        type eps = max_val;
        if (eps != 0)
            eps *= std::sqrt(std::numeric_limits<type>::epsilon())/10;
        else
            eps = 1;  // there is no max so just use 1

        return min_val < eps;
    }

// ----------------------------------------------------------------------------------------

    template <typename matrix_exp_type>
    const typename lu_decomposition<matrix_exp_type>::matrix_type lu_decomposition<matrix_exp_type>::
    get_l (
    ) const
    {
        if (LU.nr() >= LU.nc())
            return lowerm(LU,1.0);
        else
            return lowerm(subm(LU,0,0,m,m), 1.0);
    }

// ----------------------------------------------------------------------------------------

    template <typename matrix_exp_type>
    const typename lu_decomposition<matrix_exp_type>::matrix_type lu_decomposition<matrix_exp_type>::
    get_u (
    ) const
    {
        if (LU.nr() >= LU.nc())
            return upperm(subm(LU,0,0,n,n));
        else
            return upperm(LU);
    }

// ----------------------------------------------------------------------------------------

    template <typename matrix_exp_type>
    const typename lu_decomposition<matrix_exp_type>::pivot_column_vector_type& lu_decomposition<matrix_exp_type>::
    get_pivot (
    ) const
    {
        return piv;
    }

// ----------------------------------------------------------------------------------------

    template <typename matrix_exp_type>
    typename lu_decomposition<matrix_exp_type>::type lu_decomposition<matrix_exp_type>::
    det (
    ) const
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(is_square() == true,
            "\ttype lu_decomposition::det()"
            << "\n\tYou can only use this on square matrices"
            << "\n\tthis: " << this
            );

        // Check if it is singular and if it is just return 0.
        // We want to do this because a prod() operation can easily
        // overcome a single diagonal element that is effectively 0 when
        // LU is a big enough matrix.
        if (is_singular())
            return 0;

        return prod(diag(LU))*static_cast<type>(pivsign);
    }

// ----------------------------------------------------------------------------------------

    template <typename matrix_exp_type>
    template <typename EXP>
    const typename lu_decomposition<matrix_exp_type>::matrix_type lu_decomposition<matrix_exp_type>::
    solve (
        const matrix_exp<EXP> &B
    ) const
    {
        COMPILE_TIME_ASSERT((is_same_type<type, typename EXP::type>::value));

        // make sure requires clause is not broken
        DLIB_ASSERT(is_square() == true && B.nr() == nr(),
            "\ttype lu_decomposition::solve()"
            << "\n\tInvalid arguments to this function"
            << "\n\tis_square():   " << (is_square()? "true":"false" )
            << "\n\tB.nr():        " << B.nr()
            << "\n\tnr():          " << nr()
            << "\n\tthis:          " << this
            );

        // Copy right hand side with pivoting
        matrix<type,0,0,mem_manager_type,column_major_layout> X(rowm(B, piv));

        using namespace blas_bindings;
        // Solve L*Y = B(piv,:)
        triangular_solver(CblasLeft, CblasLower, CblasNoTrans, CblasUnit, LU, X);
        // Solve U*X = Y;
        triangular_solver(CblasLeft, CblasUpper, CblasNoTrans, CblasNonUnit, LU, X);
        return X;
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MATRIX_LU_DECOMPOSITION_H


dlib C++ Library - matrix_mat.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MATRIx_MAT_Hh_
#define DLIB_MATRIx_MAT_Hh_

#include "matrix_mat_abstract.h"
#include "../stl_checked.h"
#include <vector>
#include "matrix_op.h"
#include "../array2d.h"
#include "../array.h"
#include "../image_processing/generic_image.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename EXP
        >
    const matrix_exp<EXP>& mat (
        const matrix_exp<EXP>& m
    )
    {
        return m;
    }

// ----------------------------------------------------------------------------------------

    template <typename image_type, typename pixel_type>
    struct op_image_to_mat : does_not_alias
    {
        op_image_to_mat( const image_type& img) : imgview(img){}

        const_image_view<image_type> imgview;

        const static long cost = 1;
        const static long NR = 0;
        const static long NC = 0;
        typedef pixel_type type;
        typedef const pixel_type& const_ret_type;
        typedef default_memory_manager mem_manager_type;
        typedef row_major_layout layout_type;

        const_ret_type apply (long r, long c ) const { return imgview[r][c]; }

        long nr () const { return imgview.nr(); }
        long nc () const { return imgview.nc(); }
    };

// ----------------------------------------------------------------------------------------

    template <
        typename image_type
        > // The reason we disable this if it is a matrix is because this matrix_op claims
          // to not alias any matrix.  But obviously that would be a problem if we let it
          // take a matrix.
    const typename disable_if<is_matrix<image_type>,matrix_op<op_image_to_mat<image_type, typename image_traits<image_type>::pixel_type> > >::type mat (
        const image_type& img
    )
    {
        typedef op_image_to_mat<image_type, typename image_traits<image_type>::pixel_type> op;
        return matrix_op<op>(op(img));
    }

// ----------------------------------------------------------------------------------------

    template <typename image_type>
    struct op_image_view_to_mat : does_not_alias
    {
        op_image_view_to_mat( const image_view<image_type>& img) : imgview(img){}

        typedef typename image_traits<image_type>::pixel_type pixel_type;

        const image_view<image_type>& imgview;

        const static long cost = 1;
        const static long NR = 0;
        const static long NC = 0;
        typedef pixel_type type;
        typedef const pixel_type& const_ret_type;
        typedef default_memory_manager mem_manager_type;
        typedef row_major_layout layout_type;

        const_ret_type apply (long r, long c ) const { return imgview[r][c]; }

        long nr () const { return imgview.nr(); }
        long nc () const { return imgview.nc(); }
    };

    template <
        typename image_type
        >
    const matrix_op<op_image_view_to_mat<image_type> > mat (
        const image_view<image_type>& img
    )
    {
        typedef op_image_view_to_mat<image_type> op;
        return matrix_op<op>(op(img));
    }

// ----------------------------------------------------------------------------------------

    template <typename image_type>
    struct op_const_image_view_to_mat : does_not_alias
    {
        op_const_image_view_to_mat( const const_image_view<image_type>& img) : imgview(img){}

        typedef typename image_traits<image_type>::pixel_type pixel_type;

        const const_image_view<image_type>& imgview;

        const static long cost = 1;
        const static long NR = 0;
        const static long NC = 0;
        typedef pixel_type type;
        typedef const pixel_type& const_ret_type;
        typedef default_memory_manager mem_manager_type;
        typedef row_major_layout layout_type;

        const_ret_type apply (long r, long c ) const { return imgview[r][c]; }

        long nr () const { return imgview.nr(); }
        long nc () const { return imgview.nc(); }
    };

    template <
        typename image_type
        >
    const matrix_op<op_const_image_view_to_mat<image_type> > mat (
        const const_image_view<image_type>& img
    )
    {
        typedef op_const_image_view_to_mat<image_type> op;
        return matrix_op<op>(op(img));
    }

// ----------------------------------------------------------------------------------------

    template <typename T>
    struct op_array_to_mat : does_not_alias
    {
        op_array_to_mat( const T& vect_) : vect(vect_){}

        const T& vect;

        const static long cost = 1;
        const static long NR = 0;
        const static long NC = 1;
        typedef typename T::type type;
        typedef const typename T::type& const_ret_type;
        typedef typename T::mem_manager_type mem_manager_type;
        typedef row_major_layout layout_type;

        const_ret_type apply (long r, long  ) const { return vect[r]; }

        long nr () const { return vect.size(); }
        long nc () const { return 1; }
    };

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename MM
        >
    const matrix_op<op_array_to_mat<array<T,MM> > > mat (
        const array<T,MM>& m
    )
    {
        typedef op_array_to_mat<array<T,MM> > op;
        return matrix_op<op>(op(m));
    }

// ----------------------------------------------------------------------------------------

    namespace impl
    {
        template <typename U>
        struct not_bool { typedef U type; };
        template <>
        struct not_bool<const bool&> { typedef bool type; };
    }

    template <typename T>
    struct op_std_vect_to_mat : does_not_alias
    {
        op_std_vect_to_mat( const T& vect_) : vect(vect_){}

        const T& vect;

        const static long cost = 1;
        const static long NR = 0;
        const static long NC = 1;
        typedef typename T::value_type type;
        // Since std::vector returns a proxy for bool types we need to make sure we don't
        // return an element by reference if it is a bool type.
        typedef typename impl::not_bool<const typename T::value_type&>::type const_ret_type;

        typedef default_memory_manager mem_manager_type;
        typedef row_major_layout layout_type;

        const_ret_type apply (long r, long ) const { return vect[r]; }

        long nr () const { return vect.size(); }
        long nc () const { return 1; }
    };

// ----------------------------------------------------------------------------------------

    template <
        typename value_type,
        typename alloc
        >
    const matrix_op<op_std_vect_to_mat<std::vector<value_type,alloc> > > mat (
        const std::vector<value_type,alloc>& vector
    )
    {
        typedef op_std_vect_to_mat<std::vector<value_type,alloc> > op;
        return matrix_op<op>(op(vector));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename value_type,
        typename alloc
        >
    const matrix_op<op_std_vect_to_mat<std_vector_c<value_type,alloc> > > mat (
        const std_vector_c<value_type,alloc>& vector
    )
    {
        typedef op_std_vect_to_mat<std_vector_c<value_type,alloc> > op;
        return matrix_op<op>(op(vector));
    }

// ----------------------------------------------------------------------------------------

    template <typename T>
    struct op_pointer_to_mat;

    template <typename T>
    struct op_pointer_to_col_vect
    {
        op_pointer_to_col_vect(
            const T* ptr_,
            const long size_
        ) : ptr(ptr_), size(size_){}

        const T* ptr;
        const long size;

        const static long cost = 1;
        const static long NR = 0;
        const static long NC = 1;
        typedef T type;
        typedef const T& const_ret_type;
        typedef default_memory_manager mem_manager_type;
        typedef row_major_layout layout_type;

        const_ret_type apply (long r, long ) const { return ptr[r]; }

        long nr () const { return size; }
        long nc () const { return 1; }

        template <typename U> bool aliases               ( const matrix_exp<U>& ) const { return false; }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& ) const { return false; }

        template <long num_rows, long num_cols, typename mem_manager, typename layout>
        bool aliases (
            const matrix_exp<matrix<T,num_rows,num_cols, mem_manager,layout> >& item
        ) const
        {
            if (item.size() == 0)
                return false;
            else
                return (ptr == &item(0,0));
        }

        inline bool aliases (
            const matrix_exp<matrix_op<op_pointer_to_mat<T> > >& item
        ) const;

        bool aliases (
            const matrix_exp<matrix_op<op_pointer_to_col_vect<T> > >& item
        ) const
        {
            return item.ref().op.ptr == ptr;
        }
    };

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    const matrix_op<op_pointer_to_col_vect<T> > mat (
        const T* ptr,
        long nr
    )
    {
        DLIB_ASSERT(nr > 0 ,
                    "\tconst matrix_exp mat(ptr, nr)"
                    << "\n\t nr must be bigger than 0"
                    << "\n\t nr: " << nr
        );
        typedef op_pointer_to_col_vect<T> op;
        return matrix_op<op>(op(ptr, nr));
    }

// ----------------------------------------------------------------------------------------

    template <typename T>
    struct op_pointer_to_mat
    {
        op_pointer_to_mat(
            const T* ptr_,
            const long nr_,
            const long nc_
        ) : ptr(ptr_), rows(nr_), cols(nc_){}

        const T* ptr;
        const long rows;
        const long cols;

        const static long cost = 1;
        const static long NR = 0;
        const static long NC = 0;
        typedef T type;
        typedef const T& const_ret_type;
        typedef default_memory_manager mem_manager_type;
        typedef row_major_layout layout_type;

        const_ret_type apply (long r, long c) const { return ptr[r*cols + c]; }

        long nr () const { return rows; }
        long nc () const { return cols; }

        template <typename U> bool aliases               ( const matrix_exp<U>& ) const { return false; }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& ) const { return false; }

        template <long num_rows, long num_cols, typename mem_manager, typename layout>
        bool aliases (
            const matrix_exp<matrix<T,num_rows,num_cols, mem_manager,layout> >& item
        ) const
        {
            if (item.size() == 0)
                return false;
            else
                return (ptr == &item(0,0));
        }

        bool aliases (
            const matrix_exp<matrix_op<op_pointer_to_mat<T> > >& item
        ) const
        {
            return item.ref().op.ptr == ptr;
        }

        bool aliases (
            const matrix_exp<matrix_op<op_pointer_to_col_vect<T> > >& item
        ) const
        {
            return item.ref().op.ptr == ptr;
        }
    };

    template <typename T>
    bool op_pointer_to_col_vect<T>::
    aliases (
        const matrix_exp<matrix_op<op_pointer_to_mat<T> > >& item
    ) const
    {
        return item.ref().op.ptr == ptr;
    }

    template <typename T, long NR, long NC, typename MM, typename L>
    bool matrix<T,NR,NC,MM,L>::aliases (
        const matrix_exp<matrix_op<op_pointer_to_mat<T> > >& item
    ) const
    {
        if (size() != 0)
            return item.ref().op.ptr == &data(0,0);
        else
            return false;
    }

    template <typename T, long NR, long NC, typename MM, typename L>
    bool matrix<T,NR,NC,MM,L>::aliases (
        const matrix_exp<matrix_op<op_pointer_to_col_vect<T> > >& item
    ) const
    {
        if (size() != 0)
            return item.ref().op.ptr == &data(0,0);
        else
            return false;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    const matrix_op<op_pointer_to_mat<T> > mat (
        const T* ptr,
        long nr,
        long nc
    )
    {
        DLIB_ASSERT(nr > 0 && nc > 0 ,
                    "\tconst matrix_exp mat(ptr, nr, nc)"
                    << "\n\t nr and nc must be bigger than 0"
                    << "\n\t nr: " << nr
                    << "\n\t nc: " << nc
        );
        typedef op_pointer_to_mat<T> op;
        return matrix_op<op>(op(ptr,nr,nc));
    }

// ----------------------------------------------------------------------------------------

}

namespace arma
{
    template <typename T> class Mat;
}
namespace dlib
{
    template <typename T>
    struct op_arma_Mat_to_mat : does_not_alias
    {
        op_arma_Mat_to_mat( const T& array_) : array(array_){}

        const T& array;

        const static long cost = 1;
        const static long NR = 0;
        const static long NC = 0;
        typedef typename T::elem_type type;
        typedef typename T::elem_type const_ret_type;
        typedef default_memory_manager mem_manager_type;
        typedef row_major_layout layout_type;

        const_ret_type apply (long r, long c ) const { return array(r,c); }

        long nr () const { return array.n_rows; }
        long nc () const { return array.n_cols; }
    };

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    const matrix_op<op_arma_Mat_to_mat< ::arma::Mat<T> > > mat (
        const ::arma::Mat<T>& array
    )
    {
        typedef op_arma_Mat_to_mat< ::arma::Mat<T> > op;
        return matrix_op<op>(op(array));
    }
}

namespace Eigen
{
    template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols>
    class Matrix;
}

namespace dlib
{
    template <typename T, int _Rows, int _Cols>
    struct op_eigen_Matrix_to_mat : does_not_alias
    {
        op_eigen_Matrix_to_mat( const T& array_) : m(array_){}

        const T& m;

        const static long cost = 1;
        const static long NR = (_Rows > 0) ? _Rows : 0;
        const static long NC = (_Cols > 0) ? _Cols : 0;
        typedef typename T::Scalar type;
        typedef typename T::Scalar const_ret_type;
        typedef default_memory_manager mem_manager_type;
        typedef row_major_layout layout_type;

        const_ret_type apply (long r, long c ) const { return m(r,c); }

        long nr () const { return m.rows(); }
        long nc () const { return m.cols(); }
    };

// ----------------------------------------------------------------------------------------

    template <
        typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols
        >
    const matrix_op<op_eigen_Matrix_to_mat< ::Eigen::Matrix<_Scalar,_Rows,_Cols,_Options,_MaxRows,_MaxCols>,_Rows,_Cols > > mat (
        const ::Eigen::Matrix<_Scalar,_Rows,_Cols,_Options,_MaxRows,_MaxCols>& m
    )
    {
        typedef op_eigen_Matrix_to_mat< ::Eigen::Matrix<_Scalar,_Rows,_Cols,_Options,_MaxRows,_MaxCols>,_Rows,_Cols > op;
        return matrix_op<op>(op(m));
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                                  DEPRECATED FUNCTIONS
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

// vector_to_matrix(), array_to_matrix(), pointer_to_matrix(), and
// pointer_to_column_vector() have been deprecated in favor of the more uniform mat()
// function.  But they are here for backwards compatibility.

    template <
        typename vector_type
        >
    const typename disable_if<is_matrix<vector_type>, matrix_op<op_array_to_mat<vector_type> > >::type
    vector_to_matrix (
        const vector_type& vector
    )
    {
        typedef op_array_to_mat<vector_type> op;
        return matrix_op<op>(op(vector));
    }

    template <
        typename vector_type
        >
    const typename enable_if<is_matrix<vector_type>,vector_type>::type& vector_to_matrix (
        const vector_type& vector
    )
    /*!
        This overload catches the case where the argument to this function is
        already a matrix.
    !*/
    {
        return vector;
    }

    template <
        typename value_type,
        typename alloc
        >
    const matrix_op<op_std_vect_to_mat<std::vector<value_type,alloc> > > vector_to_matrix (
        const std::vector<value_type,alloc>& vector
    )
    {
        typedef op_std_vect_to_mat<std::vector<value_type,alloc> > op;
        return matrix_op<op>(op(vector));
    }

    template <
        typename value_type,
        typename alloc
        >
    const matrix_op<op_std_vect_to_mat<std_vector_c<value_type,alloc> > > vector_to_matrix (
        const std_vector_c<value_type,alloc>& vector
    )
    {
        typedef op_std_vect_to_mat<std_vector_c<value_type,alloc> > op;
        return matrix_op<op>(op(vector));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename array_type
        >
    const typename enable_if<is_matrix<array_type>,array_type>::type&
    array_to_matrix (
        const array_type& array
    )
    {
        return array;
    }

// ----------------------------------------------------------------------------------------

    template <typename T>
    struct op_array2d_to_mat : does_not_alias
    {
        op_array2d_to_mat( const T& array_) : array(array_){}

        const T& array;

        const static long cost = 1;
        const static long NR = 0;
        const static long NC = 0;
        typedef typename T::type type;
        typedef const typename T::type& const_ret_type;
        typedef typename T::mem_manager_type mem_manager_type;
        typedef row_major_layout layout_type;

        const_ret_type apply (long r, long c ) const { return array[r][c]; }

        long nr () const { return array.nr(); }
        long nc () const { return array.nc(); }
    };

    // Note that we have this version of mat() because it's slightly faster executing
    // than the general one that handles any generic image.  This is because it avoids
    // calling image_data() which for array2d involves a single if statement but this
    // version here has no if statement in its construction.
    template < typename T, typename MM >
    const matrix_op<op_array2d_to_mat<array2d<T,MM> > > mat (
        const array2d<T,MM>& array
    )
    {
        typedef op_array2d_to_mat<array2d<T,MM> > op;
        return matrix_op<op>(op(array));
    }

    template <
        typename array_type
        >
    const typename disable_if<is_matrix<array_type>,matrix_op<op_array2d_to_mat<array_type> > >::type
    array_to_matrix (
        const array_type& array
    )
    {
        typedef op_array2d_to_mat<array_type> op;
        return matrix_op<op>(op(array));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    const matrix_op<op_pointer_to_mat<T> > pointer_to_matrix (
        const T* ptr,
        long nr,
        long nc
    )
    {
        DLIB_ASSERT(nr > 0 && nc > 0 ,
                    "\tconst matrix_exp pointer_to_matrix(ptr, nr, nc)"
                    << "\n\t nr and nc must be bigger than 0"
                    << "\n\t nr: " << nr
                    << "\n\t nc: " << nc
        );
        typedef op_pointer_to_mat<T> op;
        return matrix_op<op>(op(ptr,nr,nc));
    }

    template <
        typename T
        >
    const matrix_op<op_pointer_to_col_vect<T> > pointer_to_column_vector (
        const T* ptr,
        long nr
    )
    {
        DLIB_ASSERT(nr > 0 ,
                    "\tconst matrix_exp pointer_to_column_vector(ptr, nr)"
                    << "\n\t nr must be bigger than 0"
                    << "\n\t nr: " << nr
        );
        typedef op_pointer_to_col_vect<T> op;
        return matrix_op<op>(op(ptr, nr));
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    inline matrix<double,1,1> mat (
        double value
    )
    {
        matrix<double,1,1> temp;
        temp(0) = value;
        return temp;
    }

    inline matrix<float,1,1> mat (
        float value
    )
    {
        matrix<float,1,1> temp;
        temp(0) = value;
        return temp;
    }

    inline matrix<long double,1,1> mat (
        long double value
    )
    {
        matrix<long double,1,1> temp;
        temp(0) = value;
        return temp;
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MATRIx_MAT_Hh_


dlib C++ Library - matrix_math_functions.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MATRIx_MATH_FUNCTIONS
#define DLIB_MATRIx_MATH_FUNCTIONS

#include "matrix_math_functions_abstract.h"
#include "matrix_op.h"
#include "matrix_utilities.h"
#include "matrix.h"
#include "../algs.h"
#include <cmath>
#include <complex>
#include <limits>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    DLIB_DEFINE_FUNCTION_M(op_sqrt, sqrt, std::sqrt ,7);
    DLIB_DEFINE_FUNCTION_M(op_log, log, std::log ,7);
    DLIB_DEFINE_FUNCTION_M(op_log10, log10, std::log10 ,7);
    DLIB_DEFINE_FUNCTION_M(op_exp, exp, std::exp ,7);

    DLIB_DEFINE_FUNCTION_M(op_conj, conj, std::conj ,2);

    DLIB_DEFINE_FUNCTION_M(op_ceil, ceil, std::ceil ,7);
    DLIB_DEFINE_FUNCTION_M(op_floor, floor, std::floor ,7);

    DLIB_DEFINE_FUNCTION_M(op_sin, sin, std::sin ,7);
    DLIB_DEFINE_FUNCTION_M(op_cos, cos, std::cos ,7);
    DLIB_DEFINE_FUNCTION_M(op_tan, tan, std::tan ,7);
    DLIB_DEFINE_FUNCTION_M(op_sinh, sinh, std::sinh ,7);
    DLIB_DEFINE_FUNCTION_M(op_cosh, cosh, std::cosh ,7);
    DLIB_DEFINE_FUNCTION_M(op_tanh, tanh, std::tanh ,7);
    DLIB_DEFINE_FUNCTION_M(op_asin, asin, std::asin ,7);
    DLIB_DEFINE_FUNCTION_M(op_acos, acos, std::acos ,7);
    DLIB_DEFINE_FUNCTION_M(op_atan, atan, std::atan ,7);

// ----------------------------------------------------------------------------------------

    namespace impl
    {
        template <typename type>
        inline type sigmoid (const type& val)
        {
            return static_cast<type>(1/(1 + std::exp(-val)));
        }

        template <typename type, typename S>
        inline type round_zeros_eps (const type& val, const S& eps)
        {
            // you can only round matrices that contain built in scalar types like double, long, float, etc.
            COMPILE_TIME_ASSERT(is_built_in_scalar_type<type>::value);

            if (val >= eps || val <= -eps)
                return val;
            else
                return 0;
        }

        template <typename type>
        inline type round_zeros (const type& val)
        {
            // you can only round matrices that contain built in scalar types like double, long, float, etc.
            COMPILE_TIME_ASSERT(is_built_in_scalar_type<type>::value);

            const type eps = 10*std::numeric_limits<type>::epsilon();
            if (val >= eps || val <= -eps)
                return val;
            else
                return 0;
        }

        template <typename type>
        inline type squared (const type& val)
        {
            return val*val;
        }

        template <typename type>
        inline type sign (const type& val)
        {
            if (val >= 0)
                return +1;
            else
                return -1;
        }

        template <typename type>
        type cubed (const type& val)
        {
            return val*val*val;
        }

        template <typename type, typename S>
        inline type pow1 (const type& val, const S& s)
        {
            // you can only call pow() on matrices that contain floats, doubles or long doubles.
            COMPILE_TIME_ASSERT((
                    is_same_type<type,float>::value == true ||
                    is_same_type<type,double>::value == true ||
                    is_same_type<type,long double>::value == true
            ));

            return std::pow(val,static_cast<type>(s));
        }

        template <typename type, typename S>
        inline type pow2 (const S& s, const type& val)
        {
            // you can only call pow() on matrices that contain floats, doubles or long doubles.
            COMPILE_TIME_ASSERT((
                    is_same_type<type,float>::value == true ||
                    is_same_type<type,double>::value == true ||
                    is_same_type<type,long double>::value == true
            ));

            return std::pow(static_cast<type>(s),val);
        }

        template <typename type>
        inline type reciprocal (const type& val)
        {
            // you can only compute reciprocal matrices that contain floats, doubles or long doubles.
            COMPILE_TIME_ASSERT((
                    is_same_type<type,float>::value == true ||
                    is_same_type<type,double>::value == true ||
                    is_same_type<type,long double>::value == true  ||
                    is_same_type<type,std::complex<float> >::value == true ||
                    is_same_type<type,std::complex<double> >::value == true ||
                    is_same_type<type,std::complex<long double> >::value == true
            ));

            if (val != static_cast<type>(0))
                return static_cast<type>((type)1.0/val);
            else
                return 0;
        }

        template <typename type>
        inline type reciprocal_max (const type& val)
        {
            // you can only compute reciprocal_max matrices that contain floats, doubles or long doubles.
            COMPILE_TIME_ASSERT((
                    is_same_type<type,float>::value == true ||
                    is_same_type<type,double>::value == true ||
                    is_same_type<type,long double>::value == true
            ));

            if (val != static_cast<type>(0))
                return static_cast<type>((type)1.0/val);
            else
                return std::numeric_limits<type>::max();
        }

    }

    DLIB_DEFINE_FUNCTION_M(op_sigmoid, sigmoid, impl::sigmoid, 7);
    DLIB_DEFINE_FUNCTION_MS(op_round_zeros, round_zeros, impl::round_zeros_eps, 7);
    DLIB_DEFINE_FUNCTION_M(op_round_zeros2, round_zeros, impl::round_zeros, 7);
    DLIB_DEFINE_FUNCTION_M(op_cubed, cubed, impl::cubed, 7);
    DLIB_DEFINE_FUNCTION_M(op_squared, squared, impl::squared, 6);
    DLIB_DEFINE_FUNCTION_M(op_sign, sign, impl::sign, 6);
    DLIB_DEFINE_FUNCTION_MS(op_pow1, pow, impl::pow1, 7);
    DLIB_DEFINE_FUNCTION_SM(op_pow2, pow, impl::pow2, 7);
    DLIB_DEFINE_FUNCTION_M(op_reciprocal, reciprocal, impl::reciprocal, 6);
    DLIB_DEFINE_FUNCTION_M(op_reciprocal_max, reciprocal_max, impl::reciprocal_max, 6);

// ----------------------------------------------------------------------------------------

    template <typename M, typename enabled = void>
    struct op_round : basic_op_m<M>
    {
        op_round( const M& m_) : basic_op_m<M>(m_){}

        const static long cost = M::cost+7;
        typedef typename M::type type;
        typedef const typename M::type const_ret_type;
        const_ret_type apply (long r, long c) const
        {
            return static_cast<type>(std::floor(this->m(r,c)+0.5));
        }
    };

    template <typename M>
    struct op_round<M,typename enable_if_c<std::numeric_limits<typename M::type>::is_integer>::type >
    : basic_op_m<M>
    {
        op_round( const M& m_) : basic_op_m<M>(m_){}

        const static long cost = M::cost;
        typedef typename M::type type;
        typedef typename M::const_ret_type const_ret_type;
        const_ret_type apply (long r, long c) const
        {
            return this->m(r,c);
        }
    };

    template <
        typename EXP
        >
    const matrix_op<op_round<EXP> > round (
        const matrix_exp<EXP>& m
    )
    {
        // you can only round matrices that contain built in scalar types like double, long, float, etc.
        COMPILE_TIME_ASSERT(is_built_in_scalar_type<typename EXP::type>::value);

        typedef op_round<EXP> op;
        return matrix_op<op>(op(m.ref()));
    }

// ----------------------------------------------------------------------------------------

    template <typename M>
    struct op_normalize : basic_op_m<M>
    {
        typedef typename M::type type;

        op_normalize( const M& m_, const type& s_) : basic_op_m<M>(m_), s(s_){}

        const type s;

        const static long cost = M::cost+5;
        typedef const typename M::type const_ret_type;
        const_ret_type apply (long r, long c) const
        {
            return this->m(r,c)*s;
        }
    };

    template <
        typename EXP
        >
    const matrix_op<op_normalize<EXP> > normalize (
        const matrix_exp<EXP>& m
    )
    {
        // you can only compute normalized matrices that contain floats, doubles or long doubles.
        COMPILE_TIME_ASSERT((
                is_same_type<typename EXP::type,float>::value == true ||
                is_same_type<typename EXP::type,double>::value == true ||
                is_same_type<typename EXP::type,long double>::value == true
        ));

        typedef op_normalize<EXP> op;
        typename EXP::type temp = std::sqrt(sum(squared(m)));
        if (temp != 0.0)
            temp = 1.0/temp;

        return matrix_op<op>(op(m.ref(),temp));
    }

// ----------------------------------------------------------------------------------------

    template <typename M, typename return_type = typename M::type>
    struct op_abs : basic_op_m<M>
    {
        op_abs( const M& m_) : basic_op_m<M>(m_){}

        const static long cost = M::cost+7;
        typedef typename M::type type;
        typedef const typename M::type const_ret_type;
        const_ret_type apply ( long r, long c) const
        {
            return static_cast<type>(std::abs(this->m(r,c)));
        }
    };

    template <typename M, typename T>
    struct op_abs<M, std::complex<T> > : basic_op_m<M>
    {
        op_abs( const M& m_) : basic_op_m<M>(m_){}

        const static long cost = M::cost;
        typedef T type;
        typedef const T const_ret_type;
        const_ret_type apply ( long r, long c) const
        {
            return static_cast<type>(std::abs(this->m(r,c)));
        }
    };

    template <
        typename EXP
        >
    const matrix_op<op_abs<EXP> > abs (
        const matrix_exp<EXP>& m
    )
    {
        typedef op_abs<EXP> op;
        return matrix_op<op>(op(m.ref()));
    }

// ----------------------------------------------------------------------------------------

    template <typename M>
    struct op_complex_matrix : basic_op_m<M>
    {
        op_complex_matrix( const M& m_) : basic_op_m<M>(m_){}

        const static long cost = M::cost+1;
        typedef std::complex<typename M::type> type;
        typedef const std::complex<typename M::type> const_ret_type;
        const_ret_type apply ( long r, long c) const
        {
            return type(this->m(r,c));
        }
    };

    template <
        typename EXP
        >
    const matrix_op<op_complex_matrix<EXP> > complex_matrix (
        const matrix_exp<EXP>& m
    )
    {
        typedef op_complex_matrix<EXP> op;
        return matrix_op<op>(op(m.ref()));
    }

// ----------------------------------------------------------------------------------------

    template <typename M1, typename M2>
    struct op_complex_matrix2 : basic_op_mm<M1,M2>
    {
        op_complex_matrix2( const M1& m1_, const M2& m2_) : basic_op_mm<M1,M2>(m1_,m2_){}

        const static long cost = M1::cost+M2::cost+1;
        typedef std::complex<typename M1::type> type;
        typedef const std::complex<typename M1::type> const_ret_type;

        const_ret_type apply ( long r, long c) const
        { return type(this->m1(r,c), this->m2(r,c)); }
    };

    template <
        typename EXP1,
        typename EXP2
        >
    const matrix_op<op_complex_matrix2<EXP1,EXP2> > complex_matrix (
        const matrix_exp<EXP1>& real_part,
        const matrix_exp<EXP2>& imag_part
    )
    {
        COMPILE_TIME_ASSERT((is_same_type<typename EXP1::type,typename EXP2::type>::value == true));
        COMPILE_TIME_ASSERT(EXP1::NR == EXP2::NR || EXP1::NR == 0 || EXP2::NR == 0);
        COMPILE_TIME_ASSERT(EXP1::NC == EXP2::NC || EXP1::NC == 0 || EXP2::NC == 0);

        DLIB_ASSERT(real_part.nr() == imag_part.nr() &&
               real_part.nc() == imag_part.nc(),
            "\tconst matrix_exp::type complex_matrix(real_part, imag_part)"
            << "\n\tYou can only make a complex matrix from two equally sized matrices"
            << "\n\treal_part.nr(): " << real_part.nr()
            << "\n\treal_part.nc(): " << real_part.nc()
            << "\n\timag_part.nr(): " << imag_part.nr()
            << "\n\timag_part.nc(): " << imag_part.nc()
            );

        typedef op_complex_matrix2<EXP1,EXP2> op;
        return matrix_op<op>(op(real_part.ref(),imag_part.ref()));
    }

// ----------------------------------------------------------------------------------------

    template <typename M>
    struct op_norm : basic_op_m<M>
    {
        op_norm( const M& m_) : basic_op_m<M>(m_){}

        const static long cost = M::cost+6;
        typedef typename M::type::value_type type;
        typedef const typename M::type::value_type const_ret_type;
        const_ret_type apply ( long r, long c) const
        { return std::norm(this->m(r,c)); }
    };

    template <
        typename EXP
        >
    const matrix_op<op_norm<EXP> > norm (
        const matrix_exp<EXP>& m
    )
    {
        typedef op_norm<EXP> op;
        return matrix_op<op>(op(m.ref()));
    }

// ----------------------------------------------------------------------------------------

    template <typename M>
    struct op_real : basic_op_m<M>
    {
        op_real( const M& m_) : basic_op_m<M>(m_){}

        const static long cost = M::cost;
        typedef typename M::type::value_type type;
        typedef const typename M::type::value_type const_ret_type;
        const_ret_type apply ( long r, long c) const
        { return std::real(this->m(r,c)); }
    };

    template <
        typename EXP
        >
    const matrix_op<op_real<EXP> > real (
        const matrix_exp<EXP>& m
    )
    {
        typedef op_real<EXP> op;
        return matrix_op<op>(op(m.ref()));
    }

// ----------------------------------------------------------------------------------------

    template <typename M>
    struct op_imag : basic_op_m<M>
    {
        op_imag( const M& m_) : basic_op_m<M>(m_){}

        const static long cost = M::cost;
        typedef typename M::type::value_type type;
        typedef const typename M::type::value_type const_ret_type;
        const_ret_type apply (long r, long c) const
        { return std::imag(this->m(r,c)); }
    };

    template <
        typename EXP
        >
    const matrix_op<op_imag<EXP> > imag (
        const matrix_exp<EXP>& m
    )
    {
        typedef op_imag<EXP> op;
        return matrix_op<op>(op(m.ref()));
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MATRIx_MATH_FUNCTIONS


dlib C++ Library - matrix_op.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MATRIx_OP_H_
#define DLIB_MATRIx_OP_H_

#include "matrix_exp.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <typename OP >
    class matrix_op;

    template < typename OP >
    struct matrix_traits<matrix_op<OP> >
    {
        typedef typename OP::type type;
        typedef typename OP::const_ret_type const_ret_type;
        typedef typename OP::mem_manager_type mem_manager_type;
        typedef typename OP::layout_type layout_type;
        const static long NR = OP::NR;
        const static long NC = OP::NC;
        const static long cost = OP::cost;
    };

    template <
        typename OP
        >
    class matrix_op : public matrix_exp<matrix_op<OP> >
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                The matrix_op is simply a tool for reducing the amount of boilerplate
                you need to write when creating matrix expressions.
        !*/

    public:
        typedef typename matrix_traits<matrix_op>::type type;
        typedef typename matrix_traits<matrix_op>::const_ret_type const_ret_type;
        typedef typename matrix_traits<matrix_op>::mem_manager_type mem_manager_type;
        typedef typename matrix_traits<matrix_op>::layout_type layout_type;
        const static long NR = matrix_traits<matrix_op>::NR;
        const static long NC = matrix_traits<matrix_op>::NC;
        const static long cost = matrix_traits<matrix_op>::cost;

    private:
        // This constructor exists simply for the purpose of causing a compile time error if
        // someone tries to create an instance of this object with the wrong kind of object.
        template <typename T1>
        matrix_op (T1);
    public:

        matrix_op (
            const OP& op_
        ) :
            op(op_)
        {}

        const_ret_type operator() (
            long r,
            long c
        ) const { return op.apply(r,c); }

        const_ret_type operator() ( long i ) const
        { return matrix_exp<matrix_op>::operator()(i); }

        template <typename U>
        bool aliases (
            const matrix_exp<U>& item
        ) const { return op.aliases(item); }

        template <typename U>
        bool destructively_aliases (
            const matrix_exp<U>& item
        ) const { return op.destructively_aliases(item); }

        long nr (
        ) const { return op.nr(); }

        long nc (
        ) const { return op.nc(); }

        const OP op;
    };

// ----------------------------------------------------------------------------------------

    template <typename OP >
    class matrix_diag_op;

    template < typename OP >
    struct matrix_traits<matrix_diag_op<OP> >
    {
        typedef typename OP::type type;
        typedef typename OP::const_ret_type const_ret_type;
        typedef typename OP::mem_manager_type mem_manager_type;
        typedef typename OP::layout_type layout_type;
        const static long NR = OP::NR;
        const static long NC = OP::NC;
        const static long cost = OP::cost;
    };

    template <
        typename OP
        >
    class matrix_diag_op : public matrix_diag_exp<matrix_diag_op<OP> >
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                The matrix_diag_op is simply a tool for reducing the amount of boilerplate
                you need to write when creating matrix expressions.
        !*/

    public:
        typedef typename matrix_traits<matrix_diag_op>::type type;
        typedef typename matrix_traits<matrix_diag_op>::const_ret_type const_ret_type;
        typedef typename matrix_traits<matrix_diag_op>::mem_manager_type mem_manager_type;
        typedef typename matrix_traits<matrix_diag_op>::layout_type layout_type;
        const static long NR = matrix_traits<matrix_diag_op>::NR;
        const static long NC = matrix_traits<matrix_diag_op>::NC;
        const static long cost = matrix_traits<matrix_diag_op>::cost;

    private:
        // This constructor exists simply for the purpose of causing a compile time error if
        // someone tries to create an instance of this object with the wrong kind of object.
        template <typename T1>
        matrix_diag_op (T1);
    public:

        matrix_diag_op (
            const OP& op_
        ) :
            op(op_)
        {}

        const_ret_type operator() (
            long r,
            long c
        ) const { return op.apply(r,c); }

        const_ret_type operator() ( long i ) const
        { return matrix_exp<matrix_diag_op>::operator()(i); }

        template <typename U>
        bool aliases (
            const matrix_exp<U>& item
        ) const { return op.aliases(item); }

        template <typename U>
        bool destructively_aliases (
            const matrix_exp<U>& item
        ) const { return op.destructively_aliases(item); }

        long nr (
        ) const { return op.nr(); }

        long nc (
        ) const { return op.nc(); }

        const OP op;
    };

// ----------------------------------------------------------------------------------------

    struct does_not_alias
    {
        /*!
            This is a partial implementation of a matrix operator that never aliases
            another expression.
        !*/

        template <typename U> bool aliases               ( const U& ) const { return false; }
        template <typename U> bool destructively_aliases ( const U& ) const { return false; }
    };

// ----------------------------------------------------------------------------------------

    template <typename M>
    struct basic_op_m
    {
        /*!
            This is a partial implementation of a matrix operator that preserves
            the dimensions of its argument and doesn't have destructive aliasing.
        !*/

    private:
        // This constructor exists simply for the purpose of causing a compile time error if
        // someone tries to create an instance of this object with the wrong kind of object.
        template <typename T1>
        basic_op_m (T1);
    public:

        basic_op_m(
            const M& m_
        ) : m(m_){}

        const M& m;

        const static long NR = M::NR;
        const static long NC = M::NC;
        typedef typename M::mem_manager_type mem_manager_type;
        typedef typename M::layout_type layout_type;

        long nr () const { return m.nr(); }
        long nc () const { return m.nc(); }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const
        { return m.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const
        { return m.destructively_aliases(item); }

    };

// ----------------------------------------------------------------------------------------

    template <typename M1, typename M2>
    struct basic_op_mm
    {
        /*!
            This is a partial implementation of a matrix operator that preserves
            the dimensions of its arguments and doesn't have destructive aliasing.
        !*/

    private:
        // This constructor exists simply for the purpose of causing a compile time error if
        // someone tries to create an instance of this object with the wrong kind of object.
        template <typename T1, typename T2>
        basic_op_mm (T1, T2);
    public:

        basic_op_mm(
            const M1& m1_,
            const M2& m2_
        ) : m1(m1_), m2(m2_){}

        const M1& m1;
        const M2& m2;

        const static long NR = M1::NR;
        const static long NC = M1::NC;
        typedef typename M1::mem_manager_type mem_manager_type;
        typedef typename M1::layout_type layout_type;

        long nr () const { return m1.nr(); }
        long nc () const { return m1.nc(); }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const
        { return m1.aliases(item) || m2.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const
        { return m1.destructively_aliases(item) || m2.destructively_aliases(item); }

    };

// ----------------------------------------------------------------------------------------

    template <typename M1, typename M2, typename M3>
    struct basic_op_mmm
    {
        /*!
            This is a partial implementation of a matrix operator that preserves
            the dimensions of its arguments and doesn't have destructive aliasing.
        !*/

    private:
        // This constructor exists simply for the purpose of causing a compile time error if
        // someone tries to create an instance of this object with the wrong kind of object.
        template <typename T1, typename T2, typename T3>
        basic_op_mmm (T1, T2, T3);
    public:

        basic_op_mmm(
            const M1& m1_,
            const M2& m2_,
            const M3& m3_
        ) : m1(m1_), m2(m2_), m3(m3_){}

        const M1& m1;
        const M2& m2;
        const M3& m3;

        const static long NR = M1::NR;
        const static long NC = M1::NC;
        typedef typename M1::mem_manager_type mem_manager_type;
        typedef typename M1::layout_type layout_type;

        long nr () const { return m1.nr(); }
        long nc () const { return m1.nc(); }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const
        { return m1.aliases(item) || m2.aliases(item) || m3.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const
        { return m1.destructively_aliases(item) || m2.destructively_aliases(item) ||
                 m3.destructively_aliases(item);}

    };

// ----------------------------------------------------------------------------------------

    template <typename M1, typename M2, typename M3, typename M4>
    struct basic_op_mmmm
    {
        /*!
            This is a partial implementation of a matrix operator that preserves
            the dimensions of its arguments and doesn't have destructive aliasing.
        !*/

    private:
        // This constructor exists simply for the purpose of causing a compile time error if
        // someone tries to create an instance of this object with the wrong kind of object.
        template <typename T1, typename T2, typename T3, typename T4>
        basic_op_mmmm (T1, T2, T3, T4);
    public:

        basic_op_mmmm(
            const M1& m1_,
            const M2& m2_,
            const M3& m3_,
            const M4& m4_
        ) : m1(m1_), m2(m2_), m3(m3_), m4(m4_){}

        const M1& m1;
        const M2& m2;
        const M3& m3;
        const M4& m4;

        const static long NR = M1::NR;
        const static long NC = M1::NC;
        typedef typename M1::mem_manager_type mem_manager_type;
        typedef typename M1::layout_type layout_type;

        long nr () const { return m1.nr(); }
        long nc () const { return m1.nc(); }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const
        { return m1.aliases(item) || m2.aliases(item) || m3.aliases(item) || m4.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const
        { return m1.destructively_aliases(item) || m2.destructively_aliases(item) ||
                 m3.destructively_aliases(item) || m4.destructively_aliases(item);}

    };

// ----------------------------------------------------------------------------------------

#define DLIB_DEFINE_OP_M(op_name, function, extra_cost)                                         \
    template <typename M>                                                                       \
    struct op_name                                                                              \
    {                                                                                           \
        op_name(                                                                                \
            const M& m_                                                                         \
        ) : m(m_){}                                                                             \
                                                                                \
        const M& m;                                                                             \
                                                                                \
        const static long cost = M::cost+(extra_cost);                                          \
        const static long NR = M::NR;                                                           \
        const static long NC = M::NC;                                                           \
        typedef typename M::type type;                                                          \
        typedef const typename M::type const_ret_type;                                          \
        typedef typename M::mem_manager_type mem_manager_type;                                  \
        typedef typename M::layout_type layout_type;                                            \
                                                                                \
        const_ret_type apply (long r, long c) const { return function(m(r,c)); }                \
                                                                                \
        long nr () const { return m.nr(); }                                                     \
        long nc () const { return m.nc(); }                                                     \
                                                                                \
        template <typename U> bool aliases               ( const matrix_exp<U>& item) const     \
        { return m.aliases(item); }                                                             \
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const     \
        { return m.destructively_aliases(item); }                                               \
                                                                                \
    };

#define DLIB_DEFINE_FUNCTION_M(op_name, name, function, extra_cost)                             \
    DLIB_DEFINE_OP_M(op_name, function, extra_cost)                                             \
    template < typename M >                                                                     \
    const matrix_op<op_name<M> > name ( const matrix_exp<M>& m)                                 \
    {                                                                                           \
        typedef op_name<M> op;                                                                  \
        return matrix_op<op>(op(m.ref()));                                                      \
    }

// ----------------------------------------------------------------------------------------

#define DLIB_DEFINE_OP_MS(op_name, function, extra_cost)                                        \
    template <typename M, typename S>                                                           \
    struct op_name                                                                              \
    {                                                                                           \
        op_name(                                                                                \
            const M& m_,                                                                        \
            const S& s_                                                                         \
        ) : m(m_), s(s_){}                                                                      \
                                                                                \
        const M& m;                                                                             \
        const S s;                                                                              \
                                                                                \
        const static long cost = M::cost+(extra_cost);                                          \
        const static long NR = M::NR;                                                           \
        const static long NC = M::NC;                                                           \
        typedef typename M::type type;                                                          \
        typedef const typename M::type const_ret_type;                                          \
        typedef typename M::mem_manager_type mem_manager_type;                                  \
        typedef typename M::layout_type layout_type;                                            \
                                                                                \
        const_ret_type apply (long r, long c) const { return function(m(r,c), s); }             \
                                                                                \
        long nr () const { return m.nr(); }                                                     \
        long nc () const { return m.nc(); }                                                     \
                                                                                \
        template <typename U> bool aliases               ( const matrix_exp<U>& item) const     \
        { return m.aliases(item); }                                                             \
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const     \
        { return m.destructively_aliases(item); }                                               \
                                                                                \
    };

#define DLIB_DEFINE_FUNCTION_MS(op_name, name, function, extra_cost)                            \
    DLIB_DEFINE_OP_MS(op_name, function, extra_cost)                                            \
    template < typename M, typename S >                                                         \
    const matrix_op<op_name<M, S> > name ( const matrix_exp<M>& m, const S& s)                  \
    {                                                                                           \
        typedef op_name<M, S> op;                                                               \
        return matrix_op<op>(op(m.ref(), s));                                                   \
    }

// ----------------------------------------------------------------------------------------

#define DLIB_DEFINE_OP_SM(op_name, function, extra_cost)                                        \
    template <typename S, typename M>                                                           \
    struct op_name                                                                              \
    {                                                                                           \
        op_name(                                                                                \
            const S& s_,                                                                        \
            const M& m_                                                                         \
        ) : m(m_), s(s_){}                                                                      \
                                                                                \
        const M& m;                                                                             \
        const S s;                                                                              \
                                                                                \
        const static long cost = M::cost+(extra_cost);                                          \
        const static long NR = M::NR;                                                           \
        const static long NC = M::NC;                                                           \
        typedef typename M::type type;                                                          \
        typedef const typename M::type const_ret_type;                                          \
        typedef typename M::mem_manager_type mem_manager_type;                                  \
        typedef typename M::layout_type layout_type;                                            \
                                                                                \
        const_ret_type apply (long r, long c) const { return function(s, m(r,c)); }             \
                                                                                \
        long nr () const { return m.nr(); }                                                     \
        long nc () const { return m.nc(); }                                                     \
                                                                                \
        template <typename U> bool aliases               ( const matrix_exp<U>& item) const     \
        { return m.aliases(item); }                                                             \
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const     \
        { return m.destructively_aliases(item); }                                               \
                                                                                \
    };

#define DLIB_DEFINE_FUNCTION_SM(op_name, name, function, extra_cost)                            \
    DLIB_DEFINE_OP_SM(op_name, function, extra_cost)                                            \
    template < typename S, typename M >                                                         \
    const matrix_op<op_name<S, M> > name (const S& s, const matrix_exp<M>& m)                   \
    {                                                                                           \
        typedef op_name<S, M> op;                                                               \
        return matrix_op<op>(op(s, m.ref()));                                                   \
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MATRIx_OP_H_


dlib C++ Library - matrix_qr.h

// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
// This code was adapted from code from the JAMA part of NIST's TNT library.
//    See: http://math.nist.gov/tnt/
#ifndef DLIB_MATRIX_QR_DECOMPOSITION_H
#define DLIB_MATRIX_QR_DECOMPOSITION_H

#include "matrix.h"
#include "matrix_utilities.h"
#include "matrix_subexp.h"

#ifdef DLIB_USE_LAPACK
#include "lapack/geqrf.h"
#include "lapack/ormqr.h"
#endif

#include "matrix_trsm.h"

namespace dlib
{

    template <
        typename matrix_exp_type
        >
    class qr_decomposition
    {

    public:

        const static long NR = matrix_exp_type::NR;
        const static long NC = matrix_exp_type::NC;
        typedef typename matrix_exp_type::type type;
        typedef typename matrix_exp_type::mem_manager_type mem_manager_type;
        typedef typename matrix_exp_type::layout_type layout_type;

        typedef matrix<type,0,0,mem_manager_type,layout_type>  matrix_type;

        // You have supplied an invalid type of matrix_exp_type.  You have
        // to use this object with matrices that contain float or double type data.
        COMPILE_TIME_ASSERT((is_same_type<float, type>::value ||
                             is_same_type<double, type>::value ));

        template <typename EXP>
        qr_decomposition(
            const matrix_exp<EXP>& A
        );

        bool is_full_rank(
        ) const;

        long nr(
        ) const;

        long nc(
        ) const;

        const matrix_type get_r (
        ) const;

        const matrix_type get_q (
        ) const;

        void get_q (
            matrix_type& Q
        ) const;

        template <typename EXP>
        const matrix_type solve (
            const matrix_exp<EXP>& B
        ) const;

    private:

#ifndef DLIB_USE_LAPACK
        template <typename EXP>
        const matrix_type solve_mat (
            const matrix_exp<EXP>& B
        ) const;

        template <typename EXP>
        const matrix_type solve_vect (
            const matrix_exp<EXP>& B
        ) const;
#endif

        /** Array for internal storage of decomposition.
        @serial internal array storage.
        */
        matrix<type,0,0,mem_manager_type,column_major_layout> QR_;

        /** Row and column dimensions.
        @serial column dimension.
        @serial row dimension.
        */
        long m, n;

        /** Array for internal storage of diagonal of R.
        @serial diagonal of R.
        */
        typedef matrix<type,0,1,mem_manager_type,column_major_layout> column_vector_type;
        column_vector_type tau;
        column_vector_type Rdiag;

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                                      Member functions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <typename matrix_exp_type>
    template <typename EXP>
    qr_decomposition<matrix_exp_type>::
    qr_decomposition(
        const matrix_exp<EXP>& A
    )
    {
        COMPILE_TIME_ASSERT((is_same_type<type, typename EXP::type>::value));

        // make sure requires clause is not broken
        DLIB_ASSERT(A.nr() >= A.nc() && A.size() > 0,
            "\tqr_decomposition::qr_decomposition(A)"
            << "\n\tInvalid inputs were given to this function"
            << "\n\tA.nr():   " << A.nr()
            << "\n\tA.nc():   " << A.nc()
            << "\n\tA.size(): " << A.size()
            << "\n\tthis:     " << this
            );

        QR_ = A;
        m = A.nr();
        n = A.nc();

#ifdef DLIB_USE_LAPACK

        lapack::geqrf(QR_, tau);
        Rdiag = diag(QR_);

#else
        Rdiag.set_size(n);
        long i=0, j=0, k=0;

        // Main loop.
        for (k = 0; k < n; k++)
        {
            // Compute 2-norm of k-th column without under/overflow.
            type nrm = 0;
            for (i = k; i < m; i++)
            {
                nrm = hypot(nrm,QR_(i,k));
            }

            if (nrm != 0.0)
            {
                // Form k-th Householder vector.
                if (QR_(k,k) < 0)
                {
                    nrm = -nrm;
                }
                for (i = k; i < m; i++)
                {
                    QR_(i,k) /= nrm;
                }
                QR_(k,k) += 1.0;

                // Apply transformation to remaining columns.
                for (j = k+1; j < n; j++)
                {
                    type s = 0.0;
                    for (i = k; i < m; i++)
                    {
                        s += QR_(i,k)*QR_(i,j);
                    }
                    s = -s/QR_(k,k);
                    for (i = k; i < m; i++)
                    {
                        QR_(i,j) += s*QR_(i,k);
                    }
                }
            }
            Rdiag(k) = -nrm;
        }
#endif
    }

// ----------------------------------------------------------------------------------------

    template <typename matrix_exp_type>
    long qr_decomposition<matrix_exp_type>::
    nr (
    ) const
    {
        return m;
    }

// ----------------------------------------------------------------------------------------

    template <typename matrix_exp_type>
    long qr_decomposition<matrix_exp_type>::
    nc (
    ) const
    {
        return n;
    }

// ----------------------------------------------------------------------------------------

    template <typename matrix_exp_type>
    bool qr_decomposition<matrix_exp_type>::
    is_full_rank(
    ) const
    {
        type eps = max(abs(Rdiag));
        if (eps != 0)
            eps *= std::sqrt(std::numeric_limits<type>::epsilon())/100;
        else
            eps = 1;  // there is no max so just use 1

        // check if any of the elements of Rdiag are effectively 0
        return min(abs(Rdiag)) > eps;
    }

// ----------------------------------------------------------------------------------------

    template <typename matrix_exp_type>
    const typename qr_decomposition<matrix_exp_type>::matrix_type qr_decomposition<matrix_exp_type>::
    get_r(
    ) const
    {
        matrix_type R(n,n);
        for (long i = 0; i < n; i++)
        {
            for (long j = 0; j < n; j++)
            {
                if (i < j)
                {
                    R(i,j) = QR_(i,j);
                }
                else if (i == j)
                {
                    R(i,j) = Rdiag(i);
                }
                else
                {
                    R(i,j) = 0.0;
                }
            }
        }
        return R;
    }

// ----------------------------------------------------------------------------------------

    template <typename matrix_exp_type>
    const typename qr_decomposition<matrix_exp_type>::matrix_type qr_decomposition<matrix_exp_type>::
    get_q(
    ) const
    {
        matrix_type Q;
        get_q(Q);
        return Q;
    }

// ----------------------------------------------------------------------------------------

    template <typename matrix_exp_type>
    void qr_decomposition<matrix_exp_type>::
    get_q(
        matrix_type& X
    ) const
    {
#ifdef DLIB_USE_LAPACK
        // Take only the first n columns of an identity matrix.  This way
        // X ends up being an m by n matrix.
        X = colm(identity_matrix<type>(m), range(0,n-1));

        // Compute Y = Q*X
        lapack::ormqr('L','N', QR_, tau, X);

#else
        long i=0, j=0, k=0;

        X.set_size(m,n);
        for (k = n-1; k >= 0; k--)
        {
            for (i = 0; i < m; i++)
            {
                X(i,k) = 0.0;
            }
            X(k,k) = 1.0;
            for (j = k; j < n; j++)
            {
                if (QR_(k,k) != 0)
                {
                    type s = 0.0;
                    for (i = k; i < m; i++)
                    {
                        s += QR_(i,k)*X(i,j);
                    }
                    s = -s/QR_(k,k);
                    for (i = k; i < m; i++)
                    {
                        X(i,j) += s*QR_(i,k);
                    }
                }
            }
        }
#endif
    }

// ----------------------------------------------------------------------------------------

    template <typename matrix_exp_type>
    template <typename EXP>
    const typename qr_decomposition<matrix_exp_type>::matrix_type qr_decomposition<matrix_exp_type>::
    solve(
        const matrix_exp<EXP>& B
    ) const
    {
        COMPILE_TIME_ASSERT((is_same_type<type, typename EXP::type>::value));

        // make sure requires clause is not broken
        DLIB_ASSERT(B.nr() == nr(),
            "\tconst matrix_type qr_decomposition::solve(B)"
            << "\n\tInvalid inputs were given to this function"
            << "\n\tB.nr():         " << B.nr()
            << "\n\tnr():           " << nr()
            << "\n\tthis:           " << this
            );

#ifdef DLIB_USE_LAPACK

        using namespace blas_bindings;
        matrix<type,0,0,mem_manager_type,column_major_layout> X(B);
        // Compute Y = transpose(Q)*B
        lapack::ormqr('L','T',QR_, tau, X);
        // Solve R*X = Y;
        triangular_solver(CblasLeft, CblasUpper, CblasNoTrans, CblasNonUnit, QR_, X, n);

        /* return n x nx portion of X */
        return subm(X,0,0,n,B.nc());

#else
        // just call the right version of the solve function
        if (B.nc() == 1)
            return solve_vect(B);
        else
            return solve_mat(B);
#endif
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                           Private member functions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

#ifndef DLIB_USE_LAPACK

    template <typename matrix_exp_type>
    template <typename EXP>
    const typename qr_decomposition<matrix_exp_type>::matrix_type qr_decomposition<matrix_exp_type>::
    solve_vect(
        const matrix_exp<EXP>& B
    ) const
    {

        column_vector_type x(B);

        // Compute Y = transpose(Q)*B
        for (long k = 0; k < n; k++)
        {
            type s = 0.0;
            for (long i = k; i < m; i++)
            {
                s += QR_(i,k)*x(i);
            }
            s = -s/QR_(k,k);
            for (long i = k; i < m; i++)
            {
                x(i) += s*QR_(i,k);
            }
        }
        // Solve R*X = Y;
        for (long k = n-1; k >= 0; k--)
        {
            x(k) /= Rdiag(k);
            for (long i = 0; i < k; i++)
            {
                x(i) -= x(k)*QR_(i,k);
            }
        }

        /* return n x 1 portion of x */
        return colm(x,0,n);
    }

// ----------------------------------------------------------------------------------------

    template <typename matrix_exp_type>
    template <typename EXP>
    const typename qr_decomposition<matrix_exp_type>::matrix_type qr_decomposition<matrix_exp_type>::
    solve_mat(
        const matrix_exp<EXP>& B
    ) const
    {
        const long nx = B.nc();
        matrix_type X(B);
        long i=0, j=0, k=0;

        // Compute Y = transpose(Q)*B
        for (k = 0; k < n; k++)
        {
            for (j = 0; j < nx; j++)
            {
                type s = 0.0;
                for (i = k; i < m; i++)
                {
                    s += QR_(i,k)*X(i,j);
                }
                s = -s/QR_(k,k);
                for (i = k; i < m; i++)
                {
                    X(i,j) += s*QR_(i,k);
                }
            }
        }
        // Solve R*X = Y;
        for (k = n-1; k >= 0; k--)
        {
            for (j = 0; j < nx; j++)
            {
                X(k,j) /= Rdiag(k);
            }
            for (i = 0; i < k; i++)
            {
                for (j = 0; j < nx; j++)
                {
                    X(i,j) -= X(k,j)*QR_(i,k);
                }
            }
        }

        /* return n x nx portion of X */
        return subm(X,0,0,n,nx);
    }

// ----------------------------------------------------------------------------------------

#endif // DLIB_USE_LAPACK not defined

}

#endif // DLIB_MATRIX_QR_DECOMPOSITION_H


dlib C++ Library - matrix_read_from_istream.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MATRIx_READ_FROM_ISTREAM_H_h_
#define DLIB_MATRIx_READ_FROM_ISTREAM_H_h_

#include "matrix.h"
#include <vector>
#include <iostream>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    namespace impl
    {
        inline bool next_is_whitespace (
            std::istream& in
        )
        {
            return in.peek() == '\n' ||
                in.peek() == ' ' ||
                in.peek() == ',' ||
                in.peek() == '\t' ||
                in.peek() == '\r';
        }
    }

    template <typename T, long NR, long NC, typename MM, typename L>
    std::istream& operator>> (
        std::istream& in,
        matrix<T,NR,NC,MM,L>& m
    )
    {
        using namespace dlib::impl;
        long num_rows = 0;
        std::vector<T> buf;
        buf.reserve(100);

        // eat any leading whitespace
        while (next_is_whitespace(in))
            in.get();

        bool at_start_of_line = true;
        bool stop = false;
        while(!stop && in.peek() != EOF)
        {
            T temp;
            in >> temp;
            if (!in)
                return in;

            buf.push_back(temp);
            if (at_start_of_line)
            {
                at_start_of_line = false;
                ++num_rows;
            }

            // Eat next block of whitespace but also note if we hit the start of the next
            // line.
            while (next_is_whitespace(in))
            {
                if (at_start_of_line && in.peek() == '\n')
                {
                    stop = true;
                    break;
                }

                if (in.get() == '\n')
                    at_start_of_line = true;
            }
        }

        // It's an error for there to not be any matrix data in the input stream
        if (num_rows == 0)
        {
            in.clear(in.rdstate() | std::ios::failbit);
            return in;
        }

        const long num_cols = buf.size()/num_rows;
        // It's also an error if the sizes don't make sense.
        if (num_rows*num_cols != (long)buf.size() ||
            (NR != 0 && NR != num_rows) ||
            (NC != 0 && NC != num_cols))
        {
            in.clear(in.rdstate() | std::ios::failbit);
            return in;
        }

        m = reshape(mat(buf),num_rows, buf.size()/num_rows);

        if (in.eof())
        {
            // Clear the eof and fail bits since this is caused by peeking at the EOF.
            // But in the current case, we have successfully read the matrix.
            in.clear(in.rdstate() & (~(std::ios::eofbit | std::ios::failbit)));
        }
        return in;
    }
}

// ----------------------------------------------------------------------------------------

#endif // DLIB_MATRIx_READ_FROM_ISTREAM_H_h_


dlib C++ Library - matrix_subexp.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MATRIx_SUBEXP_
#define DLIB_MATRIx_SUBEXP_

#include "matrix_subexp_abstract.h"
#include "matrix_op.h"
#include "matrix.h"
#include "../geometry/rectangle.h"
#include "matrix_expressions.h"
#include "matrix_mat.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <long start, long inc, long end>
    const matrix_range_static_exp<start,inc,end> range (
    )
    {
        COMPILE_TIME_ASSERT(inc > 0);
        return matrix_range_static_exp<start,inc,end>();
    }

    template <long start, long end>
    const matrix_range_static_exp<start,1,end> range (
    )
    {
        return matrix_range_static_exp<start,1,end>();
    }

    inline const matrix_range_exp<long> range (
        long start,
        long end
    )
    {
        return matrix_range_exp<long>(start,end);
    }

    inline const matrix_range_exp<long> range (
        long start,
        long inc,
        long end
    )
    {
        DLIB_ASSERT(inc > 0,
            "\tconst matrix_exp range(start, inc, end)"
            << "\n\tInvalid inputs to this function"
            << "\n\tstart: " << start
            << "\n\tinc:   " << inc
            << "\n\tend:   " << end
            );

        return matrix_range_exp<long>(start,inc,end);
    }

// ----------------------------------------------------------------------------------------

    template <typename M>
    struct op_subm
    {
        op_subm (
            const M& m_x,
            const long& r_x,
            const long& c_x,
            const long& nr_x,
            const long& nc_x
        ) : m(m_x), r_(r_x), c_(c_x), nr_(nr_x), nc_(nc_x) { }

        const M& m;
        const long r_;
        const long c_;
        const long nr_;
        const long nc_;

        const static long cost = M::cost+1;
        typedef typename M::type type;
        typedef typename M::const_ret_type const_ret_type;
        typedef typename M::mem_manager_type mem_manager_type;
        typedef typename M::layout_type layout_type;
        const static long NR = 0;
        const static long NC = 0;

        const_ret_type apply ( long r, long c) const { return m(r+r_,c+c_); }

        long nr () const { return nr_; }
        long nc () const { return nc_; }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }
    };

    template <
        typename EXP
        >
    const matrix_op<op_subm<EXP> > subm (
        const matrix_exp<EXP>& m,
        long r,
        long c,
        long nr,
        long nc
    )
    {
        DLIB_ASSERT(r >= 0 && c >= 0 && nr >= 0 && nc >= 0 && r+nr <= m.nr() && c+nc <= m.nc(),
            "\tconst matrix_exp subm(const matrix_exp& m, r, c, nr, nc)"
            << "\n\tYou have specified invalid sub matrix dimensions"
            << "\n\tm.nr(): " << m.nr()
            << "\n\tm.nc(): " << m.nc()
            << "\n\tr:      " << r
            << "\n\tc:      " << c
            << "\n\tnr:     " << nr
            << "\n\tnc:     " << nc
            );

        typedef op_subm<EXP> op;
        return matrix_op<op>(op(m.ref(),r,c,nr,nc));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP
        >
    const matrix_op<op_subm<EXP> > subm (
        const matrix_exp<EXP>& m,
        const rectangle& rect
    )
    {
        DLIB_ASSERT(get_rect(m).contains(rect) == true,
            "\tconst matrix_exp subm(const matrix_exp& m, const rectangle& rect)"
            << "\n\tYou have specified invalid sub matrix dimensions"
            << "\n\tm.nr(): " << m.nr()
            << "\n\tm.nc(): " << m.nc()
            << "\n\trect.left():   " << rect.left()
            << "\n\trect.top():    " << rect.top()
            << "\n\trect.right():  " << rect.right()
            << "\n\trect.bottom(): " << rect.bottom()
            );

        typedef op_subm<EXP> op;
        return matrix_op<op>(op(m.ref(),rect.top(),rect.left(),rect.height(),rect.width()));
    }

// ----------------------------------------------------------------------------------------

    template <typename M1, typename M2, typename M3>
    struct op_subm_range
    {
        op_subm_range( const M1& m1_, const M2& rows_, const M3& cols_) :
            m1(m1_), rows(rows_), cols(cols_) {}
        const M1& m1;
        const M2& rows;
        const M3& cols;

        const static long cost = M1::cost+M2::cost+M3::cost;
        typedef typename M1::type type;
        typedef typename M1::const_ret_type const_ret_type;
        typedef typename M1::mem_manager_type mem_manager_type;
        typedef typename M1::layout_type layout_type;
        const static long NR = M2::NC*M2::NR;
        const static long NC = M3::NC*M3::NR;

        const_ret_type apply ( long r, long c) const { return m1(rows(r),cols(c)); }

        long nr () const { return rows.size(); }
        long nc () const { return cols.size(); }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const
        { return m1.aliases(item) || rows.aliases(item) || cols.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const
        { return m1.aliases(item) || rows.aliases(item) || cols.aliases(item); }
    };

    template <
        typename EXP,
        typename EXPr,
        typename EXPc
        >
    const matrix_op<op_subm_range<EXP,EXPr,EXPc> > subm (
        const matrix_exp<EXP>& m,
        const matrix_exp<EXPr>& rows,
        const matrix_exp<EXPc>& cols
    )
    {
        // the rows and cols matrices must contain integer elements
        COMPILE_TIME_ASSERT(std::numeric_limits<typename EXPr::type>::is_integer);
        COMPILE_TIME_ASSERT(std::numeric_limits<typename EXPc::type>::is_integer);

        DLIB_ASSERT(0 <= min(rows) && max(rows) < m.nr() && 0 <= min(cols) && max(cols) < m.nc() &&
                    (rows.nr() == 1 || rows.nc() == 1) && (cols.nr() == 1 || cols.nc() == 1),
            "\tconst matrix_exp subm(const matrix_exp& m, const matrix_exp& rows, const matrix_exp& cols)"
            << "\n\tYou have given invalid arguments to this function"
            << "\n\tm.nr():     " << m.nr()
            << "\n\tm.nc():     " << m.nc()
            << "\n\tmin(rows):  " << min(rows)
            << "\n\tmax(rows):  " << max(rows)
            << "\n\tmin(cols):  " << min(cols)
            << "\n\tmax(cols):  " << max(cols)
            << "\n\trows.nr():  " << rows.nr()
            << "\n\trows.nc():  " << rows.nc()
            << "\n\tcols.nr():  " << cols.nr()
            << "\n\tcols.nc():  " << cols.nc()
            );

        typedef op_subm_range<EXP,EXPr,EXPc> op;
        return matrix_op<op>(op(m.ref(),rows.ref(),cols.ref()));
    }

// ----------------------------------------------------------------------------------------

    template <typename M>
    struct op_rowm
    {
        op_rowm(const M& m_, const long& row_) : m(m_), row(row_) {}
        const M& m;
        const long row;

        const static long cost = M::cost;
        const static long NR = 1;
        const static long NC = M::NC;
        typedef typename M::type type;
        typedef typename M::const_ret_type const_ret_type;
        typedef typename M::mem_manager_type mem_manager_type;
        typedef typename M::layout_type layout_type;
        const_ret_type apply ( long, long c) const { return m(row,c); }

        long nr () const { return 1; }
        long nc () const { return m.nc(); }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }
    };

    template <
        typename EXP
        >
    const matrix_op<op_rowm<EXP> > rowm (
        const matrix_exp<EXP>& m,
        long row
    )
    {
        DLIB_ASSERT(row >= 0 && row < m.nr(),
            "\tconst matrix_exp rowm(const matrix_exp& m, row)"
            << "\n\tYou have specified invalid sub matrix dimensions"
            << "\n\tm.nr(): " << m.nr()
            << "\n\tm.nc(): " << m.nc()
            << "\n\trow:    " << row
            );

        typedef op_rowm<EXP> op;
        return matrix_op<op>(op(m.ref(),row));
    }

    template <typename EXP>
    struct rowm_exp
    {
        typedef matrix_op<op_rowm<EXP> > type;
    };

// ----------------------------------------------------------------------------------------

    template <typename M>
    struct op_rowm2
    {
        op_rowm2(const M& m_, const long& row_, const long& len) : m(m_), row(row_), length(len) {}
        const M& m;
        const long row;
        const long length;

        const static long cost = M::cost;
        const static long NR = 1;
        const static long NC = 0;
        typedef typename M::type type;
        typedef typename M::const_ret_type const_ret_type;
        typedef typename M::mem_manager_type mem_manager_type;
        typedef typename M::layout_type layout_type;
        const_ret_type apply ( long , long c) const { return m(row,c); }

        long nr () const { return 1; }
        long nc () const { return length; }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }
    };

    template <
        typename EXP
        >
    const matrix_op<op_rowm2<EXP> > rowm (
        const matrix_exp<EXP>& m,
        long row,
        long length
    )
    {
        DLIB_ASSERT(row >= 0 && row < m.nr() &&
                    length >= 0 && length <= m.nc(),
            "\tconst matrix_exp rowm(const matrix_exp& m, row, length)"
            << "\n\tYou have specified invalid sub matrix dimensions"
            << "\n\tm.nr(): " << m.nr()
            << "\n\tm.nc(): " << m.nc()
            << "\n\trow:    " << row
            << "\n\tlength: " << length
            );

        typedef op_rowm2<EXP> op;
        return matrix_op<op>(op(m.ref(), row, length));
    }

// ----------------------------------------------------------------------------------------

    template <typename M1, typename M2>
    struct op_rowm_range
    {
        op_rowm_range( const M1& m1_, const M2& rows_) : m1(m1_), rows(rows_) {}
        const M1& m1;
        const M2& rows;

        const static long cost = M1::cost+M2::cost;
        typedef typename M1::type type;
        typedef typename M1::const_ret_type const_ret_type;
        typedef typename M1::mem_manager_type mem_manager_type;
        typedef typename M1::layout_type layout_type;
        const static long NR = M2::NC*M2::NR;
        const static long NC = M1::NC;

        const_ret_type apply ( long r, long c) const { return m1(rows(r),c); }

        long nr () const { return rows.size(); }
        long nc () const { return m1.nc(); }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const
        { return m1.aliases(item) || rows.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const
        { return m1.aliases(item) || rows.aliases(item); }
    };

    template <
        typename EXP1,
        typename EXP2
        >
    const matrix_op<op_rowm_range<EXP1,EXP2> > rowm (
        const matrix_exp<EXP1>& m,
        const matrix_exp<EXP2>& rows
    )
    {
        // the rows matrix must contain integer elements
        COMPILE_TIME_ASSERT(std::numeric_limits<typename EXP2::type>::is_integer);

        DLIB_ASSERT(0 <= min(rows) && max(rows) < m.nr() && (rows.nr() == 1 || rows.nc() == 1),
            "\tconst matrix_exp rowm(const matrix_exp& m, const matrix_exp& rows)"
            << "\n\tYou have given invalid arguments to this function"
            << "\n\tm.nr():     " << m.nr()
            << "\n\tm.nc():     " << m.nc()
            << "\n\tmin(rows):  " << min(rows)
            << "\n\tmax(rows):  " << max(rows)
            << "\n\trows.nr():  " << rows.nr()
            << "\n\trows.nc():  " << rows.nc()
            );

        typedef op_rowm_range<EXP1,EXP2> op;
        return matrix_op<op>(op(m.ref(),rows.ref()));
    }

// ----------------------------------------------------------------------------------------

    template <typename M>
    struct op_colm
    {
        op_colm(const M& m_, const long& col_) : m(m_), col(col_) {}
        const M& m;
        const long col;

        const static long cost = M::cost;
        const static long NR = M::NR;
        const static long NC = 1;
        typedef typename M::type type;
        typedef typename M::const_ret_type const_ret_type;
        typedef typename M::mem_manager_type mem_manager_type;
        typedef typename M::layout_type layout_type;
        const_ret_type apply ( long r, long) const { return m(r,col); }

        long nr () const { return m.nr(); }
        long nc () const { return 1; }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }
    };

    template <
        typename EXP
        >
    const matrix_op<op_colm<EXP> > colm (
        const matrix_exp<EXP>& m,
        long col
    )
    {
        DLIB_ASSERT(col >= 0 && col < m.nc(),
            "\tconst matrix_exp colm(const matrix_exp& m, row)"
            << "\n\tYou have specified invalid sub matrix dimensions"
            << "\n\tm.nr(): " << m.nr()
            << "\n\tm.nc(): " << m.nc()
            << "\n\tcol:    " << col
            );

        typedef op_colm<EXP> op;
        return matrix_op<op>(op(m.ref(),col));
    }

    template <typename EXP>
    struct colm_exp
    {
        typedef matrix_op<op_colm<EXP> > type;
    };

// ----------------------------------------------------------------------------------------

    template <typename M>
    struct op_colm2
    {
        op_colm2(const M& m_, const long& col_, const long& len) : m(m_), col(col_), length(len) {}
        const M& m;
        const long col;
        const long length;

        const static long cost = M::cost;
        const static long NR = 0;
        const static long NC = 1;
        typedef typename M::type type;
        typedef typename M::const_ret_type const_ret_type;
        typedef typename M::mem_manager_type mem_manager_type;
        typedef typename M::layout_type layout_type;
        const_ret_type apply ( long r, long ) const { return m(r,col); }

        long nr () const { return length; }
        long nc () const { return 1; }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }
    };

    template <
        typename EXP
        >
    const matrix_op<op_colm2<EXP> > colm (
        const matrix_exp<EXP>& m,
        long col,
        long length
    )
    {
        DLIB_ASSERT(col >= 0 && col < m.nc() &&
                    length >= 0 && length <= m.nr(),
            "\tconst matrix_exp colm(const matrix_exp& m, col, length)"
            << "\n\tYou have specified invalid sub matrix dimensions"
            << "\n\tm.nr(): " << m.nr()
            << "\n\tm.nc(): " << m.nc()
            << "\n\tcol:    " << col
            << "\n\tlength: " << length
            );

        typedef op_colm2<EXP> op;
        return matrix_op<op>(op(m.ref(),col, length));
    }

// ----------------------------------------------------------------------------------------

    template <typename M1, typename M2>
    struct op_colm_range
    {
        op_colm_range( const M1& m1_, const M2& cols_) : m1(m1_), cols(cols_) {}
        const M1& m1;
        const M2& cols;

        typedef typename M1::type type;
        typedef typename M1::const_ret_type const_ret_type;
        typedef typename M1::mem_manager_type mem_manager_type;
        typedef typename M1::layout_type layout_type;
        const static long NR = M1::NR;
        const static long NC = M2::NC*M2::NR;
        const static long cost = M1::cost+M2::cost;

        const_ret_type apply (long r, long c) const { return m1(r,cols(c)); }

        long nr () const { return m1.nr(); }
        long nc () const { return cols.size(); }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const
        { return m1.aliases(item) || cols.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const
        { return m1.aliases(item) || cols.aliases(item); }
    };

    template <
        typename EXP1,
        typename EXP2
        >
    const matrix_op<op_colm_range<EXP1,EXP2> > colm (
        const matrix_exp<EXP1>& m,
        const matrix_exp<EXP2>& cols
    )
    {
        // the rows matrix must contain integer elements
        COMPILE_TIME_ASSERT(std::numeric_limits<typename EXP2::type>::is_integer);

        DLIB_ASSERT(0 <= min(cols) && max(cols) < m.nc() && (cols.nr() == 1 || cols.nc() == 1),
            "\tconst matrix_exp colm(const matrix_exp& m, const matrix_exp& cols)"
            << "\n\tYou have given invalid arguments to this function"
            << "\n\tm.nr():     " << m.nr()
            << "\n\tm.nc():     " << m.nc()
            << "\n\tmin(cols):  " << min(cols)
            << "\n\tmax(cols):  " << max(cols)
            << "\n\tcols.nr():  " << cols.nr()
            << "\n\tcols.nc():  " << cols.nc()
            );

        typedef op_colm_range<EXP1,EXP2> op;
        return matrix_op<op>(op(m.ref(),cols.ref()));
    }

// ----------------------------------------------------------------------------------------

    template <typename T>
    class assignable_ptr_matrix
    {
    public:
        typedef T type;
        typedef row_major_layout layout_type;
        typedef matrix<T,0,0,default_memory_manager,layout_type> matrix_type;

        assignable_ptr_matrix(
            T* ptr_,
            long nr_,
            long nc_
        ) : ptr(ptr_), height(nr_), width(nc_){}

        T& operator() (
            long r,
            long c
        )
        {
            return ptr[r*width + c];
        }

        const T& operator() (
            long r,
            long c
        ) const
        {
            return ptr[r*width + c];
        }

        long nr() const { return height; }
        long nc() const { return width; }

        template <typename EXP>
        assignable_ptr_matrix& operator= (
            const matrix_exp<EXP>& exp
        )
        {
            // You can only assign to a set_ptrm() expression with a source matrix that
            // contains the same type of elements as the target (i.e. you can't mix double
            // and float types).
            COMPILE_TIME_ASSERT((is_same_type<T, typename EXP::type>::value == true));

            DLIB_ASSERT( exp.nr() == height && exp.nc() == width,
                "\tassignable_matrix_expression set_ptrm()"
                << "\n\tYou have tried to assign to this object using a matrix that isn't the right size"
                << "\n\texp.nr() (source matrix): " << exp.nr()
                << "\n\texp.nc() (source matrix): " << exp.nc()
                << "\n\twidth (target matrix):    " << width
                << "\n\theight (target matrix):   " << height
                );

            if (exp.destructively_aliases(mat(ptr,height,width)) == false)
            {
                matrix_assign(*this, exp);
            }
            else
            {
                // make a temporary copy of the matrix we are going to assign to ptr to
                // avoid aliasing issues during the copy
                this->operator=(tmp(exp));
            }

            return *this;
        }

        template <typename EXP>
        assignable_ptr_matrix& operator+= (
            const matrix_exp<EXP>& exp
        )
        {
            // You can only assign to a set_ptrm() expression with a source matrix that
            // contains the same type of elements as the target (i.e. you can't mix double
            // and float types).
            COMPILE_TIME_ASSERT((is_same_type<T, typename EXP::type>::value == true));

            DLIB_ASSERT( exp.nr() == height && exp.nc() == width,
                "\tassignable_matrix_expression set_ptrm()"
                << "\n\tYou have tried to assign to this object using a matrix that isn't the right size"
                << "\n\texp.nr() (source matrix): " << exp.nr()
                << "\n\texp.nc() (source matrix): " << exp.nc()
                << "\n\twidth (target matrix):    " << width
                << "\n\theight (target matrix):   " << height
                );

            if (exp.destructively_aliases(mat(ptr,height,width)) == false)
            {
                matrix_assign(*this, mat(ptr,height,width)+exp);
            }
            else
            {
                // make a temporary copy of the matrix we are going to assign to ptr to
                // avoid aliasing issues during the copy
                this->operator+=(tmp(exp));
            }

            return *this;
        }

        template <typename EXP>
        assignable_ptr_matrix& operator-= (
            const matrix_exp<EXP>& exp
        )
        {
            // You can only assign to a set_ptrm() expression with a source matrix that
            // contains the same type of elements as the target (i.e. you can't mix double
            // and float types).
            COMPILE_TIME_ASSERT((is_same_type<T, typename EXP::type>::value == true));

            DLIB_ASSERT( exp.nr() == height && exp.nc() == width,
                "\tassignable_matrix_expression set_ptrm()"
                << "\n\tYou have tried to assign to this object using a matrix that isn't the right size"
                << "\n\texp.nr() (source matrix): " << exp.nr()
                << "\n\texp.nc() (source matrix): " << exp.nc()
                << "\n\twidth (target matrix):    " << width
                << "\n\theight (target matrix):   " << height
                );

            if (exp.destructively_aliases(mat(ptr,height,width)) == false)
            {
                matrix_assign(*this, mat(ptr,height,width)-exp);
            }
            else
            {
                // make a temporary copy of the matrix we are going to assign to ptr to
                // avoid aliasing issues during the copy
                this->operator-=(tmp(exp));
            }

            return *this;
        }

        assignable_ptr_matrix& operator= (
            const T& value
        )
        {
            const long size = width*height;
            for (long i = 0; i < size; ++i)
                ptr[i] = value;

            return *this;
        }

        assignable_ptr_matrix& operator+= (
            const T& value
        )
        {
            const long size = width*height;
            for (long i = 0; i < size; ++i)
                ptr[i] += value;

            return *this;
        }

        assignable_ptr_matrix& operator-= (
            const T& value
        )
        {
            const long size = width*height;
            for (long i = 0; i < size; ++i)
                ptr[i] -= value;

            return *this;
        }

        T* ptr;
        const long height;
        const long width;
    };

    template <typename T>
    assignable_ptr_matrix<T> set_ptrm (
        T* ptr,
        long nr,
        long nc = 1
    )
    {
        DLIB_ASSERT(nr >= 0 && nc >= 0,
            "\t assignable_matrix_expression set_ptrm(T* ptr, long nr, long nc)"
            << "\n\t The dimensions can't be negative."
            << "\n\t nr: " << nr
            << "\n\t nc: " << nc
            );

        return assignable_ptr_matrix<T>(ptr,nr,nc);
    }

// ----------------------------------------------------------------------------------------

    template <typename T, long NR, long NC, typename mm, typename l>
    class assignable_sub_matrix
    {
    public:
        typedef T type;
        typedef l layout_type;
        typedef matrix<T,NR,NC,mm,l> matrix_type;

        assignable_sub_matrix(
            matrix<T,NR,NC,mm,l>& m_,
            long top_,
            long left_,
            long height_,
            long width_
        ) : m(m_), left(left_), top(top_), width(width_), height(height_) {}

        T& operator() (
            long r,
            long c
        )
        {
            return m(r+top,c+left);
        }

        const T& operator() (
            long r,
            long c
        ) const
        {
            return m(r+top,c+left);
        }

        long nr() const { return height; }
        long nc() const { return width; }

        template <typename EXP>
        assignable_sub_matrix& operator= (
            const matrix_exp<EXP>& exp
        )
        {
            DLIB_ASSERT( exp.nr() == height && exp.nc() == width,
                "\tassignable_matrix_expression set_subm()"
                << "\n\tYou have tried to assign to this object using a matrix that isn't the right size"
                << "\n\texp.nr() (source matrix): " << exp.nr()
                << "\n\texp.nc() (source matrix): " << exp.nc()
                << "\n\twidth (target matrix):    " << width
                << "\n\theight (target matrix):   " << height
                );

            if (exp.destructively_aliases(m) == false)
            {
                matrix_assign(*this, exp);
            }
            else
            {
                // make a temporary copy of the matrix we are going to assign to m to
                // avoid aliasing issues during the copy
                this->operator=(tmp(exp));
            }

            return *this;
        }

        template <typename EXP>
        assignable_sub_matrix& operator+= (
            const matrix_exp<EXP>& exp
        )
        {
            DLIB_ASSERT( exp.nr() == height && exp.nc() == width,
                "\tassignable_matrix_expression set_subm()"
                << "\n\tYou have tried to assign to this object using a matrix that isn't the right size"
                << "\n\texp.nr() (source matrix): " << exp.nr()
                << "\n\texp.nc() (source matrix): " << exp.nc()
                << "\n\twidth (target matrix):    " << width
                << "\n\theight (target matrix):   " << height
                );

            if (exp.destructively_aliases(m) == false)
            {
                matrix_assign(*this, subm(m,top,left,height,width)+exp);
            }
            else
            {
                // make a temporary copy of the matrix we are going to assign to m to
                // avoid aliasing issues during the copy
                this->operator+=(tmp(exp));
            }

            return *this;
        }

        template <typename EXP>
        assignable_sub_matrix& operator-= (
            const matrix_exp<EXP>& exp
        )
        {
            DLIB_ASSERT( exp.nr() == height && exp.nc() == width,
                "\tassignable_matrix_expression set_subm()"
                << "\n\tYou have tried to assign to this object using a matrix that isn't the right size"
                << "\n\texp.nr() (source matrix): " << exp.nr()
                << "\n\texp.nc() (source matrix): " << exp.nc()
                << "\n\twidth (target matrix):    " << width
                << "\n\theight (target matrix):   " << height
                );

            if (exp.destructively_aliases(m) == false)
            {
                matrix_assign(*this, subm(m,top,left,height,width)-exp);
            }
            else
            {
                // make a temporary copy of the matrix we are going to assign to m to
                // avoid aliasing issues during the copy
                this->operator-=(tmp(exp));
            }

            return *this;
        }

        assignable_sub_matrix& operator= (
            const T& value
        )
        {
            const long bottom = top+height-1;
            const long right = left+width-1;
            for (long r = top; r <= bottom; ++r)
            {
                for (long c = left; c <= right; ++c)
                {
                    m(r,c) = value;
                }
            }

            return *this;
        }

        assignable_sub_matrix& operator+= (
            const T& value
        )
        {
            const long bottom = top+height-1;
            const long right = left+width-1;
            for (long r = top; r <= bottom; ++r)
            {
                for (long c = left; c <= right; ++c)
                {
                    m(r,c) += value;
                }
            }

            return *this;
        }

        assignable_sub_matrix& operator-= (
            const T& value
        )
        {
            const long bottom = top+height-1;
            const long right = left+width-1;
            for (long r = top; r <= bottom; ++r)
            {
                for (long c = left; c <= right; ++c)
                {
                    m(r,c) -= value;
                }
            }

            return *this;
        }

        matrix<T,NR,NC,mm,l>& m;
        const long left, top, width, height;
    };

    template <typename T, long NR, long NC, typename mm, typename l>
    assignable_sub_matrix<T,NR,NC,mm,l> set_subm (
        matrix<T,NR,NC,mm,l>& m,
        const rectangle& rect
    )
    {
        DLIB_ASSERT(get_rect(m).contains(rect) == true,
            "\tassignable_matrix_expression set_subm(matrix& m, const rectangle& rect)"
            << "\n\tYou have specified invalid sub matrix dimensions"
            << "\n\tm.nr(): " << m.nr()
            << "\n\tm.nc(): " << m.nc()
            << "\n\trect.left():   " << rect.left()
            << "\n\trect.top():    " << rect.top()
            << "\n\trect.right():  " << rect.right()
            << "\n\trect.bottom(): " << rect.bottom()
            );

        return assignable_sub_matrix<T,NR,NC,mm,l>(m,rect.top(), rect.left(), rect.height(), rect.width());
    }

    template <typename T, long NR, long NC, typename mm, typename l>
    assignable_sub_matrix<T,NR,NC,mm,l> set_subm (
        matrix<T,NR,NC,mm,l>& m,
        long r,
        long c,
        long nr,
        long nc
    )
    {
        DLIB_ASSERT(r >= 0 && c >= 0 && nr >= 0 && nc >= 0 && r+nr <= m.nr() && c+nc <= m.nc(),
                    "\tassignable_matrix_expression set_subm(matrix& m, r, c, nr, nc)"
                    << "\n\tYou have specified invalid sub matrix dimensions"
                    << "\n\tm.nr(): " << m.nr()
                    << "\n\tm.nc(): " << m.nc()
                    << "\n\tr:      " << r
                    << "\n\tc:      " << c
                    << "\n\tnr:     " << nr
                    << "\n\tnc:     " << nc
        );

        return assignable_sub_matrix<T,NR,NC,mm,l>(m,r,c, nr, nc);
    }

// ----------------------------------------------------------------------------------------

    template <typename T, long NR, long NC, typename mm, typename l, typename EXPr, typename EXPc>
    class assignable_sub_range_matrix
    {
    public:
        typedef T type;
        typedef l layout_type;
        typedef matrix<T,NR,NC,mm,l> matrix_type;

        assignable_sub_range_matrix(
            matrix<T,NR,NC,mm,l>& m_,
            const EXPr& rows_,
            const EXPc& cols_
        ) : m(m_), rows(rows_), cols(cols_) {}

        T& operator() (
            long r,
            long c
        )
        {
            return m(rows(r),cols(c));
        }

        long nr() const { return rows.size(); }
        long nc() const { return cols.size(); }

        template <typename EXP>
        assignable_sub_range_matrix& operator= (
            const matrix_exp<EXP>& exp
        )
        {
            DLIB_ASSERT( exp.nr() == rows.size() && exp.nc() == cols.size(),
                "\tassignable_matrix_expression set_subm(matrix& m, const matrix_exp rows, const matrix_exp cols)"
                << "\n\tYou have tried to assign to this object using a matrix that isn't the right size"
                << "\n\texp.nr() (source matrix): " << exp.nr()
                << "\n\texp.nc() (source matrix): " << exp.nc()
                << "\n\trows.size() (target matrix):  " << rows.size()
                << "\n\tcols.size() (target matrix):  " << cols.size()
                );

            if (exp.destructively_aliases(m) == false)
            {
                matrix_assign(*this, exp);
            }
            else
            {
                // make a temporary copy of the matrix we are going to assign to m to
                // avoid aliasing issues during the copy
                this->operator=(tmp(exp));
            }

            return *this;
        }

        template <typename EXP>
        assignable_sub_range_matrix& operator+= (
            const matrix_exp<EXP>& exp
        )
        {
            DLIB_ASSERT( exp.nr() == rows.size() && exp.nc() == cols.size(),
                "\tassignable_matrix_expression set_subm(matrix& m, const matrix_exp rows, const matrix_exp cols)"
                << "\n\tYou have tried to assign to this object using a matrix that isn't the right size"
                << "\n\texp.nr() (source matrix): " << exp.nr()
                << "\n\texp.nc() (source matrix): " << exp.nc()
                << "\n\trows.size() (target matrix):  " << rows.size()
                << "\n\tcols.size() (target matrix):  " << cols.size()
                );

            if (exp.destructively_aliases(m) == false)
            {
                matrix_assign(*this, subm(m,rows,cols)+exp);
            }
            else
            {
                // make a temporary copy of the matrix we are going to assign to m to
                // avoid aliasing issues during the copy
                this->operator+=(tmp(exp));
            }

            return *this;
        }

        template <typename EXP>
        assignable_sub_range_matrix& operator-= (
            const matrix_exp<EXP>& exp
        )
        {
            DLIB_ASSERT( exp.nr() == rows.size() && exp.nc() == cols.size(),
                "\tassignable_matrix_expression set_subm(matrix& m, const matrix_exp rows, const matrix_exp cols)"
                << "\n\tYou have tried to assign to this object using a matrix that isn't the right size"
                << "\n\texp.nr() (source matrix): " << exp.nr()
                << "\n\texp.nc() (source matrix): " << exp.nc()
                << "\n\trows.size() (target matrix):  " << rows.size()
                << "\n\tcols.size() (target matrix):  " << cols.size()
                );

            if (exp.destructively_aliases(m) == false)
            {
                matrix_assign(*this, subm(m,rows,cols)-exp);
            }
            else
            {
                // make a temporary copy of the matrix we are going to assign to m to
                // avoid aliasing issues during the copy
                this->operator-=(tmp(exp));
            }

            return *this;
        }

        assignable_sub_range_matrix& operator= (
            const T& value
        )
        {
            for (long r = 0; r < rows.size(); ++r)
            {
                for (long c = 0; c < cols.size(); ++c)
                {
                    m(rows(r),cols(c)) = value;
                }
            }

            return *this;
        }

        assignable_sub_range_matrix& operator+= (
            const T& value
        )
        {
            for (long r = 0; r < rows.size(); ++r)
            {
                for (long c = 0; c < cols.size(); ++c)
                {
                    m(rows(r),cols(c)) += value;
                }
            }

            return *this;
        }

        assignable_sub_range_matrix& operator-= (
            const T& value
        )
        {
            for (long r = 0; r < rows.size(); ++r)
            {
                for (long c = 0; c < cols.size(); ++c)
                {
                    m(rows(r),cols(c)) -= value;
                }
            }

            return *this;
        }

    private:

        matrix<T,NR,NC,mm,l>& m;
        const EXPr rows;
        const EXPc cols;
    };

    template <typename T, long NR, long NC, typename mm, typename l, typename EXPr, typename EXPc>
    assignable_sub_range_matrix<T,NR,NC,mm,l,EXPr,EXPc > set_subm (
        matrix<T,NR,NC,mm,l>& m,
        const matrix_exp<EXPr>& rows,
        const matrix_exp<EXPc>& cols
    )
    {
        DLIB_ASSERT(0 <= min(rows) && max(rows) < m.nr() && 0 <= min(cols) && max(cols) < m.nc() &&
                    (rows.nr() == 1 || rows.nc() == 1) && (cols.nr() == 1 || cols.nc() == 1),
            "\tassignable_matrix_expression set_subm(matrix& m, const matrix_exp& rows, const matrix_exp& cols)"
            << "\n\tYou have specified invalid sub matrix dimensions"
            << "\n\tm.nr():     " << m.nr()
            << "\n\tm.nc():     " << m.nc()
            << "\n\tmin(rows):  " << min(rows)
            << "\n\tmax(rows):  " << max(rows)
            << "\n\tmin(cols):  " << min(cols)
            << "\n\tmax(cols):  " << max(cols)
            << "\n\trows.nr():  " << rows.nr()
            << "\n\trows.nc():  " << rows.nc()
            << "\n\tcols.nr():  " << cols.nr()
            << "\n\tcols.nc():  " << cols.nc()
            );

        return assignable_sub_range_matrix<T,NR,NC,mm,l,EXPr,EXPc >(m,rows.ref(),cols.ref());
    }

// ----------------------------------------------------------------------------------------

    template <typename T, long NR, long NC, typename mm, typename l, typename EXPr>
    assignable_sub_range_matrix<T,NR,NC,mm,l,EXPr,matrix_range_exp<long> > set_rowm (
        matrix<T,NR,NC,mm,l>& m,
        const matrix_exp<EXPr>& rows
    )
    {
        DLIB_ASSERT(0 <= min(rows) && max(rows) < m.nr() && (rows.nr() == 1 || rows.nc() == 1),
            "\tassignable_matrix_expression set_rowm(matrix& m, const matrix_exp& rows)"
            << "\n\tYou have specified invalid sub matrix dimensions"
            << "\n\tm.nr():     " << m.nr()
            << "\n\tm.nc():     " << m.nc()
            << "\n\tmin(rows):  " << min(rows)
            << "\n\tmax(rows):  " << max(rows)
            << "\n\trows.nr():  " << rows.nr()
            << "\n\trows.nc():  " << rows.nc()
            );

        return assignable_sub_range_matrix<T,NR,NC,mm,l,EXPr,matrix_range_exp<long> >(m,rows.ref(),range(0,m.nc()-1));
    }

// ----------------------------------------------------------------------------------------

    template <typename T, long NR, long NC, typename mm, typename l, typename EXPc>
    assignable_sub_range_matrix<T,NR,NC,mm,l,matrix_range_exp<long>,EXPc > set_colm (
        matrix<T,NR,NC,mm,l>& m,
        const matrix_exp<EXPc>& cols
    )
    {
        DLIB_ASSERT(0 <= min(cols) && max(cols) < m.nc() && (cols.nr() == 1 || cols.nc() == 1),
            "\tassignable_matrix_expression set_colm(matrix& m, const matrix_exp& cols)"
            << "\n\tYou have specified invalid sub matrix dimensions"
            << "\n\tm.nr():     " << m.nr()
            << "\n\tm.nc():     " << m.nc()
            << "\n\tmin(cols):  " << min(cols)
            << "\n\tmax(cols):  " << max(cols)
            << "\n\tcols.nr():  " << cols.nr()
            << "\n\tcols.nc():  " << cols.nc()
            );

        return assignable_sub_range_matrix<T,NR,NC,mm,l,matrix_range_exp<long>,EXPc >(m,range(0,m.nr()-1),cols.ref());
    }

// ----------------------------------------------------------------------------------------

    template <typename T, long NR, long NC, typename mm, typename l>
    class assignable_col_matrix
    {
    public:
        typedef T type;
        typedef l layout_type;
        typedef matrix<T,NR,NC,mm,l> matrix_type;

        assignable_col_matrix(
            matrix<T,NR,NC,mm,l>& m_,
            const long col_
        ) : m(m_), col(col_) {}

        T& operator() (
            long r,
            long
        )
        {
            return m(r,col);
        }

        const T& operator() (
            long r,
            long
        ) const
        {
            return m(r,col);
        }

        long nr() const { return m.nr(); }
        long nc() const { return 1; }

        template <typename EXP>
        assignable_col_matrix& operator= (
            const matrix_exp<EXP>& exp
        )
        {
            DLIB_ASSERT( exp.nc() == 1 && exp.nr() == m.nr(),
                "\tassignable_matrix_expression set_colm()"
                << "\n\tYou have tried to assign to this object using a matrix that isn't the right size"
                << "\n\texp.nr() (source matrix): " << exp.nr()
                << "\n\texp.nc() (source matrix): " << exp.nc()
                << "\n\tm.nr() (target matrix):   " << m.nr()
                );

            if (exp.destructively_aliases(m) == false)
            {
                matrix_assign(*this, exp);
            }
            else
            {
                // make a temporary copy of the matrix we are going to assign to m to
                // avoid aliasing issues during the copy
                this->operator=(tmp(exp));
            }

            return *this;
        }

        template <typename EXP>
        assignable_col_matrix& operator+= (
            const matrix_exp<EXP>& exp
        )
        {
            DLIB_ASSERT( exp.nc() == 1 && exp.nr() == m.nr(),
                "\tassignable_matrix_expression set_colm()"
                << "\n\tYou have tried to assign to this object using a matrix that isn't the right size"
                << "\n\texp.nr() (source matrix): " << exp.nr()
                << "\n\texp.nc() (source matrix): " << exp.nc()
                << "\n\tm.nr() (target matrix):   " << m.nr()
                );

            if (exp.destructively_aliases(m) == false)
            {
                matrix_assign(*this, colm(m,col)+exp);
            }
            else
            {
                // make a temporary copy of the matrix we are going to assign to m to
                // avoid aliasing issues during the copy
                this->operator+=(tmp(exp));
            }

            return *this;
        }

        template <typename EXP>
        assignable_col_matrix& operator-= (
            const matrix_exp<EXP>& exp
        )
        {
            DLIB_ASSERT( exp.nc() == 1 && exp.nr() == m.nr(),
                "\tassignable_matrix_expression set_colm()"
                << "\n\tYou have tried to assign to this object using a matrix that isn't the right size"
                << "\n\texp.nr() (source matrix): " << exp.nr()
                << "\n\texp.nc() (source matrix): " << exp.nc()
                << "\n\tm.nr() (target matrix):   " << m.nr()
                );

            if (exp.destructively_aliases(m) == false)
            {
                matrix_assign(*this, colm(m,col)-exp);
            }
            else
            {
                // make a temporary copy of the matrix we are going to assign to m to
                // avoid aliasing issues during the copy
                this->operator-=(tmp(exp));
            }

            return *this;
        }

        assignable_col_matrix& operator= (
            const T& value
        )
        {
            for (long i = 0; i < m.nr(); ++i)
            {
                m(i,col) = value;
            }

            return *this;
        }

        assignable_col_matrix& operator+= (
            const T& value
        )
        {
            for (long i = 0; i < m.nr(); ++i)
            {
                m(i,col) += value;
            }

            return *this;
        }

        assignable_col_matrix& operator-= (
            const T& value
        )
        {
            for (long i = 0; i < m.nr(); ++i)
            {
                m(i,col) -= value;
            }

            return *this;
        }

        matrix<T,NR,NC,mm,l>& m;
        const long col;
    };

    template <typename T, long NR, long NC, typename mm, typename l>
    assignable_col_matrix<T,NR,NC,mm,l> set_colm (
        matrix<T,NR,NC,mm,l>& m,
        const long col
    )
    {
        DLIB_ASSERT(col >= 0 && col < m.nc(),
            "\tassignable_matrix_expression set_colm(matrix& m, col)"
            << "\n\tYou have specified invalid sub matrix dimensions"
            << "\n\tm.nr(): " << m.nr()
            << "\n\tm.nc(): " << m.nc()
            << "\n\tcol:    " << col
            );

        return assignable_col_matrix<T,NR,NC,mm,l>(m,col);
    }

// ----------------------------------------------------------------------------------------

    template <typename T, long NR, long NC, typename mm, typename l>
    class assignable_row_matrix
    {
    public:
        typedef T type;
        typedef l layout_type;
        typedef matrix<T,NR,NC,mm,l> matrix_type;

        assignable_row_matrix(
            matrix<T,NR,NC,mm,l>& m_,
            const long row_
        ) : m(m_), row(row_) {}

        T& operator() (
            long ,
            long c
        )
        {
            return m(row,c);
        }

        const T& operator() (
            long ,
            long c
        ) const
        {
            return m(row,c);
        }

        long nr() const { return 1; }
        long nc() const { return m.nc(); }

        template <typename EXP>
        assignable_row_matrix& operator= (
            const matrix_exp<EXP>& exp
        )
        {
            DLIB_ASSERT( exp.nr() == 1 && exp.nc() == m.nc(),
                "\tassignable_matrix_expression set_rowm()"
                << "\n\tYou have tried to assign to this object using a matrix that isn't the right size"
                << "\n\texp.nr() (source matrix): " << exp.nr()
                << "\n\texp.nc() (source matrix): " << exp.nc()
                << "\n\tm.nc() (target matrix):   " << m.nc()
                );

            if (exp.destructively_aliases(m) == false)
            {
                matrix_assign(*this, exp);
            }
            else
            {
                // make a temporary copy of the matrix we are going to assign to m to
                // avoid aliasing issues during the copy
                this->operator=(tmp(exp));
            }

            return *this;
        }

        template <typename EXP>
        assignable_row_matrix& operator+= (
            const matrix_exp<EXP>& exp
        )
        {
            DLIB_ASSERT( exp.nr() == 1 && exp.nc() == m.nc(),
                "\tassignable_matrix_expression set_rowm()"
                << "\n\tYou have tried to assign to this object using a matrix that isn't the right size"
                << "\n\texp.nr() (source matrix): " << exp.nr()
                << "\n\texp.nc() (source matrix): " << exp.nc()
                << "\n\tm.nc() (target matrix):   " << m.nc()
                );

            if (exp.destructively_aliases(m) == false)
            {
                matrix_assign(*this, rowm(m,row)+exp);
            }
            else
            {
                // make a temporary copy of the matrix we are going to assign to m to
                // avoid aliasing issues during the copy
                this->operator+=(tmp(exp));
            }

            return *this;
        }

        template <typename EXP>
        assignable_row_matrix& operator-= (
            const matrix_exp<EXP>& exp
        )
        {
            DLIB_ASSERT( exp.nr() == 1 && exp.nc() == m.nc(),
                "\tassignable_matrix_expression set_rowm()"
                << "\n\tYou have tried to assign to this object using a matrix that isn't the right size"
                << "\n\texp.nr() (source matrix): " << exp.nr()
                << "\n\texp.nc() (source matrix): " << exp.nc()
                << "\n\tm.nc() (target matrix):   " << m.nc()
                );

            if (exp.destructively_aliases(m) == false)
            {
                matrix_assign(*this, rowm(m,row)-exp);
            }
            else
            {
                // make a temporary copy of the matrix we are going to assign to m to
                // avoid aliasing issues during the copy
                this->operator-=(tmp(exp));
            }

            return *this;
        }

        assignable_row_matrix& operator= (
            const T& value
        )
        {
            for (long i = 0; i < m.nc(); ++i)
            {
                m(row,i) = value;
            }

            return *this;
        }

        assignable_row_matrix& operator+= (
            const T& value
        )
        {
            for (long i = 0; i < m.nc(); ++i)
            {
                m(row,i) += value;
            }

            return *this;
        }

        assignable_row_matrix& operator-= (
            const T& value
        )
        {
            for (long i = 0; i < m.nc(); ++i)
            {
                m(row,i) -= value;
            }

            return *this;
        }

        matrix<T,NR,NC,mm,l>& m;
        const long row;
    };

    template <typename T, long NR, long NC, typename mm, typename l>
    assignable_row_matrix<T,NR,NC,mm,l> set_rowm (
        matrix<T,NR,NC,mm,l>& m,
        const long row
    )
    {
        DLIB_ASSERT(row >= 0 && row < m.nr(),
            "\tassignable_matrix_expression set_rowm(matrix& m, row)"
            << "\n\tYou have specified invalid sub matrix dimensions"
            << "\n\tm.nr(): " << m.nr()
            << "\n\tm.nc(): " << m.nc()
            << "\n\trow:    " << row
            );

        return assignable_row_matrix<T,NR,NC,mm,l>(m,row);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MATRIx_SUBEXP_


dlib C++ Library - matrix_trsm.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MATRiX_TRSM_Hh_
#define DLIB_MATRiX_TRSM_Hh_
#include "lapack/fortran_id.h"
#include "cblas_constants.h"

namespace dlib
{
    namespace blas_bindings
    {

        extern "C"
        {
            void cblas_strsm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,
                             const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,
                             const enum CBLAS_DIAG Diag, const int M, const int N,
                             const float alpha, const float *A, const int lda,
                             float *B, const int ldb);

            void cblas_dtrsm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,
                             const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,
                             const enum CBLAS_DIAG Diag, const int M, const int N,
                             const double alpha, const double *A, const int lda,
                             double *B, const int ldb);
        }

    // ------------------------------------------------------------------------------------

/*  Purpose */
/*  ======= */

/*  DTRSM  solves one of the matrix equations */

/*     op( A )*X = alpha*B,   or   X*op( A ) = alpha*B, */

/*  where alpha is a scalar, X and B are m by n matrices, A is a unit, or */
/*  non-unit,  upper or lower triangular matrix  and  op( A )  is one  of */

/*     op( A ) = A   or   op( A ) = A'. */

/*  The matrix X is overwritten on B. */

/*  Arguments */
/*  ========== */

/*  SIDE   - CHARACTER*1. */
/*           On entry, SIDE specifies whether op( A ) appears on the left */
/*           or right of X as follows: */

/*              SIDE = 'L' or 'l'   op( A )*X = alpha*B. */

/*              SIDE = 'R' or 'r'   X*op( A ) = alpha*B. */

/*           Unchanged on exit. */

/*  UPLO   - CHARACTER*1. */
/*           On entry, UPLO specifies whether the matrix A is an upper or */
/*           lower triangular matrix as follows: */

/*              UPLO = 'U' or 'u'   A is an upper triangular matrix. */

/*              UPLO = 'L' or 'l'   A is a lower triangular matrix. */

/*           Unchanged on exit. */

/*  TRANSA - CHARACTER*1. */
/*           On entry, TRANSA specifies the form of op( A ) to be used in */
/*           the matrix multiplication as follows: */

/*              TRANSA = 'N' or 'n'   op( A ) = A. */

/*              TRANSA = 'T' or 't'   op( A ) = A'. */

/*              TRANSA = 'C' or 'c'   op( A ) = A'. */

/*           Unchanged on exit. */

/*  DIAG   - CHARACTER*1. */
/*           On entry, DIAG specifies whether or not A is unit triangular */
/*           as follows: */

/*              DIAG = 'U' or 'u'   A is assumed to be unit triangular. */

/*              DIAG = 'N' or 'n'   A is not assumed to be unit */
/*                                  triangular. */

/*           Unchanged on exit. */

/*  M      - INTEGER. */
/*           On entry, M specifies the number of rows of B. M must be at */
/*           least zero. */
/*           Unchanged on exit. */

/*  N      - INTEGER. */
/*           On entry, N specifies the number of columns of B.  N must be */
/*           at least zero. */
/*           Unchanged on exit. */

/*  ALPHA  - DOUBLE PRECISION. */
/*           On entry,  ALPHA specifies the scalar  alpha. When  alpha is */
/*           zero then  A is not referenced and  B need not be set before */
/*           entry. */
/*           Unchanged on exit. */

/*  A      - DOUBLE PRECISION array of DIMENSION ( LDA, k ), where k is m */
/*           when  SIDE = 'L' or 'l'  and is  n  when  SIDE = 'R' or 'r'. */
/*           Before entry  with  UPLO = 'U' or 'u',  the  leading  k by k */
/*           upper triangular part of the array  A must contain the upper */
/*           triangular matrix  and the strictly lower triangular part of */
/*           A is not referenced. */
/*           Before entry  with  UPLO = 'L' or 'l',  the  leading  k by k */
/*           lower triangular part of the array  A must contain the lower */
/*           triangular matrix  and the strictly upper triangular part of */
/*           A is not referenced. */
/*           Note that when  DIAG = 'U' or 'u',  the diagonal elements of */
/*           A  are not referenced either,  but are assumed to be  unity. */
/*           Unchanged on exit. */

/*  LDA    - INTEGER. */
/*           On entry, LDA specifies the first dimension of A as declared */
/*           in the calling (sub) program.  When  SIDE = 'L' or 'l'  then */
/*           LDA  must be at least  max( 1, m ),  when  SIDE = 'R' or 'r' */
/*           then LDA must be at least max( 1, n ). */
/*           Unchanged on exit. */

/*  B      - DOUBLE PRECISION array of DIMENSION ( LDB, n ). */
/*           Before entry,  the leading  m by n part of the array  B must */
/*           contain  the  right-hand  side  matrix  B,  and  on exit  is */
/*           overwritten by the solution matrix  X. */

/*  LDB    - INTEGER. */
/*           On entry, LDB specifies the first dimension of B as declared */
/*           in  the  calling  (sub)  program.   LDB  must  be  at  least */
/*           max( 1, m ). */
/*           Unchanged on exit. */

/*  Level 3 Blas routine. */

/*  -- Written on 8-February-1989. */
/*     Jack Dongarra, Argonne National Laboratory. */
/*     Iain Duff, AERE Harwell. */
/*     Jeremy Du Croz, Numerical Algorithms Group Ltd. */
/*     Sven Hammarling, Numerical Algorithms Group Ltd. */

        template <typename T>
        void local_trsm(
            const enum CBLAS_ORDER Order,
            enum CBLAS_SIDE Side,
            enum CBLAS_UPLO Uplo,
            const enum CBLAS_TRANSPOSE TransA,
            const enum CBLAS_DIAG Diag,
            long m,
            long n,
            T alpha,
            const T *a,
            long lda,
            T *b,
            long ldb
        )
        /*!
            This is a copy of the dtrsm routine from the netlib.org BLAS which was run though
            f2c and converted into this form for use when a BLAS library is not available.
        !*/
        {
            if (Order == CblasRowMajor)
            {
                // since row major ordering looks like transposition to FORTRAN we need to flip a
                // few things.
                if (Side == CblasLeft)
                    Side = CblasRight;
                else
                    Side = CblasLeft;

                if (Uplo == CblasUpper)
                    Uplo = CblasLower;
                else
                    Uplo = CblasUpper;

                std::swap(m,n);
            }

            /* System generated locals */
            long a_dim1, a_offset, b_dim1, b_offset, i__1, i__2, i__3;

            /* Local variables */
            long i__, j, k, info;
            T temp;
            bool lside;
            long nrowa;
            bool upper;
            bool nounit;

            /* Parameter adjustments */
            a_dim1 = lda;
            a_offset = 1 + a_dim1;
            a -= a_offset;
            b_dim1 = ldb;
            b_offset = 1 + b_dim1;
            b -= b_offset;

            /* Function Body */
            lside = (Side == CblasLeft);
            if (lside)
            {
                nrowa = m;
            } else
            {
                nrowa = n;
            }
            nounit = (Diag == CblasNonUnit);
            upper = (Uplo == CblasUpper);

            info = 0;
            if (! lside && ! (Side == CblasRight)) {
                info = 1;
            } else if (! upper && !(Uplo == CblasLower) ) {
                info = 2;
            } else if (!(TransA == CblasNoTrans) &&
                       !(TransA == CblasTrans) &&
                       !(TransA == CblasConjTrans))  {
                info = 3;
            } else if (!(Diag == CblasUnit) &&
                       !(Diag == CblasNonUnit) ) {
                info = 4;
            } else if (m < 0) {
                info = 5;
            } else if (n < 0) {
                info = 6;
            } else if (lda < std::max<long>(1,nrowa)) {
                info = 9;
            } else if (ldb < std::max<long>(1,m)) {
                info = 11;
            }
            DLIB_CASSERT( info == 0, "Invalid inputs given to local_trsm");

            /*     Quick return if possible. */

            if (m == 0 || n == 0) {
                return;
            }

            /*     And when  alpha.eq.zero. */

            if (alpha == 0.) {
                i__1 = n;
                for (j = 1; j <= i__1; ++j) {
                    i__2 = m;
                    for (i__ = 1; i__ <= i__2; ++i__) {
                        b[i__ + j * b_dim1] = 0.;
                        /* L10: */
                    }
                    /* L20: */
                }
                return;
            }

            /*     Start the operations. */

            if (lside) {
                if (TransA == CblasNoTrans) {

                    /*           Form  B := alpha*inv( A )*B. */

                    if (upper) {
                        i__1 = n;
                        for (j = 1; j <= i__1; ++j) {
                            if (alpha != 1.) {
                                i__2 = m;
                                for (i__ = 1; i__ <= i__2; ++i__) {
                                    b[i__ + j * b_dim1] = alpha * b[i__ + j * b_dim1]
                                        ;
                                    /* L30: */
                                }
                            }
                            for (k = m; k >= 1; --k) {
                                if (b[k + j * b_dim1] != 0.) {
                                    if (nounit) {
                                        b[k + j * b_dim1] /= a[k + k * a_dim1];
                                    }
                                    i__2 = k - 1;
                                    for (i__ = 1; i__ <= i__2; ++i__) {
                                        b[i__ + j * b_dim1] -= b[k + j * b_dim1] * a[
                                            i__ + k * a_dim1];
                                        /* L40: */
                                    }
                                }
                                /* L50: */
                            }
                            /* L60: */
                        }
                    } else {
                        i__1 = n;
                        for (j = 1; j <= i__1; ++j) {
                            if (alpha != 1.) {
                                i__2 = m;
                                for (i__ = 1; i__ <= i__2; ++i__) {
                                    b[i__ + j * b_dim1] = alpha * b[i__ + j * b_dim1]
                                        ;
                                    /* L70: */
                                }
                            }
                            i__2 = m;
                            for (k = 1; k <= i__2; ++k) {
                                if (b[k + j * b_dim1] != 0.) {
                                    if (nounit) {
                                        b[k + j * b_dim1] /= a[k + k * a_dim1];
                                    }
                                    i__3 = m;
                                    for (i__ = k + 1; i__ <= i__3; ++i__) {
                                        b[i__ + j * b_dim1] -= b[k + j * b_dim1] * a[
                                            i__ + k * a_dim1];
                                        /* L80: */
                                    }
                                }
                                /* L90: */
                            }
                            /* L100: */
                        }
                    }
                } else {

                    /*           Form  B := alpha*inv( A' )*B. */

                    if (upper) {
                        i__1 = n;
                        for (j = 1; j <= i__1; ++j) {
                            i__2 = m;
                            for (i__ = 1; i__ <= i__2; ++i__) {
                                temp = alpha * b[i__ + j * b_dim1];
                                i__3 = i__ - 1;
                                for (k = 1; k <= i__3; ++k) {
                                    temp -= a[k + i__ * a_dim1] * b[k + j * b_dim1];
                                    /* L110: */
                                }
                                if (nounit) {
                                    temp /= a[i__ + i__ * a_dim1];
                                }
                                b[i__ + j * b_dim1] = temp;
                                /* L120: */
                            }
                            /* L130: */
                        }
                    } else {
                        i__1 = n;
                        for (j = 1; j <= i__1; ++j) {
                            for (i__ = m; i__ >= 1; --i__) {
                                temp = alpha * b[i__ + j * b_dim1];
                                i__2 = m;
                                for (k = i__ + 1; k <= i__2; ++k) {
                                    temp -= a[k + i__ * a_dim1] * b[k + j * b_dim1];
                                    /* L140: */
                                }
                                if (nounit) {
                                    temp /= a[i__ + i__ * a_dim1];
                                }
                                b[i__ + j * b_dim1] = temp;
                                /* L150: */
                            }
                            /* L160: */
                        }
                    }
                }
            } else {
                if (TransA == CblasNoTrans) {

                    /*           Form  B := alpha*B*inv( A ). */

                    if (upper) {
                        i__1 = n;
                        for (j = 1; j <= i__1; ++j) {
                            if (alpha != 1.) {
                                i__2 = m;
                                for (i__ = 1; i__ <= i__2; ++i__) {
                                    b[i__ + j * b_dim1] = alpha * b[i__ + j * b_dim1]
                                        ;
                                    /* L170: */
                                }
                            }
                            i__2 = j - 1;
                            for (k = 1; k <= i__2; ++k) {
                                if (a[k + j * a_dim1] != 0.) {
                                    i__3 = m;
                                    for (i__ = 1; i__ <= i__3; ++i__) {
                                        b[i__ + j * b_dim1] -= a[k + j * a_dim1] * b[
                                            i__ + k * b_dim1];
                                        /* L180: */
                                    }
                                }
                                /* L190: */
                            }
                            if (nounit) {
                                temp = 1. / a[j + j * a_dim1];
                                i__2 = m;
                                for (i__ = 1; i__ <= i__2; ++i__) {
                                    b[i__ + j * b_dim1] = temp * b[i__ + j * b_dim1];
                                    /* L200: */
                                }
                            }
                            /* L210: */
                        }
                    } else {
                        for (j = n; j >= 1; --j) {
                            if (alpha != 1.) {
                                i__1 = m;
                                for (i__ = 1; i__ <= i__1; ++i__) {
                                    b[i__ + j * b_dim1] = alpha * b[i__ + j * b_dim1]
                                        ;
                                    /* L220: */
                                }
                            }
                            i__1 = n;
                            for (k = j + 1; k <= i__1; ++k) {
                                if (a[k + j * a_dim1] != 0.) {
                                    i__2 = m;
                                    for (i__ = 1; i__ <= i__2; ++i__) {
                                        b[i__ + j * b_dim1] -= a[k + j * a_dim1] * b[
                                            i__ + k * b_dim1];
                                        /* L230: */
                                    }
                                }
                                /* L240: */
                            }
                            if (nounit) {
                                temp = 1. / a[j + j * a_dim1];
                                i__1 = m;
                                for (i__ = 1; i__ <= i__1; ++i__) {
                                    b[i__ + j * b_dim1] = temp * b[i__ + j * b_dim1];
                                    /* L250: */
                                }
                            }
                            /* L260: */
                        }
                    }
                } else {

                    /*           Form  B := alpha*B*inv( A' ). */

                    if (upper) {
                        for (k = n; k >= 1; --k) {
                            if (nounit) {
                                temp = 1. / a[k + k * a_dim1];
                                i__1 = m;
                                for (i__ = 1; i__ <= i__1; ++i__) {
                                    b[i__ + k * b_dim1] = temp * b[i__ + k * b_dim1];
                                    /* L270: */
                                }
                            }
                            i__1 = k - 1;
                            for (j = 1; j <= i__1; ++j) {
                                if (a[j + k * a_dim1] != 0.) {
                                    temp = a[j + k * a_dim1];
                                    i__2 = m;
                                    for (i__ = 1; i__ <= i__2; ++i__) {
                                        b[i__ + j * b_dim1] -= temp * b[i__ + k *
                                            b_dim1];
                                        /* L280: */
                                    }
                                }
                                /* L290: */
                            }
                            if (alpha != 1.) {
                                i__1 = m;
                                for (i__ = 1; i__ <= i__1; ++i__) {
                                    b[i__ + k * b_dim1] = alpha * b[i__ + k * b_dim1]
                                        ;
                                    /* L300: */
                                }
                            }
                            /* L310: */
                        }
                    } else {
                        i__1 = n;
                        for (k = 1; k <= i__1; ++k) {
                            if (nounit) {
                                temp = 1. / a[k + k * a_dim1];
                                i__2 = m;
                                for (i__ = 1; i__ <= i__2; ++i__) {
                                    b[i__ + k * b_dim1] = temp * b[i__ + k * b_dim1];
                                    /* L320: */
                                }
                            }
                            i__2 = n;
                            for (j = k + 1; j <= i__2; ++j) {
                                if (a[j + k * a_dim1] != 0.) {
                                    temp = a[j + k * a_dim1];
                                    i__3 = m;
                                    for (i__ = 1; i__ <= i__3; ++i__) {
                                        b[i__ + j * b_dim1] -= temp * b[i__ + k *
                                            b_dim1];
                                        /* L330: */
                                    }
                                }
                                /* L340: */
                            }
                            if (alpha != 1.) {
                                i__2 = m;
                                for (i__ = 1; i__ <= i__2; ++i__) {
                                    b[i__ + k * b_dim1] = alpha * b[i__ + k * b_dim1]
                                        ;
                                    /* L350: */
                                }
                            }
                            /* L360: */
                        }
                    }
                }
            }
        }

    // ------------------------------------------------------------------------------------

        inline void cblas_trsm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,
                               const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,
                               const enum CBLAS_DIAG Diag, const int M, const int N,
                               const float alpha, const float *A, const int lda,
                               float *B, const int ldb)
        {
#ifdef DLIB_USE_BLAS
            if (M > 4)
            {
                cblas_strsm(Order, Side, Uplo, TransA, Diag, M, N, alpha, A, lda, B, ldb);
                return;
            }
#endif
            local_trsm(Order, Side, Uplo, TransA, Diag, M, N, alpha, A, lda, B, ldb);
        }

        inline void cblas_trsm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,
                               const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,
                               const enum CBLAS_DIAG Diag, const int M, const int N,
                               const double alpha, const double *A, const int lda,
                               double *B, const int ldb)
        {
#ifdef DLIB_USE_BLAS
            if (M > 4)
            {
                cblas_dtrsm(Order, Side, Uplo, TransA, Diag, M, N, alpha, A, lda, B, ldb);
                return;
            }
#endif
            local_trsm(Order, Side, Uplo, TransA, Diag, M, N, alpha, A, lda, B, ldb);
        }

        inline void cblas_trsm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,
                               const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,
                               const enum CBLAS_DIAG Diag, const int M, const int N,
                               const long double alpha, const long double *A, const int lda,
                               long double *B, const int ldb)
        {
            local_trsm(Order, Side, Uplo, TransA, Diag, M, N, alpha, A, lda, B, ldb);
        }

    // ------------------------------------------------------------------------------------

        template <
            typename T,
            long NR1, long NR2,
            long NC1, long NC2,
            typename MM
            >
        inline void triangular_solver (
            const enum CBLAS_SIDE Side,
            const enum CBLAS_UPLO Uplo,
            const enum CBLAS_TRANSPOSE TransA,
            const enum CBLAS_DIAG Diag,
            const matrix<T,NR1,NC1,MM,row_major_layout>& A,
            const T alpha,
            matrix<T,NR2,NC2,MM,row_major_layout>& B
        )
        {
            cblas_trsm(CblasRowMajor, Side,  Uplo, TransA, Diag, B.nr(), B.nc(),
                       alpha, &A(0,0), A.nc(), &B(0,0), B.nc());
        }

    // ------------------------------------------------------------------------------------

        template <
            typename T,
            long NR1, long NR2,
            long NC1, long NC2,
            typename MM
            >
        inline void triangular_solver (
            const enum CBLAS_SIDE Side,
            const enum CBLAS_UPLO Uplo,
            const enum CBLAS_TRANSPOSE TransA,
            const enum CBLAS_DIAG Diag,
            const matrix<T,NR1,NC1,MM,column_major_layout>& A,
            const T alpha,
            matrix<T,NR2,NC2,MM,column_major_layout>& B
        )
        {
            cblas_trsm(CblasColMajor, Side,  Uplo, TransA, Diag, B.nr(), B.nc(),
                       alpha, &A(0,0), A.nr(), &B(0,0), B.nr());
        }

    // ------------------------------------------------------------------------------------

        template <
            typename T,
            long NR1, long NR2,
            long NC1, long NC2,
            typename MM
            >
        inline void triangular_solver (
            const enum CBLAS_SIDE Side,
            const enum CBLAS_UPLO Uplo,
            const enum CBLAS_TRANSPOSE TransA,
            const enum CBLAS_DIAG Diag,
            const matrix<T,NR1,NC1,MM,column_major_layout>& A,
            matrix<T,NR2,NC2,MM,column_major_layout>& B,
            long rows_of_B
        )
        {
            const T alpha = 1;
            cblas_trsm(CblasColMajor, Side,  Uplo, TransA, Diag, rows_of_B, B.nc(),
                       alpha, &A(0,0), A.nr(), &B(0,0), B.nr());
        }

    // ------------------------------------------------------------------------------------

        template <
            typename T,
            long NR1, long NR2,
            long NC1, long NC2,
            typename MM,
            typename layout
            >
        inline void triangular_solver (
            const enum CBLAS_SIDE Side,
            const enum CBLAS_UPLO Uplo,
            const enum CBLAS_TRANSPOSE TransA,
            const enum CBLAS_DIAG Diag,
            const matrix<T,NR1,NC1,MM,layout>& A,
            matrix<T,NR2,NC2,MM,layout>& B
        )
        {
            const T alpha = 1;
            triangular_solver(Side, Uplo, TransA, Diag, A, alpha, B);
        }

    // ------------------------------------------------------------------------------------

    }
}

#endif // DLIB_MATRiX_TRSM_Hh_


dlib C++ Library - symmetric_matrix_cache.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SYMMETRIC_MATRIX_CAcHE_Hh_
#define DLIB_SYMMETRIC_MATRIX_CAcHE_Hh_

#include "symmetric_matrix_cache_abstract.h"
#include <vector>
#include "../matrix.h"
#include "../algs.h"
#include "../array.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <typename M, typename cache_element_type>
    struct op_symm_cache : basic_op_m<M>
    {
        inline op_symm_cache(
            const M& m_,
            long max_size_megabytes_
        ) :
            basic_op_m<M>(m_),
            max_size_megabytes(max_size_megabytes_),
            is_initialized(false)
        {
            lookup.assign(this->m.nr(), -1);

            diag_cache = matrix_cast<cache_element_type>(dlib::diag(m_));
        }

        op_symm_cache (
            const op_symm_cache& item
        ) :
            basic_op_m<M>(item.m),
            diag_cache(item.diag_cache),
            max_size_megabytes(item.max_size_megabytes),
            is_initialized(false)
        {
            lookup.assign(this->m.nr(), -1);
        }

        typedef cache_element_type type;
        typedef const cache_element_type& const_ret_type;
        const static long cost = M::cost + 3;

        inline const_ret_type apply ( long r, long c) const
        {
            if (lookup[c] != -1)
            {
                return cache[lookup[c]](r);
            }
            else if (r == c)
            {
                return diag_cache(r);
            }
            else if (lookup[r] != -1)
            {
                // the matrix is symmetric so this is legit
                return cache[lookup[r]](c);
            }
            else
            {
                add_col_to_cache(c);
                return cache[lookup[c]](r);
            }
        }

        inline std::pair<const type*,long*> col(long i) const
        /*!
            requires
                - 0 <= i < nc()
            ensures
                - returns a pair P such that:
                    - P.first == a pointer to the first element of the ith column
                    - P.second == a pointer to the integer used to count the number of
                      outstanding references to the ith column.
        !*/
        {
            if (is_cached(i) == false)
                add_col_to_cache(i);

            // find where this column is in the cache
            long idx = lookup[i];
            if (idx == next)
            {
                // if this column was the next to be replaced
                // then make sure that doesn't happen
                next = (next + 1)%cache.size();
            }

            return std::make_pair(&cache[idx](0), &references[idx]);
        }

        const type* diag() const { init(); return &diag_cache(0); }

        long* diag_ref_count() const
        {
            return &diag_reference_count;
        }

    private:
        inline bool is_cached (
            long r
        ) const
        {
            return (lookup[r] != -1);
        }

        inline void init() const
        {
            if (is_initialized == false)
            {
                // figure out how many columns of the matrix we can have
                // with the given amount of memory.
                long max_size = (max_size_megabytes*1024*1024)/(this->m.nr()*sizeof(type));
                // don't let it be 0 or 1
                if (max_size <= 1)
                    max_size = 2;

                const long size = std::min(max_size,this->m.nr());

                diag_reference_count = 0;

                references.set_max_size(this->m.nr());
                references.set_size(size);
                for (unsigned long i = 0; i < references.size(); ++i)
                    references[i] = 0;

                cache.set_max_size(this->m.nr());
                cache.set_size(size);

                rlookup.assign(size,-1);
                next = 0;

                is_initialized = true;
            }
        }

        void make_sure_next_is_unreferenced (
        ) const
        {
            if (references[next] != 0)
            {
                // find an unreferenced element of the cache
                unsigned long i;
                for (i = 1; i < references.size(); ++i)
                {
                    const unsigned long idx = (next+i)%references.size();
                    if (references[idx] == 0)
                    {
                        next = idx;
                        break;
                    }
                }

                // if all elements of the cache are referenced then make the cache bigger
                // and use the new element.
                if (references[next] != 0)
                {
                    cache.resize(cache.size()+1);

                    next = references.size();
                    references.resize(references.size()+1);
                    references[next] = 0;

                    rlookup.push_back(-1);
                }
            }
        }

        inline void add_col_to_cache(
            long c
        ) const
        {
            init();
            make_sure_next_is_unreferenced();

            // if the lookup table is pointing to cache[next] then clear lookup[next]
            if (rlookup[next] != -1)
                lookup[rlookup[next]] = -1;

            // make the lookup table so that it says c is now cached at the spot indicated by next
            lookup[c] = next;
            rlookup[next] = c;

            // compute this column in the matrix and store it in the cache
            cache[next] = matrix_cast<cache_element_type>(colm(this->m,c));

            next = (next + 1)%cache.size();
        }

        /*!
        INITIAL VALUE
            - for all valid x:
                - lookup(x) == -1

            - diag_cache == the diagonal of the original matrix
            - is_initialized == false
            - max_size_megabytes == the max_size_megabytes from symmetric_matrix_cache()

        CONVENTION
            - diag_cache == the diagonal of the original matrix
            - lookup.size() == diag_cache.size()

            - if (is_initialized) then
                - if (lookup[c] != -1) then
                    - cache[lookup[c]] == the cached column c of the matrix
                    - rlookup[lookup[c]] == c

                - if (rlookup[x] != -1) then
                    - lookup[rlookup[x]] == x
                    - cache[x] == the cached column rlookup[x] of the matrix

                - next == the next element in the cache table to use to cache something
                - references[i] == the number of outstanding references to cache element cache[i]

                - diag_reference_count == the number of outstanding references to diag_cache.
                  (this isn't really needed.  It's just here so that we can reuse the matrix
                  expression from colm() to implement diag())
        !*/

        mutable array<matrix<type,0,1,typename M::mem_manager_type> > cache;
        mutable array<long> references;
        matrix<type,0,1,typename M::mem_manager_type> diag_cache;
        mutable std::vector<long> lookup;
        mutable std::vector<long> rlookup;
        mutable long next;

        const long max_size_megabytes;
        mutable bool is_initialized;
        mutable long diag_reference_count;

    };

    template <
        typename cache_element_type,
        typename EXP
        >
    const matrix_op<op_symm_cache<EXP,cache_element_type> >  symmetric_matrix_cache (
        const matrix_exp<EXP>& m,
        long max_size_megabytes
    )
    {
        // Don't check that m is symmetric since doing so would be extremely onerous for the
        // kinds of matrices intended for use with the symmetric_matrix_cache.  Check everything
        // else though.
        DLIB_ASSERT(m.size() > 0 && m.nr() == m.nc() && max_size_megabytes >= 0,
            "\tconst matrix_exp symmetric_matrix_cache(const matrix_exp& m, max_size_megabytes)"
            << "\n\t You have given invalid arguments to this function"
            << "\n\t m.nr():             " << m.nr()
            << "\n\t m.nc():             " << m.nc()
            << "\n\t m.size():           " << m.size()
            << "\n\t max_size_megabytes: " << max_size_megabytes
            );

        typedef op_symm_cache<EXP,cache_element_type> op;
        return matrix_op<op>(op(m.ref(), max_size_megabytes));
    }

// ----------------------------------------------------------------------------------------

    template <typename M, typename cache_element_type>
    struct op_colm_symm_cache
    {
        typedef cache_element_type type;

        op_colm_symm_cache(
            const M& m_,
            const type* data_,
            long* ref_count_
        ) :
            m(m_),
            data(data_),
            ref_count(ref_count_)
        {
            *ref_count += 1;
        }

        op_colm_symm_cache (
            const op_colm_symm_cache& item
        ) :
            m(item.m),
            data(item.data),
            ref_count(item.ref_count)
        {
            *ref_count += 1;
        }

        ~op_colm_symm_cache(
        )
        {
            *ref_count -= 1;
        }

        const M& m;

        const type* const data;
        long* const ref_count;

        const static long cost = M::cost;
        const static long NR = M::NR;
        const static long NC = 1;
        typedef const type& const_ret_type;
        typedef typename M::mem_manager_type mem_manager_type;
        typedef typename M::layout_type layout_type;
        inline const_ret_type apply ( long r, long) const { return data[r]; }

        long nr () const { return m.nr(); }
        long nc () const { return 1; }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }
    };

    template <
        typename EXP,
        typename cache_element_type
        >
    inline const matrix_op<op_colm_symm_cache<EXP,cache_element_type> > colm (
        const matrix_exp<matrix_op<op_symm_cache<EXP,cache_element_type> > >& m,
        long col
    )
    {
        DLIB_ASSERT(col >= 0 && col < m.nc(),
            "\tconst matrix_exp colm(const matrix_exp& m, row)"
            << "\n\tYou have specified invalid sub matrix dimensions"
            << "\n\tm.nr(): " << m.nr()
            << "\n\tm.nc(): " << m.nc()
            << "\n\tcol:    " << col
            );

        std::pair<const cache_element_type*,long*> p = m.ref().op.col(col);

        typedef op_colm_symm_cache<EXP,cache_element_type> op;
        return matrix_op<op>(op(m.ref().op.m,
                                p.first,
                                p.second));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP,
        typename cache_element_type
        >
    inline const matrix_op<op_colm_symm_cache<EXP,cache_element_type> > diag (
        const matrix_exp<matrix_op<op_symm_cache<EXP,cache_element_type> > >& m
    )
    {
        typedef op_colm_symm_cache<EXP,cache_element_type> op;
        return matrix_op<op>(op(m.ref().op.m,
                                m.ref().op.diag(),
                                m.ref().op.diag_ref_count()));
    }

// ----------------------------------------------------------------------------------------

    template <typename M, typename cache_element_type>
    struct op_rowm_symm_cache
    {
        typedef cache_element_type type;

        op_rowm_symm_cache(
            const M& m_,
            const type* data_,
            long* ref_count_
        ) :
            m(m_),
            data(data_),
            ref_count(ref_count_)
        {
            *ref_count += 1;
        }

        op_rowm_symm_cache (
            const op_rowm_symm_cache& item
        ) :
            m(item.m),
            data(item.data),
            ref_count(item.ref_count)
        {
            *ref_count += 1;
        }

        ~op_rowm_symm_cache(
        )
        {
            *ref_count -= 1;
        }

        const M& m;

        const type* const data;
        long* const ref_count;

        const static long cost = M::cost;
        const static long NR = 1;
        const static long NC = M::NC;
        typedef const type& const_ret_type;
        typedef typename M::mem_manager_type mem_manager_type;
        typedef typename M::layout_type layout_type;
        inline const_ret_type apply ( long , long c) const { return data[c]; }

        long nr () const { return 1; }
        long nc () const { return m.nc(); }

        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }
    };

    template <
        typename EXP,
        typename cache_element_type
        >
    inline const matrix_op<op_rowm_symm_cache<EXP,cache_element_type> > rowm (
        const matrix_exp<matrix_op<op_symm_cache<EXP,cache_element_type> > >& m,
        long row
    )
    {
        DLIB_ASSERT(row >= 0 && row < m.nr(),
            "\tconst matrix_exp rowm(const matrix_exp& m, row)"
            << "\n\tYou have specified invalid sub matrix dimensions"
            << "\n\tm.nr(): " << m.nr()
            << "\n\tm.nc(): " << m.nc()
            << "\n\trow:    " << row
            );

        std::pair<const cache_element_type*,long*> p = m.ref().op.col(row);

        typedef op_rowm_symm_cache<EXP,cache_element_type> op;
        return matrix_op<op>(op(m.ref().op.m,
                                p.first,
                                p.second));
    }

// ----------------------------------------------------------------------------------------

    template <typename EXP, typename cache_element_type>
    struct colm_exp<matrix_op<op_symm_cache<EXP, cache_element_type> > >
    {
        typedef matrix_op<op_colm_symm_cache<EXP, cache_element_type> > type;
    };

    template <typename EXP, typename cache_element_type>
    struct rowm_exp<matrix_op<op_symm_cache<EXP, cache_element_type> > >
    {
        typedef matrix_op<op_rowm_symm_cache<EXP, cache_element_type> > type;
    };

    template <typename EXP, typename cache_element_type>
    struct diag_exp<matrix_op<op_symm_cache<EXP, cache_element_type> > >
    {
        typedef matrix_op<op_colm_symm_cache<EXP, cache_element_type> > type;
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SYMMETRIC_MATRIX_CAcHE_Hh_


dlib C++ Library - fortran_id.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_BOOST_NUMERIC_BINDINGS_TRAITS_FORTRAN_H
#define DLIB_BOOST_NUMERIC_BINDINGS_TRAITS_FORTRAN_H

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//       FORTRAN BINDING STUFF FROM BOOST
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

//  Permission to copy, use, modify, sell and
//  distribute this software is granted provided this copyright notice appears
//  in all copies. This software is provided "as is" without express or implied
//  warranty, and with no claim as to its suitability for any purpose.
//  Copyright (C) 2002, 2003 Si-Lab b.v.b.a., Toon Knapen and Kresimir Fresl

// First we need to know what the conventions for linking
// C with Fortran is on this platform/toolset
#if defined(__GNUC__) || defined(__ICC) || defined(__sgi) || defined(__COMO__) || defined(__KCC)
#define DLIB_BIND_FORTRAN_LOWERCASE_UNDERSCORE
#elif defined(__IBMCPP__) || defined(_MSC_VER) || defined(__BORLANDC__)
#define DLIB_BIND_FORTRAN_LOWERCASE
#else
#error do not know how to link with fortran for the given platform
#endif

// Next we define macros to convert our symbols to
// the current convention
#if defined(DLIB_BIND_FORTRAN_LOWERCASE_UNDERSCORE)
#define DLIB_FORTRAN_ID( id ) id##_
#elif defined(DLIB_BIND_FORTRAN_LOWERCASE)
#define DLIB_FORTRAN_ID( id ) id
#else
#error do not know how to bind to fortran calling convention
#endif

namespace dlib
{
    namespace lapack
    {
            // stuff from f2c used to define what exactly is an integer in fortran
#if defined(__alpha__) || defined(__sparc64__) || defined(__x86_64__) || defined(__ia64__)
            typedef int integer;
            typedef unsigned int uinteger;
#else
            typedef long int integer;
            typedef unsigned long int uinteger;
#endif

    }
}

#endif // DLIB_BOOST_NUMERIC_BINDINGS_TRAITS_FORTRAN_H


dlib C++ Library - geev.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_LAPACk_GEEV_Hh_
#define DLIB_LAPACk_GEEV_Hh_

#include "fortran_id.h"
#include "../matrix.h"

namespace dlib
{
    namespace lapack
    {
        namespace binding
        {
            extern "C"
            {
                void DLIB_FORTRAN_ID(dgeev) (char *jobvl, char *jobvr, integer *n, double * a,
                                             integer *lda, double *wr, double *wi, double *vl,
                                             integer *ldvl, double *vr, integer *ldvr, double *work,
                                             integer *lwork, integer *info);

                void DLIB_FORTRAN_ID(sgeev) (char *jobvl, char *jobvr, integer *n, float * a,
                                             integer *lda, float *wr, float *wi, float *vl,
                                             integer *ldvl, float *vr, integer *ldvr, float *work,
                                             integer *lwork, integer *info);

            }

            inline int geev (char jobvl, char jobvr, integer n, double *a,
                             integer lda, double *wr, double *wi, double *vl,
                             integer ldvl, double *vr, integer ldvr, double *work,
                             integer lwork)
            {
                integer info = 0;
                DLIB_FORTRAN_ID(dgeev)(&jobvl, &jobvr, &n, a,
                                       &lda, wr, wi, vl,
                                       &ldvl, vr, &ldvr, work,
                                       &lwork, &info);
                return info;
            }

            inline int geev (char jobvl, char jobvr, integer n, float *a,
                             integer lda, float *wr, float *wi, float *vl,
                             integer ldvl, float *vr, integer ldvr, float *work,
                             integer lwork)
            {
                integer info = 0;
                DLIB_FORTRAN_ID(sgeev)(&jobvl, &jobvr, &n, a,
                                       &lda, wr, wi, vl,
                                       &ldvl, vr, &ldvr, work,
                                       &lwork, &info);
                return info;
            }

        }

    // ------------------------------------------------------------------------------------

/*  -- LAPACK driver routine (version 3.1) -- */
/*     Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */
/*     November 2006 */

/*     .. Scalar Arguments .. */
/*     .. */
/*     .. Array Arguments .. */
/*     .. */

/*  Purpose */
/*  ======= */

/*  DGEEV computes for an N-by-N real nonsymmetric matrix A, the */
/*  eigenvalues and, optionally, the left and/or right eigenvectors. */

/*  The right eigenvector v(j) of A satisfies */
/*                   A * v(j) = lambda(j) * v(j) */
/*  where lambda(j) is its eigenvalue. */
/*  The left eigenvector u(j) of A satisfies */
/*                u(j)**H * A = lambda(j) * u(j)**H */
/*  where u(j)**H denotes the conjugate transpose of u(j). */

/*  The computed eigenvectors are normalized to have Euclidean norm */
/*  equal to 1 and largest component real. */

/*  Arguments */
/*  ========= */

/*  JOBVL   (input) CHARACTER*1 */
/*          = 'N': left eigenvectors of A are not computed; */
/*          = 'V': left eigenvectors of A are computed. */

/*  JOBVR   (input) CHARACTER*1 */
/*          = 'N': right eigenvectors of A are not computed; */
/*          = 'V': right eigenvectors of A are computed. */

/*  N       (input) INTEGER */
/*          The order of the matrix A. N >= 0. */

/*  A       (input/output) DOUBLE PRECISION array, dimension (LDA,N) */
/*          On entry, the N-by-N matrix A. */
/*          On exit, A has been overwritten. */

/*  LDA     (input) INTEGER */
/*          The leading dimension of the array A.  LDA >= max(1,N). */

/*  WR      (output) DOUBLE PRECISION array, dimension (N) */
/*  WI      (output) DOUBLE PRECISION array, dimension (N) */
/*          WR and WI contain the real and imaginary parts, */
/*          respectively, of the computed eigenvalues.  Complex */
/*          conjugate pairs of eigenvalues appear consecutively */
/*          with the eigenvalue having the positive imaginary part */
/*          first. */

/*  VL      (output) DOUBLE PRECISION array, dimension (LDVL,N) */
/*          If JOBVL = 'V', the left eigenvectors u(j) are stored one */
/*          after another in the columns of VL, in the same order */
/*          as their eigenvalues. */
/*          If JOBVL = 'N', VL is not referenced. */
/*          If the j-th eigenvalue is real, then u(j) = VL(:,j), */
/*          the j-th column of VL. */
/*          If the j-th and (j+1)-st eigenvalues form a complex */
/*          conjugate pair, then u(j) = VL(:,j) + i*VL(:,j+1) and */
/*          u(j+1) = VL(:,j) - i*VL(:,j+1). */

/*  LDVL    (input) INTEGER */
/*          The leading dimension of the array VL.  LDVL >= 1; if */
/*          JOBVL = 'V', LDVL >= N. */

/*  VR      (output) DOUBLE PRECISION array, dimension (LDVR,N) */
/*          If JOBVR = 'V', the right eigenvectors v(j) are stored one */
/*          after another in the columns of VR, in the same order */
/*          as their eigenvalues. */
/*          If JOBVR = 'N', VR is not referenced. */
/*          If the j-th eigenvalue is real, then v(j) = VR(:,j), */
/*          the j-th column of VR. */
/*          If the j-th and (j+1)-st eigenvalues form a complex */
/*          conjugate pair, then v(j) = VR(:,j) + i*VR(:,j+1) and */
/*          v(j+1) = VR(:,j) - i*VR(:,j+1). */

/*  LDVR    (input) INTEGER */
/*          The leading dimension of the array VR.  LDVR >= 1; if */
/*          JOBVR = 'V', LDVR >= N. */

/*  WORK    (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) */
/*          On exit, if INFO = 0, WORK(1) returns the optimal LWORK. */

/*  LWORK   (input) INTEGER */
/*          The dimension of the array WORK.  LWORK >= max(1,3*N), and */
/*          if JOBVL = 'V' or JOBVR = 'V', LWORK >= 4*N.  For good */
/*          performance, LWORK must generally be larger. */

/*          If LWORK = -1, then a workspace query is assumed; the routine */
/*          only calculates the optimal size of the WORK array, returns */
/*          this value as the first entry of the WORK array, and no error */
/*          message related to LWORK is issued by XERBLA. */

/*  INFO    (output) INTEGER */
/*          = 0:  successful exit */
/*          < 0:  if INFO = -i, the i-th argument had an illegal value. */
/*          > 0:  if INFO = i, the QR algorithm failed to compute all the */
/*                eigenvalues, and no eigenvectors have been computed; */
/*                elements i+1:N of WR and WI contain eigenvalues which */
/*                have converged. */

    // ------------------------------------------------------------------------------------

        template <
            typename T,
            long NR1, long NR2, long NR3, long NR4, long NR5,
            long NC1, long NC2, long NC3, long NC4, long NC5,
            typename MM,
            typename layout
            >
        int geev (
            const char jobvl,
            const char jobvr,
            matrix<T,NR1,NC1,MM,column_major_layout>& a,
            matrix<T,NR2,NC2,MM,layout>& wr,
            matrix<T,NR3,NC3,MM,layout>& wi,
            matrix<T,NR4,NC4,MM,column_major_layout>& vl,
            matrix<T,NR5,NC5,MM,column_major_layout>& vr
        )
        {
            matrix<T,0,1,MM,column_major_layout> work;

            const long n = a.nr();

            wr.set_size(n,1);
            wi.set_size(n,1);

            if (jobvl == 'V')
                vl.set_size(n,n);
            else
                vl.set_size(NR4?NR4:1, NC4?NC4:1);

            if (jobvr == 'V')
                vr.set_size(n,n);
            else
                vr.set_size(NR5?NR5:1, NC5?NC5:1);

            // figure out how big the workspace needs to be.
            T work_size = 1;
            int info = binding::geev(jobvl, jobvr, n, &a(0,0),
                                     a.nr(), &wr(0,0), &wi(0,0), &vl(0,0),
                                     vl.nr(), &vr(0,0), vr.nr(), &work_size,
                                     -1);

            if (info != 0)
                return info;

            if (work.size() < work_size)
                work.set_size(static_cast<long>(work_size), 1);

            // compute the actual decomposition
            info = binding::geev(jobvl, jobvr, n, &a(0,0),
                                 a.nr(), &wr(0,0), &wi(0,0), &vl(0,0),
                                 vl.nr(), &vr(0,0), vr.nr(), &work(0,0),
                                 work.size());

            return info;
        }

    // ------------------------------------------------------------------------------------

    }

}

// ----------------------------------------------------------------------------------------

#endif // DLIB_LAPACk_GEEV_Hh_


dlib C++ Library - geqrf.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_LAPACk_GEQRF_Hh_
#define DLIB_LAPACk_GEQRF_Hh_

#include "fortran_id.h"
#include "../matrix.h"

namespace dlib
{
    namespace lapack
    {
        namespace binding
        {
            extern "C"
            {
                void DLIB_FORTRAN_ID(dgeqrf) (integer *m, integer *n, double *a, integer *
                                              lda, double *tau, double *work, integer *lwork,
                                              integer *info);

                void DLIB_FORTRAN_ID(sgeqrf) (integer *m, integer *n, float *a, integer *
                                              lda, float *tau, float *work, integer *lwork,
                                              integer *info);
            }

            inline int geqrf (integer m, integer n, double *a, integer lda,
                              double *tau, double *work, integer lwork)
            {
                integer info = 0;
                DLIB_FORTRAN_ID(dgeqrf)(&m, &n, a, &lda,
                                        tau, work, &lwork, &info);
                return info;
            }

            inline int geqrf (integer m, integer n, float *a, integer lda,
                              float *tau, float *work, integer lwork)
            {
                integer info = 0;
                DLIB_FORTRAN_ID(sgeqrf)(&m, &n, a, &lda,
                                        tau, work, &lwork, &info);
                return info;
            }

        }

    // ------------------------------------------------------------------------------------

/*  -- LAPACK routine (version 3.1) -- */
/*     Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */
/*     November 2006 */

/*     .. Scalar Arguments .. */
/*     .. */
/*     .. Array Arguments .. */
/*     .. */

/*  Purpose */
/*  ======= */

/*  DGEQRF computes a QR factorization of a real M-by-N matrix A: */
/*  A = Q * R. */

/*  Arguments */
/*  ========= */

/*  M       (input) INTEGER */
/*          The number of rows of the matrix A.  M >= 0. */

/*  N       (input) INTEGER */
/*          The number of columns of the matrix A.  N >= 0. */

/*  A       (input/output) DOUBLE PRECISION array, dimension (LDA,N) */
/*          On entry, the M-by-N matrix A. */
/*          On exit, the elements on and above the diagonal of the array */
/*          contain the min(M,N)-by-N upper trapezoidal matrix R (R is */
/*          upper triangular if m >= n); the elements below the diagonal, */
/*          with the array TAU, represent the orthogonal matrix Q as a */
/*          product of min(m,n) elementary reflectors (see Further */
/*          Details). */

/*  LDA     (input) INTEGER */
/*          The leading dimension of the array A.  LDA >= max(1,M). */

/*  TAU     (output) DOUBLE PRECISION array, dimension (min(M,N)) */
/*          The scalar factors of the elementary reflectors (see Further */
/*          Details). */

/*  WORK    (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) */
/*          On exit, if INFO = 0, WORK(1) returns the optimal LWORK. */

/*  LWORK   (input) INTEGER */
/*          The dimension of the array WORK.  LWORK >= max(1,N). */
/*          For optimum performance LWORK >= N*NB, where NB is */
/*          the optimal blocksize. */

/*          If LWORK = -1, then a workspace query is assumed; the routine */
/*          only calculates the optimal size of the WORK array, returns */
/*          this value as the first entry of the WORK array, and no error */
/*          message related to LWORK is issued by XERBLA. */

/*  INFO    (output) INTEGER */
/*          = 0:  successful exit */
/*          < 0:  if INFO = -i, the i-th argument had an illegal value */

/*  Further Details */
/*  =============== */

/*  The matrix Q is represented as a product of elementary reflectors */

/*     Q = H(1) H(2) . . . H(k), where k = min(m,n). */

/*  Each H(i) has the form */

/*     H(i) = I - tau * v * v' */

/*  where tau is a real scalar, and v is a real vector with */
/*  v(1:i-1) = 0 and v(i) = 1; v(i+1:m) is stored on exit in A(i+1:m,i), */
/*  and tau in TAU(i). */

    // ------------------------------------------------------------------------------------

        template <
            typename T,
            long NR1, long NR2,
            long NC1, long NC2,
            typename MM
            >
        int geqrf (
            matrix<T,NR1,NC1,MM,column_major_layout>& a,
            matrix<T,NR2,NC2,MM,column_major_layout>& tau
        )
        {
            matrix<T,0,1,MM,column_major_layout> work;

            tau.set_size(std::min(a.nr(), a.nc()), 1);

            // figure out how big the workspace needs to be.
            T work_size = 1;
            int info = binding::geqrf(a.nr(), a.nc(), &a(0,0), a.nr(),
                                      &tau(0,0), &work_size, -1);

            if (info != 0)
                return info;

            if (work.size() < work_size)
                work.set_size(static_cast<long>(work_size), 1);

            // compute the actual decomposition
            info = binding::geqrf(a.nr(), a.nc(), &a(0,0), a.nr(),
                                  &tau(0,0), &work(0,0), work.size());

            return info;
        }

    // ------------------------------------------------------------------------------------

    }

}

// ----------------------------------------------------------------------------------------

#endif // DLIB_LAPACk_GEQRF_Hh_


dlib C++ Library - gesdd.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_LAPACk_SDD_Hh_
#define DLIB_LAPACk_SDD_Hh_

#include "fortran_id.h"
#include "../matrix.h"

namespace dlib
{
    namespace lapack
    {
        namespace binding
        {
            extern "C"
            {
                void DLIB_FORTRAN_ID(dgesdd) (char const* jobz,
                                              const integer* m, const integer* n, double* a, const integer* lda,
                                              double* s, double* u, const integer* ldu,
                                              double* vt, const integer* ldvt,
                                              double* work, const integer* lwork, integer* iwork, integer* info);

                void DLIB_FORTRAN_ID(sgesdd) (char const* jobz,
                                              const integer* m, const integer* n, float* a, const integer* lda,
                                              float* s, float* u, const integer* ldu,
                                              float* vt, const integer* ldvt,
                                              float* work, const integer* lwork, integer* iwork, integer* info);

            }

            inline integer gesdd (const char jobz,
                              const integer m, const integer n, double* a, const integer lda,
                              double* s, double* u, const integer ldu,
                              double* vt, const integer ldvt,
                              double* work, const integer lwork, integer* iwork)
            {
                integer info = 0;
                DLIB_FORTRAN_ID(dgesdd)(&jobz, &m, &n, a, &lda, s, u, &ldu, vt, &ldvt, work, &lwork, iwork, &info);
                return info;
            }

            inline integer gesdd (const char jobz,
                              const integer m, const integer n, float* a, const integer lda,
                              float* s, float* u, const integer ldu,
                              float* vt, const integer ldvt,
                              float* work, const integer lwork, integer* iwork)
            {
                integer info = 0;
                DLIB_FORTRAN_ID(sgesdd)(&jobz, &m, &n, a, &lda, s, u, &ldu, vt, &ldvt, work, &lwork, iwork, &info);
                return info;
            }
        }

    // ------------------------------------------------------------------------------------

/*  -- LAPACK driver routine (version 3.1) -- */
/*     Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */
/*     November 2006 */

/*     .. Scalar Arguments .. */
/*     .. */
/*     .. Array Arguments .. */
/*     .. */

/*  Purpose */
/*  ======= */

/*  DGESDD computes the singular value decomposition (SVD) of a real */
/*  M-by-N matrix A, optionally computing the left and right singular */
/*  vectors.  If singular vectors are desired, it uses a */
/*  divide-and-conquer algorithm. */

/*  The SVD is written */

/*       A = U * SIGMA * transpose(V) */

/*  where SIGMA is an M-by-N matrix which is zero except for its */
/*  min(m,n) diagonal elements, U is an M-by-M orthogonal matrix, and */
/*  V is an N-by-N orthogonal matrix.  The diagonal elements of SIGMA */
/*  are the singular values of A; they are real and non-negative, and */
/*  are returned in descending order.  The first min(m,n) columns of */
/*  U and V are the left and right singular vectors of A. */

/*  Note that the routine returns VT = V**T, not V. */

/*  The divide and conquer algorithm makes very mild assumptions about */
/*  floating point arithmetic. It will work on machines with a guard */
/*  digit in add/subtract, or on those binary machines without guard */
/*  digits which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or */
/*  Cray-2. It could conceivably fail on hexadecimal or decimal machines */
/*  without guard digits, but we know of none. */

/*  Arguments */
/*  ========= */

/*  JOBZ    (input) CHARACTER*1 */
/*          Specifies options for computing all or part of the matrix U: */
/*          = 'A':  all M columns of U and all N rows of V**T are */
/*                  returned in the arrays U and VT; */
/*          = 'S':  the first min(M,N) columns of U and the first */
/*                  min(M,N) rows of V**T are returned in the arrays U */
/*                  and VT; */
/*          = 'O':  If M >= N, the first N columns of U are overwritten */
/*                  on the array A and all rows of V**T are returned in */
/*                  the array VT; */
/*                  otherwise, all columns of U are returned in the */
/*                  array U and the first M rows of V**T are overwritten */
/*                  in the array A; */
/*          = 'N':  no columns of U or rows of V**T are computed. */

/*  M       (input) INTEGER */
/*          The number of rows of the input matrix A.  M >= 0. */

/*  N       (input) INTEGER */
/*          The number of columns of the input matrix A.  N >= 0. */

/*  A       (input/output) DOUBLE PRECISION array, dimension (LDA,N) */
/*          On entry, the M-by-N matrix A. */
/*          On exit, */
/*          if JOBZ = 'O',  A is overwritten with the first N columns */
/*                          of U (the left singular vectors, stored */
/*                          columnwise) if M >= N; */
/*                          A is overwritten with the first M rows */
/*                          of V**T (the right singular vectors, stored */
/*                          rowwise) otherwise. */
/*          if JOBZ .ne. 'O', the contents of A are destroyed. */

/*  LDA     (input) INTEGER */
/*          The leading dimension of the array A.  LDA >= max(1,M). */

/*  S       (output) DOUBLE PRECISION array, dimension (min(M,N)) */
/*          The singular values of A, sorted so that S(i) >= S(i+1). */

/*  U       (output) DOUBLE PRECISION array, dimension (LDU,UCOL) */
/*          UCOL = M if JOBZ = 'A' or JOBZ = 'O' and M < N; */
/*          UCOL = min(M,N) if JOBZ = 'S'. */
/*          If JOBZ = 'A' or JOBZ = 'O' and M < N, U contains the M-by-M */
/*          orthogonal matrix U; */
/*          if JOBZ = 'S', U contains the first min(M,N) columns of U */
/*          (the left singular vectors, stored columnwise); */
/*          if JOBZ = 'O' and M >= N, or JOBZ = 'N', U is not referenced. */

/*  LDU     (input) INTEGER */
/*          The leading dimension of the array U.  LDU >= 1; if */
/*          JOBZ = 'S' or 'A' or JOBZ = 'O' and M < N, LDU >= M. */

/*  VT      (output) DOUBLE PRECISION array, dimension (LDVT,N) */
/*          If JOBZ = 'A' or JOBZ = 'O' and M >= N, VT contains the */
/*          N-by-N orthogonal matrix V**T; */
/*          if JOBZ = 'S', VT contains the first min(M,N) rows of */
/*          V**T (the right singular vectors, stored rowwise); */
/*          if JOBZ = 'O' and M < N, or JOBZ = 'N', VT is not referenced. */

/*  LDVT    (input) INTEGER */
/*          The leading dimension of the array VT.  LDVT >= 1; if */
/*          JOBZ = 'A' or JOBZ = 'O' and M >= N, LDVT >= N; */
/*          if JOBZ = 'S', LDVT >= min(M,N). */

/*  WORK    (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) */
/*          On exit, if INFO = 0, WORK(1) returns the optimal LWORK; */

/*  LWORK   (input) INTEGER */
/*          The dimension of the array WORK. LWORK >= 1. */
/*          If JOBZ = 'N', */
/*            LWORK >= 3*min(M,N) + max(max(M,N),7*min(M,N)). */
/*          If JOBZ = 'O', */
/*            LWORK >= 3*min(M,N)*min(M,N) + */
/*                     max(max(M,N),5*min(M,N)*min(M,N)+4*min(M,N)). */
/*          If JOBZ = 'S' or 'A' */
/*            LWORK >= 3*min(M,N)*min(M,N) + */
/*                     max(max(M,N),4*min(M,N)*min(M,N)+4*min(M,N)). */
/*          For good performance, LWORK should generally be larger. */
/*          If LWORK = -1 but other input arguments are legal, WORK(1) */
/*          returns the optimal LWORK. */

/*  IWORK   (workspace) INTEGER array, dimension (8*min(M,N)) */

/*  INFO    (output) INTEGER */
/*          = 0:  successful exit. */
/*          < 0:  if INFO = -i, the i-th argument had an illegal value. */
/*          > 0:  DBDSDC did not converge, updating process failed. */

/*  Further Details */
/*  =============== */

/*  Based on contributions by */
/*     Ming Gu and Huan Ren, Computer Science Division, University of */
/*     California at Berkeley, USA */

    // ------------------------------------------------------------------------------------

        template <
            typename T,
            long NR1, long NR2, long NR3, long NR4,
            long NC1, long NC2, long NC3, long NC4,
            typename MM
            >
        int gesdd (
            const char jobz,
            matrix<T,NR1,NC1,MM,column_major_layout>& a,
            matrix<T,NR2,NC2,MM,column_major_layout>& s,
            matrix<T,NR3,NC3,MM,column_major_layout>& u,
            matrix<T,NR4,NC4,MM,column_major_layout>& vt
        )
        {
            matrix<T,0,1,MM,column_major_layout> work;
            matrix<integer,0,1,MM,column_major_layout> iwork;

            const long m = a.nr();
            const long n = a.nc();
            s.set_size(std::min(m,n), 1);

            // make sure the iwork memory block is big enough
            if (iwork.size() < 8*std::min(m,n))
                iwork.set_size(8*std::min(m,n), 1);

            if (jobz == 'A')
            {
                u.set_size(m,m);
                vt.set_size(n,n);
            }
            else if (jobz == 'S')
            {
                u.set_size(m, std::min(m,n));
                vt.set_size(std::min(m,n), n);
            }
            else if (jobz == 'O')
            {
                DLIB_CASSERT(false, "jobz == 'O' not supported");
            }
            else
            {
                u.set_size(NR3?NR3:1, NC3?NC3:1);
                vt.set_size(NR4?NR4:1, NC4?NC4:1);
            }

            // figure out how big the workspace needs to be.
            T work_size = 1;
            int info = binding::gesdd(jobz, a.nr(), a.nc(), &a(0,0), a.nr(),
                                      &s(0,0), &u(0,0), u.nr(), &vt(0,0), vt.nr(),
                                      &work_size, -1, &iwork(0,0));

            if (info != 0)
                return info;

            // There is a bug in an older version of LAPACK in Debian etch
            // that causes the gesdd to return the wrong value for work_size
            // when jobz == 'N'.  So verify the value of work_size.
            if (jobz == 'N')
            {
                using std::min;
                using std::max;
                const T min_work_size = 3*min(m,n) + max(max(m,n),7*min(m,n));
                if (work_size < min_work_size)
                    work_size = min_work_size;
            }

            if (work.size() < work_size)
                work.set_size(static_cast<long>(work_size), 1);

            // compute the actual SVD
            info = binding::gesdd(jobz, a.nr(), a.nc(), &a(0,0), a.nr(),
                                  &s(0,0), &u(0,0), u.nr(), &vt(0,0), vt.nr(),
                                  &work(0,0), work.size(), &iwork(0,0));

            return info;
        }

    // ------------------------------------------------------------------------------------

        template <
            typename T,
            long NR1, long NR2, long NR3, long NR4,
            long NC1, long NC2, long NC3, long NC4,
            typename MM
            >
        int gesdd (
            const char jobz,
            matrix<T,NR1,NC1,MM,row_major_layout>& a,
            matrix<T,NR2,NC2,MM,row_major_layout>& s,
            matrix<T,NR3,NC3,MM,row_major_layout>& u_,
            matrix<T,NR4,NC4,MM,row_major_layout>& vt_
        )
        {
            matrix<T,0,1,MM,row_major_layout> work;
            matrix<integer,0,1,MM,row_major_layout> iwork;

            // Row major order matrices are transposed from LAPACK's point of view.
            matrix<T,NR4,NC4,MM,row_major_layout>& u = vt_;
            matrix<T,NR3,NC3,MM,row_major_layout>& vt = u_;

            const long m = a.nc();
            const long n = a.nr();
            s.set_size(std::min(m,n), 1);

            // make sure the iwork memory block is big enough
            if (iwork.size() < 8*std::min(m,n))
                iwork.set_size(8*std::min(m,n), 1);

            if (jobz == 'A')
            {
                u.set_size(m,m);
                vt.set_size(n,n);
            }
            else if (jobz == 'S')
            {
                u.set_size(std::min(m,n), m);
                vt.set_size(n, std::min(m,n));
            }
            else if (jobz == 'O')
            {
                DLIB_CASSERT(false, "jobz == 'O' not supported");
            }
            else
            {
                u.set_size(NR4?NR4:1, NC4?NC4:1);
                vt.set_size(NR3?NR3:1, NC3?NC3:1);
            }

            // figure out how big the workspace needs to be.
            T work_size = 1;
            int info = binding::gesdd(jobz, m, n, &a(0,0), a.nc(),
                                      &s(0,0), &u(0,0), u.nc(), &vt(0,0), vt.nc(),
                                      &work_size, -1, &iwork(0,0));

            if (info != 0)
                return info;

            // There is a bug in an older version of LAPACK in Debian etch
            // that causes the gesdd to return the wrong value for work_size
            // when jobz == 'N'.  So verify the value of work_size.
            if (jobz == 'N')
            {
                using std::min;
                using std::max;
                const T min_work_size = 3*min(m,n) + max(max(m,n),7*min(m,n));
                if (work_size < min_work_size)
                    work_size = min_work_size;
            }

            if (work.size() < work_size)
                work.set_size(static_cast<long>(work_size), 1);

            // compute the actual SVD
            info = binding::gesdd(jobz, m, n, &a(0,0), a.nc(),
                                  &s(0,0), &u(0,0), u.nc(), &vt(0,0), vt.nc(),
                                  &work(0,0), work.size(), &iwork(0,0));

            return info;
        }

    // ------------------------------------------------------------------------------------

    }

}

// ----------------------------------------------------------------------------------------

#endif // DLIB_LAPACk_SDD_Hh_


dlib C++ Library - gesvd.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_LAPACk_SVD_Hh_
#define DLIB_LAPACk_SVD_Hh_

#include "fortran_id.h"
#include "../matrix.h"

namespace dlib
{
    namespace lapack
    {
        namespace binding
        {
            extern "C"
            {
                void DLIB_FORTRAN_ID(dgesvd) (const char* jobu, const char* jobvt,
                                              const integer* m, const integer* n, double* a, const integer* lda,
                                              double* s, double* u, const integer* ldu,
                                              double* vt, const integer* ldvt,
                                              double* work, const integer* lwork, integer* info);

                void DLIB_FORTRAN_ID(sgesvd) (const char* jobu, const char* jobvt,
                                              const integer* m, const integer* n, float* a, const integer* lda,
                                              float* s, float* u, const integer* ldu,
                                              float* vt, const integer* ldvt,
                                              float* work, const integer* lwork, integer* info);

            }

            inline integer gesvd (const char jobu, const char jobvt,
                              const integer m, const integer n, double* a, const integer lda,
                              double* s, double* u, const integer ldu,
                              double* vt, const integer ldvt,
                              double* work, const integer lwork)
            {
                integer info = 0;
                DLIB_FORTRAN_ID(dgesvd)(&jobu, &jobvt, &m, &n, a, &lda, s, u, &ldu, vt, &ldvt, work, &lwork, &info);
                return info;
            }

            inline integer gesvd (const char jobu, const char jobvt,
                              const integer m, const integer n, float* a, const integer lda,
                              float* s, float* u, const integer ldu,
                              float* vt, const integer ldvt,
                              float* work, const integer lwork)
            {
                integer info = 0;
                DLIB_FORTRAN_ID(sgesvd)(&jobu, &jobvt, &m, &n, a, &lda, s, u, &ldu, vt, &ldvt, work, &lwork, &info);
                return info;
            }

        }

    // ------------------------------------------------------------------------------------

/*  -- LAPACK driver routine (version 3.1) -- */
/*     Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */
/*     November 2006 */

/*     .. Scalar Arguments .. */
/*     .. */
/*     .. Array Arguments .. */
/*     .. */

/*  Purpose */
/*  ======= */

/*  DGESVD computes the singular value decomposition (SVD) of a real */
/*  M-by-N matrix A, optionally computing the left and/or right singular */
/*  vectors. The SVD is written */

/*       A = U * SIGMA * transpose(V) */

/*  where SIGMA is an M-by-N matrix which is zero except for its */
/*  min(m,n) diagonal elements, U is an M-by-M orthogonal matrix, and */
/*  V is an N-by-N orthogonal matrix.  The diagonal elements of SIGMA */
/*  are the singular values of A; they are real and non-negative, and */
/*  are returned in descending order.  The first min(m,n) columns of */
/*  U and V are the left and right singular vectors of A. */

/*  Note that the routine returns V**T, not V. */

/*  Arguments */
/*  ========= */

/*  JOBU    (input) CHARACTER*1 */
/*          Specifies options for computing all or part of the matrix U: */
/*          = 'A':  all M columns of U are returned in array U: */
/*          = 'S':  the first min(m,n) columns of U (the left singular */
/*                  vectors) are returned in the array U; */
/*          = 'O':  the first min(m,n) columns of U (the left singular */
/*                  vectors) are overwritten on the array A; */
/*          = 'N':  no columns of U (no left singular vectors) are */
/*                  computed. */

/*  JOBVT   (input) CHARACTER*1 */
/*          Specifies options for computing all or part of the matrix */
/*          V**T: */
/*          = 'A':  all N rows of V**T are returned in the array VT; */
/*          = 'S':  the first min(m,n) rows of V**T (the right singular */
/*                  vectors) are returned in the array VT; */
/*          = 'O':  the first min(m,n) rows of V**T (the right singular */
/*                  vectors) are overwritten on the array A; */
/*          = 'N':  no rows of V**T (no right singular vectors) are */
/*                  computed. */

/*          JOBVT and JOBU cannot both be 'O'. */

/*  M       (input) INTEGER */
/*          The number of rows of the input matrix A.  M >= 0. */

/*  N       (input) INTEGER */
/*          The number of columns of the input matrix A.  N >= 0. */

/*  A       (input/output) DOUBLE PRECISION array, dimension (LDA,N) */
/*          On entry, the M-by-N matrix A. */
/*          On exit, */
/*          if JOBU = 'O',  A is overwritten with the first min(m,n) */
/*                          columns of U (the left singular vectors, */
/*                          stored columnwise); */
/*          if JOBVT = 'O', A is overwritten with the first min(m,n) */
/*                          rows of V**T (the right singular vectors, */
/*                          stored rowwise); */
/*          if JOBU .ne. 'O' and JOBVT .ne. 'O', the contents of A */
/*                          are destroyed. */

/*  LDA     (input) INTEGER */
/*          The leading dimension of the array A.  LDA >= max(1,M). */

/*  S       (output) DOUBLE PRECISION array, dimension (min(M,N)) */
/*          The singular values of A, sorted so that S(i) >= S(i+1). */

/*  U       (output) DOUBLE PRECISION array, dimension (LDU,UCOL) */
/*          (LDU,M) if JOBU = 'A' or (LDU,min(M,N)) if JOBU = 'S'. */
/*          If JOBU = 'A', U contains the M-by-M orthogonal matrix U; */
/*          if JOBU = 'S', U contains the first min(m,n) columns of U */
/*          (the left singular vectors, stored columnwise); */
/*          if JOBU = 'N' or 'O', U is not referenced. */

/*  LDU     (input) INTEGER */
/*          The leading dimension of the array U.  LDU >= 1; if */
/*          JOBU = 'S' or 'A', LDU >= M. */

/*  VT      (output) DOUBLE PRECISION array, dimension (LDVT,N) */
/*          If JOBVT = 'A', VT contains the N-by-N orthogonal matrix */
/*          V**T; */
/*          if JOBVT = 'S', VT contains the first min(m,n) rows of */
/*          V**T (the right singular vectors, stored rowwise); */
/*          if JOBVT = 'N' or 'O', VT is not referenced. */

/*  LDVT    (input) INTEGER */
/*          The leading dimension of the array VT.  LDVT >= 1; if */
/*          JOBVT = 'A', LDVT >= N; if JOBVT = 'S', LDVT >= min(M,N). */

/*  WORK    (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) */
/*          On exit, if INFO = 0, WORK(1) returns the optimal LWORK; */
/*          if INFO > 0, WORK(2:MIN(M,N)) contains the unconverged */
/*          superdiagonal elements of an upper bidiagonal matrix B */
/*          whose diagonal is in S (not necessarily sorted). B */
/*          satisfies A = U * B * VT, so it has the same singular values */
/*          as A, and singular vectors related by U and VT. */

/*  LWORK   (input) INTEGER */
/*          The dimension of the array WORK. */
/*          LWORK >= MAX(1,3*MIN(M,N)+MAX(M,N),5*MIN(M,N)). */
/*          For good performance, LWORK should generally be larger. */

/*          If LWORK = -1, then a workspace query is assumed; the routine */
/*          only calculates the optimal size of the WORK array, returns */
/*          this value as the first entry of the WORK array, and no error */
/*          message related to LWORK is issued by XERBLA. */

/*  INFO    (output) INTEGER */
/*          = 0:  successful exit. */
/*          < 0:  if INFO = -i, the i-th argument had an illegal value. */
/*          > 0:  if DBDSQR did not converge, INFO specifies how many */
/*                superdiagonals of an intermediate bidiagonal form B */
/*                did not converge to zero. See the description of WORK */
/*                above for details. */

    // ------------------------------------------------------------------------------------

        template <
            typename T,
            long NR1, long NR2, long NR3, long NR4,
            long NC1, long NC2, long NC3, long NC4,
            typename MM
            >
        int gesvd (
            const char jobu,
            const char jobvt,
            matrix<T,NR1,NC1,MM,column_major_layout>& a,
            matrix<T,NR2,NC2,MM,column_major_layout>& s,
            matrix<T,NR3,NC3,MM,column_major_layout>& u,
            matrix<T,NR4,NC4,MM,column_major_layout>& vt
        )
        {
            matrix<T,0,1,MM,column_major_layout> work;

            const long m = a.nr();
            const long n = a.nc();
            s.set_size(std::min(m,n), 1);

            if (jobu == 'A')
                u.set_size(m,m);
            else if (jobu == 'S')
                u.set_size(m, std::min(m,n));
            else
                u.set_size(NR3?NR3:1, NC3?NC3:1);

            if (jobvt == 'A')
                vt.set_size(n,n);
            else if (jobvt == 'S')
                vt.set_size(std::min(m,n), n);
            else
                vt.set_size(NR4?NR4:1, NC4?NC4:1);

            if (jobu == 'O' || jobvt == 'O')
            {
                DLIB_CASSERT(false, "job == 'O' not supported");
            }

            // figure out how big the workspace needs to be.
            T work_size = 1;
            int info = binding::gesvd(jobu, jobvt, a.nr(), a.nc(), &a(0,0), a.nr(),
                                      &s(0,0), &u(0,0), u.nr(), &vt(0,0), vt.nr(),
                                      &work_size, -1);

            if (info != 0)
                return info;

            if (work.size() < work_size)
                work.set_size(static_cast<long>(work_size), 1);

            // compute the actual SVD
            info = binding::gesvd(jobu, jobvt, a.nr(), a.nc(), &a(0,0), a.nr(),
                                  &s(0,0), &u(0,0), u.nr(), &vt(0,0), vt.nr(),
                                  &work(0,0), work.size());

            return info;
        }

    // ------------------------------------------------------------------------------------

        template <
            typename T,
            long NR1, long NR2, long NR3, long NR4,
            long NC1, long NC2, long NC3, long NC4,
            typename MM
            >
        int gesvd (
            char jobu,
            char jobvt,
            matrix<T,NR1,NC1,MM,row_major_layout>& a,
            matrix<T,NR2,NC2,MM,row_major_layout>& s,
            matrix<T,NR3,NC3,MM,row_major_layout>& u_,
            matrix<T,NR4,NC4,MM,row_major_layout>& vt_
        )
        {
            matrix<T,0,1,MM,row_major_layout> work;

            // Row major order matrices are transposed from LAPACK's point of view.
            matrix<T,NR4,NC4,MM,row_major_layout>& u = vt_;
            matrix<T,NR3,NC3,MM,row_major_layout>& vt = u_;
            std::swap(jobu, jobvt);

            const long m = a.nc();
            const long n = a.nr();
            s.set_size(std::min(m,n), 1);

            if (jobu == 'A')
                u.set_size(m,m);
            else if (jobu == 'S')
                u.set_size(std::min(m,n), m);
            else
                u.set_size(NR4?NR4:1, NC4?NC4:1);

            if (jobvt == 'A')
                vt.set_size(n,n);
            else if (jobvt == 'S')
                vt.set_size(n, std::min(m,n));
            else
                vt.set_size(NR3?NR3:1, NC3?NC3:1);

            if (jobu == 'O' || jobvt == 'O')
            {
                DLIB_CASSERT(false, "job == 'O' not supported");
            }

            // figure out how big the workspace needs to be.
            T work_size = 1;
            int info = binding::gesvd(jobu, jobvt, m, n, &a(0,0), a.nc(),
                                      &s(0,0), &u(0,0), u.nc(), &vt(0,0), vt.nc(),
                                      &work_size, -1);

            if (info != 0)
                return info;

            if (work.size() < work_size)
                work.set_size(static_cast<long>(work_size), 1);

            // compute the actual SVD
            info = binding::gesvd(jobu, jobvt, m, n, &a(0,0), a.nc(),
                                  &s(0,0), &u(0,0), u.nc(), &vt(0,0), vt.nc(),
                                  &work(0,0), work.size());

            return info;
        }

    // ------------------------------------------------------------------------------------

    }

}

// ----------------------------------------------------------------------------------------

#endif // DLIB_LAPACk_SVD_Hh_


dlib C++ Library - getrf.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_LAPACk_GETRF_Hh_
#define DLIB_LAPACk_GETRF_Hh_

#include "fortran_id.h"
#include "../matrix.h"

namespace dlib
{
    namespace lapack
    {
        namespace binding
        {
            extern "C"
            {
                void DLIB_FORTRAN_ID(dgetrf) (integer* m, integer *n, double *a,
                                             integer* lda, integer *ipiv, integer *info);

                void DLIB_FORTRAN_ID(sgetrf) (integer* m, integer *n, float *a,
                                             integer* lda, integer *ipiv, integer *info);

            }

            inline int getrf (integer m, integer n, double *a,
                              integer lda, integer *ipiv)
            {
                integer info = 0;
                DLIB_FORTRAN_ID(dgetrf)(&m, &n, a, &lda, ipiv, &info);
                return info;
            }

            inline int getrf (integer m, integer n, float *a,
                              integer lda, integer *ipiv)
            {
                integer info = 0;
                DLIB_FORTRAN_ID(sgetrf)(&m, &n, a, &lda, ipiv, &info);
                return info;
            }

        }

    // ------------------------------------------------------------------------------------

/*  -- LAPACK routine (version 3.1) -- */
/*     Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */
/*     November 2006 */

/*     .. Scalar Arguments .. */
/*     .. */
/*     .. Array Arguments .. */
/*     .. */

/*  Purpose */
/*  ======= */

/*  DGETRF computes an LU factorization of a general M-by-N matrix A */
/*  using partial pivoting with row interchanges. */

/*  The factorization has the form */
/*     A = P * L * U */
/*  where P is a permutation matrix, L is lower triangular with unit */
/*  diagonal elements (lower trapezoidal if m > n), and U is upper */
/*  triangular (upper trapezoidal if m < n). */

/*  This is the right-looking Level 3 BLAS version of the algorithm. */

/*  Arguments */
/*  ========= */

/*  M       (input) INTEGER */
/*          The number of rows of the matrix A.  M >= 0. */

/*  N       (input) INTEGER */
/*          The number of columns of the matrix A.  N >= 0. */

/*  A       (input/output) DOUBLE PRECISION array, dimension (LDA,N) */
/*          On entry, the M-by-N matrix to be factored. */
/*          On exit, the factors L and U from the factorization */
/*          A = P*L*U; the unit diagonal elements of L are not stored. */

/*  LDA     (input) INTEGER */
/*          The leading dimension of the array A.  LDA >= max(1,M). */

/*  IPIV    (output) INTEGER array, dimension (min(M,N)) */
/*          The pivot indices; for 1 <= i <= min(M,N), row i of the */
/*          matrix was interchanged with row IPIV(i). */

/*  INFO    (output) INTEGER */
/*          = 0:  successful exit */
/*          < 0:  if INFO = -i, the i-th argument had an illegal value */
/*          > 0:  if INFO = i, U(i,i) is exactly zero. The factorization */
/*                has been completed, but the factor U is exactly */
/*                singular, and division by zero will occur if it is used */
/*                to solve a system of equations. */

    // ------------------------------------------------------------------------------------

        template <
            typename T,
            long NR1, long NR2,
            long NC1, long NC2,
            typename MM,
            typename layout
            >
        int getrf (
            matrix<T,NR1,NC1,MM,column_major_layout>& a,
            matrix<integer,NR2,NC2,MM,layout>& ipiv
        )
        {
            const long m = a.nr();
            const long n = a.nc();

            ipiv.set_size(std::min(m,n), 1);

            // compute the actual decomposition
            return binding::getrf(m, n, &a(0,0), a.nr(), &ipiv(0,0));
        }

    // ------------------------------------------------------------------------------------

    }

}

// ----------------------------------------------------------------------------------------

#endif // DLIB_LAPACk_GETRF_Hh_


dlib C++ Library - ormqr.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_LAPACk_ORMQR_Hh_
#define DLIB_LAPACk_ORMQR_Hh_

#include "fortran_id.h"
#include "../matrix.h"

namespace dlib
{
    namespace lapack
    {
        namespace binding
        {
            extern "C"
            {
                void DLIB_FORTRAN_ID(dormqr) (char *side, char *trans, integer *m, integer *n,
                                              integer *k, const double *a, integer *lda, const double *tau,
                                              double * c_, integer *ldc, double *work, integer *lwork,
                                              integer *info);

                void DLIB_FORTRAN_ID(sormqr) (char *side, char *trans, integer *m, integer *n,
                                              integer *k, const float *a, integer *lda, const float *tau,
                                              float * c_, integer *ldc, float *work, integer *lwork,
                                              integer *info);

            }

            inline int ormqr (char side, char trans, integer m, integer n,
                              integer k, const double *a, integer lda, const double *tau,
                              double *c_, integer ldc, double *work, integer lwork)
            {
                integer info = 0;
                DLIB_FORTRAN_ID(dormqr)(&side, &trans, &m, &n,
                                        &k, a, &lda, tau,
                                        c_, &ldc, work, &lwork, &info);
                return info;
            }

            inline int ormqr (char side, char trans, integer m, integer n,
                              integer k, const float *a, integer lda, const float *tau,
                              float *c_, integer ldc, float *work, integer lwork)
            {
                integer info = 0;
                DLIB_FORTRAN_ID(sormqr)(&side, &trans, &m, &n,
                                        &k, a, &lda, tau,
                                        c_, &ldc, work, &lwork, &info);
                return info;
            }

        }

    // ------------------------------------------------------------------------------------

/*  -- LAPACK routine (version 3.1) -- */
/*     Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */
/*     November 2006 */

/*     .. Scalar Arguments .. */
/*     .. */
/*     .. Array Arguments .. */
/*     .. */

/*  Purpose */
/*  ======= */

/*  DORMQR overwrites the general real M-by-N matrix C with */

/*                  SIDE = 'L'     SIDE = 'R' */
/*  TRANS = 'N':      Q * C          C * Q */
/*  TRANS = 'T':      Q**T * C       C * Q**T */

/*  where Q is a real orthogonal matrix defined as the product of k */
/*  elementary reflectors */

/*        Q = H(1) H(2) . . . H(k) */

/*  as returned by DGEQRF. Q is of order M if SIDE = 'L' and of order N */
/*  if SIDE = 'R'. */

/*  Arguments */
/*  ========= */

/*  SIDE    (input) CHARACTER*1 */
/*          = 'L': apply Q or Q**T from the Left; */
/*          = 'R': apply Q or Q**T from the Right. */

/*  TRANS   (input) CHARACTER*1 */
/*          = 'N':  No transpose, apply Q; */
/*          = 'T':  Transpose, apply Q**T. */

/*  M       (input) INTEGER */
/*          The number of rows of the matrix C. M >= 0. */

/*  N       (input) INTEGER */
/*          The number of columns of the matrix C. N >= 0. */

/*  K       (input) INTEGER */
/*          The number of elementary reflectors whose product defines */
/*          the matrix Q. */
/*          If SIDE = 'L', M >= K >= 0; */
/*          if SIDE = 'R', N >= K >= 0. */

/*  A       (input) DOUBLE PRECISION array, dimension (LDA,K) */
/*          The i-th column must contain the vector which defines the */
/*          elementary reflector H(i), for i = 1,2,...,k, as returned by */
/*          DGEQRF in the first k columns of its array argument A. */
/*          A is modified by the routine but restored on exit. */

/*  LDA     (input) INTEGER */
/*          The leading dimension of the array A. */
/*          If SIDE = 'L', LDA >= max(1,M); */
/*          if SIDE = 'R', LDA >= max(1,N). */

/*  TAU     (input) DOUBLE PRECISION array, dimension (K) */
/*          TAU(i) must contain the scalar factor of the elementary */
/*          reflector H(i), as returned by DGEQRF. */

/*  C       (input/output) DOUBLE PRECISION array, dimension (LDC,N) */
/*          On entry, the M-by-N matrix C. */
/*          On exit, C is overwritten by Q*C or Q**T*C or C*Q**T or C*Q. */

/*  LDC     (input) INTEGER */
/*          The leading dimension of the array C. LDC >= max(1,M). */

/*  WORK    (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) */
/*          On exit, if INFO = 0, WORK(1) returns the optimal LWORK. */

/*  LWORK   (input) INTEGER */
/*          The dimension of the array WORK. */
/*          If SIDE = 'L', LWORK >= max(1,N); */
/*          if SIDE = 'R', LWORK >= max(1,M). */
/*          For optimum performance LWORK >= N*NB if SIDE = 'L', and */
/*          LWORK >= M*NB if SIDE = 'R', where NB is the optimal */
/*          blocksize. */

/*          If LWORK = -1, then a workspace query is assumed; the routine */
/*          only calculates the optimal size of the WORK array, returns */
/*          this value as the first entry of the WORK array, and no error */
/*          message related to LWORK is issued by XERBLA. */

/*  INFO    (output) INTEGER */
/*          = 0:  successful exit */
/*          < 0:  if INFO = -i, the i-th argument had an illegal value */

    // ------------------------------------------------------------------------------------

        template <
            typename T,
            long NR1, long NR2, long NR3,
            long NC1, long NC2, long NC3,
            typename MM,
            typename C_LAYOUT
            >
        int ormqr (
            char side,
            char trans,
            const matrix<T,NR1,NC1,MM,column_major_layout>& a,
            const matrix<T,NR2,NC2,MM,column_major_layout>& tau,
            matrix<T,NR3,NC3,MM,C_LAYOUT>& c
        )
        {
            long m = c.nr();
            long n = c.nc();
            const long k = a.nc();
            long ldc;
            if (is_same_type<C_LAYOUT,column_major_layout>::value)
            {
                ldc = c.nr();
            }
            else
            {
                // Since lapack expects c to be in column major layout we have to
                // do something to make this work.  Since a row major layout matrix
                // will look just like a transposed C we can just swap a few things around.

                ldc = c.nc();
                swap(m,n);

                if (side == 'L')
                    side = 'R';
                else
                    side = 'L';

                if (trans == 'T')
                    trans = 'N';
                else
                    trans = 'T';
            }

            matrix<T,0,1,MM,column_major_layout> work;

            // figure out how big the workspace needs to be.
            T work_size = 1;
            int info = binding::ormqr(side, trans, m, n,
                                      k, &a(0,0), a.nr(), &tau(0,0),
                                      &c(0,0), ldc, &work_size, -1);

            if (info != 0)
                return info;

            if (work.size() < work_size)
                work.set_size(static_cast<long>(work_size), 1);

            // compute the actual result
            info = binding::ormqr(side, trans, m, n,
                                  k, &a(0,0), a.nr(), &tau(0,0),
                                  &c(0,0), ldc, &work(0,0), work.size());

            return info;
        }

    // ------------------------------------------------------------------------------------

    }

}

// ----------------------------------------------------------------------------------------

#endif // DLIB_LAPACk_ORMQR_Hh_


dlib C++ Library - potrf.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_LAPACk_POTRF_Hh_
#define DLIB_LAPACk_POTRF_Hh_

#include "fortran_id.h"
#include "../matrix.h"

namespace dlib
{
    namespace lapack
    {
        namespace binding
        {
            extern "C"
            {
                void DLIB_FORTRAN_ID(dpotrf) (char *uplo, integer *n, double *a,
                                              integer* lda, integer *info);

                void DLIB_FORTRAN_ID(spotrf) (char *uplo, integer *n, float *a,
                                              integer* lda, integer *info);

            }

            inline int potrf (char uplo, integer n, double *a, integer lda)
            {
                integer info = 0;
                DLIB_FORTRAN_ID(dpotrf)(&uplo, &n, a, &lda, &info);
                return info;
            }

            inline int potrf (char uplo, integer n, float *a, integer lda)
            {
                integer info = 0;
                DLIB_FORTRAN_ID(spotrf)(&uplo, &n, a, &lda, &info);
                return info;
            }

        }

    // ------------------------------------------------------------------------------------

/*  -- LAPACK routine (version 3.1) -- */
/*     Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */
/*     November 2006 */

/*     .. Scalar Arguments .. */
/*     .. */
/*     .. Array Arguments .. */
/*     .. */

/*  Purpose */
/*  ======= */

/*  DPOTRF computes the Cholesky factorization of a real symmetric */
/*  positive definite matrix A. */

/*  The factorization has the form */
/*     A = U**T * U,  if UPLO = 'U', or */
/*     A = L  * L**T,  if UPLO = 'L', */
/*  where U is an upper triangular matrix and L is lower triangular. */

/*  This is the block version of the algorithm, calling Level 3 BLAS. */

/*  Arguments */
/*  ========= */

/*  UPLO    (input) CHARACTER*1 */
/*          = 'U':  Upper triangle of A is stored; */
/*          = 'L':  Lower triangle of A is stored. */

/*  N       (input) INTEGER */
/*          The order of the matrix A.  N >= 0. */

/*  A       (input/output) DOUBLE PRECISION array, dimension (LDA,N) */
/*          On entry, the symmetric matrix A.  If UPLO = 'U', the leading */
/*          N-by-N upper triangular part of A contains the upper */
/*          triangular part of the matrix A, and the strictly lower */
/*          triangular part of A is not referenced.  If UPLO = 'L', the */
/*          leading N-by-N lower triangular part of A contains the lower */
/*          triangular part of the matrix A, and the strictly upper */
/*          triangular part of A is not referenced. */

/*          On exit, if INFO = 0, the factor U or L from the Cholesky */
/*          factorization A = U**T*U or A = L*L**T. */

/*  LDA     (input) INTEGER */
/*          The leading dimension of the array A.  LDA >= max(1,N). */

/*  INFO    (output) INTEGER */
/*          = 0:  successful exit */
/*          < 0:  if INFO = -i, the i-th argument had an illegal value */
/*          > 0:  if INFO = i, the leading minor of order i is not */
/*                positive definite, and the factorization could not be */
/*                completed. */

    // ------------------------------------------------------------------------------------

        template <
            typename T,
            long NR1,
            long NC1,
            typename MM
            >
        int potrf (
            char uplo,
            matrix<T,NR1,NC1,MM,column_major_layout>& a
        )
        {
            // compute the actual decomposition
            int info = binding::potrf(uplo, a.nr(), &a(0,0), a.nr());

            // If it fails part way though the factorization then make sure
            // the end of the matrix gets properly initialized with zeros.
            if (info > 0)
            {
                if (uplo == 'L')
                    set_colm(a, range(info-1, a.nc()-1)) = 0;
                else
                    set_rowm(a, range(info-1, a.nr()-1)) = 0;
            }

            return info;
        }

    // ------------------------------------------------------------------------------------

        template <
            typename T,
            long NR1,
            long NC1,
            typename MM
            >
        int potrf (
            char uplo,
            matrix<T,NR1,NC1,MM,row_major_layout>& a
        )
        {
            // since we are working on a row major order matrix we need to ask
            // LAPACK for the transpose of whatever the user asked for.

            if (uplo == 'L')
                uplo = 'U';
            else
                uplo = 'L';

            // compute the actual decomposition
            int info = binding::potrf(uplo, a.nr(), &a(0,0), a.nr());

            // If it fails part way though the factorization then make sure
            // the end of the matrix gets properly initialized with zeros.
            if (info > 0)
            {
                if (uplo == 'U')
                    set_colm(a, range(info-1, a.nc()-1)) = 0;
                else
                    set_rowm(a, range(info-1, a.nr()-1)) = 0;
            }

            return info;
        }

    // ------------------------------------------------------------------------------------

    }

}

// ----------------------------------------------------------------------------------------

#endif // DLIB_LAPACk_POTRF_Hh_


dlib C++ Library - syev.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_LAPACk_EV_Hh_
#define DLIB_LAPACk_EV_Hh_

#include "fortran_id.h"
#include "../matrix.h"

namespace dlib
{
    namespace lapack
    {
        namespace binding
        {
            extern "C"
            {
                void DLIB_FORTRAN_ID(dsyev) (char *jobz, char *uplo, integer *n, double *a,
                                             integer *lda, double *w, double *work, integer *lwork,
                                             integer *info);

                void DLIB_FORTRAN_ID(ssyev) (char *jobz, char *uplo, integer *n, float *a,
                                             integer *lda, float *w, float *work, integer *lwork,
                                             integer *info);

            }

            inline int syev (char jobz, char uplo, integer n, double *a,
                             integer lda, double *w, double *work, integer lwork)
            {
                integer info = 0;
                DLIB_FORTRAN_ID(dsyev)(&jobz, &uplo, &n, a,
                                       &lda, w, work, &lwork, &info);
                return info;
            }

            inline int syev (char jobz, char uplo, integer n, float *a,
                             integer lda, float *w, float *work, integer lwork)
            {
                integer info = 0;
                DLIB_FORTRAN_ID(ssyev)(&jobz, &uplo, &n, a,
                                       &lda, w, work, &lwork, &info);
                return info;
            }

        }

    // ------------------------------------------------------------------------------------

/*  -- LAPACK driver routine (version 3.1) -- */
/*     Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */
/*     November 2006 */

/*     .. Scalar Arguments .. */
/*     .. */
/*     .. Array Arguments .. */
/*     .. */

/*  Purpose */
/*  ======= */

/*  DSYEV computes all eigenvalues and, optionally, eigenvectors of a */
/*  real symmetric matrix A. */

/*  Arguments */
/*  ========= */

/*  JOBZ    (input) CHARACTER*1 */
/*          = 'N':  Compute eigenvalues only; */
/*          = 'V':  Compute eigenvalues and eigenvectors. */

/*  UPLO    (input) CHARACTER*1 */
/*          = 'U':  Upper triangle of A is stored; */
/*          = 'L':  Lower triangle of A is stored. */

/*  N       (input) INTEGER */
/*          The order of the matrix A.  N >= 0. */

/*  A       (input/output) DOUBLE PRECISION array, dimension (LDA, N) */
/*          On entry, the symmetric matrix A.  If UPLO = 'U', the */
/*          leading N-by-N upper triangular part of A contains the */
/*          upper triangular part of the matrix A.  If UPLO = 'L', */
/*          the leading N-by-N lower triangular part of A contains */
/*          the lower triangular part of the matrix A. */
/*          On exit, if JOBZ = 'V', then if INFO = 0, A contains the */
/*          orthonormal eigenvectors of the matrix A. */
/*          If JOBZ = 'N', then on exit the lower triangle (if UPLO='L') */
/*          or the upper triangle (if UPLO='U') of A, including the */
/*          diagonal, is destroyed. */

/*  LDA     (input) INTEGER */
/*          The leading dimension of the array A.  LDA >= max(1,N). */

/*  W       (output) DOUBLE PRECISION array, dimension (N) */
/*          If INFO = 0, the eigenvalues in ascending order. */

/*  WORK    (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) */
/*          On exit, if INFO = 0, WORK(1) returns the optimal LWORK. */

/*  LWORK   (input) INTEGER */
/*          The length of the array WORK.  LWORK >= max(1,3*N-1). */
/*          For optimal efficiency, LWORK >= (NB+2)*N, */
/*          where NB is the blocksize for DSYTRD returned by ILAENV. */

/*          If LWORK = -1, then a workspace query is assumed; the routine */
/*          only calculates the optimal size of the WORK array, returns */
/*          this value as the first entry of the WORK array, and no error */
/*          message related to LWORK is issued by XERBLA. */

/*  INFO    (output) INTEGER */
/*          = 0:  successful exit */
/*          < 0:  if INFO = -i, the i-th argument had an illegal value */
/*          > 0:  if INFO = i, the algorithm failed to converge; i */
/*                off-diagonal elements of an intermediate tridiagonal */
/*                form did not converge to zero. */

    // ------------------------------------------------------------------------------------

        template <
            typename T,
            long NR1, long NR2,
            long NC1, long NC2,
            typename MM
            >
        int syev (
            const char jobz,
            const char uplo,
            matrix<T,NR1,NC1,MM,column_major_layout>& a,
            matrix<T,NR2,NC2,MM,column_major_layout>& w
        )
        {
            matrix<T,0,1,MM,column_major_layout> work;

            const long n = a.nr();

            w.set_size(n,1);

            // figure out how big the workspace needs to be.
            T work_size = 1;
            int info = binding::syev(jobz, uplo, n, &a(0,0),
                                     a.nr(), &w(0,0), &work_size, -1);

            if (info != 0)
                return info;

            if (work.size() < work_size)
                work.set_size(static_cast<long>(work_size), 1);

            // compute the actual decomposition
            info = binding::syev(jobz, uplo, n, &a(0,0),
                                 a.nr(), &w(0,0), &work(0,0), work.size());

            return info;
        }

    // ------------------------------------------------------------------------------------

        template <
            typename T,
            long NR1, long NR2,
            long NC1, long NC2,
            typename MM
            >
        int syev (
            char jobz,
            char uplo,
            matrix<T,NR1,NC1,MM,row_major_layout>& a,
            matrix<T,NR2,NC2,MM,row_major_layout>& w
        )
        {
            matrix<T,0,1,MM,row_major_layout> work;

            if (uplo == 'L')
                uplo = 'U';
            else
                uplo = 'L';

            const long n = a.nr();

            w.set_size(n,1);

            // figure out how big the workspace needs to be.
            T work_size = 1;
            int info = binding::syev(jobz, uplo, n, &a(0,0),
                                     a.nc(), &w(0,0), &work_size, -1);

            if (info != 0)
                return info;

            if (work.size() < work_size)
                work.set_size(static_cast<long>(work_size), 1);

            // compute the actual decomposition
            info = binding::syev(jobz, uplo, n, &a(0,0),
                                 a.nc(), &w(0,0), &work(0,0), work.size());

            a = trans(a);

            return info;
        }

    // ------------------------------------------------------------------------------------

    }

}

// ----------------------------------------------------------------------------------------

#endif // DLIB_LAPACk_EV_Hh_


dlib C++ Library - syevr.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_LAPACk_EVR_Hh_
#define DLIB_LAPACk_EVR_Hh_

#include "fortran_id.h"
#include "../matrix.h"

namespace dlib
{
    namespace lapack
    {
        namespace binding
        {
            extern "C"
            {
                void DLIB_FORTRAN_ID(dsyevr) (char *jobz, char *range, char *uplo, integer *n,
                                              double *a, integer *lda, double *vl, double *vu, integer * il,
                                              integer *iu, double *abstol, integer *m, double *w,
                                              double *z_, integer *ldz, integer *isuppz, double *work,
                                              integer *lwork, integer *iwork, integer *liwork, integer *info);

                void DLIB_FORTRAN_ID(ssyevr) (char *jobz, char *range, char *uplo, integer *n,
                                              float *a, integer *lda, float *vl, float *vu, integer * il,
                                              integer *iu, float *abstol, integer *m, float *w,
                                              float *z_, integer *ldz, integer *isuppz, float *work,
                                              integer *lwork, integer *iwork, integer *liwork, integer *info);
            }

            inline int syevr (char jobz, char range, char uplo, integer n,
                              double* a, integer lda, double vl, double vu, integer il,
                              integer iu, double abstol, integer *m, double *w,
                              double *z, integer ldz, integer *isuppz, double *work,
                              integer lwork, integer *iwork, integer liwork)
            {
                integer info = 0;
                DLIB_FORTRAN_ID(dsyevr)(&jobz, &range, &uplo, &n,
                                        a, &lda, &vl, &vu, &il,
                                        &iu, &abstol, m, w,
                                        z, &ldz, isuppz, work,
                                        &lwork, iwork, &liwork, &info);
                return info;
            }

            inline int syevr (char jobz, char range, char uplo, integer n,
                              float* a, integer lda, float vl, float vu, integer il,
                              integer iu, float abstol, integer *m, float *w,
                              float *z, integer ldz, integer *isuppz, float *work,
                              integer lwork, integer *iwork, integer liwork)
            {
                integer info = 0;
                DLIB_FORTRAN_ID(ssyevr)(&jobz, &range, &uplo, &n,
                                        a, &lda, &vl, &vu, &il,
                                        &iu, &abstol, m, w,
                                        z, &ldz, isuppz, work,
                                        &lwork, iwork, &liwork, &info);
                return info;
            }

        }

    // ------------------------------------------------------------------------------------

        /*

*  -- LAPACK driver routine (version 3.1) --
*     Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd..
*     November 2006
*
*     .. Scalar Arguments ..
      CHARACTER          JOBZ, RANGE, UPLO
      INTEGER            IL, INFO, IU, LDA, LDZ, LIWORK, LWORK, M, N
      DOUBLE PRECISION   ABSTOL, VL, VU
*     ..
*     .. Array Arguments ..
      INTEGER            ISUPPZ( * ), IWORK( * )
      DOUBLE PRECISION   A( LDA, * ), W( * ), WORK( * ), Z( LDZ, * )
*     ..
*
*  Purpose
*  =======
*
*  DSYEVR computes selected eigenvalues and, optionally, eigenvectors
*  of a real symmetric matrix A.  Eigenvalues and eigenvectors can be
*  selected by specifying either a range of values or a range of
*  indices for the desired eigenvalues.
*
*  DSYEVR first reduces the matrix A to tridiagonal form T with a call
*  to DSYTRD.  Then, whenever possible, DSYEVR calls DSTEMR to compute
*  the eigenspectrum using Relatively Robust Representations.  DSTEMR
*  computes eigenvalues by the dqds algorithm, while orthogonal
*  eigenvectors are computed from various "good" L D L^T representations
*  (also known as Relatively Robust Representations). Gram-Schmidt
*  orthogonalization is avoided as far as possible. More specifically,
*  the various steps of the algorithm are as follows.
*
*  For each unreduced block (submatrix) of T,
*     (a) Compute T - sigma I  = L D L^T, so that L and D
*         define all the wanted eigenvalues to high relative accuracy.
*         This means that small relative changes in the entries of D and L
*         cause only small relative changes in the eigenvalues and
*         eigenvectors. The standard (unfactored) representation of the
*         tridiagonal matrix T does not have this property in general.
*     (b) Compute the eigenvalues to suitable accuracy.
*         If the eigenvectors are desired, the algorithm attains full
*         accuracy of the computed eigenvalues only right before
*         the corresponding vectors have to be computed, see steps c) and d).
*     (c) For each cluster of close eigenvalues, select a new
*         shift close to the cluster, find a new factorization, and refine
*         the shifted eigenvalues to suitable accuracy.
*     (d) For each eigenvalue with a large enough relative separation compute
*         the corresponding eigenvector by forming a rank revealing twisted
*         factorization. Go back to (c) for any clusters that remain.
*
*  The desired accuracy of the output can be specified by the input
*  parameter ABSTOL.
*
*  For more details, see DSTEMR's documentation and:
*  - Inderjit S. Dhillon and Beresford N. Parlett: "Multiple representations
*    to compute orthogonal eigenvectors of symmetric tridiagonal matrices,"
*    Linear Algebra and its Applications, 387(1), pp. 1-28, August 2004.
*  - Inderjit Dhillon and Beresford Parlett: "Orthogonal Eigenvectors and
*    Relative Gaps," SIAM Journal on Matrix Analysis and Applications, Vol. 25,
*    2004.  Also LAPACK Working Note 154.
*  - Inderjit Dhillon: "A new O(n^2) algorithm for the symmetric
*    tridiagonal eigenvalue/eigenvector problem",
*    Computer Science Division Technical Report No. UCB/CSD-97-971,
*    UC Berkeley, May 1997.
*
*
*  Note 1 : DSYEVR calls DSTEMR when the full spectrum is requested
*  on machines which conform to the ieee-754 floating point standard.
*  DSYEVR calls DSTEBZ and SSTEIN on non-ieee machines and
*  when partial spectrum requests are made.
*
*  Normal execution of DSTEMR may create NaNs and infinities and
*  hence may abort due to a floating point exception in environments
*  which do not handle NaNs and infinities in the ieee standard default
*  manner.
*
*  Arguments
*  =========
*
*  JOBZ    (input) CHARACTER*1
*          = 'N':  Compute eigenvalues only;
*          = 'V':  Compute eigenvalues and eigenvectors.
*
*  RANGE   (input) CHARACTER*1
*          = 'A': all eigenvalues will be found.
*          = 'V': all eigenvalues in the half-open interval (VL,VU]
*                 will be found.
*          = 'I': the IL-th through IU-th eigenvalues will be found.
********** For RANGE = 'V' or 'I' and IU - IL < N - 1, DSTEBZ and
********** DSTEIN are called
*
*  UPLO    (input) CHARACTER*1
*          = 'U':  Upper triangle of A is stored;
*          = 'L':  Lower triangle of A is stored.
*
*  N       (input) INTEGER
*          The order of the matrix A.  N >= 0.
*
*  A       (input/output) DOUBLE PRECISION array, dimension (LDA, N)
*          On entry, the symmetric matrix A.  If UPLO = 'U', the
*          leading N-by-N upper triangular part of A contains the
*          upper triangular part of the matrix A.  If UPLO = 'L',
*          the leading N-by-N lower triangular part of A contains
*          the lower triangular part of the matrix A.
*          On exit, the lower triangle (if UPLO='L') or the upper
*          triangle (if UPLO='U') of A, including the diagonal, is
*          destroyed.
*
*  LDA     (input) INTEGER
*          The leading dimension of the array A.  LDA >= max(1,N).
*
*  VL      (input) DOUBLE PRECISION
*  VU      (input) DOUBLE PRECISION
*          If RANGE='V', the lower and upper bounds of the interval to
*          be searched for eigenvalues. VL < VU.
*          Not referenced if RANGE = 'A' or 'I'.
*
*  IL      (input) INTEGER
*  IU      (input) INTEGER
*          If RANGE='I', the indices (in ascending order) of the
*          smallest and largest eigenvalues to be returned.
*          1 <= IL <= IU <= N, if N > 0; IL = 1 and IU = 0 if N = 0.
*          Not referenced if RANGE = 'A' or 'V'.
*
*  ABSTOL  (input) DOUBLE PRECISION
*          The absolute error tolerance for the eigenvalues.
*          An approximate eigenvalue is accepted as converged
*          when it is determined to lie in an interval [a,b]
*          of width less than or equal to
*
*                  ABSTOL + EPS *   max( |a|,|b| ) ,
*
*          where EPS is the machine precision.  If ABSTOL is less than
*          or equal to zero, then  EPS*|T|  will be used in its place,
*          where |T| is the 1-norm of the tridiagonal matrix obtained
*          by reducing A to tridiagonal form.
*
*          See "Computing Small Singular Values of Bidiagonal Matrices
*          with Guaranteed High Relative Accuracy," by Demmel and
*          Kahan, LAPACK Working Note #3.
*
*          If high relative accuracy is important, set ABSTOL to
*          DLAMCH( 'Safe minimum' ).  Doing so will guarantee that
*          eigenvalues are computed to high relative accuracy when
*          possible in future releases.  The current code does not
*          make any guarantees about high relative accuracy, but
*          future releases will. See J. Barlow and J. Demmel,
*          "Computing Accurate Eigensystems of Scaled Diagonally
*          Dominant Matrices", LAPACK Working Note #7, for a discussion
*          of which matrices define their eigenvalues to high relative
*          accuracy.
*
*  M       (output) INTEGER
*          The total number of eigenvalues found.  0 <= M <= N.
*          If RANGE = 'A', M = N, and if RANGE = 'I', M = IU-IL+1.
*
*  W       (output) DOUBLE PRECISION array, dimension (N)
*          The first M elements contain the selected eigenvalues in
*          ascending order.
*
*  Z       (output) DOUBLE PRECISION array, dimension (LDZ, max(1,M))
*          If JOBZ = 'V', then if INFO = 0, the first M columns of Z
*          contain the orthonormal eigenvectors of the matrix A
*          corresponding to the selected eigenvalues, with the i-th
*          column of Z holding the eigenvector associated with W(i).
*          If JOBZ = 'N', then Z is not referenced.
*          Note: the user must ensure that at least max(1,M) columns are
*          supplied in the array Z; if RANGE = 'V', the exact value of M
*          is not known in advance and an upper bound must be used.
*          Supplying N columns is always safe.
*
*  LDZ     (input) INTEGER
*          The leading dimension of the array Z.  LDZ >= 1, and if
*          JOBZ = 'V', LDZ >= max(1,N).
*
*  ISUPPZ  (output) INTEGER array, dimension ( 2*max(1,M) )
*          The support of the eigenvectors in Z, i.e., the indices
*          indicating the nonzero elements in Z. The i-th eigenvector
*          is nonzero only in elements ISUPPZ( 2*i-1 ) through
*          ISUPPZ( 2*i ).
********** Implemented only for RANGE = 'A' or 'I' and IU - IL = N - 1
*
*  WORK    (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK))
*          On exit, if INFO = 0, WORK(1) returns the optimal LWORK.
*
*  LWORK   (input) INTEGER
*          The dimension of the array WORK.  LWORK >= max(1,26*N).
*          For optimal efficiency, LWORK >= (NB+6)*N,
*          where NB is the max of the blocksize for DSYTRD and DORMTR
*          returned by ILAENV.
*
*          If LWORK = -1, then a workspace query is assumed; the routine
*          only calculates the optimal size of the WORK array, returns
*          this value as the first entry of the WORK array, and no error
*          message related to LWORK is issued by XERBLA.
*
*  IWORK   (workspace/output) INTEGER array, dimension (MAX(1,LIWORK))
*          On exit, if INFO = 0, IWORK(1) returns the optimal LWORK.
*
*  LIWORK  (input) INTEGER
*          The dimension of the array IWORK.  LIWORK >= max(1,10*N).
*
*          If LIWORK = -1, then a workspace query is assumed; the
*          routine only calculates the optimal size of the IWORK array,
*          returns this value as the first entry of the IWORK array, and
*          no error message related to LIWORK is issued by XERBLA.
*
*  INFO    (output) INTEGER
*          = 0:  successful exit
*          < 0:  if INFO = -i, the i-th argument had an illegal value
*          > 0:  Internal error
*
*  Further Details
*  ===============
*
*  Based on contributions by
*     Inderjit Dhillon, IBM Almaden, USA
*     Osni Marques, LBNL/NERSC, USA
*     Ken Stanley, Computer Science Division, University of
*       California at Berkeley, USA
*     Jason Riedy, Computer Science Division, University of
*       California at Berkeley, USA
*
* =====================================================================

        */

    // ------------------------------------------------------------------------------------

        template <
            typename T,
            long NR1, long NR2, long NR3, long NR4,
            long NC1, long NC2, long NC3, long NC4,
            typename MM
            >
        int syevr (
            const char jobz,
            const char range,
            const char uplo,
            matrix<T,NR1,NC1,MM,column_major_layout>& a,
            const double vl,
            const double vu,
            const integer il,
            const integer iu,
            const double abstol,
            integer& num_eigenvalues_found,
            matrix<T,NR2,NC2,MM,column_major_layout>& w,
            matrix<T,NR3,NC3,MM,column_major_layout>& z,
            matrix<integer,NR4,NC4,MM,column_major_layout>& isuppz
        )
        {
            matrix<T,0,1,MM,column_major_layout> work;
            matrix<integer,0,1,MM,column_major_layout> iwork;

            const long n = a.nr();

            w.set_size(n,1);

            isuppz.set_size(2*n, 1);

            if (jobz == 'V')
            {
                z.set_size(n,n);
            }
            else
            {
                z.set_size(NR3?NR3:1, NC3?NC3:1);
            }

            // figure out how big the workspace needs to be.
            T work_size = 1;
            integer iwork_size = 1;
            int info = binding::syevr(jobz, range, uplo, n, &a(0,0),
                                      a.nr(), vl, vu, il, iu, abstol, &num_eigenvalues_found,
                                      &w(0,0), &z(0,0), z.nr(), &isuppz(0,0), &work_size, -1,
                                      &iwork_size, -1);

            if (info != 0)
                return info;

            if (work.size() < work_size)
                work.set_size(static_cast<long>(work_size), 1);
            if (iwork.size() < iwork_size)
                iwork.set_size(iwork_size, 1);

            // compute the actual decomposition
            info = binding::syevr(jobz, range, uplo, n, &a(0,0),
                                  a.nr(), vl, vu, il, iu, abstol, &num_eigenvalues_found,
                                  &w(0,0), &z(0,0), z.nr(), &isuppz(0,0), &work(0,0), work.size(),
                                  &iwork(0,0), iwork.size());

            return info;
        }

    // ------------------------------------------------------------------------------------

        template <
            typename T,
            long NR1, long NR2, long NR3, long NR4,
            long NC1, long NC2, long NC3, long NC4,
            typename MM
            >
        int syevr (
            const char jobz,
            const char range,
            char uplo,
            matrix<T,NR1,NC1,MM,row_major_layout>& a,
            const double vl,
            const double vu,
            const integer il,
            const integer iu,
            const double abstol,
            integer& num_eigenvalues_found,
            matrix<T,NR2,NC2,MM,row_major_layout>& w,
            matrix<T,NR3,NC3,MM,row_major_layout>& z,
            matrix<integer,NR4,NC4,MM,row_major_layout>& isuppz
        )
        {
            matrix<T,0,1,MM,row_major_layout> work;
            matrix<integer,0,1,MM,row_major_layout> iwork;

            if (uplo == 'L')
                uplo = 'U';
            else
                uplo = 'L';

            const long n = a.nr();

            w.set_size(n,1);

            isuppz.set_size(2*n, 1);

            if (jobz == 'V')
            {
                z.set_size(n,n);
            }
            else
            {
                z.set_size(NR3?NR3:1, NC3?NC3:1);
            }

            // figure out how big the workspace needs to be.
            T work_size = 1;
            integer iwork_size = 1;
            int info = binding::syevr(jobz, range, uplo, n, &a(0,0),
                                      a.nc(), vl, vu, il, iu, abstol, &num_eigenvalues_found,
                                      &w(0,0), &z(0,0), z.nc(), &isuppz(0,0), &work_size, -1,
                                      &iwork_size, -1);

            if (info != 0)
                return info;

            if (work.size() < work_size)
                work.set_size(static_cast<long>(work_size), 1);
            if (iwork.size() < iwork_size)
                iwork.set_size(iwork_size, 1);

            // compute the actual decomposition
            info = binding::syevr(jobz, range, uplo, n, &a(0,0),
                                  a.nc(), vl, vu, il, iu, abstol, &num_eigenvalues_found,
                                  &w(0,0), &z(0,0), z.nc(), &isuppz(0,0), &work(0,0), work.size(),
                                  &iwork(0,0), iwork.size());

            z = trans(z);

            return info;
        }

    // ------------------------------------------------------------------------------------

    }

}

// ----------------------------------------------------------------------------------------

#endif // DLIB_LAPACk_EVR_Hh_


dlib C++ Library - md5_kernel_1.cpp

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MD5_KERNEL_1_CPp_
#define DLIB_MD5_KERNEL_1_CPp_
#include "md5_kernel_1.h"
#include "../uintn.h"

#include <sstream>
#include <cstring>

namespace dlib
{

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    namespace md5_stuff
    {

        inline uint32 F (
            uint32 x,
            uint32 y,
            uint32 z
        )
        {
            return ( (x&y) | ((~x)&z) );
        }

    // ------------------------------------------------------------------------------------

        inline uint32 G (
            uint32 x,
            uint32 y,
            uint32 z
        )
        {
            return ( (x&z) | (y&(~z)) );
        }

    // ------------------------------------------------------------------------------------

        inline uint32 H (
            uint32 x,
            uint32 y,
            uint32 z
        )
        {
            return ( x^y^z );
        }

    // ------------------------------------------------------------------------------------

        inline uint32 I (
            uint32 x,
            uint32 y,
            uint32 z
        )
        {
            return ( y ^ (x|(~z)) );
        }

    // ------------------------------------------------------------------------------------

        inline uint32 rotate_left (
            uint32 x,
            uint32 n
        )
        {
            return  ( (x<<n) | (x>>(32-n)) );
        }

    // ------------------------------------------------------------------------------------

        inline void FF (
            uint32& a,
            uint32 b,
            uint32 c,
            uint32 d,
            uint32 x,
            uint32 s,
            uint32 ac
        )
        {
            a += F(b, c, d) + x + ac;
            a = rotate_left(a, s);
            a += b;
        }

    // ------------------------------------------------------------------------------------

        inline void GG (
            uint32& a,
            uint32 b,
            uint32 c,
            uint32 d,
            uint32 x,
            uint32 s,
            uint32 ac
        )
        {
            a += G(b, c, d) + x + ac;
            a = rotate_left(a, s);
            a += b;
        }

    // ------------------------------------------------------------------------------------

        inline void HH (
            uint32& a,
            uint32 b,
            uint32 c,
            uint32 d,
            uint32 x,
            uint32 s,
            uint32 ac
        )
        {
            a += H(b, c, d) + x + ac;
            a = rotate_left(a, s);
            a += b;
        }

    // ------------------------------------------------------------------------------------

        inline void II (
            uint32& a,
            uint32 b,
            uint32 c,
            uint32 d,
            uint32 x,
            uint32 s,
            uint32 ac
        )
        {
            a += I(b, c, d) + x + ac;
            a = rotate_left(a, s);
            a += b;
        }

    // ------------------------------------------------------------------------------------

        void scramble_block (
            uint32& a,
            uint32& b,
            uint32& c,
            uint32& d,
            uint32* x
        )
        {
            const uint32 S11 = 7;
            const uint32 S12 = 12;
            const uint32 S13 = 17;
            const uint32 S14 = 22;
            const uint32 S21 = 5;
            const uint32 S22 = 9;
            const uint32 S23 = 14;
            const uint32 S24 = 20;
            const uint32 S31 = 4;
            const uint32 S32 = 11;
            const uint32 S33 = 16;
            const uint32 S34 = 23;
            const uint32 S41 = 6;
            const uint32 S42 = 10;
            const uint32 S43 = 15;
            const uint32 S44 = 21;

            // round 1
            FF (a, b, c, d, x[ 0], S11, 0xd76aa478); // 1
            FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); // 2
            FF (c, d, a, b, x[ 2], S13, 0x242070db); // 3
            FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); // 4
            FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); // 5
            FF (d, a, b, c, x[ 5], S12, 0x4787c62a); // 6
            FF (c, d, a, b, x[ 6], S13, 0xa8304613); // 7
            FF (b, c, d, a, x[ 7], S14, 0xfd469501); // 8
            FF (a, b, c, d, x[ 8], S11, 0x698098d8); // 9
            FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); // 10
            FF (c, d, a, b, x[10], S13, 0xffff5bb1); // 11
            FF (b, c, d, a, x[11], S14, 0x895cd7be); // 12
            FF (a, b, c, d, x[12], S11, 0x6b901122); // 13
            FF (d, a, b, c, x[13], S12, 0xfd987193); // 14
            FF (c, d, a, b, x[14], S13, 0xa679438e); // 15
            FF (b, c, d, a, x[15], S14, 0x49b40821); // 16

            // Round 2
            GG (a, b, c, d, x[ 1], S21, 0xf61e2562); // 17
            GG (d, a, b, c, x[ 6], S22, 0xc040b340); // 18
            GG (c, d, a, b, x[11], S23, 0x265e5a51); // 19
            GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); // 20
            GG (a, b, c, d, x[ 5], S21, 0xd62f105d); // 21
            GG (d, a, b, c, x[10], S22,  0x2441453); // 22
            GG (c, d, a, b, x[15], S23, 0xd8a1e681); // 23
            GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); // 24
            GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); // 25
            GG (d, a, b, c, x[14], S22, 0xc33707d6); // 26
            GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); // 27
            GG (b, c, d, a, x[ 8], S24, 0x455a14ed); // 28
            GG (a, b, c, d, x[13], S21, 0xa9e3e905); // 29
            GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); // 30
            GG (c, d, a, b, x[ 7], S23, 0x676f02d9); // 31
            GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); // 32

            // Round 3
            HH (a, b, c, d, x[ 5], S31, 0xfffa3942); // 33
            HH (d, a, b, c, x[ 8], S32, 0x8771f681); // 34
            HH (c, d, a, b, x[11], S33, 0x6d9d6122); // 35
            HH (b, c, d, a, x[14], S34, 0xfde5380c); // 36
            HH (a, b, c, d, x[ 1], S31, 0xa4beea44); // 37
            HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); // 38
            HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); // 39
            HH (b, c, d, a, x[10], S34, 0xbebfbc70); // 40
            HH (a, b, c, d, x[13], S31, 0x289b7ec6); // 41
            HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); // 42
            HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); // 43
            HH (b, c, d, a, x[ 6], S34,  0x4881d05); // 44
            HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); // 45
            HH (d, a, b, c, x[12], S32, 0xe6db99e5); // 46
            HH (c, d, a, b, x[15], S33, 0x1fa27cf8); // 47
            HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); // 48

            // Round 4
            II (a, b, c, d, x[ 0], S41, 0xf4292244); // 49
            II (d, a, b, c, x[ 7], S42, 0x432aff97); // 50
            II (c, d, a, b, x[14], S43, 0xab9423a7); // 51
            II (b, c, d, a, x[ 5], S44, 0xfc93a039); // 52
            II (a, b, c, d, x[12], S41, 0x655b59c3); // 53
            II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); // 54
            II (c, d, a, b, x[10], S43, 0xffeff47d); // 55
            II (b, c, d, a, x[ 1], S44, 0x85845dd1); // 56
            II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); // 57
            II (d, a, b, c, x[15], S42, 0xfe2ce6e0); // 58
            II (c, d, a, b, x[ 6], S43, 0xa3014314); // 59
            II (b, c, d, a, x[13], S44, 0x4e0811a1); // 60
            II (a, b, c, d, x[ 4], S41, 0xf7537e82); // 61
            II (d, a, b, c, x[11], S42, 0xbd3af235); // 62
            II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); // 63
            II (b, c, d, a, x[ 9], S44, 0xeb86d391); // 64
        }

    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    const std::string md5 (
        const std::string& input
    )
    {
        unsigned char output[16];
        md5 (
            reinterpret_cast<const unsigned char*>(input.data()),
            static_cast<unsigned long>(input.size()),
            output
            );

        std::stringstream temp;
        for (int i = 0; i < 16; ++i)
        {
            temp.fill('0');
            temp.width(2);
            temp << std::hex << static_cast<unsigned int>(output[i]);
        }

        return temp.str();
    }

// ----------------------------------------------------------------------------------------

    void md5 (
        const unsigned char* input,
        unsigned long len,
        unsigned char* output
    )
    {
        using namespace md5_stuff;

        // make a temp version of input with enough space for padding and len appended
        unsigned long extra_len = 64-len%64;
        if (extra_len <= 8)
            extra_len += 64;
        unsigned char* temp = new unsigned char[extra_len + len];

        // number of 16 word blocks
        const unsigned long N = (extra_len + len)/64;

        const unsigned char* input2 = input;
        unsigned char* temp2 = temp;
        unsigned char* end = temp+len;

        // copy input into temp
        while (temp2 != end)
        {
            *temp2 = *input2;
            ++temp2;
            ++input2;
        }

        // pad temp
        end += extra_len-8;
        *temp2 = static_cast<unsigned char>(0x80);
        ++temp2;
        while (temp2 != end)
        {
            *temp2 = 0;
            ++temp2;
        }

        // make len the number of bits in the original message
        // but first multiply len by 8 and since len is only 32 bits the number might
        // overflow so we will carry out the multiplication manually and end up with
        // the result in the base 65536 number with three digits
        // result = low + high*65536 + upper*65536*65536
        unsigned long low = len & 0xFFFF;
        unsigned long high = len >> 16;
        unsigned long upper;
        unsigned long tmp;
        tmp = low * 8;
        low = tmp & 0xFFFF;
        tmp = high * 8 + (tmp>>16);
        high = tmp & 0xFFFF;
        upper = tmp >> 16;

        // append the length
        *temp2 = static_cast<unsigned char>(low&0xFF);
        ++temp2;
        *temp2 = static_cast<unsigned char>((low>>8)&0xFF);
        ++temp2;
        *temp2 = static_cast<unsigned char>((high)&0xFF);
        ++temp2;
        *temp2 = static_cast<unsigned char>((high>>8)&0xFF);
        ++temp2;
        *temp2 = static_cast<unsigned char>((upper)&0xFF);;
        ++temp2;
        *temp2 = static_cast<unsigned char>((upper>>8)&0xFF);;
        ++temp2;
        *temp2 = 0;
        ++temp2;
        *temp2 = 0;

        uint32 a = 0x67452301;
        uint32 b = 0xefcdab89;
        uint32 c = 0x98badcfe;
        uint32 d = 0x10325476;

        // an array of 16 words
        uint32 x[16];

        for (unsigned long i = 0; i < N; ++i)
        {

            // copy a block of 16 words from m into x
            for (unsigned long j = 0; j < 16; ++j)
            {
                x[j] = (
                    (static_cast<uint32>(temp[4*(j + 16*i) + 3]) << 24) |
                    (static_cast<uint32>(temp[4*(j + 16*i) + 2]) << 16) |
                    (static_cast<uint32>(temp[4*(j + 16*i) + 1]) << 8 ) |
                    (static_cast<uint32>(temp[4*(j + 16*i)    ])      )
                    );
            }

            uint32 aa = a;
            uint32 bb = b;
            uint32 cc = c;
            uint32 dd = d;

            scramble_block(a,b,c,d,x);

            a = a + aa;
            b = b + bb;
            c = c + cc;
            d = d + dd;

        }

        // put a, b, c, and d into output
        output[0]   = static_cast<unsigned char>((a)    &0xFF);
        output[1]   = static_cast<unsigned char>((a>>8) &0xFF);
        output[2]   = static_cast<unsigned char>((a>>16)&0xFF);
        output[3]   = static_cast<unsigned char>((a>>24)&0xFF);

        output[4]   = static_cast<unsigned char>((b)    &0xFF);
        output[5]   = static_cast<unsigned char>((b>>8) &0xFF);
        output[6]   = static_cast<unsigned char>((b>>16)&0xFF);
        output[7]   = static_cast<unsigned char>((b>>24)&0xFF);

        output[8]   = static_cast<unsigned char>((c)    &0xFF);
        output[9]   = static_cast<unsigned char>((c>>8) &0xFF);
        output[10]  = static_cast<unsigned char>((c>>16)&0xFF);
        output[11]  = static_cast<unsigned char>((c>>24)&0xFF);

        output[12]  = static_cast<unsigned char>((d)    &0xFF);
        output[13]  = static_cast<unsigned char>((d>>8) &0xFF);
        output[14]  = static_cast<unsigned char>((d>>16)&0xFF);
        output[15]  = static_cast<unsigned char>((d>>24)&0xFF);

        delete [] temp;
    }

// ----------------------------------------------------------------------------------------

    const std::string md5 (
        std::istream& input
    )
    {
        unsigned char output[16];
        md5 (
            input,
            output
            );

        std::stringstream temp;
        for (int i = 0; i < 16; ++i)
        {
            temp.fill('0');
            temp.width(2);
            temp << std::hex << static_cast<unsigned int>(output[i]);
        }

        return temp.str();
    }

// ----------------------------------------------------------------------------------------

    void md5 (
        std::istream& input,
        unsigned char* output
    )
    {
        using namespace md5_stuff;

        uint32 a = 0x67452301;
        uint32 b = 0xefcdab89;
        uint32 c = 0x98badcfe;
        uint32 d = 0x10325476;

        unsigned long len = 0;

        // an array of 16 words
        uint32 x[16];
        unsigned char temp[64];

        bool write_length = false;
        bool at_end = false;
        std::streambuf& inputbuf = *input.rdbuf();
        while(!at_end)
        {
            int num = inputbuf.sgetn(reinterpret_cast<char*>(temp),64);
            len += num;

            // if we hit the end of the stream then pad and add length
            if (num < 64)
            {
                at_end = true;
                unsigned char* temp2 = temp;
                unsigned char* end;
                if (num < 56)
                    end = temp+56;
                else
                    end = temp+64;

                temp2 += num;

                // apply padding
                *temp2 = 0x80;
                ++temp2;
                while (temp2 != end)
                {
                    *temp2 = 0;
                    ++temp2;
                }

                if (num < 56)
                {
                    write_length = true;
                    // make len the number of bits in the original message
                    // but first multiply len by 8 and since len is only 32 bits the number might
                    // overflow so we will carry out the multiplication manually and end up with
                    // the result in the base 65536 number with three digits
                    // result = low + high*65536 + upper*65536*65536
                    unsigned long low = len & 0xFFFF;
                    unsigned long high = len >> 16;
                    unsigned long upper;
                    unsigned long tmp;
                    tmp = low * 8;
                    low = tmp & 0xFFFF;
                    tmp = high * 8 + (tmp>>16);
                    high = tmp & 0xFFFF;
                    upper = tmp >> 16;

                    // append the length
                    *temp2 = static_cast<unsigned char>(low&0xFF);
                    ++temp2;
                    *temp2 = static_cast<unsigned char>((low>>8)&0xFF);
                    ++temp2;
                    *temp2 = static_cast<unsigned char>((high)&0xFF);
                    ++temp2;
                    *temp2 = static_cast<unsigned char>((high>>8)&0xFF);
                    ++temp2;
                    *temp2 = static_cast<unsigned char>((upper)&0xFF);;
                    ++temp2;
                    *temp2 = static_cast<unsigned char>((upper>>8)&0xFF);;
                    ++temp2;
                    *temp2 = 0;
                    ++temp2;
                    *temp2 = 0;
                }

            }

            // copy a block of 16 words from m into x
            for (unsigned long i = 0; i < 16; ++i)
            {
                x[i] = (
                    (static_cast<uint32>(temp[4*i + 3]) << 24) |
                    (static_cast<uint32>(temp[4*i + 2]) << 16) |
                    (static_cast<uint32>(temp[4*i + 1]) << 8 ) |
                    (static_cast<uint32>(temp[4*i    ])      )
                    );
            }

            uint32 aa = a;
            uint32 bb = b;
            uint32 cc = c;
            uint32 dd = d;

            scramble_block(a,b,c,d,x);

            a = a + aa;
            b = b + bb;
            c = c + cc;
            d = d + dd;

        }

        if (!write_length)
        {
            uint64 temp = len*8;

            uint32 aa = a;
            uint32 bb = b;
            uint32 cc = c;
            uint32 dd = d;

            std::memset(x, 0, sizeof(x));
            x[15] = (temp>>32);
            x[14] = (temp&0xFFFFFFFF);

            scramble_block(a,b,c,d,x);

            a = a + aa;
            b = b + bb;
            c = c + cc;
            d = d + dd;

        }

        // put a, b, c, and d into output
        output[0]   = static_cast<unsigned char>((a)    &0xFF);
        output[1]   = static_cast<unsigned char>((a>>8) &0xFF);
        output[2]   = static_cast<unsigned char>((a>>16)&0xFF);
        output[3]   = static_cast<unsigned char>((a>>24)&0xFF);

        output[4]   = static_cast<unsigned char>((b)    &0xFF);
        output[5]   = static_cast<unsigned char>((b>>8) &0xFF);
        output[6]   = static_cast<unsigned char>((b>>16)&0xFF);
        output[7]   = static_cast<unsigned char>((b>>24)&0xFF);

        output[8]   = static_cast<unsigned char>((c)    &0xFF);
        output[9]   = static_cast<unsigned char>((c>>8) &0xFF);
        output[10]  = static_cast<unsigned char>((c>>16)&0xFF);
        output[11]  = static_cast<unsigned char>((c>>24)&0xFF);

        output[12]  = static_cast<unsigned char>((d)    &0xFF);
        output[13]  = static_cast<unsigned char>((d>>8) &0xFF);
        output[14]  = static_cast<unsigned char>((d>>16)&0xFF);
        output[15]  = static_cast<unsigned char>((d>>24)&0xFF);

        input.clear(std::ios::eofbit);
    }

// ----------------------------------------------------------------------------------------

}
#endif // DLIB_MD5_KERNEL_1_CPp_


dlib C++ Library - md5_kernel_1.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MD5_KERNEl_1_
#define DLIB_MD5_KERNEl_1_

#include "md5_kernel_abstract.h"
#include <string>
#include <iosfwd>
#include "../algs.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    const std::string md5 (
        const std::string& input
    );

// ----------------------------------------------------------------------------------------

    void md5 (
        const unsigned char* input,
        unsigned long len,
        unsigned char* output
    );

// ----------------------------------------------------------------------------------------

    const std::string md5 (
        std::istream& input
    );

// ----------------------------------------------------------------------------------------

    void md5 (
        std::istream& input,
        unsigned char* output
    );

// ----------------------------------------------------------------------------------------

}

#ifdef NO_MAKEFILE
#include "md5_kernel_1.cpp"
#endif

#endif // DLIB_MD5_KERNEl_1_


dlib C++ Library - make_mfp.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MAKE_MFp_H_
#define DLIB_MAKE_MFp_H_

#include "member_function_pointer_kernel_1.h"
#include "make_mfp_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    member_function_pointer<> make_mfp (
        T& object,
        void (T::*cb)()
    )
    {
        member_function_pointer<> temp;
        temp.set(object, cb);
        return temp;
    }

    template <
        typename T
        >
    member_function_pointer<> make_mfp (
        const T& object,
        void (T::*cb)()const
    )
    {
        member_function_pointer<> temp;
        temp.set(object, cb);
        return temp;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename A1
        >
    member_function_pointer<A1> make_mfp (
        T& object,
        void (T::*cb)(A1)
    )
    {
        member_function_pointer<A1> temp;
        temp.set(object, cb);
        return temp;
    }

    template <
        typename T,
        typename A1
        >
    member_function_pointer<A1> make_mfp (
        const T& object,
        void (T::*cb)(A1)const
    )
    {
        member_function_pointer<A1> temp;
        temp.set(object, cb);
        return temp;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename A1,
        typename A2
        >
    member_function_pointer<A1,A2> make_mfp (
        T& object,
        void (T::*cb)(A1,A2)
    )
    {
        member_function_pointer<A1,A2> temp;
        temp.set(object, cb);
        return temp;
    }

    template <
        typename T,
        typename A1,
        typename A2
        >
    member_function_pointer<A1,A2> make_mfp (
        const T& object,
        void (T::*cb)(A1,A2)const
    )
    {
        member_function_pointer<A1,A2> temp;
        temp.set(object, cb);
        return temp;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename A1,
        typename A2,
        typename A3
        >
    member_function_pointer<A1,A2,A3> make_mfp (
        T& object,
        void (T::*cb)(A1,A2,A3)
    )
    {
        member_function_pointer<A1,A2,A3> temp;
        temp.set(object, cb);
        return temp;
    }

    template <
        typename T,
        typename A1,
        typename A2,
        typename A3
        >
    member_function_pointer<A1,A2,A3> make_mfp (
        const T& object,
        void (T::*cb)(A1,A2,A3)const
    )
    {
        member_function_pointer<A1,A2,A3> temp;
        temp.set(object, cb);
        return temp;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename A1,
        typename A2,
        typename A3,
        typename A4
        >
    member_function_pointer<A1,A2,A3,A4> make_mfp (
        T& object,
        void (T::*cb)(A1,A2,A3,A4)
    )
    {
        member_function_pointer<A1,A2,A3,A4> temp;
        temp.set(object, cb);
        return temp;
    }

    template <
        typename T,
        typename A1,
        typename A2,
        typename A3,
        typename A4
        >
    member_function_pointer<A1,A2,A3,A4> make_mfp (
        const T& object,
        void (T::*cb)(A1,A2,A3,A4)const
    )
    {
        member_function_pointer<A1,A2,A3,A4> temp;
        temp.set(object, cb);
        return temp;
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MAKE_MFp_H_


dlib C++ Library - member_function_pointer_kernel_1.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MEMBER_FUNCTION_POINTER_KERNEl_1_
#define DLIB_MEMBER_FUNCTION_POINTER_KERNEl_1_

#include "../algs.h"
#include "member_function_pointer_kernel_abstract.h"
#include "../enable_if.h"
#include <new>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename PARAM1 = void,
        typename PARAM2 = void,
        typename PARAM3 = void,
        typename PARAM4 = void
        >
    class member_function_pointer;

// ----------------------------------------------------------------------------------------

#define DLIB_MFP_SC DLIB_ASSERT(cb != 0,                                \
                   "\tvoid member_function_pointer::set"                \
                   << "\n\tthe member function pointer can't be null"   \
                   << "\n\tthis: " << this   );

#define DLIB_MFP_OC DLIB_ASSERT(this->is_set() == true ,                            \
                   "\tvoid member_function_pointer::operator()"                     \
                   << "\n\tYou must call set() before you can use this function"    \
                   << "\n\tthis: " << this);

// ----------------------------------------------------------------------------------------

    template <unsigned long num_args>
    class mfp_kernel_1_base_class
    {
        /*
            All member function pointer classes inherit from this class.  This
            is where most of the things in a member function pointer are defined.

            The reason for the num_args template argument to this class is to prevent
            any sort of implicit casting between derived member function pointer classes
            that take different numbers of arguments.
        */
    protected:
        enum mfp_type { mfp_nonconst, mfp_const, mfp_null};

        class mp_base_base
        {
        public:
            mp_base_base(void* ptr, mfp_type type_) : o(ptr),type(type_) {}
            virtual ~mp_base_base(){}
            virtual void clone(void* ptr) const = 0;
            virtual bool is_same (const mp_base_base* item) const = 0;
            bool is_set () const { return o!=0; }

            void* const o;
            const mfp_type type;
        };

        template <typename T>
        class mp_null : public mp_base_base
        {
        public:
            typedef void (T::*mfp_pointer_type)() ;

            mp_null (void* , mfp_pointer_type ) : mp_base_base(0,mfp_null), callback(0) {}
            mp_null () : mp_base_base(0,mfp_null), callback(0) {}

            const mfp_pointer_type callback;
        };

        template <typename mp_impl>
        class mp_impl_T : public mp_impl
        {
            /*
                This class supplies the implementations clone() and is_same() for any
                classes that inherit from mp_base_base.  It does this in a very
                roundabout way...
            */

        public:
            typedef typename mp_impl::mfp_pointer_type mfp_pointer_type;

            mp_impl_T() : mp_impl(0,0) {}
            mp_impl_T(void* ptr, mfp_pointer_type cb) : mp_impl(ptr,cb) {}

            template <unsigned long mem_size>
            void safe_clone(stack_based_memory_block<mem_size>& buf)
            {
                // This is here just to validate the assumption that our block of memory we have made
                // in mp_memory is the right size to store the data for this object.  If you
                // get a compiler error on this line then email me :)
                COMPILE_TIME_ASSERT(sizeof(mp_impl_T) <= mem_size);
                clone(buf.get());
            }

            void clone   (void* ptr) const  { new(ptr) mp_impl_T(this->o,this->callback); }
            bool is_same (const mp_base_base* item) const
            {
                if (item->o == 0 && this->o == 0)
                {
                    return true;
                }
                else if (item->o == this->o && this->type == item->type)
                {
                    const mp_impl* i = reinterpret_cast<const mp_impl*>(item);
                    return (i->callback == this->callback);
                }
                return false;
            }
        };

        struct dummy_base { virtual void nonnull() {}; virtual ~dummy_base(){}; int a; };
        struct dummy : virtual public dummy_base{ void nonnull() {}; };

        typedef mp_impl_T<mp_null<dummy> > mp_null_impl;
    public:

        mfp_kernel_1_base_class (
            const mfp_kernel_1_base_class& item
        ) { item.mp()->clone(mp_memory.get()); }

        mfp_kernel_1_base_class (
        ) { mp_null_impl().safe_clone(mp_memory); }

        bool operator == (
            const mfp_kernel_1_base_class& item
        ) const { return mp()->is_same(item.mp()); }

        bool operator != (
            const mfp_kernel_1_base_class& item
        ) const { return !(*this == item); }

        mfp_kernel_1_base_class& operator= (
            const mfp_kernel_1_base_class& item
        ) { mfp_kernel_1_base_class(item).swap(*this); return *this;  }

        ~mfp_kernel_1_base_class (
        ) { destroy_mp_memory(); }

        void clear(
        ) { mfp_kernel_1_base_class().swap(*this); }

        bool is_set (
        ) const { return mp()->is_set(); }

    private:
        typedef void (dummy::*safe_bool)();

    public:
        operator safe_bool () const { return is_set() ? &dummy::nonnull : 0; }
        bool operator!() const { return !is_set(); }

        void swap (
            mfp_kernel_1_base_class& item
        )
        {
            // make a temp copy of item
            mfp_kernel_1_base_class temp(item);

            // destory the stuff in item
            item.destroy_mp_memory();
            // copy *this into item
            mp()->clone(item.mp_memory.get());

            // destory the stuff in this
            destroy_mp_memory();
            // copy temp into *this
            temp.mp()->clone(mp_memory.get());
        }

    protected:

        // The reason for adding 1 here is because visual studio 2003 will sometimes
        // try to compile this code with sizeof(mp_null_impl) == 0 (which is a bug in visual studio).
        // Fortunately, no actual real instances of this template seem to end up with that screwed up
        // value so everything works fine if we just add 1 so that this degenerate case doesn't cause
        // trouble.  Note that we know it all works fine because safe_clone() checks the size of this
        // memory block whenever the member function pointer is used.
        stack_based_memory_block<sizeof(mp_null_impl)+1> mp_memory;

        void destroy_mp_memory (
        )
        {
            // Honestly this probably doesn't even do anything but I'm putting
            // it here just for good measure.
            mp()->~mp_base_base();
        }

        mp_base_base*       mp ()       { return static_cast<mp_base_base*>(mp_memory.get()); }
        const mp_base_base* mp () const { return static_cast<const mp_base_base*>(mp_memory.get()); }

    };

// ----------------------------------------------------------------------------------------

    template <>
    class member_function_pointer<void,void,void,void> : public mfp_kernel_1_base_class<0>
    {
        class mp_base : public mp_base_base {
        public:
            mp_base(void* ptr, mfp_type type_) : mp_base_base(ptr,type_) {}
            virtual void call() const = 0;
        };

        template <typename T>
        class mp_impl : public mp_base {
        public:
            typedef void (T::*mfp_pointer_type)() ;
            void call () const { (static_cast<T*>(this->o)->*callback)(); }

            mp_impl      ( void* object, mfp_pointer_type cb) : mp_base(object, mfp_nonconst), callback(cb) {}
            const mfp_pointer_type callback;
        };

        template <typename T>
        class mp_impl_const : public mp_base {
        public:
            typedef void ((T::*mfp_pointer_type)()const);
            void call () const  { (static_cast<const T*>(this->o)->*callback)(); }

            mp_impl_const ( void* object, mfp_pointer_type cb) : mp_base(object,mfp_const), callback(cb) {}
            const mfp_pointer_type callback;
        };

    public:
        typedef void param1_type;
        typedef void param2_type;
        typedef void param3_type;
        typedef void param4_type;

        // These two typedefs are here for backwards compatibility with previous versions
        // of dlib.
        typedef member_function_pointer kernel_1a;
        typedef member_function_pointer kernel_1a_c;

        void operator() () const { DLIB_MFP_OC; static_cast<const mp_base*>(mp_memory.get())->call(); }

        // the reason for putting disable_if on this function is that it avoids an overload
        // resolution bug in visual studio.
        template <typename T> typename disable_if<is_const_type<T>,void>::type
        set(T& object, typename mp_impl<T>::mfp_pointer_type cb)
        { DLIB_MFP_SC;  destroy_mp_memory(); mp_impl_T<mp_impl<T> >(&object,cb).safe_clone(mp_memory); }

        template <typename T> void set(const T& object, typename mp_impl_const<T>::mfp_pointer_type cb)
        { DLIB_MFP_SC;  destroy_mp_memory(); mp_impl_T<mp_impl_const<T> >((void*)&object,cb).safe_clone(mp_memory); }

    };

// ----------------------------------------------------------------------------------------

    template <
        typename PARAM1
        >
    class member_function_pointer<PARAM1,void,void,void> : public mfp_kernel_1_base_class<1>
    {
        class mp_base : public mp_base_base {
        public:
            mp_base(void* ptr, mfp_type type_) : mp_base_base(ptr,type_) {}
            virtual void call(PARAM1) const = 0;
        };

        template <typename T>
        class mp_impl : public mp_base {
        public:
            typedef void (T::*mfp_pointer_type)(PARAM1) ;
            void call (PARAM1 p1) const { (static_cast<T*>(this->o)->*callback)(p1); }

            mp_impl      ( void* object, mfp_pointer_type cb) : mp_base(object, mfp_nonconst), callback(cb) {}
            const mfp_pointer_type callback;
        };

        template <typename T>
        class mp_impl_const : public mp_base {
        public:
            typedef void ((T::*mfp_pointer_type)(PARAM1)const);
            void call (PARAM1 p1) const  { (static_cast<const T*>(this->o)->*callback)(p1); }

            mp_impl_const ( void* object, mfp_pointer_type cb) : mp_base(object,mfp_const), callback(cb) {}
            const mfp_pointer_type callback;
        };

    public:
        typedef PARAM1 param1_type;
        typedef void param2_type;
        typedef void param3_type;
        typedef void param4_type;

        // These two typedefs are here for backwards compatibility with previous versions
        // of dlib.
        typedef member_function_pointer kernel_1a;
        typedef member_function_pointer kernel_1a_c;

        void operator() (PARAM1 p1) const { DLIB_MFP_OC;  static_cast<const mp_base*>(mp_memory.get())->call(p1); }

        // the reason for putting disable_if on this function is that it avoids an overload
        // resolution bug in visual studio.
        template <typename T> typename disable_if<is_const_type<T>,void>::type
        set(T& object, typename mp_impl<T>::mfp_pointer_type cb)
        { DLIB_MFP_SC;  destroy_mp_memory(); mp_impl_T<mp_impl<T> >(&object,cb).safe_clone(mp_memory); }

        template <typename T> void set(const T& object, typename mp_impl_const<T>::mfp_pointer_type cb)
        { DLIB_MFP_SC;  destroy_mp_memory(); mp_impl_T<mp_impl_const<T> >((void*)&object,cb).safe_clone(mp_memory); }

    };

// ----------------------------------------------------------------------------------------

    template <
        typename PARAM1,
        typename PARAM2
        >
    class member_function_pointer<PARAM1,PARAM2,void,void> : public mfp_kernel_1_base_class<2>
    {
        class mp_base : public mp_base_base {
        public:
            mp_base(void* ptr, mfp_type type_) : mp_base_base(ptr,type_) {}
            virtual void call(PARAM1,PARAM2) const = 0;
        };

        template <typename T>
        class mp_impl : public mp_base {
        public:
            typedef void (T::*mfp_pointer_type)(PARAM1,PARAM2) ;
            void call (PARAM1 p1, PARAM2 p2) const { (static_cast<T*>(this->o)->*callback)(p1,p2); }

            mp_impl      ( void* object, mfp_pointer_type cb) : mp_base(object, mfp_nonconst), callback(cb) {}
            const mfp_pointer_type callback;
        };

        template <typename T>
        class mp_impl_const : public mp_base {
        public:
            typedef void ((T::*mfp_pointer_type)(PARAM1,PARAM2)const);
            void call (PARAM1 p1, PARAM2 p2) const  { (static_cast<const T*>(this->o)->*callback)(p1,p2); }

            mp_impl_const ( void* object, mfp_pointer_type cb) : mp_base(object,mfp_const), callback(cb) {}
            const mfp_pointer_type callback;
        };

    public:
        typedef PARAM1 param1_type;
        typedef PARAM2 param2_type;
        typedef void param3_type;
        typedef void param4_type;

        // These two typedefs are here for backwards compatibility with previous versions
        // of dlib.
        typedef member_function_pointer kernel_1a;
        typedef member_function_pointer kernel_1a_c;

        void operator() (PARAM1 p1, PARAM2 p2) const { DLIB_MFP_OC;  static_cast<const mp_base*>(mp_memory.get())->call(p1,p2); }

        // the reason for putting disable_if on this function is that it avoids an overload
        // resolution bug in visual studio.
        template <typename T> typename disable_if<is_const_type<T>,void>::type
        set(T& object, typename mp_impl<T>::mfp_pointer_type cb)
        { DLIB_MFP_SC;  destroy_mp_memory(); mp_impl_T<mp_impl<T> >(&object,cb).safe_clone(mp_memory); }

        template <typename T> void set(const T& object, typename mp_impl_const<T>::mfp_pointer_type cb)
        { DLIB_MFP_SC;  destroy_mp_memory(); mp_impl_T<mp_impl_const<T> >((void*)&object,cb).safe_clone(mp_memory); }

    };

// ----------------------------------------------------------------------------------------

    template <
        typename PARAM1,
        typename PARAM2,
        typename PARAM3
        >
    class member_function_pointer<PARAM1,PARAM2,PARAM3,void> : public mfp_kernel_1_base_class<3>
    {
        class mp_base : public mp_base_base {
        public:
            mp_base(void* ptr, mfp_type type_) : mp_base_base(ptr,type_) {}
            virtual void call(PARAM1,PARAM2,PARAM3) const = 0;
        };

        template <typename T>
        class mp_impl : public mp_base {
        public:
            typedef void (T::*mfp_pointer_type)(PARAM1,PARAM2,PARAM3) ;
            void call (PARAM1 p1, PARAM2 p2, PARAM3 p3) const { (static_cast<T*>(this->o)->*callback)(p1,p2,p3); }

            mp_impl      ( void* object, mfp_pointer_type cb) : mp_base(object, mfp_nonconst), callback(cb) {}
            const mfp_pointer_type callback;
        };

        template <typename T>
        class mp_impl_const : public mp_base {
        public:
            typedef void ((T::*mfp_pointer_type)(PARAM1,PARAM2,PARAM3)const);
            void call (PARAM1 p1, PARAM2 p2, PARAM3 p3) const  { (static_cast<const T*>(this->o)->*callback)(p1,p2,p3); }

            mp_impl_const ( void* object, mfp_pointer_type cb) : mp_base(object,mfp_const), callback(cb) {}
            const mfp_pointer_type callback;
        };

    public:
        typedef PARAM1 param1_type;
        typedef PARAM2 param2_type;
        typedef PARAM3 param3_type;
        typedef void param4_type;

        // These two typedefs are here for backwards compatibility with previous versions
        // of dlib.
        typedef member_function_pointer kernel_1a;
        typedef member_function_pointer kernel_1a_c;

        void operator() (PARAM1 p1, PARAM2 p2, PARAM3 p3) const { DLIB_MFP_OC;  static_cast<const mp_base*>(mp_memory.get())->call(p1,p2,p3); }

        // the reason for putting disable_if on this function is that it avoids an overload
        // resolution bug in visual studio.
        template <typename T> typename disable_if<is_const_type<T>,void>::type
        set(T& object, typename mp_impl<T>::mfp_pointer_type cb)
        { DLIB_MFP_SC;  destroy_mp_memory(); mp_impl_T<mp_impl<T> >(&object,cb).safe_clone(mp_memory); }

        template <typename T> void set(const T& object, typename mp_impl_const<T>::mfp_pointer_type cb)
        { DLIB_MFP_SC;  destroy_mp_memory(); mp_impl_T<mp_impl_const<T> >((void*)&object,cb).safe_clone(mp_memory); }

    };

// ----------------------------------------------------------------------------------------

    template <
        typename PARAM1,
        typename PARAM2,
        typename PARAM3,
        typename PARAM4
        >
    class member_function_pointer : public mfp_kernel_1_base_class<4>
    {
        class mp_base : public mp_base_base {
        public:
            mp_base(void* ptr, mfp_type type_) : mp_base_base(ptr,type_) {}
            virtual void call(PARAM1,PARAM2,PARAM3,PARAM4) const = 0;
        };

        template <typename T>
        class mp_impl : public mp_base {
        public:
            typedef void (T::*mfp_pointer_type)(PARAM1,PARAM2,PARAM3, PARAM4) ;
            void call (PARAM1 p1, PARAM2 p2, PARAM3 p3, PARAM4 p4) const { (static_cast<T*>(this->o)->*callback)(p1,p2,p3,p4); }

            mp_impl      ( void* object, mfp_pointer_type cb) : mp_base(object, mfp_nonconst), callback(cb) {}
            const mfp_pointer_type callback;
        };

        template <typename T>
        class mp_impl_const : public mp_base {
        public:
            typedef void ((T::*mfp_pointer_type)(PARAM1,PARAM2,PARAM3,PARAM4)const);
            void call (PARAM1 p1, PARAM2 p2, PARAM3 p3, PARAM4 p4) const  { (static_cast<const T*>(this->o)->*callback)(p1,p2,p3,p4); }

            mp_impl_const ( void* object, mfp_pointer_type cb) : mp_base(object,mfp_const), callback(cb) {}
            const mfp_pointer_type callback;
        };

    public:
        typedef PARAM1 param1_type;
        typedef PARAM2 param2_type;
        typedef PARAM3 param3_type;
        typedef PARAM4 param4_type;

        // These two typedefs are here for backwards compatibility with previous versions
        // of dlib.
        typedef member_function_pointer kernel_1a;
        typedef member_function_pointer kernel_1a_c;

        void operator() (PARAM1 p1, PARAM2 p2, PARAM3 p3, PARAM4 p4) const
        { DLIB_MFP_OC;  static_cast<const mp_base*>(mp_memory.get())->call(p1,p2,p3,p4); }

        // the reason for putting disable_if on this function is that it avoids an overload
        // resolution bug in visual studio.
        template <typename T> typename disable_if<is_const_type<T>,void>::type
        set(T& object, typename mp_impl<T>::mfp_pointer_type cb)
        { DLIB_MFP_SC;  destroy_mp_memory(); mp_impl_T<mp_impl<T> >(&object,cb).safe_clone(mp_memory); }

        template <typename T> void set(const T& object, typename mp_impl_const<T>::mfp_pointer_type cb)
        { DLIB_MFP_SC;  destroy_mp_memory(); mp_impl_T<mp_impl_const<T> >((void*)&object,cb).safe_clone(mp_memory); }

    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MEMBER_FUNCTION_POINTER_KERNEl_1_


dlib C++ Library - memory_manager_kernel_1.h

// Copyright (C) 2004  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MEMORY_MANAGER_KERNEl_1_
#define DLIB_MEMORY_MANAGER_KERNEl_1_

#include "../algs.h"
#include "memory_manager_kernel_abstract.h"
#include "../assert.h"
#include <new>

namespace dlib
{

    template <
        typename T,
        unsigned long max_pool_size
        >
    class memory_manager_kernel_1
    {
        /*!
            INITIAL VALUE
                allocations == 0
                next == 0
                pool_size == 0

            REQUIREMENTS ON max_pool_size
                max_pool_size is the maximum number of nodes we will keep in our linked list at once.
                So you can put any value in for this argument.

            CONVENTION
                This memory manager implementation allocates T objects one at a time when there are
                allocation requests.  Then when there is a deallocate request the returning T object
                is place into a list of free blocks if that list has less than max_pool_size
                blocks in it.  subsequent allocation requests will be serviced by drawing from the
                free list whenever it isn't empty.

                allocations == get_number_of_allocations()

                - if (next != 0) then
                    - next == the next pointer to return from allocate()
                      and next == pointer to the first node in a linked list.  each node
                      is one item in the memory pool.
                    - the last node in the linked list has next set to 0
                    - pool_size == the number of nodes in the linked list
                    - pool_size <= max_pool_size
                - else
                    - we need to call new to get the next pointer to return from allocate()

        !*/

        union node
        {
            node* next;
            char item[sizeof(T)];
        };

    public:

        typedef T type;

        template <typename U>
        struct rebind {
            typedef memory_manager_kernel_1<U,max_pool_size> other;
        };

        memory_manager_kernel_1(
        ) :
            allocations(0),
            next(0),
            pool_size(0)
        {
        }

        virtual ~memory_manager_kernel_1(
        )
        {

            while (next != 0)
            {
                node* temp = next;
                next = next->next;
                ::operator delete ( static_cast<void*>(temp));
            }
        }

        unsigned long get_number_of_allocations (
        ) const { return allocations; }

        T* allocate_array (
            unsigned long size
        )
        {
            T* temp = new T[size];
            ++allocations;
            return temp;
        }

        void deallocate_array (
            T* item
        )
        {
            --allocations;
            delete [] item;
        }

        T* allocate (
        )
        {
            T* temp;
            if (next != 0)
            {
                temp = reinterpret_cast<T*>(next);

                node* n = next->next;

                try
                {
                    // construct this new T object with placement new.
                    new (static_cast<void*>(temp))T();
                }
                catch (...)
                {
                    next->next = n;
                    throw;
                }

                next = n;

                --pool_size;
            }
            else
            {
                temp = static_cast<T*>(::operator new(sizeof(node)));
                try
                {
                    // construct this new T object with placement new.
                    new (static_cast<void*>(temp))T();
                }
                catch (...)
                {
                    // construction of the new object threw so delete the block of memory
                    ::operator delete ( static_cast<void*>(temp));
                    throw;
                }
            }

            ++allocations;
            return temp;
        }

        void deallocate (
            T* item
        )
        {
            --allocations;
            item->~T();

            if (pool_size >= max_pool_size)
            {
                ::operator delete ( static_cast<void*>(item));
                return;
            }

            // add this memory chunk into our linked list.
            node* temp = reinterpret_cast<node*>(item);
            temp->next = next;
            next = temp;
            ++pool_size;
        }

        void swap (
            memory_manager_kernel_1& item
        )
        {
            exchange(allocations,item.allocations);
            exchange(next,item.next);
            exchange(pool_size,item.pool_size);
        }

    private:

        // data members
        unsigned long allocations;
        node* next;
        unsigned long pool_size;

        // restricted functions
        memory_manager_kernel_1(memory_manager_kernel_1&);        // copy constructor
        memory_manager_kernel_1& operator=(memory_manager_kernel_1&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    class memory_manager_kernel_1<T,0>
    {
        /*!
            INITIAL VALUE
                allocations == 0

            CONVENTION
                This memory manager just calls new and delete directly so it doesn't
                really do anything.

                allocations == get_number_of_allocations()
        !*/

    public:

        typedef T type;

        template <typename U>
        struct rebind {
            typedef memory_manager_kernel_1<U,0> other;
        };

        memory_manager_kernel_1(
        ) :
            allocations(0)
        {
        }

        virtual ~memory_manager_kernel_1(
        )
        {
        }

        unsigned long get_number_of_allocations (
        ) const { return allocations; }

        T* allocate_array (
            unsigned long size
        )
        {
            T* temp = new T[size];
            ++allocations;
            return temp;
        }

        void deallocate_array (
            T* item
        )
        {
            --allocations;
            delete [] item;
        }

        T* allocate (
        )
        {
            T* temp = new T;
            ++allocations;
            return temp;
        }

        void deallocate (
            T* item
        )
        {
            delete item;
            --allocations;
        }

        void swap (
            memory_manager_kernel_1& item
        )
        {
            exchange(allocations,item.allocations);
        }

    private:

        // data members
        unsigned long allocations;

        // restricted functions
        memory_manager_kernel_1(memory_manager_kernel_1&);        // copy constructor
        memory_manager_kernel_1& operator=(memory_manager_kernel_1&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        unsigned long max_pool_size
        >
    inline void swap (
        memory_manager_kernel_1<T,max_pool_size>& a,
        memory_manager_kernel_1<T,max_pool_size>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MEMORY_MANAGER_KERNEl_1_


dlib C++ Library - memory_manager_kernel_2.h

// Copyright (C) 2004  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MEMORY_MANAGER_KERNEl_2_
#define DLIB_MEMORY_MANAGER_KERNEl_2_

#include "../algs.h"
#include "memory_manager_kernel_abstract.h"
#include "../assert.h"
#include <new>

namespace dlib
{

    template <
        typename T,
        unsigned long chunk_size
        >
    class memory_manager_kernel_2
    {
        /*!
            INITIAL VALUE
                allocations == 0
                next == 0
                first_chunk == 0

            REQUIREMENTS ON chunk_size
                chunk_size is the number of items of type T we will allocate at a time. so
                it must be > 0.

            CONVENTION
                This memory manager implementation allocates memory in blocks of chunk_size*sizeof(T)
                bytes.  All the sizeof(T) subblocks are kept in a linked list of free memory blocks
                and are given out whenever an allocation request occurs.  Also, memory is not freed
                until this object is destructed.

                Note that array allocations are not memory managed.

                allocations == get_number_of_allocations()

                - if (next != 0) then
                    - next == the next pointer to return from allocate()
                      and next == pointer to the first node in a linked list.  each node
                      is one item in the memory pool.
                    - the last node in the linked list has next set to 0
                - else
                    - we need to call new to get the next pointer to return from allocate()

                - if (first_chunk != 0) then
                    - first_chunk == the first node in a linked list that contains pointers
                      to all the chunks we have ever allocated.  The last link in the list
                      has its next pointer set to 0.
        !*/

        union node
        {
            node* next;
            char item[sizeof(T)];
        };

        struct chunk_node
        {
            node* chunk;
            chunk_node* next;
        };

    public:

        typedef T type;

        template <typename U>
        struct rebind {
            typedef memory_manager_kernel_2<U,chunk_size> other;
        };

        memory_manager_kernel_2(
        ) :
            allocations(0),
            next(0),
            first_chunk(0)
        {
            // You FOOL!  You can't have a zero chunk_size.
            COMPILE_TIME_ASSERT(chunk_size > 0);
        }

        virtual ~memory_manager_kernel_2(
        )
        {
            if (allocations == 0)
            {
                while (first_chunk != 0)
                {
                    chunk_node* temp = first_chunk;
                    first_chunk = first_chunk->next;
                    // delete the memory chunk
                    ::operator delete ( static_cast<void*>(temp->chunk));
                    // delete the chunk_node
                    delete temp;
                }
            }
        }

        unsigned long get_number_of_allocations (
        ) const { return allocations; }

        T* allocate_array (
            unsigned long size
        )
        {
            T* temp = new T[size];
            ++allocations;
            return temp;
        }

        void deallocate_array (
            T* item
        )
        {
            --allocations;
            delete [] item;
        }

        T* allocate (
        )
        {
            T* temp = 0;
            if (next != 0)
            {
                temp = reinterpret_cast<T*>(next);
                node* n = next->next;

                try
                {
                    // construct this new T object with placement new.
                    new (static_cast<void*>(temp))T();
                }
                catch (...)
                {
                    next->next = n;
                    throw;
                }

                next = n;
            }
            else
            {
                // the linked list is empty so we need to allocate some more memory
                node* block = 0;
                block = static_cast<node*>(::operator new (sizeof(node)*chunk_size));

                // the first part of this block can be our new object
                temp = reinterpret_cast<T*>(block);

                try
                {
                    // construct this new T object with placement new.
                    new (static_cast<void*>(temp))T();
                }
                catch (...)
                {
                    // construction of the new object threw so delete the block of memory
                    ::operator delete ( static_cast<void*>(block));
                    throw;
                }

                // allocate a new chunk_node
                chunk_node* chunk;
                try {chunk = new chunk_node; }
                catch (...)
                {
                    temp->~T();
                    ::operator delete ( static_cast<void*>(block));
                    throw;
                }

                // add this block into the chunk list
                chunk->chunk = block;
                chunk->next = first_chunk;
                first_chunk = chunk;

                ++block;
                // now add the rest of the block into the linked list of free nodes.
                for (unsigned long i = 0; i < chunk_size-1; ++i)
                {
                    block->next = next;
                    next = block;
                    ++block;
                }

            }

            ++allocations;
            return temp;
        }

        void deallocate (
            T* item
        )
        {
            --allocations;
            item->~T();

            // add this memory into our linked list.
            node* temp = reinterpret_cast<node*>(item);
            temp->next = next;
            next = temp;
        }

        void swap (
            memory_manager_kernel_2& item
        )
        {
            exchange(allocations,item.allocations);
            exchange(next,item.next);
            exchange(first_chunk,item.first_chunk);
        }

    private:

        // data members
        unsigned long allocations;
        node* next;

        chunk_node* first_chunk;

        // restricted functions
        memory_manager_kernel_2(memory_manager_kernel_2&);        // copy constructor
        memory_manager_kernel_2& operator=(memory_manager_kernel_2&);    // assignment operator
    };

    template <
        typename T,
        unsigned long chunk_size
        >
    inline void swap (
        memory_manager_kernel_2<T,chunk_size>& a,
        memory_manager_kernel_2<T,chunk_size>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MEMORY_MANAGER_KERNEl_2_


dlib C++ Library - memory_manager_kernel_3.h

// Copyright (C) 2004  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MEMORY_MANAGER_KERNEl_3_
#define DLIB_MEMORY_MANAGER_KERNEl_3_

#include "../algs.h"
#include "memory_manager_kernel_abstract.h"
#include "../assert.h"
#include <new>
#include "memory_manager_kernel_2.h"
#include "../binary_search_tree/binary_search_tree_kernel_2.h"

namespace dlib
{

    template <
        typename T,
        unsigned long chunk_size
        >
    class memory_manager_kernel_3
    {
        /*!
            INITIAL VALUE
                allocations == 0
                next == 0
                first_chunk == 0
                bst_of_arrays == 0

            REQUIREMENTS ON chunk_size
                chunk_size is the number of items of type T we will allocate at a time. so
                it must be > 0.

            CONVENTION
                This memory manager implementation allocates memory in blocks of chunk_size*sizeof(T)
                bytes.  All the sizeof(T) subblocks are kept in a linked list of free memory blocks
                and are given out whenever an allocation request occurs.  Also, memory is not freed
                until this object is destructed.

                allocations == get_number_of_allocations()

                - if (next != 0) then
                    - next == the next pointer to return from allocate()
                      and next == pointer to the first node in a linked list.  each node
                      is one item in the memory pool.
                    - the last node in the linked list has next set to 0
                - else
                    - we need to call new to get the next pointer to return from allocate()

                - if (arrays != 0) then
                    - someone has called allocate_array()
                    - (*arrays)[size] == an array of size bytes of memory

                - if (first_chunk != 0) then
                    - first_chunk == the first node in a linked list that contains pointers
                      to all the chunks we have ever allocated.  The last link in the list
                      has its next pointer set to 0.
        !*/

        union node
        {
            node* next;
            char item[sizeof(T)];
        };

        struct chunk_node
        {
            node* chunk;
            chunk_node* next;
        };

        typedef binary_search_tree_kernel_2<
            size_t,
            char*,
            memory_manager_kernel_2<char,5>
            > bst_of_arrays;

    public:

        typedef T type;

        template <typename U>
        struct rebind {
            typedef memory_manager_kernel_3<U,chunk_size> other;
        };

        memory_manager_kernel_3(
        ) :
            allocations(0),
            next(0),
            first_chunk(0),
            arrays(0)
        {
            // You FOOL!  You can't have a zero chunk_size.
            COMPILE_TIME_ASSERT(chunk_size > 0);
        }

        virtual ~memory_manager_kernel_3(
        )
        {
            if (allocations == 0)
            {
                while (first_chunk != 0)
                {
                    chunk_node* temp = first_chunk;
                    first_chunk = first_chunk->next;
                    // delete the memory chunk
                    ::operator delete ( static_cast<void*>(temp->chunk));
                    // delete the chunk_node
                    delete temp;
                }
            }

            if (arrays)
            {
                arrays->reset();
                while (arrays->move_next())
                {
                    ::operator delete (arrays->element().value());
                }
                delete arrays;
            }
        }

        unsigned long get_number_of_allocations (
        ) const { return allocations; }

        T* allocate_array (
            unsigned long size
        )
        {
            size_t block_size = sizeof(T)*size + sizeof(size_t)*2;

            // make sure we have initialized the arrays object.
            if (arrays == 0)
            {
                arrays = new bst_of_arrays;
            }

            char* temp;

            // see if we have a suitable block of memory already.
            arrays->position_enumerator(block_size);
            if (arrays->current_element_valid())
            {
                // we have a suitable block of memory already so use that one.
                arrays->remove_current_element(block_size,temp);
            }
            else
            {
                temp = static_cast<char*>(::operator new(block_size));
            }

            reinterpret_cast<size_t*>(temp)[0] = block_size;
            reinterpret_cast<size_t*>(temp)[1] = size;
            temp += sizeof(size_t)*2;

            try
            {
                initialize_array(reinterpret_cast<T*>(temp),size);
            }
            catch (...)
            {
                // something was thrown while we were initializing the array so
                // stick our memory block into arrays and rethrow the exception
                temp -= sizeof(size_t)*2;
                arrays->add(block_size,temp);
                throw;
            }

            ++allocations;
            return reinterpret_cast<T*>(temp);
        }

        void deallocate_array (
            T* item
        )
        {
            char* temp = reinterpret_cast<char*>(item);
            temp -= sizeof(size_t)*2;
            size_t block_size = reinterpret_cast<size_t*>(temp)[0];
            size_t size = reinterpret_cast<size_t*>(temp)[1];

            deinitialize_array(item,size);

            arrays->add(block_size,temp);

            --allocations;
        }

        T* allocate (
        )
        {
            T* temp;
            if (next != 0)
            {
                temp = reinterpret_cast<T*>(next);
                node* n = next->next;

                try
                {
                    // construct this new T object with placement new.
                    new (static_cast<void*>(temp))T();
                }
                catch (...)
                {
                    next->next = n;
                    throw;
                }

                next = n;
            }
            else
            {
                // the linked list is empty so we need to allocate some more memory
                node* block = static_cast<node*>(::operator new (sizeof(node)*chunk_size));

                // the first part of this block can be our new object
                temp = reinterpret_cast<T*>(block);

                try
                {
                    // construct this new T object with placement new.
                    new (static_cast<void*>(temp))T();
                }
                catch (...)
                {
                    // construction of the new object threw so delete the block of memory
                    ::operator delete ( static_cast<void*>(block));
                    throw;
                }

                // allocate a new chunk_node
                chunk_node* chunk;
                try {chunk = new chunk_node; }
                catch (...)
                {
                    temp->~T();
                    ::operator delete ( static_cast<void*>(block));
                    throw;
                }

                // add this block into the chunk list
                chunk->chunk = block;
                chunk->next = first_chunk;
                first_chunk = chunk;

                ++block;
                // now add the rest of the block into the linked list of free nodes.
                for (unsigned long i = 0; i < chunk_size-1; ++i)
                {
                    block->next = next;
                    next = block;
                    ++block;
                }

            }

            ++allocations;
            return temp;
        }

        void deallocate (
            T* item
        )
        {
            --allocations;
            item->~T();

            // add this memory into our linked list.
            node* temp = reinterpret_cast<node*>(item);
            temp->next = next;
            next = temp;
        }

        void swap (
            memory_manager_kernel_3& item
        )
        {
            exchange(allocations,item.allocations);
            exchange(next,item.next);
            exchange(first_chunk,item.first_chunk);
            exchange(arrays,item.arrays);
        }

    private:

        // data members
        unsigned long allocations;
        node* next;

        chunk_node* first_chunk;
        bst_of_arrays* arrays;

        void initialize_array (
            T* array,
            size_t size
        ) const
        {
            size_t i;
            try
            {
                for (i = 0; i < size; ++i)
                {
                    // construct this new T object with placement new.
                    new (static_cast<void*>(array+i))T();
                }
            }
            catch (...)
            {
                // Catch any exceptions thrown during the construction process
                // and then destruct any T objects that actually were successfully
                // constructed.
                for (size_t j = 0; j < i; ++j)
                {
                    array[i].~T();
                }
                throw;
            }
        }

        void deinitialize_array (
            T* array,
            size_t size
        ) const
        {
            for (size_t i = 0; i < size; ++i)
            {
                array[i].~T();
            }
        }

        // don't do any initialization for the built in types
        void initialize_array(unsigned char*, size_t) {}
        void deinitialize_array(unsigned char*, size_t) {}
        void initialize_array(signed char*, size_t) {}
        void deinitialize_array(signed char*, size_t) {}
        void initialize_array(char*, size_t) {}
        void deinitialize_array(char*, size_t) {}
        void initialize_array(int*, size_t) {}
        void deinitialize_array(int*, size_t) {}
        void initialize_array(unsigned int*, size_t) {}
        void deinitialize_array(unsigned int*, size_t) {}
        void initialize_array(unsigned long*, size_t) {}
        void deinitialize_array(unsigned long*, size_t) {}
        void initialize_array(long*, size_t) {}
        void deinitialize_array(long*, size_t) {}
        void initialize_array(float*, size_t) {}
        void deinitialize_array(float*, size_t) {}
        void initialize_array(double*, size_t) {}
        void deinitialize_array(double*, size_t) {}
        void initialize_array(short*, size_t) {}
        void deinitialize_array(short*, size_t) {}
        void initialize_array(unsigned short*, size_t) {}
        void deinitialize_array(unsigned short*, size_t) {}

        // restricted functions
        memory_manager_kernel_3(memory_manager_kernel_3&);        // copy constructor
        memory_manager_kernel_3& operator=(memory_manager_kernel_3&);    // assignment operator
    };

    template <
        typename T,
        unsigned long chunk_size
        >
    inline void swap (
        memory_manager_kernel_3<T,chunk_size>& a,
        memory_manager_kernel_3<T,chunk_size>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MEMORY_MANAGER_KERNEl_3_


dlib C++ Library - memory_manager_global_kernel_1.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MEMORY_MANAGER_GLOBAl_1_
#define DLIB_MEMORY_MANAGER_GLOBAl_1_

#include "../algs.h"
#include "../memory_manager/memory_manager_kernel_abstract.h"
#include "memory_manager_global_kernel_abstract.h"

namespace dlib
{
    template <
        typename T,
        typename factory
        >
    class memory_manager_global_kernel_1
    {
        /*!
            INITIAL VALUE
                - *global_mm == get_global_memory_manager()

            CONVENTION
                - global_mm->get_number_of_allocations() == get_number_of_allocations()
                - *global_mm == get_global_memory_manager()
        !*/

        public:

            typedef typename factory::template return_type<T>::type mm_global_type;

            typedef T type;

            template <typename U>
            struct rebind {
                typedef memory_manager_global_kernel_1<U,factory> other;
            };

            memory_manager_global_kernel_1(
            ) :
                global_mm(factory::template get_instance<T>())
            {}

            virtual ~memory_manager_global_kernel_1(
            )  {}

            unsigned long get_number_of_allocations (
            ) const { return global_mm->get_number_of_allocations(); }

            mm_global_type& get_global_memory_manager (
            ) { return *global_mm; }

            T* allocate (
            )
            {
                return global_mm->allocate();
            }

            void deallocate (
                T* item
            )
            {
                global_mm->deallocate(item);
            }

            T* allocate_array (
                unsigned long size
            )
            {
                return global_mm->allocate_array(size);
            }

            void deallocate_array (
                T* item
            )
            {
                global_mm->deallocate_array(item);
            }

            void swap (
                memory_manager_global_kernel_1& item
            )
            {
                exchange(item.global_mm, global_mm);
            }

        private:

            mm_global_type* global_mm;

            // restricted functions
            memory_manager_global_kernel_1(memory_manager_global_kernel_1&);        // copy constructor
            memory_manager_global_kernel_1& operator=(memory_manager_global_kernel_1&);    // assignment operator
    };

    template <
        typename T,
        typename factory
        >
    inline void swap (
        memory_manager_global_kernel_1<T,factory>& a,
        memory_manager_global_kernel_1<T,factory>& b
    ) { a.swap(b); }
    /*!
        provides a global swap function
    !*/

}

#endif // DLIB_MEMORY_MANAGER_GLOBAl_1_


dlib C++ Library - memory_manager_stateless_kernel_1.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MEMORY_MANAGER_STATELESs_1_
#define DLIB_MEMORY_MANAGER_STATELESs_1_

#include "memory_manager_stateless_kernel_abstract.h"

namespace dlib
{
    template <
        typename T
        >
    class memory_manager_stateless_kernel_1
    {
        /*!
            this implementation just calls new and delete directly
        !*/

        public:

            typedef T type;
            const static bool is_stateless = true;

            template <typename U>
            struct rebind {
                typedef memory_manager_stateless_kernel_1<U> other;
            };

            memory_manager_stateless_kernel_1(
            )
            {}

            virtual ~memory_manager_stateless_kernel_1(
            ) {}

            T* allocate (
            )
            {
                return new T;
            }

            void deallocate (
                T* item
            )
            {
                delete item;
            }

            T* allocate_array (
                unsigned long size
            )
            {
                return new T[size];
            }

            void deallocate_array (
                T* item
            )
            {
                delete [] item;
            }

            void swap (memory_manager_stateless_kernel_1&)
            {}

        private:

            // restricted functions
            memory_manager_stateless_kernel_1(memory_manager_stateless_kernel_1&);        // copy constructor
            memory_manager_stateless_kernel_1& operator=(memory_manager_stateless_kernel_1&);    // assignment operator
    };

    template <
        typename T
        >
    inline void swap (
        memory_manager_stateless_kernel_1<T>& a,
        memory_manager_stateless_kernel_1<T>& b
    ) { a.swap(b); }

}

#endif // DLIB_MEMORY_MANAGER_STATELESs_1_


dlib C++ Library - memory_manager_stateless_kernel_2.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MEMORY_MANAGER_STATELESs_2_
#define DLIB_MEMORY_MANAGER_STATELESs_2_

#include "../algs.h"
#include "memory_manager_stateless_kernel_abstract.h"
#include "../threads.h"

namespace dlib
{
    template <
        typename T,
        typename mem_manager
        >
    class memory_manager_stateless_kernel_2
    {
        /*!
            REQUIREMENTS ON mem_manager
                mem_manager must be an implementation of memory_manager/memory_manager_kernel_abstract.h

            CONVENTION
                this object has a single global instance of mem_manager
        !*/

        public:

            typedef T type;
            const static bool is_stateless = true;

            template <typename U>
            struct rebind {
                typedef memory_manager_stateless_kernel_2<U,mem_manager> other;
            };

            memory_manager_stateless_kernel_2(
            )
            {
                // call this just to make sure the mutex is is initialized before
                // multiple threads start calling the member functions.
                global_mutex();
            }

            virtual ~memory_manager_stateless_kernel_2(
            ) {}

            T* allocate (
            )
            {
                auto_mutex M(global_mutex());
                return global_mm().allocate();
            }

            void deallocate (
                T* item
            )
            {
                auto_mutex M(global_mutex());
                return global_mm().deallocate(item);
            }

            T* allocate_array (
                unsigned long size
            )
            {
                auto_mutex M(global_mutex());
                return global_mm().allocate_array(size);
            }

            void deallocate_array (
                T* item
            )
            {
                auto_mutex M(global_mutex());
                return global_mm().deallocate_array(item);
            }

            void swap (memory_manager_stateless_kernel_2&)
            {}

        private:

            static mutex& global_mutex (
            )
            {
                static mutex lock;
                return lock;
            }

            typedef typename mem_manager::template rebind<T>::other rebound_mm_type;

            static rebound_mm_type& global_mm (
            )
            {
                static rebound_mm_type mm;
                return mm;
            }

            // restricted functions
            memory_manager_stateless_kernel_2(memory_manager_stateless_kernel_2&);        // copy constructor
            memory_manager_stateless_kernel_2& operator=(memory_manager_stateless_kernel_2&);    // assignment operator
    };

    template <
        typename T,
        typename mem_manager
        >
    inline void swap (
        memory_manager_stateless_kernel_2<T,mem_manager>& a,
        memory_manager_stateless_kernel_2<T,mem_manager>& b
    ) { a.swap(b); }

}

#endif // DLIB_MEMORY_MANAGER_STATELESs_2_


dlib C++ Library - misc_api_kernel_1.cpp

// Copyright (C) 2004  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MISC_API_KERNEL_1_CPp_
#define DLIB_MISC_API_KERNEL_1_CPp_

#include "../platform.h"
#include "../threads.h"

#ifdef WIN32

#include "misc_api_kernel_1.h"

#include "../windows_magic.h"
#include <windows.h>

// tell visual studio to link to the library needed to call timeGetTime()
#ifdef _MSC_VER
#pragma comment (lib, "winmm.lib")
#endif

#ifdef __BORLANDC__
// Apparently the borland compiler doesn't define this.
#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
#endif

namespace dlib
{
// ----------------------------------------------------------------------------------------

    void sleep (
        unsigned long milliseconds
    )
    {
        ::Sleep(milliseconds);
    }

// ----------------------------------------------------------------------------------------

    namespace
    {
        mutex& cwd_mutex()
        {
            static mutex m;
            return m;
        }
        // Make sure the above mutex gets constructed before main()
        // starts.  This way we can be pretty sure it will be constructed
        // before any threads could possibly call set_current_dir() or
        // get_current_dir() simultaneously.
        struct construct_cwd_mutex
        {
            construct_cwd_mutex()
            {
                cwd_mutex();
            }
        } oaimvweoinvwe;
    }

    std::string get_current_dir (
    )
    {
        // need to lock a mutex here because getting and setting the
        // current working directory is not thread safe on windows.
        auto_mutex lock(cwd_mutex());
        char buf[1024];
        if (GetCurrentDirectoryA(sizeof(buf),buf) == 0)
        {
            return std::string();
        }
        else
        {
            return std::string(buf);
        }
    }

// ----------------------------------------------------------------------------------------

    void set_current_dir (
        const std::string& new_dir
    )
    {
        // need to lock a mutex here because getting and setting the
        // current working directory is not thread safe on windows.
        auto_mutex lock(cwd_mutex());
        if (SetCurrentDirectoryA(new_dir.c_str()) == 0)
        {
            throw set_current_dir_error("Error changing current dir to '" + new_dir + "'");
        }
    }

// ----------------------------------------------------------------------------------------

    uint64 timestamper::
    get_timestamp (
    ) const
    {
        unsigned long temp = timeGetTime();
        if (temp >= last_time)
        {
            last_time = temp;
            return (offset + temp)*1000;
        }
        else
        {
            last_time = temp;

            // there was overflow since the last call so we need to make the offset
            // bigger to account for that
            offset += dword_max;
            return (offset + temp)*1000;
        }
    }

// ----------------------------------------------------------------------------------------

    void create_directory (
        const std::string& dir
    )
    {
        if (CreateDirectoryA(dir.c_str(),0) == 0)
        {
            // an error has occurred
            if (GetLastError() == ERROR_ALREADY_EXISTS)
            {
                // make sure this is actually a directory
                DWORD attribs = GetFileAttributesA(dir.c_str());
                if (attribs == INVALID_FILE_ATTRIBUTES ||
                    (attribs&FILE_ATTRIBUTE_DIRECTORY) == 0)
                {
                    // it isn't a directory
                    throw dir_create_error(dir);
                }
            }
            else
            {
                throw dir_create_error(dir);
            }
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // WIN32

#endif // DLIB_MISC_API_KERNEL_1_CPp_


dlib C++ Library - misc_api_kernel_1.h

// Copyright (C) 2004  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MISC_API_KERNEl_1_
#define DLIB_MISC_API_KERNEl_1_

#ifdef DLIB_ISO_CPP_ONLY
#error "DLIB_ISO_CPP_ONLY is defined so you can't use this OS dependent code.  Turn DLIB_ISO_CPP_ONLY off if you want to use it."
#endif

#include "misc_api_kernel_abstract.h"
#include "../algs.h"
#include <string>
#include "../uintn.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    void sleep (
        unsigned long milliseconds
    );

// ----------------------------------------------------------------------------------------

    std::string get_current_dir (
    );

// ----------------------------------------------------------------------------------------

    class set_current_dir_error : public error
    {
    public:
        set_current_dir_error(
            const std::string& a
        ): error(a) {}
    };

    void set_current_dir (
        const std::string& new_dir
    );

// ----------------------------------------------------------------------------------------

    class timestamper
    {
        /*!
            INITIAL VALUE
                - last_time == 0
                - offset == 0
                - dword_max == 2^32

            CONVENTION
                - last_time == the time returned by GetTickCount() the last time we
                  called it.
                - offset == the number of microseconds we should add to the result of
                  GetTickCount() so that it is correct.
                - dword_max == 2^32.
                  This is the number of values representable by a DWORD.
        !*/

        mutable unsigned long last_time;
        mutable uint64 offset;
        mutable uint64 dword_max;

    public:
        timestamper(
        ) :
            last_time(0),
            offset(0)
        {
            dword_max = 0xFFFFFFFF;
            ++dword_max;
        }

        uint64 get_timestamp (
        ) const;
    };

// ----------------------------------------------------------------------------------------

    class dir_create_error : public error
    {
    public:
        dir_create_error(
            const std::string& dir_name
        ) :
            error(EDIR_CREATE,"Error creating directory '" + dir_name + "'."),
            name(dir_name)
        {}

        ~dir_create_error() throw() {}
        const std::string name;
    };

    void create_directory (
        const std::string& dir
    );

// ----------------------------------------------------------------------------------------

}

#ifdef NO_MAKEFILE
#include "misc_api_kernel_1.cpp"
#endif

#endif // DLIB_MISC_API_KERNEl_1_


dlib C++ Library - misc_api_kernel_2.cpp

// Copyright (C) 2004  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MISC_API_KERNEL_2_CPp_
#define DLIB_MISC_API_KERNEL_2_CPp_
#include "../platform.h"

#ifdef POSIX

#include <unistd.h>
#include "misc_api_kernel_2.h"
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>

namespace dlib
{
// ----------------------------------------------------------------------------------------

    void sleep (
        unsigned long milliseconds
    )
    {
        // in HP-UX you can only usleep for less than a second
#ifdef HPUX
        if (milliseconds >= 1000)
        {
            ::sleep(milliseconds/1000);
            unsigned long remaining = milliseconds%1000;
            if (remaining > 0)
                ::usleep(remaining*1000);
        }
        else
        {
            ::usleep(milliseconds*1000);
        }
#else
        ::usleep(milliseconds*1000);
#endif
    }

// ----------------------------------------------------------------------------------------

    std::string get_current_dir (
    )
    {
        char buf[1024];
        if (getcwd(buf,sizeof(buf)) == 0)
        {
            return std::string();
        }
        else
        {
            return std::string(buf);
        }
    }

// ----------------------------------------------------------------------------------------

    void set_current_dir (
        const std::string& new_dir
    )
    {
        if (chdir(new_dir.c_str()))
        {
            throw set_current_dir_error("Error changing current dir to '" + new_dir + "'");
        }
    }

// ----------------------------------------------------------------------------------------

    uint64 timestamper::
    get_timestamp (
    ) const
    {
        uint64 ts;
        timeval curtime;
        gettimeofday(&curtime,0);

        ts = curtime.tv_sec;
        ts *= 1000000;
        ts += curtime.tv_usec;
        return ts;
    }

// ----------------------------------------------------------------------------------------

    void create_directory (
        const std::string& dir
    )
    {
        if (mkdir(dir.c_str(),0777))
        {
            // an error has occurred
            if (errno == EEXIST)
            {
                struct stat buffer;
                // now check that this is actually a valid directory
                if (::stat(dir.c_str(),&buffer))
                {
                    // the directory was not found
                    throw dir_create_error(dir);
                }
                else if (S_ISDIR(buffer.st_mode) == 0)
                {
                    // It is not a directory
                    throw dir_create_error(dir);
                }
            }
            else
            {
                throw dir_create_error(dir);
            }
        }
    }

// ----------------------------------------------------------------------------------------
}

#endif // POSIX

#endif // DLIB_MISC_API_KERNEL_2_CPp_


dlib C++ Library - misc_api_kernel_2.h

// Copyright (C) 2004  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MISC_API_KERNEl_2_
#define DLIB_MISC_API_KERNEl_2_

#ifdef DLIB_ISO_CPP_ONLY
#error "DLIB_ISO_CPP_ONLY is defined so you can't use this OS dependent code.  Turn DLIB_ISO_CPP_ONLY off if you want to use it."
#endif

#include "misc_api_kernel_abstract.h"
#include "../algs.h"
#include <string>
#include "../uintn.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    void sleep (
        unsigned long milliseconds
    );

// ----------------------------------------------------------------------------------------

    std::string get_current_dir (
    );

// ----------------------------------------------------------------------------------------

    class set_current_dir_error : public error
    {
    public:
        set_current_dir_error(
            const std::string& a
        ): error(a) {}
    };

    void set_current_dir (
        const std::string& new_dir
    );

// ----------------------------------------------------------------------------------------

    class timestamper
    {
    public:
        uint64 get_timestamp (
        ) const;
    };

// ----------------------------------------------------------------------------------------

    class dir_create_error : public error
    {
    public:
        dir_create_error(
            const std::string& dir_name
        ) :
            error(EDIR_CREATE,"Error creating directory '" + dir_name + "'."),
            name(dir_name)
        {}
        const std::string& name;
    };

    void create_directory (
        const std::string& dir
    );

// ----------------------------------------------------------------------------------------

}

#ifdef NO_MAKEFILE
#include "misc_api_kernel_2.cpp"
#endif

#endif // DLIB_MISC_API_KERNEl_2_


dlib C++ Library - misc_api_shared.h

// Copyright (C) 2014  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MISC_API_ShARED_Hh_
#define DLIB_MISC_API_ShARED_Hh_

#include <string>
#include "../noncopyable.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class locally_change_current_dir : noncopyable
    {
    public:
        explicit locally_change_current_dir (
            const std::string& new_dir
        )
        {
            reverted = false;
            _old_dir = get_current_dir();
            set_current_dir(new_dir);
        }

        ~locally_change_current_dir()
        {
            revert();
        }

        const std::string& old_dir (
        ) const
        {
            return _old_dir;
        }

        void revert (
        )
        {
            if (!reverted)
            {
                set_current_dir(_old_dir);
                reverted = true;
            }
        }

    private:
        bool reverted;
        std::string _old_dir;
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MISC_API_ShARED_Hh_


dlib C++ Library - posix.h

// Copyright (C) 2004  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MISC_API_KERNEl_1_
#include "misc_api_kernel_2.h"
#endif


dlib C++ Library - windows.h

// Copyright (C) 2004  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MISC_API_KERNEl_2_
#include "misc_api_kernel_1.h"
#endif


dlib C++ Library - mlp_kernel_1.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MLp_KERNEL_1_
#define DLIB_MLp_KERNEL_1_

#include "../algs.h"
#include "../serialize.h"
#include "../matrix.h"
#include "../rand.h"
#include "mlp_kernel_abstract.h"
#include <ctime>
#include <sstream>

namespace dlib
{

    class mlp_kernel_1 : noncopyable
    {
        /*!
            INITIAL VALUE
                The network is initially initialized with random weights

            CONVENTION
                - input_layer_nodes() == input_nodes
                - first_hidden_layer_nodes() == first_hidden_nodes
                - second_hidden_layer_nodes() == second_hidden_nodes
                - output_layer_nodes() == output_nodes
                - get_alpha == alpha
                - get_momentum() == momentum

                - if (second_hidden_nodes == 0) then
                    - for all i and j:
                        - w1(i,j) == the weight on the link from node i in the first hidden layer
                          to input node j
                        - w3(i,j) == the weight on the link from node i in the output layer
                          to first hidden layer node j
                    - for all i and j:
                        - w1m == the momentum terms for w1 from the previous update
                        - w3m == the momentum terms for w3 from the previous update
                - else
                    - for all i and j:
                        - w1(i,j) == the weight on the link from node i in the first hidden layer
                          to input node j
                        - w2(i,j) == the weight on the link from node i in the second hidden layer
                          to first hidden layer node j
                        - w3(i,j) == the weight on the link from node i in the output layer
                          to second hidden layer node j
                    - for all i and j:
                        - w1m == the momentum terms for w1 from the previous update
                        - w2m == the momentum terms for w2 from the previous update
                        - w3m == the momentum terms for w3 from the previous update
        !*/

    public:

        mlp_kernel_1 (
            long nodes_in_input_layer,
            long nodes_in_first_hidden_layer,
            long nodes_in_second_hidden_layer = 0,
            long nodes_in_output_layer = 1,
            double alpha_ = 0.1,
            double momentum_ = 0.8
        ) :
            input_nodes(nodes_in_input_layer),
            first_hidden_nodes(nodes_in_first_hidden_layer),
            second_hidden_nodes(nodes_in_second_hidden_layer),
            output_nodes(nodes_in_output_layer),
            alpha(alpha_),
            momentum(momentum_)
        {

            // seed the random number generator
            std::ostringstream sout;
            sout << time(0);
            rand_nums.set_seed(sout.str());

            w1.set_size(first_hidden_nodes+1, input_nodes+1);
            w1m.set_size(first_hidden_nodes+1, input_nodes+1);
            z.set_size(input_nodes+1,1);

            if (second_hidden_nodes != 0)
            {
                w2.set_size(second_hidden_nodes+1, first_hidden_nodes+1);
                w3.set_size(output_nodes, second_hidden_nodes+1);

                w2m.set_size(second_hidden_nodes+1, first_hidden_nodes+1);
                w3m.set_size(output_nodes, second_hidden_nodes+1);
            }
            else
            {
                w3.set_size(output_nodes, first_hidden_nodes+1);

                w3m.set_size(output_nodes, first_hidden_nodes+1);
            }

            reset();
        }

        virtual ~mlp_kernel_1 (
        ) {}

        void reset (
        )
        {
            // randomize the weights for the first layer
            for (long r = 0; r < w1.nr(); ++r)
                for (long c = 0; c < w1.nc(); ++c)
                    w1(r,c) = rand_nums.get_random_double();

            // randomize the weights for the second layer
            for (long r = 0; r < w2.nr(); ++r)
                for (long c = 0; c < w2.nc(); ++c)
                    w2(r,c) = rand_nums.get_random_double();

            // randomize the weights for the third layer
            for (long r = 0; r < w3.nr(); ++r)
                for (long c = 0; c < w3.nc(); ++c)
                    w3(r,c) = rand_nums.get_random_double();

            // zero all the momentum terms
            set_all_elements(w1m,0);
            set_all_elements(w2m,0);
            set_all_elements(w3m,0);
        }

        long input_layer_nodes (
        ) const { return input_nodes; }

        long first_hidden_layer_nodes (
        ) const { return first_hidden_nodes; }

        long second_hidden_layer_nodes (
        ) const { return second_hidden_nodes; }

        long output_layer_nodes (
        ) const { return output_nodes; }

        double get_alpha (
        ) const { return alpha; }

        double get_momentum (
        ) const { return momentum; }

        template <typename EXP>
        const matrix<double> operator() (
            const matrix_exp<EXP>& in
        ) const
        {
            for (long i = 0; i < in.nr(); ++i)
                z(i) = in(i);
            // insert the bias
            z(z.nr()-1) = -1;

            tmp1 = sigmoid(w1*z);
            // insert the bias
            tmp1(tmp1.nr()-1) = -1;

            if (second_hidden_nodes == 0)
            {
                return sigmoid(w3*tmp1);
            }
            else
            {
                tmp2 = sigmoid(w2*tmp1);
                // insert the bias
                tmp2(tmp2.nr()-1) = -1;

                return sigmoid(w3*tmp2);
            }
        }

        template <typename EXP1, typename EXP2>
        void train (
            const matrix_exp<EXP1>& example_in,
            const matrix_exp<EXP2>& example_out
        )
        {
            for (long i = 0; i < example_in.nr(); ++i)
                z(i) = example_in(i);
            // insert the bias
            z(z.nr()-1) = -1;

            tmp1 = sigmoid(w1*z);
            // insert the bias
            tmp1(tmp1.nr()-1) = -1;

            if (second_hidden_nodes == 0)
            {
                o = sigmoid(w3*tmp1);

                // now compute the errors and propagate them backwards though the network
                e3 = pointwise_multiply(example_out-o, uniform_matrix<double>(output_nodes,1,1.0)-o, o);
                e1 = pointwise_multiply(tmp1, uniform_matrix<double>(first_hidden_nodes+1,1,1.0) - tmp1, trans(w3)*e3 );

                // compute the new weight updates
                w3m = alpha * e3*trans(tmp1) + w3m*momentum;
                w1m = alpha * e1*trans(z)    + w1m*momentum;

                // now update the weights
                w1 += w1m;
                w3 += w3m;
            }
            else
            {
                tmp2 = sigmoid(w2*tmp1);
                // insert the bias
                tmp2(tmp2.nr()-1) = -1;

                o = sigmoid(w3*tmp2);

                // now compute the errors and propagate them backwards though the network
                e3 = pointwise_multiply(example_out-o, uniform_matrix<double>(output_nodes,1,1.0)-o, o);
                e2 = pointwise_multiply(tmp2, uniform_matrix<double>(second_hidden_nodes+1,1,1.0) - tmp2, trans(w3)*e3 );
                e1 = pointwise_multiply(tmp1, uniform_matrix<double>(first_hidden_nodes+1,1,1.0) - tmp1, trans(w2)*e2 );

                // compute the new weight updates
                w3m = alpha * e3*trans(tmp2) + w3m*momentum;
                w2m = alpha * e2*trans(tmp1) + w2m*momentum;
                w1m = alpha * e1*trans(z)    + w1m*momentum;

                // now update the weights
                w1 += w1m;
                w2 += w2m;
                w3 += w3m;
            }
        }

        template <typename EXP>
        void train (
            const matrix_exp<EXP>& example_in,
            double example_out
        )
        {
            matrix<double,1,1> e_out;
            e_out(0) = example_out;
            train(example_in,e_out);
        }

        double get_average_change (
        ) const
        {
            // sum up all the weight changes
            double delta = sum(abs(w1m)) + sum(abs(w2m)) + sum(abs(w3m));

            // divide by the number of weights
            delta /=  w1m.nr()*w1m.nc() +
                w2m.nr()*w2m.nc() +
                w3m.nr()*w3m.nc();

            return delta;
        }

        void swap (
            mlp_kernel_1& item
        )
        {
            exchange(input_nodes, item.input_nodes);
            exchange(first_hidden_nodes, item.first_hidden_nodes);
            exchange(second_hidden_nodes, item.second_hidden_nodes);
            exchange(output_nodes, item.output_nodes);
            exchange(alpha, item.alpha);
            exchange(momentum, item.momentum);

            w1.swap(item.w1);
            w2.swap(item.w2);
            w3.swap(item.w3);

            w1m.swap(item.w1m);
            w2m.swap(item.w2m);
            w3m.swap(item.w3m);

            // even swap the temporary matrices because this may ultimately result in
            // fewer calls to new and delete.
            e1.swap(item.e1);
            e2.swap(item.e2);
            e3.swap(item.e3);
            z.swap(item.z);
            tmp1.swap(item.tmp1);
            tmp2.swap(item.tmp2);
            o.swap(item.o);
        }

        friend void serialize (
            const mlp_kernel_1& item,
            std::ostream& out
        );

        friend void deserialize (
            mlp_kernel_1& item,
            std::istream& in
        );

    private:

        long input_nodes;
        long first_hidden_nodes;
        long second_hidden_nodes;
        long output_nodes;
        double alpha;
        double momentum;

        matrix<double> w1;
        matrix<double> w2;
        matrix<double> w3;

        matrix<double> w1m;
        matrix<double> w2m;
        matrix<double> w3m;

        rand rand_nums;

        // temporary storage
        mutable matrix<double> e1, e2, e3;
        mutable matrix<double> z, tmp1, tmp2, o;
    };

    inline void swap (
        mlp_kernel_1& a,
        mlp_kernel_1& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------

    inline void serialize (
        const mlp_kernel_1& item,
        std::ostream& out
    )
    {
        try
        {
            serialize(item.input_nodes, out);
            serialize(item.first_hidden_nodes, out);
            serialize(item.second_hidden_nodes, out);
            serialize(item.output_nodes, out);
            serialize(item.alpha, out);
            serialize(item.momentum, out);

            serialize(item.w1, out);
            serialize(item.w2, out);
            serialize(item.w3, out);

            serialize(item.w1m, out);
            serialize(item.w2m, out);
            serialize(item.w3m, out);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while serializing object of type mlp_kernel_1");
        }
    }

    inline void deserialize (
        mlp_kernel_1& item,
        std::istream& in
    )
    {
        try
        {
            deserialize(item.input_nodes, in);
            deserialize(item.first_hidden_nodes, in);
            deserialize(item.second_hidden_nodes, in);
            deserialize(item.output_nodes, in);
            deserialize(item.alpha, in);
            deserialize(item.momentum, in);

            deserialize(item.w1, in);
            deserialize(item.w2, in);
            deserialize(item.w3, in);

            deserialize(item.w1m, in);
            deserialize(item.w2m, in);
            deserialize(item.w3m, in);

            item.z.set_size(item.input_nodes+1,1);
        }
        catch (serialization_error& e)
        {
            // give item a reasonable value since the deserialization failed
            mlp_kernel_1(1,1).swap(item);
            throw serialization_error(e.info + "\n   while deserializing object of type mlp_kernel_1");
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MLp_KERNEL_1_


dlib C++ Library - find_max_factor_graph_nmplp.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_FIND_MAX_FACTOR_GRAPH_nMPLP_Hh_
#define DLIB_FIND_MAX_FACTOR_GRAPH_nMPLP_Hh_

#include "find_max_factor_graph_nmplp_abstract.h"
#include <vector>
#include <map>
#include "../matrix.h"
#include "../hash.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    namespace impl
    {
        class simple_hash_map
        {
        public:

            simple_hash_map(
            ) :
                scan_dist(6)
            {
                data.resize(5000);
            }

            void insert (
                const unsigned long a,
                const unsigned long b,
                const unsigned long value
            )
            /*!
                requires
                    - a != std::numeric_limits<unsigned long>::max()
                ensures
                    - #(*this)(a,b) == value
            !*/
            {
                const uint32 h = murmur_hash3_2(a,b)%(data.size()-scan_dist);

                const unsigned long empty_bucket = std::numeric_limits<unsigned long>::max();

                for (uint32 i = 0; i < scan_dist; ++i)
                {
                    if (data[i+h].key1 == empty_bucket)
                    {
                        data[i+h].key1 = a;
                        data[i+h].key2 = b;
                        data[i+h].value = value;
                        return;
                    }
                }

                // if we get this far it means the hash table is filling up.  So double its size.
                std::vector<bucket> new_data;
                new_data.resize(data.size()*2);
                new_data.swap(data);
                for (uint32 i = 0; i < new_data.size(); ++i)
                {
                    if (new_data[i].key1 != empty_bucket)
                    {
                        insert(new_data[i].key1, new_data[i].key2, new_data[i].value);
                    }
                }

                insert(a,b,value);
            }

            unsigned long operator() (
                const unsigned long a,
                const unsigned long b
            ) const
            /*!
                requires
                    - this->insert(a,b,some_value) has been called
                ensures
                    - returns the value stored at key (a,b)
            !*/
            {
                DLIB_ASSERT(a != b, "An invalid map_problem was given to find_max_factor_graph_nmplp()."
                            << "\nNode " << a << " is listed as being a neighbor with itself, which is illegal.");

                uint32 h = murmur_hash3_2(a,b)%(data.size()-scan_dist);

                for (unsigned long i = 0; i < scan_dist; ++i)
                {
                    if (data[h].key1 == a && data[h].key2 == b)
                    {
                        return data[h].value;
                    }
                    ++h;
                }

                // this should never happen (since this function requires (a,b) to be in the hash table
                DLIB_ASSERT(false, "An invalid map_problem was given to find_max_factor_graph_nmplp()."
                            << "\nThe nodes in the map_problem are inconsistent because node "<<a<<" is in the neighbor list"
                            << "\nof node "<<b<< " but node "<<b<<" isn't in the neighbor list of node "<<a<<".  The neighbor relationship"
                            << "\nis supposed to be symmetric."
                            );
                return 0;
            }

        private:

            struct bucket
            {
                // having max() in key1 indicates that the bucket isn't used.
                bucket() : key1(std::numeric_limits<unsigned long>::max()) {}
                unsigned long key1;
                unsigned long key2;
                unsigned long value;
            };

            std::vector<bucket> data;
            const unsigned int scan_dist;
        };
    }

// ----------------------------------------------------------------------------------------

    template <
        typename map_problem
        >
    void find_max_factor_graph_nmplp (
        const map_problem& prob,
        std::vector<unsigned long>& map_assignment,
        unsigned long max_iter,
        double eps
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( eps > 0,
                     "\t void find_max_factor_graph_nmplp()"
                     << "\n\t eps must be greater than zero"
                     << "\n\t eps:  " << eps
                );

        /*
            This function is an implementation of the NMPLP algorithm introduced in the
            following papers:
                Fixing Max-Product: Convergent Message Passing Algorithms for MAP LP-Relaxations (2008)
                by Amir Globerson and Tommi Jaakkola

                Introduction to dual decomposition for inference (2011)
                by David Sontag, Amir Globerson, and Tommi Jaakkola

            In particular, this function implements the star MPLP update equations shown as
            equation 1.20 from the paper Introduction to dual decomposition for inference
            (the method was called NMPLP in the first paper).  It should also be noted that
            the original description of the NMPLP in the first paper had an error in the
            equations and the second paper contains corrected equations, which is what this
            function uses.
        */

        typedef typename map_problem::node_iterator node_iterator;
        typedef typename map_problem::neighbor_iterator neighbor_iterator;

        map_assignment.resize(prob.number_of_nodes());

        if (prob.number_of_nodes() == 0)
            return;

        std::vector<double> delta_elements;
        delta_elements.reserve(prob.number_of_nodes()*prob.num_states(prob.begin())*3);

        impl::simple_hash_map delta_idx;

        // Initialize delta to zero and fill up the hash table with the appropriate values
        // so we can index into delta later on.
        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);
                delta_idx.insert(id_i, id_j, delta_elements.size());

                const unsigned long num_states_xj = prob.num_states(j);
                for (unsigned long xj = 0; xj < num_states_xj; ++xj)
                    delta_elements.push_back(0);
            }
        }

        std::vector<double> gamma_i;
        std::vector<std::vector<double> > gamma_ji;
        std::vector<std::vector<double> > delta_to_j_no_i;
        // These arrays will end up with a length equal to the maximum number of neighbors
        // of any node in the graph.  So reserve a bigish number of slots so that we are
        // very unlikely to need to preform an expensive reallocation during the
        // optimization.
        gamma_ji.reserve(10000);
        delta_to_j_no_i.reserve(10000);

        double max_change = eps + 1;
        // Now do the main body of the optimization.
        unsigned long iter;
        for (iter = 0; iter < max_iter && max_change > eps; ++iter)
        {
            max_change = -std::numeric_limits<double>::infinity();

            for (node_iterator i = prob.begin(); i != prob.end(); ++i)
            {
                const unsigned long id_i = prob.node_id(i);
                const unsigned long num_states_xi = prob.num_states(i);
                gamma_i.assign(num_states_xi, 0);

                double num_neighbors = 0;

                unsigned int jcnt = 0;
                // first we fill in the gamma vectors
                for (neighbor_iterator j = prob.begin(i); j != prob.end(i); ++j)
                {
                    // Make sure these arrays are big enough to hold all the neighbor
                    // information.
                    if (jcnt >= gamma_ji.size())
                    {
                        gamma_ji.resize(gamma_ji.size()+1);
                        delta_to_j_no_i.resize(delta_to_j_no_i.size()+1);
                    }

                    ++num_neighbors;
                    const unsigned long id_j = prob.node_id(j);
                    const unsigned long num_states_xj = prob.num_states(j);

                    gamma_ji[jcnt].assign(num_states_xi, -std::numeric_limits<double>::infinity());
                    delta_to_j_no_i[jcnt].assign(num_states_xj, 0);

                    // compute delta_j^{-i} and store it in delta_to_j_no_i[jcnt]
                    for (neighbor_iterator k = prob.begin(j); k != prob.end(j); ++k)
                    {
                        const unsigned long id_k = prob.node_id(k);
                        if (id_k==id_i)
                            continue;
                        const double* const delta_kj = &delta_elements[delta_idx(id_k,id_j)];
                        for (unsigned long xj = 0; xj < num_states_xj; ++xj)
                        {
                            delta_to_j_no_i[jcnt][xj] += delta_kj[xj];
                        }
                    }

                    // now compute gamma values
                    for (unsigned long xi = 0; xi < num_states_xi; ++xi)
                    {
                        for (unsigned long xj = 0; xj < num_states_xj; ++xj)
                        {
                            gamma_ji[jcnt][xi] = std::max(gamma_ji[jcnt][xi], prob.factor_value(i,j,xi,xj) + delta_to_j_no_i[jcnt][xj]);
                        }
                        gamma_i[xi] += gamma_ji[jcnt][xi];
                    }
                    ++jcnt;
                }

                // now update the delta values
                jcnt = 0;
                for (neighbor_iterator j = prob.begin(i); j != prob.end(i); ++j)
                {
                    const unsigned long id_j = prob.node_id(j);
                    const unsigned long num_states_xj = prob.num_states(j);

                    // messages from j to i
                    double* const delta_ji = &delta_elements[delta_idx(id_j,id_i)];

                    // messages from i to j
                    double* const delta_ij = &delta_elements[delta_idx(id_i,id_j)];

                    for (unsigned long xj = 0; xj < num_states_xj; ++xj)
                    {
                        double best_val = -std::numeric_limits<double>::infinity();

                        for (unsigned long xi = 0; xi < num_states_xi; ++xi)
                        {
                            double val = prob.factor_value(i,j,xi,xj) + 2/(num_neighbors+1)*gamma_i[xi] -gamma_ji[jcnt][xi];
                            if (val > best_val)
                                best_val = val;
                        }
                        best_val = -0.5*delta_to_j_no_i[jcnt][xj] + 0.5*best_val;

                        if (std::abs(delta_ij[xj] - best_val) > max_change)
                            max_change = std::abs(delta_ij[xj] - best_val);

                        delta_ij[xj] = best_val;
                    }

                    for (unsigned long xi = 0; xi < num_states_xi; ++xi)
                    {
                        double new_val = -1/(num_neighbors+1)*gamma_i[xi] + gamma_ji[jcnt][xi];
                        if (std::abs(delta_ji[xi] - new_val) > max_change)
                            max_change = std::abs(delta_ji[xi] - new_val);
                        delta_ji[xi] = new_val;
                    }
                    ++jcnt;
                }
            }
        }

        // now decode the "beliefs"
        std::vector<double> b;
        for (node_iterator i = prob.begin(); i != prob.end(); ++i)
        {
            const unsigned long id_i = prob.node_id(i);
            b.assign(prob.num_states(i), 0);

            for (neighbor_iterator k = prob.begin(i); k != prob.end(i); ++k)
            {
                const unsigned long id_k = prob.node_id(k);

                for (unsigned long xi = 0; xi < b.size(); ++xi)
                {
                    const double* const delta_ki = &delta_elements[delta_idx(id_k,id_i)];
                    b[xi] += delta_ki[xi];
                }
            }

            map_assignment[id_i] = index_of_max(mat(b));
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_FIND_MAX_FACTOR_GRAPH_nMPLP_Hh_


dlib C++ Library - find_max_factor_graph_viterbi.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_FIND_MAX_FACTOR_GRAPH_VITERBi_Hh_
#define DLIB_FIND_MAX_FACTOR_GRAPH_VITERBi_Hh_

#include "find_max_factor_graph_viterbi_abstract.h"
#include <vector>
#include "../matrix.h"
#include "../array2d.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    namespace impl
    {
        struct viterbi_data
        {
            viterbi_data() :val(-std::numeric_limits<double>::infinity()), back_index(0) {}
            double val;
            unsigned long back_index;
        };

        template <long NC>
        inline bool advance_state(
            matrix<unsigned long,1,NC>& node_states,
            unsigned long num_states
        )
        /*!
            ensures
                - advances node_states to the next state by adding 1
                  to node_states(node_states.size()-1) and carrying any
                  rollover (modulo num_states).  Stores the result into #node_states.
                - if (#node_states is all zeros) then
                    - returns false
                - else
                    - returns true
        !*/
        {
            for (long i = node_states.size()-1; i >= 0; --i)
            {
                node_states(i) += 1;
                if (node_states(i) < num_states)
                    return true;

                node_states(i) = 0;
            }
            return false;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename map_problem
        >
    void find_max_factor_graph_viterbi (
        const map_problem& prob,
        std::vector<unsigned long>& map_assignment
    )
    {
        using namespace dlib::impl;
        const unsigned long order = prob.order();
        const unsigned long num_states = prob.num_states();

        DLIB_ASSERT(prob.num_states() > 0,
            "\t void find_max_factor_graph_viterbi()"
            << "\n\t The nodes in a factor graph have to be able to take on more than 0 states."
            );
        DLIB_ASSERT(std::pow(num_states,(double)order) < std::numeric_limits<unsigned long>::max(),
            "\t void find_max_factor_graph_viterbi()"
            << "\n\t The order is way too large for this algorithm to handle."
            << "\n\t order:      " << order
            << "\n\t num_states: " << num_states
            << "\n\t std::pow(num_states,order):                " << std::pow(num_states,(double)order)
            << "\n\t std::numeric_limits<unsigned long>::max(): " << std::numeric_limits<unsigned long>::max()
            );

        if (prob.number_of_nodes() == 0)
        {
            map_assignment.clear();
            return;
        }

        if (order == 0)
        {
            map_assignment.resize(prob.number_of_nodes());
            for (unsigned long i = 0; i < map_assignment.size(); ++i)
            {
                matrix<unsigned long,1,1> node_state;
                unsigned long best_state = 0;
                double best_val = -std::numeric_limits<double>::infinity();
                for (unsigned long s = 0; s < num_states; ++s)
                {
                    node_state(0) = s;
                    const double temp = prob.factor_value(i,node_state);
                    if (temp > best_val)
                    {
                        best_val = temp;
                        best_state = s;
                    }
                }
                map_assignment[i] = best_state;
            }
            return;
        }

        const unsigned long trellis_size = static_cast<unsigned long>(std::pow(num_states,(double)order));
        unsigned long init_ring_size = 1;

        array2d<impl::viterbi_data> trellis;
        trellis.set_size(prob.number_of_nodes(), trellis_size);

        for (unsigned long node = 0; node < prob.number_of_nodes(); ++node)
        {

            if (node < order)
            {
                matrix<unsigned long,1,0> node_states;
                node_states.set_size(std::min<int>(node, order) + 1);
                node_states = 0;

                unsigned long idx = 0;
                if (node == 0)
                {
                    do
                    {
                        trellis[node][idx].val = prob.factor_value(node,node_states);
                        ++idx;
                    } while(advance_state(node_states,num_states));
                }
                else
                {
                    init_ring_size *= num_states;
                    do
                    {
                        const unsigned long back_index = idx%init_ring_size;
                        trellis[node][idx].val = prob.factor_value(node,node_states) + trellis[node-1][back_index].val;
                        trellis[node][idx].back_index = back_index;
                        ++idx;
                    } while(advance_state(node_states,num_states));

                }
            }
            else if (order == 1)
            {
                /*
                    WHAT'S THE DEAL WITH THIS PREPROCESSOR MACRO?
                        Well, if we can declare the dimensions of node_states as a compile
                        time constant then this function runs significantly faster.  So this macro
                        is here to let us do that.  It just lets us avoid replicating this code
                        block in the following if statements for different order sizes.
                */
#define DLIB_FMFGV_WORK                                                                                                     \
                node_states = 0;                                                                                            \
                unsigned long count = 0;                                                                                    \
                for (unsigned long i = 0; i < trellis_size; ++i)                                                            \
                {                                                                                                           \
                    unsigned long back_index = 0;                                                                           \
                    double best_score = -std::numeric_limits<double>::infinity();                                           \
                    for (unsigned long s = 0; s < num_states; ++s)                                                          \
                    {                                                                                                       \
                        const double temp = prob.factor_value(node,node_states) + trellis[node-1][count%trellis_size].val;  \
                        if (temp > best_score)                                                                              \
                        {                                                                                                   \
                            best_score = temp;                                                                              \
                            back_index = count%trellis_size;                                                                \
                        }                                                                                                   \
                        advance_state(node_states,num_states);                                                              \
                        ++count;                                                                                            \
                    }                                                                                                       \
                    trellis[node][i].val = best_score;                                                                      \
                    trellis[node][i].back_index = back_index;                                                               \
                }

                matrix<unsigned long,1,2> node_states;
                DLIB_FMFGV_WORK
            }
            else if (order == 2)
            {
                matrix<unsigned long,1,3> node_states;
                DLIB_FMFGV_WORK
            }
            else if (order == 3)
            {
                matrix<unsigned long,1,4> node_states;
                DLIB_FMFGV_WORK
            }
            else
            {
                // The general case, here we don't define the size of node_states at compile time.
                matrix<unsigned long,1,0> node_states(order+1);
                DLIB_FMFGV_WORK
            }
        }

        map_assignment.resize(prob.number_of_nodes());
        // Figure out which state of the last node has the biggest value.
        unsigned long back_index = 0;
        double best_val = -std::numeric_limits<double>::infinity();
        for (long i = 0; i < trellis.nc(); ++i)
        {
            if (trellis[trellis.nr()-1][i].val > best_val)
            {
                best_val = trellis[trellis.nr()-1][i].val;
                back_index = i;
            }
        }
        // Follow the back links to find the decoding.
        for (long node = map_assignment.size()-1; node >= 0; --node)
        {
            map_assignment[node] = back_index/init_ring_size;
            back_index = trellis[node][back_index].back_index;
            if (node < (long)order)
                init_ring_size /= num_states;
        }

    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_FIND_MAX_FACTOR_GRAPH_VITERBi_Hh_


dlib C++ Library - find_max_parse_cky.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_FIND_MAX_PaRSE_CKY_Hh_
#define DLIB_FIND_MAX_PaRSE_CKY_Hh_

#include "find_max_parse_cky_abstract.h"
#include <vector>
#include <string>
#include <sstream>
#include "../serialize.h"
#include "../array2d.h"

namespace dlib
{

// -----------------------------------------------------------------------------------------

    template <typename T>
    struct constituent
    {
        unsigned long begin, end, k;
        T left_tag;
        T right_tag;
    };

    template <typename T>
    void serialize(
        const constituent<T>& item,
        std::ostream& out
    )
    {
        serialize(item.begin, out);
        serialize(item.end, out);
        serialize(item.k, out);
        serialize(item.left_tag, out);
        serialize(item.right_tag, out);
    }

    template <typename T>
    void deserialize(
        constituent<T>& item,
        std::istream& in
    )
    {
        deserialize(item.begin, in);
        deserialize(item.end, in);
        deserialize(item.k, in);
        deserialize(item.left_tag, in);
        deserialize(item.right_tag, in);
    }

// -----------------------------------------------------------------------------------------

    const unsigned long END_OF_TREE = 0xFFFFFFFF;

// -----------------------------------------------------------------------------------------

    template <typename T>
    struct parse_tree_element
    {
        constituent<T> c;
        T tag; // id for the constituent corresponding to this level of the tree

        unsigned long left;
        unsigned long right;
        double score;
    };

    template <typename T>
    void serialize (
        const parse_tree_element<T>& item,
        std::ostream& out
    )
    {
        serialize(item.c, out);
        serialize(item.tag, out);
        serialize(item.left, out);
        serialize(item.right, out);
        serialize(item.score, out);
    }

    template <typename T>
    void deserialize (
        parse_tree_element<T>& item,
        std::istream& in
    )
    {
        deserialize(item.c, in);
        deserialize(item.tag, in);
        deserialize(item.left, in);
        deserialize(item.right, in);
        deserialize(item.score, in);
    }

// -----------------------------------------------------------------------------------------

    namespace impl
    {
        template <typename T>
        unsigned long fill_parse_tree(
            std::vector<parse_tree_element<T> >& parse_tree,
            const T& tag,
            const array2d<std::map<T, parse_tree_element<T> > >& back,
            long r, long c
        )
        /*!
            requires
                - back[r][c].size() == 0 || back[r][c].count(tag) != 0
        !*/
        {
            // base case of the recursion
            if (back[r][c].size() == 0)
            {
                return END_OF_TREE;
            }

            const unsigned long idx = parse_tree.size();
            const parse_tree_element<T>& item = back[r][c].find(tag)->second;
            parse_tree.push_back(item);

            const long k = item.c.k;
            const unsigned long idx_left  = fill_parse_tree(parse_tree, item.c.left_tag, back, r, k-1);
            const unsigned long idx_right = fill_parse_tree(parse_tree, item.c.right_tag, back, k, c);
            parse_tree[idx].left = idx_left;
            parse_tree[idx].right = idx_right;
            return idx;
        }
    }

    template <typename T, typename production_rule_function>
    void find_max_parse_cky (
        const std::vector<T>& sequence,
        const production_rule_function& production_rules,
        std::vector<parse_tree_element<T> >& parse_tree
    )
    {
        parse_tree.clear();
        if (sequence.size() == 0)
            return;

        array2d<std::map<T,double> > table(sequence.size(), sequence.size());
        array2d<std::map<T,parse_tree_element<T> > > back(sequence.size(), sequence.size());
        typedef typename std::map<T,double>::iterator itr;
        typedef typename std::map<T,parse_tree_element<T> >::iterator itr_b;

        for (long r = 0; r < table.nr(); ++r)
            table[r][r][sequence[r]] = 0;

        std::vector<std::pair<T,double> > possible_tags;

        for (long r = table.nr()-2; r >= 0; --r)
        {
            for (long c = r+1; c < table.nc(); ++c)
            {
                for (long k = r; k < c; ++k)
                {
                    for (itr i = table[k+1][c].begin(); i != table[k+1][c].end(); ++i)
                    {
                        for (itr j = table[r][k].begin(); j != table[r][k].end(); ++j)
                        {
                            constituent<T> con;
                            con.begin = r;
                            con.end = c+1;
                            con.k = k+1;
                            con.left_tag = j->first;
                            con.right_tag = i->first;
                            possible_tags.clear();
                            production_rules(sequence, con, possible_tags);
                            for (unsigned long m = 0; m < possible_tags.size(); ++m)
                            {
                                const double score = possible_tags[m].second + i->second + j->second;
                                itr match = table[r][c].find(possible_tags[m].first);
                                if (match == table[r][c].end() || score > match->second)
                                {
                                    table[r][c][possible_tags[m].first] = score;
                                    parse_tree_element<T> item;
                                    item.c = con;
                                    item.score = score;
                                    item.tag = possible_tags[m].first;
                                    item.left = END_OF_TREE;
                                    item.right = END_OF_TREE;
                                    back[r][c][possible_tags[m].first] = item;
                                }
                            }
                        }
                    }
                }
            }
        }

        // now use back pointers to build the parse trees
        const long r = 0;
        const long c = back.nc()-1;
        if (back[r][c].size() != 0)
        {

            // find the max scoring element in back[r][c]
            itr_b max_i = back[r][c].begin();
            itr_b i = max_i;
            ++i;
            for (; i != back[r][c].end(); ++i)
            {
                if (i->second.score > max_i->second.score)
                    max_i = i;
            }

            parse_tree.reserve(c);
            impl::fill_parse_tree(parse_tree, max_i->second.tag, back, r, c);
        }
    }

// -----------------------------------------------------------------------------------------

    class parse_tree_to_string_error : public error
    {
    public:
        parse_tree_to_string_error(const std::string& str): error(str) {}
    };

    namespace impl
    {
        template <bool enabled, typename T>
        typename enable_if_c<enabled>::type conditional_print(
            const T& item,
            std::ostream& out
        ) { out << item << " "; }

        template <bool enabled, typename T>
        typename disable_if_c<enabled>::type conditional_print(
            const T& ,
            std::ostream&
        ) {  }

        template <bool print_tag, bool skip_tag, typename T, typename U >
        void print_parse_tree_helper (
            const std::vector<parse_tree_element<T> >& tree,
            const std::vector<U>& words,
            unsigned long i,
            const T& tag_to_skip,
            std::ostream& out
        )
        {
            if (!skip_tag || tree[i].tag != tag_to_skip)
                out << "[";

            bool left_recurse = false;

            // Only print if we are supposed to.  Doing it this funny way avoids compiler
            // errors in parse_tree_to_string() for the case where tag isn't
            // printable.
            if (!skip_tag || tree[i].tag != tag_to_skip)
                conditional_print<print_tag>(tree[i].tag, out);

            if (tree[i].left < tree.size())
            {
                left_recurse = true;
                print_parse_tree_helper<print_tag,skip_tag>(tree, words, tree[i].left, tag_to_skip, out);
            }
            else
            {
                if ((tree[i].c.begin) < words.size())
                {
                    out << words[tree[i].c.begin] << " ";
                }
                else
                {
                    std::ostringstream sout;
                    sout << "Parse tree refers to element " << tree[i].c.begin
                         << " of sequence which is only of size " << words.size() << ".";
                    throw parse_tree_to_string_error(sout.str());
                }
            }

            if (left_recurse == true)
                out << " ";

            if (tree[i].right < tree.size())
            {
                print_parse_tree_helper<print_tag,skip_tag>(tree, words, tree[i].right, tag_to_skip, out);
            }
            else
            {
                if (tree[i].c.k < words.size())
                {
                    out << words[tree[i].c.k];
                }
                else
                {
                    std::ostringstream sout;
                    sout << "Parse tree refers to element " << tree[i].c.k
                         << " of sequence which is only of size " << words.size() << ".";
                    throw parse_tree_to_string_error(sout.str());
                }
            }

            if (!skip_tag || tree[i].tag != tag_to_skip)
                out << "]";
        }
    }

// -----------------------------------------------------------------------------------------

    template <typename T, typename U>
    std::string parse_tree_to_string (
        const std::vector<parse_tree_element<T> >& tree,
        const std::vector<U>& words,
        const unsigned long root_idx = 0
    )
    {
        if (root_idx >= tree.size())
            return "";

        std::ostringstream sout;
        impl::print_parse_tree_helper<false,false>(tree, words, root_idx, tree[root_idx].tag, sout);
        return sout.str();
    }

// -----------------------------------------------------------------------------------------

    template <typename T, typename U>
    std::string parse_tree_to_string_tagged (
        const std::vector<parse_tree_element<T> >& tree,
        const std::vector<U>& words,
        const unsigned long root_idx = 0
    )
    {
        if (root_idx >= tree.size())
            return "";

        std::ostringstream sout;
        impl::print_parse_tree_helper<true,false>(tree, words, root_idx, tree[root_idx].tag, sout);
        return sout.str();
    }

// -----------------------------------------------------------------------------------------

    template <typename T, typename U>
    std::string parse_trees_to_string (
        const std::vector<parse_tree_element<T> >& tree,
        const std::vector<U>& words,
        const T& tag_to_skip
    )
    {
        if (tree.size() == 0)
            return "";

        std::ostringstream sout;
        impl::print_parse_tree_helper<false,true>(tree, words, 0, tag_to_skip, sout);
        return sout.str();
    }

// -----------------------------------------------------------------------------------------

    template <typename T, typename U>
    std::string parse_trees_to_string_tagged (
        const std::vector<parse_tree_element<T> >& tree,
        const std::vector<U>& words,
        const T& tag_to_skip
    )
    {
        if (tree.size() == 0)
            return "";

        std::ostringstream sout;
        impl::print_parse_tree_helper<true,true>(tree, words, 0, tag_to_skip, sout);
        return sout.str();
    }

// -----------------------------------------------------------------------------------------

    namespace impl
    {
        template <typename T>
        void helper_find_trees_without_tag (
            const std::vector<parse_tree_element<T> >& tree,
            const T& tag,
            std::vector<unsigned long>& tree_roots,
            unsigned long idx
        )
        {
            if (idx < tree.size())
            {
                if (tree[idx].tag != tag)
                {
                    tree_roots.push_back(idx);
                }
                else
                {
                    helper_find_trees_without_tag(tree, tag, tree_roots, tree[idx].left);
                    helper_find_trees_without_tag(tree, tag, tree_roots, tree[idx].right);
                }
            }
        }
    }

    template <typename T>
    void find_trees_not_rooted_with_tag (
        const std::vector<parse_tree_element<T> >& tree,
        const T& tag,
        std::vector<unsigned long>& tree_roots
    )
    {
        tree_roots.clear();
        impl::helper_find_trees_without_tag(tree, tag, tree_roots, 0);
    }

// -----------------------------------------------------------------------------------------

}

#endif // DLIB_FIND_MAX_PaRSE_CKY_Hh_


dlib C++ Library - max_cost_assignment.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MAX_COST_ASSIgNMENT_Hh_
#define DLIB_MAX_COST_ASSIgNMENT_Hh_

#include "max_cost_assignment_abstract.h"
#include "../matrix.h"
#include <vector>
#include <deque>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <typename EXP>
    typename EXP::type assignment_cost (
        const matrix_exp<EXP>& cost,
        const std::vector<long>& assignment
    )
    {
        DLIB_ASSERT(cost.nr() == cost.nc(),
            "\t type assignment_cost(cost,assignment)"
            << "\n\t cost.nr(): " << cost.nr()
            << "\n\t cost.nc(): " << cost.nc()
            );
#ifdef ENABLE_ASSERTS
        // can't call max on an empty vector. So put an if here to guard against it.
        if (assignment.size() > 0)
        {
            DLIB_ASSERT(0 <= min(mat(assignment)) && max(mat(assignment)) < cost.nr(),
                "\t type assignment_cost(cost,assignment)"
                << "\n\t cost.nr(): " << cost.nr()
                << "\n\t cost.nc(): " << cost.nc()
                << "\n\t min(assignment): " << min(mat(assignment))
                << "\n\t max(assignment): " << max(mat(assignment))
                );
        }
#endif

        typename EXP::type temp = 0;
        for (unsigned long i = 0; i < assignment.size(); ++i)
        {
            temp += cost(i, assignment[i]);
        }
        return temp;
    }

// ----------------------------------------------------------------------------------------

    namespace impl
    {
        template <typename EXP>
        inline void compute_slack(
            const long x,
            std::vector<typename EXP::type>& slack,
            std::vector<long>& slackx,
            const matrix_exp<EXP>& cost,
            const std::vector<typename EXP::type>& lx,
            const std::vector<typename EXP::type>& ly
        )
        {
            for (long y = 0; y < cost.nc(); ++y)
            {
                if (lx[x] + ly[y] - cost(x,y) < slack[y])
                {
                    slack[y] = lx[x] + ly[y] - cost(x,y);
                    slackx[y] = x;
                }
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <typename EXP>
    std::vector<long> max_cost_assignment (
        const matrix_exp<EXP>& cost_
    )
    {
        const_temp_matrix<EXP> cost(cost_);
        typedef typename EXP::type type;
        // This algorithm only works if the elements of the cost matrix can be reliably
        // compared using operator==. However, comparing for equality with floating point
        // numbers is not a stable operation. So you need to use an integer cost matrix.
        COMPILE_TIME_ASSERT(std::numeric_limits<type>::is_integer);
        DLIB_ASSERT(cost.nr() == cost.nc(),
            "\t std::vector<long> max_cost_assignment(cost)"
            << "\n\t cost.nr(): " << cost.nr()
            << "\n\t cost.nc(): " << cost.nc()
            );

        using namespace dlib::impl;
        /*
            I based the implementation of this algorithm on the description of the
            Hungarian algorithm on the following websites:
                http://www.math.uwo.ca/~mdawes/courses/344/kuhn-munkres.pdf
                http://www.topcoder.com/tc?module=Static&d1=tutorials&d2=hungarianAlgorithm

            Note that this is the fast O(n^3) version of the algorithm.
        */

        if (cost.size() == 0)
            return std::vector<long>();

        std::vector<type> lx, ly;
        std::vector<long> xy;
        std::vector<long> yx;
        std::vector<char> S, T;
        std::vector<type> slack;
        std::vector<long> slackx;
        std::vector<long> aug_path;

        // Initially, nothing is matched.
        xy.assign(cost.nc(), -1);
        yx.assign(cost.nc(), -1);
        /*
            We maintain the following invariant:
                Vertex x is matched to vertex xy[x] and
                vertex y is matched to vertex yx[y].

                A value of -1 means a vertex isn't matched to anything.  Moreover,
                x corresponds to rows of the cost matrix and y corresponds to the
                columns of the cost matrix.  So we are matching X to Y.
        */

        // Create an initial feasible labeling.  Moreover, in the following
        // code we will always have:
        //     for all valid x and y:  lx[x] + ly[y] >= cost(x,y)
        lx.resize(cost.nc());
        ly.assign(cost.nc(),0);
        for (long x = 0; x < cost.nr(); ++x)
            lx[x] = max(rowm(cost,x));

        // Now grow the match set by picking edges from the equality subgraph until
        // we have a complete matching.
        for (long match_size = 0; match_size < cost.nc(); ++match_size)
        {
            std::deque<long> q;

            // Empty out the S and T sets
            S.assign(cost.nc(), false);
            T.assign(cost.nc(), false);

            // clear out old slack values
            slack.assign(cost.nc(), std::numeric_limits<type>::max());
            slackx.resize(cost.nc());
            /*
                slack and slackx are maintained such that we always
                have the following (once they get initialized by compute_slack() below):
                    - for all y:
                        - let x == slackx[y]
                        - slack[y] == lx[x] + ly[y] - cost(x,y)
            */

            aug_path.assign(cost.nc(), -1);

            for (long x = 0; x < cost.nc(); ++x)
            {
                // If x is not matched to anything
                if (xy[x] == -1)
                {
                    q.push_back(x);
                    S[x] = true;

                    compute_slack(x, slack, slackx, cost, lx, ly);
                    break;
                }
            }

            long x_start = 0;
            long y_start = 0;

            // Find an augmenting path.
            bool found_augmenting_path = false;
            while (!found_augmenting_path)
            {
                while (q.size() > 0 && !found_augmenting_path)
                {
                    const long x = q.front();
                    q.pop_front();
                    for (long y = 0; y < cost.nc(); ++y)
                    {
                        if (cost(x,y) == lx[x] + ly[y] && !T[y])
                        {
                            // if vertex y isn't matched with anything
                            if (yx[y] == -1)
                            {
                                y_start = y;
                                x_start = x;
                                found_augmenting_path = true;
                                break;
                            }

                            T[y] = true;
                            q.push_back(yx[y]);

                            aug_path[yx[y]] = x;
                            S[yx[y]] = true;
                            compute_slack(yx[y], slack, slackx, cost, lx, ly);
                        }
                    }
                }

                if (found_augmenting_path)
                    break;

                // Since we didn't find an augmenting path we need to improve the
                // feasible labeling stored in lx and ly.  We also need to keep the
                // slack updated accordingly.
                type delta = std::numeric_limits<type>::max();
                for (unsigned long i = 0; i < T.size(); ++i)
                {
                    if (!T[i])
                        delta = std::min(delta, slack[i]);
                }
                for (unsigned long i = 0; i < T.size(); ++i)
                {
                    if (S[i])
                        lx[i] -= delta;

                    if (T[i])
                        ly[i] += delta;
                    else
                        slack[i] -= delta;
                }

                q.clear();
                for (long y = 0; y < cost.nc(); ++y)
                {
                    if (!T[y] && slack[y] == 0)
                    {
                        // if vertex y isn't matched with anything
                        if (yx[y] == -1)
                        {
                            x_start = slackx[y];
                            y_start = y;
                            found_augmenting_path = true;
                            break;
                        }
                        else
                        {
                            T[y] = true;
                            if (!S[yx[y]])
                            {
                                q.push_back(yx[y]);

                                aug_path[yx[y]] = slackx[y];
                                S[yx[y]] = true;
                                compute_slack(yx[y], slack, slackx, cost, lx, ly);
                            }
                        }
                    }
                }
            } // end while (!found_augmenting_path)

            // Flip the edges along the augmenting path.  This means we will add one more
            // item to our matching.
            for (long cx = x_start, cy = y_start, ty;
                 cx != -1;
                 cx = aug_path[cx], cy = ty)
            {
                ty = xy[cx];
                yx[cy] = cx;
                xy[cx] = cy;
            }

        }

        return xy;
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MAX_COST_ASSIgNMENT_Hh_


dlib C++ Library - max_sum_submatrix.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MAX_SUM_SUBMaTRIX_Hh_
#define DLIB_MAX_SUM_SUBMaTRIX_Hh_

#include "max_sum_submatrix_abstract.h"
#include "../matrix.h"
#include <vector>
#include <queue>
#include "../geometry.h"

namespace dlib
{
    namespace impl
    {

    // ------------------------------------------------------------------------------------

        template <typename T>
        struct range_set
        {
            int top_min;
            int top_max;
            int bottom_min;
            int bottom_max;
            T weight;

            bool operator<(const range_set& item) const { return weight < item.weight; }
        };

    // ------------------------------------------------------------------------------------

        template <typename T>
        bool is_terminal_set (
            const range_set<T>& item
        )
        {
            return (item.top_min  >= item.top_max &&
                    item.bottom_min >= item.bottom_max);
        }

    // ------------------------------------------------------------------------------------

        template <typename T>
        void split (
            const range_set<T>& rset,
            range_set<T>& a,
            range_set<T>& b
        )
        {
            if (rset.top_max - rset.top_min > rset.bottom_max - rset.bottom_min)
            {
                // split top
                const int middle = (rset.top_max + rset.top_min)/2;
                a.top_min = rset.top_min;
                a.top_max = middle;
                b.top_min = middle+1;
                b.top_max = rset.top_max;

                a.bottom_min = rset.bottom_min;
                a.bottom_max = rset.bottom_max;
                b.bottom_min = rset.bottom_min;
                b.bottom_max = rset.bottom_max;
            }
            else
            {
                // split bottom
                const int middle = (rset.bottom_max + rset.bottom_min)/2;
                a.bottom_min = rset.bottom_min;
                a.bottom_max = middle;
                b.bottom_min = middle+1;
                b.bottom_max = rset.bottom_max;

                a.top_min = rset.top_min;
                a.top_max = rset.top_max;
                b.top_min = rset.top_min;
                b.top_max = rset.top_max;
            }
        }

    // ------------------------------------------------------------------------------------

        template <typename EXP, typename T>
        void find_best_column_range (
            const matrix_exp<EXP>& sum_pos,
            const matrix_exp<EXP>& sum_neg,
            const range_set<T>& row_range,
            T& weight,
            int& left,
            int& right
        )
        {
            left = 0;
            right = -1;
            weight = 0;
            T cur_sum = 0;
            int cur_pos = 0;
            for (long c = 0; c < sum_pos.nc(); ++c)
            {
                // compute the value for the current column
                T temp = sum_pos(row_range.bottom_max+1,c) - sum_pos(row_range.top_min,c);
                if (row_range.top_max <= row_range.bottom_min)
                    temp += sum_neg(row_range.bottom_min+1,c) - sum_neg(row_range.top_max,c);

                cur_sum += temp;
                if (cur_sum > weight)
                {
                    left = cur_pos;
                    right = c;
                    weight = cur_sum;
                }

                if (cur_sum <= 0)
                {
                    cur_sum = 0;
                    cur_pos = c+1;
                }

            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <typename EXP>
    std::vector<rectangle> max_sum_submatrix(
        const matrix_exp<EXP>& mat,
        unsigned long max_rects,
        double thresh_ = 0
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(thresh_ >= 0 && mat.size() > 0,
            "\t std::vector<rectangle> max_sum_submatrix()"
            << "\n\t Invalid arguments were given to this function."
            << "\n\t mat.size(): " << mat.size()
            << "\n\t thresh_:    " << thresh_
            );

        /*
            This function is basically an implementation of the efficient subwindow search (I-ESS)
            algorithm presented in the following paper:
                Efficient Algorithms for Subwindow Search in Object Detection and Localization
                by Senjian An, Patrick Peursum, Wanquan Liu and Svetha Venkatesh
                In CVPR 2009

        */

        if (max_rects == 0)
            return std::vector<rectangle>();

        using namespace dlib::impl;
        typedef typename EXP::type element_type;
        typedef typename promote<element_type>::type scalar_type;

        const scalar_type thresh = static_cast<scalar_type>(thresh_);

        matrix<scalar_type> sum_pos;
        matrix<scalar_type> sum_neg;
        sum_pos.set_size(mat.nr()+1, mat.nc());
        sum_neg.set_size(mat.nr()+1, mat.nc());
        // integrate over the rows.
        for (long c = 0; c < mat.nc(); ++c)
        {
            sum_pos(0,c) = 0;
            sum_neg(0,c) = 0;
        }
        for (long r = 0; r < mat.nr(); ++r)
        {
            for (long c = 0; c < mat.nc(); ++c)
            {
                if (mat(r,c) > 0)
                {
                    sum_pos(r+1,c) = mat(r,c) + sum_pos(r,c);
                    sum_neg(r+1,c) = sum_neg(r,c);
                }
                else
                {
                    sum_pos(r+1,c) = sum_pos(r,c);
                    sum_neg(r+1,c) = mat(r,c) + sum_neg(r,c);
                }
            }
        }

        std::priority_queue<range_set<scalar_type> > q;

        // the range_sets will represent ranges of columns
        range_set<scalar_type> universe_set;
        universe_set.bottom_min = 0;
        universe_set.top_min = 0;
        universe_set.bottom_max = mat.nr()-1;
        universe_set.top_max = mat.nr()-1;
        universe_set.weight = sum(rowm(dlib::mat(sum_pos),mat.nr()));

        q.push(universe_set);

        std::vector<rectangle> results;
        std::vector<scalar_type> temp_pos(mat.nc());
        std::vector<scalar_type> temp_neg(mat.nc());

        while (q.size() > 0)
        {
            if (is_terminal_set(q.top()))
            {
                int left, right;
                scalar_type weight;
                find_best_column_range(sum_pos, sum_neg, q.top(), weight, left, right);

                rectangle rect(left, q.top().top_min,
                               right, q.top().bottom_min);

                if (weight <= thresh)
                    break;

                results.push_back(rect);

                if (results.size() >= max_rects)
                    break;

                q = std::priority_queue<range_set<scalar_type> >();
                // We are going to blank out the weights we just used.  So adjust the sum images appropriately.
                for (long c = rect.left(); c <= rect.right(); ++c)
                {
                    temp_pos[c] = sum_pos(rect.bottom()+1,c) - sum_pos(rect.top(),c);
                    temp_neg[c] = sum_neg(rect.bottom()+1,c) - sum_neg(rect.top(),c);
                }
                // blank out the area inside the rectangle
                for (long r = rect.top(); r <= rect.bottom(); ++r)
                {
                    for (long c = rect.left(); c <= rect.right(); ++c)
                    {
                        sum_pos(r+1,c) = sum_pos(r,c);
                        sum_neg(r+1,c) = sum_neg(r,c);
                    }
                }
                // account for the area below the rectangle
                for (long r = rect.bottom()+2; r < sum_pos.nr(); ++r)
                {
                    for (long c = rect.left(); c <= rect.right(); ++c)
                    {
                        sum_pos(r,c) -= temp_pos[c];
                        sum_neg(r,c) -= temp_neg[c];
                    }
                }

                universe_set.weight = sum(rowm(dlib::mat(sum_pos),mat.nr()));
                if (universe_set.weight <= thresh)
                    break;

                q.push(universe_set);
                continue;
            }

            range_set<scalar_type> a, b;
            split(q.top(), a,b);
            q.pop();

            // these variables are not used at this point in the algorithm.
            int a_left, a_right;
            int b_left, b_right;

            find_best_column_range(sum_pos, sum_neg, a, a.weight, a_left, a_right);
            find_best_column_range(sum_pos, sum_neg, b, b.weight, b_left, b_right);

            if (a.weight > thresh)
                q.push(a);
            if (b.weight > thresh)
                q.push(b);

        }

        return results;
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MAX_SUM_SUBMaTRIX_Hh_


dlib C++ Library - optimization.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_OPTIMIZATIOn_H_
#define DLIB_OPTIMIZATIOn_H_

#include <cmath>
#include <limits>
#include "optimization_abstract.h"
#include "optimization_search_strategies.h"
#include "optimization_stop_strategies.h"
#include "optimization_line_search.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                    Functions that transform other functions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <typename funct>
    class central_differences
    {
    public:
        central_differences(const funct& f_, double eps_ = 1e-7) : f(f_), eps(eps_){}

        template <typename T>
        typename T::matrix_type operator()(const T& x) const
        {
            // T must be some sort of dlib matrix
            COMPILE_TIME_ASSERT(is_matrix<T>::value);

            typename T::matrix_type der(x.size());
            typename T::matrix_type e(x);
            for (long i = 0; i < x.size(); ++i)
            {
                const double old_val = e(i);

                e(i) += eps;
                const double delta_plus = f(e);
                e(i) = old_val - eps;
                const double delta_minus = f(e);

                der(i) = (delta_plus - delta_minus)/(2*eps);

                // and finally restore the old value of this element
                e(i) = old_val;
            }

            return der;
        }

        template <typename T, typename U>
        typename U::matrix_type operator()(const T& item, const U& x) const
        {
            // U must be some sort of dlib matrix
            COMPILE_TIME_ASSERT(is_matrix<U>::value);

            typename U::matrix_type der(x.size());
            typename U::matrix_type e(x);
            for (long i = 0; i < x.size(); ++i)
            {
                const double old_val = e(i);

                e(i) += eps;
                const double delta_plus = f(item,e);
                e(i) = old_val - eps;
                const double delta_minus = f(item,e);

                der(i) = (delta_plus - delta_minus)/(2*eps);

                // and finally restore the old value of this element
                e(i) = old_val;
            }

            return der;
        }

        double operator()(const double& x) const
        {
            return (f(x+eps)-f(x-eps))/(2*eps);
        }

    private:
        const funct& f;
        const double eps;
    };

    template <typename funct>
    const central_differences<funct> derivative(const funct& f) { return central_differences<funct>(f); }
    template <typename funct>
    const central_differences<funct> derivative(const funct& f, double eps)
    {
        DLIB_ASSERT (
            eps > 0,
            "\tcentral_differences derivative(f,eps)"
            << "\n\tYou must give an epsilon > 0"
            << "\n\teps:     " << eps
        );
        return central_differences<funct>(f,eps);
    }

// ----------------------------------------------------------------------------------------

    template <typename funct, typename EXP1, typename EXP2>
    struct clamped_function_object
    {
        clamped_function_object(
            const funct& f_,
            const matrix_exp<EXP1>& x_lower_,
            const matrix_exp<EXP2>& x_upper_
        ) : f(f_), x_lower(x_lower_), x_upper(x_upper_)
        {
        }

        template <typename T>
        double operator() (
            const T& x
        ) const
        {
            return f(clamp(x,x_lower,x_upper));
        }

        const funct& f;
        const matrix_exp<EXP1>& x_lower;
        const matrix_exp<EXP2>& x_upper;
    };

    template <typename funct, typename EXP1, typename EXP2>
    clamped_function_object<funct,EXP1,EXP2> clamp_function(
        const funct& f,
        const matrix_exp<EXP1>& x_lower,
        const matrix_exp<EXP2>& x_upper
    ) { return clamped_function_object<funct,EXP1,EXP2>(f,x_lower,x_upper); }

// ----------------------------------------------------------------------------------------

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                    Functions that perform unconstrained optimization
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename search_strategy_type,
        typename stop_strategy_type,
        typename funct,
        typename funct_der,
        typename T
        >
    double find_min (
        search_strategy_type search_strategy,
        stop_strategy_type stop_strategy,
        const funct& f,
        const funct_der& der,
        T& x,
        double min_f
    )
    {
        COMPILE_TIME_ASSERT(is_matrix<T>::value);
        // The starting point (i.e. x) must be a column vector.
        COMPILE_TIME_ASSERT(T::NC <= 1);

        DLIB_CASSERT (
            is_col_vector(x),
            "\tdouble find_min()"
            << "\n\tYou have to supply column vectors to this function"
            << "\n\tx.nc():    " << x.nc()
        );

        T g, s;

        double f_value = f(x);
        g = der(x);

        if (!is_finite(f_value))
            throw error("The objective function generated non-finite outputs");
        if (!is_finite(g))
            throw error("The objective function generated non-finite outputs");

        while(stop_strategy.should_continue_search(x, f_value, g) && f_value > min_f)
        {
            s = search_strategy.get_next_direction(x, f_value, g);

            double alpha = line_search(
                        make_line_search_function(f,x,s, f_value),
                        f_value,
                        make_line_search_function(der,x,s, g),
                        dot(g,s), // compute initial gradient for the line search
                        search_strategy.get_wolfe_rho(), search_strategy.get_wolfe_sigma(), min_f,
                        search_strategy.get_max_line_search_iterations());

            // Take the search step indicated by the above line search
            x += alpha*s;

            if (!is_finite(f_value))
                throw error("The objective function generated non-finite outputs");
            if (!is_finite(g))
                throw error("The objective function generated non-finite outputs");
        }

        return f_value;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename search_strategy_type,
        typename stop_strategy_type,
        typename funct,
        typename funct_der,
        typename T
        >
    double find_max (
        search_strategy_type search_strategy,
        stop_strategy_type stop_strategy,
        const funct& f,
        const funct_der& der,
        T& x,
        double max_f
    )
    {
        COMPILE_TIME_ASSERT(is_matrix<T>::value);
        // The starting point (i.e. x) must be a column vector.
        COMPILE_TIME_ASSERT(T::NC <= 1);

        DLIB_CASSERT (
            is_col_vector(x),
            "\tdouble find_max()"
            << "\n\tYou have to supply column vectors to this function"
            << "\n\tx.nc():    " << x.nc()
        );

        T g, s;

        // This function is basically just a copy of find_min() but with - put in the right places
        // to flip things around so that it ends up looking for the max rather than the min.

        double f_value = -f(x);
        g = -der(x);

        if (!is_finite(f_value))
            throw error("The objective function generated non-finite outputs");
        if (!is_finite(g))
            throw error("The objective function generated non-finite outputs");

        while(stop_strategy.should_continue_search(x, f_value, g) && f_value > -max_f)
        {
            s = search_strategy.get_next_direction(x, f_value, g);

            double alpha = line_search(
                        negate_function(make_line_search_function(f,x,s, f_value)),
                        f_value,
                        negate_function(make_line_search_function(der,x,s, g)),
                        dot(g,s), // compute initial gradient for the line search
                        search_strategy.get_wolfe_rho(), search_strategy.get_wolfe_sigma(), -max_f,
                        search_strategy.get_max_line_search_iterations()
                        );

            // Take the search step indicated by the above line search
            x += alpha*s;

            // Don't forget to negate these outputs from the line search since they are
            // from the unnegated versions of f() and der()
            g *= -1;
            f_value *= -1;

            if (!is_finite(f_value))
                throw error("The objective function generated non-finite outputs");
            if (!is_finite(g))
                throw error("The objective function generated non-finite outputs");
        }

        return -f_value;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename search_strategy_type,
        typename stop_strategy_type,
        typename funct,
        typename T
        >
    double find_min_using_approximate_derivatives (
        search_strategy_type search_strategy,
        stop_strategy_type stop_strategy,
        const funct& f,
        T& x,
        double min_f,
        double derivative_eps = 1e-7
    )
    {
        COMPILE_TIME_ASSERT(is_matrix<T>::value);
        // The starting point (i.e. x) must be a column vector.
        COMPILE_TIME_ASSERT(T::NC <= 1);

        DLIB_CASSERT (
            is_col_vector(x) && derivative_eps > 0,
            "\tdouble find_min_using_approximate_derivatives()"
            << "\n\tYou have to supply column vectors to this function"
            << "\n\tx.nc():         " << x.nc()
            << "\n\tderivative_eps: " << derivative_eps
        );

        T g, s;

        double f_value = f(x);
        g = derivative(f,derivative_eps)(x);

        if (!is_finite(f_value))
            throw error("The objective function generated non-finite outputs");
        if (!is_finite(g))
            throw error("The objective function generated non-finite outputs");

        while(stop_strategy.should_continue_search(x, f_value, g) && f_value > min_f)
        {
            s = search_strategy.get_next_direction(x, f_value, g);

            double alpha = line_search(
                        make_line_search_function(f,x,s,f_value),
                        f_value,
                        derivative(make_line_search_function(f,x,s),derivative_eps),
                        dot(g,s),  // Sometimes the following line is a better way of determining the initial gradient.
                        //derivative(make_line_search_function(f,x,s),derivative_eps)(0),
                        search_strategy.get_wolfe_rho(), search_strategy.get_wolfe_sigma(), min_f,
                        search_strategy.get_max_line_search_iterations()
                        );

            // Take the search step indicated by the above line search
            x += alpha*s;

            g = derivative(f,derivative_eps)(x);

            if (!is_finite(f_value))
                throw error("The objective function generated non-finite outputs");
            if (!is_finite(g))
                throw error("The objective function generated non-finite outputs");
        }

        return f_value;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename search_strategy_type,
        typename stop_strategy_type,
        typename funct,
        typename T
        >
    double find_max_using_approximate_derivatives (
        search_strategy_type search_strategy,
        stop_strategy_type stop_strategy,
        const funct& f,
        T& x,
        double max_f,
        double derivative_eps = 1e-7
    )
    {
        COMPILE_TIME_ASSERT(is_matrix<T>::value);
        // The starting point (i.e. x) must be a column vector.
        COMPILE_TIME_ASSERT(T::NC <= 1);

        DLIB_CASSERT (
            is_col_vector(x) && derivative_eps > 0,
            "\tdouble find_max_using_approximate_derivatives()"
            << "\n\tYou have to supply column vectors to this function"
            << "\n\tx.nc():         " << x.nc()
            << "\n\tderivative_eps: " << derivative_eps
        );

        // Just negate the necessary things and call the find_min version of this function.
        return -find_min_using_approximate_derivatives(
            search_strategy,
            stop_strategy,
            negate_function(f),
            x,
            -max_f,
            derivative_eps
        );
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                      Functions for box constrained optimization
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <typename T, typename U, typename V>
    T zero_bounded_variables (
        const double eps,
        T vect,
        const T& x,
        const T& gradient,
        const U& x_lower,
        const V& x_upper
    )
    {
        for (long i = 0; i < gradient.size(); ++i)
        {
            const double tol = eps*std::abs(x(i));
            // if x(i) is an active bound constraint
            if (x_lower(i)+tol >= x(i) && gradient(i) > 0)
                vect(i) = 0;
            else if (x_upper(i)-tol <= x(i) && gradient(i) < 0)
                vect(i) = 0;
        }
        return vect;
    }

// ----------------------------------------------------------------------------------------

    template <typename T, typename U, typename V>
    T gap_step_assign_bounded_variables (
        const double eps,
        T vect,
        const T& x,
        const T& gradient,
        const U& x_lower,
        const V& x_upper
    )
    {
        for (long i = 0; i < gradient.size(); ++i)
        {
            const double tol = eps*std::abs(x(i));
            // if x(i) is an active bound constraint then we should set it's search
            // direction such that a single step along the direction either does nothing or
            // closes the gap of size tol before hitting the bound exactly.
            if (x_lower(i)+tol >= x(i) && gradient(i) > 0)
                vect(i) = x_lower(i)-x(i);
            else if (x_upper(i)-tol <= x(i) && gradient(i) < 0)
                vect(i) = x_upper(i)-x(i);
        }
        return vect;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename search_strategy_type,
        typename stop_strategy_type,
        typename funct,
        typename funct_der,
        typename T,
        typename EXP1,
        typename EXP2
        >
    double find_min_box_constrained (
        search_strategy_type search_strategy,
        stop_strategy_type stop_strategy,
        const funct& f,
        const funct_der& der,
        T& x,
        const matrix_exp<EXP1>& x_lower,
        const matrix_exp<EXP2>& x_upper
    )
    {
        /*
            The implementation of this function is more or less based on the discussion in
            the paper Projected Newton-type Methods in Machine Learning by Mark Schmidt, et al.
        */

        // make sure the requires clause is not violated
        COMPILE_TIME_ASSERT(is_matrix<T>::value);
        // The starting point (i.e. x) must be a column vector.
        COMPILE_TIME_ASSERT(T::NC <= 1);

        DLIB_CASSERT (
            is_col_vector(x) && is_col_vector(x_lower) && is_col_vector(x_upper) &&
            x.size() == x_lower.size() && x.size() == x_upper.size(),
            "\tdouble find_min_box_constrained()"
            << "\n\t The inputs to this function must be equal length column vectors."
            << "\n\t is_col_vector(x):       " << is_col_vector(x)
            << "\n\t is_col_vector(x_upper): " << is_col_vector(x_upper)
            << "\n\t is_col_vector(x_upper): " << is_col_vector(x_upper)
            << "\n\t x.size():               " << x.size()
            << "\n\t x_lower.size():         " << x_lower.size()
            << "\n\t x_upper.size():         " << x_upper.size()
        );
        DLIB_ASSERT (
            min(x_upper-x_lower) > 0,
            "\tdouble find_min_box_constrained()"
            << "\n\t You have to supply proper box constraints to this function."
            << "\n\r min(x_upper-x_lower): " << min(x_upper-x_lower)
        );

        T g, s;
        double f_value = f(x);
        g = der(x);

        if (!is_finite(f_value))
            throw error("The objective function generated non-finite outputs");
        if (!is_finite(g))
            throw error("The objective function generated non-finite outputs");

        // gap_eps determines how close we have to get to a bound constraint before we
        // start basically dropping it from the optimization and consider it to be an
        // active constraint.
        const double gap_eps = 1e-8;

        double last_alpha = 1;
        while(stop_strategy.should_continue_search(x, f_value, g))
        {
            s = search_strategy.get_next_direction(x, f_value, zero_bounded_variables(gap_eps, g, x, g, x_lower, x_upper));
            s = gap_step_assign_bounded_variables(gap_eps, s, x, g, x_lower, x_upper);

            double alpha = backtracking_line_search(
                        make_line_search_function(clamp_function(f,x_lower,x_upper), x, s, f_value),
                        f_value,
                        dot(g,s), // compute gradient for the line search
                        last_alpha,
                        search_strategy.get_wolfe_rho(),
                        search_strategy.get_max_line_search_iterations());

            // Do a trust region style thing for alpha.  The idea is that if we take a
            // small step then we are likely to take another small step.  So we reuse the
            // alpha from the last iteration unless the line search didn't shrink alpha at
            // all, in that case, we start with a bigger alpha next time.
            if (alpha == last_alpha)
                last_alpha = std::min(last_alpha*10,1.0);
            else
                last_alpha = alpha;

            // Take the search step indicated by the above line search
            x = clamp(x + alpha*s, x_lower, x_upper);
            g = der(x);

            if (!is_finite(f_value))
                throw error("The objective function generated non-finite outputs");
            if (!is_finite(g))
                throw error("The objective function generated non-finite outputs");
        }

        return f_value;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename search_strategy_type,
        typename stop_strategy_type,
        typename funct,
        typename funct_der,
        typename T
        >
    double find_min_box_constrained (
        search_strategy_type search_strategy,
        stop_strategy_type stop_strategy,
        const funct& f,
        const funct_der& der,
        T& x,
        double x_lower,
        double x_upper
    )
    {
        // The starting point (i.e. x) must be a column vector.
        COMPILE_TIME_ASSERT(T::NC <= 1);

        typedef typename T::type scalar_type;
        return find_min_box_constrained(search_strategy,
                                        stop_strategy,
                                        f,
                                        der,
                                        x,
                                        uniform_matrix<scalar_type>(x.size(),1,x_lower),
                                        uniform_matrix<scalar_type>(x.size(),1,x_upper) );
    }

// ----------------------------------------------------------------------------------------

    template <
        typename search_strategy_type,
        typename stop_strategy_type,
        typename funct,
        typename funct_der,
        typename T,
        typename EXP1,
        typename EXP2
        >
    double find_max_box_constrained (
        search_strategy_type search_strategy,
        stop_strategy_type stop_strategy,
        const funct& f,
        const funct_der& der,
        T& x,
        const matrix_exp<EXP1>& x_lower,
        const matrix_exp<EXP2>& x_upper
    )
    {
        // make sure the requires clause is not violated
        COMPILE_TIME_ASSERT(is_matrix<T>::value);
        // The starting point (i.e. x) must be a column vector.
        COMPILE_TIME_ASSERT(T::NC <= 1);

        DLIB_CASSERT (
            is_col_vector(x) && is_col_vector(x_lower) && is_col_vector(x_upper) &&
            x.size() == x_lower.size() && x.size() == x_upper.size(),
            "\tdouble find_max_box_constrained()"
            << "\n\t The inputs to this function must be equal length column vectors."
            << "\n\t is_col_vector(x):       " << is_col_vector(x)
            << "\n\t is_col_vector(x_upper): " << is_col_vector(x_upper)
            << "\n\t is_col_vector(x_upper): " << is_col_vector(x_upper)
            << "\n\t x.size():               " << x.size()
            << "\n\t x_lower.size():         " << x_lower.size()
            << "\n\t x_upper.size():         " << x_upper.size()
        );
        DLIB_ASSERT (
            min(x_upper-x_lower) > 0,
            "\tdouble find_max_box_constrained()"
            << "\n\t You have to supply proper box constraints to this function."
            << "\n\r min(x_upper-x_lower): " << min(x_upper-x_lower)
        );

        // This function is basically just a copy of find_min_box_constrained() but with - put
        // in the right places to flip things around so that it ends up looking for the max
        // rather than the min.

        T g, s;
        double f_value = -f(x);
        g = -der(x);

        if (!is_finite(f_value))
            throw error("The objective function generated non-finite outputs");
        if (!is_finite(g))
            throw error("The objective function generated non-finite outputs");

        // gap_eps determines how close we have to get to a bound constraint before we
        // start basically dropping it from the optimization and consider it to be an
        // active constraint.
        const double gap_eps = 1e-8;

        double last_alpha = 1;
        while(stop_strategy.should_continue_search(x, f_value, g))
        {
            s = search_strategy.get_next_direction(x, f_value, zero_bounded_variables(gap_eps, g, x, g, x_lower, x_upper));
            s = gap_step_assign_bounded_variables(gap_eps, s, x, g, x_lower, x_upper);

            double alpha = backtracking_line_search(
                        negate_function(make_line_search_function(clamp_function(f,x_lower,x_upper), x, s, f_value)),
                        f_value,
                        dot(g,s), // compute gradient for the line search
                        last_alpha,
                        search_strategy.get_wolfe_rho(),
                        search_strategy.get_max_line_search_iterations());

            // Do a trust region style thing for alpha.  The idea is that if we take a
            // small step then we are likely to take another small step.  So we reuse the
            // alpha from the last iteration unless the line search didn't shrink alpha at
            // all, in that case, we start with a bigger alpha next time.
            if (alpha == last_alpha)
                last_alpha = std::min(last_alpha*10,1.0);
            else
                last_alpha = alpha;

            // Take the search step indicated by the above line search
            x = clamp(x + alpha*s, x_lower, x_upper);
            g = -der(x);

            // Don't forget to negate the output from the line search since it is  from the
            // unnegated version of f()
            f_value *= -1;

            if (!is_finite(f_value))
                throw error("The objective function generated non-finite outputs");
            if (!is_finite(g))
                throw error("The objective function generated non-finite outputs");
        }

        return -f_value;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename search_strategy_type,
        typename stop_strategy_type,
        typename funct,
        typename funct_der,
        typename T
        >
    double find_max_box_constrained (
        search_strategy_type search_strategy,
        stop_strategy_type stop_strategy,
        const funct& f,
        const funct_der& der,
        T& x,
        double x_lower,
        double x_upper
    )
    {
        // The starting point (i.e. x) must be a column vector.
        COMPILE_TIME_ASSERT(T::NC <= 1);

        typedef typename T::type scalar_type;
        return find_max_box_constrained(search_strategy,
                                        stop_strategy,
                                        f,
                                        der,
                                        x,
                                        uniform_matrix<scalar_type>(x.size(),1,x_lower),
                                        uniform_matrix<scalar_type>(x.size(),1,x_upper) );
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_OPTIMIZATIOn_H_


dlib C++ Library - optimization_bobyqa.h

// Copyright (C) 2009 M.J.D. Powell, Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_OPTIMIZATIOn_BOBYQA_Hh_
#define DLIB_OPTIMIZATIOn_BOBYQA_Hh_

/*
    The code in this file is derived from Powell's BOBYQA Fortran code.
    It was created by running f2c on the original Fortran code and then
    massaging the resulting C code into what you can see below.

    The following paper, published in 2009 by Powell, describes the
    detailed workings of the BOBYQA algorithm.

        The BOBYQA algorithm for bound constrained optimization
        without derivatives by M.J.D. Powell
*/

#include <algorithm>
#include <cmath>
#include "../matrix.h"
#include "../smart_pointers.h"
#include "optimization_bobyqa_abstract.h"
#include "optimization.h"

// ----------------------------------------------------------------------------------------

namespace dlib
{

    class bobyqa_failure : public error {
    public: bobyqa_failure(const std::string& s):error(s){}
    };

// ----------------------------------------------------------------------------------------

    class bobyqa_implementation
    {
        typedef long integer;
        typedef double doublereal;

    public:

        template <
            typename funct,
            typename T,
            typename U
            >
        double find_min (
            const funct& f,
            T& x,
            long npt,
            const U& xl_,
            const U& xu_,
            const double rhobeg,
            const double rhoend,
            const long max_f_evals
        ) const
        {
            const unsigned long n = x.size();
            const unsigned long w_size = (npt+5)*(npt+n)+3*n*(n+5)/2;
            scoped_ptr<doublereal[]> w(new doublereal[w_size]);

            // make these temporary matrices becuse U might be some
            // kind of matrix_exp that doesn't support taking the address
            // of the first element.
            matrix<double,0,1> xl(xl_);
            matrix<double,0,1> xu(xu_);

            return bobyqa_ (f,
                            x.size(),
                            npt,
                            &x(0),
                            &xl(0),
                            &xu(0),
                            rhobeg,
                            rhoend,
                            max_f_evals,
                            w.get() );
        }

    private:

        template <typename funct>
        doublereal bobyqa_(
            const funct& calfun,
            const integer n,
            const integer npt,
            doublereal *x,
            const doublereal *xl,
            const doublereal *xu,
            const doublereal rhobeg,
            const doublereal rhoend,
            const integer maxfun,
            doublereal *w
        ) const
        {

            /* System generated locals */
            integer i__1;
            doublereal d__1, d__2;

            /* Local variables */
            integer j, id_, np, iw, igo, ihq, ixb, ixa, ifv, isl, jsl, ipq, ivl, ixn, ixo, ixp, isu, jsu, ndim;
            doublereal temp, zero;
            integer ibmat, izmat;

            /*     This subroutine seeks the least value of a function of many variables, */
            /*     by applying a trust region method that forms quadratic models by */
            /*     interpolation. There is usually some freedom in the interpolation */
            /*     conditions, which is taken up by minimizing the Frobenius norm of */
            /*     the change to the second derivative of the model, beginning with the */
            /*     zero matrix. The values of the variables are constrained by upper and */
            /*     lower bounds. The arguments of the subroutine are as follows. */

            /*     N must be set to the number of variables and must be at least two. */
            /*     NPT is the number of interpolation conditions. Its value must be in */
            /*       the interval [N+2,(N+1)(N+2)/2]. Choices that exceed 2*N+1 are not */
            /*       recommended. */
            /*     Initial values of the variables must be set in X(1),X(2),...,X(N). They */
            /*       will be changed to the values that give the least calculated F. */
            /*     For I=1,2,...,N, XL(I) and XU(I) must provide the lower and upper */
            /*       bounds, respectively, on X(I). The construction of quadratic models */
            /*       requires XL(I) to be strictly less than XU(I) for each I. Further, */
            /*       the contribution to a model from changes to the I-th variable is */
            /*       damaged severely by rounding errors if XU(I)-XL(I) is too small. */
            /*     RHOBEG and RHOEND must be set to the initial and final values of a trust */
            /*       region radius, so both must be positive with RHOEND no greater than */
            /*       RHOBEG. Typically, RHOBEG should be about one tenth of the greatest */
            /*       expected change to a variable, while RHOEND should indicate the */
            /*       accuracy that is required in the final values of the variables. An */
            /*       error return occurs if any of the differences XU(I)-XL(I), I=1,...,N, */
            /*       is less than 2*RHOBEG. */
            /*     MAXFUN must be set to an upper bound on the number of calls of CALFUN. */
            /*     The array W will be used for working space. Its length must be at least */
            /*       (NPT+5)*(NPT+N)+3*N*(N+5)/2. */

            /* Parameter adjustments */
            --w;
            --xu;
            --xl;
            --x;

            /* Function Body */
            np = n + 1;

            /*     Return if the value of NPT is unacceptable. */
            if (npt < n + 2 || npt > (n + 2) * np / 2) {
                throw bobyqa_failure("Return from BOBYQA because NPT is not in the required interval");
                //goto L40;
            }

            /*     Partition the working space array, so that different parts of it can */
            /*     be treated separately during the calculation of BOBYQB. The partition */
            /*     requires the first (NPT+2)*(NPT+N)+3*N*(N+5)/2 elements of W plus the */
            /*     space that is taken by the last array in the argument list of BOBYQB. */

            ndim = npt + n;
            ixb = 1;
            ixp = ixb + n;
            ifv = ixp + n * npt;
            ixo = ifv + npt;
            igo = ixo + n;
            ihq = igo + n;
            ipq = ihq + n * np / 2;
            ibmat = ipq + npt;
            izmat = ibmat + ndim * n;
            isl = izmat + npt * (npt - np);
            isu = isl + n;
            ixn = isu + n;
            ixa = ixn + n;
            id_ = ixa + n;
            ivl = id_ + n;
            iw = ivl + ndim;

            /*     Return if there is insufficient space between the bounds. Modify the */
            /*     initial X if necessary in order to avoid conflicts between the bounds */
            /*     and the construction of the first quadratic model. The lower and upper */
            /*     bounds on moves from the updated X are set now, in the ISL and ISU */
            /*     partitions of W, in order to provide useful and exact information about */
            /*     components of X that become within distance RHOBEG from their bounds. */

            zero = 0.;
            i__1 = n;
            for (j = 1; j <= i__1; ++j) {
                temp = xu[j] - xl[j];
                if (temp < rhobeg + rhobeg) {
                    throw bobyqa_failure("Return from BOBYQA because one of the differences in x_lower and x_upper is less than 2*rho_begin");
                    //goto L40;
                }
                jsl = isl + j - 1;
                jsu = jsl + n;
                w[jsl] = xl[j] - x[j];
                w[jsu] = xu[j] - x[j];
                if (w[jsl] >= -(rhobeg)) {
                    if (w[jsl] >= zero) {
                        x[j] = xl[j];
                        w[jsl] = zero;
                        w[jsu] = temp;
                    } else {
                        x[j] = xl[j] + rhobeg;
                        w[jsl] = -(rhobeg);
                        /* Computing MAX */
                        d__1 = xu[j] - x[j];
                        w[jsu] = std::max(d__1,rhobeg);
                    }
                } else if (w[jsu] <= rhobeg) {
                    if (w[jsu] <= zero) {
                        x[j] = xu[j];
                        w[jsl] = -temp;
                        w[jsu] = zero;
                    } else {
                        x[j] = xu[j] - rhobeg;
                        /* Computing MIN */
                        d__1 = xl[j] - x[j], d__2 = -(rhobeg);
                        w[jsl] = std::min(d__1,d__2);
                        w[jsu] = rhobeg;
                    }
                }
                /* L30: */
            }

            /*     Make the call of BOBYQB. */

            return bobyqb_(calfun, n, npt, &x[1], &xl[1], &xu[1], rhobeg, rhoend, maxfun, &w[
                    ixb], &w[ixp], &w[ifv], &w[ixo], &w[igo], &w[ihq], &w[ipq], &w[
                    ibmat], &w[izmat], ndim, &w[isl], &w[isu], &w[ixn], &w[ixa], &w[
                    id_], &w[ivl], &w[iw]);
            //L40:
            ;
        } /* bobyqa_ */

    // ----------------------------------------------------------------------------------------

        template <typename funct>
        doublereal bobyqb_(
            const funct& calfun,
            const integer n,
            const integer npt,
            doublereal *x,
            const doublereal *xl,
            const doublereal *xu,
            const doublereal rhobeg,
            const doublereal rhoend,
            const integer maxfun,
            doublereal *xbase,
            doublereal *xpt,
            doublereal *fval,
            doublereal *xopt,
            doublereal *gopt,
            doublereal *hq,
            doublereal *pq,
            doublereal *bmat,
            doublereal *zmat,
            const integer ndim,
            doublereal *sl,
            doublereal *su,
            doublereal *xnew,
            doublereal *xalt,
            doublereal *d__,
            doublereal *vlag,
            doublereal *w
        ) const
        {
            /* System generated locals */
            integer xpt_dim1, xpt_offset, bmat_dim1, bmat_offset, zmat_dim1,
            zmat_offset, i__1, i__2, i__3;
            doublereal d__1, d__2, d__3, d__4;

            /* Local variables */
            doublereal f = 0;
            integer i__, j, k, ih, nf, jj, nh, ip, jp;
            doublereal dx;
            integer np;
            doublereal den = 0, one = 0, ten = 0, dsq = 0, rho = 0, sum = 0, two = 0, diff = 0, half = 0, beta = 0, gisq = 0;
            integer knew = 0;
            doublereal temp, suma, sumb, bsum, fopt;
            integer kopt = 0, nptm;
            doublereal zero, curv;
            integer ksav;
            doublereal gqsq = 0, dist = 0, sumw = 0, sumz = 0, diffa = 0, diffb = 0, diffc = 0, hdiag = 0;
            integer kbase;
            doublereal alpha = 0, delta = 0, adelt = 0, denom = 0, fsave = 0, bdtol = 0, delsq = 0;
            integer nresc, nfsav;
            doublereal ratio = 0, dnorm = 0, vquad = 0, pqold = 0, tenth = 0;
            integer itest;
            doublereal sumpq, scaden;
            doublereal errbig, cauchy, fracsq, biglsq, densav;
            doublereal bdtest;
            doublereal crvmin, frhosq;
            doublereal distsq;
            integer ntrits;
            doublereal xoptsq;

            /*     The arguments N, NPT, X, XL, XU, RHOBEG, RHOEND, IPRINT and MAXFUN */
            /*       are identical to the corresponding arguments in SUBROUTINE BOBYQA. */
            /*     XBASE holds a shift of origin that should reduce the contributions */
            /*       from rounding errors to values of the model and Lagrange functions. */
            /*     XPT is a two-dimensional array that holds the coordinates of the */
            /*       interpolation points relative to XBASE. */
            /*     FVAL holds the values of F at the interpolation points. */
            /*     XOPT is set to the displacement from XBASE of the trust region centre. */
            /*     GOPT holds the gradient of the quadratic model at XBASE+XOPT. */
            /*     HQ holds the explicit second derivatives of the quadratic model. */
            /*     PQ contains the parameters of the implicit second derivatives of the */
            /*       quadratic model. */
            /*     BMAT holds the last N columns of H. */
            /*     ZMAT holds the factorization of the leading NPT by NPT submatrix of H, */
            /*       this factorization being ZMAT times ZMAT^T, which provides both the */
            /*       correct rank and positive semi-definiteness. */
            /*     NDIM is the first dimension of BMAT and has the value NPT+N. */
            /*     SL and SU hold the differences XL-XBASE and XU-XBASE, respectively. */
            /*       All the components of every XOPT are going to satisfy the bounds */
            /*       SL(I) .LEQ. XOPT(I) .LEQ. SU(I), with appropriate equalities when */
            /*       XOPT is on a constraint boundary. */
            /*     XNEW is chosen by SUBROUTINE TRSBOX or ALTMOV. Usually XBASE+XNEW is the */
            /*       vector of variables for the next call of CALFUN. XNEW also satisfies */
            /*       the SL and SU constraints in the way that has just been mentioned. */
            /*     XALT is an alternative to XNEW, chosen by ALTMOV, that may replace XNEW */
            /*       in order to increase the denominator in the updating of UPDATE. */
            /*     D is reserved for a trial step from XOPT, which is usually XNEW-XOPT. */
            /*     VLAG contains the values of the Lagrange functions at a new point X. */
            /*       They are part of a product that requires VLAG to be of length NDIM. */
            /*     W is a one-dimensional array that is used for working space. Its length */
            /*       must be at least 3*NDIM = 3*(NPT+N). */

            /*     Set some constants. */

            /* Parameter adjustments */
            zmat_dim1 = npt;
            zmat_offset = 1 + zmat_dim1;
            zmat -= zmat_offset;
            xpt_dim1 = npt;
            xpt_offset = 1 + xpt_dim1;
            xpt -= xpt_offset;
            --x;
            --xl;
            --xu;
            --xbase;
            --fval;
            --xopt;
            --gopt;
            --hq;
            --pq;
            bmat_dim1 = ndim;
            bmat_offset = 1 + bmat_dim1;
            bmat -= bmat_offset;
            --sl;
            --su;
            --xnew;
            --xalt;
            --d__;
            --vlag;
            --w;

            /* Function Body */
            half = .5;
            one = 1.;
            ten = 10.;
            tenth = .1;
            two = 2.;
            zero = 0.;
            np = n + 1;
            nptm = npt - np;
            nh = n * np / 2;

            /*     The call of PRELIM sets the elements of XBASE, XPT, FVAL, GOPT, HQ, PQ, */
            /*     BMAT and ZMAT for the first iteration, with the corresponding values of */
            /*     of NF and KOPT, which are the number of calls of CALFUN so far and the */
            /*     index of the interpolation point at the trust region centre. Then the */
            /*     initial XOPT is set too. The branch to label 720 occurs if MAXFUN is */
            /*     less than NPT. GOPT will be updated if KOPT is different from KBASE. */

            prelim_(calfun, n, npt, &x[1], &xl[1], &xu[1], rhobeg, maxfun, &xbase[1],
                    &xpt[xpt_offset], &fval[1], &gopt[1], &hq[1], &pq[1], &bmat[bmat_offset],
                    &zmat[zmat_offset], ndim, &sl[1], &su[1], nf, kopt);
            xoptsq = zero;
            i__1 = n;
            for (i__ = 1; i__ <= i__1; ++i__) {
                xopt[i__] = xpt[kopt + i__ * xpt_dim1];
                /* L10: */
                /* Computing 2nd power */
                d__1 = xopt[i__];
                xoptsq += d__1 * d__1;
            }
            fsave = fval[1];
            if (nf < npt) {
                throw bobyqa_failure("Return from BOBYQA because the objective function has been called max_f_evals times.");
                //goto L720;
            }
            kbase = 1;

            /*     Complete the settings that are required for the iterative procedure. */

            rho = rhobeg;
            delta = rho;
            nresc = nf;
            ntrits = 0;
            diffa = zero;
            diffb = zero;
            itest = 0;
            nfsav = nf;

            /*     Update GOPT if necessary before the first iteration and after each */
            /*     call of RESCUE that makes a call of CALFUN. */

L20:
            if (kopt != kbase) {
                ih = 0;
                i__1 = n;
                for (j = 1; j <= i__1; ++j) {
                    i__2 = j;
                    for (i__ = 1; i__ <= i__2; ++i__) {
                        ++ih;
                        if (i__ < j) {
                            gopt[j] += hq[ih] * xopt[i__];
                        }
                        /* L30: */
                        gopt[i__] += hq[ih] * xopt[j];
                    }
                }
                if (nf > npt) {
                    i__2 = npt;
                    for (k = 1; k <= i__2; ++k) {
                        temp = zero;
                        i__1 = n;
                        for (j = 1; j <= i__1; ++j) {
                            /* L40: */
                            temp += xpt[k + j * xpt_dim1] * xopt[j];
                        }
                        temp = pq[k] * temp;
                        i__1 = n;
                        for (i__ = 1; i__ <= i__1; ++i__) {
                            /* L50: */
                            gopt[i__] += temp * xpt[k + i__ * xpt_dim1];
                        }
                    }
                }
            }

            /*     Generate the next point in the trust region that provides a small value */
            /*     of the quadratic model subject to the constraints on the variables. */
            /*     The integer NTRITS is set to the number "trust region" iterations that */
            /*     have occurred since the last "alternative" iteration. If the length */
            /*     of XNEW-XOPT is less than HALF*RHO, however, then there is a branch to */
            /*     label 650 or 680 with NTRITS=-1, instead of calculating F at XNEW. */

L60:
            trsbox_(n, npt, &xpt[xpt_offset], &xopt[1], &gopt[1], &hq[1], &pq[1], &sl[1],
                    &su[1], delta, &xnew[1], &d__[1], &w[1], &w[np], &w[np + n],
                    &w[np + (n << 1)], &w[np + n * 3], &dsq, &crvmin);
            /* Computing MIN */
            d__1 = delta, d__2 = std::sqrt(dsq);
            dnorm = std::min(d__1,d__2);
            if (dnorm < half * rho) {
                ntrits = -1;
                /* Computing 2nd power */
                d__1 = ten * rho;
                distsq = d__1 * d__1;
                if (nf <= nfsav + 2) {
                    goto L650;
                }

                /*     The following choice between labels 650 and 680 depends on whether or */
                /*     not our work with the current RHO seems to be complete. Either RHO is */
                /*     decreased or termination occurs if the errors in the quadratic model at */
                /*     the last three interpolation points compare favourably with predictions */
                /*     of likely improvements to the model within distance HALF*RHO of XOPT. */

                /* Computing MAX */
                d__1 = std::max(diffa,diffb);
                errbig = std::max(d__1,diffc);
                frhosq = rho * .125 * rho;
                if (crvmin > zero && errbig > frhosq * crvmin) {
                    goto L650;
                }
                bdtol = errbig / rho;
                i__1 = n;
                for (j = 1; j <= i__1; ++j) {
                    bdtest = bdtol;
                    if (xnew[j] == sl[j]) {
                        bdtest = w[j];
                    }
                    if (xnew[j] == su[j]) {
                        bdtest = -w[j];
                    }
                    if (bdtest < bdtol) {
                        curv = hq[(j + j * j) / 2];
                        i__2 = npt;
                        for (k = 1; k <= i__2; ++k) {
                            /* L70: */
                            /* Computing 2nd power */
                            d__1 = xpt[k + j * xpt_dim1];
                            curv += pq[k] * (d__1 * d__1);
                        }
                        bdtest += half * curv * rho;
                        if (bdtest < bdtol) {
                            goto L650;
                        }
                    }
                    /* L80: */
                }
                goto L680;
            }
            ++ntrits;

            /*     Severe cancellation is likely to occur if XOPT is too far from XBASE. */
            /*     If the following test holds, then XBASE is shifted so that XOPT becomes */
            /*     zero. The appropriate changes are made to BMAT and to the second */
            /*     derivatives of the current model, beginning with the changes to BMAT */
            /*     that do not depend on ZMAT. VLAG is used temporarily for working space. */

L90:
            if (dsq <= xoptsq * .001) {
                fracsq = xoptsq * .25;
                sumpq = zero;
                i__1 = npt;
                for (k = 1; k <= i__1; ++k) {
                    sumpq += pq[k];
                    sum = -half * xoptsq;
                    i__2 = n;
                    for (i__ = 1; i__ <= i__2; ++i__) {
                        /* L100: */
                        sum += xpt[k + i__ * xpt_dim1] * xopt[i__];
                    }
                    w[npt + k] = sum;
                    temp = fracsq - half * sum;
                    i__2 = n;
                    for (i__ = 1; i__ <= i__2; ++i__) {
                        w[i__] = bmat[k + i__ * bmat_dim1];
                        vlag[i__] = sum * xpt[k + i__ * xpt_dim1] + temp * xopt[i__];
                        ip = npt + i__;
                        i__3 = i__;
                        for (j = 1; j <= i__3; ++j) {
                            /* L110: */
                            bmat[ip + j * bmat_dim1] = bmat[ip + j * bmat_dim1] + w[
                                i__] * vlag[j] + vlag[i__] * w[j];
                        }
                    }
                }

                /*     Then the revisions of BMAT that depend on ZMAT are calculated. */

                i__3 = nptm;
                for (jj = 1; jj <= i__3; ++jj) {
                    sumz = zero;
                    sumw = zero;
                    i__2 = npt;
                    for (k = 1; k <= i__2; ++k) {
                        sumz += zmat[k + jj * zmat_dim1];
                        vlag[k] = w[npt + k] * zmat[k + jj * zmat_dim1];
                        /* L120: */
                        sumw += vlag[k];
                    }
                    i__2 = n;
                    for (j = 1; j <= i__2; ++j) {
                        sum = (fracsq * sumz - half * sumw) * xopt[j];
                        i__1 = npt;
                        for (k = 1; k <= i__1; ++k) {
                            /* L130: */
                            sum += vlag[k] * xpt[k + j * xpt_dim1];
                        }
                        w[j] = sum;
                        i__1 = npt;
                        for (k = 1; k <= i__1; ++k) {
                            /* L140: */
                            bmat[k + j * bmat_dim1] += sum * zmat[k + jj * zmat_dim1];
                        }
                    }
                    i__1 = n;
                    for (i__ = 1; i__ <= i__1; ++i__) {
                        ip = i__ + npt;
                        temp = w[i__];
                        i__2 = i__;
                        for (j = 1; j <= i__2; ++j) {
                            /* L150: */
                            bmat[ip + j * bmat_dim1] += temp * w[j];
                        }
                    }
                }

                /*     The following instructions complete the shift, including the changes */
                /*     to the second derivative parameters of the quadratic model. */

                ih = 0;
                i__2 = n;
                for (j = 1; j <= i__2; ++j) {
                    w[j] = -half * sumpq * xopt[j];
                    i__1 = npt;
                    for (k = 1; k <= i__1; ++k) {
                        w[j] += pq[k] * xpt[k + j * xpt_dim1];
                        /* L160: */
                        xpt[k + j * xpt_dim1] -= xopt[j];
                    }
                    i__1 = j;
                    for (i__ = 1; i__ <= i__1; ++i__) {
                        ++ih;
                        hq[ih] = hq[ih] + w[i__] * xopt[j] + xopt[i__] * w[j];
                        /* L170: */
                        bmat[npt + i__ + j * bmat_dim1] = bmat[npt + j + i__ *
                            bmat_dim1];
                    }
                }
                i__1 = n;
                for (i__ = 1; i__ <= i__1; ++i__) {
                    xbase[i__] += xopt[i__];
                    xnew[i__] -= xopt[i__];
                    sl[i__] -= xopt[i__];
                    su[i__] -= xopt[i__];
                    /* L180: */
                    xopt[i__] = zero;
                }
                xoptsq = zero;
            }
            if (ntrits == 0) {
                goto L210;
            }
            goto L230;

            /*     XBASE is also moved to XOPT by a call of RESCUE. This calculation is */
            /*     more expensive than the previous shift, because new matrices BMAT and */
            /*     ZMAT are generated from scratch, which may include the replacement of */
            /*     interpolation points whose positions seem to be causing near linear */
            /*     dependence in the interpolation conditions. Therefore RESCUE is called */
            /*     only if rounding errors have reduced by at least a factor of two the */
            /*     denominator of the formula for updating the H matrix. It provides a */
            /*     useful safeguard, but is not invoked in most applications of BOBYQA. */

L190:
            nfsav = nf;
            kbase = kopt;
            rescue_(calfun, n, npt, &xl[1], &xu[1], maxfun, &xbase[1], &xpt[
                    xpt_offset], &fval[1], &xopt[1], &gopt[1], &hq[1], &pq[1], &bmat[
                    bmat_offset], &zmat[zmat_offset], ndim, &sl[1], &su[1], nf, delta,
                    kopt, &vlag[1], &w[1], &w[n + np], &w[ndim + np]);

            /*     XOPT is updated now in case the branch below to label 720 is taken. */
            /*     Any updating of GOPT occurs after the branch below to label 20, which */
            /*     leads to a trust region iteration as does the branch to label 60. */

            xoptsq = zero;
            if (kopt != kbase) {
                i__1 = n;
                for (i__ = 1; i__ <= i__1; ++i__) {
                    xopt[i__] = xpt[kopt + i__ * xpt_dim1];
                    /* L200: */
                    /* Computing 2nd power */
                    d__1 = xopt[i__];
                    xoptsq += d__1 * d__1;
                }
            }
            if (nf < 0) {
                nf = maxfun;
                throw bobyqa_failure("Return from BOBYQA because the objective function has been called max_f_evals times.");
                //goto L720;
            }
            nresc = nf;
            if (nfsav < nf) {
                nfsav = nf;
                goto L20;
            }
            if (ntrits > 0) {
                goto L60;
            }

            /*     Pick two alternative vectors of variables, relative to XBASE, that */
            /*     are suitable as new positions of the KNEW-th interpolation point. */
            /*     Firstly, XNEW is set to the point on a line through XOPT and another */
            /*     interpolation point that minimizes the predicted value of the next */
            /*     denominator, subject to ||XNEW - XOPT|| .LEQ. ADELT and to the SL */
            /*     and SU bounds. Secondly, XALT is set to the best feasible point on */
            /*     a constrained version of the Cauchy step of the KNEW-th Lagrange */
            /*     function, the corresponding value of the square of this function */
            /*     being returned in CAUCHY. The choice between these alternatives is */
            /*     going to be made when the denominator is calculated. */

L210:
            altmov_(n, npt, &xpt[xpt_offset], &xopt[1], &bmat[bmat_offset], &zmat[zmat_offset],
                    ndim, &sl[1], &su[1], kopt, knew, adelt, &xnew[1],
                    &xalt[1], alpha, cauchy, &w[1], &w[np], &w[ndim + 1]);
            i__1 = n;
            for (i__ = 1; i__ <= i__1; ++i__) {
                /* L220: */
                d__[i__] = xnew[i__] - xopt[i__];
            }

            /*     Calculate VLAG and BETA for the current choice of D. The scalar */
            /*     product of D with XPT(K,.) is going to be held in W(NPT+K) for */
            /*     use when VQUAD is calculated. */

L230:
            i__1 = npt;
            for (k = 1; k <= i__1; ++k) {
                suma = zero;
                sumb = zero;
                sum = zero;
                i__2 = n;
                for (j = 1; j <= i__2; ++j) {
                    suma += xpt[k + j * xpt_dim1] * d__[j];
                    sumb += xpt[k + j * xpt_dim1] * xopt[j];
                    /* L240: */
                    sum += bmat[k + j * bmat_dim1] * d__[j];
                }
                w[k] = suma * (half * suma + sumb);
                vlag[k] = sum;
                /* L250: */
                w[npt + k] = suma;
            }
            beta = zero;
            i__1 = nptm;
            for (jj = 1; jj <= i__1; ++jj) {
                sum = zero;
                i__2 = npt;
                for (k = 1; k <= i__2; ++k) {
                    /* L260: */
                    sum += zmat[k + jj * zmat_dim1] * w[k];
                }
                beta -= sum * sum;
                i__2 = npt;
                for (k = 1; k <= i__2; ++k) {
                    /* L270: */
                    vlag[k] += sum * zmat[k + jj * zmat_dim1];
                }
            }
            dsq = zero;
            bsum = zero;
            dx = zero;
            i__2 = n;
            for (j = 1; j <= i__2; ++j) {
                /* Computing 2nd power */
                d__1 = d__[j];
                dsq += d__1 * d__1;
                sum = zero;
                i__1 = npt;
                for (k = 1; k <= i__1; ++k) {
                    /* L280: */
                    sum += w[k] * bmat[k + j * bmat_dim1];
                }
                bsum += sum * d__[j];
                jp = npt + j;
                i__1 = n;
                for (i__ = 1; i__ <= i__1; ++i__) {
                    /* L290: */
                    sum += bmat[jp + i__ * bmat_dim1] * d__[i__];
                }
                vlag[jp] = sum;
                bsum += sum * d__[j];
                /* L300: */
                dx += d__[j] * xopt[j];
            }
            beta = dx * dx + dsq * (xoptsq + dx + dx + half * dsq) + beta - bsum;
            vlag[kopt] += one;

            /*     If NTRITS is zero, the denominator may be increased by replacing */
            /*     the step D of ALTMOV by a Cauchy step. Then RESCUE may be called if */
            /*     rounding errors have damaged the chosen denominator. */

            if (ntrits == 0) {
                /* Computing 2nd power */
                d__1 = vlag[knew];
                denom = d__1 * d__1 + alpha * beta;
                if (denom < cauchy && cauchy > zero) {
                    i__2 = n;
                    for (i__ = 1; i__ <= i__2; ++i__) {
                        xnew[i__] = xalt[i__];
                        /* L310: */
                        d__[i__] = xnew[i__] - xopt[i__];
                    }
                    cauchy = zero;
                    goto L230;
                }
                /* Computing 2nd power */
                d__1 = vlag[knew];
                if (denom <= half * (d__1 * d__1)) {
                    if (nf > nresc) {
                        goto L190;
                    }
                    throw bobyqa_failure("Return from BOBYQA because of much cancellation in a denominator.");
                    //goto L720;
                }

                /*     Alternatively, if NTRITS is positive, then set KNEW to the index of */
                /*     the next interpolation point to be deleted to make room for a trust */
                /*     region step. Again RESCUE may be called if rounding errors have damaged */
                /*     the chosen denominator, which is the reason for attempting to select */
                /*     KNEW before calculating the next value of the objective function. */

            } else {
                delsq = delta * delta;
                scaden = zero;
                biglsq = zero;
                knew = 0;
                i__2 = npt;
                for (k = 1; k <= i__2; ++k) {
                    if (k == kopt) {
                        goto L350;
                    }
                    hdiag = zero;
                    i__1 = nptm;
                    for (jj = 1; jj <= i__1; ++jj) {
                        /* L330: */
                        /* Computing 2nd power */
                        d__1 = zmat[k + jj * zmat_dim1];
                        hdiag += d__1 * d__1;
                    }
                    /* Computing 2nd power */
                    d__1 = vlag[k];
                    den = beta * hdiag + d__1 * d__1;
                    distsq = zero;
                    i__1 = n;
                    for (j = 1; j <= i__1; ++j) {
                        /* L340: */
                        /* Computing 2nd power */
                        d__1 = xpt[k + j * xpt_dim1] - xopt[j];
                        distsq += d__1 * d__1;
                    }
                    /* Computing MAX */
                    /* Computing 2nd power */
                    d__3 = distsq / delsq;
                    d__1 = one, d__2 = d__3 * d__3;
                    temp = std::max(d__1,d__2);
                    if (temp * den > scaden) {
                        scaden = temp * den;
                        knew = k;
                        denom = den;
                    }
                    /* Computing MAX */
                    /* Computing 2nd power */
                    d__3 = vlag[k];
                    d__1 = biglsq, d__2 = temp * (d__3 * d__3);
                    biglsq = std::max(d__1,d__2);
L350:
                    ;
                }
                if (scaden <= half * biglsq) {
                    if (nf > nresc) {
                        goto L190;
                    }
                    throw bobyqa_failure("Return from BOBYQA because of much cancellation in a denominator.");
                    //goto L720;
                }
            }

            /*     Put the variables for the next calculation of the objective function */
            /*       in XNEW, with any adjustments for the bounds. */

            /*     Calculate the value of the objective function at XBASE+XNEW, unless */
            /*       the limit on the number of calculations of F has been reached. */

L360:
            i__2 = n;
            for (i__ = 1; i__ <= i__2; ++i__) {
                /* Computing MIN */
                /* Computing MAX */
                d__3 = xl[i__], d__4 = xbase[i__] + xnew[i__];
                d__1 = std::max(d__3,d__4), d__2 = xu[i__];
                x[i__] = std::min(d__1,d__2);
                if (xnew[i__] == sl[i__]) {
                    x[i__] = xl[i__];
                }
                if (xnew[i__] == su[i__]) {
                    x[i__] = xu[i__];
                }
                /* L380: */
            }
            if (nf >= maxfun) {
                throw bobyqa_failure("Return from BOBYQA because the objective function has been called max_f_evals times.");
                //goto L720;
            }
            ++nf;
            f = calfun(mat(&x[1], n));
            if (ntrits == -1) {
                fsave = f;
                goto L720;
            }

            /*     Use the quadratic model to predict the change in F due to the step D, */
            /*       and set DIFF to the error of this prediction. */

            fopt = fval[kopt];
            vquad = zero;
            ih = 0;
            i__2 = n;
            for (j = 1; j <= i__2; ++j) {
                vquad += d__[j] * gopt[j];
                i__1 = j;
                for (i__ = 1; i__ <= i__1; ++i__) {
                    ++ih;
                    temp = d__[i__] * d__[j];
                    if (i__ == j) {
                        temp = half * temp;
                    }
                    /* L410: */
                    vquad += hq[ih] * temp;
                }
            }
            i__1 = npt;
            for (k = 1; k <= i__1; ++k) {
                /* L420: */
                /* Computing 2nd power */
                d__1 = w[npt + k];
                vquad += half * pq[k] * (d__1 * d__1);
            }
            diff = f - fopt - vquad;
            diffc = diffb;
            diffb = diffa;
            diffa = std::abs(diff);
            if (dnorm > rho) {
                nfsav = nf;
            }

            /*     Pick the next value of DELTA after a trust region step. */

            if (ntrits > 0) {
                if (vquad >= zero) {
                    throw bobyqa_failure("Return from BOBYQA because a trust region step has failed to reduce Q.");
                    //goto L720;
                }
                ratio = (f - fopt) / vquad;
                if (ratio <= tenth) {
                    /* Computing MIN */
                    d__1 = half * delta;
                    delta = std::min(d__1,dnorm);
                } else if (ratio <= .7) {
                    /* Computing MAX */
                    d__1 = half * delta;
                    delta = std::max(d__1,dnorm);
                } else {
                    /* Computing MAX */
                    d__1 = half * delta, d__2 = dnorm + dnorm;
                    delta = std::max(d__1,d__2);
                }
                if (delta <= rho * 1.5) {
                    delta = rho;
                }

                /*     Recalculate KNEW and DENOM if the new F is less than FOPT. */

                if (f < fopt) {
                    ksav = knew;
                    densav = denom;
                    delsq = delta * delta;
                    scaden = zero;
                    biglsq = zero;
                    knew = 0;
                    i__1 = npt;
                    for (k = 1; k <= i__1; ++k) {
                        hdiag = zero;
                        i__2 = nptm;
                        for (jj = 1; jj <= i__2; ++jj) {
                            /* L440: */
                            /* Computing 2nd power */
                            d__1 = zmat[k + jj * zmat_dim1];
                            hdiag += d__1 * d__1;
                        }
                        /* Computing 2nd power */
                        d__1 = vlag[k];
                        den = beta * hdiag + d__1 * d__1;
                        distsq = zero;
                        i__2 = n;
                        for (j = 1; j <= i__2; ++j) {
                            /* L450: */
                            /* Computing 2nd power */
                            d__1 = xpt[k + j * xpt_dim1] - xnew[j];
                            distsq += d__1 * d__1;
                        }
                        /* Computing MAX */
                        /* Computing 2nd power */
                        d__3 = distsq / delsq;
                        d__1 = one, d__2 = d__3 * d__3;
                        temp = std::max(d__1,d__2);
                        if (temp * den > scaden) {
                            scaden = temp * den;
                            knew = k;
                            denom = den;
                        }
                        /* L460: */
                        /* Computing MAX */
                        /* Computing 2nd power */
                        d__3 = vlag[k];
                        d__1 = biglsq, d__2 = temp * (d__3 * d__3);
                        biglsq = std::max(d__1,d__2);
                    }
                    if (scaden <= half * biglsq) {
                        knew = ksav;
                        denom = densav;
                    }
                }
            }

            /*     Update BMAT and ZMAT, so that the KNEW-th interpolation point can be */
            /*     moved. Also update the second derivative terms of the model. */

            update_(n, npt, &bmat[bmat_offset], &zmat[zmat_offset], ndim, &vlag[1],
                    beta, denom, knew, &w[1]);
            ih = 0;
            pqold = pq[knew];
            pq[knew] = zero;
            i__1 = n;
            for (i__ = 1; i__ <= i__1; ++i__) {
                temp = pqold * xpt[knew + i__ * xpt_dim1];
                i__2 = i__;
                for (j = 1; j <= i__2; ++j) {
                    ++ih;
                    /* L470: */
                    hq[ih] += temp * xpt[knew + j * xpt_dim1];
                }
            }
            i__2 = nptm;
            for (jj = 1; jj <= i__2; ++jj) {
                temp = diff * zmat[knew + jj * zmat_dim1];
                i__1 = npt;
                for (k = 1; k <= i__1; ++k) {
                    /* L480: */
                    pq[k] += temp * zmat[k + jj * zmat_dim1];
                }
            }

            /*     Include the new interpolation point, and make the changes to GOPT at */
            /*     the old XOPT that are caused by the updating of the quadratic model. */

            fval[knew] = f;
            i__1 = n;
            for (i__ = 1; i__ <= i__1; ++i__) {
                xpt[knew + i__ * xpt_dim1] = xnew[i__];
                /* L490: */
                w[i__] = bmat[knew + i__ * bmat_dim1];
            }
            i__1 = npt;
            for (k = 1; k <= i__1; ++k) {
                suma = zero;
                i__2 = nptm;
                for (jj = 1; jj <= i__2; ++jj) {
                    /* L500: */
                    suma += zmat[knew + jj * zmat_dim1] * zmat[k + jj * zmat_dim1];
                }
                sumb = zero;
                i__2 = n;
                for (j = 1; j <= i__2; ++j) {
                    /* L510: */
                    sumb += xpt[k + j * xpt_dim1] * xopt[j];
                }
                temp = suma * sumb;
                i__2 = n;
                for (i__ = 1; i__ <= i__2; ++i__) {
                    /* L520: */
                    w[i__] += temp * xpt[k + i__ * xpt_dim1];
                }
            }
            i__2 = n;
            for (i__ = 1; i__ <= i__2; ++i__) {
                /* L530: */
                gopt[i__] += diff * w[i__];
            }

            /*     Update XOPT, GOPT and KOPT if the new calculated F is less than FOPT. */

            if (f < fopt) {
                kopt = knew;
                xoptsq = zero;
                ih = 0;
                i__2 = n;
                for (j = 1; j <= i__2; ++j) {
                    xopt[j] = xnew[j];
                    /* Computing 2nd power */
                    d__1 = xopt[j];
                    xoptsq += d__1 * d__1;
                    i__1 = j;
                    for (i__ = 1; i__ <= i__1; ++i__) {
                        ++ih;
                        if (i__ < j) {
                            gopt[j] += hq[ih] * d__[i__];
                        }
                        /* L540: */
                        gopt[i__] += hq[ih] * d__[j];
                    }
                }
                i__1 = npt;
                for (k = 1; k <= i__1; ++k) {
                    temp = zero;
                    i__2 = n;
                    for (j = 1; j <= i__2; ++j) {
                        /* L550: */
                        temp += xpt[k + j * xpt_dim1] * d__[j];
                    }
                    temp = pq[k] * temp;
                    i__2 = n;
                    for (i__ = 1; i__ <= i__2; ++i__) {
                        /* L560: */
                        gopt[i__] += temp * xpt[k + i__ * xpt_dim1];
                    }
                }
            }

            /*     Calculate the parameters of the least Frobenius norm interpolant to */
            /*     the current data, the gradient of this interpolant at XOPT being put */
            /*     into VLAG(NPT+I), I=1,2,...,N. */

            if (ntrits > 0) {
                i__2 = npt;
                for (k = 1; k <= i__2; ++k) {
                    vlag[k] = fval[k] - fval[kopt];
                    /* L570: */
                    w[k] = zero;
                }
                i__2 = nptm;
                for (j = 1; j <= i__2; ++j) {
                    sum = zero;
                    i__1 = npt;
                    for (k = 1; k <= i__1; ++k) {
                        /* L580: */
                        sum += zmat[k + j * zmat_dim1] * vlag[k];
                    }
                    i__1 = npt;
                    for (k = 1; k <= i__1; ++k) {
                        /* L590: */
                        w[k] += sum * zmat[k + j * zmat_dim1];
                    }
                }
                i__1 = npt;
                for (k = 1; k <= i__1; ++k) {
                    sum = zero;
                    i__2 = n;
                    for (j = 1; j <= i__2; ++j) {
                        /* L600: */
                        sum += xpt[k + j * xpt_dim1] * xopt[j];
                    }
                    w[k + npt] = w[k];
                    /* L610: */
                    w[k] = sum * w[k];
                }
                gqsq = zero;
                gisq = zero;
                i__1 = n;
                for (i__ = 1; i__ <= i__1; ++i__) {
                    sum = zero;
                    i__2 = npt;
                    for (k = 1; k <= i__2; ++k) {
                        /* L620: */
                        sum = sum + bmat[k + i__ * bmat_dim1] * vlag[k] + xpt[k + i__
                            * xpt_dim1] * w[k];
                    }
                    if (xopt[i__] == sl[i__]) {
                        /* Computing MIN */
                        d__2 = zero, d__3 = gopt[i__];
                        /* Computing 2nd power */
                        d__1 = std::min(d__2,d__3);
                        gqsq += d__1 * d__1;
                        /* Computing 2nd power */
                        d__1 = std::min(zero,sum);
                        gisq += d__1 * d__1;
                    } else if (xopt[i__] == su[i__]) {
                        /* Computing MAX */
                        d__2 = zero, d__3 = gopt[i__];
                        /* Computing 2nd power */
                        d__1 = std::max(d__2,d__3);
                        gqsq += d__1 * d__1;
                        /* Computing 2nd power */
                        d__1 = std::max(zero,sum);
                        gisq += d__1 * d__1;
                    } else {
                        /* Computing 2nd power */
                        d__1 = gopt[i__];
                        gqsq += d__1 * d__1;
                        gisq += sum * sum;
                    }
                    /* L630: */
                    vlag[npt + i__] = sum;
                }

                /*     Test whether to replace the new quadratic model by the least Frobenius */
                /*     norm interpolant, making the replacement if the test is satisfied. */

                ++itest;
                if (gqsq < ten * gisq) {
                    itest = 0;
                }
                if (itest >= 3) {
                    i__1 = std::max(npt,nh);
                    for (i__ = 1; i__ <= i__1; ++i__) {
                        if (i__ <= n) {
                            gopt[i__] = vlag[npt + i__];
                        }
                        if (i__ <= npt) {
                            pq[i__] = w[npt + i__];
                        }
                        if (i__ <= nh) {
                            hq[i__] = zero;
                        }
                        itest = 0;
                        /* L640: */
                    }
                }
            }

            /*     If a trust region step has provided a sufficient decrease in F, then */
            /*     branch for another trust region calculation. The case NTRITS=0 occurs */
            /*     when the new interpolation point was reached by an alternative step. */

            if (ntrits == 0) {
                goto L60;
            }
            if (f <= fopt + tenth * vquad) {
                goto L60;
            }

            /*     Alternatively, find out if the interpolation points are close enough */
            /*       to the best point so far. */

            /* Computing MAX */
            /* Computing 2nd power */
            d__3 = two * delta;
            /* Computing 2nd power */
            d__4 = ten * rho;
            d__1 = d__3 * d__3, d__2 = d__4 * d__4;
            distsq = std::max(d__1,d__2);
L650:
            knew = 0;
            i__1 = npt;
            for (k = 1; k <= i__1; ++k) {
                sum = zero;
                i__2 = n;
                for (j = 1; j <= i__2; ++j) {
                    /* L660: */
                    /* Computing 2nd power */
                    d__1 = xpt[k + j * xpt_dim1] - xopt[j];
                    sum += d__1 * d__1;
                }
                if (sum > distsq) {
                    knew = k;
                    distsq = sum;
                }
                /* L670: */
            }

            /*     If KNEW is positive, then ALTMOV finds alternative new positions for */
            /*     the KNEW-th interpolation point within distance ADELT of XOPT. It is */
            /*     reached via label 90. Otherwise, there is a branch to label 60 for */
            /*     another trust region iteration, unless the calculations with the */
            /*     current RHO are complete. */

            if (knew > 0) {
                dist = std::sqrt(distsq);
                if (ntrits == -1) {
                    /* Computing MIN */
                    d__1 = tenth * delta, d__2 = half * dist;
                    delta = std::min(d__1,d__2);
                    if (delta <= rho * 1.5) {
                        delta = rho;
                    }
                }
                ntrits = 0;
                /* Computing MAX */
                /* Computing MIN */
                d__2 = tenth * dist;
                d__1 = std::min(d__2,delta);
                adelt = std::max(d__1,rho);
                dsq = adelt * adelt;
                goto L90;
            }
            if (ntrits == -1) {
                goto L680;
            }
            if (ratio > zero) {
                goto L60;
            }
            if (std::max(delta,dnorm) > rho) {
                goto L60;
            }

            /*     The calculations with the current value of RHO are complete. Pick the */
            /*       next values of RHO and DELTA. */

L680:
            if (rho > rhoend) {
                delta = half * rho;
                ratio = rho / rhoend;
                if (ratio <= 16.) {
                    rho = rhoend;
                } else if (ratio <= 250.) {
                    rho = std::sqrt(ratio) * rhoend;
                } else {
                    rho = tenth * rho;
                }
                delta = std::max(delta,rho);
                ntrits = 0;
                nfsav = nf;
                goto L60;
            }

            /*     Return from the calculation, after another Newton-Raphson step, if */
            /*       it is too short to have been tried before. */

            if (ntrits == -1) {
                goto L360;
            }
L720:
            if (fval[kopt] <= fsave) {
                i__1 = n;
                for (i__ = 1; i__ <= i__1; ++i__) {
                    /* Computing MIN */
                    /* Computing MAX */
                    d__3 = xl[i__], d__4 = xbase[i__] + xopt[i__];
                    d__1 = std::max(d__3,d__4), d__2 = xu[i__];
                    x[i__] = std::min(d__1,d__2);
                    if (xopt[i__] == sl[i__]) {
                        x[i__] = xl[i__];
                    }
                    if (xopt[i__] == su[i__]) {
                        x[i__] = xu[i__];
                    }
                    /* L730: */
                }
                f = fval[kopt];
            }

            return f;
        } /* bobyqb_ */

    // ----------------------------------------------------------------------------------------

        void altmov_(
            const integer n,
            const integer npt,
            const doublereal *xpt,
            const doublereal *xopt,
            const doublereal *bmat,
            const doublereal *zmat,
            const integer ndim,
            const doublereal *sl,
            const doublereal *su,
            const integer kopt,
            const integer knew,
            const doublereal adelt,
            doublereal *xnew,
            doublereal *xalt,
            doublereal& alpha,
            doublereal& cauchy,
            doublereal *glag,
            doublereal *hcol,
            doublereal *w
        ) const
        {
            /* System generated locals */
            integer xpt_dim1, xpt_offset, bmat_dim1, bmat_offset, zmat_dim1,
            zmat_offset, i__1, i__2;
            doublereal d__1, d__2, d__3, d__4;

            /* Local variables */
            integer i__, j, k;
            doublereal ha, gw, one, diff, half;
            integer ilbd, isbd;
            doublereal slbd;
            integer iubd;
            doublereal vlag, subd, temp;
            integer ksav = 0;
            doublereal step = 0, zero = 0, curv = 0;
            integer iflag;
            doublereal scale = 0, csave = 0, tempa = 0, tempb = 0, tempd = 0, const__ = 0, sumin = 0,
                       ggfree = 0;
            integer ibdsav = 0;
            doublereal dderiv = 0, bigstp = 0, predsq = 0, presav = 0, distsq = 0, stpsav = 0, wfixsq = 0, wsqsav = 0;

            /*     The arguments N, NPT, XPT, XOPT, BMAT, ZMAT, NDIM, SL and SU all have */
            /*       the same meanings as the corresponding arguments of BOBYQB. */
            /*     KOPT is the index of the optimal interpolation point. */
            /*     KNEW is the index of the interpolation point that is going to be moved. */
            /*     ADELT is the current trust region bound. */
            /*     XNEW will be set to a suitable new position for the interpolation point */
            /*       XPT(KNEW,.). Specifically, it satisfies the SL, SU and trust region */
            /*       bounds and it should provide a large denominator in the next call of */
            /*       UPDATE. The step XNEW-XOPT from XOPT is restricted to moves along the */
            /*       straight lines through XOPT and another interpolation point. */
            /*     XALT also provides a large value of the modulus of the KNEW-th Lagrange */
            /*       function subject to the constraints that have been mentioned, its main */
            /*       difference from XNEW being that XALT-XOPT is a constrained version of */
            /*       the Cauchy step within the trust region. An exception is that XALT is */
            /*       not calculated if all components of GLAG (see below) are zero. */
            /*     ALPHA will be set to the KNEW-th diagonal element of the H matrix. */
            /*     CAUCHY will be set to the square of the KNEW-th Lagrange function at */
            /*       the step XALT-XOPT from XOPT for the vector XALT that is returned, */
            /*       except that CAUCHY is set to zero if XALT is not calculated. */
            /*     GLAG is a working space vector of length N for the gradient of the */
            /*       KNEW-th Lagrange function at XOPT. */
            /*     HCOL is a working space vector of length NPT for the second derivative */
            /*       coefficients of the KNEW-th Lagrange function. */
            /*     W is a working space vector of length 2N that is going to hold the */
            /*       constrained Cauchy step from XOPT of the Lagrange function, followed */
            /*       by the downhill version of XALT when the uphill step is calculated. */

            /*     Set the first NPT components of W to the leading elements of the */
            /*     KNEW-th column of the H matrix. */

            /* Parameter adjustments */
            zmat_dim1 = npt;
            zmat_offset = 1 + zmat_dim1;
            zmat -= zmat_offset;
            xpt_dim1 = npt;
            xpt_offset = 1 + xpt_dim1;
            xpt -= xpt_offset;
            --xopt;
            bmat_dim1 = ndim;
            bmat_offset = 1 + bmat_dim1;
            bmat -= bmat_offset;
            --sl;
            --su;
            --xnew;
            --xalt;
            --glag;
            --hcol;
            --w;

            /* Function Body */
            half = .5;
            one = 1.;
            zero = 0.;
            const__ = one + std::sqrt(2.);
            i__1 = npt;
            for (k = 1; k <= i__1; ++k) {
                /* L10: */
                hcol[k] = zero;
            }
            i__1 = npt - n - 1;
            for (j = 1; j <= i__1; ++j) {
                temp = zmat[knew + j * zmat_dim1];
                i__2 = npt;
                for (k = 1; k <= i__2; ++k) {
                    /* L20: */
                    hcol[k] += temp * zmat[k + j * zmat_dim1];
                }
            }
            alpha = hcol[knew];
            ha = half * alpha;

            /*     Calculate the gradient of the KNEW-th Lagrange function at XOPT. */

            i__2 = n;
            for (i__ = 1; i__ <= i__2; ++i__) {
                /* L30: */
                glag[i__] = bmat[knew + i__ * bmat_dim1];
            }
            i__2 = npt;
            for (k = 1; k <= i__2; ++k) {
                temp = zero;
                i__1 = n;
                for (j = 1; j <= i__1; ++j) {
                    /* L40: */
                    temp += xpt[k + j * xpt_dim1] * xopt[j];
                }
                temp = hcol[k] * temp;
                i__1 = n;
                for (i__ = 1; i__ <= i__1; ++i__) {
                    /* L50: */
                    glag[i__] += temp * xpt[k + i__ * xpt_dim1];
                }
            }

            /*     Search for a large denominator along the straight lines through XOPT */
            /*     and another interpolation point. SLBD and SUBD will be lower and upper */
            /*     bounds on the step along each of these lines in turn. PREDSQ will be */
            /*     set to the square of the predicted denominator for each line. PRESAV */
            /*     will be set to the largest admissible value of PREDSQ that occurs. */

            presav = zero;
            i__1 = npt;
            for (k = 1; k <= i__1; ++k) {
                if (k == kopt) {
                    goto L80;
                }
                dderiv = zero;
                distsq = zero;
                i__2 = n;
                for (i__ = 1; i__ <= i__2; ++i__) {
                    temp = xpt[k + i__ * xpt_dim1] - xopt[i__];
                    dderiv += glag[i__] * temp;
                    /* L60: */
                    distsq += temp * temp;
                }
                subd = adelt / std::sqrt(distsq);
                slbd = -subd;
                ilbd = 0;
                iubd = 0;
                sumin = std::min(one,subd);

                /*     Revise SLBD and SUBD if necessary because of the bounds in SL and SU. */

                i__2 = n;
                for (i__ = 1; i__ <= i__2; ++i__) {
                    temp = xpt[k + i__ * xpt_dim1] - xopt[i__];
                    if (temp > zero) {
                        if (slbd * temp < sl[i__] - xopt[i__]) {
                            slbd = (sl[i__] - xopt[i__]) / temp;
                            ilbd = -i__;
                        }
                        if (subd * temp > su[i__] - xopt[i__]) {
                            /* Computing MAX */
                            d__1 = sumin, d__2 = (su[i__] - xopt[i__]) / temp;
                            subd = std::max(d__1,d__2);
                            iubd = i__;
                        }
                    } else if (temp < zero) {
                        if (slbd * temp > su[i__] - xopt[i__]) {
                            slbd = (su[i__] - xopt[i__]) / temp;
                            ilbd = i__;
                        }
                        if (subd * temp < sl[i__] - xopt[i__]) {
                            /* Computing MAX */
                            d__1 = sumin, d__2 = (sl[i__] - xopt[i__]) / temp;
                            subd = std::max(d__1,d__2);
                            iubd = -i__;
                        }
                    }
                    /* L70: */
                }

                /*     Seek a large modulus of the KNEW-th Lagrange function when the index */
                /*     of the other interpolation point on the line through XOPT is KNEW. */

                if (k == knew) {
                    diff = dderiv - one;
                    step = slbd;
                    vlag = slbd * (dderiv - slbd * diff);
                    isbd = ilbd;
                    temp = subd * (dderiv - subd * diff);
                    if (std::abs(temp) > std::abs(vlag)) {
                        step = subd;
                        vlag = temp;
                        isbd = iubd;
                    }
                    tempd = half * dderiv;
                    tempa = tempd - diff * slbd;
                    tempb = tempd - diff * subd;
                    if (tempa * tempb < zero) {
                        temp = tempd * tempd / diff;
                        if (std::abs(temp) > std::abs(vlag)) {
                            step = tempd / diff;
                            vlag = temp;
                            isbd = 0;
                        }
                    }

                    /*     Search along each of the other lines through XOPT and another point. */

                } else {
                    step = slbd;
                    vlag = slbd * (one - slbd);
                    isbd = ilbd;
                    temp = subd * (one - subd);
                    if (std::abs(temp) > std::abs(vlag)) {
                        step = subd;
                        vlag = temp;
                        isbd = iubd;
                    }
                    if (subd > half) {
                        if (std::abs(vlag) < .25) {
                            step = half;
                            vlag = .25;
                            isbd = 0;
                        }
                    }
                    vlag *= dderiv;
                }

                /*     Calculate PREDSQ for the current line search and maintain PRESAV. */

                temp = step * (one - step) * distsq;
                predsq = vlag * vlag * (vlag * vlag + ha * temp * temp);
                if (predsq > presav) {
                    presav = predsq;
                    ksav = k;
                    stpsav = step;
                    ibdsav = isbd;
                }
L80:
                ;
            }

            /*     Construct XNEW in a way that satisfies the bound constraints exactly. */

            i__1 = n;
            for (i__ = 1; i__ <= i__1; ++i__) {
                temp = xopt[i__] + stpsav * (xpt[ksav + i__ * xpt_dim1] - xopt[i__]);
                /* L90: */
                /* Computing MAX */
                /* Computing MIN */
                d__3 = su[i__];
                d__1 = sl[i__], d__2 = std::min(d__3,temp);
                xnew[i__] = std::max(d__1,d__2);
            }
            if (ibdsav < 0) {
                xnew[-ibdsav] = sl[-ibdsav];
            }
            if (ibdsav > 0) {
                xnew[ibdsav] = su[ibdsav];
            }

            /*     Prepare for the iterative method that assembles the constrained Cauchy */
            /*     step in W. The sum of squares of the fixed components of W is formed in */
            /*     WFIXSQ, and the free components of W are set to BIGSTP. */

            bigstp = adelt + adelt;
            iflag = 0;
L100:
            wfixsq = zero;
            ggfree = zero;
            i__1 = n;
            for (i__ = 1; i__ <= i__1; ++i__) {
                w[i__] = zero;
                /* Computing MIN */
                d__1 = xopt[i__] - sl[i__], d__2 = glag[i__];
                tempa = std::min(d__1,d__2);
                /* Computing MAX */
                d__1 = xopt[i__] - su[i__], d__2 = glag[i__];
                tempb = std::max(d__1,d__2);
                if (tempa > zero || tempb < zero) {
                    w[i__] = bigstp;
                    /* Computing 2nd power */
                    d__1 = glag[i__];
                    ggfree += d__1 * d__1;
                }
                /* L110: */
            }
            if (ggfree == zero) {
                cauchy = zero;
                goto L200;
            }

            /*     Investigate whether more components of W can be fixed. */

L120:
            temp = adelt * adelt - wfixsq;
            if (temp > zero) {
                wsqsav = wfixsq;
                step = std::sqrt(temp / ggfree);
                ggfree = zero;
                i__1 = n;
                for (i__ = 1; i__ <= i__1; ++i__) {
                    if (w[i__] == bigstp) {
                        temp = xopt[i__] - step * glag[i__];
                        if (temp <= sl[i__]) {
                            w[i__] = sl[i__] - xopt[i__];
                            /* Computing 2nd power */
                            d__1 = w[i__];
                            wfixsq += d__1 * d__1;
                        } else if (temp >= su[i__]) {
                            w[i__] = su[i__] - xopt[i__];
                            /* Computing 2nd power */
                            d__1 = w[i__];
                            wfixsq += d__1 * d__1;
                        } else {
                            /* Computing 2nd power */
                            d__1 = glag[i__];
                            ggfree += d__1 * d__1;
                        }
                    }
                    /* L130: */
                }
                if (wfixsq > wsqsav && ggfree > zero) {
                    goto L120;
                }
            }

            /*     Set the remaining free components of W and all components of XALT, */
            /*     except that W may be scaled later. */

            gw = zero;
            i__1 = n;
            for (i__ = 1; i__ <= i__1; ++i__) {
                if (w[i__] == bigstp) {
                    w[i__] = -step * glag[i__];
                    /* Computing MAX */
                    /* Computing MIN */
                    d__3 = su[i__], d__4 = xopt[i__] + w[i__];
                    d__1 = sl[i__], d__2 = std::min(d__3,d__4);
                    xalt[i__] = std::max(d__1,d__2);
                } else if (w[i__] == zero) {
                    xalt[i__] = xopt[i__];
                } else if (glag[i__] > zero) {
                    xalt[i__] = sl[i__];
                } else {
                    xalt[i__] = su[i__];
                }
                /* L140: */
                gw += glag[i__] * w[i__];
            }

            /*     Set CURV to the curvature of the KNEW-th Lagrange function along W. */
            /*     Scale W by a factor less than one if that can reduce the modulus of */
            /*     the Lagrange function at XOPT+W. Set CAUCHY to the final value of */
            /*     the square of this function. */

            curv = zero;
            i__1 = npt;
            for (k = 1; k <= i__1; ++k) {
                temp = zero;
                i__2 = n;
                for (j = 1; j <= i__2; ++j) {
                    /* L150: */
                    temp += xpt[k + j * xpt_dim1] * w[j];
                }
                /* L160: */
                curv += hcol[k] * temp * temp;
            }
            if (iflag == 1) {
                curv = -curv;
            }
            if (curv > -gw && curv < -const__ * gw) {
                scale = -gw / curv;
                i__1 = n;
                for (i__ = 1; i__ <= i__1; ++i__) {
                    temp = xopt[i__] + scale * w[i__];
                    /* L170: */
                    /* Computing MAX */
                    /* Computing MIN */
                    d__3 = su[i__];
                    d__1 = sl[i__], d__2 = std::min(d__3,temp);
                    xalt[i__] = std::max(d__1,d__2);
                }
                /* Computing 2nd power */
                d__1 = half * gw * scale;
                cauchy = d__1 * d__1;
            } else {
                /* Computing 2nd power */
                d__1 = gw + half * curv;
                cauchy = d__1 * d__1;
            }

            /*     If IFLAG is zero, then XALT is calculated as before after reversing */
            /*     the sign of GLAG. Thus two XALT vectors become available. The one that */
            /*     is chosen is the one that gives the larger value of CAUCHY. */

            if (iflag == 0) {
                i__1 = n;
                for (i__ = 1; i__ <= i__1; ++i__) {
                    glag[i__] = -glag[i__];
                    /* L180: */
                    w[n + i__] = xalt[i__];
                }
                csave = cauchy;
                iflag = 1;
                goto L100;
            }
            if (csave > cauchy) {
                i__1 = n;
                for (i__ = 1; i__ <= i__1; ++i__) {
                    /* L190: */
                    xalt[i__] = w[n + i__];
                }
                cauchy = csave;
            }
L200:
            ;
        } /* altmov_ */

    // ----------------------------------------------------------------------------------------

        template <typename funct>
        void prelim_(
            const funct& calfun,
            const integer n,
            const integer npt,
            doublereal *x,
            const doublereal *xl,
            const doublereal *xu,
            const doublereal rhobeg,
            const integer maxfun,
            doublereal *xbase,
            doublereal *xpt,
            doublereal *fval,
            doublereal *gopt,
            doublereal *hq,
            doublereal *pq,
            doublereal *bmat,
            doublereal *zmat,
            const integer ndim,
            const doublereal *sl,
            const doublereal *su,
            integer& nf,
            integer& kopt
        ) const
        {
            /* System generated locals */
            integer xpt_dim1, xpt_offset, bmat_dim1, bmat_offset, zmat_dim1,
            zmat_offset, i__1, i__2;
            doublereal d__1, d__2, d__3, d__4;

            /* Local variables */
            doublereal f;
            integer i__, j, k, ih, np, nfm;
            doublereal one;
            integer nfx = 0, ipt = 0, jpt = 0;
            doublereal two = 0, fbeg = 0, diff = 0, half = 0, temp = 0, zero = 0, recip = 0, stepa = 0, stepb = 0;
            integer itemp;
            doublereal rhosq;

            /*     The arguments N, NPT, X, XL, XU, RHOBEG, IPRINT and MAXFUN are the */
            /*       same as the corresponding arguments in SUBROUTINE BOBYQA. */
            /*     The arguments XBASE, XPT, FVAL, HQ, PQ, BMAT, ZMAT, NDIM, SL and SU */
            /*       are the same as the corresponding arguments in BOBYQB, the elements */
            /*       of SL and SU being set in BOBYQA. */
            /*     GOPT is usually the gradient of the quadratic model at XOPT+XBASE, but */
            /*       it is set by PRELIM to the gradient of the quadratic model at XBASE. */
            /*       If XOPT is nonzero, BOBYQB will change it to its usual value later. */
            /*     NF is maintaned as the number of calls of CALFUN so far. */
            /*     KOPT will be such that the least calculated value of F so far is at */
            /*       the point XPT(KOPT,.)+XBASE in the space of the variables. */

            /*     SUBROUTINE PRELIM sets the elements of XBASE, XPT, FVAL, GOPT, HQ, PQ, */
            /*     BMAT and ZMAT for the first iteration, and it maintains the values of */
            /*     NF and KOPT. The vector X is also changed by PRELIM. */

            /*     Set some constants. */

            /* Parameter adjustments */
            zmat_dim1 = npt;
            zmat_offset = 1 + zmat_dim1;
            zmat -= zmat_offset;
            xpt_dim1 = npt;
            xpt_offset = 1 + xpt_dim1;
            xpt -= xpt_offset;
            --x;
            --xl;
            --xu;
            --xbase;
            --fval;
            --gopt;
            --hq;
            --pq;
            bmat_dim1 = ndim;
            bmat_offset = 1 + bmat_dim1;
            bmat -= bmat_offset;
            --sl;
            --su;

            /* Function Body */
            half = .5;
            one = 1.;
            two = 2.;
            zero = 0.;
            rhosq = rhobeg * rhobeg;
            recip = one / rhosq;
            np = n + 1;

            /*     Set XBASE to the initial vector of variables, and set the initial */
            /*     elements of XPT, BMAT, HQ, PQ and ZMAT to zero. */

            i__1 = n;
            for (j = 1; j <= i__1; ++j) {
                xbase[j] = x[j];
                i__2 = npt;
                for (k = 1; k <= i__2; ++k) {
                    /* L10: */
                    xpt[k + j * xpt_dim1] = zero;
                }
                i__2 = ndim;
                for (i__ = 1; i__ <= i__2; ++i__) {
                    /* L20: */
                    bmat[i__ + j * bmat_dim1] = zero;
                }
            }
            i__2 = n * np / 2;
            for (ih = 1; ih <= i__2; ++ih) {
                /* L30: */
                hq[ih] = zero;
            }
            i__2 = npt;
            for (k = 1; k <= i__2; ++k) {
                pq[k] = zero;
                i__1 = npt - np;
                for (j = 1; j <= i__1; ++j) {
                    /* L40: */
                    zmat[k + j * zmat_dim1] = zero;
                }
            }

            /*     Begin the initialization procedure. NF becomes one more than the number */
            /*     of function values so far. The coordinates of the displacement of the */
            /*     next initial interpolation point from XBASE are set in XPT(NF+1,.). */

            nf = 0;
L50:
            nfm = nf;
            nfx = nf - n;
            ++(nf);
            if (nfm <= n << 1) {
                if (nfm >= 1 && nfm <= n) {
                    stepa = rhobeg;
                    if (su[nfm] == zero) {
                        stepa = -stepa;
                    }
                    xpt[nf + nfm * xpt_dim1] = stepa;
                } else if (nfm > n) {
                    stepa = xpt[nf - n + nfx * xpt_dim1];
                    stepb = -(rhobeg);
                    if (sl[nfx] == zero) {
                        /* Computing MIN */
                        d__1 = two * rhobeg, d__2 = su[nfx];
                        stepb = std::min(d__1,d__2);
                    }
                    if (su[nfx] == zero) {
                        /* Computing MAX */
                        d__1 = -two * rhobeg, d__2 = sl[nfx];
                        stepb = std::max(d__1,d__2);
                    }
                    xpt[nf + nfx * xpt_dim1] = stepb;
                }
            } else {
                itemp = (nfm - np) / n;
                jpt = nfm - itemp * n - n;
                ipt = jpt + itemp;
                if (ipt > n) {
                    itemp = jpt;
                    jpt = ipt - n;
                    ipt = itemp;
                }
                xpt[nf + ipt * xpt_dim1] = xpt[ipt + 1 + ipt * xpt_dim1];
                xpt[nf + jpt * xpt_dim1] = xpt[jpt + 1 + jpt * xpt_dim1];
            }

            /*     Calculate the next value of F. The least function value so far and */
            /*     its index are required. */

            i__1 = n;
            for (j = 1; j <= i__1; ++j) {
                /* Computing MIN */
                /* Computing MAX */
                d__3 = xl[j], d__4 = xbase[j] + xpt[nf + j * xpt_dim1];
                d__1 = std::max(d__3,d__4), d__2 = xu[j];
                x[j] = std::min(d__1,d__2);
                if (xpt[nf + j * xpt_dim1] == sl[j]) {
                    x[j] = xl[j];
                }
                if (xpt[nf + j * xpt_dim1] == su[j]) {
                    x[j] = xu[j];
                }
                /* L60: */
            }
            f = calfun(mat(&x[1],n));
            fval[nf] = f;
            if (nf == 1) {
                fbeg = f;
                kopt = 1;
            } else if (f < fval[kopt]) {
                kopt = nf;
            }

            /*     Set the nonzero initial elements of BMAT and the quadratic model in the */
            /*     cases when NF is at most 2*N+1. If NF exceeds N+1, then the positions */
            /*     of the NF-th and (NF-N)-th interpolation points may be switched, in */
            /*     order that the function value at the first of them contributes to the */
            /*     off-diagonal second derivative terms of the initial quadratic model. */

            if (nf <= (n << 1) + 1) {
                if (nf >= 2 && nf <= n + 1) {
                    gopt[nfm] = (f - fbeg) / stepa;
                    if (npt < nf + n) {
                        bmat[nfm * bmat_dim1 + 1] = -one / stepa;
                        bmat[nf + nfm * bmat_dim1] = one / stepa;
                        bmat[npt + nfm + nfm * bmat_dim1] = -half * rhosq;
                    }
                } else if (nf >= n + 2) {
                    ih = nfx * (nfx + 1) / 2;
                    temp = (f - fbeg) / stepb;
                    diff = stepb - stepa;
                    hq[ih] = two * (temp - gopt[nfx]) / diff;
                    gopt[nfx] = (gopt[nfx] * stepb - temp * stepa) / diff;
                    if (stepa * stepb < zero) {
                        if (f < fval[nf - n]) {
                            fval[nf] = fval[nf - n];
                            fval[nf - n] = f;
                            if (kopt == nf) {
                                kopt = nf - n;
                            }
                            xpt[nf - n + nfx * xpt_dim1] = stepb;
                            xpt[nf + nfx * xpt_dim1] = stepa;
                        }
                    }
                    bmat[nfx * bmat_dim1 + 1] = -(stepa + stepb) / (stepa * stepb);
                    bmat[nf + nfx * bmat_dim1] = -half / xpt[nf - n + nfx *
                        xpt_dim1];
                    bmat[nf - n + nfx * bmat_dim1] = -bmat[nfx * bmat_dim1 + 1] -
                        bmat[nf + nfx * bmat_dim1];
                    zmat[nfx * zmat_dim1 + 1] = std::sqrt(two) / (stepa * stepb);
                    zmat[nf + nfx * zmat_dim1] = std::sqrt(half) / rhosq;
                    zmat[nf - n + nfx * zmat_dim1] = -zmat[nfx * zmat_dim1 + 1] -
                        zmat[nf + nfx * zmat_dim1];
                }

                /*     Set the off-diagonal second derivatives of the Lagrange functions and */
                /*     the initial quadratic model. */

            } else {
                ih = ipt * (ipt - 1) / 2 + jpt;
                zmat[nfx * zmat_dim1 + 1] = recip;
                zmat[nf + nfx * zmat_dim1] = recip;
                zmat[ipt + 1 + nfx * zmat_dim1] = -recip;
                zmat[jpt + 1 + nfx * zmat_dim1] = -recip;
                temp = xpt[nf + ipt * xpt_dim1] * xpt[nf + jpt * xpt_dim1];
                hq[ih] = (fbeg - fval[ipt + 1] - fval[jpt + 1] + f) / temp;
            }
            if (nf < npt && nf < maxfun) {
                goto L50;
            }

        } /* prelim_ */

    // ----------------------------------------------------------------------------------------

        template <typename funct>
        void rescue_ (
            const funct& calfun,
            const integer n,
            const integer npt,
            const doublereal *xl,
            const doublereal *xu,
            const integer maxfun,
            doublereal *xbase,
            doublereal *xpt,
            doublereal *fval,
            doublereal *xopt,
            doublereal *gopt,
            doublereal *hq,
            doublereal *pq,
            doublereal *bmat,
            doublereal *zmat,
            const integer ndim,
            doublereal *sl,
            doublereal *su,
            integer& nf,
            const doublereal delta,
            integer& kopt,
            doublereal *vlag,
            doublereal * ptsaux,
            doublereal *ptsid,
            doublereal *w
        ) const
        {
            /* System generated locals */
            integer xpt_dim1, xpt_offset, bmat_dim1, bmat_offset, zmat_dim1,
            zmat_offset, i__1, i__2, i__3;
            doublereal d__1, d__2, d__3, d__4;

            /* Local variables */
            doublereal f;
            integer i__, j, k, ih, jp, ip, iq, np, iw;
            doublereal xp = 0, xq = 0, den = 0;
            integer ihp = 0;
            doublereal one;
            integer ihq, jpn, kpt;
            doublereal sum = 0, diff = 0, half = 0, beta = 0;
            integer kold;
            doublereal winc;
            integer nrem, knew;
            doublereal temp, bsum;
            integer nptm;
            doublereal zero = 0, hdiag = 0, fbase = 0, sfrac = 0, denom = 0, vquad = 0, sumpq = 0;
            doublereal dsqmin, distsq, vlmxsq;

            /*     The arguments N, NPT, XL, XU, IPRINT, MAXFUN, XBASE, XPT, FVAL, XOPT, */
            /*       GOPT, HQ, PQ, BMAT, ZMAT, NDIM, SL and SU have the same meanings as */
            /*       the corresponding arguments of BOBYQB on the entry to RESCUE. */
            /*     NF is maintained as the number of calls of CALFUN so far, except that */
            /*       NF is set to -1 if the value of MAXFUN prevents further progress. */
            /*     KOPT is maintained so that FVAL(KOPT) is the least calculated function */
            /*       value. Its correct value must be given on entry. It is updated if a */
            /*       new least function value is found, but the corresponding changes to */
            /*       XOPT and GOPT have to be made later by the calling program. */
            /*     DELTA is the current trust region radius. */
            /*     VLAG is a working space vector that will be used for the values of the */
            /*       provisional Lagrange functions at each of the interpolation points. */
            /*       They are part of a product that requires VLAG to be of length NDIM. */
            /*     PTSAUX is also a working space array. For J=1,2,...,N, PTSAUX(1,J) and */
            /*       PTSAUX(2,J) specify the two positions of provisional interpolation */
            /*       points when a nonzero step is taken along e_J (the J-th coordinate */
            /*       direction) through XBASE+XOPT, as specified below. Usually these */
            /*       steps have length DELTA, but other lengths are chosen if necessary */
            /*       in order to satisfy the given bounds on the variables. */
            /*     PTSID is also a working space array. It has NPT components that denote */
            /*       provisional new positions of the original interpolation points, in */
            /*       case changes are needed to restore the linear independence of the */
            /*       interpolation conditions. The K-th point is a candidate for change */
            /*       if and only if PTSID(K) is nonzero. In this case let p and q be the */
            /*       integer parts of PTSID(K) and (PTSID(K)-p) multiplied by N+1. If p */
            /*       and q are both positive, the step from XBASE+XOPT to the new K-th */
            /*       interpolation point is PTSAUX(1,p)*e_p + PTSAUX(1,q)*e_q. Otherwise */
            /*       the step is PTSAUX(1,p)*e_p or PTSAUX(2,q)*e_q in the cases q=0 or */
            /*       p=0, respectively. */
            /*     The first NDIM+NPT elements of the array W are used for working space. */
            /*     The final elements of BMAT and ZMAT are set in a well-conditioned way */
            /*       to the values that are appropriate for the new interpolation points. */
            /*     The elements of GOPT, HQ and PQ are also revised to the values that are */
            /*       appropriate to the final quadratic model. */

            /*     Set some constants. */

            /* Parameter adjustments */
            zmat_dim1 = npt;
            zmat_offset = 1 + zmat_dim1;
            zmat -= zmat_offset;
            xpt_dim1 = npt;
            xpt_offset = 1 + xpt_dim1;
            xpt -= xpt_offset;
            --xl;
            --xu;
            --xbase;
            --fval;
            --xopt;
            --gopt;
            --hq;
            --pq;
            bmat_dim1 = ndim;
            bmat_offset = 1 + bmat_dim1;
            bmat -= bmat_offset;
            --sl;
            --su;
            --vlag;
            ptsaux -= 3;
            --ptsid;
            --w;

            /* Function Body */
            half = .5;
            one = 1.;
            zero = 0.;
            np = n + 1;
            sfrac = half / (doublereal) np;
            nptm = npt - np;

            /*     Shift the interpolation points so that XOPT becomes the origin, and set */
            /*     the elements of ZMAT to zero. The value of SUMPQ is required in the */
            /*     updating of HQ below. The squares of the distances from XOPT to the */
            /*     other interpolation points are set at the end of W. Increments of WINC */
            /*     may be added later to these squares to balance the consideration of */
            /*     the choice of point that is going to become current. */

            sumpq = zero;
            winc = zero;
            i__1 = npt;
            for (k = 1; k <= i__1; ++k) {
                distsq = zero;
                i__2 = n;
                for (j = 1; j <= i__2; ++j) {
                    xpt[k + j * xpt_dim1] -= xopt[j];
                    /* L10: */
                    /* Computing 2nd power */
                    d__1 = xpt[k + j * xpt_dim1];
                    distsq += d__1 * d__1;
                }
                sumpq += pq[k];
                w[ndim + k] = distsq;
                winc = std::max(winc,distsq);
                i__2 = nptm;
                for (j = 1; j <= i__2; ++j) {
                    /* L20: */
                    zmat[k + j * zmat_dim1] = zero;
                }
            }

            /*     Update HQ so that HQ and PQ define the second derivatives of the model */
            /*     after XBASE has been shifted to the trust region centre. */

            ih = 0;
            i__2 = n;
            for (j = 1; j <= i__2; ++j) {
                w[j] = half * sumpq * xopt[j];
                i__1 = npt;
                for (k = 1; k <= i__1; ++k) {
                    /* L30: */
                    w[j] += pq[k] * xpt[k + j * xpt_dim1];
                }
                i__1 = j;
                for (i__ = 1; i__ <= i__1; ++i__) {
                    ++ih;
                    /* L40: */
                    hq[ih] = hq[ih] + w[i__] * xopt[j] + w[j] * xopt[i__];
                }
            }

            /*     Shift XBASE, SL, SU and XOPT. Set the elements of BMAT to zero, and */
            /*     also set the elements of PTSAUX. */

            i__1 = n;
            for (j = 1; j <= i__1; ++j) {
                xbase[j] += xopt[j];
                sl[j] -= xopt[j];
                su[j] -= xopt[j];
                xopt[j] = zero;
                /* Computing MIN */
                d__1 = delta, d__2 = su[j];
                ptsaux[(j << 1) + 1] = std::min(d__1,d__2);
                /* Computing MAX */
                d__1 = -(delta), d__2 = sl[j];
                ptsaux[(j << 1) + 2] = std::max(d__1,d__2);
                if (ptsaux[(j << 1) + 1] + ptsaux[(j << 1) + 2] < zero) {
                    temp = ptsaux[(j << 1) + 1];
                    ptsaux[(j << 1) + 1] = ptsaux[(j << 1) + 2];
                    ptsaux[(j << 1) + 2] = temp;
                }
                if ((d__2 = ptsaux[(j << 1) + 2], std::abs(d__2)) < half * (d__1 = ptsaux[(
                            j << 1) + 1], std::abs(d__1))) {
                    ptsaux[(j << 1) + 2] = half * ptsaux[(j << 1) + 1];
                }
                i__2 = ndim;
                for (i__ = 1; i__ <= i__2; ++i__) {
                    /* L50: */
                    bmat[i__ + j * bmat_dim1] = zero;
                }
            }
            fbase = fval[kopt];

            /*     Set the identifiers of the artificial interpolation points that are */
            /*     along a coordinate direction from XOPT, and set the corresponding */
            /*     nonzero elements of BMAT and ZMAT. */

            ptsid[1] = sfrac;
            i__2 = n;
            for (j = 1; j <= i__2; ++j) {
                jp = j + 1;
                jpn = jp + n;
                ptsid[jp] = (doublereal) j + sfrac;
                if (jpn <= npt) {
                    ptsid[jpn] = (doublereal) j / (doublereal) np + sfrac;
                    temp = one / (ptsaux[(j << 1) + 1] - ptsaux[(j << 1) + 2]);
                    bmat[jp + j * bmat_dim1] = -temp + one / ptsaux[(j << 1) + 1];
                    bmat[jpn + j * bmat_dim1] = temp + one / ptsaux[(j << 1) + 2];
                    bmat[j * bmat_dim1 + 1] = -bmat[jp + j * bmat_dim1] - bmat[jpn +
                        j * bmat_dim1];
                    zmat[j * zmat_dim1 + 1] = std::sqrt(2.) / (d__1 = ptsaux[(j << 1) + 1]
                                                          * ptsaux[(j << 1) + 2], std::abs(d__1));
                    zmat[jp + j * zmat_dim1] = zmat[j * zmat_dim1 + 1] * ptsaux[(j <<
                                                                                1) + 2] * temp;
                    zmat[jpn + j * zmat_dim1] = -zmat[j * zmat_dim1 + 1] * ptsaux[(j
                                                                                << 1) + 1] * temp;
                } else {
                    bmat[j * bmat_dim1 + 1] = -one / ptsaux[(j << 1) + 1];
                    bmat[jp + j * bmat_dim1] = one / ptsaux[(j << 1) + 1];
                    /* Computing 2nd power */
                    d__1 = ptsaux[(j << 1) + 1];
                    bmat[j + npt + j * bmat_dim1] = -half * (d__1 * d__1);
                }
                /* L60: */
            }

            /*     Set any remaining identifiers with their nonzero elements of ZMAT. */

            if (npt >= n + np) {
                i__2 = npt;
                for (k = np << 1; k <= i__2; ++k) {
                    iw = (integer) (((doublereal) (k - np) - half) / (doublereal) (n)
                    );
                    ip = k - np - iw * n;
                    iq = ip + iw;
                    if (iq > n) {
                        iq -= n;
                    }
                    ptsid[k] = (doublereal) ip + (doublereal) iq / (doublereal) np +
                        sfrac;
                    temp = one / (ptsaux[(ip << 1) + 1] * ptsaux[(iq << 1) + 1]);
                    zmat[(k - np) * zmat_dim1 + 1] = temp;
                    zmat[ip + 1 + (k - np) * zmat_dim1] = -temp;
                    zmat[iq + 1 + (k - np) * zmat_dim1] = -temp;
                    /* L70: */
                    zmat[k + (k - np) * zmat_dim1] = temp;
                }
            }
            nrem = npt;
            kold = 1;
            knew = kopt;

            /*     Reorder the provisional points in the way that exchanges PTSID(KOLD) */
            /*     with PTSID(KNEW). */

L80:
            i__2 = n;
            for (j = 1; j <= i__2; ++j) {
                temp = bmat[kold + j * bmat_dim1];
                bmat[kold + j * bmat_dim1] = bmat[knew + j * bmat_dim1];
                /* L90: */
                bmat[knew + j * bmat_dim1] = temp;
            }
            i__2 = nptm;
            for (j = 1; j <= i__2; ++j) {
                temp = zmat[kold + j * zmat_dim1];
                zmat[kold + j * zmat_dim1] = zmat[knew + j * zmat_dim1];
                /* L100: */
                zmat[knew + j * zmat_dim1] = temp;
            }
            ptsid[kold] = ptsid[knew];
            ptsid[knew] = zero;
            w[ndim + knew] = zero;
            --nrem;
            if (knew != kopt) {
                temp = vlag[kold];
                vlag[kold] = vlag[knew];
                vlag[knew] = temp;

                /*     Update the BMAT and ZMAT matrices so that the status of the KNEW-th */
                /*     interpolation point can be changed from provisional to original. The */
                /*     branch to label 350 occurs if all the original points are reinstated. */
                /*     The nonnegative values of W(NDIM+K) are required in the search below. */

                update_(n, npt, &bmat[bmat_offset], &zmat[zmat_offset], ndim, &vlag[1],
                        beta, denom, knew, &w[1]);
                if (nrem == 0) {
                    goto L350;
                }
                i__2 = npt;
                for (k = 1; k <= i__2; ++k) {
                    /* L110: */
                    w[ndim + k] = (d__1 = w[ndim + k], std::abs(d__1));
                }
            }

            /*     Pick the index KNEW of an original interpolation point that has not */
            /*     yet replaced one of the provisional interpolation points, giving */
            /*     attention to the closeness to XOPT and to previous tries with KNEW. */

L120:
            dsqmin = zero;
            i__2 = npt;
            for (k = 1; k <= i__2; ++k) {
                if (w[ndim + k] > zero) {
                    if (dsqmin == zero || w[ndim + k] < dsqmin) {
                        knew = k;
                        dsqmin = w[ndim + k];
                    }
                }
                /* L130: */
            }
            if (dsqmin == zero) {
                goto L260;
            }

            /*     Form the W-vector of the chosen original interpolation point. */

            i__2 = n;
            for (j = 1; j <= i__2; ++j) {
                /* L140: */
                w[npt + j] = xpt[knew + j * xpt_dim1];
            }
            i__2 = npt;
            for (k = 1; k <= i__2; ++k) {
                sum = zero;
                if (k == kopt) {
                } else if (ptsid[k] == zero) {
                    i__1 = n;
                    for (j = 1; j <= i__1; ++j) {
                        /* L150: */
                        sum += w[npt + j] * xpt[k + j * xpt_dim1];
                    }
                } else {
                    ip = (integer) ptsid[k];
                    if (ip > 0) {
                        sum = w[npt + ip] * ptsaux[(ip << 1) + 1];
                    }
                    iq = (integer) ((doublereal) np * ptsid[k] - (doublereal) (ip *
                                                                               np));
                    if (iq > 0) {
                        iw = 1;
                        if (ip == 0) {
                            iw = 2;
                        }
                        sum += w[npt + iq] * ptsaux[iw + (iq << 1)];
                    }
                }
                /* L160: */
                w[k] = half * sum * sum;
            }

            /*     Calculate VLAG and BETA for the required updating of the H matrix if */
            /*     XPT(KNEW,.) is reinstated in the set of interpolation points. */

            i__2 = npt;
            for (k = 1; k <= i__2; ++k) {
                sum = zero;
                i__1 = n;
                for (j = 1; j <= i__1; ++j) {
                    /* L170: */
                    sum += bmat[k + j * bmat_dim1] * w[npt + j];
                }
                /* L180: */
                vlag[k] = sum;
            }
            beta = zero;
            i__2 = nptm;
            for (j = 1; j <= i__2; ++j) {
                sum = zero;
                i__1 = npt;
                for (k = 1; k <= i__1; ++k) {
                    /* L190: */
                    sum += zmat[k + j * zmat_dim1] * w[k];
                }
                beta -= sum * sum;
                i__1 = npt;
                for (k = 1; k <= i__1; ++k) {
                    /* L200: */
                    vlag[k] += sum * zmat[k + j * zmat_dim1];
                }
            }
            bsum = zero;
            distsq = zero;
            i__1 = n;
            for (j = 1; j <= i__1; ++j) {
                sum = zero;
                i__2 = npt;
                for (k = 1; k <= i__2; ++k) {
                    /* L210: */
                    sum += bmat[k + j * bmat_dim1] * w[k];
                }
                jp = j + npt;
                bsum += sum * w[jp];
                i__2 = ndim;
                for (ip = npt + 1; ip <= i__2; ++ip) {
                    /* L220: */
                    sum += bmat[ip + j * bmat_dim1] * w[ip];
                }
                bsum += sum * w[jp];
                vlag[jp] = sum;
                /* L230: */
                /* Computing 2nd power */
                d__1 = xpt[knew + j * xpt_dim1];
                distsq += d__1 * d__1;
            }
            beta = half * distsq * distsq + beta - bsum;
            vlag[kopt] += one;

            /*     KOLD is set to the index of the provisional interpolation point that is */
            /*     going to be deleted to make way for the KNEW-th original interpolation */
            /*     point. The choice of KOLD is governed by the avoidance of a small value */
            /*     of the denominator in the updating calculation of UPDATE. */

            denom = zero;
            vlmxsq = zero;
            i__1 = npt;
            for (k = 1; k <= i__1; ++k) {
                if (ptsid[k] != zero) {
                    hdiag = zero;
                    i__2 = nptm;
                    for (j = 1; j <= i__2; ++j) {
                        /* L240: */
                        /* Computing 2nd power */
                        d__1 = zmat[k + j * zmat_dim1];
                        hdiag += d__1 * d__1;
                    }
                    /* Computing 2nd power */
                    d__1 = vlag[k];
                    den = beta * hdiag + d__1 * d__1;
                    if (den > denom) {
                        kold = k;
                        denom = den;
                    }
                }
                /* L250: */
                /* Computing MAX */
                /* Computing 2nd power */
                d__3 = vlag[k];
                d__1 = vlmxsq, d__2 = d__3 * d__3;
                vlmxsq = std::max(d__1,d__2);
            }
            if (denom <= vlmxsq * .01) {
                w[ndim + knew] = -w[ndim + knew] - winc;
                goto L120;
            }
            goto L80;

            /*     When label 260 is reached, all the final positions of the interpolation */
            /*     points have been chosen although any changes have not been included yet */
            /*     in XPT. Also the final BMAT and ZMAT matrices are complete, but, apart */
            /*     from the shift of XBASE, the updating of the quadratic model remains to */
            /*     be done. The following cycle through the new interpolation points begins */
            /*     by putting the new point in XPT(KPT,.) and by setting PQ(KPT) to zero, */
            /*     except that a RETURN occurs if MAXFUN prohibits another value of F. */

L260:
            i__1 = npt;
            for (kpt = 1; kpt <= i__1; ++kpt) {
                if (ptsid[kpt] == zero) {
                    goto L340;
                }
                if (nf >= maxfun) {
                    nf = -1;
                    goto L350;
                }
                ih = 0;
                i__2 = n;
                for (j = 1; j <= i__2; ++j) {
                    w[j] = xpt[kpt + j * xpt_dim1];
                    xpt[kpt + j * xpt_dim1] = zero;
                    temp = pq[kpt] * w[j];
                    i__3 = j;
                    for (i__ = 1; i__ <= i__3; ++i__) {
                        ++ih;
                        /* L270: */
                        hq[ih] += temp * w[i__];
                    }
                }
                pq[kpt] = zero;
                ip = (integer) ptsid[kpt];
                iq = (integer) ((doublereal) np * ptsid[kpt] - (doublereal) (ip * np))
                    ;
                if (ip > 0) {
                    xp = ptsaux[(ip << 1) + 1];
                    xpt[kpt + ip * xpt_dim1] = xp;
                }
                if (iq > 0) {
                    xq = ptsaux[(iq << 1) + 1];
                    if (ip == 0) {
                        xq = ptsaux[(iq << 1) + 2];
                    }
                    xpt[kpt + iq * xpt_dim1] = xq;
                }

                /*     Set VQUAD to the value of the current model at the new point. */

                vquad = fbase;
                if (ip > 0) {
                    ihp = (ip + ip * ip) / 2;
                    vquad += xp * (gopt[ip] + half * xp * hq[ihp]);
                }
                if (iq > 0) {
                    ihq = (iq + iq * iq) / 2;
                    vquad += xq * (gopt[iq] + half * xq * hq[ihq]);
                    if (ip > 0) {
                        iw = std::max(ihp,ihq) - (i__3 = ip - iq, std::abs(i__3));
                        vquad += xp * xq * hq[iw];
                    }
                }
                i__3 = npt;
                for (k = 1; k <= i__3; ++k) {
                    temp = zero;
                    if (ip > 0) {
                        temp += xp * xpt[k + ip * xpt_dim1];
                    }
                    if (iq > 0) {
                        temp += xq * xpt[k + iq * xpt_dim1];
                    }
                    /* L280: */
                    vquad += half * pq[k] * temp * temp;
                }

                /*     Calculate F at the new interpolation point, and set DIFF to the factor */
                /*     that is going to multiply the KPT-th Lagrange function when the model */
                /*     is updated to provide interpolation to the new function value. */

                i__3 = n;
                for (i__ = 1; i__ <= i__3; ++i__) {
                    /* Computing MIN */
                    /* Computing MAX */
                    d__3 = xl[i__], d__4 = xbase[i__] + xpt[kpt + i__ * xpt_dim1];
                    d__1 = std::max(d__3,d__4), d__2 = xu[i__];
                    w[i__] = std::min(d__1,d__2);
                    if (xpt[kpt + i__ * xpt_dim1] == sl[i__]) {
                        w[i__] = xl[i__];
                    }
                    if (xpt[kpt + i__ * xpt_dim1] == su[i__]) {
                        w[i__] = xu[i__];
                    }
                    /* L290: */
                }
                ++(nf);
                f = calfun(mat(&w[1],n));
                fval[kpt] = f;
                if (f < fval[kopt]) {
                    kopt = kpt;
                }
                diff = f - vquad;

                /*     Update the quadratic model. The RETURN from the subroutine occurs when */
                /*     all the new interpolation points are included in the model. */

                i__3 = n;
                for (i__ = 1; i__ <= i__3; ++i__) {
                    /* L310: */
                    gopt[i__] += diff * bmat[kpt + i__ * bmat_dim1];
                }
                i__3 = npt;
                for (k = 1; k <= i__3; ++k) {
                    sum = zero;
                    i__2 = nptm;
                    for (j = 1; j <= i__2; ++j) {
                        /* L320: */
                        sum += zmat[k + j * zmat_dim1] * zmat[kpt + j * zmat_dim1];
                    }
                    temp = diff * sum;
                    if (ptsid[k] == zero) {
                        pq[k] += temp;
                    } else {
                        ip = (integer) ptsid[k];
                        iq = (integer) ((doublereal) np * ptsid[k] - (doublereal) (ip
                                                                                * np));
                        ihq = (iq * iq + iq) / 2;
                        if (ip == 0) {
                            /* Computing 2nd power */
                            d__1 = ptsaux[(iq << 1) + 2];
                            hq[ihq] += temp * (d__1 * d__1);
                        } else {
                            ihp = (ip * ip + ip) / 2;
                            /* Computing 2nd power */
                            d__1 = ptsaux[(ip << 1) + 1];
                            hq[ihp] += temp * (d__1 * d__1);
                            if (iq > 0) {
                                /* Computing 2nd power */
                                d__1 = ptsaux[(iq << 1) + 1];
                                hq[ihq] += temp * (d__1 * d__1);
                                iw = std::max(ihp,ihq) - (i__2 = iq - ip, std::abs(i__2));
                                hq[iw] += temp * ptsaux[(ip << 1) + 1] * ptsaux[(iq <<
                                                                                1) + 1];
                            }
                        }
                    }
                    /* L330: */
                }
                ptsid[kpt] = zero;
L340:
                ;
            }
L350:
            ;
        } /* rescue_ */

    // ----------------------------------------------------------------------------------------

        void trsbox_(
            const integer n,
            const integer npt,
            const doublereal *xpt,
            const doublereal *xopt,
            const doublereal *gopt,
            const doublereal *hq,
            const doublereal *pq,
            const doublereal *sl,
            const doublereal *su,
            const doublereal delta,
            doublereal *xnew,
            doublereal *d__,
            doublereal *gnew,
            doublereal *xbdi,
            doublereal *s,
            doublereal *hs,
            doublereal *hred,
            doublereal *dsq,
            doublereal *crvmin
        ) const
        {
            /* System generated locals */
            integer xpt_dim1, xpt_offset, i__1, i__2;
            doublereal d__1, d__2, d__3, d__4;

            /* Local variables */
            integer i__, j, k, ih;
            doublereal ds;
            integer iu;
            doublereal dhd, dhs, cth, one, shs, sth, ssq, half, beta, sdec, blen;
            integer iact = 0, nact = 0;
            doublereal angt, qred;
            integer isav;
            doublereal temp = 0, zero = 0, xsav = 0, xsum = 0, angbd = 0, dredg = 0, sredg = 0;
            integer iterc;
            doublereal resid = 0, delsq = 0, ggsav = 0, tempa = 0, tempb = 0,
                       redmax = 0, dredsq = 0, redsav = 0, onemin = 0, gredsq = 0, rednew = 0;
            integer itcsav = 0;
            doublereal rdprev = 0, rdnext = 0, stplen = 0, stepsq = 0;
            integer itermax = 0;

            /*     The arguments N, NPT, XPT, XOPT, GOPT, HQ, PQ, SL and SU have the same */
            /*       meanings as the corresponding arguments of BOBYQB. */
            /*     DELTA is the trust region radius for the present calculation, which */
            /*       seeks a small value of the quadratic model within distance DELTA of */
            /*       XOPT subject to the bounds on the variables. */
            /*     XNEW will be set to a new vector of variables that is approximately */
            /*       the one that minimizes the quadratic model within the trust region */
            /*       subject to the SL and SU constraints on the variables. It satisfies */
            /*       as equations the bounds that become active during the calculation. */
            /*     D is the calculated trial step from XOPT, generated iteratively from an */
            /*       initial value of zero. Thus XNEW is XOPT+D after the final iteration. */
            /*     GNEW holds the gradient of the quadratic model at XOPT+D. It is updated */
            /*       when D is updated. */
            /*     XBDI is a working space vector. For I=1,2,...,N, the element XBDI(I) is */
            /*       set to -1.0, 0.0, or 1.0, the value being nonzero if and only if the */
            /*       I-th variable has become fixed at a bound, the bound being SL(I) or */
            /*       SU(I) in the case XBDI(I)=-1.0 or XBDI(I)=1.0, respectively. This */
            /*       information is accumulated during the construction of XNEW. */
            /*     The arrays S, HS and HRED are also used for working space. They hold the */
            /*       current search direction, and the changes in the gradient of Q along S */
            /*       and the reduced D, respectively, where the reduced D is the same as D, */
            /*       except that the components of the fixed variables are zero. */
            /*     DSQ will be set to the square of the length of XNEW-XOPT. */
            /*     CRVMIN is set to zero if D reaches the trust region boundary. Otherwise */
            /*       it is set to the least curvature of H that occurs in the conjugate */
            /*       gradient searches that are not restricted by any constraints. The */
            /*       value CRVMIN=-1.0D0 is set, however, if all of these searches are */
            /*       constrained. */

            /*     A version of the truncated conjugate gradient is applied. If a line */
            /*     search is restricted by a constraint, then the procedure is restarted, */
            /*     the values of the variables that are at their bounds being fixed. If */
            /*     the trust region boundary is reached, then further changes may be made */
            /*     to D, each one being in the two dimensional space that is spanned */
            /*     by the current D and the gradient of Q at XOPT+D, staying on the trust */
            /*     region boundary. Termination occurs when the reduction in Q seems to */
            /*     be close to the greatest reduction that can be achieved. */

            /*     Set some constants. */

            /* Parameter adjustments */
            xpt_dim1 = npt;
            xpt_offset = 1 + xpt_dim1;
            xpt -= xpt_offset;
            --xopt;
            --gopt;
            --hq;
            --pq;
            --sl;
            --su;
            --xnew;
            --d__;
            --gnew;
            --xbdi;
            --s;
            --hs;
            --hred;

            /* Function Body */
            half = .5;
            one = 1.;
            onemin = -1.;
            zero = 0.;

            /*     The sign of GOPT(I) gives the sign of the change to the I-th variable */
            /*     that will reduce Q from its value at XOPT. Thus XBDI(I) shows whether */
            /*     or not to fix the I-th variable at one of its bounds initially, with */
            /*     NACT being set to the number of fixed variables. D and GNEW are also */
            /*     set for the first iteration. DELSQ is the upper bound on the sum of */
            /*     squares of the free variables. QRED is the reduction in Q so far. */

            iterc = 0;
            nact = 0;
            i__1 = n;
            for (i__ = 1; i__ <= i__1; ++i__) {
                xbdi[i__] = zero;
                if (xopt[i__] <= sl[i__]) {
                    if (gopt[i__] >= zero) {
                        xbdi[i__] = onemin;
                    }
                } else if (xopt[i__] >= su[i__]) {
                    if (gopt[i__] <= zero) {
                        xbdi[i__] = one;
                    }
                }
                if (xbdi[i__] != zero) {
                    ++nact;
                }
                d__[i__] = zero;
                /* L10: */
                gnew[i__] = gopt[i__];
            }
            delsq = delta * delta;
            qred = zero;
            *crvmin = onemin;

            /*     Set the next search direction of the conjugate gradient method. It is */
            /*     the steepest descent direction initially and when the iterations are */
            /*     restarted because a variable has just been fixed by a bound, and of */
            /*     course the components of the fixed variables are zero. ITERMAX is an */
            /*     upper bound on the indices of the conjugate gradient iterations. */

L20:
            beta = zero;
L30:
            stepsq = zero;
            i__1 = n;
            for (i__ = 1; i__ <= i__1; ++i__) {
                if (xbdi[i__] != zero) {
                    s[i__] = zero;
                } else if (beta == zero) {
                    s[i__] = -gnew[i__];
                } else {
                    s[i__] = beta * s[i__] - gnew[i__];
                }
                /* L40: */
                /* Computing 2nd power */
                d__1 = s[i__];
                stepsq += d__1 * d__1;
            }
            if (stepsq == zero) {
                goto L190;
            }
            if (beta == zero) {
                gredsq = stepsq;
                itermax = iterc + n - nact;
            }
            if (gredsq * delsq <= qred * 1e-4 * qred) {
                goto L190;
            }

            /*     Multiply the search direction by the second derivative matrix of Q and */
            /*     calculate some scalars for the choice of steplength. Then set BLEN to */
            /*     the length of the the step to the trust region boundary and STPLEN to */
            /*     the steplength, ignoring the simple bounds. */

            goto L210;
L50:
            resid = delsq;
            ds = zero;
            shs = zero;
            i__1 = n;
            for (i__ = 1; i__ <= i__1; ++i__) {
                if (xbdi[i__] == zero) {
                    /* Computing 2nd power */
                    d__1 = d__[i__];
                    resid -= d__1 * d__1;
                    ds += s[i__] * d__[i__];
                    shs += s[i__] * hs[i__];
                }
                /* L60: */
            }
            if (resid <= zero) {
                goto L90;
            }
            temp = std::sqrt(stepsq * resid + ds * ds);
            if (ds < zero) {
                blen = (temp - ds) / stepsq;
            } else {
                blen = resid / (temp + ds);
            }
            stplen = blen;
            if (shs > zero) {
                /* Computing MIN */
                d__1 = blen, d__2 = gredsq / shs;
                stplen = std::min(d__1,d__2);
            }

            /*     Reduce STPLEN if necessary in order to preserve the simple bounds, */
            /*     letting IACT be the index of the new constrained variable. */

            iact = 0;
            i__1 = n;
            for (i__ = 1; i__ <= i__1; ++i__) {
                if (s[i__] != zero) {
                    xsum = xopt[i__] + d__[i__];
                    if (s[i__] > zero) {
                        temp = (su[i__] - xsum) / s[i__];
                    } else {
                        temp = (sl[i__] - xsum) / s[i__];
                    }
                    if (temp < stplen) {
                        stplen = temp;
                        iact = i__;
                    }
                }
                /* L70: */
            }

            /*     Update CRVMIN, GNEW and D. Set SDEC to the decrease that occurs in Q. */

            sdec = zero;
            if (stplen > zero) {
                ++iterc;
                temp = shs / stepsq;
                if (iact == 0 && temp > zero) {
                    *crvmin = std::min(*crvmin,temp);
                    if (*crvmin == onemin) {
                        *crvmin = temp;
                    }
                }
                ggsav = gredsq;
                gredsq = zero;
                i__1 = n;
                for (i__ = 1; i__ <= i__1; ++i__) {
                    gnew[i__] += stplen * hs[i__];
                    if (xbdi[i__] == zero) {
                        /* Computing 2nd power */
                        d__1 = gnew[i__];
                        gredsq += d__1 * d__1;
                    }
                    /* L80: */
                    d__[i__] += stplen * s[i__];
                }
                /* Computing MAX */
                d__1 = stplen * (ggsav - half * stplen * shs);
                sdec = std::max(d__1,zero);
                qred += sdec;
            }

            /*     Restart the conjugate gradient method if it has hit a new bound. */

            if (iact > 0) {
                ++nact;
                xbdi[iact] = one;
                if (s[iact] < zero) {
                    xbdi[iact] = onemin;
                }
                /* Computing 2nd power */
                d__1 = d__[iact];
                delsq -= d__1 * d__1;
                if (delsq <= zero) {
                    goto L90;
                }
                goto L20;
            }

            /*     If STPLEN is less than BLEN, then either apply another conjugate */
            /*     gradient iteration or RETURN. */

            if (stplen < blen) {
                if (iterc == itermax) {
                    goto L190;
                }
                if (sdec <= qred * .01) {
                    goto L190;
                }
                beta = gredsq / ggsav;
                goto L30;
            }
L90:
            *crvmin = zero;

            /*     Prepare for the alternative iteration by calculating some scalars */
            /*     and by multiplying the reduced D by the second derivative matrix of */
            /*     Q, where S holds the reduced D in the call of GGMULT. */

L100:
            if (nact >= n - 1) {
                goto L190;
            }
            dredsq = zero;
            dredg = zero;
            gredsq = zero;
            i__1 = n;
            for (i__ = 1; i__ <= i__1; ++i__) {
                if (xbdi[i__] == zero) {
                    /* Computing 2nd power */
                    d__1 = d__[i__];
                    dredsq += d__1 * d__1;
                    dredg += d__[i__] * gnew[i__];
                    /* Computing 2nd power */
                    d__1 = gnew[i__];
                    gredsq += d__1 * d__1;
                    s[i__] = d__[i__];
                } else {
                    s[i__] = zero;
                }
                /* L110: */
            }
            itcsav = iterc;
            goto L210;

            /*     Let the search direction S be a linear combination of the reduced D */
            /*     and the reduced G that is orthogonal to the reduced D. */

L120:
            ++iterc;
            temp = gredsq * dredsq - dredg * dredg;
            if (temp <= qred * 1e-4 * qred) {
                goto L190;
            }
            temp = std::sqrt(temp);
            i__1 = n;
            for (i__ = 1; i__ <= i__1; ++i__) {
                if (xbdi[i__] == zero) {
                    s[i__] = (dredg * d__[i__] - dredsq * gnew[i__]) / temp;
                } else {
                    s[i__] = zero;
                }
                /* L130: */
            }
            sredg = -temp;

            /*     By considering the simple bounds on the variables, calculate an upper */
            /*     bound on the tangent of half the angle of the alternative iteration, */
            /*     namely ANGBD, except that, if already a free variable has reached a */
            /*     bound, there is a branch back to label 100 after fixing that variable. */

            angbd = one;
            iact = 0;
            i__1 = n;
            for (i__ = 1; i__ <= i__1; ++i__) {
                if (xbdi[i__] == zero) {
                    tempa = xopt[i__] + d__[i__] - sl[i__];
                    tempb = su[i__] - xopt[i__] - d__[i__];
                    if (tempa <= zero) {
                        ++nact;
                        xbdi[i__] = onemin;
                        goto L100;
                    } else if (tempb <= zero) {
                        ++nact;
                        xbdi[i__] = one;
                        goto L100;
                    }
                    /* Computing 2nd power */
                    d__1 = d__[i__];
                    /* Computing 2nd power */
                    d__2 = s[i__];
                    ssq = d__1 * d__1 + d__2 * d__2;
                    /* Computing 2nd power */
                    d__1 = xopt[i__] - sl[i__];
                    temp = ssq - d__1 * d__1;
                    if (temp > zero) {
                        temp = std::sqrt(temp) - s[i__];
                        if (angbd * temp > tempa) {
                            angbd = tempa / temp;
                            iact = i__;
                            xsav = onemin;
                        }
                    }
                    /* Computing 2nd power */
                    d__1 = su[i__] - xopt[i__];
                    temp = ssq - d__1 * d__1;
                    if (temp > zero) {
                        temp = std::sqrt(temp) + s[i__];
                        if (angbd * temp > tempb) {
                            angbd = tempb / temp;
                            iact = i__;
                            xsav = one;
                        }
                    }
                }
                /* L140: */
            }

            /*     Calculate HHD and some curvatures for the alternative iteration. */

            goto L210;
L150:
            shs = zero;
            dhs = zero;
            dhd = zero;
            i__1 = n;
            for (i__ = 1; i__ <= i__1; ++i__) {
                if (xbdi[i__] == zero) {
                    shs += s[i__] * hs[i__];
                    dhs += d__[i__] * hs[i__];
                    dhd += d__[i__] * hred[i__];
                }
                /* L160: */
            }

            /*     Seek the greatest reduction in Q for a range of equally spaced values */
            /*     of ANGT in [0,ANGBD], where ANGT is the tangent of half the angle of */
            /*     the alternative iteration. */

            redmax = zero;
            isav = 0;
            redsav = zero;
            iu = (integer) (angbd * 17. + 3.1);
            i__1 = iu;
            for (i__ = 1; i__ <= i__1; ++i__) {
                angt = angbd * (doublereal) i__ / (doublereal) iu;
                sth = (angt + angt) / (one + angt * angt);
                temp = shs + angt * (angt * dhd - dhs - dhs);
                rednew = sth * (angt * dredg - sredg - half * sth * temp);
                if (rednew > redmax) {
                    redmax = rednew;
                    isav = i__;
                    rdprev = redsav;
                } else if (i__ == isav + 1) {
                    rdnext = rednew;
                }
                /* L170: */
                redsav = rednew;
            }

            /*     Return if the reduction is zero. Otherwise, set the sine and cosine */
            /*     of the angle of the alternative iteration, and calculate SDEC. */

            if (isav == 0) {
                goto L190;
            }
            if (isav < iu) {
                temp = (rdnext - rdprev) / (redmax + redmax - rdprev - rdnext);
                angt = angbd * ((doublereal) isav + half * temp) / (doublereal) iu;
            }
            cth = (one - angt * angt) / (one + angt * angt);
            sth = (angt + angt) / (one + angt * angt);
            temp = shs + angt * (angt * dhd - dhs - dhs);
            sdec = sth * (angt * dredg - sredg - half * sth * temp);
            if (sdec <= zero) {
                goto L190;
            }

            /*     Update GNEW, D and HRED. If the angle of the alternative iteration */
            /*     is restricted by a bound on a free variable, that variable is fixed */
            /*     at the bound. */

            dredg = zero;
            gredsq = zero;
            i__1 = n;
            for (i__ = 1; i__ <= i__1; ++i__) {
                gnew[i__] = gnew[i__] + (cth - one) * hred[i__] + sth * hs[i__];
                if (xbdi[i__] == zero) {
                    d__[i__] = cth * d__[i__] + sth * s[i__];
                    dredg += d__[i__] * gnew[i__];
                    /* Computing 2nd power */
                    d__1 = gnew[i__];
                    gredsq += d__1 * d__1;
                }
                /* L180: */
                hred[i__] = cth * hred[i__] + sth * hs[i__];
            }
            qred += sdec;
            if (iact > 0 && isav == iu) {
                ++nact;
                xbdi[iact] = xsav;
                goto L100;
            }

            /*     If SDEC is sufficiently small, then RETURN after setting XNEW to */
            /*     XOPT+D, giving careful attention to the bounds. */

            if (sdec > qred * .01) {
                goto L120;
            }
L190:
            *dsq = zero;
            i__1 = n;
            for (i__ = 1; i__ <= i__1; ++i__) {
                /* Computing MAX */
                /* Computing MIN */
                d__3 = xopt[i__] + d__[i__], d__4 = su[i__];
                d__1 = std::min(d__3,d__4), d__2 = sl[i__];
                xnew[i__] = std::max(d__1,d__2);
                if (xbdi[i__] == onemin) {
                    xnew[i__] = sl[i__];
                }
                if (xbdi[i__] == one) {
                    xnew[i__] = su[i__];
                }
                d__[i__] = xnew[i__] - xopt[i__];
                /* L200: */
                /* Computing 2nd power */
                d__1 = d__[i__];
                *dsq += d__1 * d__1;
            }
            return;
            /*     The following instructions multiply the current S-vector by the second */
            /*     derivative matrix of the quadratic model, putting the product in HS. */
            /*     They are reached from three different parts of the software above and */
            /*     they can be regarded as an external subroutine. */

L210:
            ih = 0;
            i__1 = n;
            for (j = 1; j <= i__1; ++j) {
                hs[j] = zero;
                i__2 = j;
                for (i__ = 1; i__ <= i__2; ++i__) {
                    ++ih;
                    if (i__ < j) {
                        hs[j] += hq[ih] * s[i__];
                    }
                    /* L220: */
                    hs[i__] += hq[ih] * s[j];
                }
            }
            i__2 = npt;
            for (k = 1; k <= i__2; ++k) {
                if (pq[k] != zero) {
                    temp = zero;
                    i__1 = n;
                    for (j = 1; j <= i__1; ++j) {
                        /* L230: */
                        temp += xpt[k + j * xpt_dim1] * s[j];
                    }
                    temp *= pq[k];
                    i__1 = n;
                    for (i__ = 1; i__ <= i__1; ++i__) {
                        /* L240: */
                        hs[i__] += temp * xpt[k + i__ * xpt_dim1];
                    }
                }
                /* L250: */
            }
            if (*crvmin != zero) {
                goto L50;
            }
            if (iterc > itcsav) {
                goto L150;
            }
            i__2 = n;
            for (i__ = 1; i__ <= i__2; ++i__) {
                /* L260: */
                hred[i__] = hs[i__];
            }
            goto L120;
        } /* trsbox_ */

    // ----------------------------------------------------------------------------------------

        void update_(
            const integer n,
            const integer npt,
            doublereal *bmat,
            doublereal *zmat,
            const integer ndim,
            doublereal *vlag,
            const doublereal beta,
            const doublereal denom,
            const integer knew,
            doublereal *w
        ) const
        {
            /* System generated locals */
            integer bmat_dim1, bmat_offset, zmat_dim1, zmat_offset, i__1, i__2;
            doublereal d__1, d__2, d__3;

            /* Local variables */
            integer i__, j, k, jp;
            doublereal one, tau, temp;
            integer nptm;
            doublereal zero, alpha, tempa, tempb, ztest;

            /*     The arrays BMAT and ZMAT are updated, as required by the new position */
            /*     of the interpolation point that has the index KNEW. The vector VLAG has */
            /*     N+NPT components, set on entry to the first NPT and last N components */
            /*     of the product Hw in equation (4.11) of the Powell (2006) paper on */
            /*     NEWUOA. Further, BETA is set on entry to the value of the parameter */
            /*     with that name, and DENOM is set to the denominator of the updating */
            /*     formula. Elements of ZMAT may be treated as zero if their moduli are */
            /*     at most ZTEST. The first NDIM elements of W are used for working space. */

            /*     Set some constants. */

            /* Parameter adjustments */
            zmat_dim1 = npt;
            zmat_offset = 1 + zmat_dim1;
            zmat -= zmat_offset;
            bmat_dim1 = ndim;
            bmat_offset = 1 + bmat_dim1;
            bmat -= bmat_offset;
            --vlag;
            --w;

            /* Function Body */
            one = 1.;
            zero = 0.;
            nptm = npt - n - 1;
            ztest = zero;
            i__1 = npt;
            for (k = 1; k <= i__1; ++k) {
                i__2 = nptm;
                for (j = 1; j <= i__2; ++j) {
                    /* L10: */
                    /* Computing MAX */
                    d__2 = ztest, d__3 = (d__1 = zmat[k + j * zmat_dim1], std::abs(d__1));
                    ztest = std::max(d__2,d__3);
                }
            }
            ztest *= 1e-20;

            /*     Apply the rotations that put zeros in the KNEW-th row of ZMAT. */

            i__2 = nptm;
            for (j = 2; j <= i__2; ++j) {
                if ((d__1 = zmat[knew + j * zmat_dim1], std::abs(d__1)) > ztest) {
                    /* Computing 2nd power */
                    d__1 = zmat[knew + zmat_dim1];
                    /* Computing 2nd power */
                    d__2 = zmat[knew + j * zmat_dim1];
                    temp = std::sqrt(d__1 * d__1 + d__2 * d__2);
                    tempa = zmat[knew + zmat_dim1] / temp;
                    tempb = zmat[knew + j * zmat_dim1] / temp;
                    i__1 = npt;
                    for (i__ = 1; i__ <= i__1; ++i__) {
                        temp = tempa * zmat[i__ + zmat_dim1] + tempb * zmat[i__ + j *
                            zmat_dim1];
                        zmat[i__ + j * zmat_dim1] = tempa * zmat[i__ + j * zmat_dim1]
                            - tempb * zmat[i__ + zmat_dim1];
                        /* L20: */
                        zmat[i__ + zmat_dim1] = temp;
                    }
                }
                zmat[knew + j * zmat_dim1] = zero;
                /* L30: */
            }

            /*     Put the first NPT components of the KNEW-th column of HLAG into W, */
            /*     and calculate the parameters of the updating formula. */

            i__2 = npt;
            for (i__ = 1; i__ <= i__2; ++i__) {
                w[i__] = zmat[knew + zmat_dim1] * zmat[i__ + zmat_dim1];
                /* L40: */
            }
            alpha = w[knew];
            tau = vlag[knew];
            vlag[knew] -= one;

            /*     Complete the updating of ZMAT. */

            temp = std::sqrt(denom);
            tempb = zmat[knew + zmat_dim1] / temp;
            tempa = tau / temp;
            i__2 = npt;
            for (i__ = 1; i__ <= i__2; ++i__) {
                /* L50: */
                zmat[i__ + zmat_dim1] = tempa * zmat[i__ + zmat_dim1] - tempb * vlag[
                    i__];
            }

            /*     Finally, update the matrix BMAT. */

            i__2 = n;
            for (j = 1; j <= i__2; ++j) {
                jp = npt + j;
                w[jp] = bmat[knew + j * bmat_dim1];
                tempa = (alpha * vlag[jp] - tau * w[jp]) / denom;
                tempb = (-(beta) * w[jp] - tau * vlag[jp]) / denom;
                i__1 = jp;
                for (i__ = 1; i__ <= i__1; ++i__) {
                    bmat[i__ + j * bmat_dim1] = bmat[i__ + j * bmat_dim1] + tempa *
                        vlag[i__] + tempb * w[i__];
                    if (i__ > npt) {
                        bmat[jp + (i__ - npt) * bmat_dim1] = bmat[i__ + j *
                            bmat_dim1];
                    }
                    /* L60: */
                }
            }
        } /* update_ */
    };

// ----------------------------------------------------------------------------------------

    template <
        typename funct,
        typename T,
        typename U
        >
    double find_min_bobyqa (
        const funct& f,
        T& x,
        long npt,
        const U& x_lower,
        const U& x_upper,
        const double rho_begin,
        const double rho_end,
        const long max_f_evals
    )
    {
        // The starting point (i.e. x) must be a column vector.
        COMPILE_TIME_ASSERT(T::NC <= 1);

        // check the requirements.  Also split the assert up so that the error message isn't huge.
        DLIB_CASSERT(is_col_vector(x) && is_col_vector(x_lower) && is_col_vector(x_upper) &&
                    x.size() == x_lower.size() && x_lower.size() == x_upper.size() &&
                    x.size() > 1 && max_f_evals > 1,
            "\tvoid find_min_bobyqa()"
            << "\n\t Invalid arguments have been given to this function"
            << "\n\t is_col_vector(x):       " << is_col_vector(x)
            << "\n\t is_col_vector(x_lower): " << is_col_vector(x_lower)
            << "\n\t is_col_vector(x_upper): " << is_col_vector(x_upper)
            << "\n\t x.size():               " << x.size()
            << "\n\t x_lower.size():         " << x_lower.size()
            << "\n\t x_upper.size():         " << x_upper.size()
            << "\n\t max_f_evals:            " << max_f_evals
        );

        DLIB_CASSERT(x.size() + 2 <= npt && npt <= (x.size()+1)*(x.size()+2)/2 &&
                    0 < rho_end && rho_end < rho_begin &&
                    min(x_upper - x_lower) > 2*rho_begin &&
                    min(x - x_lower) >= 0 && min(x_upper - x) >= 0,
            "\tvoid find_min_bobyqa()"
            << "\n\t Invalid arguments have been given to this function"
            << "\n\t ntp in valid range: " << (x.size() + 2 <= npt && npt <= (x.size()+1)*(x.size()+2)/2)
            << "\n\t npt:                " << npt
            << "\n\t rho_begin:          " << rho_begin
            << "\n\t rho_end:            " << rho_end
            << "\n\t min(x_upper - x_lower) > 2*rho_begin:           " << (min(x_upper - x_lower) > 2*rho_begin)
            << "\n\t min(x - x_lower) >= 0 && min(x_upper - x) >= 0: " << (min(x - x_lower) >= 0 && min(x_upper - x) >= 0)
        );

        bobyqa_implementation impl;
        return impl.find_min(f, x, npt, x_lower, x_upper, rho_begin, rho_end, max_f_evals);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename funct,
        typename T,
        typename U
        >
    double find_max_bobyqa (
        const funct& f,
        T& x,
        long npt,
        const U& x_lower,
        const U& x_upper,
        const double rho_begin,
        const double rho_end,
        const long max_f_evals
    )
    {
        // The starting point (i.e. x) must be a column vector.
        COMPILE_TIME_ASSERT(T::NC <= 1);

        return -find_min_bobyqa(negate_function(f), x, npt, x_lower, x_upper, rho_begin, rho_end, max_f_evals);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_OPTIMIZATIOn_BOBYQA_Hh_


dlib C++ Library - optimization_least_squares.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_OPTIMIZATION_LEAST_SQuARES_H_h_
#define DLIB_OPTIMIZATION_LEAST_SQuARES_H_h_

#include "../matrix.h"
#include "optimization_trust_region.h"
#include "optimization_least_squares_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename column_vector_type,
        typename funct_type,
        typename funct_der_type,
        typename vector_type
        >
    class least_squares_function_model
    {
    public:
        least_squares_function_model (
            const funct_type& f_,
            const funct_der_type& der_,
            const vector_type& list_
        ) : f(f_), der(der_), list(list_)
        {
            S = 0;
            last_f = 0;
            last_f2 = 0;

            r.set_size(list.size(),1);
        }

        const funct_type& f;
        const funct_der_type& der;
        const vector_type& list;

        typedef typename column_vector_type::type type;
        typedef typename column_vector_type::mem_manager_type mem_manager_type;
        typedef typename column_vector_type::layout_type layout_type;
        const static long NR = column_vector_type::NR;

        typedef column_vector_type column_vector;
        typedef matrix<type,NR,NR,mem_manager_type,layout_type> general_matrix;

        type operator() (
            const column_vector& x
        ) const
        {
            type result = 0;
            for (long i = 0; i < list.size(); ++i)
            {
                const type temp = f(list(i), x);
                // save the residual for later
                r(i) = temp;
                result += temp*temp;
            }

            last_f = 0.5*result;
            return 0.5*result;
        }

        void get_derivative_and_hessian (
            const column_vector& x,
            column_vector& d,
            general_matrix& h
        ) const
        {
            J.set_size(list.size(), x.size());

            // compute the Jacobian
            for (long i = 0; i < list.size(); ++i)
            {
                set_rowm(J,i) = trans(der(list(i), x));
            }

            // Compute the Levenberg-Marquardt gradient and hessian
            d = trans(J)*r;
            h = trans(J)*J;

            if (S.size() == 0)
            {
                S.set_size(x.size(), x.size());
                S = 0;
            }

            // If this isn't the first iteration then check if using
            // a quasi-newton update helps things.
            if (last_r.size() != 0)
            {

                s = x - last_x;
                y = d - last_d;
                yy = d - trans(last_J)*r;

                const type ys = trans(y)*s;
                vtemp = yy - S*s;
                const type temp2 = std::abs(trans(s)*S*s);
                type scale = (temp2 != 0) ? std::min<type>(1, std::abs(dot(s,yy))/temp2)  :  1;

                if (ys != 0)
                    S = scale*S + (vtemp*trans(y) + y*trans(vtemp))/(ys) - dot(vtemp,s)/ys/ys*y*trans(y);
                else
                    S *= scale;

                // check how well both the models fit the last change we saw in f()
                const type measured_delta = last_f2 - last_f;
                s = -s;
                const type h_predicted_delta = 0.5*trans(s)*h*s + trans(d)*s;
                const type s_predicted_delta = 0.5*trans(s)*(h+S)*s + trans(d)*s;

                const type h_error = std::abs((h_predicted_delta/measured_delta) - 1);
                const type s_error = std::abs((s_predicted_delta/measured_delta) - 1);

                if (s_error < h_error && h_error > 0.01)
                {
                    h += make_symmetric(S);
                }
                else if (s_error > 10)
                {
                    S = 0;
                }

                // put r into last_r
                r.swap(last_r);
            }
            else
            {
                // put r into last_r
                last_r = r;
            }

            J.swap(last_J);
            last_x = x;
            last_d = d;

            last_f2 = last_f;
        }

        mutable type last_f;   // value of function we saw in last operator()
        mutable type last_f2;  // value of last_f we saw in get_derivative_and_hessian()
        mutable matrix<type,0,1,mem_manager_type,layout_type> r;
        mutable column_vector vtemp;
        mutable column_vector s, y, yy;

        mutable general_matrix S;
        mutable column_vector last_x;
        mutable column_vector last_d;
        mutable matrix<type,0,1,mem_manager_type,layout_type> last_r;
        mutable matrix<type,0,NR,mem_manager_type,layout_type> last_J;
        mutable matrix<type,0,NR,mem_manager_type,layout_type> J;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename column_vector_type,
        typename funct_type,
        typename funct_der_type,
        typename vector_type
        >
    least_squares_function_model<column_vector_type,funct_type,funct_der_type,vector_type> least_squares_model (
        const funct_type& f,
        const funct_der_type& der,
        const vector_type& list
    )
    {
        return least_squares_function_model<column_vector_type,funct_type,funct_der_type,vector_type>(f,der,list);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename stop_strategy_type,
        typename funct_type,
        typename funct_der_type,
        typename vector_type,
        typename T
        >
    double solve_least_squares (
        stop_strategy_type stop_strategy,
        const funct_type& f,
        const funct_der_type& der,
        const vector_type& list,
        T& x,
        double radius = 1
    )
    {
        // The starting point (i.e. x) must be a column vector.
        COMPILE_TIME_ASSERT(T::NC <= 1);

        // make sure requires clause is not broken
        DLIB_ASSERT(is_vector(mat(list)) && list.size() > 0 &&
                    is_col_vector(x) && radius > 0,
            "\t double solve_least_squares()"
            << "\n\t invalid arguments were given to this function"
            << "\n\t is_vector(list):  " << is_vector(mat(list))
            << "\n\t list.size():      " << list.size()
            << "\n\t is_col_vector(x): " << is_col_vector(x)
            << "\n\t radius:           " << radius
            );

        return find_min_trust_region(stop_strategy,
                                     least_squares_model<T>(f, der, mat(list)),
                                     x,
                                     radius);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename column_vector_type,
        typename funct_type,
        typename funct_der_type,
        typename vector_type
        >
    class least_squares_lm_function_model
    {
    public:
        least_squares_lm_function_model (
            const funct_type& f_,
            const funct_der_type& der_,
            const vector_type& list_
        ) : f(f_), der(der_), list(list_)
        {
            r.set_size(list.size(),1);
        }

        const funct_type& f;
        const funct_der_type& der;
        const vector_type& list;

        typedef typename column_vector_type::type type;
        typedef typename column_vector_type::mem_manager_type mem_manager_type;
        typedef typename column_vector_type::layout_type layout_type;
        const static long NR = column_vector_type::NR;

        typedef column_vector_type column_vector;
        typedef matrix<type,NR,NR,mem_manager_type,layout_type> general_matrix;

        mutable matrix<type,0,1,mem_manager_type,layout_type> r;
        mutable column_vector vtemp;

        type operator() (
            const column_vector& x
        ) const
        {
            type result = 0;
            for (long i = 0; i < list.size(); ++i)
            {
                const type temp = f(list(i), x);
                // save the residual for later
                r(i) = temp;
                result += temp*temp;
            }

            return 0.5*result;
        }

        void get_derivative_and_hessian (
            const column_vector& x,
            column_vector& d,
            general_matrix& h
        ) const
        {
            d = 0;
            h = 0;
            for (long i = 0; i < list.size(); ++i)
            {
                vtemp = der(list(i), x);
                d += r(i)*vtemp;
                h += vtemp*trans(vtemp);
            }
        }

    };

// ----------------------------------------------------------------------------------------

    template <
        typename column_vector_type,
        typename funct_type,
        typename funct_der_type,
        typename vector_type
        >
    least_squares_lm_function_model<column_vector_type,funct_type,funct_der_type,vector_type> least_squares_lm_model (
        const funct_type& f,
        const funct_der_type& der,
        const vector_type& list
    )
    {
        return least_squares_lm_function_model<column_vector_type,funct_type,funct_der_type,vector_type>(f,der,list);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename stop_strategy_type,
        typename funct_type,
        typename funct_der_type,
        typename vector_type,
        typename T
        >
    double solve_least_squares_lm (
        stop_strategy_type stop_strategy,
        const funct_type& f,
        const funct_der_type& der,
        const vector_type& list,
        T& x,
        double radius = 1
    )
    {
        // The starting point (i.e. x) must be a column vector.
        COMPILE_TIME_ASSERT(T::NC <= 1);

        // make sure requires clause is not broken
        DLIB_ASSERT(is_vector(mat(list)) && list.size() > 0 &&
                    is_col_vector(x) && radius > 0,
            "\t double solve_least_squares_lm()"
            << "\n\t invalid arguments were given to this function"
            << "\n\t is_vector(list):  " << is_vector(mat(list))
            << "\n\t list.size():      " << list.size()
            << "\n\t is_col_vector(x): " << is_col_vector(x)
            << "\n\t radius:           " << radius
            );

        return find_min_trust_region(stop_strategy,
                                     least_squares_lm_model<T>(f, der, mat(list)),
                                     x,
                                     radius);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_OPTIMIZATION_LEAST_SQuARES_H_h_


dlib C++ Library - optimization_line_search.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_OPTIMIZATIOn_LINE_SEARCH_H_
#define DLIB_OPTIMIZATIOn_LINE_SEARCH_H_

#include <cmath>
#include <limits>
#include "../matrix.h"
#include "../algs.h"
#include "optimization_line_search_abstract.h"
#include <utility>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <typename funct, typename T>
    class line_search_funct
    {
    public:
        line_search_funct(const funct& f_, const T& start_, const T& direction_)
            : f(f_),start(start_), direction(direction_), matrix_r(0), scalar_r(0)
        {}

        line_search_funct(const funct& f_, const T& start_, const T& direction_, T& r)
            : f(f_),start(start_), direction(direction_), matrix_r(&r), scalar_r(0)
        {}

        line_search_funct(const funct& f_, const T& start_, const T& direction_, double& r)
            : f(f_),start(start_), direction(direction_), matrix_r(0), scalar_r(&r)
        {}

        double operator()(const double& x) const
        {
            return get_value(f(start + x*direction));
        }

    private:

        double get_value (const double& r) const
        {
            // save a copy of this value for later
            if (scalar_r)
                *scalar_r = r;

            return r;
        }

        template <typename U>
        double get_value (const U& r) const
        {
            // U should be a matrix type
            COMPILE_TIME_ASSERT(is_matrix<U>::value);

            // save a copy of this value for later
            if (matrix_r)
                *matrix_r = r;

            return dot(r,direction);
        }

        const funct& f;
        const T& start;
        const T& direction;
        T* matrix_r;
        double* scalar_r;
    };

    template <typename funct, typename T>
    const line_search_funct<funct,T> make_line_search_function(const funct& f, const T& start, const T& direction)
    {
        COMPILE_TIME_ASSERT(is_matrix<T>::value);
        DLIB_ASSERT (
            is_col_vector(start) && is_col_vector(direction) && start.size() == direction.size(),
            "\tline_search_funct make_line_search_function(f,start,direction)"
            << "\n\tYou have to supply column vectors to this function"
            << "\n\tstart.nc():     " << start.nc()
            << "\n\tdirection.nc(): " << direction.nc()
            << "\n\tstart.nr():     " << start.nr()
            << "\n\tdirection.nr(): " << direction.nr()
        );
        return line_search_funct<funct,T>(f,start,direction);
    }

// ----------------------------------------------------------------------------------------

    template <typename funct, typename T>
    const line_search_funct<funct,T> make_line_search_function(const funct& f, const T& start, const T& direction, double& f_out)
    {
        COMPILE_TIME_ASSERT(is_matrix<T>::value);
        DLIB_ASSERT (
            is_col_vector(start) && is_col_vector(direction) && start.size() == direction.size(),
            "\tline_search_funct make_line_search_function(f,start,direction)"
            << "\n\tYou have to supply column vectors to this function"
            << "\n\tstart.nc():     " << start.nc()
            << "\n\tdirection.nc(): " << direction.nc()
            << "\n\tstart.nr():     " << start.nr()
            << "\n\tdirection.nr(): " << direction.nr()
        );
        return line_search_funct<funct,T>(f,start,direction, f_out);
    }

// ----------------------------------------------------------------------------------------

    template <typename funct, typename T>
    const line_search_funct<funct,T> make_line_search_function(const funct& f, const T& start, const T& direction, T& grad_out)
    {
        COMPILE_TIME_ASSERT(is_matrix<T>::value);
        DLIB_ASSERT (
            is_col_vector(start) && is_col_vector(direction) && start.size() == direction.size(),
            "\tline_search_funct make_line_search_function(f,start,direction)"
            << "\n\tYou have to supply column vectors to this function"
            << "\n\tstart.nc():     " << start.nc()
            << "\n\tdirection.nc(): " << direction.nc()
            << "\n\tstart.nr():     " << start.nr()
            << "\n\tdirection.nr(): " << direction.nr()
        );
        return line_search_funct<funct,T>(f,start,direction,grad_out);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    inline double poly_min_extrap (
        double f0,
        double d0,
        double f1,
        double d1
    )
    {
        const double n = 3*(f1 - f0) - 2*d0 - d1;
        const double e = d0 + d1 - 2*(f1 - f0);

        // find the minimum of the derivative of the polynomial

        double temp = std::max(n*n - 3*e*d0,0.0);

        if (temp < 0)
            return 0.5;

        temp = std::sqrt(temp);

        if (std::abs(e) <= std::numeric_limits<double>::epsilon())
            return 0.5;

        // figure out the two possible min values
        double x1 = (temp - n)/(3*e);
        double x2 = -(temp + n)/(3*e);

        // compute the value of the interpolating polynomial at these two points
        double y1 = f0 + d0*x1 + n*x1*x1 + e*x1*x1*x1;
        double y2 = f0 + d0*x2 + n*x2*x2 + e*x2*x2*x2;

        // pick the best point
        double x;
        if (y1 < y2)
            x = x1;
        else
            x = x2;

        // now make sure the minimum is within the allowed range of (0,1)
        return put_in_range(0,1,x);
    }

// ----------------------------------------------------------------------------------------

    inline double poly_min_extrap (
        double f0,
        double d0,
        double f1
    )
    {
        const double temp = 2*(f1 - f0 - d0);
        if (std::abs(temp) <= d0*std::numeric_limits<double>::epsilon())
            return 0.5;

        const double alpha = -d0/temp;

        // now make sure the minimum is within the allowed range of (0,1)
        return put_in_range(0,1,alpha);
    }

// ----------------------------------------------------------------------------------------

    inline double poly_min_extrap (
        double f0,
        double d0,
        double x1,
        double f_x1,
        double x2,
        double f_x2
    )
    {
        DLIB_ASSERT(0 < x1 && x1 < x2,"Invalid inputs were given to this function");
        // The contents of this function follow the equations described on page 58 of the
        // book Numerical Optimization by Nocedal and Wright, second edition.
        matrix<double,2,2> m;
        matrix<double,2,1> v;

        const double aa2 = x2*x2;
        const double aa1 = x1*x1;
        m =  aa2,       -aa1,
            -aa2*x2, aa1*x1;
        v = f_x1 - f0 - d0*x1,
            f_x2 - f0 - d0*x2;

        double temp = aa2*aa1*(x1-x2);

        // just take a guess if this happens
        if (temp == 0)
        {
            return x1/2.0;
        }

        matrix<double,2,1> temp2;
        temp2 = m*v/temp;
        const double a = temp2(0);
        const double b = temp2(1);

        temp = b*b - 3*a*d0;
        if (temp < 0 || a == 0)
        {
            // This is probably a line so just pick the lowest point
            if (f0 < f_x2)
                return 0;
            else
                return x2;
        }
        temp = (-b + std::sqrt(temp))/(3*a);
        return put_in_range(0, x2, temp);
    }

// ----------------------------------------------------------------------------------------

    inline double lagrange_poly_min_extrap (
        double p1,
        double p2,
        double p3,
        double f1,
        double f2,
        double f3
    )
    {
        DLIB_ASSERT(p1 < p2 && p2 < p3 && f1 >= f2 && f2 <= f3,
                     "   p1: " << p1
                     << "   p2: " << p2
                     << "   p3: " << p3
                     << "   f1: " << f1
                     << "   f2: " << f2
                     << "   f3: " << f3);

        // This formula is out of the book Nonlinear Optimization by Andrzej Ruszczynski.  See section 5.2.
        double temp1 =    f1*(p3*p3 - p2*p2) + f2*(p1*p1 - p3*p3) + f3*(p2*p2 - p1*p1);
        double temp2 = 2*(f1*(p3 - p2)       + f2*(p1 - p3)       + f3*(p2 - p1) );

        if (temp2 == 0)
        {
            return p2;
        }

        const double result = temp1/temp2;

        // do a final sanity check to make sure the result is in the right range
        if (p1 <= result && result <= p3)
        {
            return result;
        }
        else
        {
            return std::min(std::max(p1,result),p3);
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename funct,
        typename funct_der
        >
    double line_search (
        const funct& f,
        const double f0,
        const funct_der& der,
        const double d0,
        double rho,
        double sigma,
        double min_f,
        unsigned long max_iter
    )
    {
        DLIB_ASSERT (
            0 < rho && rho < sigma && sigma < 1 && max_iter > 0,
            "\tdouble line_search()"
            << "\n\tYou have given invalid arguments to this function"
            << "\n\t sigma:    " << sigma
            << "\n\t rho:      " << rho
            << "\n\t max_iter: " << max_iter
        );

        // The bracketing phase of this function is implemented according to block 2.6.2 from
        // the book Practical Methods of Optimization by R. Fletcher.   The sectioning
        // phase is an implementation of 2.6.4 from the same book.

        // tau1 > 1. Controls the alpha jump size during the search
        const double tau1 = 9;

        // it must be the case that 0 < tau2 < tau3 <= 1/2 for the algorithm to function
        // correctly but the specific values of tau2 and tau3 aren't super important.
        const double tau2 = 1.0/10.0;
        const double tau3 = 1.0/2.0;

        // Stop right away and return a step size of 0 if the gradient is 0 at the starting point
        if (std::abs(d0) < std::numeric_limits<double>::epsilon())
            return 0;

        // Stop right away if the current value is good enough according to min_f
        if (f0 <= min_f)
            return 0;

        // Figure out a reasonable upper bound on how large alpha can get.
        const double mu = (min_f-f0)/(rho*d0);

        double alpha = 1;
        if (mu < 0)
            alpha = -alpha;
        alpha = put_in_range(0, 0.65*mu, alpha);

        double last_alpha = 0;
        double last_val = f0;
        double last_val_der = d0;

        // The bracketing stage will find a range of points [a,b]
        // that contains a reasonable solution to the line search
        double a, b;

        // These variables will hold the values and derivatives of f(a) and f(b)
        double a_val, b_val, a_val_der, b_val_der;

        // This thresh value represents the Wolfe curvature condition
        const double thresh = std::abs(sigma*d0);

        unsigned long itr = 0;
        // do the bracketing stage to find the bracket range [a,b]
        while (true)
        {
            ++itr;
            const double val = f(alpha);
            const double val_der = der(alpha);

            // we are done with the line search since we found a value smaller
            // than the minimum f value
            if (val <= min_f)
                return alpha;

            if (val > f0 + rho*alpha*d0 || val >= last_val)
            {
                a_val = last_val;
                a_val_der = last_val_der;
                b_val = val;
                b_val_der = val_der;

                a = last_alpha;
                b = alpha;
                break;
            }

            if (std::abs(val_der) <= thresh)
                return alpha;

            // if we are stuck not making progress then quit with the current alpha
            if (last_alpha == alpha || itr >= max_iter)
                return alpha;

            if (val_der >= 0)
            {
                a_val = val;
                a_val_der = val_der;
                b_val = last_val;
                b_val_der = last_val_der;

                a = alpha;
                b = last_alpha;
                break;
            }

            if (mu <= 2*alpha - last_alpha)
            {
                last_alpha = alpha;
                alpha = mu;
            }
            else
            {
                const double temp = alpha;

                double first = 2*alpha - last_alpha;
                double last;
                if (mu > 0)
                    last = std::min(mu, alpha + tau1*(alpha - last_alpha));
                else
                    last = std::max(mu, alpha + tau1*(alpha - last_alpha));

                // pick a point between first and last by doing some kind of interpolation
                if (last_alpha < alpha)
                    alpha = last_alpha + (alpha-last_alpha)*poly_min_extrap(last_val, last_val_der, val, val_der);
                else
                    alpha = alpha + (last_alpha-alpha)*poly_min_extrap(val, val_der, last_val, last_val_der);

                alpha = put_in_range(first,last,alpha);

                last_alpha = temp;
            }

            last_val = val;
            last_val_der = val_der;

        }

        // Now do the sectioning phase from 2.6.4
        while (true)
        {
            ++itr;
            double first = a + tau2*(b-a);
            double last = b - tau3*(b-a);

            // use interpolation to pick alpha between first and last
            alpha = a + (b-a)*poly_min_extrap(a_val, a_val_der, b_val, b_val_der);
            alpha = put_in_range(first,last,alpha);

            const double val = f(alpha);
            const double val_der = der(alpha);

            // we are done with the line search since we found a value smaller
            // than the minimum f value or we ran out of iterations.
            if (val <= min_f || itr >= max_iter)
                return alpha;

            // stop if the interval gets so small that it isn't shrinking any more due to rounding error
            if (a == first || b == last)
            {
                return b;
            }

            if (val > f0 + rho*alpha*d0 || val >= a_val)
            {
                b = alpha;
                b_val = val;
                b_val_der = val_der;
            }
            else
            {
                if (std::abs(val_der) <= thresh)
                    return alpha;

                if ( (b-a)*val_der >= 0)
                {
                    b = a;
                    b_val = a_val;
                    b_val_der = a_val_der;
                }

                a = alpha;
                a_val = val;
                a_val_der = val_der;
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename funct
        >
    double backtracking_line_search (
        const funct& f,
        double f0,
        double d0,
        double alpha,
        double rho,
        unsigned long max_iter
    )
    {
        DLIB_ASSERT (
            0 < rho && rho < 1 && max_iter > 0,
            "\tdouble backtracking_line_search()"
            << "\n\tYou have given invalid arguments to this function"
            << "\n\t rho:      " << rho
            << "\n\t max_iter: " << max_iter
        );

        // make sure alpha is going in the right direction.  That is, it should be opposite
        // the direction of the gradient.
        if ((d0 > 0 && alpha > 0) ||
            (d0 < 0 && alpha < 0))
        {
            alpha *= -1;
        }

        bool have_prev_alpha = false;
        double prev_alpha = 0;
        double prev_val = 0;
        unsigned long iter = 0;
        while (true)
        {
            ++iter;
            const double val = f(alpha);
            if (val <= f0 + alpha*rho*d0 || iter >= max_iter)
            {
                return alpha;
            }
            else
            {
                // Interpolate a new alpha.  We also make sure the step by which we
                // reduce alpha is not super small.
                double step;
                if (!have_prev_alpha)
                {
                    if (d0 < 0)
                        step = alpha*put_in_range(0.1,0.9, poly_min_extrap(f0, d0, val));
                    else
                        step = alpha*put_in_range(0.1,0.9, poly_min_extrap(f0, -d0, val));
                    have_prev_alpha = true;
                }
                else
                {
                    if (d0 < 0)
                        step = put_in_range(0.1*alpha,0.9*alpha, poly_min_extrap(f0, d0, alpha, val, prev_alpha, prev_val));
                    else
                        step = put_in_range(0.1*alpha,0.9*alpha, -poly_min_extrap(f0, -d0, -alpha, val, -prev_alpha, prev_val));
                }

                prev_alpha = alpha;
                prev_val = val;

                alpha = step;
            }
        }
    }

// ----------------------------------------------------------------------------------------

    class optimize_single_variable_failure : public error {
    public: optimize_single_variable_failure(const std::string& s):error(s){}
    };

// ----------------------------------------------------------------------------------------

    template <typename funct>
    double find_min_single_variable (
        const funct& f,
        double& starting_point,
        const double begin = -1e200,
        const double end = 1e200,
        const double eps = 1e-3,
        const long max_iter = 100,
        const double initial_search_radius = 1
    )
    {
        DLIB_CASSERT( eps > 0 &&
                      max_iter > 1 &&
                      begin <= starting_point && starting_point <= end &&
                      initial_search_radius > 0,
                      "eps: " << eps
                      << "\n max_iter: "<< max_iter
                      << "\n begin: "<< begin
                      << "\n end:   "<< end
                      << "\n starting_point: "<< starting_point
                      << "\n initial_search_radius: "<< initial_search_radius
        );

        double search_radius = initial_search_radius;

        double p1=0, p2=0, p3=0, f1=0, f2=0, f3=0;
        long f_evals = 1;

        if (begin == end)
        {
            return f(starting_point);
        }

        using std::abs;
        using std::min;
        using std::max;

        // find three bracketing points such that f1 > f2 < f3.   Do this by generating a sequence
        // of points expanding away from 0.   Also note that, in the following code, it is always the
        // case that p1 < p2 < p3.

        // The first thing we do is get a starting set of 3 points that are inside the [begin,end] bounds
        p1 = max(starting_point-search_radius, begin);
        p3 = min(starting_point+search_radius, end);
        f1 = f(p1);
        f3 = f(p3);

        if (starting_point == p1 || starting_point == p3)
        {
            p2 = (p1+p3)/2;
            f2 = f(p2);
        }
        else
        {
            p2 = starting_point;
            f2 = f(starting_point);
        }

        f_evals += 2;

        // Now we have 3 points on the function.  Start looking for a bracketing set such that
        // f1 > f2 < f3 is the case.
        while ( !(f1 > f2 && f2 < f3))
        {
            // check for hitting max_iter or if the interval is now too small
            if (f_evals >= max_iter)
            {
                throw optimize_single_variable_failure(
                    "The max number of iterations of single variable optimization have been reached\n"
                    "without converging.");
            }
            if (p3-p1 < eps)
            {
                if (f1 < min(f2,f3))
                {
                    starting_point = p1;
                    return f1;
                }

                if (f2 < min(f1,f3))
                {
                    starting_point = p2;
                    return f2;
                }

                starting_point = p3;
                return f3;
            }

            // If the left most points are identical in function value then expand out the
            // left a bit, unless it's already at bound or we would drop that left most
            // point anyway because it's bad.
            if (f1==f2 && f1<f3 && p1!=begin)
            {
                p1 = max(p1 - search_radius, begin);
                f1 = f(p1);
                ++f_evals;
                search_radius *= 2;
                continue;
            }
            if (f2==f3 && f3<f1 && p3!=end)
            {
                p3 = min(p3 + search_radius, end);
                f3 = f(p3);
                ++f_evals;
                search_radius *= 2;
                continue;
            }

            // if f1 is small then take a step to the left
            if (f1 <= f3)
            {
                // check if the minimum is butting up against the bounds and if so then pick
                // a point between p1 and p2 in the hopes that shrinking the interval will
                // be a good thing to do.  Or if p1 and p2 aren't differentiated then try and
                // get them to obtain different values.
                if (p1 == begin || (f1 == f2 && (end-begin) < search_radius ))
                {
                    p3 = p2;
                    f3 = f2;

                    p2 = (p1+p2)/2.0;
                    f2 = f(p2);
                }
                else
                {
                    // pick a new point to the left of our current bracket
                    p3 = p2;
                    f3 = f2;

                    p2 = p1;
                    f2 = f1;

                    p1 = max(p1 - search_radius, begin);
                    f1 = f(p1);

                    search_radius *= 2;
                }

            }
            // otherwise f3 is small and we should take a step to the right
            else
            {
                // check if the minimum is butting up against the bounds and if so then pick
                // a point between p2 and p3 in the hopes that shrinking the interval will
                // be a good thing to do.  Or if p2 and p3 aren't differentiated then try and
                // get them to obtain different values.
                if (p3 == end || (f2 == f3 && (end-begin) < search_radius))
                {
                    p1 = p2;
                    f1 = f2;

                    p2 = (p3+p2)/2.0;
                    f2 = f(p2);
                }
                else
                {
                    // pick a new point to the right of our current bracket
                    p1 = p2;
                    f1 = f2;

                    p2 = p3;
                    f2 = f3;

                    p3 = min(p3 + search_radius, end);
                    f3 = f(p3);

                    search_radius *= 2;
                }
            }

            ++f_evals;
        }

        // Loop until we have done the max allowable number of iterations or
        // the bracketing window is smaller than eps.
        // Within this loop we maintain the invariant that: f1 > f2 < f3 and p1 < p2 < p3
        const double tau = 0.1;
        while( f_evals < max_iter && p3-p1 > eps)
        {
            double p_min = lagrange_poly_min_extrap(p1,p2,p3, f1,f2,f3);

            // make sure p_min isn't too close to the three points we already have
            if (p_min < p2)
            {
                const double min_dist = (p2-p1)*tau;
                if (abs(p1-p_min) < min_dist)
                {
                    p_min = p1 + min_dist;
                }
                else if (abs(p2-p_min) < min_dist)
                {
                    p_min = p2 - min_dist;
                }
            }
            else
            {
                const double min_dist = (p3-p2)*tau;
                if (abs(p2-p_min) < min_dist)
                {
                    p_min = p2 + min_dist;
                }
                else if (abs(p3-p_min) < min_dist)
                {
                    p_min = p3 - min_dist;
                }
            }

            // make sure one side of the bracket isn't super huge compared to the other
            // side.  If it is then contract it.
            const double bracket_ratio = abs(p1-p2)/abs(p2-p3);
            if ( !( bracket_ratio < 10 && bracket_ratio > 0.1) )
            {
                // Force p_min to be on a reasonable side.  But only if lagrange_poly_min_extrap()
                // didn't put it on a good side already.
                if (bracket_ratio > 1 && p_min > p2)
                    p_min = (p1+p2)/2;
                else if (p_min < p2)
                    p_min = (p2+p3)/2;
            }

            const double f_min = f(p_min);

            // Remove one of the endpoints of our bracket depending on where the new point falls.
            if (p_min < p2)
            {
                if (f1 > f_min && f_min < f2)
                {
                    p3 = p2;
                    f3 = f2;
                    p2 = p_min;
                    f2 = f_min;
                }
                else
                {
                    p1 = p_min;
                    f1 = f_min;
                }
            }
            else
            {
                if (f2 > f_min && f_min < f3)
                {
                    p1 = p2;
                    f1 = f2;
                    p2 = p_min;
                    f2 = f_min;
                }
                else
                {
                    p3 = p_min;
                    f3 = f_min;
                }
            }

            ++f_evals;
        }

        if (f_evals >= max_iter)
        {
            throw optimize_single_variable_failure(
                "The max number of iterations of single variable optimization have been reached\n"
                "without converging.");
        }

        starting_point = p2;
        return f2;
    }

// ----------------------------------------------------------------------------------------

    template <typename funct>
    class negate_function_object
    {
    public:
        negate_function_object(const funct& f_) : f(f_){}

        template <typename T>
        double operator()(const T& x) const
        {
            return -f(x);
        }

    private:
        const funct& f;
    };

    template <typename funct>
    const negate_function_object<funct> negate_function(const funct& f) { return negate_function_object<funct>(f); }

// ----------------------------------------------------------------------------------------

    template <typename funct>
    double find_max_single_variable (
        const funct& f,
        double& starting_point,
        const double begin = -1e200,
        const double end = 1e200,
        const double eps = 1e-3,
        const long max_iter = 100,
        const double initial_search_radius = 1
    )
    {
        return -find_min_single_variable(negate_function(f), starting_point, begin, end, eps, max_iter, initial_search_radius);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_OPTIMIZATIOn_LINE_SEARCH_H_


dlib C++ Library - optimization_oca.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_OPTIMIZATIoN_OCA_Hh_
#define DLIB_OPTIMIZATIoN_OCA_Hh_

#include "optimization_oca_abstract.h"

#include "../matrix.h"
#include "optimization_solve_qp_using_smo.h"
#include <vector>
#include "../sequence.h"

// ----------------------------------------------------------------------------------------

namespace dlib
{
    template <typename matrix_type>
    class oca_problem
    {
    public:
        typedef typename matrix_type::type scalar_type;

        virtual ~oca_problem() {}

        virtual bool risk_has_lower_bound (
            scalar_type&
        ) const { return false; }

        virtual bool optimization_status (
            scalar_type ,
            scalar_type ,
            scalar_type ,
            scalar_type ,
            unsigned long,
            unsigned long
        ) const = 0;

        virtual scalar_type get_c (
        ) const = 0;

        virtual long get_num_dimensions (
        ) const = 0;

        virtual void get_risk (
            matrix_type& current_solution,
            scalar_type& risk_value,
            matrix_type& risk_subgradient
        ) const = 0;

    };

// ----------------------------------------------------------------------------------------

    class oca
    {
    public:

        oca ()
        {
            sub_eps = 1e-2;
            sub_max_iter = 50000;

            inactive_thresh = 20;
        }

        void set_subproblem_epsilon (
            double eps_
        ) { sub_eps = eps_; }

        double get_subproblem_epsilon (
        ) const { return sub_eps; }

        void set_subproblem_max_iterations (
            unsigned long sub_max_iter_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(sub_max_iter_ > 0,
                "\t void oca::set_subproblem_max_iterations"
                << "\n\t max iterations must be greater than 0"
                << "\n\t sub_max_iter_: " << sub_max_iter_
                << "\n\t this: " << this
                );

            sub_max_iter = sub_max_iter_;
        }

        unsigned long get_subproblem_max_iterations (
        ) const { return sub_max_iter; }

        void set_inactive_plane_threshold (
            unsigned long inactive_thresh_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(inactive_thresh_ > 0,
                "\t void oca::set_inactive_plane_threshold"
                << "\n\t inactive threshold must be greater than 0"
                << "\n\t inactive_thresh_: " << inactive_thresh_
                << "\n\t this: " << this
                );

            inactive_thresh = inactive_thresh_;
        }

        unsigned long get_inactive_plane_threshold (
        ) const { return inactive_thresh; }

        template <
            typename matrix_type
            >
        typename matrix_type::type operator() (
            const oca_problem<matrix_type>& problem,
            matrix_type& w,
            unsigned long num_nonnegative = 0,
            unsigned long force_weight_to_1 = std::numeric_limits<unsigned long>::max()
        ) const
        {
            matrix_type empty_prior;
            return oca_impl(problem, w, empty_prior, false, num_nonnegative, force_weight_to_1);
        }

        template <
            typename matrix_type
            >
        typename matrix_type::type operator() (
            const oca_problem<matrix_type>& problem,
            matrix_type& w,
            const matrix_type& prior
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(is_col_vector(prior) && prior.size() == problem.get_num_dimensions(),
                "\t scalar_type oca::operator()"
                << "\n\t The prior vector does not have the correct dimensions."
                << "\n\t is_col_vector(prior):         " << is_col_vector(prior)
                << "\n\t prior.size():                 " << prior.size()
                << "\n\t problem.get_num_dimensions(): " << problem.get_num_dimensions()
                << "\n\t this:                         " << this
                );
            // disable the force weight to 1 option for this mode.  We also disable the
            // non-negative constraints.
            unsigned long force_weight_to_1 = std::numeric_limits<unsigned long>::max();
            return oca_impl(problem, w, prior, true, 0, force_weight_to_1);
        }

    private:

        template <
            typename matrix_type
            >
        typename matrix_type::type oca_impl (
            const oca_problem<matrix_type>& problem,
            matrix_type& w,
            const matrix_type prior,
            bool have_prior,
            unsigned long num_nonnegative,
            unsigned long force_weight_to_1
        ) const
        {
            const unsigned long num_dims = problem.get_num_dimensions();

            // make sure requires clause is not broken
            DLIB_ASSERT(problem.get_c() > 0 &&
                        problem.get_num_dimensions() > 0,
                "\t scalar_type oca::operator()"
                << "\n\t The oca_problem is invalid"
                << "\n\t problem.get_c():              " << problem.get_c()
                << "\n\t problem.get_num_dimensions(): " << num_dims
                << "\n\t this: " << this
                );

            if (num_nonnegative > num_dims)
                num_nonnegative = num_dims;

            typedef typename matrix_type::type scalar_type;
            typedef typename matrix_type::layout_type layout_type;
            typedef typename matrix_type::mem_manager_type mem_manager_type;
            typedef matrix_type vect_type;

            const scalar_type C = problem.get_c();

            typename sequence<vect_type>::kernel_2a planes;
            std::vector<scalar_type> bs, miss_count;

            vect_type new_plane, alpha;

            w.set_size(num_dims, 1);
            w = 0;

            // The current objective value.  Note also that w always contains
            // the current solution.
            scalar_type cur_obj = std::numeric_limits<scalar_type>::max();

            // This will hold the cutting plane objective value.  This value is
            // a lower bound on the true optimal objective value.
            scalar_type cp_obj = 0;

            matrix<scalar_type,0,0,mem_manager_type, layout_type> K, Ktmp;

            scalar_type R_lower_bound;
            if (problem.risk_has_lower_bound(R_lower_bound))
            {
                // The flat lower bounding plane is always good to have if we know
                // what it is.
                bs.push_back(R_lower_bound);
                new_plane = zeros_matrix(w);
                planes.add(0, new_plane);
                alpha = uniform_matrix<scalar_type>(1,1, C);
                miss_count.push_back(0);

                K.set_size(1,1);
                K(0,0) = 0;
            }

            const double prior_norm = have_prior ?  0.5*dot(prior,prior) : 0;

            unsigned long counter = 0;
            while (true)
            {

                // add the next cutting plane
                scalar_type cur_risk;
                if (force_weight_to_1 < (unsigned long)w.size())
                    w(force_weight_to_1) = 1;

                problem.get_risk(w, cur_risk, new_plane);

                if (force_weight_to_1 < (unsigned long)w.size())
                {
                    // We basically arrange for the w(force_weight_to_1) element and all
                    // subsequent elements of w to not be involved in the optimization at
                    // all.  An easy way to do this is to just make sure the elements of w
                    // corresponding elements in the subgradient are always set to zero
                    // while we run the cutting plane algorithm.  The only time
                    // w(force_weight_to_1) is 1 is when we pass it to the oca_problem.
                    set_rowm(w, range(force_weight_to_1, w.size()-1)) = 0;
                    set_rowm(new_plane, range(force_weight_to_1, new_plane.size()-1)) = 0;
                }

                if (have_prior)
                    bs.push_back(cur_risk - dot(w,new_plane) + dot(prior,new_plane));
                else
                    bs.push_back(cur_risk - dot(w,new_plane));
                planes.add(planes.size(), new_plane);
                miss_count.push_back(0);

                // If alpha is empty then initialize it (we must always have sum(alpha) == C).
                // But otherwise, just append a zero.
                if (alpha.size() == 0)
                    alpha = uniform_matrix<scalar_type>(1,1, C);
                else
                    alpha = join_cols(alpha,zeros_matrix<scalar_type>(1,1));

                const scalar_type wnorm = 0.5*trans(w)*w;
                const double prior_part = have_prior? dot(w,prior) : 0;
                cur_obj = wnorm + C*cur_risk + prior_norm-prior_part;

                // report current status
                const scalar_type risk_gap = cur_risk - (cp_obj-wnorm+prior_part-prior_norm)/C;
                if (counter > 0 && problem.optimization_status(cur_obj, cur_obj - cp_obj,
                                                               cur_risk, risk_gap, planes.size(), counter))
                {
                    break;
                }

                // compute kernel matrix for all the planes
                K.swap(Ktmp);
                K.set_size(planes.size(), planes.size());
                // copy over the old K matrix
                set_subm(K, 0,0, Ktmp.nr(), Ktmp.nc()) = Ktmp;

                // now add the new row and column to K
                for (unsigned long c = 0; c < planes.size(); ++c)
                {
                    K(c, Ktmp.nc()) = dot(planes[c], planes[planes.size()-1]);
                    K(Ktmp.nc(), c) = K(c,Ktmp.nc());
                }

                // solve the cutting plane subproblem for the next w.   We solve it to an
                // accuracy that is related to how big the error gap is
                scalar_type eps = std::min<scalar_type>(sub_eps, 0.1*(cur_obj-cp_obj)) ;
                // just a sanity check
                if (eps < 1e-16)
                    eps = 1e-16;
                // Note that we warm start this optimization by using the alpha from the last
                // iteration as the starting point.
                if (num_nonnegative != 0)
                {
                    // copy planes into a matrix so we can call solve_qp4_using_smo()
                    matrix<scalar_type,0,0,mem_manager_type, layout_type> planes_mat(num_nonnegative,planes.size());
                    for (unsigned long i = 0; i < planes.size(); ++i)
                        set_colm(planes_mat,i) = colm(planes[i],0,num_nonnegative);

                    solve_qp4_using_smo(planes_mat, K, mat(bs), alpha, eps, sub_max_iter);
                }
                else
                {
                    solve_qp_using_smo(K, mat(bs), alpha, eps, sub_max_iter);
                }

                // construct the w that minimized the subproblem.
                w = -alpha(0)*planes[0];
                for (unsigned long i = 1; i < planes.size(); ++i)
                    w -= alpha(i)*planes[i];
                // threshold the first num_nonnegative w elements if necessary.
                if (num_nonnegative != 0)
                    set_rowm(w,range(0,num_nonnegative-1)) = lowerbound(rowm(w,range(0,num_nonnegative-1)),0);

                for (long i = 0; i < alpha.size(); ++i)
                {
                    if (alpha(i) != 0)
                        miss_count[i] = 0;
                    else
                        miss_count[i] += 1;
                }

                // Compute the lower bound on the true objective given to us by the cutting
                // plane subproblem.
                cp_obj = -0.5*trans(w)*w + trans(alpha)*mat(bs);
                if (have_prior)
                    w += prior;

                // If it has been a while since a cutting plane was an active constraint then
                // we should throw it away.
                while (max(mat(miss_count)) >= inactive_thresh)
                {
                    const long idx = index_of_max(mat(miss_count));
                    bs.erase(bs.begin()+idx);
                    miss_count.erase(miss_count.begin()+idx);
                    K = removerc(K, idx, idx);
                    alpha = remove_row(alpha,idx);
                    planes.remove(idx, new_plane);
                }

                ++counter;
            }

            if (force_weight_to_1 < (unsigned long)w.size())
                w(force_weight_to_1) = 1;

            return cur_obj;
        }

        double sub_eps;

        unsigned long sub_max_iter;

        unsigned long inactive_thresh;
    };
}

// ----------------------------------------------------------------------------------------

#endif // DLIB_OPTIMIZATIoN_OCA_Hh_


dlib C++ Library - optimization_search_strategies.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_OPTIMIZATIOn_SEARCH_STRATEGIES_H_
#define DLIB_OPTIMIZATIOn_SEARCH_STRATEGIES_H_

#include <cmath>
#include <limits>
#include "../matrix.h"
#include "../algs.h"
#include "optimization_search_strategies_abstract.h"
#include "../sequence.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class cg_search_strategy
    {
    public:
        cg_search_strategy() : been_used(false) {}

        double get_wolfe_rho (
        ) const { return 0.001; }

        double get_wolfe_sigma (
        ) const { return 0.01; }

        unsigned long get_max_line_search_iterations (
        ) const { return 100; }

        template <typename T>
        const matrix<double,0,1>& get_next_direction (
            const T& ,
            const double ,
            const T& funct_derivative
        )
        {
            if (been_used == false)
            {
                been_used = true;
                prev_direction = -funct_derivative;
            }
            else
            {
                // Use the Polak-Ribiere (4.1.12) conjugate gradient described by Fletcher on page 83
                const double temp = trans(prev_derivative)*prev_derivative;
                // If this value hits zero then just use the direction of steepest descent.
                if (std::abs(temp) < std::numeric_limits<double>::epsilon())
                {
                    prev_derivative = funct_derivative;
                    prev_direction = -funct_derivative;
                    return prev_direction;
                }

                double b = trans(funct_derivative-prev_derivative)*funct_derivative/(temp);
                prev_direction = -funct_derivative + b*prev_direction;

            }

            prev_derivative = funct_derivative;
            return prev_direction;
        }

    private:
        bool been_used;
        matrix<double,0,1> prev_derivative;
        matrix<double,0,1> prev_direction;
    };

// ----------------------------------------------------------------------------------------

    class bfgs_search_strategy
    {
    public:
        bfgs_search_strategy() : been_used(false), been_used_twice(false) {}

        double get_wolfe_rho (
        ) const { return 0.01; }

        double get_wolfe_sigma (
        ) const { return 0.9; }

        unsigned long get_max_line_search_iterations (
        ) const { return 100; }

        template <typename T>
        const matrix<double,0,1>& get_next_direction (
            const T& x,
            const double ,
            const T& funct_derivative
        )
        {
            if (been_used == false)
            {
                been_used = true;
                H = identity_matrix<double>(x.size());
            }
            else
            {
                // update H with the BFGS formula from (3.2.12) on page 55 of Fletcher
                delta = (x-prev_x);
                gamma = funct_derivative-prev_derivative;

                double dg = dot(delta,gamma);

                // Try to set the initial value of the H matrix to something reasonable if we are still
                // in the early stages of figuring out what it is.  This formula below is what is suggested
                // in the book Numerical Optimization by Nocedal and Wright in the chapter on Quasi-Newton methods.
                if (been_used_twice == false)
                {
                    double gg = trans(gamma)*gamma;
                    if (std::abs(gg) > std::numeric_limits<double>::epsilon())
                    {
                        const double temp = put_in_range(0.01, 100, dg/gg);
                        H = diagm(uniform_matrix<double>(x.size(),1, temp));
                        been_used_twice = true;
                    }
                }

                Hg = H*gamma;
                gH = trans(trans(gamma)*H);
                double gHg = trans(gamma)*H*gamma;
                if (gHg < std::numeric_limits<double>::infinity() && dg < std::numeric_limits<double>::infinity() &&
                    dg != 0)
                {
                    H += (1 + gHg/dg)*delta*trans(delta)/(dg) - (delta*trans(gH) + Hg*trans(delta))/(dg);
                }
                else
                {
                    H = identity_matrix<double>(H.nr());
                    been_used_twice = false;
                }
            }

            prev_x = x;
            prev_direction = -H*funct_derivative;
            prev_derivative = funct_derivative;
            return prev_direction;
        }

    private:
        bool been_used;
        bool been_used_twice;
        matrix<double,0,1> prev_x;
        matrix<double,0,1> prev_derivative;
        matrix<double,0,1> prev_direction;
        matrix<double> H;
        matrix<double,0,1> delta, gamma, Hg, gH;
    };

// ----------------------------------------------------------------------------------------

    class lbfgs_search_strategy
    {
    public:
        explicit lbfgs_search_strategy(unsigned long max_size_) : max_size(max_size_), been_used(false)
        {
            DLIB_ASSERT (
                max_size > 0,
                "\t lbfgs_search_strategy(max_size)"
                << "\n\t max_size can't be zero"
            );
        }

        lbfgs_search_strategy(const lbfgs_search_strategy& item)
        {
            max_size = item.max_size;
            been_used = item.been_used;
            prev_x = item.prev_x;
            prev_derivative = item.prev_derivative;
            prev_direction = item.prev_direction;
            alpha = item.alpha;
            dh_temp = item.dh_temp;
        }

        double get_wolfe_rho (
        ) const { return 0.01; }

        double get_wolfe_sigma (
        ) const { return 0.9; }

        unsigned long get_max_line_search_iterations (
        ) const { return 100; }

        template <typename T>
        const matrix<double,0,1>& get_next_direction (
            const T& x,
            const double ,
            const T& funct_derivative
        )
        {
            prev_direction = -funct_derivative;

            if (been_used == false)
            {
                been_used = true;
            }
            else
            {
                // add an element into the stored data sequence
                dh_temp.s = x - prev_x;
                dh_temp.y = funct_derivative - prev_derivative;
                double temp = dot(dh_temp.s, dh_temp.y);
                // only accept this bit of data if temp isn't zero
                if (std::abs(temp) > std::numeric_limits<double>::epsilon())
                {
                    dh_temp.rho = 1/temp;
                    data.add(data.size(), dh_temp);
                }
                else
                {
                    data.clear();
                }

                if (data.size() > 0)
                {
                    // This block of code is from algorithm 7.4 in the Nocedal book.

                    alpha.resize(data.size());
                    for (unsigned long i = data.size()-1; i < data.size(); --i)
                    {
                        alpha[i] = data[i].rho*dot(data[i].s, prev_direction);
                        prev_direction -= alpha[i]*data[i].y;
                    }

                    // Take a guess at what the first H matrix should be.  This formula below is what is suggested
                    // in the book Numerical Optimization by Nocedal and Wright in the chapter on Large Scale
                    // Unconstrained Optimization (in the L-BFGS section).
                    double H_0 = 1.0/data[data.size()-1].rho/dot(data[data.size()-1].y, data[data.size()-1].y);
                    H_0 = put_in_range(0.001, 1000.0, H_0);
                    prev_direction *= H_0;

                    for (unsigned long i = 0; i < data.size(); ++i)
                    {
                        double beta = data[i].rho*dot(data[i].y, prev_direction);
                        prev_direction += data[i].s * (alpha[i] - beta);
                    }
                }

            }

            if (data.size() > max_size)
            {
                // remove the oldest element in the data sequence
                data.remove(0, dh_temp);
            }

            prev_x = x;
            prev_derivative = funct_derivative;
            return prev_direction;
        }

    private:

        struct data_helper
        {
            matrix<double,0,1> s;
            matrix<double,0,1> y;
            double rho;

            friend void swap(data_helper& a, data_helper& b)
            {
                a.s.swap(b.s);
                a.y.swap(b.y);
                std::swap(a.rho, b.rho);
            }
        };
        sequence<data_helper>::kernel_2a data;

        unsigned long max_size;
        bool been_used;
        matrix<double,0,1> prev_x;
        matrix<double,0,1> prev_derivative;
        matrix<double,0,1> prev_direction;
        std::vector<double> alpha;

        data_helper dh_temp;
    };

// ----------------------------------------------------------------------------------------

    template <typename hessian_funct>
    class newton_search_strategy_obj
    {
    public:
        explicit newton_search_strategy_obj(
            const hessian_funct& hess
        ) : hessian(hess) {}

        double get_wolfe_rho (
        ) const { return 0.01; }

        double get_wolfe_sigma (
        ) const { return 0.9; }

        unsigned long get_max_line_search_iterations (
        ) const { return 100; }

        template <typename T>
        const matrix<double,0,1> get_next_direction (
            const T& x,
            const double ,
            const T& funct_derivative
        )
        {
            return -inv(hessian(x))*funct_derivative;
        }

    private:
        hessian_funct hessian;
    };

    template <typename hessian_funct>
    newton_search_strategy_obj<hessian_funct> newton_search_strategy (
        hessian_funct hessian
    ) { return newton_search_strategy_obj<hessian_funct>(hessian); }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_OPTIMIZATIOn_SEARCH_STRATEGIES_H_


dlib C++ Library - optimization_solve_qp2_using_smo.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SOLVE_QP2_USING_SMo_Hh_
#define DLIB_SOLVE_QP2_USING_SMo_Hh_

#include "optimization_solve_qp2_using_smo_abstract.h"
#include <cmath>
#include <limits>
#include <sstream>
#include "../matrix.h"
#include "../algs.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class invalid_nu_error : public dlib::error
    {
    public:
        invalid_nu_error(const std::string& msg, double nu_) : dlib::error(msg), nu(nu_) {};
        const double nu;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    typename T::type maximum_nu_impl (
        const T& y
    )
    {
        typedef typename T::type scalar_type;
        // make sure requires clause is not broken
        DLIB_ASSERT(y.size() > 1 && is_col_vector(y),
            "\ttypedef T::type maximum_nu(y)"
            << "\n\ty should be a column vector with more than one entry"
            << "\n\ty.nr(): " << y.nr()
            << "\n\ty.nc(): " << y.nc()
            );

        long pos_count = 0;
        long neg_count = 0;
        for (long r = 0; r < y.nr(); ++r)
        {
            if (y(r) == 1.0)
            {
                ++pos_count;
            }
            else if (y(r) == -1.0)
            {
                ++neg_count;
            }
            else
            {
                // make sure requires clause is not broken
                DLIB_ASSERT(y(r) == -1.0 || y(r) == 1.0,
                       "\ttypedef T::type maximum_nu(y)"
                       << "\n\ty should contain only 1 and 0 entries"
                       << "\n\tr:    " << r
                       << "\n\ty(r): " << y(r)
                );
            }
        }
        return static_cast<scalar_type>(2.0*(scalar_type)std::min(pos_count,neg_count)/(scalar_type)y.nr());
    }

    template <
        typename T
        >
    typename T::type maximum_nu (
        const T& y
    )
    {
        return maximum_nu_impl(mat(y));
    }

    template <
        typename T
        >
    typename T::value_type maximum_nu (
        const T& y
    )
    {
        return maximum_nu_impl(mat(y));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_type
        >
    class solve_qp2_using_smo
    {
    public:
        typedef typename matrix_type::mem_manager_type mem_manager_type;
        typedef typename matrix_type::type scalar_type;
        typedef typename matrix_type::layout_type layout_type;
        typedef matrix<scalar_type,0,0,mem_manager_type,layout_type> general_matrix;
        typedef matrix<scalar_type,0,1,mem_manager_type,layout_type> column_matrix;

        template <
            typename EXP1,
            typename EXP2,
            long NR
            >
        unsigned long operator() (
            const matrix_exp<EXP1>& Q,
            const matrix_exp<EXP2>& y,
            const scalar_type nu,
            matrix<scalar_type,NR,1,mem_manager_type, layout_type>& alpha,
            scalar_type eps
        )
        {
            DLIB_ASSERT(Q.nr() == Q.nc() && y.size() == Q.nr() && y.size() > 1 && is_col_vector(y) &&
                        sum((y == +1) + (y == -1)) == y.size() &&
                        0 < nu && nu <= 1 &&
                        eps > 0,
                "\t void solve_qp2_using_smo::operator()"
                << "\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(y):           " << is_col_vector(y)
                << "\n\t y.size():                   " << y.size()
                << "\n\t sum((y == +1) + (y == -1)): " << sum((y == +1) + (y == -1))
                << "\n\t nu:                         " << nu
                << "\n\t eps:                        " << eps
                );

            alpha.set_size(Q.nr(),1);
            df.set_size(Q.nr());

            // now initialize alpha
            set_initial_alpha(y, nu, alpha);

            const scalar_type tau = 1e-12;

            typedef typename colm_exp<EXP1>::type col_type;

            set_all_elements(df, 0);
            // initialize df.  Compute df = Q*alpha
            for (long r = 0; r < df.nr(); ++r)
            {
                if (alpha(r) != 0)
                {
                    df += alpha(r)*matrix_cast<scalar_type>(colm(Q,r));
                }
            }

            unsigned long count = 0;

            // now perform the actual optimization of alpha
            long i=0, j=0;
            while (find_working_group(y,alpha,Q,df,tau,eps,i,j))
            {
                ++count;
                const scalar_type old_alpha_i = alpha(i);
                const scalar_type old_alpha_j = alpha(j);

                optimize_working_pair(alpha,Q,df,tau,i,j);

                // update the df vector now that we have modified alpha(i) and alpha(j)
                scalar_type delta_alpha_i = alpha(i) - old_alpha_i;
                scalar_type delta_alpha_j = alpha(j) - old_alpha_j;

                col_type Q_i = colm(Q,i);
                col_type Q_j = colm(Q,j);
                for(long k = 0; k < df.nr(); ++k)
                    df(k) += Q_i(k)*delta_alpha_i + Q_j(k)*delta_alpha_j;
            }

            return count;
        }

        const column_matrix& get_gradient (
        ) const { return df; }

    private:

    // -------------------------------------------------------------------------------------

        template <
            typename scalar_type,
            typename scalar_vector_type,
            typename scalar_vector_type2
            >
        inline void set_initial_alpha (
            const scalar_vector_type& y,
            const scalar_type nu,
            scalar_vector_type2& alpha
        ) const
        {
            set_all_elements(alpha,0);
            const scalar_type l = y.nr();
            scalar_type temp = nu*l/2;
            long num = (long)std::floor(temp);
            long num_total = (long)std::ceil(temp);

            bool has_slack = false;
            int count = 0;
            for (int i = 0; i < alpha.nr(); ++i)
            {
                if (y(i) == 1)
                {
                    if (count < num)
                    {
                        ++count;
                        alpha(i) = 1;
                    }
                    else
                    {
                        has_slack = true;
                        if (num_total > num)
                        {
                            ++count;
                            alpha(i) = temp - std::floor(temp);
                        }
                        break;
                    }
                }
            }

            if (count != num_total || has_slack == false)
            {
                std::ostringstream sout;
                sout << "Invalid nu of " << nu << ".  It is required that: 0 < nu < " << 2*(scalar_type)count/y.nr();
                throw invalid_nu_error(sout.str(),nu);
            }

            has_slack = false;
            count = 0;
            for (int i = 0; i < alpha.nr(); ++i)
            {
                if (y(i) == -1)
                {
                    if (count < num)
                    {
                        ++count;
                        alpha(i) = 1;
                    }
                    else
                    {
                        has_slack = true;
                        if (num_total > num)
                        {
                            ++count;
                            alpha(i) = temp - std::floor(temp);
                        }
                        break;
                    }
                }
            }

            if (count != num_total || has_slack == false)
            {
                std::ostringstream sout;
                sout << "Invalid nu of " << nu << ".  It is required that: 0 < nu < " << 2*(scalar_type)count/y.nr();
                throw invalid_nu_error(sout.str(),nu);
            }
        }

    // ------------------------------------------------------------------------------------

        template <
            typename scalar_vector_type,
            typename scalar_type,
            typename EXP,
            typename U, typename V
            >
        inline bool find_working_group (
            const V& y,
            const U& alpha,
            const matrix_exp<EXP>& Q,
            const scalar_vector_type& df,
            const scalar_type tau,
            const scalar_type eps,
            long& i_out,
            long& j_out
        ) const
        {
            using namespace std;
            long ip = 0;
            long jp = 0;
            long in = 0;
            long jn = 0;

            typedef typename colm_exp<EXP>::type col_type;
            typedef typename diag_exp<EXP>::type diag_type;

            scalar_type ip_val = -numeric_limits<scalar_type>::infinity();
            scalar_type jp_val = numeric_limits<scalar_type>::infinity();
            scalar_type in_val = -numeric_limits<scalar_type>::infinity();
            scalar_type jn_val = numeric_limits<scalar_type>::infinity();

            // loop over the alphas and find the maximum ip and in indices.
            for (long i = 0; i < alpha.nr(); ++i)
            {
                if (y(i) == 1)
                {
                    if (alpha(i) < 1.0)
                    {
                        if (-df(i) > ip_val)
                        {
                            ip_val = -df(i);
                            ip = i;
                        }
                    }
                }
                else
                {
                    if (alpha(i) > 0.0)
                    {
                        if (df(i) > in_val)
                        {
                            in_val = df(i);
                            in = i;
                        }
                    }
                }
            }

            scalar_type Mp = numeric_limits<scalar_type>::infinity();
            scalar_type Mn = numeric_limits<scalar_type>::infinity();

            // Pick out the columns and diagonal of Q we need below.  Doing
            // it this way is faster if Q is actually a symmetric_matrix_cache
            // object.
            col_type Q_ip = colm(Q,ip);
            col_type Q_in = colm(Q,in);
            diag_type Q_diag = diag(Q);

            // now we need to find the minimum jp and jn indices
            for (long j = 0; j < alpha.nr(); ++j)
            {
                if (y(j) == 1)
                {
                    if (alpha(j) > 0.0)
                    {
                        scalar_type b = ip_val + df(j);
                        if (-df(j) < Mp)
                            Mp = -df(j);

                        if (b > 0)
                        {
                            scalar_type a = Q_ip(ip) + Q_diag(j) - 2*Q_ip(j);
                            if (a <= 0)
                                a = tau;
                            scalar_type temp = -b*b/a;
                            if (temp < jp_val)
                            {
                                jp_val = temp;
                                jp = j;
                            }
                        }
                    }
                }
                else
                {
                    if (alpha(j) < 1.0)
                    {
                        scalar_type b = in_val - df(j);
                        if (df(j) < Mn)
                            Mn = df(j);

                        if (b > 0)
                        {
                            scalar_type a = Q_in(in) + Q_diag(j) - 2*Q_in(j);
                            if (a <= 0)
                                a = tau;
                            scalar_type temp = -b*b/a;
                            if (temp < jn_val)
                            {
                                jn_val = temp;
                                jn = j;
                            }
                        }
                    }
                }
            }

            // if we are at the optimal point then return false so the caller knows
            // to stop optimizing
            if (std::max(ip_val - Mp, in_val - Mn) < eps)
                return false;

            if (jp_val < jn_val)
            {
                i_out = ip;
                j_out = jp;
            }
            else
            {
                i_out = in;
                j_out = jn;
            }

            return true;
        }

    // ------------------------------------------------------------------------------------

        template <
            typename EXP,
            typename T, typename U
            >
        inline void optimize_working_pair (
            T& alpha,
            const matrix_exp<EXP>& Q,
            const U& df,
            const scalar_type tau,
            const long i,
            const long j
        ) const
        {
            scalar_type quad_coef = Q(i,i)+Q(j,j)-2*Q(j,i);
            if (quad_coef <= 0)
                quad_coef = tau;
            scalar_type delta = (df(i)-df(j))/quad_coef;
            scalar_type sum = alpha(i) + alpha(j);
            alpha(i) -= delta;
            alpha(j) += delta;

            if(sum > 1)
            {
                if(alpha(i) > 1)
                {
                    alpha(i) = 1;
                    alpha(j) = sum - 1;
                }
                else if(alpha(j) > 1)
                {
                    alpha(j) = 1;
                    alpha(i) = sum - 1;
                }
            }
            else
            {
                if(alpha(j) < 0)
                {
                    alpha(j) = 0;
                    alpha(i) = sum;
                }
                else if(alpha(i) < 0)
                {
                    alpha(i) = 0;
                    alpha(j) = sum;
                }
            }
        }

    // ------------------------------------------------------------------------------------

        column_matrix df; // gradient of f(alpha)
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SOLVE_QP2_USING_SMo_Hh_


dlib C++ Library - optimization_solve_qp3_using_smo.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SOLVE_QP3_USING_SMo_Hh_
#define DLIB_SOLVE_QP3_USING_SMo_Hh_

#include "optimization_solve_qp3_using_smo_abstract.h"
#include <cmath>
#include <limits>
#include <sstream>
#include "../matrix.h"
#include "../algs.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class invalid_qp3_error : public dlib::error
    {

    public:
        invalid_qp3_error(
            const std::string& msg,
            double B_,
            double Cp_,
            double Cn_
        ) :
            dlib::error(msg),
            B(B_),
            Cp(Cp_),
            Cn(Cn_)
        {};

        const double B;
        const double Cp;
        const double Cn;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_type
        >
    class solve_qp3_using_smo
    {
    public:
        typedef typename matrix_type::mem_manager_type mem_manager_type;
        typedef typename matrix_type::type scalar_type;
        typedef typename matrix_type::layout_type layout_type;
        typedef matrix<scalar_type,0,0,mem_manager_type,layout_type> general_matrix;
        typedef matrix<scalar_type,0,1,mem_manager_type,layout_type> column_matrix;

        template <
            typename EXP1,
            typename EXP2,
            typename EXP3,
            long NR
            >
        unsigned long operator() (
            const matrix_exp<EXP1>& Q,
            const matrix_exp<EXP2>& p,
            const matrix_exp<EXP3>& y,
            const scalar_type B,
            const scalar_type Cp,
            const scalar_type Cn,
            matrix<scalar_type,NR,1,mem_manager_type, layout_type>& alpha,
            scalar_type eps
        )
        {
            DLIB_ASSERT(Q.nr() == Q.nc() && y.size() == Q.nr() && p.size() == y.size() &&
                        y.size() > 0 && is_col_vector(y) && is_col_vector(p) &&
                        sum((y == +1) + (y == -1)) == y.size() &&
                        Cp > 0 && Cn > 0 &&
                        eps > 0,
                "\t void solve_qp3_using_smo::operator()"
                << "\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(p):           " << is_col_vector(p)
                << "\n\t p.size():                   " << p.size()
                << "\n\t is_col_vector(y):           " << is_col_vector(y)
                << "\n\t y.size():                   " << y.size()
                << "\n\t sum((y == +1) + (y == -1)): " << sum((y == +1) + (y == -1))
                << "\n\t Cp:                         " << Cp
                << "\n\t Cn:                         " << Cn
                << "\n\t eps:                        " << eps
                );

            set_initial_alpha(y, B, Cp, Cn, alpha);

            const scalar_type tau = 1e-12;

            typedef typename colm_exp<EXP1>::type col_type;

            // initialize df.  Compute df = Q*alpha + p
            df = p;
            for (long r = 0; r < df.nr(); ++r)
            {
                if (alpha(r) != 0)
                {
                    df += alpha(r)*matrix_cast<scalar_type>(colm(Q,r));
                }
            }

            unsigned long count = 0;
            // now perform the actual optimization of alpha
            long i=0, j=0;
            while (find_working_group(y,alpha,Q,df,Cp,Cn,tau,eps,i,j))
            {
                ++count;
                const scalar_type old_alpha_i = alpha(i);
                const scalar_type old_alpha_j = alpha(j);

                optimize_working_pair(alpha,Q,y,df,tau,i,j, Cp, Cn );

                // update the df vector now that we have modified alpha(i) and alpha(j)
                scalar_type delta_alpha_i = alpha(i) - old_alpha_i;
                scalar_type delta_alpha_j = alpha(j) - old_alpha_j;

                col_type Q_i = colm(Q,i);
                col_type Q_j = colm(Q,j);
                for(long k = 0; k < df.nr(); ++k)
                    df(k) += Q_i(k)*delta_alpha_i + Q_j(k)*delta_alpha_j;
            }

            return count;
        }

        const column_matrix& get_gradient (
        ) const { return df; }

    private:

    // -------------------------------------------------------------------------------------

        template <
            typename scalar_type,
            typename scalar_vector_type,
            typename scalar_vector_type2
            >
        inline void set_initial_alpha (
            const scalar_vector_type& y,
            const scalar_type B,
            const scalar_type Cp,
            const scalar_type Cn,
            scalar_vector_type2& alpha
        ) const
        {
            alpha.set_size(y.size());

            set_all_elements(alpha,0);

            // It's easy in the B == 0 case
            if (B == 0)
                return;

            const scalar_type C = (B > 0)?  Cp : Cn;

            scalar_type temp = std::abs(B)/C;
            long num = (long)std::floor(temp);
            long num_total = (long)std::ceil(temp);

            const scalar_type B_sign = (B > 0)? 1 : -1;

            long count = 0;
            for (long i = 0; i < alpha.nr(); ++i)
            {
                if (y(i) == B_sign)
                {
                    if (count < num)
                    {
                        ++count;
                        alpha(i) = C;
                    }
                    else
                    {
                        if (count < num_total)
                        {
                            ++count;
                            alpha(i) = C*(temp - std::floor(temp));
                        }
                        break;
                    }
                }
            }

            if (count != num_total)
            {
                std::ostringstream sout;
                sout << "Invalid QP3 constraint parameters of B: " << B << ", Cp: " << Cp << ", Cn: "<< Cn;
                throw invalid_qp3_error(sout.str(),B,Cp,Cn);
            }
        }

    // ------------------------------------------------------------------------------------

        template <
            typename scalar_vector_type,
            typename scalar_type,
            typename EXP,
            typename U, typename V
            >
        inline bool find_working_group (
            const V& y,
            const U& alpha,
            const matrix_exp<EXP>& Q,
            const scalar_vector_type& df,
            const scalar_type Cp,
            const scalar_type Cn,
            const scalar_type tau,
            const scalar_type eps,
            long& i_out,
            long& j_out
        ) const
        {
            using namespace std;

            long ip = 0;
            long jp = 0;

            typedef typename colm_exp<EXP>::type col_type;
            typedef typename diag_exp<EXP>::type diag_type;

            scalar_type ip_val = -numeric_limits<scalar_type>::infinity();
            scalar_type jp_val = numeric_limits<scalar_type>::infinity();

            // loop over the alphas and find the maximum ip and in indices.
            for (long i = 0; i < alpha.nr(); ++i)
            {
                if (y(i) == 1)
                {
                    if (alpha(i) < Cp)
                    {
                        if (-df(i) > ip_val)
                        {
                            ip_val = -df(i);
                            ip = i;
                        }
                    }
                }
                else
                {
                    if (alpha(i) > 0.0)
                    {
                        if (df(i) > ip_val)
                        {
                            ip_val = df(i);
                            ip = i;
                        }
                    }
                }
            }

            scalar_type Mp = -numeric_limits<scalar_type>::infinity();

            // Pick out the column and diagonal of Q we need below.  Doing
            // it this way is faster if Q is actually a symmetric_matrix_cache
            // object.
            col_type Q_ip = colm(Q,ip);
            diag_type Q_diag = diag(Q);

            // now we need to find the minimum jp indices
            for (long j = 0; j < alpha.nr(); ++j)
            {
                if (y(j) == 1)
                {
                    if (alpha(j) > 0.0)
                    {
                        scalar_type b = ip_val + df(j);
                        if (df(j) > Mp)
                            Mp = df(j);

                        if (b > 0)
                        {
                            scalar_type a = Q_ip(ip) + Q_diag(j) - 2*y(ip)*Q_ip(j);
                            if (a <= 0)
                                a = tau;
                            scalar_type temp = -b*b/a;
                            if (temp < jp_val)
                            {
                                jp_val = temp;
                                jp = j;
                            }
                        }
                    }
                }
                else
                {
                    if (alpha(j) < Cn)
                    {
                        scalar_type b = ip_val - df(j);
                        if (-df(j) > Mp)
                            Mp = -df(j);

                        if (b > 0)
                        {
                            scalar_type a = Q_ip(ip) + Q_diag(j) + 2*y(ip)*Q_ip(j);
                            if (a <= 0)
                                a = tau;
                            scalar_type temp = -b*b/a;
                            if (temp < jp_val)
                            {
                                jp_val = temp;
                                jp = j;
                            }
                        }
                    }
                }
            }

            // if we are at the optimal point then return false so the caller knows
            // to stop optimizing
            if (Mp + ip_val < eps)
                return false;

            i_out = ip;
            j_out = jp;

            return true;
        }

    // ------------------------------------------------------------------------------------

        template <
            typename EXP,
            typename EXP2,
            typename T, typename U
            >
        inline void optimize_working_pair (
            T& alpha,
            const matrix_exp<EXP>& Q,
            const matrix_exp<EXP2>& y,
            const U& df,
            const scalar_type& tau,
            const long i,
            const long j,
            const scalar_type& Cp,
            const scalar_type& Cn
        ) const
        {
            const scalar_type Ci = (y(i) > 0 )? Cp : Cn;
            const scalar_type Cj = (y(j) > 0 )? Cp : Cn;

            if (y(i) != y(j))
            {
                scalar_type quad_coef = Q(i,i)+Q(j,j)+2*Q(j,i);
                if (quad_coef <= 0)
                    quad_coef = tau;
                scalar_type delta = (-df(i)-df(j))/quad_coef;
                scalar_type diff = alpha(i) - alpha(j);
                alpha(i) += delta;
                alpha(j) += delta;

                if (diff > 0)
                {
                    if (alpha(j) < 0)
                    {
                        alpha(j) = 0;
                        alpha(i) = diff;
                    }
                }
                else
                {
                    if (alpha(i) < 0)
                    {
                        alpha(i) = 0;
                        alpha(j) = -diff;
                    }
                }

                if (diff > Ci - Cj)
                {
                    if (alpha(i) > Ci)
                    {
                        alpha(i) = Ci;
                        alpha(j) = Ci - diff;
                    }
                }
                else
                {
                    if (alpha(j) > Cj)
                    {
                        alpha(j) = Cj;
                        alpha(i) = Cj + diff;
                    }
                }
            }
            else
            {
                scalar_type quad_coef = Q(i,i)+Q(j,j)-2*Q(j,i);
                if (quad_coef <= 0)
                    quad_coef = tau;
                scalar_type delta = (df(i)-df(j))/quad_coef;
                scalar_type sum = alpha(i) + alpha(j);
                alpha(i) -= delta;
                alpha(j) += delta;

                if(sum > Ci)
                {
                    if(alpha(i) > Ci)
                    {
                        alpha(i) = Ci;
                        alpha(j) = sum - Ci;
                    }
                }
                else
                {
                    if(alpha(j) < 0)
                    {
                        alpha(j) = 0;
                        alpha(i) = sum;
                    }
                }

                if(sum > Cj)
                {
                    if(alpha(j) > Cj)
                    {
                        alpha(j) = Cj;
                        alpha(i) = sum - Cj;
                    }
                }
                else
                {
                    if(alpha(i) < 0)
                    {
                        alpha(i) = 0;
                        alpha(j) = sum;
                    }
                }

            }
        }

    // ------------------------------------------------------------------------------------

        column_matrix df; // gradient of f(alpha)
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SOLVE_QP3_USING_SMo_Hh_


dlib C++ Library - optimization_solve_qp_using_smo.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_OPTIMIZATION_SOLVE_QP_UsING_SMO_Hh_
#define DLIB_OPTIMIZATION_SOLVE_QP_UsING_SMO_Hh_

#include "optimization_solve_qp_using_smo_abstract.h"
#include "../matrix.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    /*
        The algorithm defined in the solve_qp_using_smo() function below can be
        derived by using an important theorem from the theory of constrained optimization.
        This theorem tells us that any optimal point of a constrained function must
        satisfy what are called the KKT conditions (also sometimes called just the KT
        conditions, especially in older literature).  A very good book to consult
        regarding this topic is Practical Methods of Optimization (second edition) by
        R. Fletcher.  Below I will try to explain the general idea of how this is
        applied.

        Let e == ones_matrix(alpha.size(),1)

        First, note that the function below solves the following quadratic program.
            Minimize: f(alpha) == 0.5*trans(alpha)*Q*alpha - trans(alpha)*b
            subject to the following constraints:
                - trans(e)*alpha == C (i.e. the sum of alpha values doesn't change)
                - min(alpha) >= 0 (i.e. all alpha values are nonnegative)
            Where f is convex.  This means that Q should be positive-semidefinite.

        To get from this problem formulation to the algorithm below we have to
        consider the KKT conditions.  They tell us that any solution to the above
        problem must satisfy the following 5 conditions:
            1. trans(e)*alpha == C
            2. min(alpha) >= 0

            3. Let L(alpha, x, y) == f(alpha) - trans(x)*alpha - y*(trans(e)*alpha - C)
               Where x is a vector of length alpha.size() and y is a single scalar.
               Then the derivative of L with respect to alpha must == 0
               So we get the following as our 3rd condition:
               f'(alpha) - x - y*e == 0

            4. min(x) >= 0 (i.e. all x values are nonnegative)
            5. pointwise_multiply(x, alpha) == 0
               (i.e. only one member of each x(i) and alpha(i) pair can be non-zero)

        From 3 we can easily obtain this rule:
            for all i: f'(alpha)(i) - x(i) == y

        If we then consider 4 and 5 we see that we can infer that the following
        must also be the case:
            - if (alpha(i) > 0) then
                - x(i) == 0
                - f'(alpha)(i) == y
            - else
                - x(i) == some nonnegative number
                - f'(alpha)(i) >= y

        The important thing to take away is the final rule.  It tells us that at the
        optimal solution all elements of the gradient of f have the same value if
        their corresponding alpha is non-zero.  It also tells us that all the other
        gradient values are bigger than y.  We can use this information to help us
        pick which alpha variables to optimize at each iteration.
    */

// ----------------------------------------------------------------------------------------

    template <
        typename EXP1,
        typename EXP2,
        typename T, long NR, long NC, typename MM, typename L
        >
    unsigned long solve_qp_using_smo (
        const matrix_exp<EXP1>& Q,
        const matrix_exp<EXP2>& b,
        matrix<T,NR,NC,MM,L>& alpha,
        T eps,
        unsigned long max_iter
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(Q.nr() == Q.nc() &&
                     is_col_vector(b) &&
                     is_col_vector(alpha) &&
                     b.size() == alpha.size() &&
                     b.size() == Q.nr() &&
                     alpha.size() > 0 &&
                     min(alpha) >= 0 &&
                     eps > 0 &&
                     max_iter > 0,
                     "\t unsigned long solve_qp_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 b.size():             " << b.size()
                     << "\n\t alpha.size():         " << alpha.size()
                     << "\n\t Q.nr():               " << Q.nr()
                     << "\n\t min(alpha):           " << min(alpha)
                     << "\n\t eps:                  " << eps
                     << "\n\t max_iter:             " << max_iter
        );

        const T C = sum(alpha);

        // Compute f'(alpha) (i.e. the gradient of f(alpha)) for the current alpha.
        matrix<T,NR,NC,MM,L> df = Q*alpha - b;

        const T tau = 1000*std::numeric_limits<T>::epsilon();

        T big, little;
        unsigned long iter = 0;
        for (; iter < max_iter; ++iter)
        {
            // Find the two elements of df that satisfy the following:
            //    - little_idx == index_of_min(df)
            //    - big_idx   == the index of the largest element in df such that alpha(big_idx) > 0
            // These two indices will tell us which two alpha values are most in violation of the KKT
            // optimality conditions.
            big = -std::numeric_limits<T>::max();
            long big_idx = 0;
            little = std::numeric_limits<T>::max();
            long little_idx = 0;
            for (long i = 0; i < df.nr(); ++i)
            {
                if (df(i) > big && alpha(i) > 0)
                {
                    big = df(i);
                    big_idx = i;
                }
                if (df(i) < little)
                {
                    little = df(i);
                    little_idx = i;
                }
            }

            // Check if the KKT conditions are still violated and stop if so.
            //if (alpha(little_idx) > 0 && (big - little) < eps)
            //    break;

            // Check how big the duality gap is and stop when it goes below eps.
            // The duality gap is the gap between the objective value of the function
            // we are optimizing and the value of its primal form.  This value is always
            // greater than or equal to the distance to the optimum solution so it is a
            // good way to decide if we should stop.   See the book referenced above for
            // more information.  In particular, see the part about the Wolfe Dual.
            if (trans(alpha)*df - C*little < eps)
                break;

            // Save these values, we will need them later.
            const T old_alpha_big = alpha(big_idx);
            const T old_alpha_little = alpha(little_idx);

            // Now optimize the two variables we just picked.
            T quad_coef = Q(big_idx,big_idx) + Q(little_idx,little_idx) - 2*Q(big_idx, little_idx);
            if (quad_coef <= tau)
                quad_coef = tau;
            const T delta = (big - little)/quad_coef;
            alpha(big_idx) -= delta;
            alpha(little_idx) += delta;

            // Make sure alpha stays feasible.  That is, make sure the updated alpha doesn't
            // violate the non-negativity constraint.
            if (alpha(big_idx) < 0)
            {
                // Since an alpha can't be negative we will just set it to 0 and shift all the
                // weight to the other alpha.
                alpha(big_idx) = 0;
                alpha(little_idx) = old_alpha_big + old_alpha_little;
            }

            // Every 300 iterations
            if ((iter%300) == 299)
            {
                // Perform this form of the update every so often because doing so can help
                // avoid the buildup of numerical errors you get with the alternate update
                // below.
                df = Q*alpha - b;
            }
            else
            {
                // Now update the gradient. We will perform the equivalent of: df = Q*alpha - b;
                const T delta_alpha_big   = alpha(big_idx) - old_alpha_big;
                const T delta_alpha_little = alpha(little_idx) - old_alpha_little;

                for(long k = 0; k < df.nr(); ++k)
                    df(k) += Q(big_idx,k)*delta_alpha_big + Q(little_idx,k)*delta_alpha_little;;
            }
        }

        /*
        using namespace std;
        cout << "SMO: " << endl;
        cout << "   duality gap: "<< trans(alpha)*df - C*min(df) << endl;
        cout << "   KKT gap:     "<< big-little << endl;
        cout << "   iter:        "<< iter+1 << endl;
        cout << "   eps:         "<< eps << endl;
        */

        return iter+1;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP1,
        typename EXP2,
        typename EXP3,
        typename T, long NR, long NC, typename MM, typename L
        >
    unsigned long solve_qp4_using_smo (
        const matrix_exp<EXP1>& A,
        const matrix_exp<EXP2>& Q,
        const matrix_exp<EXP3>& b,
        matrix<T,NR,NC,MM,L>& alpha,
        T eps,
        unsigned long max_iter
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(A.nc() == alpha.size() &&
                     Q.nr() == Q.nc() &&
                     is_col_vector(b) &&
                     is_col_vector(alpha) &&
                     b.size() == alpha.size() &&
                     b.size() == Q.nr() &&
                     alpha.size() > 0 &&
                     min(alpha) >= 0 &&
                     eps > 0 &&
                     max_iter > 0,
                     "\t void solve_qp4_using_smo()"
                     << "\n\t Invalid arguments were given to this function"
                     << "\n\t A.nc():               " << A.nc()
                     << "\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 b.size():             " << b.size()
                     << "\n\t alpha.size():         " << alpha.size()
                     << "\n\t Q.nr():               " << Q.nr()
                     << "\n\t min(alpha):           " << min(alpha)
                     << "\n\t eps:                  " << eps
                     << "\n\t max_iter:             " << max_iter
        );

        const T C = sum(alpha);

        /*
            For this optimization problem, it is the case that the optimal
            value of lambda is given by a simple closed form expression if we
            know the optimal alpha.  So what we will do is to just optimize
            alpha and every now and then we will update lambda with its optimal
            value.  Therefore, we use essentially the same method as the
            solve_qp_using_smo() routine.
        */

        // compute optimal lambda for current alpha
        matrix<T,NR,1,MM,L> lambda = A*alpha;
        lambda = lowerbound(lambda, 0);

        // Compute f'(alpha) (i.e. the gradient of f(alpha) with respect to alpha) for the current alpha.
        matrix<T,NR,NC,MM,L> df = Q*alpha - b - trans(A)*lambda;

        const T tau = 1000*std::numeric_limits<T>::epsilon();

        T big, little;
        unsigned long iter = 0;
        for (; iter < max_iter; ++iter)
        {
            // Find the two elements of df that satisfy the following:
            //    - little_idx == index_of_min(df)
            //    - big_idx   == the index of the largest element in df such that alpha(big_idx) > 0
            // These two indices will tell us which two alpha values are most in violation of the KKT
            // optimality conditions.
            big = -std::numeric_limits<T>::max();
            long big_idx = 0;
            little = std::numeric_limits<T>::max();
            long little_idx = 0;
            for (long i = 0; i < df.nr(); ++i)
            {
                if (df(i) > big && alpha(i) > 0)
                {
                    big = df(i);
                    big_idx = i;
                }
                if (df(i) < little)
                {
                    little = df(i);
                    little_idx = i;
                }
            }

            // Check how big the duality gap is and stop when it goes below eps.
            // The duality gap is the gap between the objective value of the function
            // we are optimizing and the value of its primal form.  This value is always
            // greater than or equal to the distance to the optimum solution so it is a
            // good way to decide if we should stop.
            if (trans(alpha)*df - C*little < eps)
            {
                // compute optimal lambda and recheck the duality gap to make
                // sure we have really converged.
                lambda = A*alpha;
                lambda = lowerbound(lambda, 0);
                df = Q*alpha - b - trans(A)*lambda;

                if (trans(alpha)*df - C*min(df) < eps)
                    break;
                else
                    continue;
            }

            // Save these values, we will need them later.
            const T old_alpha_big = alpha(big_idx);
            const T old_alpha_little = alpha(little_idx);

            // Now optimize the two variables we just picked.
            T quad_coef = Q(big_idx,big_idx) + Q(little_idx,little_idx) - 2*Q(big_idx, little_idx);
            if (quad_coef <= tau)
                quad_coef = tau;
            const T delta = (big - little)/quad_coef;
            alpha(big_idx) -= delta;
            alpha(little_idx) += delta;

            // Make sure alpha stays feasible.  That is, make sure the updated alpha doesn't
            // violate the non-negativity constraint.
            if (alpha(big_idx) < 0)
            {
                // Since an alpha can't be negative we will just set it to 0 and shift all the
                // weight to the other alpha.
                alpha(big_idx) = 0;
                alpha(little_idx) = old_alpha_big + old_alpha_little;
            }

            // Every 300 iterations
            if ((iter%300) == 299)
            {
                // compute the optimal lambda for the current alpha
                lambda = A*alpha;
                lambda = lowerbound(lambda, 0);

                // Perform this form of the update every so often because doing so can help
                // avoid the buildup of numerical errors you get with the alternate update
                // below.
                df = Q*alpha - b - trans(A)*lambda;
            }
            else
            {
                // Now update the gradient. We will perform the equivalent of: df = Q*alpha - b;
                const T delta_alpha_big   = alpha(big_idx) - old_alpha_big;
                const T delta_alpha_little = alpha(little_idx) - old_alpha_little;

                for(long k = 0; k < df.nr(); ++k)
                    df(k) += Q(big_idx,k)*delta_alpha_big + Q(little_idx,k)*delta_alpha_little;;
            }
        }

        /*
        using namespace std;
        cout << "SMO: " << endl;
        cout << "   duality gap: "<< trans(alpha)*df - C*min(df) << endl;
        cout << "   KKT gap:     "<< big-little << endl;
        cout << "   iter:        "<< iter+1 << endl;
        cout << "   eps:         "<< eps << endl;
        */

        return iter+1;
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_OPTIMIZATION_SOLVE_QP_UsING_SMO_Hh_


dlib C++ Library - optimization_stop_strategies.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_OPTIMIZATIOn_STOP_STRATEGIES_H_
#define DLIB_OPTIMIZATIOn_STOP_STRATEGIES_H_

#include <cmath>
#include <limits>
#include "../matrix.h"
#include "../algs.h"
#include "optimization_stop_strategies_abstract.h"
#include <iostream>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class objective_delta_stop_strategy
    {
    public:
        explicit objective_delta_stop_strategy (
            double min_delta = 1e-7
        ) : _verbose(false), _been_used(false), _min_delta(min_delta), _max_iter(0), _cur_iter(0), _prev_funct_value(0)
        {
            DLIB_ASSERT (
                min_delta >= 0,
                "\t objective_delta_stop_strategy(min_delta)"
                << "\n\t min_delta can't be negative"
                << "\n\t min_delta: " << min_delta
            );
        }

        objective_delta_stop_strategy (
            double min_delta,
            unsigned long max_iter
        ) : _verbose(false), _been_used(false), _min_delta(min_delta), _max_iter(max_iter), _cur_iter(0), _prev_funct_value(0)
        {
            DLIB_ASSERT (
                min_delta >= 0 && max_iter > 0,
                "\t objective_delta_stop_strategy(min_delta, max_iter)"
                << "\n\t min_delta can't be negative and max_iter can't be 0"
                << "\n\t min_delta: " << min_delta
                << "\n\t max_iter:  " << max_iter
            );
        }

        objective_delta_stop_strategy& be_verbose(
        )
        {
            _verbose = true;
            return *this;
        }

        template <typename T>
        bool should_continue_search (
            const T& ,
            const double funct_value,
            const T&
        )
        {
            if (_verbose)
            {
                using namespace std;
                cout << "iteration: " << _cur_iter << "   objective: " << funct_value << endl;
            }

            ++_cur_iter;
            if (_been_used)
            {
                // Check if we have hit the max allowable number of iterations.  (but only
                // check if _max_iter is enabled (i.e. not 0)).
                if (_max_iter != 0 && _cur_iter > _max_iter)
                    return false;

                // check if the function change was too small
                if (std::abs(funct_value - _prev_funct_value) < _min_delta)
                    return false;
            }

            _been_used = true;
            _prev_funct_value = funct_value;
            return true;
        }

    private:
        bool _verbose;

        bool _been_used;
        double _min_delta;
        unsigned long _max_iter;
        unsigned long _cur_iter;
        double _prev_funct_value;
    };

// ----------------------------------------------------------------------------------------

    class gradient_norm_stop_strategy
    {
    public:
        explicit gradient_norm_stop_strategy (
            double min_norm = 1e-7
        ) : _verbose(false), _min_norm(min_norm), _max_iter(0), _cur_iter(0)
        {
            DLIB_ASSERT (
                min_norm >= 0,
                "\t gradient_norm_stop_strategy(min_norm)"
                << "\n\t min_norm can't be negative"
                << "\n\t min_norm: " << min_norm
            );
        }

        gradient_norm_stop_strategy (
            double min_norm,
            unsigned long max_iter
        ) : _verbose(false), _min_norm(min_norm), _max_iter(max_iter), _cur_iter(0)
        {
            DLIB_ASSERT (
                min_norm >= 0 && max_iter > 0,
                "\t gradient_norm_stop_strategy(min_norm, max_iter)"
                << "\n\t min_norm can't be negative and max_iter can't be 0"
                << "\n\t min_norm: " << min_norm
                << "\n\t max_iter:  " << max_iter
            );
        }

        gradient_norm_stop_strategy& be_verbose(
        )
        {
            _verbose = true;
            return *this;
        }

        template <typename T>
        bool should_continue_search (
            const T& ,
            const double funct_value,
            const T& funct_derivative
        )
        {
            if (_verbose)
            {
                using namespace std;
                cout << "iteration: " << _cur_iter << "   objective: " << funct_value << "   gradient norm: " << length(funct_derivative) << endl;
            }

            ++_cur_iter;

            // Check if we have hit the max allowable number of iterations.  (but only
            // check if _max_iter is enabled (i.e. not 0)).
            if (_max_iter != 0 && _cur_iter > _max_iter)
                return false;

            // check if the gradient norm is too small
            if (length(funct_derivative) < _min_norm)
                return false;

            return true;
        }

    private:
        bool _verbose;

        double _min_norm;
        unsigned long _max_iter;
        unsigned long _cur_iter;
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_OPTIMIZATIOn_STOP_STRATEGIES_H_


dlib C++ Library - optimization_trust_region.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_OPTIMIZATION_TRUST_REGIoN_Hh_
#define DLIB_OPTIMIZATION_TRUST_REGIoN_Hh_

#include "../matrix.h"
#include "optimization_trust_region_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename EXP1,
        typename EXP2,
        typename T, long NR, long NC, typename MM, typename L
        >
    unsigned long solve_trust_region_subproblem (
        const matrix_exp<EXP1>& B,
        const matrix_exp<EXP2>& g,
        const typename EXP1::type radius,
        matrix<T,NR,NC,MM,L>& p,
        double eps,
        unsigned long max_iter
    )
    {
        /*
            This is an implementation of algorithm 4.3(Trust Region Subproblem)
            from the book Numerical Optimization by Nocedal and Wright.  Some of
            the details are also from Practical Methods of Optimization by Fletcher.
        */

        // make sure requires clause is not broken
        DLIB_ASSERT(B.nr() == B.nc() && is_col_vector(g) && g.size() == B.nr(),
            "\t unsigned long solve_trust_region_subproblem()"
            << "\n\t invalid arguments were given to this function"
            << "\n\t B.nr():            " << B.nr()
            << "\n\t B.nc():            " << B.nc()
            << "\n\t is_col_vector(g):  " << is_col_vector(g)
            << "\n\t g.size():          " << g.size()
            );
        DLIB_ASSERT(radius > 0 && eps > 0 && max_iter > 0,
            "\t unsigned long solve_trust_region_subproblem()"
            << "\n\t invalid arguments were given to this function"
            << "\n\t radius:   " << radius
            << "\n\t eps:      " << eps
            << "\n\t max_iter: " << max_iter
            );

        const_temp_matrix<EXP1> BB(B);
        const_temp_matrix<EXP2> gg(g);

        p.set_size(g.nr(),g.nc());
        p = 0;

        const T numeric_eps = max(diag(abs(BB)))*std::numeric_limits<T>::epsilon();

        matrix<T,EXP1::NR,EXP2::NR,MM,L> R;

        T lambda = 0;

        // We need to put a bracket around lambda.  It can't go below 0.  We
        // can get an upper bound using Gershgorin disks.
        // This number is a lower bound on the eigenvalues in BB
        const T BB_min_eigenvalue = min(diag(BB) - (sum_cols(abs(BB)) - abs(diag(BB))));

        const T g_norm = length(gg);

        T lambda_min = 0;
        T lambda_max = put_in_range(0,
                                    std::numeric_limits<T>::max(),
                                    g_norm/radius - BB_min_eigenvalue);

        // If we can tell that the minimum is at 0 then don't do anything.  Just return the answer.
        if (g_norm < numeric_eps && BB_min_eigenvalue > numeric_eps)
        {
            return 0;
        }

        // how much lambda has changed recently
        T lambda_delta = 0;

        for (unsigned long i = 0; i < max_iter; ++i)
        {
            R = chol(BB + lambda*identity_matrix<T>(BB.nr()));

            // if the cholesky decomposition doesn't exist.
            if (R(R.nr()-1, R.nc()-1) <= 0)
            {
                // If B is indefinite and g is equal to 0 then we should
                // quit this loop and go right to the eigenvalue decomposition method.
                if (g_norm <= numeric_eps)
                    break;

                // narrow the bracket on lambda.  Obviously the current lambda is
                // too small.
                lambda_min = lambda;

                // jump towards the max value.  Eventually there will
                // be a lambda that results in a cholesky decomposition.
                const T alpha = 0.10;
                lambda = (1-alpha)*lambda + alpha*lambda_max;
                continue;
            }

            using namespace blas_bindings;

            p = -gg;
            // Solve RR'*p = -g for p.
            // Solve R*q = -g for q where q = R'*p.
            if (R.nr() == 2)
            {
                p(0) = p(0)/R(0,0);
                p(1) = (p(1)-R(1,0)*p(0))/R(1,1);
            }
            else
            {
                triangular_solver(CblasLeft, CblasLower, CblasNoTrans, CblasNonUnit, R, p);
            }
            const T q_norm = length(p);

            // Solve R'*p = q for p.
            if (R.nr() == 2)
            {
                p(1) = p(1)/R(1,1);
                p(0) = (p(0)-R(1,0)*p(1))/R(0,0);
            }
            else
            {
                triangular_solver(CblasLeft, CblasLower, CblasTrans, CblasNonUnit, R, p);
            }
            const T p_norm = length(p);

            // check if we are done.
            if (lambda == 0)
            {
                if (p_norm < radius)
                {
                    // i will always be 0 in this case.  So we return 1.
                    return i+1;
                }
            }
            else
            {
                // if we are close enough to the solution then terminate
                if (std::abs(p_norm - radius)/radius < eps)
                    return i+1;
            }

            // shrink our bracket on lambda
            if (p_norm < radius)
                lambda_max = lambda;
            else
                lambda_min = lambda;

            if (p_norm <= radius*std::numeric_limits<T>::epsilon())
            {
                const T alpha = 0.01;
                lambda = (1-alpha)*lambda_min + alpha*lambda_max;
                continue;
            }

            const T old_lambda = lambda;

            // figure out which lambda to try next
            lambda = lambda + std::pow(q_norm/p_norm,2)*(p_norm - radius)/radius;

            // make sure the chosen lambda is within our bracket (but not exactly at either end).
            const T gap = (lambda_max-lambda_min)*0.01;
            lambda = put_in_range(lambda_min+gap, lambda_max-gap, lambda);

            // Keep track of how much lambda is thrashing around inside the search bracket.  If it
            // keeps moving around a whole lot then cut the search bracket in half.
            lambda_delta += std::abs(lambda - old_lambda);
            if (lambda_delta > 3*(lambda_max-lambda_min))
            {
                lambda = (lambda_min+lambda_max)/2;
                lambda_delta = 0;
            }
        } // end for loop

        // We are probably in the "hard case".   Use an eigenvalue decomposition to sort things out.
        // Either that or the eps was just set too tight and really we are already done.
        eigenvalue_decomposition<EXP1> ed(make_symmetric(BB));

        matrix<T,NR,NC,MM,L> ev = ed.get_real_eigenvalues();
        const long min_eig_idx = index_of_min(ev);

        ev -= min(ev);
        // zero out any values which are basically zero
        ev = pointwise_multiply(ev, ev > max(abs(ev))*std::numeric_limits<T>::epsilon());
        ev = reciprocal(ev);

        // figure out part of what p should be assuming we are in the hard case.
        matrix<T,NR,NC,MM,L> p_hard;
        p_hard = trans(ed.get_pseudo_v())*gg;
        p_hard = diagm(ev)*p_hard;
        p_hard = ed.get_pseudo_v()*p_hard;

        // If we really are in the hard case then this if will be true.  Otherwise, the p
        // we found in the "easy case" loop up top is the best answer.
        if (length(p_hard) < radius && length(p_hard) >= length(p))
        {
            // adjust the length of p_hard by adding a component along the eigenvector associated with
            // the smallest eigenvalue.  We want to make it the case that length(p) == radius.
            const T tau = std::sqrt(radius*radius - length_squared(p_hard));
            p = p_hard + tau*colm(ed.get_pseudo_v(),min_eig_idx);

            // if we have to do an eigenvalue decomposition then say we did all the iterations
            return max_iter;
        }

        // if we get this far it means we didn't converge to eps accuracy.
        return max_iter+1;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename stop_strategy_type,
        typename funct_model
        >
    double find_min_trust_region (
        stop_strategy_type stop_strategy,
        const funct_model& model,
        typename funct_model::column_vector& x,
        double radius = 1
    )
    {
        /*
            This is an implementation of algorithm 4.1(Trust Region)
            from the book Numerical Optimization by Nocedal and Wright.
        */

        // make sure requires clause is not broken
        DLIB_ASSERT(is_col_vector(x) && radius > 0,
            "\t double find_min_trust_region()"
            << "\n\t invalid arguments were given to this function"
            << "\n\t is_col_vector(x): " << is_col_vector(x)
            << "\n\t radius:           " << radius
            );

        const double initial_radius = radius;

        typedef typename funct_model::column_vector T;
        typedef typename T::type type;

        typename funct_model::general_matrix h;
        typename funct_model::column_vector g, p, d;
        type f_value = model(x);

        model.get_derivative_and_hessian(x,g,h);

        DLIB_ASSERT(is_finite(x), "The objective function generated non-finite outputs");
        DLIB_ASSERT(is_finite(g), "The objective function generated non-finite outputs");
        DLIB_ASSERT(is_finite(h), "The objective function generated non-finite outputs");

        // Sometimes the loop below won't modify x because the trust region step failed.
        // This bool tells us when we are in that case.
        bool stale_x = false;

        while(stale_x || stop_strategy.should_continue_search(x, f_value, g))
        {
            const unsigned long iter = solve_trust_region_subproblem(h,
                                                                     g,
                                                                     radius,
                                                                     p,
                                                                     0.1,
                                                                     20);

            const type new_f_value = model(x+p);
            const type predicted_improvement = -0.5*trans(p)*h*p - trans(g)*p;
            const type measured_improvement = (f_value - new_f_value);

            // If the sub-problem can't find a way to improve then stop.  This only happens when p is essentially 0.
            if (std::abs(predicted_improvement) <= std::abs(measured_improvement)*std::numeric_limits<type>::epsilon())
                break;

            // predicted_improvement shouldn't be negative but it might be if something went
            // wrong in the trust region solver.  So put abs() here to guard against that.  This
            // way the sign of rho is determined only by the sign of measured_improvement.
            const type rho = measured_improvement/std::abs(predicted_improvement);

            if (rho < 0.25)
            {
                radius *= 0.25;

                // something has gone horribly wrong if the radius has shrunk to zero.  So just
                // give up if that happens.
                if (radius <= initial_radius*std::numeric_limits<double>::epsilon())
                    break;
            }
            else
            {
                // if rho > 0.75 and we are being checked by the radius
                if (rho > 0.75 && iter > 1)
                {
                    radius = std::min<type>(1000,  2*radius);
                }
            }

            if (rho > 0)
            {
                x = x + p;
                f_value = new_f_value;
                model.get_derivative_and_hessian(x,g,h);
                stale_x = false;
            }
            else
            {
                stale_x = true;
            }

            DLIB_ASSERT(is_finite(x), "The objective function generated non-finite outputs");
            DLIB_ASSERT(is_finite(g), "The objective function generated non-finite outputs");
            DLIB_ASSERT(is_finite(h), "The objective function generated non-finite outputs");
        }

        return f_value;
    }

// ----------------------------------------------------------------------------------------

    template <typename funct_model>
    struct negate_tr_model
    {
        negate_tr_model( const funct_model& m) : model(m) {}

        const funct_model& model;

        typedef typename funct_model::column_vector column_vector;
        typedef typename funct_model::general_matrix general_matrix;

        template <typename T>
        typename T::type operator() (const T& x) const
        {
            return -model(x);
        }

        template <typename T, typename U>
        void get_derivative_and_hessian (
            const T& x,
            T& d,
            U& h
        ) const
        {
            model.get_derivative_and_hessian(x,d,h);
            d = -d;
            h = -h;
        }

    };

// ----------------------------------------------------------------------------------------

    template <
        typename stop_strategy_type,
        typename funct_model
        >
    double find_max_trust_region (
        stop_strategy_type stop_strategy,
        const funct_model& model,
        typename funct_model::column_vector& x,
        double radius = 1
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(is_col_vector(x) && radius > 0,
            "\t double find_max_trust_region()"
            << "\n\t invalid arguments were given to this function"
            << "\n\t is_col_vector(x): " << is_col_vector(x)
            << "\n\t radius:           " << radius
            );

        return -find_min_trust_region(stop_strategy,
                                      negate_tr_model<funct_model>(model),
                                      x,
                                      radius);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_OPTIMIZATION_TRUST_REGIoN_Hh_


dlib C++ Library - queue_kernel_1.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_QUEUE_KERNEl_1_
#define DLIB_QUEUE_KERNEl_1_

#include "queue_kernel_abstract.h"
#include "../algs.h"
#include "../interfaces/enumerable.h"
#include "../interfaces/remover.h"
#include "../serialize.h"

namespace dlib
{

    template <
        typename T,
        typename mem_manager = default_memory_manager
        >
    class queue_kernel_1 : public enumerable<T>,
                           public remover<T>
    {

        /*!
            INITIAL VALUE
                queue_size == 0
                current_element == 0
                at_start_ == true

            CONVENTION
                queue_size == the number of elements in the queue
                at_start() == at_start_
                current_element_valid() == (current_element != 0)
                element() == current_element->item

                if (queue_size > 0)
                {
                    in points to the last element to be inserted into the queue
                    out points to the next element to be dequeued

                    each node points to the node inserted after it except for the most
                    recently inserted node

                    current_element == 0
                }

        !*/

        struct node
        {
            node* last;

            T item;
        };

        public:

            typedef T type;
            typedef mem_manager mem_manager_type;

            queue_kernel_1 (
            ) :
                in(0),
                out(0),
                queue_size(0),
                current_element(0),
                at_start_(true)
            {
            }

            virtual ~queue_kernel_1 (
            );

            inline void clear(
            );

            void enqueue (
                T& item
            );

            void dequeue (
                T& item
            );

            void cat (
                queue_kernel_1& item
            );

            T& current (
            );

            const T& current (
            ) const;

            void swap (
                queue_kernel_1& item
            );

            // functions from the remover interface
            inline void remove_any (
                T& item
            );

            // functions from the enumerable interface
            inline unsigned long size (
            ) const;

            inline bool at_start (
            ) const;

            inline void reset (
            ) const;

            bool current_element_valid (
            ) const;

            inline const T& element (
            ) const;

            inline T& element (
            );

            bool move_next (
            ) const;

        private:

            void delete_nodes (
                node* start,
                unsigned long length
            );
            /*!
                requires
                    - start points to a node in a singly linked list
                    - start->last points to the next node in the list
                    - there are at least length nodes in the list begining with start
                ensures
                    - length nodes have been deleted starting with the node pointed
                      to by start
            !*/

            // data members

            node* in;
            node* out;
            unsigned long queue_size;
            mutable node* current_element;
            mutable bool at_start_;

            // restricted functions
            queue_kernel_1(queue_kernel_1&);        // copy constructor
            queue_kernel_1& operator=(queue_kernel_1&);    // assignment operator

    };

    template <
        typename T,
        typename mem_manager
        >
    inline void swap (
        queue_kernel_1<T,mem_manager>& a,
        queue_kernel_1<T,mem_manager>& b
    ) { a.swap(b); }

    template <
        typename T,
        typename mem_manager
        >
    void deserialize (
        queue_kernel_1<T,mem_manager>& item,
        std::istream& in
    )
    {
        try
        {
            item.clear();
            unsigned long size;
            deserialize(size,in);
            T temp;
            for (unsigned long i = 0; i < size; ++i)
            {
                deserialize(temp,in);
                item.enqueue(temp);
            }
        }
        catch (serialization_error e)
        {
            item.clear();
            throw serialization_error(e.info + "\n   while deserializing object of type queue_kernel_1");
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    queue_kernel_1<T,mem_manager>::
    ~queue_kernel_1 (
    )
    {
        delete_nodes(out,queue_size);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void queue_kernel_1<T,mem_manager>::
    clear (
    )
    {
        delete_nodes(out,queue_size);
        queue_size = 0;

        // put the enumerator at the start
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void queue_kernel_1<T,mem_manager>::
    enqueue (
        T& item
    )
    {
        // make new node
        node* temp = new node;

        // swap item into new node
        exchange(item,temp->item);

        if (queue_size == 0)
            out = temp;
        else
            in->last = temp;

        // make in point to the new node
        in = temp;

        ++queue_size;

        // put the enumerator at the start
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void queue_kernel_1<T,mem_manager>::
    dequeue (
        T& item
    )
    {
        // swap out into item
        exchange(item,out->item);

        --queue_size;

        if (queue_size == 0)
        {
            delete out;
        }
        else
        {
            node* temp = out;

            // move out pointer to the next element in the queue
            out = out->last;

            // delete old node
            delete temp;
        }

        // put the enumerator at the start
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void queue_kernel_1<T,mem_manager>::
    cat (
        queue_kernel_1<T,mem_manager>& item
    )
    {
        if (item.queue_size > 0)
        {
            if (queue_size > 0)
            {
                in->last = item.out;
            }
            else
            {
                out = item.out;
            }

            in = item.in;
            queue_size += item.queue_size;
            item.queue_size = 0;
        }

        // put the enumerator at the start
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    T& queue_kernel_1<T,mem_manager>::
    current (
    )
    {
        return out->item;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    const T& queue_kernel_1<T,mem_manager>::
    current (
    ) const
    {
        return out->item;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void queue_kernel_1<T,mem_manager>::
    swap (
        queue_kernel_1<T,mem_manager>& item
    )
    {
        node* in_temp = in;
        node* out_temp = out;
        unsigned long queue_size_temp = queue_size;
        node* current_element_temp = current_element;
        bool at_start_temp = at_start_;

        in = item.in;
        out = item.out;
        queue_size = item.queue_size;
        current_element = item.current_element;
        at_start_ = item.at_start_;

        item.in = in_temp;
        item.out = out_temp;
        item.queue_size = queue_size_temp;
        item.current_element = current_element_temp;
        item.at_start_ = at_start_temp;
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // enumerable function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    bool queue_kernel_1<T,mem_manager>::
    at_start (
    ) const
    {
        return at_start_;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    unsigned long queue_kernel_1<T,mem_manager>::
    size (
    ) const
    {
        return queue_size;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void queue_kernel_1<T,mem_manager>::
    reset (
    ) const
    {
        at_start_ = true;
        current_element = 0;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    bool queue_kernel_1<T,mem_manager>::
    current_element_valid (
    ) const
    {
        return (current_element != 0);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    const T& queue_kernel_1<T,mem_manager>::
    element (
    ) const
    {
        return current_element->item;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    T& queue_kernel_1<T,mem_manager>::
    element (
    )
    {
        return current_element->item;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    bool queue_kernel_1<T,mem_manager>::
    move_next (
    ) const
    {
        if (at_start_)
        {
            at_start_ = false;
            // if the queue is empty then there is nothing to do
            if (queue_size == 0)
            {
                return false;
            }
            else
            {
                current_element = out;
                return true;
            }
        }
        else
        {
            // if we are at the last element then the enumeration has finished
            if (current_element == in || current_element == 0)
            {
                current_element = 0;
                return false;
            }
            else
            {
                current_element = current_element->last;
                return true;
            }
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // remover function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void queue_kernel_1<T,mem_manager>::
    remove_any (
        T& item
    )
    {
        dequeue(item);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // private member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void queue_kernel_1<T,mem_manager>::
    delete_nodes (
        node* start,
        unsigned long length
    )
    {
        node* temp;
        while (length)
        {
            temp = start->last;
            delete start;
            start = temp;
            --length;
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_QUEUE_KERNEl_1_


dlib C++ Library - queue_kernel_2.h

// Copyright (C) 2004  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_QUEUE_KERNEl_2_
#define DLIB_QUEUE_KERNEl_2_

#include "queue_kernel_abstract.h"
#include "../algs.h"
#include "../assert.h"
#include "../interfaces/enumerable.h"
#include "../interfaces/remover.h"
#include "../serialize.h"

namespace dlib
{

    template <
        typename T,
        unsigned long block_size,
        typename mem_manager = default_memory_manager
        >
    class queue_kernel_2 : public enumerable<T>,
                           public remover<T>
    {

        /*!
            REQUIREMENTS ON block_size
                0 < block_size < 2000000000

            INITIAL VALUE
                queue_size == 0
                current_element == 0
                at_start_ == true

            CONVENTION
                queue_size == the number of elements in the queue
                at_start() == at_start_
                current_element_valid() == (current_element != 0)
                if (current_element_valid()) then
                    element() == current_element->item[current_element_pos]

                if (queue_size > 0)
                {
                    in->item[in_pos] == the spot where we will put the next item added
                                        into the queue
                    out->item[out_pos] == current()

                    when enqueuing elements inside each node item[0] is filled first, then
                    item[1], then item[2], etc.

                    each node points to the node inserted after it except for the most
                    recently inserted node.
                }

        !*/

        struct node
        {
            node* next;

            T item[block_size];
        };

        public:

            typedef T type;
            typedef mem_manager mem_manager_type;

            queue_kernel_2 (
            ) :
                in(0),
                out(0),
                queue_size(0),
                current_element(0),
                at_start_(true)
            {
            }

            virtual ~queue_kernel_2 (
            );

            inline void clear(
            );

            void enqueue (
                T& item
            );

            void dequeue (
                T& item
            );

            void cat (
                queue_kernel_2& item
            );

            T& current (
            );

            const T& current (
            ) const;

            void swap (
                queue_kernel_2& item
            );

            // functions from the remover interface
            inline void remove_any (
                T& item
            );

            // functions from the enumerable interface
            inline unsigned long size (
            ) const;

            inline bool at_start (
            ) const;

            inline void reset (
            ) const;

            bool current_element_valid (
            ) const;

            inline const T& element (
            ) const;

            inline T& element (
            );

            bool move_next (
            ) const;

        private:

            void delete_nodes (
                node* start,
                node* end
            );
            /*!
                requires
                    - start points to a node in a singly linked list
                    - start->next points to the next node in the list
                    - by following the next pointers you eventually hit the node pointed
                      to by end
                ensures
                    - calls delete on the start node, the end node, and all nodes in between
            !*/

            // data members

            typename mem_manager::template rebind<node>::other pool;

            node* in;
            node* out;
            unsigned long queue_size;
            unsigned long in_pos;
            unsigned long out_pos;

            mutable node* current_element;
            mutable unsigned long current_element_pos;
            mutable bool at_start_;

            // restricted functions
            queue_kernel_2(queue_kernel_2&);        // copy constructor
            queue_kernel_2& operator=(queue_kernel_2&);    // assignment operator

    };

    template <
        typename T,
        unsigned long block_size,
        typename mem_manager
        >
    inline void swap (
        queue_kernel_2<T,block_size,mem_manager>& a,
        queue_kernel_2<T,block_size,mem_manager>& b
    ) { a.swap(b); }

    template <
        typename T,
        unsigned long block_size,
        typename mem_manager
        >
    void deserialize (
        queue_kernel_2<T,block_size,mem_manager>& item,
        std::istream& in
    )
    {
        try
        {
            item.clear();
            unsigned long size;
            deserialize(size,in);
            T temp;
            for (unsigned long i = 0; i < size; ++i)
            {
                deserialize(temp,in);
                item.enqueue(temp);
            }
        }
        catch (serialization_error e)
        {
            item.clear();
            throw serialization_error(e.info + "\n   while deserializing object of type queue_kernel_2");
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        unsigned long block_size,
        typename mem_manager
        >
    queue_kernel_2<T,block_size,mem_manager>::
    ~queue_kernel_2 (
    )
    {
        COMPILE_TIME_ASSERT(0 < block_size && block_size < (unsigned long)(2000000000));

        if (queue_size > 0)
            delete_nodes(out,in);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        unsigned long block_size,
        typename mem_manager
        >
    void queue_kernel_2<T,block_size,mem_manager>::
    clear (
    )
    {
        if (queue_size > 0)
        {
            delete_nodes(out,in);
            queue_size = 0;
        }

        // put the enumerator at the start
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        unsigned long block_size,
        typename mem_manager
        >
    void queue_kernel_2<T,block_size,mem_manager>::
    enqueue (
        T& item
    )
    {
        if (queue_size == 0)
        {
            out = in = pool.allocate();
            in_pos = 0;
            out_pos = 0;
        }
        else if (in_pos >= block_size)
        {
            in->next = pool.allocate();
            in_pos = 0;
            in = in->next;
        }

        exchange(item,in->item[in_pos]);
        ++in_pos;

        ++queue_size;

        // put the enumerator at the start
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        unsigned long block_size,
        typename mem_manager
        >
    void queue_kernel_2<T,block_size,mem_manager>::
    dequeue (
        T& item
    )
    {
        // swap out into item
        exchange(item,out->item[out_pos]);

        ++out_pos;
        --queue_size;

        // if this was the last element in this node then remove this node
        if (out_pos == block_size)
        {
            out_pos = 0;
            node* temp = out;
            out = out->next;
            pool.deallocate(temp);
        }
        else if (queue_size == 0)
        {
            pool.deallocate(out);
        }

        // put the enumerator at the start
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        unsigned long block_size,
        typename mem_manager
        >
    void queue_kernel_2<T,block_size,mem_manager>::
    cat (
        queue_kernel_2<T,block_size,mem_manager>& item
    )
    {
        if (queue_size > 0)
        {
            T temp;
            assign_zero_if_built_in_scalar_type(temp);
            while (item.size() > 0)
            {
                item.dequeue(temp);
                enqueue(temp);
            }
        }
        else
        {
            in = item.in;
            out = item.out;
            out_pos = item.out_pos;
            in_pos = item.in_pos;

            queue_size = item.queue_size;
            item.queue_size = 0;

            // put the enumerator at the start
            reset();
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        unsigned long block_size,
        typename mem_manager
        >
    T& queue_kernel_2<T,block_size,mem_manager>::
    current (
    )
    {
        return out->item[out_pos];
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        unsigned long block_size,
        typename mem_manager
        >
    const T& queue_kernel_2<T,block_size,mem_manager>::
    current (
    ) const
    {
        return out->item[out_pos];
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        unsigned long block_size,
        typename mem_manager
        >
    void queue_kernel_2<T,block_size,mem_manager>::
    swap (
        queue_kernel_2<T,block_size,mem_manager>& item
    )
    {
        exchange(in,item.in);
        exchange(out,item.out);
        exchange(queue_size,item.queue_size);
        exchange(in_pos,item.in_pos);
        exchange(out_pos,item.out_pos);
        exchange(current_element,item.current_element);
        exchange(current_element_pos,item.current_element_pos);
        exchange(at_start_,item.at_start_);
        pool.swap(item.pool);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // enumerable function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        unsigned long block_size,
        typename mem_manager
        >
    unsigned long queue_kernel_2<T,block_size,mem_manager>::
    size (
    ) const
    {
        return queue_size;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        unsigned long block_size,
        typename mem_manager
        >
    bool queue_kernel_2<T,block_size,mem_manager>::
    at_start (
    ) const
    {
        return at_start_;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        unsigned long block_size,
        typename mem_manager
        >
    void queue_kernel_2<T,block_size,mem_manager>::
    reset (
    ) const
    {
        at_start_ = true;
        current_element = 0;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        unsigned long block_size,
        typename mem_manager
        >
    bool queue_kernel_2<T,block_size,mem_manager>::
    current_element_valid (
    ) const
    {
        return (current_element != 0);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        unsigned long block_size,
        typename mem_manager
        >
    const T& queue_kernel_2<T,block_size,mem_manager>::
    element (
    ) const
    {
        return current_element->item[current_element_pos];
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        unsigned long block_size,
        typename mem_manager
        >
    T& queue_kernel_2<T,block_size,mem_manager>::
    element (
    )
    {
        return current_element->item[current_element_pos];
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        unsigned long block_size,
        typename mem_manager
        >
    bool queue_kernel_2<T,block_size,mem_manager>::
    move_next (
    ) const
    {
        if (at_start_)
        {
            at_start_ = false;
            // if the queue is empty then there is nothing to do
            if (queue_size == 0)
            {
                return false;
            }
            else
            {
                current_element = out;
                current_element_pos = out_pos;
                return true;
            }
        }
        else if (current_element == 0)
        {
            return false;
        }
        else
        {
            ++current_element_pos;
            // if we are at the last element then the enumeration has finished
            if (current_element == in && current_element_pos == in_pos )
            {
                current_element = 0;
                return false;
            }
            else if (current_element_pos == block_size)
            {
                current_element_pos = 0;
                current_element = current_element->next;
            }

            return true;
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // remover function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        unsigned long block_size,
        typename mem_manager
        >
    void queue_kernel_2<T,block_size,mem_manager>::
    remove_any (
        T& item
    )
    {
        dequeue(item);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // private member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        unsigned long block_size,
        typename mem_manager
        >
    void queue_kernel_2<T,block_size,mem_manager>::
    delete_nodes (
        node* start,
        node* end
    )
    {
        node* temp;
        while (start != end)
        {
            temp = start;
            start = start->next;
            pool.deallocate(temp);
        }
        pool.deallocate(start);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_QUEUE_KERNEl_2_


dlib C++ Library - queue_kernel_c.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_QUEUE_KERNEl_C_
#define DLIB_QUEUE_KERNEl_C_

#include "queue_kernel_abstract.h"
#include "../algs.h"
#include "../assert.h"

namespace dlib
{

    template <
        typename queue_base // is an implementation of queue_kernel_abstract.h
        >
    class queue_kernel_c : public queue_base
    {
        typedef typename queue_base::type T;

        public:

            void dequeue (
                T& item
            );

            T& current (
            );

            const T& current (
            ) const;

            const T& element (
            ) const;

            T& element (
            );

            void remove_any (
                T& item
            );

    };

    template <
        typename queue_base
        >
    inline void swap (
        queue_kernel_c<queue_base>& a,
        queue_kernel_c<queue_base>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename queue_base
        >
    void queue_kernel_c<queue_base>::
    dequeue (
        T& item
    )
    {

        // make sure requires clause is not broken
        DLIB_CASSERT(this->size() != 0,
            "\tvoid queue::dequeue"
            << "\n\tsize of queue should not be zero"
            << "\n\tthis: " << this
            );

        // call the real function
        queue_base::dequeue(item);

    }

// ----------------------------------------------------------------------------------------

    template <
        typename queue_base
        >
    const typename queue_base::type& queue_kernel_c<queue_base>::
    current (
    ) const
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(this->size() != 0,
            "\tconst T& queue::current"
            << "\n\tsize of queue should not be zero"
            << "\n\tthis: " << this
            );

        // call the real function
        return queue_base::current();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename queue_base
        >
    typename queue_base::type& queue_kernel_c<queue_base>::
    current (
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(this->size() != 0,
            "\tT& queue::current"
            << "\n\tsize of queue should not be zero"
            << "\n\tthis: " << this
            );

        // call the real function
        return queue_base::current();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename queue_base
        >
    const typename queue_base::type& queue_kernel_c<queue_base>::
    element (
    ) const
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(this->current_element_valid() == true,
            "\tconst T& queue::element"
            << "\n\tyou can't access the current element if it doesn't exist"
            << "\n\tthis: " << this
            );

        // call the real function
        return queue_base::element();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename queue_base
        >
    typename queue_base::type& queue_kernel_c<queue_base>::
    element (
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(this->current_element_valid() == true,
            "\tT& queue::element"
            << "\n\tyou can't access the current element if it doesn't exist"
            << "\n\tthis: " << this
            );

        // call the real function
        return queue_base::element();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename queue_base
        >
    void queue_kernel_c<queue_base>::
    remove_any (
        T& item
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT( (this->size() > 0),
            "\tvoid queue::remove_any"
            << "\n\tsize() must be greater than zero if something is going to be removed"
            << "\n\tsize(): " << this->size()
            << "\n\tthis:   " << this
            );

        // call the real function
        queue_base::remove_any(item);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_QUEUE_KERNEl_C_


dlib C++ Library - queue_sort_1.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_QUEUE_SORt_1_
#define DLIB_QUEUE_SORt_1_

#include "queue_sort_abstract.h"
#include "../algs.h"
#include <vector>
#include "../sort.h"

namespace dlib
{

    template <
        typename queue_base
        >
    class queue_sort_1 : public queue_base
    {
        typedef typename queue_base::type T;

        public:

            /*!
                This implementation uses the QuickSort algorithm and
                when the quicksort depth goes too high it uses the dlib::qsort_array()
                function on the data.
            !*/

            void sort (
            );

            template <typename compare_type>
            void sort (
                const compare_type& compare
            )
            {
                if (this->size() > 1)
                {
                    sort_this_queue(*this,0,compare);
                }
            }

        private:

            template <typename compare_type>
            void sort_this_queue (
                queue_base& queue,
                long depth,
                const compare_type& compare
            )
            /*!
                ensures
                    each element in the queue is < the element behind it according
                    to compare
            !*/
            {
                if (queue.size() <= 1)
                {
                    // already sorted
                }
                else if (queue.size() <= 29)
                {
                    T vect[29];
                    const unsigned long size = queue.size();
                    for (unsigned long i = 0; i < size; ++i)
                    {
                        queue.dequeue(vect[i]);
                    }
                    isort_array(vect,0,size-1,compare);
                    for (unsigned long i = 0; i < size; ++i)
                    {
                        queue.enqueue(vect[i]);
                    }
                }
                else if (depth > 50)
                {
                    std::vector<T> vect(queue.size());
                    for (unsigned long i = 0; i < vect.size(); ++i)
                    {
                        queue.dequeue(vect[i]);
                    }
                    hsort_array(vect,0,vect.size()-1,compare);
                    for (unsigned long i = 0; i < vect.size(); ++i)
                    {
                        queue.enqueue(vect[i]);
                    }
                }
                else
                {
                    queue_base left, right;
                    T partition_element;
                    T temp;
                    // do this just to avoid a compiler warning
                    assign_zero_if_built_in_scalar_type(temp);
                    assign_zero_if_built_in_scalar_type(partition_element);

                    queue.dequeue(partition_element);

                    // partition queue into left and right
                    while (queue.size() > 0)
                    {
                        queue.dequeue(temp);
                        if (compare(temp , partition_element))
                        {
                            left.enqueue(temp);
                        }
                        else
                        {
                            right.enqueue(temp);
                        }
                    }

                    long ratio;
                    if (left.size() > right.size())
                        ratio = left.size()/(right.size()+1);  // add 1 so we can't divide by zero
                    else
                        ratio = right.size()/(left.size()+1);

                    sort_this_queue(left,ratio+depth,compare);
                    sort_this_queue(right,ratio+depth,compare);

                    // combine the two queues
                    left.swap(queue);
                    queue.enqueue(partition_element);
                    queue.cat(right);
                }
            }

    };

    template <
        typename queue_base
        >
    inline void swap (
        queue_sort_1<queue_base>& a,
        queue_sort_1<queue_base>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename queue_base
        >
    void queue_sort_1<queue_base>::
    sort (
    )
    {
        if (this->size() > 1)
        {
            sort_this_queue(*this,0,std::less<typename queue_base::type>());
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_QUEUE_SORt_1_


dlib C++ Library - mersenne_twister.h

/* boost random/mersenne_twister.hpp header file
 *
 * Copyright Jens Maurer 2000-2001
 * Distributed under the Boost Software License, Version 1.0. (See
 * accompanying file LICENSE_1_0.txt or copy at
 * http://www.boost.org/LICENSE_1_0.txt)
 *
 * See http://www.boost.org for most recent version including documentation.
 *
 * $Id: mersenne_twister.hpp,v 1.20 2005/07/21 22:04:31 jmaurer Exp $
 *
 * Revision history
 *  2001-02-18  moved to individual header files
*/

#ifndef DLIB_BOOST_RANDOM_MERSENNE_TWISTER_HPP
#define DLIB_BOOST_RANDOM_MERSENNE_TWISTER_HPP

#include <iostream>
#include <algorithm>     // std::copy
#include <stdexcept>
#include "../uintn.h"
#include "../serialize.h"

namespace dlib
{
    namespace random_helpers
    {

    // ------------------------------------------------------------------------------------

        // http://www.math.keio.ac.jp/matumoto/emt.html
        template<
            class UIntType,
            int w,
            int n,
            int m,
            int r,
            UIntType a,
            int u,
            int s,
            UIntType b,
            int t,
            UIntType c,
            int l,
            UIntType val
            >
        class mersenne_twister
        {
        public:
            typedef UIntType result_type;
            const static int word_size = w;
            const static int state_size = n;
            const static int shift_size = m;
            const static int mask_bits = r;
            const static UIntType parameter_a = a;
            const static int output_u = u;
            const static int output_s = s;
            const static UIntType output_b = b;
            const static int output_t = t;
            const static UIntType output_c = c;
            const static int output_l = l;

            const static bool has_fixed_range = false;

            mersenne_twister() { seed(); }

            explicit mersenne_twister(UIntType value) { seed(value); }

            void seed () { seed(UIntType(5489)); }

            // compiler-generated copy ctor and assignment operator are fine

            void seed(UIntType value)
            {
                // New seeding algorithm from
                // http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/emt19937ar.html
                // In the previous versions, MSBs of the seed affected only MSBs of the
                // state x[].
                const UIntType mask = ~0u;
                x[0] = value & mask;
                for (i = 1; i < n; i++) {
                    // See Knuth "The Art of Computer Programming" Vol. 2, 3rd ed., page 106
                    x[i] = (1812433253UL * (x[i-1] ^ (x[i-1] >> (w-2))) + i) & mask;
                }
            }

            result_type min() const { return 0; }
            result_type max() const
            {
                // avoid "left shift count >= with of type" warning
                result_type res = 0;
                for(int i = 0; i < w; ++i)
                    res |= (1u << i);
                return res;
            }

            result_type operator()();

            friend void serialize(
                const mersenne_twister& item,
                std::ostream& out
            )
            {
                dlib::serialize(item.x, out);
                dlib::serialize(item.i, out);
            }

            friend void deserialize(
                mersenne_twister& item,
                std::istream& in
            )
            {
                dlib::deserialize(item.x, in);
                dlib::deserialize(item.i, in);
            }

        private:

            void twist(int block);

            // state representation: next output is o(x(i))
            //   x[0]  ... x[k] x[k+1] ... x[n-1]     x[n]     ... x[2*n-1]   represents
            //  x(i-k) ... x(i) x(i+1) ... x(i-k+n-1) x(i-k-n) ... x[i(i-k-1)]
            // The goal is to always have x(i-n) ... x(i-1) available for
            // operator== and save/restore.

            UIntType x[2*n];
            int i;
        };

    // ------------------------------------------------------------------------------------

        template<
            class UIntType, int w, int n, int m, int r, UIntType a, int u,
            int s, UIntType b, int t, UIntType c, int l, UIntType val
            >
        void mersenne_twister<UIntType,w,n,m,r,a,u,s,b,t,c,l,val>::twist(
            int block
        )
        {
            const UIntType upper_mask = (~0u) << r;
            const UIntType lower_mask = ~upper_mask;

            if(block == 0) {
                for(int j = n; j < 2*n; j++) {
                    UIntType y = (x[j-n] & upper_mask) | (x[j-(n-1)] & lower_mask);
                    x[j] = x[j-(n-m)] ^ (y >> 1) ^ (y&1 ? a : 0);
                }
            } else if (block == 1) {
                // split loop to avoid costly modulo operations
                {  // extra scope for MSVC brokenness w.r.t. for scope
                    for(int j = 0; j < n-m; j++) {
                        UIntType y = (x[j+n] & upper_mask) | (x[j+n+1] & lower_mask);
                        x[j] = x[j+n+m] ^ (y >> 1) ^ (y&1 ? a : 0);
                    }
                }

                for(int j = n-m; j < n-1; j++) {
                    UIntType y = (x[j+n] & upper_mask) | (x[j+n+1] & lower_mask);
                    x[j] = x[j-(n-m)] ^ (y >> 1) ^ (y&1 ? a : 0);
                }
                // last iteration
                UIntType y = (x[2*n-1] & upper_mask) | (x[0] & lower_mask);
                x[n-1] = x[m-1] ^ (y >> 1) ^ (y&1 ? a : 0);
                i = 0;
            }
        }

    // ------------------------------------------------------------------------------------

        template<
            class UIntType, int w, int n, int m, int r, UIntType a, int u,
            int s, UIntType b, int t, UIntType c, int l, UIntType val
            >
        inline typename mersenne_twister<UIntType,w,n,m,r,a,u,s,b,t,c,l,val>::result_type
        mersenne_twister<UIntType,w,n,m,r,a,u,s,b,t,c,l,val>::operator()(
        )
        {
            if(i == n)
                twist(0);
            else if(i >= 2*n)
                twist(1);
            // Step 4
            UIntType z = x[i];
            ++i;
            z ^= (z >> u);
            z ^= ((z << s) & b);
            z ^= ((z << t) & c);
            z ^= (z >> l);
            return z;
        }

    // ------------------------------------------------------------------------------------

    } // namespace random

    typedef random_helpers::mersenne_twister<uint32,32,351,175,19,0xccab8ee7,11,
    7,0x31b6ab00,15,0xffe50000,17, 0xa37d3c92> mt11213b;

    // validation by experiment from mt19937.c
    typedef random_helpers::mersenne_twister<uint32,32,624,397,31,0x9908b0df,11,
    7,0x9d2c5680,15,0xefc60000,18, 3346425566U> mt19937;

} // namespace dlib

#endif // DLIB_BOOST_RANDOM_MERSENNE_TWISTER_HPP


dlib C++ Library - rand_kernel_1.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_RAND_KERNEl_1_
#define DLIB_RAND_KERNEl_1_

#include <string>
#include "../algs.h"
#include "rand_kernel_abstract.h"
#include "mersenne_twister.h"
#include "../is_kind.h"
#include <iostream>
#include "../serialize.h"

namespace dlib
{

    class rand
    {

        /*!
            INITIAL VALUE
                - seed == ""

            CONVENTION
                - the random numbers come from the boost mersenne_twister code
                - get_seed() == seed
        !*/

        public:

            // These typedefs are here for backwards compatibility with older versions of dlib.
            typedef rand kernel_1a;
            typedef rand float_1a;

            rand(
            )
            {
                init();
            }

            rand (
                const std::string& seed_value
            )
            {
                init();
                set_seed(seed_value);
            }

            virtual ~rand(
            )
            {}

            void clear(
            )
            {
                mt.seed();
                seed.clear();

                has_gaussian = false;
                next_gaussian = 0;

                // prime the generator a bit
                for (int i = 0; i < 10000; ++i)
                    mt();
            }

            const std::string& get_seed (
            )
            {
                return seed;
            }

            void set_seed (
                const std::string& value
            )
            {
                seed = value;

                // make sure we do the seeding so that using a seed of "" gives the same
                // state as calling this->clear()
                if (value.size() != 0)
                {
                    uint32 s = 0;
                    for (std::string::size_type i = 0; i < seed.size(); ++i)
                    {
                        s = (s*37) + static_cast<uint32>(seed[i]);
                    }
                    mt.seed(s);
                }
                else
                {
                    mt.seed();
                }

                // prime the generator a bit
                for (int i = 0; i < 10000; ++i)
                    mt();

                has_gaussian = false;
                next_gaussian = 0;
            }

            unsigned char get_random_8bit_number (
            )
            {
                return static_cast<unsigned char>(mt());
            }

            uint16 get_random_16bit_number (
            )
            {
                return static_cast<uint16>(mt());
            }

            inline uint32 get_random_32bit_number (
            )
            {
                return mt();
            }

            inline uint64 get_random_64bit_number (
            )
            {
                const uint64 a = get_random_32bit_number();
                const uint64 b = get_random_32bit_number();
                return (a<<32)|b;
            }

            double get_random_double (
            )
            {
                uint32 temp;

                temp = rand::get_random_32bit_number();
                temp &= 0xFFFFFF;

                double val = static_cast<double>(temp);

                val *= 0x1000000;

                temp = rand::get_random_32bit_number();
                temp &= 0xFFFFFF;

                val += temp;

                val /= max_val;

                if (val < 1.0)
                {
                    return val;
                }
                else
                {
                    // return a value slightly less than 1.0
                    return 1.0 - std::numeric_limits<double>::epsilon();
                }
            }

            float get_random_float (
            )
            {
                uint32 temp;

                temp = rand::get_random_32bit_number();
                temp &= 0xFFFFFF;

                const float scale = 1.0/0x1000000;

                const float val = static_cast<float>(temp)*scale;
                if (val < 1.0f)
                {
                    return val;
                }
                else
                {
                    // return a value slightly less than 1.0
                    return 1.0f - std::numeric_limits<float>::epsilon();
                }
            }

            double get_random_gaussian (
            )
            {
                if (has_gaussian)
                {
                    has_gaussian = false;
                    return next_gaussian;
                }

                double x1, x2, w;

                const double rndmax = std::numeric_limits<dlib::uint32>::max();

                // Generate a pair of Gaussian random numbers using the Box-Muller transformation.
                do
                {
                    const double rnd1 = get_random_32bit_number()/rndmax;
                    const double rnd2 = get_random_32bit_number()/rndmax;

                    x1 = 2.0 * rnd1 - 1.0;
                    x2 = 2.0 * rnd2 - 1.0;
                    w = x1 * x1 + x2 * x2;
                } while ( w >= 1.0 );

                w = std::sqrt( (-2.0 * std::log( w ) ) / w );
                next_gaussian = x2 * w;
                has_gaussian = true;
                return x1 * w;
            }

            void swap (
                rand& item
            )
            {
                exchange(mt,item.mt);
                exchange(seed, item.seed);
                exchange(has_gaussian, item.has_gaussian);
                exchange(next_gaussian, item.next_gaussian);
            }

            friend void serialize(
                const rand& item,
                std::ostream& out
            );

            friend void deserialize(
                rand& item,
                std::istream& in
            );

        private:

            void init()
            {
                // prime the generator a bit
                for (int i = 0; i < 10000; ++i)
                    mt();

                max_val =  0xFFFFFF;
                max_val *= 0x1000000;
                max_val += 0xFFFFFF;
                max_val += 0.01;

                has_gaussian = false;
                next_gaussian = 0;
            }

            mt19937 mt;

            std::string seed;

            double max_val;
            bool has_gaussian;
            double next_gaussian;
    };

    inline void swap (
        rand& a,
        rand& b
    ) { a.swap(b); }

    template <>
    struct is_rand<rand>
    {
        static const bool value = true;
    };

    inline void serialize(
        const rand& item,
        std::ostream& out
    )
    {
        int version = 1;
        serialize(version, out);

        serialize(item.mt, out);
        serialize(item.seed, out);
        serialize(item.has_gaussian, out);
        serialize(item.next_gaussian, out);
    }

    inline void deserialize(
        rand& item,
        std::istream& in
    )
    {
        int version;
        deserialize(version, in);
        if (version != 1)
            throw serialization_error("Error deserializing object of type rand: unexpected version.");

        deserialize(item.mt, in);
        deserialize(item.seed, in);
        deserialize(item.has_gaussian, in);
        deserialize(item.next_gaussian, in);
    }
}

#endif // DLIB_RAND_KERNEl_1_


dlib C++ Library - reference_counter_kernel_1.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_REFERENCE_COUNTER_KERNEl_1_
#define DLIB_REFERENCE_COUNTER_KERNEl_1_

#include "reference_counter_kernel_abstract.h"
#include "../algs.h"

namespace dlib
{

    template <
        typename T,
        typename copy = copy_functor<T>
        >
    class reference_counter_kernel_1
    {

        /*!
                INITIAL VALUE
                    *data = item of type T with its initial value
                    *count = 1

                CONVENTION
                    *data = pointer to item of type T
                    *count = number of references to *data

                    if clear() threw an exception then count = 0 and data is not a
                    valid pointer
        !*/

        public:

            typedef T type;

            reference_counter_kernel_1 (
            );

            inline reference_counter_kernel_1 (
                const reference_counter_kernel_1& item
            );

            virtual ~reference_counter_kernel_1 (
            );

            void clear (
            );

            T& modify (
            );

            inline const T& access (
            ) const;

            inline reference_counter_kernel_1& operator= (
                const reference_counter_kernel_1& rhs
            );

            inline void swap (
                reference_counter_kernel_1& item
            );

        private:

            T* data;
            unsigned long* count;
            mutable copy copy_item;
    };

    template <
        typename T,
        typename copy
        >
    inline void swap (
        reference_counter_kernel_1<T,copy>& a,
        reference_counter_kernel_1<T,copy>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename copy
        >
    reference_counter_kernel_1<T,copy>::
    reference_counter_kernel_1 (
    )
    {
        data = new T;
        try { count = new unsigned long; }
        catch (...) { delete data; throw; }

        *count = 1;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename copy
        >
    reference_counter_kernel_1<T,copy>::
    reference_counter_kernel_1 (
        const reference_counter_kernel_1<T,copy>& item
    ) :
        data(item.data),
        count(item.count)
    {
        ++(*count);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename copy
        >
    reference_counter_kernel_1<T,copy>::
    ~reference_counter_kernel_1 (
    )
    {
        if (*count > 1)
        {
            // if there are other references to this data
            --(*count);
        }
        else
        {
            // if there are no other references to this data
            delete count;
            delete data;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename copy
        >
    void reference_counter_kernel_1<T,copy>::
    clear (
    )
    {
        // if an exception was thrown last time clear() was called then do this
        if (count == 0)
        {
            data = new T;
            try { count = new unsigned long; }
            catch (...) { delete data; throw; }

            *count = 1;
        }
        // if there are other references to the data then do this
        else if (*count > 1)
        {
            --(*count);

            try { data = new T; }
            catch (...) { count = 0; throw; }

            try { count = new unsigned long; }
            catch (...) { delete data; count = 0; throw; }

            *count = 1;

        }
        else
        {
            // if there are no other references to this data
            *count = 1;
            delete data;
            try { data = new T; } catch (...) { delete count; count = 0; throw; }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename copy
        >
    T& reference_counter_kernel_1<T,copy>::
    modify (
    )
    {
        // if this is not the only reference then make a new copy
        if ( *count > 1 )
        {
            T&              old_data    = *data;
            unsigned long&  old_count   = *count;

            // get memory for the new copy
            try { data = new T; }
            catch (...) { data = &old_data; throw; }

            try { count = new unsigned long; }
            catch (...) {delete data; data = &old_data; count = &old_count; throw;}

            // decrement the number of references to old_data
            --(old_count);

            *count = 1;

            // make a copy of the old data
            try { copy_item(old_data,*data); }
            catch (...)
            { delete data; delete count; data = &old_data; count = &old_count; }

        }

        return *data;

    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename copy
        >
    const T& reference_counter_kernel_1<T,copy>::
    access (
    ) const
    {
        return *data;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename copy
        >
    reference_counter_kernel_1<T,copy>& reference_counter_kernel_1<T,copy>::
    operator= (
        const reference_counter_kernel_1<T,copy>& rhs
    )
    {
        if (this == &rhs)
            return *this;

        // delete the current data if this is the last reference to it
        if (*count > 1)
        {
            // if there are other references to this data
            --(*count);
        }
        else
        {
            // if there are no other references to this data
            delete count;
            delete data;
        }

        // copy the pointers
        count = (rhs.count);
        data = (rhs.data);
        ++(*count);

        return *this;

    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename copy
        >
    void reference_counter_kernel_1<T,copy>::
    swap (
        reference_counter_kernel_1<T,copy>& item
    )
    {
        T* data_temp                = data;
        unsigned long* count_temp   = count;

        data    = item.data;
        count   = item.count;

        item.data   = data_temp;
        item.count  = count_temp;
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_REFERENCE_COUNTER_KERNEl_1_


dlib C++ Library - sequence_compare_1.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SEQUENCE_COMPARe_1_
#define DLIB_SEQUENCE_COMPARe_1_

#include "sequence_compare_abstract.h"

#include "../algs.h"

namespace dlib
{

    template <
        typename seq_base
        >
    class sequence_compare_1 : public seq_base
    {
        typedef typename seq_base::type T;

    public:

        bool operator< (
            const sequence_compare_1& rhs
        ) const;

        bool operator== (
            const sequence_compare_1& rhs
        ) const;

    };

    template <
        typename seq_base
        >
    inline void swap (
        sequence_compare_1<seq_base>& a,
        sequence_compare_1<seq_base>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename seq_base
        >
    bool sequence_compare_1<seq_base>::
    operator< (
        const sequence_compare_1<seq_base>& rhs
    ) const
    {
        unsigned int length;
        if (this->size() < rhs.size())
            length = this->size();
        else
            length = rhs.size();

        for (unsigned long i = 0; i < length; ++i)
        {
            if ((*this)[i] < rhs[i])
                return true;
            else if ( !((*this)[i] == rhs[i]) )
                return false;
        }
        // they are equal so far
        if (this->size() < rhs.size())
            return true;
        else
            return false;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename seq_base
        >
    bool sequence_compare_1<seq_base>::
    operator== (
        const sequence_compare_1<seq_base>& rhs
    ) const
    {
        if (this->size() != rhs.size())
            return false;

        for (unsigned long i = 0; i < this->size(); ++i)
        {
            if (!((*this)[i] == rhs[i]))
                return false;
        }
        return true;
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SEQUENCE_COMPARe_1_


dlib C++ Library - sequence_kernel_1.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SEQUENCE_KERNEl_1_
#define DLIB_SEQUENCE_KERNEl_1_

#include "sequence_kernel_abstract.h"
#include "../algs.h"
#include "../interfaces/enumerable.h"
#include "../interfaces/remover.h"
#include "../serialize.h"

namespace dlib
{

    template <
        typename T,
        typename mem_manager = default_memory_manager
        >
    class sequence_kernel_1 : public enumerable<T>,
                              public remover<T>
    {

        /*!
            INITIAL VALUE
                - tree_root == 0
                - tree_size == 0
                - at_start_ == true
                - current_element == 0
                - stack == array of 50 node pointers
                - stack_pos == 0

            CONVENTION

                - if (tree_size > 0)
                    - tree_root == pointer to the root node of the binary search tree
                - else
                    - tree_root == 0

                - stack[stack_pos-1] == pop()

                - current_element_valid() == (current_element != 0)

                - at_start_ == at_start()
                - if (current_element != 0 && current_element != tree_root) then
                    - stack[stack_pos-1] == the parent of the node pointed to by current_element

                - if (current_element_valid()) then
                    - element() == current_element->item

                - tree_size == size()
                - (*this)[i] == return_reference(i)

                - for all nodes:
                    - left_size == the number of elements in the left subtree.
                    - left points to the left subtree or 0 if there is no left subtree.
                    - right points to the right subtree or 0 if there is no right subtree.

                    - all elements in a left subtree have a position in the sequence < that
                      of the root of the current tree.

                    - all elements in a right subtree have a position in the
                      sequence > that of the root of the current tree.

                    - item is the sequence element for that node.
                    - balance:
                        - balance == 0 if both subtrees have the same height
                        - balance == -1 if the left subtree has a height that is
                          greater than the height of the right subtree by 1
                        - balance == 1 if the right subtree has a height that is
                          greater than the height of the left subtree by 1
                    - for all subtrees:
                        - the height of the left and right subtrees differ by at most one

        !*/

        class node
        {
        public:
            node* left;
            node* right;
            unsigned long left_size;
            T item;
            signed char balance;
        };

        public:

            typedef T type;
            typedef mem_manager mem_manager_type;

            sequence_kernel_1 (
            ) :
                tree_root(0),
                tree_size(0),
                stack(ppool.allocate_array(50)),
                current_element(0),
                at_start_(true),
                stack_pos(0)
            {}

            virtual ~sequence_kernel_1 (
            );

            inline void clear (
            );

            void add (
                unsigned long pos,
                T& item
            );

            void remove (
                unsigned long pos,
                T& item
            );

            void cat (
                sequence_kernel_1& item
            );

            const T& operator[] (
                unsigned long pos
            ) const;

            T& operator[] (
                unsigned long pos
            );

            inline void swap (
                sequence_kernel_1& item
            );

            // functions from the remover interface
            inline void remove_any (
                T& item
            );

            // functions from the enumerable interface
            inline unsigned long size (
            ) const;

            bool at_start (
            ) const;

            inline void reset (
            ) const;

            bool current_element_valid (
            ) const;

            const T& element (
            ) const;

            T& element (
            );

            bool move_next (
            ) const;

        private:

            void delete_nodes (
                node* t
            );
            /*!
                requires
                    - t == a pointer to a valid node
                ensures
                    - deletes t and all its sub nodes.
            !*/

            inline void rotate_left (
                node*& t
            );
            /*!
                requires
                    - t->balance == 2
                    - t->right->balance == 0 or 1
                ensures
                    - #t is still a binary search tree
                    - #t->balance is between 1 and -1
                    - #t now has a height smaller by 1 if #t->balance == 0
            !*/

            inline void rotate_right (
                node*& t
            );
            /*!
                requires
                    - t->balance == -2
                    - t->left->balance == 0 or -1
                ensures
                    - #t is still a binary search tree
                    - #t->balance is between 1 and -1
                    - #t now has a height smaller by 1 if #t->balance == 0

            !*/

            inline void double_rotate_right (
                node*& t
            );
            /*!
                requires
                    - #t->balance == -2
                    - #t->left->balance == 1
                ensures
                    - #t is still a binary search tree
                    - #t now has a balance of 0
                    - #t now has a height smaller by 1
            !*/

            inline void double_rotate_left (
                node*& t
            );
            /*!
                requires
                    - #t->balance == 2
                    - #t->right->balance == -1
                ensures
                    - #t is still a binary search tree
                    - #t now has a balance of 0 and
                    - #t now has a height smaller by 1
            !*/

            bool remove_least_element_in_tree (
                node*& t,
                T& item
            );
            /*!
                requires
                    - t != 0  (i.e. there must be something in the tree to remove)
                ensures
                    - the least node in t has been removed
                    - the least node element in t has been put into #item
                    - #t is still a binary search tree
                    - returns false if the height of the tree has not changed
                    - returns true if the height of the tree has shrunk by one
            !*/

            bool add_to_tree (
                node*& t,
                unsigned long pos,
                T& item
            );
            /*!
                requires
                    - pos <= the number of items in the tree
                ensures
                    - item has been added to #t
                    - #return_reference(pos) == item
                    - the convention is still satisfied
                    - #item has an initial value for its type
                    - returns false if the height of the tree has not changed
                    - returns true if the height of the tree has grown by one
            !*/

            bool remove_from_tree (
                node*& t,
                unsigned long pos,
                T& item
            );
            /*!
                requires
                    - there is an item in the tree associated with pos
                ensures
                    - the element in the tree associated with pos has been removed
                      and put into #item
                    - the convention is still satisfied
                    - returns false if the height of the tree has not changed
                    - returns true if the height of the tree has shrunk by one
            !*/

            const T& return_reference (
                const node* t,
                unsigned long pos
            ) const;
            /*!
                requires
                    - there is an item in the tree associated with pos
                ensures
                    - returns a const reference to the item in the tree associated with pos
            !*/

            T& return_reference (
                node* t,
                unsigned long pos
            );
            /*!
                requires
                    - there is an item in the tree associated with pos
                ensures
                    - returns a non-const reference to the item in the tree associated
                      with pos
            !*/

            inline bool keep_node_balanced (
                node*& t
            );
            /*!
                requires
                    - t != 0
                ensures
                    - if (t->balance is < 1 or > 1) then
                        - keep_node_balanced() will ensure that t->balance == 0, -1, or 1
                    - returns true if it made the tree one height shorter
                    - returns false if it didn't change the height
            !*/

            void push (
                node* n
            ) const { stack[stack_pos] = n; ++stack_pos; }
            /*!
                ensures
                    - pushes n onto the stack
            !*/

            node* pop (
            ) const { --stack_pos; return stack[stack_pos]; }
            /*!
                ensures
                    - pops the top of the stack and returns it
            !*/

            // data members
            typename mem_manager::template rebind<node>::other pool;
            typename mem_manager::template rebind<node*>::other ppool;

            node* tree_root;
            unsigned long tree_size;

            mutable node** stack;
            mutable node* current_element;
            mutable bool at_start_;
            mutable unsigned char stack_pos;

            // restricted functions
            sequence_kernel_1(sequence_kernel_1&);        // copy constructor
            sequence_kernel_1& operator=(sequence_kernel_1&); // assignment operator

    };

    template <
        typename T,
        typename mem_manager
        >
    inline void swap (
        sequence_kernel_1<T,mem_manager>& a,
        sequence_kernel_1<T,mem_manager>& b
    ) { a.swap(b); }

    template <
        typename T,
        typename mem_manager
        >
    void deserialize (
        sequence_kernel_1<T,mem_manager>& item,
        std::istream& in
    )
    {
        try
        {
            item.clear();
            unsigned long size;
            deserialize(size,in);
            T temp;
            for (unsigned long i = 0; i < size; ++i)
            {
                deserialize(temp,in);
                item.add(i,temp);
            }
        }
        catch (serialization_error e)
        {
            item.clear();
            throw serialization_error(e.info + "\n   while deserializing object of type sequence_kernel_1");
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    sequence_kernel_1<T,mem_manager>::
    ~sequence_kernel_1 (
    )
    {
        ppool.deallocate_array(stack);
        if (tree_size > 0)
        {
            delete_nodes(tree_root);
        }
    }

// ----------------------------------------------------------------------------------------
    template <
        typename T,
        typename mem_manager
        >
    void sequence_kernel_1<T,mem_manager>::
    swap (
        sequence_kernel_1<T,mem_manager>& item
    )
    {
        exchange(stack,item.stack);
        exchange(stack_pos,item.stack_pos);

        pool.swap(item.pool);
        ppool.swap(item.ppool);

        node* tree_root_temp            = item.tree_root;
        unsigned long tree_size_temp    = item.tree_size;
        node* current_element_temp      = item.current_element;
        bool at_start_temp              = item.at_start_;

        item.tree_root = tree_root;
        item.tree_size = tree_size;
        item.current_element = current_element;
        item.at_start_   = at_start_;

        tree_root = tree_root_temp;
        tree_size = tree_size_temp;
        current_element = current_element_temp;
        at_start_   = at_start_temp;

    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    unsigned long sequence_kernel_1<T,mem_manager>::
    size (
    ) const
    {
        return tree_size;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    const T& sequence_kernel_1<T,mem_manager>::
    operator[] (
        unsigned long pos
    ) const
    {
        return return_reference(tree_root,pos);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    T& sequence_kernel_1<T,mem_manager>::
    operator[] (
        unsigned long pos
    )
    {
        return return_reference(tree_root,pos);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void sequence_kernel_1<T,mem_manager>::
    add (
        unsigned long pos,
        T& item
    )
    {
        add_to_tree(tree_root,pos,item);
        ++tree_size;
        // reset the enumerator
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void sequence_kernel_1<T,mem_manager>::
    remove (
        unsigned long pos,
        T& item
    )
    {
        remove_from_tree(tree_root,pos,item);
        --tree_size;
        // reset the enumerator
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void sequence_kernel_1<T,mem_manager>::
    cat (
        sequence_kernel_1<T,mem_manager>& item
    )
    {
        for (unsigned long i = 0; i < item.tree_size; ++i)
        {
            add_to_tree(
                tree_root,
                tree_size,
                return_reference(item.tree_root,i)
            );

            ++tree_size;
        }

        item.clear();
        // reset the enumerator
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void sequence_kernel_1<T,mem_manager>::
    clear (
    )
    {
        if (tree_size > 0)
        {
            delete_nodes(tree_root);
            tree_root = 0;
            tree_size = 0;
        }
        // reset the enumerator
        reset();
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // enumerable function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    bool sequence_kernel_1<T,mem_manager>::
    at_start (
    ) const
    {
        return at_start_;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void sequence_kernel_1<T,mem_manager>::
    reset (
    ) const
    {
        at_start_ = true;
        current_element = 0;
        stack_pos = 0;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    bool sequence_kernel_1<T,mem_manager>::
    current_element_valid (
    ) const
    {
        return (current_element != 0);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    const T& sequence_kernel_1<T,mem_manager>::
    element (
    ) const
    {
        return current_element->item;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    T& sequence_kernel_1<T,mem_manager>::
    element (
    )
    {
        return current_element->item;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    bool sequence_kernel_1<T,mem_manager>::
    move_next (
    ) const
    {
        // if we haven't started iterating yet
        if (at_start_)
        {
            at_start_ = false;
            if (tree_size == 0)
            {
                return false;
            }
            else
            {
                // find the first element in the tree
                current_element = tree_root;
                node* temp = current_element->left;
                while (temp != 0)
                {
                    push(current_element);
                    current_element = temp;
                    temp = current_element->left;
                }
                return true;
            }
        }
        else
        {
            if (current_element == 0)
            {
                return false;
            }
            else
            {
                node* temp;
                bool went_up;  // true if we went up the tree from a child node to parent
                bool from_left = false; // true if we went up and were coming from a left child node
                // find the next element in the tree
                if (current_element->right != 0)
                {
                    // go right and down
                    temp = current_element;
                    push(current_element);
                    current_element = temp->right;
                    went_up = false;
                }
                else
                {
                    // go up to the parent if we can
                    if (current_element == tree_root)
                    {
                        // in this case we have iterated over all the element of the tree
                        current_element = 0;
                        return false;
                    }
                    went_up = true;
                    node* parent = pop();

                    from_left = (parent->left == current_element);
                    // go up to parent
                    current_element = parent;
                }

                while (true)
                {
                    if (went_up)
                    {
                        if (from_left)
                        {
                            // in this case we have found the next node
                            break;
                        }
                        else
                        {
                            if (current_element == tree_root)
                            {
                                // in this case we have iterated over all the elements
                                // in the tree
                                current_element = 0;
                                return false;
                            }
                            // we should go up
                            node* parent = pop();
                            from_left = (parent->left == current_element);
                            current_element = parent;
                        }
                    }
                    else
                    {
                        // we just went down to a child node
                        if (current_element->left != 0)
                        {
                            // go left
                            went_up = false;
                            temp = current_element;
                            push(current_element);
                            current_element = temp->left;
                        }
                        else
                        {
                            // if there is no left child then we have found the next node
                            break;
                        }
                    }
                }

                return true;
            }
        }

    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // remover function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void sequence_kernel_1<T,mem_manager>::
    remove_any (
        T& item
    )
    {
        remove(0,item);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // private member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void sequence_kernel_1<T,mem_manager>::
    rotate_left (
        node*& t
    )
    {

        // set the new balance numbers
        if (t->right->balance == 1)
        {
            t->balance = 0;
            t->right->balance = 0;
        }
        else
        {
            t->balance = 1;
            t->right->balance = -1;
        }

        // perform the rotation
        node* temp = t->right;
        t->right = temp->left;
        temp->left = t;
        t = temp;

        // set left_size to its correct value
        t->left_size += t->left->left_size + 1;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void sequence_kernel_1<T,mem_manager>::
    rotate_right (
        node*& t
    )
    {
        // set the new balance numbers
        if (t->left->balance == -1)
        {
            t->balance = 0;
            t->left->balance = 0;
        }
        else
        {
            t->balance = -1;
            t->left->balance = 1;
        }

        // preform the rotation
        node* temp = t->left;
        t->left = temp->right;
        temp->right = t;
        t = temp;

        // set left_size to its correct value
        t->right->left_size -= t->left_size + 1;

    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void sequence_kernel_1<T,mem_manager>::
    double_rotate_right (
        node*& t
    )
    {

        node* temp = t;
        t = t->left->right;

        temp->left->right = t->left;
        t->left = temp->left;

        temp->left = t->right;
        t->right = temp;

        if (t->balance < 0)
        {
            t->left->balance = 0;
            t->right->balance = 1;
        }
        else if (t->balance > 0)
        {
            t->left->balance = -1;
            t->right->balance = 0;
        }
        else
        {
            t->left->balance = 0;
            t->right->balance = 0;
        }
        t->balance = 0;

        // set left_size to its correct value
        t->left_size += t->left->left_size + 1;
        t->right->left_size -= t->left_size + 1;

    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void sequence_kernel_1<T,mem_manager>::
    double_rotate_left (
        node*& t
    )
    {
        node* temp = t;
        t = t->right->left;

        temp->right->left = t->right;
        t->right = temp->right;

        temp->right = t->left;
        t->left = temp;

        if (t->balance < 0)
        {
            t->left->balance = 0;
            t->right->balance = 1;
        }
        else if (t->balance > 0)
        {
            t->left->balance = -1;
            t->right->balance = 0;
        }
        else
        {
            t->left->balance = 0;
            t->right->balance = 0;
        }

        t->balance = 0;

        // set left_size to its correct value
        t->right->left_size -= t->left_size + 1;
        t->left_size += t->left->left_size + 1;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    bool sequence_kernel_1<T,mem_manager>::
    remove_least_element_in_tree (
        node*& t,
        T& item
    )
    {
        // make a reference to the current node so we don't have to dereference
        // a pointer a bunch of times
        node& tree = *t;

        // if the left tree is an empty tree
        if ( tree.left == 0)
        {
            // swap nodes element into item
            exchange(tree.item,item);

            // plug hole left by removing this node
            t = tree.right;

            // delete the node that was just removed
            tree.right = 0;
            delete_nodes(&tree);

            // return that the height of this part of the tree has decreased
            return true;
        }
        else
        {
            // subtract one from the left size
            --tree.left_size;

            // keep going left

            // if remove made the tree one height shorter
            if ( remove_least_element_in_tree(tree.left,item) )
            {
                // if this caused the current tree to strink then report that
                if ( tree.balance == -1)
                {
                    ++tree.balance;
                    return true;
                }
                else
                {
                    ++tree.balance;
                    return keep_node_balanced(t);
                }
            }

            return false;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    bool sequence_kernel_1<T,mem_manager>::
    add_to_tree (
        node*& t,
        unsigned long pos,
        T& item
    )
    {
        // if found place to add
        if (t == 0)
        {
            // create a node to add new item into
            t = pool.allocate();

            // make a reference to the current node so we don't have to dereference
            // a pointer a bunch of times
            node& tree = *t;

            // set left and right pointers to 0 to indicate that there are no
            // left or right subtrees
            tree.left = 0;
            tree.right = 0;
            tree.balance = 0;
            tree.left_size = 0;

            // put item into t
            exchange(item,tree.item);

            // indicate that the height of this tree has increased
            return true;
        }
        else  // keep looking for a place to add the new item
        {
            // make a reference to the current node so we don't have to dereference
            // a pointer a bunch of times
            node& tree = *t;
            signed char old_balance = tree.balance;

            // add the new item to whatever subtree it should go into
            if ( pos < tree.left_size + 1 )
            {
                tree.balance -= add_to_tree(tree.left,pos,item);
                ++tree.left_size;
            }
            else
                tree.balance += add_to_tree(tree.right,pos - tree.left_size - 1,item);

            // if the tree was balanced to start with
            if (old_balance == 0)
            {
                // if its not balanced anymore then it grew in height
                if (tree.balance != 0)
                    return true;
                else
                    return false;
            }
            else
            {
                // if the tree is now balanced then it didn't grow
                if (tree.balance == 0)
                {
                    return false;
                }
                else
                {
                    // if the tree needs to be balanced
                    if (tree.balance != old_balance)
                    {
                        return !keep_node_balanced(t);
                    }
                    // if there has been no change in the heights
                    else
                    {
                        return false;
                    }
                }
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    bool sequence_kernel_1<T,mem_manager>::
    remove_from_tree (
        node*& t,
        unsigned long pos,
        T& item
    )
    {

        // make a reference to the current node so we don't have to dereference
        // a pointer a bunch of times
        node& tree = *t;

        // if item is on the left
        if (pos < tree.left_size)
        {
            // adjust the left size
            --tree.left_size;

            // if the left side of the tree has the greatest height
            if (tree.balance == -1)
            {
                tree.balance += remove_from_tree(tree.left,pos,item);
                return !tree.balance;
            }
            else
            {
                tree.balance += remove_from_tree(tree.left,pos,item);
                return keep_node_balanced(t);
            }

        }
        // if item is found
        else if (pos == tree.left_size)
        {
            // if there is no left node
            if (tree.left == 0)
            {
                // swap nodes element into item
                exchange(tree.item,item);

                // plug hole left by removing this node and free memory
                t = tree.right;  // plug hole with right subtree

                // delete old node
                tree.right = 0;
                delete_nodes(&tree);

                // indicate that the height has changed
                return true;
            }
            // if there is no right node
            else if (tree.right == 0)
            {
                // swap nodes element into item
                exchange(tree.item,item);

                // plug hole left by removing this node and free memory
                t = tree.left;  // plug hole with left subtree

                // delete old node
                tree.left = 0;
                delete_nodes(&tree);

                // indicate that the height of this tree has changed
                return true;
            }
            // if there are both a left and right sub node
            else
            {
                // get an element that can replace the one being removed and do this
                // if it made the right subtree shrink by one
                if (remove_least_element_in_tree(tree.right,item))
                {
                    // adjust the tree height
                    --tree.balance;

                    // put the element into item copy and also plug the
                    // hole with the smallest element from the right.
                    exchange(item,tree.item);

                    // if the height of the current tree has dropped by one
                    if (tree.balance == 0)
                    {
                        return true;
                    }
                    else
                    {
                        return keep_node_balanced(t);
                    }
                }
                // else this remove did not effect the height of this tree
                else
                {
                    // put the element into item copy and also plug the
                    // hole with the smallest element from the right.
                    exchange(item,tree.item);

                    return false;
                }

            }
        }
        // if item is on the right
        else
        {

            // if the right side of the tree has the greatest height
            if (tree.balance == 1)
            {
                tree.balance -= remove_from_tree(tree.right,pos - tree.left_size - 1,item);
                return !tree.balance;
            }
            else
            {
                tree.balance -= remove_from_tree(tree.right,pos - tree.left_size - 1,item);
                return keep_node_balanced(t);
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    T& sequence_kernel_1<T,mem_manager>::
    return_reference (
        node* t,
        unsigned long pos
    )
    {
        while (true)
        {
            // if we have found the node
            if (pos == t->left_size)
                return t->item;

            if (pos < t->left_size)
            {
                // go left
                t = t->left;
            }
            else
            {
                // go right
                pos -= t->left_size+1;
                t = t->right;
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    const T& sequence_kernel_1<T,mem_manager>::
    return_reference (
        const node* t,
        unsigned long pos
    ) const
    {
        while (true)
        {
            // if we have found the node
            if (pos == t->left_size)
                return t->item;

            if (pos < t->left_size)
            {
                // go left
                t = t->left;
            }
            else
            {
                // go right
                pos -= t->left_size+1;
                t = t->right;
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    bool sequence_kernel_1<T,mem_manager>::
    keep_node_balanced (
        node*& t
    )
    {
        // make a reference to the current node so we don't have to dereference
        // a pointer a bunch of times
        node& tree = *t;

        // if tree does not need to be balanced then return false
        if (tree.balance == 0)
            return false;

        // if tree needs to be rotated left
        if (tree.balance == 2)
        {
            if (tree.right->balance >= 0)
                rotate_left(t);
            else
                double_rotate_left(t);
        }
        // else if the tree needs to be rotated right
        else if (tree.balance == -2)
        {
            if (tree.left->balance <= 0)
                rotate_right(t);
            else
                double_rotate_right(t);
        }

        if (t->balance == 0)
            return true;
        else
            return false;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void sequence_kernel_1<T,mem_manager>::
    delete_nodes (
        node* t
    )
    {
        if (t->left)
            delete_nodes(t->left);
        if (t->right)
            delete_nodes(t->right);
        pool.deallocate(t);
    }

// ----------------------------------------------------------------------------------------
}

#endif // DLIB_SEQUENCE_KERNEl_1_


dlib C++ Library - sequence_kernel_2.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SEQUENCE_KERNEl_2_
#define DLIB_SEQUENCE_KERNEl_2_

#include "sequence_kernel_abstract.h"
#include "../algs.h"
#include "../interfaces/enumerable.h"
#include "../interfaces/remover.h"
#include "../serialize.h"

namespace dlib
{

    template <
        typename T,
        typename mem_manager = default_memory_manager
        >
    class sequence_kernel_2 : public enumerable<T>,
                              public remover<T>
    {
        /*!
            INITIAL VALUE
                sequence_size   == 0
                at_start_       == true
                current_enumeration_node == 0

            CONVENTION
                sequence_size == the number of elements in the sequence

                at_start_ == at_start()
                (current_enumeration_node!=0) == current_element_valid()
                if (current_enumeration_node!=0) then
                    current_enumeration_node->item == element()
                    current_enumeration_pos == the position of the node pointed to by
                                               current_enumeration_node

                if ( sequence_size > 0 )
                {
                    current_node        == pointer to a node in the linked list and
                    current_node->right->right->... eventually == current_node and
                    current_node->left->left->... eventually == current_node and
                    current_pos         == the position in the sequence of
                                           current_node->item
                }

        !*/

        struct node {
            T item;
            node* right;
            node* left;
        };

        public:

            typedef T type;
            typedef mem_manager mem_manager_type;

            sequence_kernel_2 (
            ) :
                sequence_size(0),
                at_start_(true),
                current_enumeration_node(0)
            {}

            virtual ~sequence_kernel_2 (
            );

            inline void clear (
            );

            void add (
                unsigned long pos,
                T& item
            );

            void remove (
                unsigned long pos,
                T& item
            );

            void cat (
                sequence_kernel_2& item
            );

            const T& operator[] (
                unsigned long pos
            ) const;

            T& operator[] (
                unsigned long pos
            );

            void swap (
                sequence_kernel_2& item
            );

            // functions from the remover interface
            inline void remove_any (
                T& item
            );

            // functions from the enumerable interface
            inline unsigned long size (
            ) const;

            bool at_start (
            ) const;

            inline void reset (
            ) const;

            bool current_element_valid (
            ) const;

            const T& element (
            ) const;

            T& element (
            );

            bool move_next (
            ) const;

        private:

            void delete_nodes (
                node* current_node,
                unsigned long sequence_size
            );
            /*!
                requires
                    CONVENTION IS CORRECT
                ensures
                    all memory associated with the ring of nodes has been freed
            !*/

            void move_to_pos (
                node*& current_node,
                unsigned long& current_pos,
                unsigned long pos,
                unsigned long size
            ) const;
            /*!
                requires
                    everything in the CONVENTION is correct and
                    there is a node corresponding to pos in the CONVENTION and
                    0 <= pos < size
                ensures
                    current_pos == pos and
                    current_node->item is the item in the sequence associated with
                    position pos
            !*/

            // data members
            unsigned long sequence_size;
            mutable node* current_node;
            mutable unsigned long current_pos;
            mutable bool at_start_;
            mutable node* current_enumeration_node;
            mutable unsigned long current_enumeration_pos;

            // restricted functions
            sequence_kernel_2(sequence_kernel_2&);        // copy constructor
            sequence_kernel_2& operator=(sequence_kernel_2&); // assignment operator

    };

    template <
        typename T,
        typename mem_manager
        >
    inline void swap (
        sequence_kernel_2<T,mem_manager>& a,
        sequence_kernel_2<T,mem_manager>& b
    ) { a.swap(b); }

    template <
        typename T,
        typename mem_manager
        >
    void deserialize (
        sequence_kernel_2<T,mem_manager>& item,
        std::istream& in
    )
    {
        try
        {
            item.clear();
            unsigned long size;
            deserialize(size,in);
            T temp;
            for (unsigned long i = 0; i < size; ++i)
            {
                deserialize(temp,in);
                item.add(i,temp);
            }
        }
        catch (serialization_error e)
        {
            item.clear();
            throw serialization_error(e.info + "\n   while deserializing object of type sequence_kernel_2");
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    sequence_kernel_2<T,mem_manager>::
    ~sequence_kernel_2 (
    )
    {
        delete_nodes(current_node,sequence_size);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void sequence_kernel_2<T,mem_manager>::
    clear (
    )
    {
        if (sequence_size != 0)
        {
            delete_nodes(current_node,sequence_size);
            sequence_size = 0;
        }
        // reset the enumerator
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void sequence_kernel_2<T,mem_manager>::
    add (
        unsigned long pos,
        T& item
    )
    {
        // make new node and swap item into it
        node* new_node = new node;
        exchange(item,new_node->item);

        if (sequence_size > 0)
        {
            if (pos == sequence_size)
            {
                move_to_pos(current_node,current_pos,pos-1,sequence_size);

                node& n_node = *new_node;
                node& c_node = *current_node;

                // make new node point to the nodes to its left and right
                n_node.right = c_node.right;
                n_node.left  = current_node;

                // make the left node point back to new_node
                c_node.right->left = new_node;

                // make the right node point back to new_node
                c_node.right = new_node;
                current_pos = pos;

            }
            else
            {
                move_to_pos(current_node,current_pos,pos,sequence_size);

                node& n_node = *new_node;
                node& c_node = *current_node;

                // make new node point to the nodes to its left and right
                n_node.right = current_node;
                n_node.left  = c_node.left;

                // make the left node point back to new_node
                c_node.left->right = new_node;

                // make the right node point back to new_node
                c_node.left = new_node;
            }

        }
        else
        {
            current_pos = 0;
            new_node->left = new_node;
            new_node->right = new_node;
        }

        // make the new node the current node
        current_node = new_node;

        ++sequence_size;
        // reset the enumerator
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void sequence_kernel_2<T,mem_manager>::
    remove (
        unsigned long pos,
        T& item
    )
    {
        move_to_pos(current_node,current_pos,pos,sequence_size);
        node& c_node = *current_node;
        exchange(c_node.item,item);

        node* temp = current_node;

        // close up gap left by remove
        c_node.left->right = c_node.right;
        c_node.right->left = c_node.left;

        current_node = c_node.right;

        --sequence_size;

        delete temp;
        // reset the enumerator
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    const T& sequence_kernel_2<T,mem_manager>::
    operator[] (
        unsigned long pos
    ) const
    {
        move_to_pos(current_node,current_pos,pos,sequence_size);
        return current_node->item;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void sequence_kernel_2<T,mem_manager>::
    cat (
        sequence_kernel_2<T,mem_manager>& item
    )
    {
        if (item.sequence_size > 0)
        {
            if (sequence_size > 0)
            {
                // move both sequences to a convenient location
                move_to_pos(current_node,current_pos,0,sequence_size);
                item.move_to_pos (
                    item.current_node,
                    item.current_pos,
                    item.sequence_size-1,
                    item.sequence_size
                );

                // make copies of poitners
                node& item_right = *item.current_node->right;
                node& left = *current_node->left;

                item.current_node->right = current_node;
                current_node->left = item.current_node;

                left.right = &item_right;
                item_right.left = &left;

                // set sizes
                sequence_size += item.sequence_size;
                item.sequence_size = 0;
            }
            else
            {
                // *this is empty so just swap
                item.swap(*this);
            }
        }
        item.clear();
        // reset the enumerator
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    T& sequence_kernel_2<T,mem_manager>::
    operator[] (
        unsigned long pos
    )
    {
        move_to_pos(current_node,current_pos,pos,sequence_size);
        return current_node->item;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    unsigned long sequence_kernel_2<T,mem_manager>::
    size (
    ) const
    {
        return sequence_size;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void sequence_kernel_2<T,mem_manager>::
    swap (
        sequence_kernel_2<T,mem_manager>& item
    )
    {
        unsigned long   sequence_size_temp         = item.sequence_size;
        node*           current_node_temp          = item.current_node;
        unsigned long   current_pos_temp           = item.current_pos;
        bool            at_start_temp              = item.at_start_;
        node*           current_enumeration_node_temp = item.current_enumeration_node;
        unsigned long   current_enumeration_pos_temp = item.current_enumeration_pos;

        item.sequence_size  = sequence_size;
        item.current_node   = current_node;
        item.current_pos    = current_pos;
        item.at_start_      = at_start_;
        item.current_enumeration_node = current_enumeration_node;
        item.current_enumeration_pos = current_enumeration_pos;

        sequence_size   = sequence_size_temp;
        current_node    = current_node_temp;
        current_pos     = current_pos_temp;
        at_start_       = at_start_temp;
        current_enumeration_node = current_enumeration_node_temp;
        current_enumeration_pos = current_enumeration_pos_temp;
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // enumerable function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    bool sequence_kernel_2<T,mem_manager>::
    at_start (
    ) const
    {
        return at_start_;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void sequence_kernel_2<T,mem_manager>::
    reset (
    ) const
    {
        at_start_ = true;
        current_enumeration_node = 0;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    bool sequence_kernel_2<T,mem_manager>::
    current_element_valid (
    ) const
    {
        return (current_enumeration_node!=0);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    const T& sequence_kernel_2<T,mem_manager>::
    element (
    ) const
    {
        return current_enumeration_node->item;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    T& sequence_kernel_2<T,mem_manager>::
    element (
    )
    {
        return current_enumeration_node->item;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    bool sequence_kernel_2<T,mem_manager>::
    move_next (
    ) const
    {
        if (at_start_ && sequence_size>0)
        {
            move_to_pos(current_node,current_pos,0,sequence_size);
            current_enumeration_node = current_node;
            current_enumeration_pos = 0;
        }
        else if (current_enumeration_node!=0)
        {
            ++current_enumeration_pos;
            if (current_enumeration_pos<sequence_size)
            {
                current_enumeration_node = current_enumeration_node->right;
            }
            else
            {
                // we have reached the end of the sequence
                current_enumeration_node = 0;
            }
        }

        at_start_ = false;
        return (current_enumeration_node!=0);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // remover function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void sequence_kernel_2<T,mem_manager>::
    remove_any (
        T& item
    )
    {
        remove(0,item);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // private member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void sequence_kernel_2<T,mem_manager>::
    delete_nodes (
        node* current_node,
        unsigned long sequence_size
    )
    {
        node* temp;
        while (sequence_size)
        {
            temp = current_node->right;
            delete current_node;
            current_node = temp;
            --sequence_size;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void sequence_kernel_2<T,mem_manager>::
    move_to_pos (
        node*& current_node,
        unsigned long& current_pos,
        unsigned long pos,
        unsigned long size
    ) const
    {
        if ( current_pos > pos)
        {
            // number of hops in each direction needed to reach pos
            unsigned long right = size + pos - current_pos;
            unsigned long left = current_pos - pos;
            current_pos = pos;

            if (left < right)
            {
                // move left to position pos
                for (; left > 0; --left)
                    current_node = current_node->left;
            }
            else
            {
                // move left to position pos
                for (; right > 0; --right)
                    current_node = current_node->right;
            }
        }
        else if (current_pos != pos)
        {
            // number of hops in each direction needed to reach pos
            unsigned long right = pos - current_pos;
            unsigned long left = size - pos + current_pos;
            current_pos = pos;

            if (left < right)
            {
                // move left to position pos
                for (; left > 0; --left)
                    current_node = current_node->left;
            }
            else
            {
                // move left to position pos
                for (; right > 0; --right)
                    current_node = current_node->right;
            }
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SEQUENCE_KERNEl_2_


dlib C++ Library - sequence_kernel_c.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SEQUENCE_KERNEl_C_
#define DLIB_SEQUENCE_KERNEl_C_

#include "sequence_kernel_abstract.h"
#include "../algs.h"
#include "../assert.h"

namespace dlib
{

    template <
        typename seq_base
        >
    class sequence_kernel_c : public seq_base
    {
        typedef typename seq_base::type T;
    public:

        void add (
            unsigned long pos,
            T& item
        );

        void remove (
            unsigned long pos,
            T& item
        );

        const T& operator[] (
            unsigned long pos
        ) const;

        T& operator[] (
            unsigned long pos
        );

        void cat (
            sequence_kernel_c& item
        );

        const T& element (
        ) const;

        T& element (
        );

        void remove_any (
            T& item
        );

    };

    template <
        typename seq_base
        >
    inline void swap (
        sequence_kernel_c<seq_base>& a,
        sequence_kernel_c<seq_base>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename seq_base
        >
    void sequence_kernel_c<seq_base>::
    add(
        unsigned long pos,
        T& item
    )
    {

        // make sure requires clause is not broken
        DLIB_CASSERT(( pos <= this->size() ),
                "\tvoid sequence::add"
                << "\n\tpos must be >= 0 and <= size()"
                << "\n\tpos: " << pos
                << "\n\tsize(): " << this->size()
                << "\n\tthis: " << this
        );

        // call the real function
        seq_base::add(pos,item);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename seq_base
        >
    void sequence_kernel_c<seq_base>::
    cat (
        sequence_kernel_c<seq_base>& item
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(&item != this,
                "\tvoid sequence::cat"
                << "\n\tyou can't concatenate a sequence onto itself"
                << "\n\t&item: " << &item
                << "\n\tthis:  " << this
        );

        // call the real function
        seq_base::cat(item);

    }

// ----------------------------------------------------------------------------------------

    template <
        typename seq_base
        >
    void sequence_kernel_c<seq_base>::
    remove (
        unsigned long pos,
        T& item
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(( pos < this->size() ),
                "\tvoid sequence::remove"
                << "\n\tpos must be >= 0 and < size()"
                << "\n\tpos: " << pos
                << "\n\tsize(): " << this->size()
                << "\n\tthis: " << this
        );

        // call the real function
        seq_base::remove(pos,item);

    }

// ----------------------------------------------------------------------------------------

    template <
        typename seq_base
        >
    const typename seq_base::type& sequence_kernel_c<seq_base>::
    operator[] (
        unsigned long pos
    ) const
    {

        // make sure requires clause is not broken
        DLIB_CASSERT(( pos < this->size() ),
                "\tconst T& sequence::operator[]"
                << "\n\tpos must be >= 0 and < size()"
                << "\n\tpos: " << pos
                << "\n\tsize(): " << this->size()
                << "\n\tthis: " << this
        );

        // call the real function
        return seq_base::operator[](pos);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename seq_base
        >
    typename seq_base::type& sequence_kernel_c<seq_base>::
    operator[] (
        unsigned long pos
    )
    {

        // make sure requires clause is not broken
        DLIB_CASSERT(( pos < this->size() ),
                "\tT& sequence::operator[]"
                << "\n\tpos must be >= 0 and < size()"
                << "\n\tpos: " << pos
                << "\n\tsize(): " << this->size()
                << "\n\tthis: " << this
        );

        // call the real function
        return seq_base::operator[](pos);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename seq_base
        >
    const typename seq_base::type& sequence_kernel_c<seq_base>::
    element (
    ) const
    {
        DLIB_CASSERT(this->current_element_valid() == true,
                "\tconst T& sequence::element() const"
                << "\n\tyou can't access the current element if it doesn't exist"
                << "\n\tthis: " << this
        );

        return seq_base::element();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename seq_base
        >
    typename seq_base::type& sequence_kernel_c<seq_base>::
    element (
    )
    {
        DLIB_CASSERT(this->current_element_valid() == true,
                "\tT& sequence::element()"
                << "\n\tyou can't access the current element if it doesn't exist"
                << "\n\tthis: " << this
        );

        return seq_base::element();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename seq_base
        >
    void sequence_kernel_c<seq_base>::
    remove_any (
        T& item
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT( (this->size() > 0),
                 "\tvoid sequence::remove_any"
                 << "\n\tsize() must be greater than zero if something is going to be removed"
                 << "\n\tsize(): " << this->size()
                 << "\n\tthis:   " << this
        );

        // call the real function
        seq_base::remove_any(item);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SEQUENCE_KERNEl_C_


dlib C++ Library - sequence_sort_1.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SEQUENCE_SORt_1_
#define DLIB_SEQUENCE_SORt_1_

#include "sequence_sort_abstract.h"
#include "../algs.h"

namespace dlib
{

    template <
        typename seq_base
        >
    class sequence_sort_1 : public seq_base
    {
        typedef typename seq_base::type T;

    public:

        /*!
            this is a median of three version of the QuickSort algorithm and
            it sorts sequences of less than 30 elements with a selection sort
        !*/

        void sort (
        );

    private:

        void sort_this_sequence (
            seq_base& sequence
        );
        /*!
            ensures
                - each element in the sequence is < the element behind it
        !*/

        void selection_sort (
            seq_base& sequence
        );
        /*!
            ensures
                - sequence is sorted with a selection_sort
        !*/

    };

    template <
        typename seq_base
        >
    inline void swap (
        sequence_sort_1<seq_base>& a,
        sequence_sort_1<seq_base>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename seq_base
        >
    void sequence_sort_1<seq_base>::
    sort (
    )
    {
        if (this->size() > 1)
        {
            sort_this_sequence(*this);
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// private member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename seq_base
        >
    void sequence_sort_1<seq_base>::
    sort_this_sequence (
        seq_base& sequence
    )
    {
        if (sequence.size() < 30)
        {
            selection_sort(sequence);
        }
        else
        {
            seq_base left, right;
            T partition_element;

            sequence.remove(0,partition_element);

            dlib::median (
                partition_element,
                sequence[sequence.size()-1],
                sequence[(sequence.size()-1)/2]
            );

            // partition sequence into left and right
            T temp;
            while (sequence.size() > 0)
            {
                sequence.remove(0,temp);
                if (temp < partition_element)
                {
                    left.add(0,temp);
                }
                else
                {
                    right.add(0,temp);
                }
            }

            sort_this_sequence(left);
            sort_this_sequence(right);

            // combine left and right into sequence
            left.swap(sequence);
            sequence.add(sequence.size(),partition_element);
            sequence.cat(right);
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename seq_base
        >
    void sequence_sort_1<seq_base>::
    selection_sort (
        seq_base& sequence
    )
    {
        if (sequence.size() > 2)
        {
            T temp[29];
            unsigned long ssize = sequence.size();

            for (unsigned long i = 0; i < ssize; ++i)
                sequence.remove(0,temp[i]);

            unsigned long smallest;
            for (unsigned long i = 0; i < ssize - 1; ++i)
            {
                // find smallest element and swap into i
                smallest = i;
                for (unsigned long j = i+1; j < ssize; ++j)
                {
                    if (temp[j] < temp[smallest])
                        smallest = j;
                }
                exchange(temp[smallest],temp[i]);
            }

            for (unsigned long i = 0; i < ssize; ++i)
                sequence.add(i,temp[i]);
        }
        else if (sequence.size() == 2)
        {
            if (sequence[1] < sequence[0])
            {
                exchange(sequence[0],sequence[1]);
            }
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SEQUENCE_SORt_1_


dlib C++ Library - sequence_sort_2.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SEQUENCE_SORt_2_
#define DLIB_SEQUENCE_SORt_2_

#include "sequence_sort_abstract.h"
#include "../algs.h"
#include "../sort.h"

namespace dlib
{

    template <
        typename seq_base
        >
    class sequence_sort_2 : public seq_base
    {
        typedef typename seq_base::type T;

    public:

        /*!
            this is a version of the QuickSort algorithm
            this uses the dlib::qsort_array function
        !*/

        void sort (
        );

    };

    template <
        typename seq_base
        >
    inline void swap (
        sequence_sort_2<seq_base>& a,
        sequence_sort_2<seq_base>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename seq_base
        >
    void sequence_sort_2<seq_base>::
    sort (
    )
    {
        if (this->size() > 1)
        {
            dlib::qsort_array(*this,0,this->size()-1);
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SEQUENCE_SORt_2_


dlib C++ Library - server_http.cpp

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SERVER_HTTP_CPp_
#define DLIB_SERVER_HTTP_CPp_

#include "server_http.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    namespace http_impl
    {
        inline unsigned char to_hex( unsigned char x )
        {
            return x + (x > 9 ? ('A'-10) : '0');
        }

        const std::string urlencode( const std::string& s )
        {
            std::ostringstream os;

            for ( std::string::const_iterator ci = s.begin(); ci != s.end(); ++ci )
            {
                if ( (*ci >= 'a' && *ci <= 'z') ||
                     (*ci >= 'A' && *ci <= 'Z') ||
                     (*ci >= '0' && *ci <= '9') )
                { // allowed
                    os << *ci;
                }
                else if ( *ci == ' ')
                {
                    os << '+';
                }
                else
                {
                    os << '%' << to_hex(*ci >> 4) << to_hex(*ci % 16);
                }
            }

            return os.str();
        }

        inline unsigned char from_hex (
            unsigned char ch
        )
        {
            if (ch <= '9' && ch >= '0')
                ch -= '0';
            else if (ch <= 'f' && ch >= 'a')
                ch -= 'a' - 10;
            else if (ch <= 'F' && ch >= 'A')
                ch -= 'A' - 10;
            else
                ch = 0;
            return ch;
        }

        const std::string urldecode (
            const std::string& str
        )
        {
            using namespace std;
            string result;
            string::size_type i;
            for (i = 0; i < str.size(); ++i)
            {
                if (str[i] == '+')
                {
                    result += ' ';
                }
                else if (str[i] == '%' && str.size() > i+2)
                {
                    const unsigned char ch1 = from_hex(str[i+1]);
                    const unsigned char ch2 = from_hex(str[i+2]);
                    const unsigned char ch = (ch1 << 4) | ch2;
                    result += ch;
                    i += 2;
                }
                else
                {
                    result += str[i];
                }
            }
            return result;
        }

        void parse_url(
            std::string word,
            key_value_map& queries
        )
        /*!
            Parses the query string of a URL.  word should be the stuff that comes
            after the ? in the query URL.
        !*/
        {
            std::string::size_type pos;

            for (pos = 0; pos < word.size(); ++pos)
            {
                if (word[pos] == '&')
                    word[pos] = ' ';
            }

            std::istringstream sin(word);
            sin >> word;
            while (sin)
            {
                pos = word.find_first_of("=");
                if (pos != std::string::npos)
                {
                    std::string key = urldecode(word.substr(0,pos));
                    std::string value = urldecode(word.substr(pos+1));

                    queries[key] = value;
                }
                sin >> word;
            }
        }

        void read_with_limit(
            std::istream& in,
            std::string& buffer,
            int delim = '\n'
        )
        {
            using namespace std;
            const size_t max = 64*1024;
            buffer.clear();
            buffer.reserve(300);

            while (in.peek() != delim && in.peek() != '\n' && in.peek() != EOF && buffer.size() < max)
            {
                buffer += (char)in.get();
            }

            // if we quit the loop because the data is longer than expected or we hit EOF
            if (in.peek() == EOF)
                throw http_parse_error("HTTP field from client terminated incorrectly", 414);
            if (buffer.size() == max)
                throw http_parse_error("HTTP field from client is too long", 414);

            in.get();
            // eat any remaining whitespace
            if (delim == ' ')
            {
                while (in.peek() == ' ')
                    in.get();
            }
        }
    }

// ----------------------------------------------------------------------------------------

    unsigned long parse_http_request (
        std::istream& in,
        incoming_things& incoming,
        unsigned long max_content_length
    )
    {
        using namespace std;
        using namespace http_impl;
        read_with_limit(in, incoming.request_type, ' ');

        // get the path
        read_with_limit(in, incoming.path, ' ');

        // Get the HTTP/1.1 - Ignore for now...
        read_with_limit(in, incoming.protocol);

        key_value_map_ci& incoming_headers = incoming.headers;
        key_value_map& cookies          = incoming.cookies;
        std::string& path               = incoming.path;
        std::string& content_type       = incoming.content_type;
        unsigned long content_length = 0;

        string line;
        read_with_limit(in, line);
        string first_part_of_header;
        string::size_type position_of_double_point;
        // now loop over all the incoming_headers
        while (line != "\r")
        {
            position_of_double_point = line.find_first_of(':');
            if ( position_of_double_point != string::npos )
            {
                first_part_of_header = dlib::trim(line.substr(0, position_of_double_point));

                if ( !incoming_headers[first_part_of_header].empty() )
                    incoming_headers[ first_part_of_header ] += " ";
                incoming_headers[first_part_of_header] += dlib::trim(line.substr(position_of_double_point+1));

                // look for Content-Type:
                if (line.size() > 14 && strings_equal_ignore_case(line, "Content-Type:", 13))
                {
                    content_type = line.substr(14);
                    if (content_type[content_type.size()-1] == '\r')
                        content_type.erase(content_type.size()-1);
                }
                // look for Content-Length:
                else if (line.size() > 16 && strings_equal_ignore_case(line, "Content-Length:", 15))
                {
                    istringstream sin(line.substr(16));
                    sin >> content_length;
                    if (!sin)
                    {
                        throw http_parse_error("Invalid Content-Length of '" + line.substr(16) + "'", 411);
                    }

                    if (content_length > max_content_length)
                    {
                        std::ostringstream sout;
                        sout << "Content-Length of post back is too large.  It must be less than " << max_content_length;
                        throw http_parse_error(sout.str(), 413);
                    }
                }
                // look for any cookies
                else if (line.size() > 6 && strings_equal_ignore_case(line, "Cookie:", 7))
                {
                    string::size_type pos = 6;
                    string key, value;
                    bool seen_key_start = false;
                    bool seen_equal_sign = false;
                    while (pos + 1 < line.size())
                    {
                        ++pos;
                        // ignore whitespace between cookies
                        if (!seen_key_start && line[pos] == ' ')
                            continue;

                        seen_key_start = true;
                        if (!seen_equal_sign)
                        {
                            if (line[pos] == '=')
                            {
                                seen_equal_sign = true;
                            }
                            else
                            {
                                key += line[pos];
                            }
                        }
                        else
                        {
                            if (line[pos] == ';')
                            {
                                cookies[urldecode(key)] = urldecode(value);
                                seen_equal_sign = false;
                                seen_key_start = false;
                                key.clear();
                                value.clear();
                            }
                            else
                            {
                                value += line[pos];
                            }
                        }
                    }
                    if (key.size() > 0)
                    {
                        cookies[urldecode(key)] = urldecode(value);
                        key.clear();
                        value.clear();
                    }
                }
            } // no ':' in it!
            read_with_limit(in, line);
        } // while (line != "\r")

        // If there is data being posted back to us as a query string then
        // pick out the queries using parse_url.
        if ((strings_equal_ignore_case(incoming.request_type, "POST") ||
             strings_equal_ignore_case(incoming.request_type, "PUT")) &&
            strings_equal_ignore_case(left_substr(content_type,";"), "application/x-www-form-urlencoded"))
        {
            if (content_length > 0)
            {
                incoming.body.resize(content_length);
                in.read(&incoming.body[0],content_length);
            }
            parse_url(incoming.body, incoming.queries);
        }

        string::size_type pos = path.find_first_of("?");
        if (pos != string::npos)
        {
            parse_url(path.substr(pos+1), incoming.queries);
        }

        if (!in)
            throw http_parse_error("Error parsing HTTP request", 500);

        return content_length;
    }

// ----------------------------------------------------------------------------------------

    void read_body (
        std::istream& in,
        incoming_things& incoming
    )
    {
        // if the body hasn't already been loaded and there is data to load
        if (incoming.body.size() == 0 &&
            incoming.headers.count("Content-Length") != 0)
        {
            const unsigned long content_length = string_cast<unsigned long>(incoming.headers["Content-Length"]);

            incoming.body.resize(content_length);
            if (content_length > 0)
            {
                in.read(&incoming.body[0],content_length);
            }
        }
    }

// ----------------------------------------------------------------------------------------

    void write_http_response (
        std::ostream& out,
        outgoing_things outgoing,
        const std::string& result
    )
    {
        using namespace http_impl;
        key_value_map& new_cookies      = outgoing.cookies;
        key_value_map_ci& response_headers = outgoing.headers;

        // only send this header if the user hasn't told us to send another kind
        bool has_content_type = false, has_location = false;
        for(key_value_map_ci::const_iterator ci = response_headers.begin(); ci != response_headers.end(); ++ci )
        {
            if ( !has_content_type && strings_equal_ignore_case(ci->first , "content-type") )
            {
                has_content_type = true;
            }
            else if ( !has_location && strings_equal_ignore_case(ci->first , "location") )
            {
                has_location = true;
            }
        }

        if ( has_location )
        {
            outgoing.http_return = 302;
        }

        if ( !has_content_type )
        {
            response_headers["Content-Type"] = "text/html";
        }

        response_headers["Content-Length"] = cast_to_string(result.size());

        out << "HTTP/1.0 " << outgoing.http_return << " " << outgoing.http_return_status << "\r\n";

        // Set any new headers
        for(key_value_map_ci::const_iterator ci = response_headers.begin(); ci != response_headers.end(); ++ci )
        {
            out << ci->first << ": " << ci->second << "\r\n";
        }

        // set any cookies
        for(key_value_map::const_iterator ci = new_cookies.begin(); ci != new_cookies.end(); ++ci )
        {
            out << "Set-Cookie: " << urlencode(ci->first) << '=' << urlencode(ci->second) << "\r\n";
        }
        out << "\r\n" << result;
    }

// ----------------------------------------------------------------------------------------

    void write_http_response (
        std::ostream& out,
        const http_parse_error& e
    )
    {
        outgoing_things outgoing;
        outgoing.http_return = e.http_error_code;
        outgoing.http_return_status = e.what();
        write_http_response(out, outgoing, std::string("Error processing request: ") + e.what());
    }

// ----------------------------------------------------------------------------------------

    void write_http_response (
        std::ostream& out,
        const std::exception& e
    )
    {
        outgoing_things outgoing;
        outgoing.http_return = 500;
        outgoing.http_return_status = e.what();
        write_http_response(out, outgoing, std::string("Error processing request: ") + e.what());
    }

// ----------------------------------------------------------------------------------------

    const logger server_http::dlog("dlib.server_http");

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SERVER_HTTP_CPp_


dlib C++ Library - server_http.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net), Steven Van Ingelgem
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SERVER_HTTp_1_
#define DLIB_SERVER_HTTp_1_

#include "server_http_abstract.h"
#include <iostream>
#include <sstream>
#include <string>
#include <cctype>
#include <map>
#include "../logger.h"
#include "../string.h"
#include "server_iostream.h"

#ifdef  __INTEL_COMPILER
// ignore the bogus warning about hiding on_connect()
#pragma warning (disable: 1125)
#endif

#if _MSC_VER
#  pragma warning( disable: 4503 )
#endif // _MSC_VER

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class http_parse_error : public error
    {
    public:
        http_parse_error(const std::string& str, int http_error_code_):
            error(str),http_error_code(http_error_code_) {}

        const int http_error_code;
    };

// ----------------------------------------------------------------------------------------

    template <typename Key, typename Value, typename Comparer = std::less<Key> >
    class constmap : public std::map<Key, Value, Comparer>
    {
    public:
        const Value& operator[](const Key& k) const
        {
            static const Value dummy = Value();

            typename std::map<Key, Value, Comparer>::const_iterator ci = std::map<Key, Value, Comparer>::find(k);

            if ( ci == this->end() )
                return dummy;
            else
                return ci->second;
        }

        Value& operator[](const Key& k)
        {
            return std::map<Key, Value, Comparer>::operator [](k);
        }
    };

    class less_case_insensitive
    {
    public:
        bool operator()(const std::string& a, const std::string& b) const
        {
            unsigned long i = 0;
            while (i < a.size() && i < b.size())
            {
                const int cha = std::tolower(a[i]);
                const int chb = std::tolower(b[i]);
                if (cha < chb)
                    return true;
                else if (cha > chb)
                    return false;
                ++i;
            }
            if (a.size() < b.size())
                return true;
            else
                return false;
        }
    };
    typedef constmap< std::string, std::string, less_case_insensitive > key_value_map_ci;
    typedef constmap< std::string, std::string > key_value_map;

    struct incoming_things
    {
        incoming_things (
            const std::string& foreign_ip_,
            const std::string& local_ip_,
            unsigned short foreign_port_,
            unsigned short local_port_
        ):
            foreign_ip(foreign_ip_),
            foreign_port(foreign_port_),
            local_ip(local_ip_),
            local_port(local_port_)
        {}

        std::string path;
        std::string request_type;
        std::string content_type;
        std::string protocol;
        std::string body;

        key_value_map queries;
        key_value_map cookies;
        key_value_map_ci headers;

        std::string foreign_ip;
        unsigned short foreign_port;
        std::string local_ip;
        unsigned short local_port;
    };

    struct outgoing_things
    {
        outgoing_things() : http_return(200), http_return_status("OK") { }

        key_value_map  cookies;
        key_value_map_ci  headers;
        unsigned short http_return;
        std::string    http_return_status;
    };

// ----------------------------------------------------------------------------------------

    unsigned long parse_http_request (
        std::istream& in,
        incoming_things& incoming,
        unsigned long max_content_length
    );

    void read_body (
        std::istream& in,
        incoming_things& incoming
    );

    void write_http_response (
        std::ostream& out,
        outgoing_things outgoing,
        const std::string& result
    );

    void write_http_response (
        std::ostream& out,
        const http_parse_error& e
    );

    void write_http_response (
        std::ostream& out,
        const std::exception& e
    );

// ----------------------------------------------------------------------------------------

    class server_http : public server_iostream
    {

    public:

        server_http()
        {
            max_content_length = 10*1024*1024; // 10MB
        }

        unsigned long get_max_content_length (
        ) const
        {
            auto_mutex lock(http_class_mutex);
            return max_content_length;
        }

        void set_max_content_length (
            unsigned long max_length
        )
        {
            auto_mutex lock(http_class_mutex);
            max_content_length = max_length;
        }

    private:
        virtual const std::string on_request (
            const incoming_things& incoming,
            outgoing_things& outgoing
        ) = 0;

        virtual void on_connect (
            std::istream& in,
            std::ostream& out,
            const std::string& foreign_ip,
            const std::string& local_ip,
            unsigned short foreign_port,
            unsigned short local_port,
            uint64
        )
        {
            try
            {
                incoming_things incoming(foreign_ip, local_ip, foreign_port, local_port);
                outgoing_things outgoing;

                parse_http_request(in, incoming, get_max_content_length());
                read_body(in, incoming);
                const std::string& result = on_request(incoming, outgoing);
                write_http_response(out, outgoing, result);
            }
            catch (http_parse_error& e)
            {
                dlog << LERROR << "Error processing request from: " << foreign_ip << " - " << e.what();
                write_http_response(out, e);
            }
            catch (std::exception& e)
            {
                dlog << LERROR << "Error processing request from: " << foreign_ip << " - " << e.what();
                write_http_response(out, e);
            }
        }

        mutex http_class_mutex;
        unsigned long max_content_length;
        const static logger dlog;
    };

// ----------------------------------------------------------------------------------------

}

#ifdef NO_MAKEFILE
#include "server_http.cpp"
#endif

#endif // DLIB_SERVER_HTTp_1_


dlib C++ Library - server_iostream.cpp

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SERVER_IOSTREAM_CPp_
#define DLIB_SERVER_IOSTREAM_CPp_

#include "server_iostream.h"

namespace dlib
{
    const logger server_iostream::_dLog("dlib.server_iostream");
}

#endif // DLIB_SERVER_IOSTREAM_CPp_


dlib C++ Library - server_iostream.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SERVER_IOSTREAm_1_
#define DLIB_SERVER_IOSTREAm_1_

#include <iostream>
#include "server_iostream_abstract.h"
#include "../logger.h"
#include "../uintn.h"
#include "server_kernel.h"
#include "../sockstreambuf.h"
#include "../map.h"

namespace dlib
{

    class server_iostream : public server
    {

        /*!
            INITIAL VALUE
                - next_id == 0
                - con_map.size() == 0

            CONVENTION
                - next_id == the id of the next connection
                - for all current connections
                    - con_map[id] == the connection object with the given id
                - m == the mutex that protects the members of this object
        !*/

        typedef map<uint64,connection*,memory_manager<char>::kernel_2a>::kernel_1b id_map;

    public:
        server_iostream(
        ) :
            next_id(0)
        {}

        ~server_iostream(
        )
        {
            server::clear();
        }

    protected:

        void shutdown_connection (
            uint64 id
        )
        {
            auto_mutex M(m);
            if (con_map.is_in_domain(id))
            {
                con_map[id]->shutdown();
            }
        }

    private:

        virtual void on_connect (
            std::istream& in,
            std::ostream& out,
            const std::string& foreign_ip,
            const std::string& local_ip,
            unsigned short foreign_port,
            unsigned short local_port,
            uint64 connection_id
        )=0;

        void on_connect (
            connection& con
        )
        {
            bool my_fault = true;
            uint64 this_con_id;
            try
            {
                sockstreambuf buf(&con);
                std::istream in(&buf);
                std::ostream out(&buf);
                in.tie(&out);

                // add this connection to the con_map
                {
                    auto_mutex M(m);
                    this_con_id = next_id;
                    connection* this_con = &con;
                    con_map.add(this_con_id,this_con);
                    this_con_id = next_id;
                    ++next_id;
                }

                my_fault = false;
                on_connect(
                    in,
                    out,
                    con.get_foreign_ip(),
                    con.get_local_ip(),
                    con.get_foreign_port(),
                    con.get_local_port(),
                    this_con_id
                );

                // remove this connection from the con_map
                {
                    auto_mutex M(m);
                    connection* this_con;
                    uint64 junk;
                    con_map.remove(this_con_id,junk,this_con);
                }

            }
            catch (std::bad_alloc&)
            {
                // make sure we remove this connection from the con_map
                {
                    auto_mutex M(m);
                    if (con_map.is_in_domain(this_con_id))
                    {
                        connection* this_con;
                        uint64 junk;
                        con_map.remove(this_con_id,junk,this_con);
                    }
                }

                _dLog << LERROR << "We ran out of memory in server_iostream::on_connect()";
                // if this is an escaped exception from on_connect then let it fly!
                // Seriously though, this way it is obvious to the user that something bad happened
                // since they probably won't have the dlib logger enabled.
                if (!my_fault)
                    throw;
            }
        }

        uint64 next_id;
        id_map con_map;
        const static logger _dLog;
        mutex m;

    };

}

#ifdef NO_MAKEFILE
#include "server_iostream.cpp"
#endif

#endif // DLIB_SERVER_IOSTREAm_1_


dlib C++ Library - server_kernel.cpp

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SERVER_KERNEL_CPp_
#define DLIB_SERVER_KERNEL_CPp_

#include "server_kernel.h"
#include "../string.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    server::
    server (
    ) :
        listening_port(0),
        running(false),
        shutting_down(false),
        running_signaler(running_mutex),
        thread_count(0),
        thread_count_signaler(thread_count_mutex),
        max_connections(1000),
        thread_count_zero(thread_count_mutex),
        graceful_close_timeout(500)
    {
    }

// ----------------------------------------------------------------------------------------

    server::
    ~server (
    )
    {
        clear();
    }

// ----------------------------------------------------------------------------------------

    unsigned long server::
    get_graceful_close_timeout (
    ) const
    {
        auto_mutex lock(max_connections_mutex);
        return graceful_close_timeout;
    }

// ----------------------------------------------------------------------------------------

    void server::
    set_graceful_close_timeout (
        unsigned long timeout
    )
    {
        auto_mutex lock(max_connections_mutex);
        graceful_close_timeout = timeout;
    }

// ----------------------------------------------------------------------------------------

    int server::
    get_max_connections (
    ) const
    {
        max_connections_mutex.lock();
        int temp = max_connections;
        max_connections_mutex.unlock();
        return temp;
    }

// ----------------------------------------------------------------------------------------

    void server::
    set_max_connections (
        int max
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(
            max >= 0 ,
            "\tvoid server::set_max_connections"
            << "\n\tmax == " << max
            << "\n\tthis: " << this
            );

        max_connections_mutex.lock();
        max_connections = max;
        max_connections_mutex.unlock();
    }

// ----------------------------------------------------------------------------------------

    void server::
    clear (
    )
    {
        // signal that we are shutting down
        shutting_down_mutex.lock();
        shutting_down = true;
        shutting_down_mutex.unlock();

        max_connections_mutex.lock();
        listening_port_mutex.lock();
        listening_ip_mutex.lock();
        listening_ip = "";
        listening_port = 0;
        max_connections = 1000;
        graceful_close_timeout = 500;
        listening_port_mutex.unlock();
        listening_ip_mutex.unlock();
        max_connections_mutex.unlock();

        // tell all the connections to shut down
        cons_mutex.lock();
        connection* temp;
        while (cons.size() > 0)
        {
            cons.remove_any(temp);
            temp->shutdown();
        }
        cons_mutex.unlock();

        // wait for all the connections to shut down
        thread_count_mutex.lock();
        while (thread_count > 0)
        {
            thread_count_zero.wait();
        }
        thread_count_mutex.unlock();

        // wait for the listener to close
        running_mutex.lock();
        while (running == true)
        {
            running_signaler.wait();
        }
        running_mutex.unlock();

        // signal that the shutdown is complete
        shutting_down_mutex.lock();
        shutting_down = false;
        shutting_down_mutex.unlock();
    }

// ----------------------------------------------------------------------------------------

    void server::
    start_async_helper (
    )
    {
        try
        {
            start_accepting_connections();
        }
        catch (std::exception& e)
        {
            sdlog << LERROR << e.what();
        }
    }

// ----------------------------------------------------------------------------------------

    void server::
    start_async (
    )
    {
        auto_mutex lock(running_mutex);
        if (running)
            return;

        // Any exceptions likely to be thrown by the server are going to be
        // thrown when trying to bind the port.  So calling this here rather
        // than in the thread we are about to make will cause start_async()
        // to report errors back to the user in a very straight forward way.
        open_listening_socket();

        async_start_thread.reset(new thread_function(make_mfp(*this,&server::start_async_helper)));
    }

// ----------------------------------------------------------------------------------------

    void server::
    open_listening_socket (
    )
    {
        if (!sock)
        {
            int status = create_listener(sock,listening_port,listening_ip);
            const int port_used = listening_port;

            // if there was an error then clear this object
            if (status < 0)
            {
                max_connections_mutex.lock();
                listening_port_mutex.lock();
                listening_ip_mutex.lock();
                listening_ip = "";
                listening_port = 0;
                max_connections = 1000;
                graceful_close_timeout = 500;
                listening_port_mutex.unlock();
                listening_ip_mutex.unlock();
                max_connections_mutex.unlock();
            }

            // throw an exception for the error
            if (status == PORTINUSE)
            {
                throw dlib::socket_error(
                    EPORT_IN_USE,
                    "error occurred in server::start()\nport " + cast_to_string(port_used) + " already in use"
                );
            }
            else if (status == OTHER_ERROR)
            {
                throw dlib::socket_error(
                    "error occurred in server::start()\nunable to create listener"
                );
            }
        }

        running_mutex.lock();
        running = true;
        running_mutex.unlock();
    }

// ----------------------------------------------------------------------------------------

    void server::
    start (
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(
              this->is_running() == false,
            "\tvoid server::start"
            << "\n\tis_running() == " << this->is_running()
            << "\n\tthis: " << this
            );

        start_accepting_connections();

    }

// ----------------------------------------------------------------------------------------

    void server::
    start_accepting_connections (
    )
    {
        open_listening_socket();

        // determine the listening port
        bool port_assigned = false;
        listening_port_mutex.lock();
        if (listening_port == 0)
        {
            port_assigned = true;
            listening_port = sock->get_listening_port();
        }
        listening_port_mutex.unlock();
        if (port_assigned)
            on_listening_port_assigned();

        int status = 0;

        connection* client;
        bool exit = false;
        while ( true )
        {

            // accept the next connection
            status = sock->accept(client,1000);

            // if there was an error then quit the loop
            if (status == OTHER_ERROR)
            {
                break;
            }

            shutting_down_mutex.lock();
            // if we are shutting down then signal that we should quit the loop
            exit = shutting_down;
            shutting_down_mutex.unlock();

            // if we should be shutting down
            if (exit)
            {
                // if a connection was opened then close it
                if (status == 0)
                    delete client;
                break;
            }

            // if the accept timed out
            if (status == TIMEOUT)
            {
                continue;
            }

            // add this new connection to cons
            cons_mutex.lock();
            connection* client_temp = client;
            try{cons.add(client_temp);}
            catch(...)
            {
                sock.reset();
                delete client;
                cons_mutex.unlock();

                // signal that we are not running start() anymore
                running_mutex.lock();
                running = false;
                running_signaler.broadcast();
                running_mutex.unlock();

                clear();
                throw;
            }
            cons_mutex.unlock();

            // make a param structure
            param* temp = 0;
            try{
            temp = new param (
                            *this,
                            *client,
                            get_graceful_close_timeout()
                            );
            } catch (...)
            {
                sock.reset();
                delete client;
                running_mutex.lock();
                running = false;
                running_signaler.broadcast();
                running_mutex.unlock();
                clear();
                throw;
            }

            // if create_new_thread failed
            if (!create_new_thread(service_connection,temp))
            {
                delete temp;
                // close the listening socket
                sock.reset();

                // close the new connection and remove it from cons
                cons_mutex.lock();
                connection* ctemp;
                if (cons.is_member(client))
                {
                    cons.remove(client,ctemp);
                }
                delete client;
                cons_mutex.unlock();

                // signal that the listener has closed
                running_mutex.lock();
                running = false;
                running_signaler.broadcast();
                running_mutex.unlock();

                // make sure the object is cleared
                clear();

                // throw the exception
                throw dlib::thread_error(
                    ECREATE_THREAD,
                    "error occurred in server::start()\nunable to start thread"
                    );
            }
            // if we made the new thread then update thread_count
            else
            {
                // increment the thread count
                thread_count_mutex.lock();
                ++thread_count;
                if (thread_count == 0)
                    thread_count_zero.broadcast();
                thread_count_mutex.unlock();
            }

            // check if we have hit the maximum allowed number of connections
            max_connections_mutex.lock();
            // if max_connections is zero or the loop is ending then skip this
            if (max_connections != 0)
            {
                // wait for thread_count to be less than max_connections
                thread_count_mutex.lock();
                while (thread_count >= max_connections)
                {
                    max_connections_mutex.unlock();
                    thread_count_signaler.wait();
                    max_connections_mutex.lock();

                    // if we are shutting down the quit the loop
                    shutting_down_mutex.lock();
                    exit = shutting_down;
                    shutting_down_mutex.unlock();
                    if (exit)
                        break;
                }
                thread_count_mutex.unlock();
            }
            max_connections_mutex.unlock();

            if (exit)
            {
                break;
            }
        } //while ( true )

        // close the socket
        sock.reset();

        // signal that the listener has closed
        running_mutex.lock();
        running = false;
        running_signaler.broadcast();
        running_mutex.unlock();

        // if there was an error with accept then throw an exception
        if (status == OTHER_ERROR)
        {
            // make sure the object is cleared
            clear();

            // throw the exception
            throw dlib::socket_error(
             "error occurred in server::start()\nlistening socket returned error"
                );
        }
    }

// ----------------------------------------------------------------------------------------

    bool server::
    is_running (
    ) const
    {
        running_mutex.lock();
        bool temp = running;
        running_mutex.unlock();
        return temp;
    }

// ----------------------------------------------------------------------------------------

    const std::string server::
    get_listening_ip (
    ) const
    {
        listening_ip_mutex.lock();
        std::string ip(listening_ip);
        listening_ip_mutex.unlock();
        return ip;
    }

// ----------------------------------------------------------------------------------------

    int server::
    get_listening_port (
    ) const
    {
        listening_port_mutex.lock();
        int port = listening_port;
        listening_port_mutex.unlock();
        return port;
    }

// ----------------------------------------------------------------------------------------

    void server::
    set_listening_port (
        int port
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(
            ( port >= 0 &&
              this->is_running() == false ),
            "\tvoid server::set_listening_port"
            << "\n\tport         == " << port
            << "\n\tis_running() == " << this->is_running()
            << "\n\tthis: " << this
            );

        listening_port_mutex.lock();
        listening_port = port;
        listening_port_mutex.unlock();
    }

// ----------------------------------------------------------------------------------------

    void server::
    set_listening_ip (
        const std::string& ip
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(
            ( ( is_ip_address(ip) || ip == "" ) &&
              this->is_running() == false ),
            "\tvoid server::set_listening_ip"
            << "\n\tip           == " << ip
            << "\n\tis_running() == " << this->is_running()
            << "\n\tthis: " << this
            );

        listening_ip_mutex.lock();
        listening_ip = ip;
        listening_ip_mutex.unlock();
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // static member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    const logger server::sdlog("dlib.server");

    void server::
    service_connection(
        void* item
    )
    {
        param& p = *static_cast<param*>(item);

        p.the_server.on_connect(p.new_connection);

        // remove this connection from cons and close it
        p.the_server.cons_mutex.lock();
        connection* temp;
        if (p.the_server.cons.is_member(&p.new_connection))
            p.the_server.cons.remove(&p.new_connection,temp);
        p.the_server.cons_mutex.unlock();

        try{ close_gracefully(&p.new_connection, p.graceful_close_timeout); }
        catch (...) { sdlog << LERROR << "close_gracefully() threw"; }

        // decrement the thread count and signal if it is now zero
        p.the_server.thread_count_mutex.lock();
        --p.the_server.thread_count;
        p.the_server.thread_count_signaler.broadcast();
        if (p.the_server.thread_count == 0)
            p.the_server.thread_count_zero.broadcast();
        p.the_server.thread_count_mutex.unlock();

        delete &p;

    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SERVER_KERNEL_CPp_


dlib C++ Library - server_kernel.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SERVER_KERNEL_1_
#define DLIB_SERVER_KERNEL_1_

#include "server_kernel_abstract.h"

#include "../threads.h"
#include "../sockets.h"
#include <string>
#include "../algs.h"
#include "../set.h"
#include "../logger.h"
#include "../smart_pointers.h"

namespace dlib
{

    // These forward declarations are here so we can use them in the typedefs in the server
    // class.  The reason for this is for backwards compatibility with previous versions of
    // dlib.
    class server_http;
    class server_iostream;

    class server
    {

        /*!
            INITIAL VALUE
                listening_port          == 0
                listening_ip            == ""
                running                 == false
                shutting_down           == false
                cons.size()             == 0
                listening_port_mutex    == a mutex
                listening_ip_mutex      == a mutex
                running_mutex           == a mutex
                running_signaler        == a signaler associated with running_mutex
                shutting_down_mutex     == a mutex
                cons_mutex              == a mutex
                thread_count            == 0
                thread_count_mutex      == a mutex
                thread_count_signaler   == a signaler associated with thread_count_mutex
                thread_count_zero       == a signaler associated with thread_count_mutex
                max_connections         == 1000
                max_connections_mutex   == a mutex for max_connections and graceful_close_timeout
                graceful_close_timeout  == 500

            CONVENTION
                listening_port          == get_listening_port()
                listening_ip            == get_listening_ip()
                running                 == is_running()
                shutting_down           == true while clear() is running.  this
                                           bool is used to tell the thread blocked on
                                           accept that it should terminate
                cons                    == a set containing all open connections
                listening_port_mutex    == a mutex for listening_port
                listening_ip_mutex      == a mutex for listening_ip
                running_mutex           == a mutex for running
                running_signaler        == a signaler for running and
                                           is associated with running_mutex.  it is
                                           used to signal when running is false
                shutting_down_mutex     == a mutex for shutting_down
                cons_mutex              == a mutex for cons
                thread_count            == the number of threads currently running
                thread_count_mutex      == a mutex for thread_count
                thread_count_signaler   == a signaler for thread_count and
                                           is associated with thread_count_mutex.  it
                                           is used to signal when thread_count is
                                           decremented
                thread_count_zero       == a signaler for thread_count and
                                           is associated with thread_count_mutex.  it
                                           is used to signal when thread_count becomes
                                           zero
                max_connections         == get_max_connections()
                max_connections_mutex   == a mutex for max_connections
        !*/

        typedef set<connection*>::kernel_1a set_of_connections;

        // this structure is used to pass parameters to new threads
        struct param
        {
            param (
                server& server_,
                connection& new_connection_,
                unsigned long graceful_close_timeout_
            ) :
                the_server(server_),
                new_connection(new_connection_),
                graceful_close_timeout(graceful_close_timeout_)
            {}

            server& the_server;
            connection& new_connection;
            unsigned long graceful_close_timeout;
        };

        public:

            // These typedefs are here for backward compatibility with previous versions of dlib
            typedef     server kernel_1a;
            typedef     server kernel_1a_c;
            typedef     server_iostream iostream_1a;
            typedef     server_iostream iostream_1a_c;
            typedef     server_http http_1a;
            typedef     server_http http_1a_c;

            server(
            );

            virtual ~server(
            );

            void clear(
            );

            void start (
            );

            bool is_running (
            ) const;

            const std::string get_listening_ip (
            ) const;

            int get_listening_port (
            ) const;

            void set_listening_port (
                int port
            );

            void set_listening_ip (
                const std::string& ip
            );

            void set_max_connections (
                int max
            );

            int get_max_connections (
            ) const;

            void start_async (
            );

            void set_graceful_close_timeout (
                unsigned long timeout
            );

            unsigned long get_graceful_close_timeout (
            ) const;

        private:

            void start_async_helper (
            );

            void start_accepting_connections (
            );

            void open_listening_socket (
            );

            virtual void on_connect (
                connection& new_connection
            )=0;

            virtual void on_listening_port_assigned (
            ) {}

            const static logger sdlog;

            static void service_connection(
                void* item
            );
            /*!
                requires
                    item is a pointer to a param struct
                ensures
                    services the new connection
                    will take care of closing the connection and
                    adding the connection to cons when it first starts and
                    remove the connection from cons and signal that it has
                    done so when it ends
            !*/

            // data members
            int listening_port;
            std::string listening_ip;
            bool running;
            bool shutting_down;
            set_of_connections cons;
            mutex listening_port_mutex;
            mutex listening_ip_mutex;
            rmutex running_mutex;
            rsignaler running_signaler;
            mutex shutting_down_mutex;
            mutex cons_mutex;
            int thread_count;
            mutex thread_count_mutex;
            signaler thread_count_signaler;
            int max_connections;
            mutex max_connections_mutex;
            signaler thread_count_zero;
            scoped_ptr<thread_function> async_start_thread;
            scoped_ptr<listener> sock;
            unsigned long graceful_close_timeout;

            // restricted functions
            server(server&);
            server& operator= (
                server&
                );
    };

// ----------------------------------------------------------------------------------------

}

#ifdef NO_MAKEFILE
#include "server_kernel.cpp"
#endif

#endif // DLIB_SERVER_KERNEL_1_


dlib C++ Library - set_compare_1.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SET_COMPARe_1_
#define DLIB_SET_COMPARe_1_

#include "set_compare_abstract.h"

#include "../algs.h"

namespace dlib
{

    template <
        typename set_base
        >
    class set_compare_1 : public set_base
    {

        public:

            bool operator< (
                const set_compare_1& rhs
            ) const;

            bool operator== (
                const set_compare_1& rhs
            ) const;

    };

    template <
        typename set_base
        >
    inline void swap (
        set_compare_1<set_base>& a,
        set_compare_1<set_base>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename set_base
        >
    bool set_compare_1<set_base>::
    operator< (
        const set_compare_1<set_base>& rhs
    ) const
    {
        bool result = false;
        if (set_base::size() < rhs.size())
            result = true;

        if (set_base::size() == rhs.size())
        {
            rhs.reset();
            set_base::reset();
            while (rhs.move_next())
            {
                set_base::move_next();
                if (set_base::element() < rhs.element())
                {
                    result = true;
                    break;
                }
                else if (rhs.element() < set_base::element())
                {
                    break;
                }
            }
        }

        set_base::reset();
        rhs.reset();

        return result;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename set_base
        >
    bool set_compare_1<set_base>::
    operator== (
        const set_compare_1<set_base>& rhs
    ) const
    {
        bool result = true;
        if (set_base::size() != rhs.size())
            result = false;

        rhs.reset();
        set_base::reset();
        while (rhs.move_next() && set_base::move_next())
        {
            if (!(rhs.element() == set_base::element()))
            {
                result = false;
                break;
            }
        }

        set_base::reset();
        rhs.reset();

        return result;
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SET_COMPARe_1_


dlib C++ Library - set_kernel_1.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SET_KERNEl_1_
#define DLIB_SET_KERNEl_1_

#include "set_kernel_abstract.h"
#include "../algs.h"
#include "../interfaces/enumerable.h"
#include "../interfaces/remover.h"
#include "../serialize.h"

namespace dlib
{

    template <
        typename T,
        typename bst_base,
        typename mem_manager = default_memory_manager
        >
    class set_kernel_1 : public enumerable<const T>,
                         public asc_remover<T,typename bst_base::compare_type>
    {

        /*!
            REQUIREMENTS ON bst_base
                bst_base is instantiated with <domain=T,range=char> and
                implements binray_search_tree/binary_search_tree_kernel_abstract.h

            INITIAL VALUE
                bst has its initial value

            CONVENTION
                bst.size() == the number of elements in the set and
                the elements in the set are stored in bst
        !*/

        public:

            typedef T type;
            typedef typename bst_base::compare_type compare_type;
            typedef mem_manager mem_manager_type;

            set_kernel_1(
            )
            {
            }

            virtual ~set_kernel_1(
            )
            {}

            inline void clear(
            );

            inline void add (
                T& item
            );

            inline bool is_member (
                const T& item
            ) const;

            inline void remove (
                const T& item,
                T& item_copy
            );

            inline void destroy (
                const T& item
            );

            inline void swap (
                set_kernel_1& item
            );

            // functions from the remover interface
            inline void remove_any (
                T& item
            );

            // functions from the enumerable interface
            inline unsigned long size (
            ) const;

            inline bool at_start (
            ) const;

            inline void reset (
            ) const;

            inline bool current_element_valid (
            ) const;

            inline const T& element (
            ) const;

            inline const T& element (
            );

            inline bool move_next (
            ) const;

        private:

            bst_base bst;
            char junk;

            // restricted functions
            set_kernel_1(set_kernel_1&);
            set_kernel_1& operator=(set_kernel_1&);

    };

    template <
        typename T,
        typename bst_base,
        typename mem_manager
        >
    inline void swap (
        set_kernel_1<T,bst_base,mem_manager>& a,
        set_kernel_1<T,bst_base,mem_manager>& b
    ) { a.swap(b); }

    template <
        typename T,
        typename bst_base,
        typename mem_manager
        >
    void deserialize (
        set_kernel_1<T,bst_base,mem_manager>& item,
        std::istream& in
    )
    {
        try
        {
            item.clear();
            unsigned long size;
            deserialize(size,in);
            T temp;
            for (unsigned long i = 0; i < size; ++i)
            {
                deserialize(temp,in);
                item.add(temp);
            }
        }
        catch (serialization_error e)
        {
            item.clear();
            throw serialization_error(e.info + "\n   while deserializing object of type set_kernel_1");
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename bst_base,
        typename mem_manager
        >
    void set_kernel_1<T,bst_base,mem_manager>::
    clear (
    )
    {
        bst.clear();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename bst_base,
        typename mem_manager
        >
    void set_kernel_1<T,bst_base,mem_manager>::
    add (
        T& item
    )
    {
        bst.add(item,junk);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename bst_base,
        typename mem_manager
        >
    bool set_kernel_1<T,bst_base,mem_manager>::
    is_member(
        const T& item
    ) const
    {
        return (bst[item] != 0);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename bst_base,
        typename mem_manager
        >
    void set_kernel_1<T,bst_base,mem_manager>::
    remove_any (
        T& item
    )
    {
        bst.remove_any(item,junk);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename bst_base,
        typename mem_manager
        >
    void set_kernel_1<T,bst_base,mem_manager>::
    remove(
        const T& item,
        T& item_copy
    )
    {
        bst.remove(item,item_copy,junk);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename bst_base,
        typename mem_manager
        >
    void set_kernel_1<T,bst_base,mem_manager>::
    destroy(
        const T& item
    )
    {
        bst.destroy(item);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename bst_base,
        typename mem_manager
        >
    unsigned long set_kernel_1<T,bst_base,mem_manager>::
    size (
    ) const
    {
        return bst.size();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename bst_base,
        typename mem_manager
        >
    void set_kernel_1<T,bst_base,mem_manager>::
    swap (
        set_kernel_1<T,bst_base,mem_manager>& item
    )
    {
        bst.swap(item.bst);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // enumerable function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename bst_base,
        typename mem_manager
        >
    bool set_kernel_1<T,bst_base,mem_manager>::
    at_start (
    ) const
    {
        return bst.at_start();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename bst_base,
        typename mem_manager
        >
    void set_kernel_1<T,bst_base,mem_manager>::
    reset (
    ) const
    {
        bst.reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename bst_base,
        typename mem_manager
        >
    bool set_kernel_1<T,bst_base,mem_manager>::
    current_element_valid (
    ) const
    {
        return bst.current_element_valid();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename bst_base,
        typename mem_manager
        >
    const T& set_kernel_1<T,bst_base,mem_manager>::
    element (
    ) const
    {
        return bst.element().key();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename bst_base,
        typename mem_manager
        >
    const T& set_kernel_1<T,bst_base,mem_manager>::
    element (
    )
    {
        return bst.element().key();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename bst_base,
        typename mem_manager
        >
    bool set_kernel_1<T,bst_base,mem_manager>::
    move_next (
    ) const
    {
        return bst.move_next();
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SET_KERNEl_1_


dlib C++ Library - set_kernel_c.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SET_KERNEl_C_
#define DLIB_SET_KERNEl_C_

#include "set_kernel_abstract.h"
#include "../algs.h"
#include "../assert.h"

namespace dlib
{

    template <
        typename set_base
        >
    class set_kernel_c : public set_base
    {
        typedef typename set_base::type T;
    public:

        void add (
            T& item
        );

        void remove_any (
            T& item
        );

        void remove (
            const T& item,
            T& item_copy
        );

        void destroy (
            const T& item
        );

        const T& element (
        );

        const T& element (
        ) const;
    };

    template <
        typename set_base
        >
    inline void swap (
        set_kernel_c<set_base>& a,
        set_kernel_c<set_base>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename set_base
        >
    void set_kernel_c<set_base>::
    add(
        T& item
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT( !this->is_member(item),
                 "\tvoid set::add"
                 << "\n\titem being added must not already be in the set"
                 << "\n\tthis: " << this
        );

        // call the real function
        set_base::add(item);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename set_base
        >
    void set_kernel_c<set_base>::
    remove (
        const T& item,
        T& item_copy
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT( this->is_member(item) &&
                 (static_cast<const void*>(&item) != static_cast<void*>(&item_copy)),
                 "\tvoid set::remove"
                 << "\n\titem should be in the set if it's going to be removed"
                 << "\n\tthis:            " << this
                 << "\n\t&item:           " << &item
                 << "\n\t&item_copy:      " << &item_copy
                 << "\n\tis_member(item): " << (this->is_member(item)?"true":"false")
        );

        // call the real function
        set_base::remove(item,item_copy);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename set_base
        >
    void set_kernel_c<set_base>::
    destroy (
        const T& item
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT( this->is_member(item),
                 "\tvoid set::destroy"
                 << "\n\titem should be in the set if it's going to be removed"
                 << "\n\tthis:            " << this
                 << "\n\t&item:           " << &item
        );

        // call the real function
        set_base::destroy(item);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename set_base
        >
    void set_kernel_c<set_base>::
    remove_any (
        T& item
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT( this->size() != 0,
                 "\tvoid set::remove_any"
                 << "\n\tsize must be greater than zero if an item is to be removed"
                 << "\n\tthis: " << this
        );

        // call the real function
        set_base::remove_any(item);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename set_base
        >
    const typename set_base::type& set_kernel_c<set_base>::
    element (
    ) const
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(this->current_element_valid() == true,
                "\tconst T& set::element() const"
                << "\n\tyou can't access the current element if it doesn't exist"
                << "\n\tthis: " << this
        );

        // call the real function
        return set_base::element();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename set_base
        >
    const typename set_base::type& set_kernel_c<set_base>::
    element (
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(this->current_element_valid() == true,
                "\tconst T& set::element"
                << "\n\tyou can't access the current element if it doesn't exist"
                << "\n\tthis: " << this
        );

        // call the real function
        return set_base::element();
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SET_KERNEl_C_


dlib C++ Library - set_utils.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SET_UTILs_
#define DLIB_SET_UTILs_

#include "../algs.h"
#include "set_utils_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename U
        >
    unsigned long set_intersection_size (
        const T& a,
        const U& b
    )
    {
        if (is_same_object(a,b))
            return a.size();

        unsigned long num = 0;

        if (a.size() < b.size())
        {
            a.reset();
            while (a.move_next())
            {
                if (b.is_member(a.element()))
                    ++num;
            }
        }
        else
        {
            b.reset();
            while (b.move_next())
            {
                if (a.is_member(b.element()))
                    ++num;
            }
        }

        return num;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename U,
        typename V
        >
    void set_union (
        const T& a,
        const U& b,
        V& u
    )
    {
        typedef typename T::type type;
        if (is_same_object(a,u) || is_same_object(b,u))
        {
            V local_u;
            type temp;
            a.reset();
            while (a.move_next())
            {
                temp = a.element();
                local_u.add(temp);
            }

            b.reset();
            while (b.move_next())
            {
                if (a.is_member(b.element()) == false)
                {
                    temp = b.element();
                    local_u.add(temp);
                }
            }

            local_u.swap(u);
        }
        else
        {
            u.clear();

            type temp;
            a.reset();
            while (a.move_next())
            {
                temp = a.element();
                u.add(temp);
            }

            b.reset();
            while (b.move_next())
            {
                if (a.is_member(b.element()) == false)
                {
                    temp = b.element();
                    u.add(temp);
                }
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename U,
        typename V
        >
    void set_intersection (
        const T& a,
        const U& b,
        V& i
    )
    {
        typedef typename T::type type;
        if (is_same_object(a,i) || is_same_object(b,i))
        {
            V local_i;

            type temp;

            if (a.size() < b.size())
            {
                a.reset();
                while (a.move_next())
                {
                    if (b.is_member(a.element()))
                    {
                        temp = a.element();
                        local_i.add(temp);
                    }
                }
            }
            else
            {
                b.reset();
                while (b.move_next())
                {
                    if (a.is_member(b.element()))
                    {
                        temp = b.element();
                        local_i.add(temp);
                    }
                }
            }

            local_i.swap(i);
        }
        else
        {
            i.clear();
            type temp;

            if (a.size() < b.size())
            {
                a.reset();
                while (a.move_next())
                {
                    if (b.is_member(a.element()))
                    {
                        temp = a.element();
                        i.add(temp);
                    }
                }
            }
            else
            {
                b.reset();
                while (b.move_next())
                {
                    if (a.is_member(b.element()))
                    {
                        temp = b.element();
                        i.add(temp);
                    }
                }
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename U,
        typename V
        >
    void set_difference (
        const T& a,
        const U& b,
        V& d
    )
    {
        typedef typename T::type type;
        if (is_same_object(a,d) || is_same_object(b,d))
        {
            V local_d;

            type temp;

            a.reset();
            while (a.move_next())
            {
                if (b.is_member(a.element()) == false)
                {
                    temp = a.element();
                    local_d.add(temp);
                }
            }

            local_d.swap(d);
        }
        else
        {
            d.clear();
            type temp;

            a.reset();
            while (a.move_next())
            {
                if (b.is_member(a.element()) == false)
                {
                    temp = a.element();
                    d.add(temp);
                }
            }
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SET_UTILs_


dlib C++ Library - simd4f.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_sIMD4F_Hh_
#define DLIB_sIMD4F_Hh_

#include "simd_check.h"
#include "simd4i.h"
#include <cmath>
#include <iostream>

namespace dlib
{

#ifdef DLIB_HAVE_SSE2
    class simd4f
    {
    public:
        typedef float type;

        inline simd4f() {}
        inline simd4f(float f) { x = _mm_set1_ps(f); }
        inline simd4f(float r0, float r1, float r2, float r3) { x = _mm_setr_ps(r0,r1,r2,r3); }
        inline simd4f(const __m128& val):x(val) {}
        inline simd4f(const simd4i& val):x(_mm_cvtepi32_ps(val)) {}

        inline simd4f& operator=(const simd4i& val)
        {
            x = simd4f(val);
            return *this;
        }

        inline simd4f& operator=(const float& val)
        {
            x = simd4f(val);
            return *this;
        }

        inline simd4f& operator=(const __m128& val)
        {
            x = val;
            return *this;
        }

        inline operator __m128() const { return x; }

        // truncate to 32bit integers
        inline operator __m128i() const { return _mm_cvttps_epi32(x); }

        inline void load_aligned(const type* ptr)  { x = _mm_load_ps(ptr); }
        inline void store_aligned(type* ptr) const { _mm_store_ps(ptr, x); }
        inline void load(const type* ptr)          { x = _mm_loadu_ps(ptr); }
        inline void store(type* ptr)         const { _mm_storeu_ps(ptr, x); }

        inline unsigned int size() const { return 4; }
        inline float operator[](unsigned int idx) const
        {
            float temp[4];
            store(temp);
            return temp[idx];
        }

    private:
        __m128 x;
    };

    class simd4f_bool
    {
    public:
        typedef float type;

        inline simd4f_bool() {}
        inline simd4f_bool(const __m128& val):x(val) {}

        inline simd4f_bool& operator=(const __m128& val)
        {
            x = val;
            return *this;
        }

        inline operator __m128() const { return x; }

    private:
        __m128 x;
    };
#else
    class simd4f
    {
    public:
        typedef float type;

        inline simd4f() {}
        inline simd4f(float f) { x[0]=f; x[1]=f; x[2]=f; x[3]=f; }
        inline simd4f(float r0, float r1, float r2, float r3) { x[0]=r0; x[1]=r1; x[2]=r2; x[3]=r3;}
        inline simd4f(const simd4i& val) { x[0]=val[0]; x[1]=val[1]; x[2]=val[2]; x[3]=val[3];}

        // truncate to 32bit integers
        inline operator simd4i::rawarray() const
        {
            simd4i::rawarray temp;
            temp.a[0] = (int32)x[0];
            temp.a[1] = (int32)x[1];
            temp.a[2] = (int32)x[2];
            temp.a[3] = (int32)x[3];
            return temp;
        }

        inline simd4f& operator=(const float& val)
        {
            *this = simd4f(val);
            return *this;
        }

        inline simd4f& operator=(const simd4i& val)
        {
            x[0] = val[0];
            x[1] = val[1];
            x[2] = val[2];
            x[3] = val[3];
            return *this;
        }

        inline void load_aligned(const type* ptr)
        {
            x[0] = ptr[0];
            x[1] = ptr[1];
            x[2] = ptr[2];
            x[3] = ptr[3];
        }

        inline void store_aligned(type* ptr) const
        {
            ptr[0] = x[0];
            ptr[1] = x[1];
            ptr[2] = x[2];
            ptr[3] = x[3];
        }

        inline void load(const type* ptr)
        {
            x[0] = ptr[0];
            x[1] = ptr[1];
            x[2] = ptr[2];
            x[3] = ptr[3];
        }

        inline void store(type* ptr) const
        {
            ptr[0] = x[0];
            ptr[1] = x[1];
            ptr[2] = x[2];
            ptr[3] = x[3];
        }

        inline unsigned int size() const { return 4; }
        inline float operator[](unsigned int idx) const { return x[idx]; }

    private:
        float x[4];
    };

    class simd4f_bool
    {
    public:
        typedef float type;

        inline simd4f_bool() {}
        inline simd4f_bool(bool r0, bool r1, bool r2, bool r3) { x[0]=r0; x[1]=r1; x[2]=r2; x[3]=r3;}

        inline bool operator[](unsigned int idx) const { return x[idx]; }
    private:
        bool x[4];
    };
#endif

// ----------------------------------------------------------------------------------------

    inline std::ostream& operator<<(std::ostream& out, const simd4f& item)
    {
        float temp[4];
        item.store(temp);
        out << "(" << temp[0] << ", " << temp[1] << ", " << temp[2] << ", " << temp[3] << ")";
        return out;
    }

// ----------------------------------------------------------------------------------------

    inline simd4f operator+ (const simd4f& lhs, const simd4f& rhs)
    {
#ifdef DLIB_HAVE_SSE2
        return _mm_add_ps(lhs, rhs);
#else
        return simd4f(lhs[0]+rhs[0],
                      lhs[1]+rhs[1],
                      lhs[2]+rhs[2],
                      lhs[3]+rhs[3]);
#endif
    }
    inline simd4f& operator+= (simd4f& lhs, const simd4f& rhs)
    { return lhs = lhs + rhs; return lhs;}

// ----------------------------------------------------------------------------------------

    inline simd4f operator- (const simd4f& lhs, const simd4f& rhs)
    {
#ifdef DLIB_HAVE_SSE2
        return _mm_sub_ps(lhs, rhs);
#else
        return simd4f(lhs[0]-rhs[0],
                      lhs[1]-rhs[1],
                      lhs[2]-rhs[2],
                      lhs[3]-rhs[3]);
#endif
    }
    inline simd4f& operator-= (simd4f& lhs, const simd4f& rhs)
    { return lhs = lhs - rhs; return lhs;}

// ----------------------------------------------------------------------------------------

    inline simd4f operator* (const simd4f& lhs, const simd4f& rhs)
    {
#ifdef DLIB_HAVE_SSE2
        return _mm_mul_ps(lhs, rhs);
#else
        return simd4f(lhs[0]*rhs[0],
                      lhs[1]*rhs[1],
                      lhs[2]*rhs[2],
                      lhs[3]*rhs[3]);
#endif
    }
    inline simd4f& operator*= (simd4f& lhs, const simd4f& rhs)
    { return lhs = lhs * rhs; return lhs;}

// ----------------------------------------------------------------------------------------

    inline simd4f operator/ (const simd4f& lhs, const simd4f& rhs)
    {
#ifdef DLIB_HAVE_SSE2
        return _mm_div_ps(lhs, rhs);
#else
        return simd4f(lhs[0]/rhs[0],
                      lhs[1]/rhs[1],
                      lhs[2]/rhs[2],
                      lhs[3]/rhs[3]);
#endif
    }
    inline simd4f& operator/= (simd4f& lhs, const simd4f& rhs)
    { return lhs = lhs / rhs; return lhs;}

// ----------------------------------------------------------------------------------------

    inline simd4f_bool operator== (const simd4f& lhs, const simd4f& rhs)
    {
#ifdef DLIB_HAVE_SSE2
        return _mm_cmpeq_ps(lhs, rhs);
#else
        return simd4f_bool(lhs[0]==rhs[0],
                           lhs[1]==rhs[1],
                           lhs[2]==rhs[2],
                           lhs[3]==rhs[3]);
#endif
    }

// ----------------------------------------------------------------------------------------

    inline simd4f_bool operator!= (const simd4f& lhs, const simd4f& rhs)
    {
#ifdef DLIB_HAVE_SSE2
        return _mm_cmpneq_ps(lhs, rhs);
#else
        return simd4f_bool(lhs[0]!=rhs[0],
                           lhs[1]!=rhs[1],
                           lhs[2]!=rhs[2],
                           lhs[3]!=rhs[3]);
#endif
    }

// ----------------------------------------------------------------------------------------

    inline simd4f_bool operator< (const simd4f& lhs, const simd4f& rhs)
    {
#ifdef DLIB_HAVE_SSE2
        return _mm_cmplt_ps(lhs, rhs);
#else
        return simd4f_bool(lhs[0]<rhs[0],
                           lhs[1]<rhs[1],
                           lhs[2]<rhs[2],
                           lhs[3]<rhs[3]);
#endif
    }

// ----------------------------------------------------------------------------------------

    inline simd4f_bool operator> (const simd4f& lhs, const simd4f& rhs)
    {
        return rhs < lhs;
    }

// ----------------------------------------------------------------------------------------

    inline simd4f_bool operator<= (const simd4f& lhs, const simd4f& rhs)
    {
#ifdef DLIB_HAVE_SSE2
        return _mm_cmple_ps(lhs, rhs);
#else
        return simd4f_bool(lhs[0]<=rhs[0],
                           lhs[1]<=rhs[1],
                           lhs[2]<=rhs[2],
                           lhs[3]<=rhs[3]);
#endif
    }

// ----------------------------------------------------------------------------------------

    inline simd4f_bool operator>= (const simd4f& lhs, const simd4f& rhs)
    {
        return rhs <= lhs;
    }

// ----------------------------------------------------------------------------------------

    inline simd4f min (const simd4f& lhs, const simd4f& rhs)
    {
#ifdef DLIB_HAVE_SSE2
        return _mm_min_ps(lhs, rhs);
#else
        return simd4f(std::min(lhs[0],rhs[0]),
                      std::min(lhs[1],rhs[1]),
                      std::min(lhs[2],rhs[2]),
                      std::min(lhs[3],rhs[3]));
#endif
    }

// ----------------------------------------------------------------------------------------

    inline simd4f max (const simd4f& lhs, const simd4f& rhs)
    {
#ifdef DLIB_HAVE_SSE2
        return _mm_max_ps(lhs, rhs);
#else
        return simd4f(std::max(lhs[0],rhs[0]),
                      std::max(lhs[1],rhs[1]),
                      std::max(lhs[2],rhs[2]),
                      std::max(lhs[3],rhs[3]));
#endif
    }

// ----------------------------------------------------------------------------------------

    inline simd4f reciprocal (const simd4f& item)
    {
#ifdef DLIB_HAVE_SSE2
        return _mm_rcp_ps(item);
#else
        return simd4f(1.0f/item[0],
                      1.0f/item[1],
                      1.0f/item[2],
                      1.0f/item[3]);
#endif
    }

// ----------------------------------------------------------------------------------------

    inline simd4f reciprocal_sqrt (const simd4f& item)
    {
#ifdef DLIB_HAVE_SSE2
        return _mm_rsqrt_ps(item);
#else
        return simd4f(1.0f/std::sqrt(item[0]),
                      1.0f/std::sqrt(item[1]),
                      1.0f/std::sqrt(item[2]),
                      1.0f/std::sqrt(item[3]));
#endif
    }

// ----------------------------------------------------------------------------------------

    inline float dot(const simd4f& lhs, const simd4f& rhs);
    inline float sum(const simd4f& item)
    {
#ifdef DLIB_HAVE_SSE41
        return dot(simd4f(1), item);
#elif defined(DLIB_HAVE_SSE3)
        simd4f temp = _mm_hadd_ps(item,item);
        return _mm_cvtss_f32(_mm_hadd_ps(temp,temp));
#elif defined(DLIB_HAVE_SSE2) && (!defined(_MSC_VER) || _MSC_VER!=1400)
        simd4f temp = _mm_add_ps(item,_mm_movehl_ps(item,item));
        simd4f temp2 = _mm_shuffle_ps(temp,temp,1);
        return _mm_cvtss_f32(_mm_add_ss(temp,temp2));
#else
        return item[0]+item[1]+item[2]+item[3];
#endif
    }

// ----------------------------------------------------------------------------------------

    inline float dot(const simd4f& lhs, const simd4f& rhs)
    {
#ifdef DLIB_HAVE_SSE41
        return _mm_cvtss_f32(_mm_dp_ps(lhs, rhs, 0xff));
#else
        return sum(lhs*rhs);
#endif
    }

// ----------------------------------------------------------------------------------------

    inline simd4f sqrt(const simd4f& item)
    {
#ifdef DLIB_HAVE_SSE2
        return _mm_sqrt_ps(item);
#else
        return simd4f(std::sqrt(item[0]),
                      std::sqrt(item[1]),
                      std::sqrt(item[2]),
                      std::sqrt(item[3]));
#endif
    }

// ----------------------------------------------------------------------------------------

    inline simd4f ceil(const simd4f& item)
    {
#ifdef DLIB_HAVE_SSE41
        return _mm_ceil_ps(item);
#elif defined(DLIB_HAVE_SSE2)
        float temp[4];
        item.store(temp);
        temp[0] = std::ceil(temp[0]);
        temp[1] = std::ceil(temp[1]);
        temp[2] = std::ceil(temp[2]);
        temp[3] = std::ceil(temp[3]);
        simd4f temp2;
        temp2.load(temp);
        return temp2;
#else
        return simd4f(std::ceil(item[0]),
                      std::ceil(item[1]),
                      std::ceil(item[2]),
                      std::ceil(item[3]));
#endif
    }

// ----------------------------------------------------------------------------------------

    inline simd4f floor(const simd4f& item)
    {
#ifdef DLIB_HAVE_SSE41
        return _mm_floor_ps(item);
#elif defined(DLIB_HAVE_SSE2)
        float temp[4];
        item.store(temp);
        temp[0] = std::floor(temp[0]);
        temp[1] = std::floor(temp[1]);
        temp[2] = std::floor(temp[2]);
        temp[3] = std::floor(temp[3]);
        simd4f temp2;
        temp2.load(temp);
        return temp2;
#else
        return simd4f(std::floor(item[0]),
                      std::floor(item[1]),
                      std::floor(item[2]),
                      std::floor(item[3]));
#endif
    }

// ----------------------------------------------------------------------------------------

    // perform cmp ? a : b
    inline simd4f select(const simd4f_bool& cmp, const simd4f& a, const simd4f& b)
    {
#ifdef DLIB_HAVE_SSE41
        return _mm_blendv_ps(b,a,cmp);
#elif defined(DLIB_HAVE_SSE2)
        return _mm_or_ps(_mm_and_ps(cmp,a) , _mm_andnot_ps(cmp,b));
#else
        return simd4f(cmp[0]?a[0]:b[0],
                      cmp[1]?a[1]:b[1],
                      cmp[2]?a[2]:b[2],
                      cmp[3]?a[3]:b[3]);
#endif
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_sIMD4F_Hh_


dlib C++ Library - simd4i.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_sIMD4I_Hh_
#define DLIB_sIMD4I_Hh_

#include "simd_check.h"
#include "../uintn.h"

namespace dlib
{

#ifdef DLIB_HAVE_SSE2
    class simd4i
    {
    public:
        typedef int32 type;

        inline simd4i() {}
        inline simd4i(int32 f) { x = _mm_set1_epi32(f); }
        inline simd4i(int32 r0, int32 r1, int32 r2, int32 r3) { x = _mm_setr_epi32(r0,r1,r2,r3); }
        inline simd4i(const __m128i& val):x(val) {}

        inline simd4i& operator=(const __m128i& val)
        {
            x = val;
            return *this;
        }

        inline operator __m128i() const { return x; }

        inline void load_aligned(const type* ptr)  { x = _mm_load_si128((const __m128i*)ptr); }
        inline void store_aligned(type* ptr) const { _mm_store_si128((__m128i*)ptr, x); }
        inline void load(const type* ptr)          { x = _mm_loadu_si128((const __m128i*)ptr); }
        inline void store(type* ptr)         const { _mm_storeu_si128((__m128i*)ptr, x); }

        inline unsigned int size() const { return 4; }
        inline int32 operator[](unsigned int idx) const
        {
            int32 temp[4];
            store(temp);
            return temp[idx];
        }

    private:
        __m128i x;
    };
#else

    class simd4i
    {
    public:
        typedef int32 type;

        inline simd4i() {}
        inline simd4i(int32 f) { x[0]=f; x[1]=f; x[2]=f; x[3]=f; }
        inline simd4i(int32 r0, int32 r1, int32 r2, int32 r3) { x[0]=r0; x[1]=r1; x[2]=r2; x[3]=r3;}

        struct rawarray
        {
            int32 a[4];
        };
        inline simd4i(const rawarray& a) { x[0]=a.a[0]; x[1]=a.a[1]; x[2]=a.a[2]; x[3]=a.a[3]; }

        inline void load_aligned(const type* ptr)
        {
            x[0] = ptr[0];
            x[1] = ptr[1];
            x[2] = ptr[2];
            x[3] = ptr[3];
        }

        inline void store_aligned(type* ptr) const
        {
            ptr[0] = x[0];
            ptr[1] = x[1];
            ptr[2] = x[2];
            ptr[3] = x[3];
        }

        inline void load(const type* ptr)
        {
            x[0] = ptr[0];
            x[1] = ptr[1];
            x[2] = ptr[2];
            x[3] = ptr[3];
        }

        inline void store(type* ptr) const
        {
            ptr[0] = x[0];
            ptr[1] = x[1];
            ptr[2] = x[2];
            ptr[3] = x[3];
        }

        inline unsigned int size() const { return 4; }
        inline int32 operator[](unsigned int idx) const { return x[idx]; }

    private:
        int32 x[4];
    };
#endif

// ----------------------------------------------------------------------------------------

    inline std::ostream& operator<<(std::ostream& out, const simd4i& item)
    {
        int32 temp[4];
        item.store(temp);
        out << "(" << temp[0] << ", " << temp[1] << ", " << temp[2] << ", " << temp[3] << ")";
        return out;
    }

// ----------------------------------------------------------------------------------------

    inline simd4i operator+ (const simd4i& lhs, const simd4i& rhs)
    {
#ifdef DLIB_HAVE_SSE2
        return _mm_add_epi32(lhs, rhs);
#else
        return simd4i(lhs[0]+rhs[0],
                      lhs[1]+rhs[1],
                      lhs[2]+rhs[2],
                      lhs[3]+rhs[3]);
#endif
    }
    inline simd4i& operator+= (simd4i& lhs, const simd4i& rhs)
    { return lhs = lhs + rhs; return lhs;}

// ----------------------------------------------------------------------------------------

    inline simd4i operator- (const simd4i& lhs, const simd4i& rhs)
    {
#ifdef DLIB_HAVE_SSE2
        return _mm_sub_epi32(lhs, rhs);
#else
        return simd4i(lhs[0]-rhs[0],
                      lhs[1]-rhs[1],
                      lhs[2]-rhs[2],
                      lhs[3]-rhs[3]);
#endif
    }
    inline simd4i& operator-= (simd4i& lhs, const simd4i& rhs)
    { return lhs = lhs - rhs; return lhs;}

// ----------------------------------------------------------------------------------------

    inline simd4i operator* (const simd4i& lhs, const simd4i& rhs)
    {
#ifdef DLIB_HAVE_SSE41
        return _mm_mullo_epi32(lhs, rhs);
#elif defined(DLIB_HAVE_SSE2)
        int32 _lhs[4]; lhs.store(_lhs);
        int32 _rhs[4]; rhs.store(_rhs);
        return simd4i(_lhs[0]*_rhs[0],
                      _lhs[1]*_rhs[1],
                      _lhs[2]*_rhs[2],
                      _lhs[3]*_rhs[3]);
#else
        return simd4i(lhs[0]*rhs[0],
                      lhs[1]*rhs[1],
                      lhs[2]*rhs[2],
                      lhs[3]*rhs[3]);
#endif
    }
    inline simd4i& operator*= (simd4i& lhs, const simd4i& rhs)
    { return lhs = lhs * rhs; return lhs;}

// ----------------------------------------------------------------------------------------

    inline simd4i operator& (const simd4i& lhs, const simd4i& rhs)
    {
#ifdef DLIB_HAVE_SSE2
        return _mm_and_si128(lhs, rhs);
#else
        return simd4i(lhs[0]&rhs[0],
                      lhs[1]&rhs[1],
                      lhs[2]&rhs[2],
                      lhs[3]&rhs[3]);
#endif
    }
    inline simd4i& operator&= (simd4i& lhs, const simd4i& rhs)
    { return lhs = lhs & rhs; return lhs;}

// ----------------------------------------------------------------------------------------

    inline simd4i operator| (const simd4i& lhs, const simd4i& rhs)
    {
#ifdef DLIB_HAVE_SSE2
        return _mm_or_si128(lhs, rhs);
#else
        return simd4i(lhs[0]|rhs[0],
                      lhs[1]|rhs[1],
                      lhs[2]|rhs[2],
                      lhs[3]|rhs[3]);
#endif
    }
    inline simd4i& operator|= (simd4i& lhs, const simd4i& rhs)
    { return lhs = lhs | rhs; return lhs;}

// ----------------------------------------------------------------------------------------

    inline simd4i operator^ (const simd4i& lhs, const simd4i& rhs)
    {
#ifdef DLIB_HAVE_SSE2
        return _mm_xor_si128(lhs, rhs);
#else
        return simd4i(lhs[0]^rhs[0],
                      lhs[1]^rhs[1],
                      lhs[2]^rhs[2],
                      lhs[3]^rhs[3]);
#endif
    }
    inline simd4i& operator^= (simd4i& lhs, const simd4i& rhs)
    { return lhs = lhs ^ rhs; return lhs;}

// ----------------------------------------------------------------------------------------

    inline simd4i operator~ (const simd4i& lhs)
    {
#ifdef DLIB_HAVE_SSE2
        return _mm_xor_si128(lhs, _mm_set1_epi32(0xFFFFFFFF));
#else
        return simd4i(~lhs[0],
                      ~lhs[1],
                      ~lhs[2],
                      ~lhs[3]);
#endif
    }

// ----------------------------------------------------------------------------------------

    inline simd4i operator<< (const simd4i& lhs, const int& rhs)
    {
#ifdef DLIB_HAVE_SSE2
        return _mm_sll_epi32(lhs,_mm_cvtsi32_si128(rhs));
#else
        return simd4i(lhs[0]<<rhs,
                      lhs[1]<<rhs,
                      lhs[2]<<rhs,
                      lhs[3]<<rhs);
#endif
    }
    inline simd4i& operator<<= (simd4i& lhs, const int& rhs)
    { return lhs = lhs << rhs; return lhs;}

// ----------------------------------------------------------------------------------------

    inline simd4i operator>> (const simd4i& lhs, const int& rhs)
    {
#ifdef DLIB_HAVE_SSE2
        return _mm_sra_epi32(lhs,_mm_cvtsi32_si128(rhs));
#else
        return simd4i(lhs[0]>>rhs,
                      lhs[1]>>rhs,
                      lhs[2]>>rhs,
                      lhs[3]>>rhs);
#endif
    }
    inline simd4i& operator>>= (simd4i& lhs, const int& rhs)
    { return lhs = lhs >> rhs; return lhs;}

// ----------------------------------------------------------------------------------------

    inline simd4i operator== (const simd4i& lhs, const simd4i& rhs)
    {
#ifdef DLIB_HAVE_SSE2
        return _mm_cmpeq_epi32(lhs, rhs);
#else
        return simd4i(lhs[0]==rhs[0] ? 0xFFFFFFFF : 0,
                      lhs[1]==rhs[1] ? 0xFFFFFFFF : 0,
                      lhs[2]==rhs[2] ? 0xFFFFFFFF : 0,
                      lhs[3]==rhs[3] ? 0xFFFFFFFF : 0);
#endif
    }

// ----------------------------------------------------------------------------------------

    inline simd4i operator!= (const simd4i& lhs, const simd4i& rhs)
    {
#ifdef DLIB_HAVE_SSE2
        return ~(lhs==rhs);
#else
        return simd4i(lhs[0]!=rhs[0] ? 0xFFFFFFFF : 0,
                      lhs[1]!=rhs[1] ? 0xFFFFFFFF : 0,
                      lhs[2]!=rhs[2] ? 0xFFFFFFFF : 0,
                      lhs[3]!=rhs[3] ? 0xFFFFFFFF : 0);
#endif
    }

// ----------------------------------------------------------------------------------------

    inline simd4i operator< (const simd4i& lhs, const simd4i& rhs)
    {
#ifdef DLIB_HAVE_SSE2
        return _mm_cmplt_epi32(lhs, rhs);
#else
        return simd4i(lhs[0]<rhs[0] ? 0xFFFFFFFF : 0,
                      lhs[1]<rhs[1] ? 0xFFFFFFFF : 0,
                      lhs[2]<rhs[2] ? 0xFFFFFFFF : 0,
                      lhs[3]<rhs[3] ? 0xFFFFFFFF : 0);
#endif
    }

// ----------------------------------------------------------------------------------------

    inline simd4i operator> (const simd4i& lhs, const simd4i& rhs)
    {
        return rhs < lhs;
    }

// ----------------------------------------------------------------------------------------

    inline simd4i operator<= (const simd4i& lhs, const simd4i& rhs)
    {
#ifdef DLIB_HAVE_SSE2
        return ~(lhs > rhs);
#else
        return simd4i(lhs[0]<=rhs[0] ? 0xFFFFFFFF : 0,
                      lhs[1]<=rhs[1] ? 0xFFFFFFFF : 0,
                      lhs[2]<=rhs[2] ? 0xFFFFFFFF : 0,
                      lhs[3]<=rhs[3] ? 0xFFFFFFFF : 0);
#endif
    }

// ----------------------------------------------------------------------------------------

    inline simd4i operator>= (const simd4i& lhs, const simd4i& rhs)
    {
        return rhs <= lhs;
    }

// ----------------------------------------------------------------------------------------

    inline simd4i min (const simd4i& lhs, const simd4i& rhs)
    {
#ifdef DLIB_HAVE_SSE41
        return _mm_min_epi32(lhs, rhs);
#elif defined(DLIB_HAVE_SSE2)
        int32 _lhs[4]; lhs.store(_lhs);
        int32 _rhs[4]; rhs.store(_rhs);
        return simd4i(std::min(_lhs[0],_rhs[0]),
                      std::min(_lhs[1],_rhs[1]),
                      std::min(_lhs[2],_rhs[2]),
                      std::min(_lhs[3],_rhs[3]));
#else
        return simd4i(std::min(lhs[0],rhs[0]),
                      std::min(lhs[1],rhs[1]),
                      std::min(lhs[2],rhs[2]),
                      std::min(lhs[3],rhs[3]));
#endif
    }

// ----------------------------------------------------------------------------------------

    inline simd4i max (const simd4i& lhs, const simd4i& rhs)
    {
#ifdef DLIB_HAVE_SSE41
        return _mm_max_epi32(lhs, rhs);
#elif defined(DLIB_HAVE_SSE2)
        int32 _lhs[4]; lhs.store(_lhs);
        int32 _rhs[4]; rhs.store(_rhs);
        return simd4i(std::max(_lhs[0],_rhs[0]),
                      std::max(_lhs[1],_rhs[1]),
                      std::max(_lhs[2],_rhs[2]),
                      std::max(_lhs[3],_rhs[3]));
#else
        return simd4i(std::max(lhs[0],rhs[0]),
                      std::max(lhs[1],rhs[1]),
                      std::max(lhs[2],rhs[2]),
                      std::max(lhs[3],rhs[3]));
#endif
    }

// ----------------------------------------------------------------------------------------

    inline int32 sum(const simd4i& item)
    {
#ifdef DLIB_HAVE_SSE3
        simd4i temp = _mm_hadd_epi32(item,item);
        temp = _mm_hadd_epi32(temp,temp);
        return _mm_cvtsi128_si32(temp);
#elif defined(DLIB_HAVE_SSE2)
        int32 temp[4];
        item.store(temp);
        return temp[0]+temp[1]+temp[2]+temp[3];
#else
        return item[0]+item[1]+item[2]+item[3];
#endif
    }

// ----------------------------------------------------------------------------------------

    // perform cmp ? a : b
    inline simd4i select(const simd4i& cmp, const simd4i& a, const simd4i& b)
    {
#ifdef DLIB_HAVE_SSE41
        return _mm_blendv_epi8(b,a,cmp);
#elif defined(DLIB_HAVE_SSE2)
        return ((cmp&a) | _mm_andnot_si128(cmp,b));
#else
        return ((cmp&a) | (~cmp&b));
#endif
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_sIMD4I_Hh_


dlib C++ Library - simd8f.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_sIMD8F_Hh_
#define DLIB_sIMD8F_Hh_

#include "simd_check.h"
#include "simd4f.h"
#include "simd8i.h"

namespace dlib
{
#ifdef DLIB_HAVE_AVX
    class simd8f
    {
    public:
        typedef float type;

        inline simd8f() {}
        inline simd8f(const simd4f& low, const simd4f& high)
        {
            x = _mm256_insertf128_ps(_mm256_castps128_ps256(low),high,1);
        }
        inline simd8f(float f) { x = _mm256_set1_ps(f); }
        inline simd8f(float r0, float r1, float r2, float r3, float r4, float r5, float r6, float r7)
        { x = _mm256_setr_ps(r0,r1,r2,r3,r4,r5,r6,r7); }

        inline simd8f(const simd8i& val):x(_mm256_cvtepi32_ps(val)) {}
        inline simd8f(const __m256& val):x(val) {}
        inline simd8f& operator=(const __m256& val)
        {
            x = val;
            return *this;
        }
        inline operator __m256() const { return x; }

        // truncate to 32bit integers
        inline operator __m256i() const { return _mm256_cvttps_epi32(x); }

        inline void load_aligned(const type* ptr)  { x = _mm256_load_ps(ptr); }
        inline void store_aligned(type* ptr) const { _mm256_store_ps(ptr, x); }
        inline void load(const type* ptr)          { x = _mm256_loadu_ps(ptr); }
        inline void store(type* ptr)         const { _mm256_storeu_ps(ptr, x); }

        inline unsigned int size() const { return 8; }
        inline float operator[](unsigned int idx) const
        {
            float temp[8];
            store(temp);
            return temp[idx];
        }

        inline simd4f low() const { return _mm256_castps256_ps128(x); }
        inline simd4f high() const { return _mm256_extractf128_ps(x,1); }

    private:
        __m256 x;
    };

    class simd8f_bool
    {
    public:
        typedef float type;

        inline simd8f_bool() {}
        inline simd8f_bool(const __m256& val):x(val) {}
        inline simd8f_bool(const simd4f_bool& low, const simd4f_bool& high)
        {
            x = _mm256_insertf128_ps(_mm256_castps128_ps256(low),high,1);
        }

        inline simd8f_bool& operator=(const __m256& val)
        {
            x = val;
            return *this;
        }

        inline operator __m256() const { return x; }

    private:
        __m256 x;
    };

#else
    class simd8f
    {
    public:
        typedef float type;

        inline simd8f() {}
        inline simd8f(const simd4f& low_, const simd4f& high_): _low(low_),_high(high_){}
        inline simd8f(float f) :_low(f),_high(f) {}
        inline simd8f(float r0, float r1, float r2, float r3, float r4, float r5, float r6, float r7) :
            _low(r0,r1,r2,r3), _high(r4,r5,r6,r7) {}
        inline simd8f(const simd8i& val) : _low(val.low()), _high(val.high()) { }

        // truncate to 32bit integers
        inline operator simd8i::rawarray() const
        {
            simd8i::rawarray temp;
            temp.low = simd4i(_low);
            temp.high = simd4i(_high);
            return temp;
        }

        inline void load_aligned(const type* ptr)  { _low.load_aligned(ptr); _high.load_aligned(ptr+4); }
        inline void store_aligned(type* ptr) const { _low.store_aligned(ptr); _high.store_aligned(ptr+4); }
        inline void load(const type* ptr)          { _low.load(ptr); _high.load(ptr+4); }
        inline void store(type* ptr)         const { _low.store(ptr); _high.store(ptr+4); }

        inline unsigned int size() const { return 8; }
        inline float operator[](unsigned int idx) const
        {
            if (idx < 4)
                return _low[idx];
            else
                return _high[idx-4];
        }

        inline simd4f low() const { return _low; }
        inline simd4f high() const { return _high; }

    private:
        simd4f _low, _high;
    };

    class simd8f_bool
    {
    public:
        typedef float type;

        inline simd8f_bool() {}
        inline simd8f_bool(const simd4f_bool& low_, const simd4f_bool& high_): _low(low_),_high(high_){}

        inline simd4f_bool low() const { return _low; }
        inline simd4f_bool high() const { return _high; }
    private:
        simd4f_bool _low,_high;
    };
#endif

// ----------------------------------------------------------------------------------------

    inline std::ostream& operator<<(std::ostream& out, const simd8f& item)
    {
        float temp[8];
        item.store(temp);
        out << "(" << temp[0] << ", " << temp[1] << ", " << temp[2] << ", " << temp[3] << ", "
                   << temp[4] << ", " << temp[5] << ", " << temp[6] << ", " << temp[7] << ")";
        return out;
    }

// ----------------------------------------------------------------------------------------

    inline simd8f operator+ (const simd8f& lhs, const simd8f& rhs)
    {
#ifdef DLIB_HAVE_AVX
        return _mm256_add_ps(lhs, rhs);
#else
        return simd8f(lhs.low()+rhs.low(),
                      lhs.high()+rhs.high());
#endif
    }
    inline simd8f& operator+= (simd8f& lhs, const simd8f& rhs)
    { return lhs = lhs + rhs; return lhs;}

// ----------------------------------------------------------------------------------------

    inline simd8f operator- (const simd8f& lhs, const simd8f& rhs)
    {
#ifdef DLIB_HAVE_AVX
        return _mm256_sub_ps(lhs, rhs);
#else
        return simd8f(lhs.low()-rhs.low(),
                      lhs.high()-rhs.high());
#endif
    }
    inline simd8f& operator-= (simd8f& lhs, const simd8f& rhs)
    { return lhs = lhs - rhs; return lhs;}

// ----------------------------------------------------------------------------------------

    inline simd8f operator* (const simd8f& lhs, const simd8f& rhs)
    {
#ifdef DLIB_HAVE_AVX
        return _mm256_mul_ps(lhs, rhs);
#else
        return simd8f(lhs.low()*rhs.low(),
                      lhs.high()*rhs.high());
#endif
    }
    inline simd8f& operator*= (simd8f& lhs, const simd8f& rhs)
    { return lhs = lhs * rhs; return lhs;}

// ----------------------------------------------------------------------------------------

    inline simd8f operator/ (const simd8f& lhs, const simd8f& rhs)
    {
#ifdef DLIB_HAVE_AVX
        return _mm256_div_ps(lhs, rhs);
#else
        return simd8f(lhs.low()/rhs.low(),
                      lhs.high()/rhs.high());
#endif
    }
    inline simd8f& operator/= (simd8f& lhs, const simd8f& rhs)
    { return lhs = lhs / rhs; return lhs;}

// ----------------------------------------------------------------------------------------

    inline simd8f_bool operator== (const simd8f& lhs, const simd8f& rhs)
    {
#ifdef DLIB_HAVE_AVX
        return _mm256_cmp_ps(lhs, rhs, 0);
#else
        return simd8f_bool(lhs.low() ==rhs.low(),
                      lhs.high()==rhs.high());
#endif
    }

// ----------------------------------------------------------------------------------------

    inline simd8f_bool operator!= (const simd8f& lhs, const simd8f& rhs)
    {
#ifdef DLIB_HAVE_AVX
        return _mm256_cmp_ps(lhs, rhs, 4);
#else
        return simd8f_bool(lhs.low() !=rhs.low(),
                      lhs.high()!=rhs.high());
#endif
    }

// ----------------------------------------------------------------------------------------

    inline simd8f_bool operator< (const simd8f& lhs, const simd8f& rhs)
    {
#ifdef DLIB_HAVE_AVX
        return _mm256_cmp_ps(lhs, rhs, 1);
#else
        return simd8f_bool(lhs.low() <rhs.low(),
                      lhs.high()<rhs.high());
#endif
    }

// ----------------------------------------------------------------------------------------

    inline simd8f_bool operator> (const simd8f& lhs, const simd8f& rhs)
    {
        return rhs < lhs;
    }

// ----------------------------------------------------------------------------------------

    inline simd8f_bool operator<= (const simd8f& lhs, const simd8f& rhs)
    {
#ifdef DLIB_HAVE_AVX
        return _mm256_cmp_ps(lhs, rhs, 2);
#else
        return simd8f_bool(lhs.low() <=rhs.low(),
                      lhs.high()<=rhs.high());
#endif
    }

// ----------------------------------------------------------------------------------------

    inline simd8f_bool operator>= (const simd8f& lhs, const simd8f& rhs)
    {
        return rhs <= lhs;
    }

// ----------------------------------------------------------------------------------------

    inline simd8f min (const simd8f& lhs, const simd8f& rhs)
    {
#ifdef DLIB_HAVE_AVX
        return _mm256_min_ps(lhs, rhs);
#else
        return simd8f(min(lhs.low(), rhs.low()),
                      min(lhs.high(),rhs.high()));
#endif
    }

// ----------------------------------------------------------------------------------------

    inline simd8f max (const simd8f& lhs, const simd8f& rhs)
    {
#ifdef DLIB_HAVE_AVX
        return _mm256_max_ps(lhs, rhs);
#else
        return simd8f(max(lhs.low(), rhs.low()),
                      max(lhs.high(),rhs.high()));
#endif
    }

// ----------------------------------------------------------------------------------------

    inline simd8f reciprocal (const simd8f& item)
    {
#ifdef DLIB_HAVE_AVX
        return _mm256_rcp_ps(item);
#else
        return simd8f(reciprocal(item.low()),
                      reciprocal(item.high()));
#endif
    }

// ----------------------------------------------------------------------------------------

    inline simd8f reciprocal_sqrt (const simd8f& item)
    {
#ifdef DLIB_HAVE_AVX
        return _mm256_rsqrt_ps(item);
#else
        return simd8f(reciprocal_sqrt(item.low()),
                      reciprocal_sqrt(item.high()));
#endif
    }

// ----------------------------------------------------------------------------------------

    inline float sum(const simd8f& item)
    {
#ifdef DLIB_HAVE_AVX
        simd8f temp = _mm256_hadd_ps(item,item);
        simd8f temp2 = _mm256_hadd_ps(temp,temp);
        return _mm_cvtss_f32(_mm_add_ss(_mm256_castps256_ps128(temp2),_mm256_extractf128_ps(temp2,1)));
#else
        return sum(item.low()+item.high());
#endif
    }

// ----------------------------------------------------------------------------------------

    inline float dot(const simd8f& lhs, const simd8f& rhs)
    {
        return sum(lhs*rhs);
    }

// ----------------------------------------------------------------------------------------

    inline simd8f sqrt(const simd8f& item)
    {
#ifdef DLIB_HAVE_AVX
        return _mm256_sqrt_ps(item);
#else
        return simd8f(sqrt(item.low()),
                      sqrt(item.high()));
#endif
    }

// ----------------------------------------------------------------------------------------

    inline simd8f ceil(const simd8f& item)
    {
#ifdef DLIB_HAVE_AVX
        return _mm256_ceil_ps(item);
#else
        return simd8f(ceil(item.low()),
                      ceil(item.high()));
#endif
    }

// ----------------------------------------------------------------------------------------

    inline simd8f floor(const simd8f& item)
    {
#ifdef DLIB_HAVE_AVX
        return _mm256_floor_ps(item);
#else
        return simd8f(floor(item.low()),
                      floor(item.high()));
#endif
    }

// ----------------------------------------------------------------------------------------

    // perform cmp ? a : b
    inline simd8f select(const simd8f_bool& cmp, const simd8f& a, const simd8f& b)
    {
#ifdef DLIB_HAVE_AVX
        return _mm256_blendv_ps(b,a,cmp);
#else
        return simd8f(select(cmp.low(),  a.low(),  b.low()),
                      select(cmp.high(), a.high(), b.high()));
#endif
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_sIMD8F_Hh_


dlib C++ Library - simd8i.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_sIMD8I_Hh_
#define DLIB_sIMD8I_Hh_

#include "simd_check.h"
#include "../uintn.h"

namespace dlib
{

#ifdef DLIB_HAVE_AVX
    class simd8i
    {
    public:
        typedef int32 type;

        inline simd8i() {}
        inline simd8i(int32 f) { x = _mm256_set1_epi32(f); }
        inline simd8i(int32 r0, int32 r1, int32 r2, int32 r3,
               int32 r4, int32 r5, int32 r6, int32 r7 )
        { x = _mm256_setr_epi32(r0,r1,r2,r3,r4,r5,r6,r7); }

        inline simd8i(const __m256i& val):x(val) {}

        inline simd8i(const simd4i& low, const simd4i& high)
        {
            x = _mm256_insertf128_si256(_mm256_castsi128_si256(low),high,1);
        }

        inline simd8i& operator=(const __m256i& val)
        {
            x = val;
            return *this;
        }

        inline operator __m256i() const { return x; }

        inline void load_aligned(const type* ptr)  { x = _mm256_load_si256((const __m256i*)ptr); }
        inline void store_aligned(type* ptr) const { _mm256_store_si256((__m256i*)ptr, x); }
        inline void load(const type* ptr)          { x = _mm256_loadu_si256((const __m256i*)ptr); }
        inline void store(type* ptr)         const { _mm256_storeu_si256((__m256i*)ptr, x); }

        inline simd4i low() const { return _mm256_castsi256_si128(x); }
        inline simd4i high() const { return _mm256_extractf128_si256(x,1); }

        inline unsigned int size() const { return 4; }
        inline int32 operator[](unsigned int idx) const
        {
            int32 temp[8];
            store(temp);
            return temp[idx];
        }

    private:
        __m256i x;
    };
#else
    class simd8i
    {
    public:
        typedef int32 type;

        inline simd8i() {}
        inline simd8i(const simd4i& low_, const simd4i& high_): _low(low_),_high(high_){}
        inline simd8i(int32 f) :_low(f),_high(f) {}
        inline simd8i(int32 r0, int32 r1, int32 r2, int32 r3, int32 r4, int32 r5, int32 r6, int32 r7) :
            _low(r0,r1,r2,r3), _high(r4,r5,r6,r7) {}

        struct rawarray
        {
            simd4i low, high;
        };
        inline simd8i(const rawarray& a)
        {
            _low = a.low;
            _high = a.high;
        }

        inline void load_aligned(const type* ptr)  { _low.load_aligned(ptr); _high.load_aligned(ptr+4); }
        inline void store_aligned(type* ptr) const { _low.store_aligned(ptr); _high.store_aligned(ptr+4); }
        inline void load(const type* ptr)          { _low.load(ptr); _high.load(ptr+4); }
        inline void store(type* ptr)         const { _low.store(ptr); _high.store(ptr+4); }

        inline unsigned int size() const { return 8; }
        inline int32 operator[](unsigned int idx) const
        {
            if (idx < 4)
                return _low[idx];
            else
                return _high[idx-4];
        }

        inline simd4i low() const { return _low; }
        inline simd4i high() const { return _high; }

    private:
        simd4i _low, _high;
    };

#endif

// ----------------------------------------------------------------------------------------

    inline std::ostream& operator<<(std::ostream& out, const simd8i& item)
    {
        int32 temp[8];
        item.store(temp);
        out << "(" << temp[0] << ", " << temp[1] << ", " << temp[2] << ", " << temp[3] << ", "
                   << temp[4] << ", " << temp[5] << ", " << temp[6] << ", " << temp[7] << ")";
        return out;
    }

// ----------------------------------------------------------------------------------------

    inline simd8i operator+ (const simd8i& lhs, const simd8i& rhs)
    {
#ifdef DLIB_HAVE_AVX2
        return _mm256_add_epi32(lhs, rhs);
#else
        return simd8i(lhs.low()+rhs.low(),
                      lhs.high()+rhs.high());
#endif
    }
    inline simd8i& operator+= (simd8i& lhs, const simd8i& rhs)
    { return lhs = lhs + rhs; return lhs;}

// ----------------------------------------------------------------------------------------

    inline simd8i operator- (const simd8i& lhs, const simd8i& rhs)
    {
#ifdef DLIB_HAVE_AVX2
        return _mm256_sub_epi32(lhs, rhs);
#else
        return simd8i(lhs.low()-rhs.low(),
                      lhs.high()-rhs.high());
#endif
    }
    inline simd8i& operator-= (simd8i& lhs, const simd8i& rhs)
    { return lhs = lhs - rhs; return lhs;}

// ----------------------------------------------------------------------------------------

    inline simd8i operator* (const simd8i& lhs, const simd8i& rhs)
    {
#ifdef DLIB_HAVE_AVX2
        return _mm256_mullo_epi32(lhs, rhs);
#else
        return simd8i(lhs.low()*rhs.low(),
                      lhs.high()*rhs.high());
#endif
    }
    inline simd8i& operator*= (simd8i& lhs, const simd8i& rhs)
    { return lhs = lhs * rhs; return lhs;}

// ----------------------------------------------------------------------------------------

    inline simd8i operator& (const simd8i& lhs, const simd8i& rhs)
    {
#ifdef DLIB_HAVE_AVX2
        return _mm256_and_si256(lhs, rhs);
#else
        return simd8i(lhs.low()&rhs.low(),
                      lhs.high()&rhs.high());
#endif
    }
    inline simd8i& operator&= (simd8i& lhs, const simd8i& rhs)
    { return lhs = lhs & rhs; return lhs;}

// ----------------------------------------------------------------------------------------

    inline simd8i operator| (const simd8i& lhs, const simd8i& rhs)
    {
#ifdef DLIB_HAVE_AVX2
        return _mm256_or_si256(lhs, rhs);
#else
        return simd8i(lhs.low()|rhs.low(),
                      lhs.high()|rhs.high());
#endif
    }
    inline simd8i& operator|= (simd8i& lhs, const simd8i& rhs)
    { return lhs = lhs | rhs; return lhs;}

// ----------------------------------------------------------------------------------------

    inline simd8i operator^ (const simd8i& lhs, const simd8i& rhs)
    {
#ifdef DLIB_HAVE_AVX2
        return _mm256_xor_si256(lhs, rhs);
#else
        return simd8i(lhs.low()^rhs.low(),
                      lhs.high()^rhs.high());
#endif
    }
    inline simd8i& operator^= (simd8i& lhs, const simd8i& rhs)
    { return lhs = lhs ^ rhs; return lhs;}

// ----------------------------------------------------------------------------------------

    inline simd8i operator~ (const simd8i& lhs)
    {
#ifdef DLIB_HAVE_AVX2
        return _mm256_xor_si256(lhs, _mm256_set1_epi32(0xFFFFFFFF));
#else
        return simd8i(~lhs.low(), ~lhs.high());
#endif
    }

// ----------------------------------------------------------------------------------------

    inline simd8i operator<< (const simd8i& lhs, const int& rhs)
    {
#ifdef DLIB_HAVE_AVX2
        return _mm256_sll_epi32(lhs,_mm_cvtsi32_si128(rhs));
#else
        return simd8i(lhs.low()<<rhs,
                      lhs.high()<<rhs);
#endif
    }
    inline simd8i& operator<<= (simd8i& lhs, const int& rhs)
    { return lhs = lhs << rhs; return lhs;}

// ----------------------------------------------------------------------------------------

    inline simd8i operator>> (const simd8i& lhs, const int& rhs)
    {
#ifdef DLIB_HAVE_AVX2
        return _mm256_sra_epi32(lhs,_mm_cvtsi32_si128(rhs));
#else
        return simd8i(lhs.low()>>rhs,
                      lhs.high()>>rhs);
#endif
    }
    inline simd8i& operator>>= (simd8i& lhs, const int& rhs)
    { return lhs = lhs >> rhs; return lhs;}

// ----------------------------------------------------------------------------------------

    inline simd8i operator== (const simd8i& lhs, const simd8i& rhs)
    {
#ifdef DLIB_HAVE_AVX2
        return _mm256_cmpeq_epi32(lhs, rhs);
#else
        return simd8i(lhs.low()==rhs.low(),
                      lhs.high()==rhs.high());
#endif
    }

// ----------------------------------------------------------------------------------------

    inline simd8i operator!= (const simd8i& lhs, const simd8i& rhs)
    {
        return ~(lhs==rhs);
    }

// ----------------------------------------------------------------------------------------

    inline simd8i operator> (const simd8i& lhs, const simd8i& rhs)
    {
#ifdef DLIB_HAVE_AVX2
        return _mm256_cmpgt_epi32(lhs, rhs);
#else
        return simd8i(lhs.low()>rhs.low(),
                      lhs.high()>rhs.high());
#endif
    }

// ----------------------------------------------------------------------------------------

    inline simd8i operator< (const simd8i& lhs, const simd8i& rhs)
    {
        return rhs > lhs;
    }

// ----------------------------------------------------------------------------------------

    inline simd8i operator<= (const simd8i& lhs, const simd8i& rhs)
    {
        return ~(lhs > rhs);
    }

// ----------------------------------------------------------------------------------------

    inline simd8i operator>= (const simd8i& lhs, const simd8i& rhs)
    {
        return rhs <= lhs;
    }

// ----------------------------------------------------------------------------------------

    inline simd8i min (const simd8i& lhs, const simd8i& rhs)
    {
#ifdef DLIB_HAVE_AVX2
        return _mm256_min_epi32(lhs, rhs);
#else
        return simd8i(min(lhs.low(),rhs.low()),
                      min(lhs.high(),rhs.high()));
#endif
    }

// ----------------------------------------------------------------------------------------

    inline simd8i max (const simd8i& lhs, const simd8i& rhs)
    {
#ifdef DLIB_HAVE_AVX2
        return _mm256_max_epi32(lhs, rhs);
#else
        return simd8i(max(lhs.low(),rhs.low()),
                      max(lhs.high(),rhs.high()));
#endif
    }

// ----------------------------------------------------------------------------------------

    inline int32 sum(const simd8i& item)
    {
        return sum(item.low()+item.high());
    }

// ----------------------------------------------------------------------------------------

    // perform cmp ? a : b
    inline simd8i select(const simd8i& cmp, const simd8i& a, const simd8i& b)
    {
#ifdef DLIB_HAVE_AVX2
        return _mm256_blendv_epi8(b,a,cmp);
#else
        return simd8i(select(cmp.low(),  a.low(),  b.low()),
                      select(cmp.high(), a.high(), b.high()));
#endif
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_sIMD8I_Hh_


dlib C++ Library - simd_check.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SIMd_CHECK_Hh_
#define DLIB_SIMd_CHECK_Hh_

//#define DLIB_DO_NOT_USE_SIMD

// figure out which SIMD instructions we can use.
#ifndef DLIB_DO_NOT_USE_SIMD
    #if defined(_MSC_VER)
        #ifdef __AVX__
            #ifndef DLIB_HAVE_SSE2
                #define DLIB_HAVE_SSE2
            #endif
            #ifndef DLIB_HAVE_SSE3
                #define DLIB_HAVE_SSE3
            #endif
            #ifndef DLIB_HAVE_SSE41
                #define DLIB_HAVE_SSE41
            #endif
            #ifndef DLIB_HAVE_AVX
                #define DLIB_HAVE_AVX
            #endif
        #endif
        #if defined(_M_IX86_FP) && _M_IX86_FP >= 2 && !defined(DLIB_HAVE_SSE2)
            #define DLIB_HAVE_SSE2
        #endif
    #else
        #ifdef __SSE2__
            #ifndef DLIB_HAVE_SSE2
                #define DLIB_HAVE_SSE2
            #endif
        #endif
        #ifdef __SSSE3__
            #ifndef DLIB_HAVE_SSE3
                #define DLIB_HAVE_SSE3
            #endif
        #endif
        #ifdef __SSE4_1__
            #ifndef DLIB_HAVE_SSE41
                #define DLIB_HAVE_SSE41
            #endif
        #endif
        #ifdef __AVX__
            #ifndef DLIB_HAVE_AVX
                #define DLIB_HAVE_AVX
            #endif
        #endif
        #ifdef __AVX2__
            #ifndef DLIB_HAVE_AVX2
                #define DLIB_HAVE_AVX2
            #endif
        #endif
    #endif
#endif

// ----------------------------------------------------------------------------------------

#ifdef DLIB_HAVE_SSE2
    #include <xmmintrin.h>
    #include <emmintrin.h>
    #include <mmintrin.h>
#endif
#ifdef DLIB_HAVE_SSE3
    #include <pmmintrin.h> // SSE3
    #include <tmmintrin.h>
#endif
#ifdef DLIB_HAVE_SSE41
    #include <smmintrin.h> // SSE4
#endif
#ifdef DLIB_HAVE_AVX
    #include <immintrin.h> // AVX
#endif
#ifdef DLIB_HAVE_AVX2
    #include <avx2intrin.h>
#endif

#endif // DLIB_SIMd_CHECK_Hh_


dlib C++ Library - circular_buffer.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_CIRCULAR_BuFFER_Hh_
#define DLIB_CIRCULAR_BuFFER_Hh_

#include "circular_buffer_abstract.h"
#include <vector>
#include "../algs.h"
#include "../serialize.h"
#include "../matrix/matrix_mat.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    class circular_buffer
    {
    public:
        typedef default_memory_manager mem_manager_type;
        typedef T value_type;
        typedef T type;

        circular_buffer()
        {
            offset = 0;
        }

        void clear (
        )
        {
            offset = 0;
            data.clear();
        }

        T& operator[] ( unsigned long i)
        {
            DLIB_ASSERT(i < size(),
                "\t T& circular_buffer::operator[](i)"
                << "\n\t You have supplied an invalid index"
                << "\n\t this:   " << this
                << "\n\t i:      " << i
                << "\n\t size(): " << size()
            );
            return data[(i+offset)%data.size()];
        }

        const T& operator[] ( unsigned long i) const
        {
            DLIB_ASSERT(i < size(),
                "\t const T& circular_buffer::operator[](i)"
                << "\n\t You have supplied an invalid index"
                << "\n\t this:   " << this
                << "\n\t i:      " << i
                << "\n\t size(): " << size()
            );
            return data[(i+offset)%data.size()];
        }

        void resize(unsigned long size)
        {
            offset = 0;
            data.resize(size);
        }

        void assign(
            unsigned long size,
            const T& value
        )
        {
            offset = 0;
            data.assign(size,value);
        }

        unsigned long size() const { return data.size(); }

        void push_front(const T& value)
        {
            if (data.size() != 0)
            {
                offset = (offset - 1 + data.size())%data.size();
                data[offset] = value;
            }
        }

        void push_back(const T& value)
        {
            if (data.size() != 0)
            {
                data[offset] = value;
                offset = (offset + 1 + data.size())%data.size();
            }
        }

        T& front(
        )
        {
            DLIB_CASSERT(size() > 0,
                "\t T& circular_buffer::front()"
                << "\n\t You can't call front() on an empty circular_buffer"
                << "\n\t this:   " << this
            );
            return (*this)[0];
        }

        const T& front(
        ) const
        {
            DLIB_CASSERT(size() > 0,
                "\t const T& circular_buffer::front()"
                << "\n\t You can't call front() on an empty circular_buffer"
                << "\n\t this:   " << this
            );
            return (*this)[0];
        }

        T& back(
        )
        {
            DLIB_CASSERT(size() > 0,
                "\t T& circular_buffer::back()"
                << "\n\t You can't call back() on an empty circular_buffer"
                << "\n\t this:   " << this
            );
            return (*this)[size()-1];
        }

        const T& back(
        ) const
        {
            DLIB_CASSERT(size() > 0,
                "\t const T& circular_buffer::back()"
                << "\n\t You can't call back() on an empty circular_buffer"
                << "\n\t this:   " << this
            );
            return (*this)[size()-1];
        }

        void swap( circular_buffer& item)
        {
            std::swap(item.offset, offset);
            data.swap(item.data);
        }

    private:
        std::vector<T> data;

        unsigned long offset;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    void swap (
        circular_buffer<T>& a,
        circular_buffer<T>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    void serialize (
        const circular_buffer<T>& item,
        std::ostream& out
    )
    {
        try
        {
            serialize(item.size(),out);
            for (unsigned long i = 0; i < item.size(); ++i)
                serialize(item[i],out);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while serializing object of type circular_buffer");
        }

    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    void deserialize (
        circular_buffer<T>& item,
        std::istream& in
    )
    {
        try
        {
            unsigned long size;
            deserialize(size,in);
            item.resize(size);
            for (unsigned long i = 0; i < size; ++i)
                deserialize(item[i],in);
        }
        catch (serialization_error& e)
        {
            item.clear();
            throw serialization_error(e.info + "\n   while deserializing object of type circular_buffer");
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    const matrix_op<op_array_to_mat<circular_buffer<T> > > mat (
        const circular_buffer<T>& m
    )
    {
        typedef op_array_to_mat<circular_buffer<T> > op;
        return matrix_op<op>(op(m));
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_CIRCULAR_BuFFER_Hh_


dlib C++ Library - sliding_buffer_kernel_1.h

// Copyright (C) 2004  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SLIDING_BUFFER_KERNEl_1_
#define DLIB_SLIDING_BUFFER_KERNEl_1_

#include "sliding_buffer_kernel_abstract.h"
#include "../algs.h"
#include "../interfaces/enumerable.h"
#include "../serialize.h"

namespace dlib
{

    template <
        typename T
        >
    class sliding_buffer_kernel_1 : public enumerable<T>
    {
        /*!
            INITIAL VALUE
                - buffer_size == 0
                - buffer == 0
                - buffer_start == 0
                - current == 0
                - at_start_ == true

            CONVENTION
                - buffer_size == size()

                - element() == (*this)[current]
                - current_element_valid() == (current < buffer_size) && at_start_ == false
                - at_start() == at_start_

                - if (buffer_size != 0) then
                    - buffer[(buffer_start+i)&(mask)] == operator[](i)
                    - mask == buffer_size-1
                - else
                    - buffer == 0
                    - buffer_size == 0
        !*/

    public:

        typedef T type;

        sliding_buffer_kernel_1 (
        ) :
            buffer_start(0),
            buffer_size(0),
            buffer(0),
            current(0),
            at_start_(true)
        {}

        virtual ~sliding_buffer_kernel_1 (
        ) { if (buffer) delete [] buffer; }

        void clear(
        )
        {
            buffer_size = 0;
            if (buffer) delete [] buffer;
            buffer = 0;
            at_start_ = true;
            current = 0;
        }

        void set_size (
            unsigned long exp_size
        )
        {
            at_start_ = true;
            if (buffer) delete [] buffer;
            buffer_size = 1;
            while (exp_size != 0)
            {
                --exp_size;
                buffer_size <<= 1;
            }
            mask = buffer_size-1;
            try { buffer = new T[buffer_size]; }
            catch (...) { buffer = 0; buffer_size = 0; throw; }
        }

        unsigned long size (
        ) const { return buffer_size; }

        void rotate_left (
            unsigned long amount
        ) { buffer_start = ((buffer_start-amount)&mask); at_start_ = true; }

        void rotate_right (
            unsigned long amount
        ) { buffer_start = ((buffer_start+amount)&mask); at_start_ = true;}

        const T& operator[] (
            unsigned long index
        ) const { return buffer[(buffer_start+index)&mask]; }

        T& operator[] (
            unsigned long index
        ) { return buffer[(buffer_start+index)&mask]; }

        unsigned long get_element_id(
            unsigned long index
        ) const { return ((buffer_start+index)&mask); }

        unsigned long get_element_index (
            unsigned long element_id
        ) const { return ((element_id-buffer_start)&mask);}

        void swap (
            sliding_buffer_kernel_1<T>& item
        )
        {
            exchange(buffer_start,item.buffer_start);
            exchange(buffer_size,item.buffer_size);
            exchange(buffer,item.buffer);
            exchange(mask,item.mask);
            exchange(current,item.current);
            exchange(at_start_,item.at_start_);
        }

        bool at_start (
        ) const { return at_start_; }

        void reset (
        ) const { at_start_ = true; }

        bool current_element_valid (
        ) const { return (current < buffer_size) && (at_start_ == false); }

        const T& element (
        ) const { return (*this)[current]; }

        T& element (
        ) { return (*this)[current]; }

        bool move_next (
        ) const
        {
            if (at_start_ == false)
            {
                if (current+1 < buffer_size)
                {
                    ++current;
                    return true;
                }
                else
                {
                    current = buffer_size;
                    return false;
                }
            }
            else
            {
                at_start_ = false;
                current = 0;
                return (buffer_size != 0);
            }
        }

    private:

        // data members
        unsigned long buffer_start;
        unsigned long buffer_size;
        T* buffer;
        unsigned long mask;

        mutable unsigned long current;
        mutable bool at_start_;

        // restricted functions
        sliding_buffer_kernel_1(sliding_buffer_kernel_1<T>&);        // copy constructor
        sliding_buffer_kernel_1<T>& operator=(sliding_buffer_kernel_1<T>&);    // assignment operator

    };

    template <
        typename T
        >
    inline void swap (
        sliding_buffer_kernel_1<T>& a,
        sliding_buffer_kernel_1<T>& b
    ) { a.swap(b); }

    template <
        typename T
        >
    void deserialize (
        sliding_buffer_kernel_1<T>& item,
        std::istream& in
    )
    {
        try
        {
            item.clear();
            unsigned long size;
            deserialize(size,in);
            if (size > 0)
            {
                int count = 0;
                while (size != 1)
                {
                    size /= 2;
                    ++count;
                }
                item.set_size(count);

                for (unsigned long i = 0; i < item.size(); ++i)
                    deserialize(item[i],in);
            }
        }
        catch (serialization_error e)
        {
            item.clear();
            throw serialization_error(e.info + "\n   while deserializing object of type sliding_buffer_kernel_1");
        }
    }
}

#endif // DLIB_SLIDING_BUFFER_KERNEl_1_


dlib C++ Library - sliding_buffer_kernel_c.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SLIDING_BUFFER_KERNEl_C_
#define DLIB_SLIDING_BUFFER_KERNEl_C_

#include "sliding_buffer_kernel_abstract.h"
#include "../algs.h"
#include "../assert.h"
#include <iostream>

namespace dlib
{

    template <
        typename sb_base
        >
    class sliding_buffer_kernel_c : public sb_base
    {
        typedef typename sb_base::type T;

        public:
            void set_size (
                unsigned long exp_size
            );

            const T& operator[] (
                unsigned long index
            ) const;

            T& operator[] (
                unsigned long index
            );

            unsigned long get_element_id (
                unsigned long index
            ) const;

            unsigned long get_element_index (
                unsigned long element_id
            ) const;

            const T& element (
            ) const;

            T& element (
            );

    };

    template <
        typename sb_base
        >
    inline void swap (
        sliding_buffer_kernel_c<sb_base>& a,
        sliding_buffer_kernel_c<sb_base>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename sb_base
        >
    void sliding_buffer_kernel_c<sb_base>::
    set_size (
        unsigned long exp_size
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT( 0 < exp_size && exp_size < 32,
            "\tvoid sliding_buffer::set_size(unsigned long)"
            << "\n\texp_size must be some number between 1 and 31"
            << "\n\tthis:     " << this
            << "\n\texp_size: " << exp_size
            );

        // call the real function
        sb_base::set_size(exp_size);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename sb_base
        >
    unsigned long sliding_buffer_kernel_c<sb_base>::
    get_element_id (
        unsigned long index
    ) const
    {
        // make sure requires clause is not broken
        DLIB_CASSERT( index < this->size(),
            "\tunsigned long sliding_buffer::get_element_id(unsigned long) const"
            << "\n\tindex must be in the range 0 to size()-1"
            << "\n\tthis:   " << this
            << "\n\tsize(): " << this->size()
            << "\n\tindex:  " << index
            );

        // call the real function
        return sb_base::get_element_id(index);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename sb_base
        >
    unsigned long sliding_buffer_kernel_c<sb_base>::
    get_element_index (
        unsigned long element_id
    ) const
    {
        // make sure requires clause is not broken
        DLIB_CASSERT( element_id < this->size(),
            "\tunsigned long sliding_buffer::get_element_index(unsigned long) const"
            << "\n\tid must be in the range 0 to size()-1"
            << "\n\tthis:   " << this
            << "\n\tsize(): " << this->size()
            << "\n\tid:     " << element_id
            );

        // call the real function
        return sb_base::get_element_index(element_id);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename sb_base
        >
    const typename sb_base::type& sliding_buffer_kernel_c<sb_base>::
    operator[] (
        unsigned long index
    ) const
    {
        // make sure requires clause is not broken
        DLIB_CASSERT( index < this->size(),
            "\tconst T& sliding_buffer::operator[](unsigned long) const"
            << "\n\tindex must be in the range 0 to size()-1"
            << "\n\tthis:   " << this
            << "\n\tsize(): " << this->size()
            << "\n\tindex:  " << index
            );

        // call the real function
        return sb_base::operator[](index);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename sb_base
        >
    typename sb_base::type& sliding_buffer_kernel_c<sb_base>::
    operator[] (
        unsigned long index
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT( index < this->size(),
            "\tT& sliding_buffer::operator[](unsigned long)"
            << "\n\tindex must be in the range 0 to size()-1"
            << "\n\tthis:   " << this
            << "\n\tsize(): " << this->size()
            << "\n\tindex:  " << index
            );

        // call the real function
        return sb_base::operator[](index);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename sb_base
        >
    const typename sb_base::type& sliding_buffer_kernel_c<sb_base>::
    element (
    ) const
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(this->current_element_valid() == true,
            "\tconst T& sliding_buffer::element"
            << "\n\tyou can't access the current element if it doesn't exist"
            << "\n\tthis: " << this
            );

        // call the real function
        return sb_base::element();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename sb_base
        >
    typename sb_base::type& sliding_buffer_kernel_c<sb_base>::
    element (
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(this->current_element_valid() == true,
            "\tT& sliding_buffer::element"
            << "\n\tyou can't access the current element if it doesn't exist"
            << "\n\tthis: " << this
            );

        // call the real function
        return sb_base::element();
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SLIDING_BUFFER_KERNEl_C_


dlib C++ Library - scoped_ptr.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SCOPED_PTr_
#define DLIB_SCOPED_PTr_

#include <algorithm>
#include "../noncopyable.h"
#include "../algs.h"
#include "scoped_ptr_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <typename T>
    struct default_deleter
    {
        void operator() (T* item) const
        {
            delete item;
        }
    };

    template <typename T>
    struct default_deleter<T[]>
    {
        void operator() (T* item) const
        {
            delete [] item;
        }
    };

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename deleter = default_deleter<T>
        >
    class scoped_ptr : noncopyable
    {
        /*!
            CONVENTION
                - get() == ptr
        !*/

    public:
        typedef T element_type;
        typedef deleter deleter_type;

        explicit scoped_ptr (
            T* p = 0
        ) : ptr(p) { }

        ~scoped_ptr()
        {
            if (ptr)
            {
                deleter del;
                del(ptr);
            }
        }

        void reset (
            T* p = 0
        )
        {
            if (ptr)
            {
                deleter del;
                del(ptr);
            }

            ptr = p;
        }

        T& operator*() const
        {
            DLIB_ASSERT(get() != 0,
                        "\tscoped_ptr::operator*()"
                        << "\n\tget() can't be null if you are going to dereference it"
                        << "\n\tthis: " << this
            );

            return *ptr;
        }

        T* operator->() const
        {
            DLIB_ASSERT(get() != 0,
                        "\tscoped_ptr::operator*()"
                        << "\n\tget() can't be null"
                        << "\n\tthis: " << this
            );

            return ptr;
        }

        T* get() const
        {
            return ptr;
        }

        operator bool() const
        {
            return (ptr != 0);
        }

        void swap(
            scoped_ptr& b
        )
        {
            std::swap(ptr,b.ptr);
        }

    private:

        T* ptr;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename deleter
        >
    class scoped_ptr<T[],deleter> : noncopyable
    {
        /*!
            CONVENTION
                - get() == ptr
        !*/

    public:
        typedef T element_type;

        explicit scoped_ptr (
            T* p = 0
        ) : ptr(p) { }

        ~scoped_ptr()
        {
            if (ptr)
            {
                deleter del;
                del(ptr);
            }
        }

        void reset (
            T* p = 0
        )
        {
            if (ptr)
            {
                deleter del;
                del(ptr);
            }
            ptr = p;
        }

        T& operator[] (
            unsigned long idx
        ) const
        {
            DLIB_ASSERT(get() != 0,
                        "\tscoped_ptr::operator[]()"
                        << "\n\tget() can't be null if you are going to dereference it"
                        << "\n\tthis: " << this
            );

            return ptr[idx];
        }

        T* get() const
        {
            return ptr;
        }

        operator bool() const
        {
            return (ptr != 0);
        }

        void swap(
            scoped_ptr& b
        )
        {
            std::swap(ptr,b.ptr);
        }

    private:

        T* ptr;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename deleter
        >
    void swap(
        scoped_ptr<T,deleter>& a,
        scoped_ptr<T,deleter>& b
    )
    {
        a.swap(b);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SCOPED_PTr_


dlib C++ Library - shared_ptr.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SHARED_PTr_
#define DLIB_SHARED_PTr_

#include <algorithm>
#include <memory>
#include <typeinfo>
#include <string>       // for the exceptions
#include "../algs.h"
#include "shared_ptr_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class bad_weak_ptr: public std::exception {};

// ----------------------------------------------------------------------------------------

    template<typename T> class weak_ptr;

// ----------------------------------------------------------------------------------------

    struct shared_ptr_deleter
    {
        virtual void del(const void* p) = 0;
        virtual ~shared_ptr_deleter() {}

        virtual void* get_deleter_void(const std::type_info& t) const = 0;
        /*!
            ensures
                - if (the deleter in this object has typeid() == t) then
                    - returns a pointer to the deleter
                - else
                    - return 0
        !*/
    };

    struct shared_ptr_node;
    struct weak_ptr_node
    {
        weak_ptr_node (
            shared_ptr_node* sn
        ) :
            ref_count(1),
            shared_node(sn)
        {
            DLIB_ASSERT(sn != 0,"");
        }

        long ref_count;
        shared_ptr_node* shared_node;
    };

    struct shared_ptr_node
    {
        shared_ptr_node(
        ) :
            ref_count(1),
            del(0),
            weak_node(0)
        {}

        long ref_count;
        shared_ptr_deleter* del;
        weak_ptr_node* weak_node;
    };

    struct shared_ptr_static_cast {};
    struct shared_ptr_const_cast {};
    struct shared_ptr_dynamic_cast {};

// ----------------------------------------------------------------------------------------

    template<typename T>
    class shared_ptr
    {
        /*!
            CONVENTION
                - get() == data
                - unique() == (shared_node != 0) && (shared_node->ref_count == 1)
                - if (shared_node != 0) then
                    - use_count() == shared_node->ref_count
                    - get() == a valid pointer
                    - if (we are supposed to use the deleter) then
                        - shared_node->del == the deleter to use
                    - else
                        - shared_node->del == 0
                - else
                    - use_count() == 0
                    - get() == 0

                - if (there are any weak_ptrs that reference this->data) then
                    - shared_node->weak_node->ref_count == the number of referencing weak_ptrs
                - else
                    - shared_node->weak_node == 0
        !*/

        template <typename D>
        struct deleter_template : public shared_ptr_deleter
        {
            deleter_template(const D& d_) : d(d_) {}
            void del(const void* p) { d((T*)p); }
            D d;

            void* get_deleter_void(const std::type_info& t) const
            {
                if (typeid(D) == t)
                    return (void*)&d;
                else
                    return 0;
            }
        };

        struct default_deleter : public shared_ptr_deleter
        {
            void del(const void* p) { delete ((T*)p); }

            void* get_deleter_void(const std::type_info&) const
            {
                return 0;
            }
        };

    public:

        typedef T element_type;

        shared_ptr(
        ) : data(0), shared_node(0) {}

        template<typename Y>
        explicit shared_ptr(
            Y* p
        ) : data(p)
        {
            DLIB_ASSERT(p != 0,
                "\tshared_ptr::shared_ptr(p)"
                << "\n\tp can't be null"
                << "\n\tthis: " << this
                );
            try
            {
                shared_node = new shared_ptr_node;
                shared_node->del = new default_deleter;
            }
            catch (...)
            {
                delete p;
                throw;
            }
        }

        template<typename Y, typename D>
        shared_ptr(
            Y* p,
            const D& d
        ) :
            data(p)
        {
            DLIB_ASSERT(p != 0,
                "\tshared_ptr::shared_ptr(p,d)"
                << "\n\tp can't be null"
                << "\n\tthis: " << this
                );
            try
            {
                shared_node = 0;
                shared_node = new shared_ptr_node;
                shared_node->del = new deleter_template<D>(d);
            }
            catch (...)
            {
                if (shared_node) delete shared_node;
                d(p);
                throw;
            }
        }

        ~shared_ptr()
        {
            if ( shared_node != 0)
            {
                if (shared_node->ref_count == 1)
                {
                    // delete the data in the appropriate way
                    shared_node->del->del(data);
                    delete shared_node->del;

                    // notify any weak_ptrs that the data has now expired
                    if (shared_node->weak_node)
                        shared_node->weak_node->shared_node = 0;

                    // finally delete the shared_node
                    delete shared_node;
                }
                else
                {
                    shared_node->ref_count -= 1;
                }
            }
        }

        shared_ptr(
            const shared_ptr& r
        )
        {
            data = r.data;
            shared_node = r.shared_node;
            if (shared_node)
                shared_node->ref_count += 1;
        }

        template<typename Y>
        shared_ptr(
            const shared_ptr<Y>& r,
            const shared_ptr_static_cast&
        )
        {
            data = static_cast<T*>(r.data);
            if (data != 0)
            {
                shared_node = r.shared_node;
                shared_node->ref_count += 1;
            }
            else
            {
                shared_node = 0;
            }
        }

        template<typename Y>
        shared_ptr(
            const shared_ptr<Y>& r,
            const shared_ptr_const_cast&
        )
        {
            data = const_cast<T*>(r.data);
            if (data != 0)
            {
                shared_node = r.shared_node;
                shared_node->ref_count += 1;
            }
            else
            {
                shared_node = 0;
            }
        }

        template<typename Y>
        shared_ptr(
            const shared_ptr<Y>& r,
            const shared_ptr_dynamic_cast&
        )
        {
            data = dynamic_cast<T*>(r.data);
            if (data != 0)
            {
                shared_node = r.shared_node;
                shared_node->ref_count += 1;
            }
            else
            {
                shared_node = 0;
            }
        }

        template<typename Y>
        shared_ptr(
            const shared_ptr<Y>& r
        )
        {
            data = r.data;
            shared_node = r.shared_node;
            if (shared_node)
                shared_node->ref_count += 1;
        }

        template<typename Y>
        explicit shared_ptr(
            const weak_ptr<Y>& r
        )
        {
            if (r.expired())
                throw bad_weak_ptr();

            data = r.data;
            shared_node = r.weak_node->shared_node;
            shared_node->ref_count += 1;
        }

        template<typename Y>
        explicit shared_ptr(
            std::auto_ptr<Y>& r
        )
        {
            DLIB_ASSERT(r.get() != 0,
                "\tshared_ptr::shared_ptr(auto_ptr r)"
                << "\n\tr.get() can't be null"
                << "\n\tthis: " << this
                );
            shared_node = new shared_ptr_node;
            shared_node->del = new default_deleter;
            data = r.release();
        }

        shared_ptr& operator= (
            const shared_ptr& r
        )
        {
            shared_ptr(r).swap(*this);
            return *this;
        }

        template<typename Y>
        shared_ptr& operator= (
            const shared_ptr<Y>& r
        )
        {
            shared_ptr(r).swap(*this);
            return *this;
        }

        template<typename Y>
        shared_ptr& operator= (
            std::auto_ptr<Y>& r
        )
        {
            DLIB_ASSERT(r.get() != 0,
                "\tshared_ptr::operator=(auto_ptr r)"
                << "\n\tr.get() can't be null"
                << "\n\tthis: " << this
                );

            reset();
            shared_node = new shared_ptr_node;
            shared_node->del = new default_deleter;
            data = r.release();
            return *this;
        }

        void reset()
        {
            shared_ptr().swap(*this);
        }

        template<typename Y>
        void reset(Y* p)
        {
            DLIB_ASSERT(p != 0,
                "\tshared_ptr::reset(p)"
                << "\n\tp can't be null"
                << "\n\tthis: " << this
                );

            shared_ptr(p).swap(*this);
        }

        template<typename Y, typename D>
        void reset(
            Y* p,
            const D& d
        )
        {
            DLIB_ASSERT(p != 0,
                "\tshared_ptr::reset(p,d)"
                << "\n\tp can't be null"
                << "\n\tthis: " << this
                );

            shared_ptr(p,d).swap(*this);
        }

        T& operator*(
        ) const
        {
            DLIB_ASSERT(get() != 0,
                "\tshared_ptr::operator*()"
                << "\n\tget() can't be null if you are going to dereference it"
                << "\n\tthis: " << this
                );

            return *data;
        }

        T* operator->(
        ) const
        {
            DLIB_ASSERT(get() != 0,
                "\tshared_ptr::operator->()"
                << "\n\tget() can't be null"
                << "\n\tthis: " << this
                );

            return data;
        }

        T* get() const { return data; }

        bool unique() const
        {
            return use_count() == 1;
        }

        long use_count() const
        {
            if (shared_node != 0)
                return shared_node->ref_count;
            else
                return 0;
        }

        operator bool(
        ) const { return get() != 0; }

        void swap(shared_ptr& b)
        {
            std::swap(data, b.data);
            std::swap(shared_node, b.shared_node);
        }

        template <typename D>
        D* _get_deleter(
        ) const
        {
            if (shared_node && shared_node->del)
                return static_cast<D*>(shared_node->del->get_deleter_void(typeid(D)));
            else
                return 0;
        }

        template <typename Y>
        bool _private_less (
            const shared_ptr<Y>& rhs
        ) const
        {
            return shared_node < rhs.shared_node;
        }

    private:

        template <typename Y> friend class shared_ptr;
        template <typename Y> friend class weak_ptr;

        T* data;
        shared_ptr_node* shared_node;
    };

// ----------------------------------------------------------------------------------------

    template<typename T, typename U>
    bool operator== (
        const shared_ptr<T>& a,
        const shared_ptr<U>& b
    ) { return a.get() == b.get(); }

    template<typename T, typename U>
    bool operator!= (
        const shared_ptr<T>& a,
        const shared_ptr<U>& b
    ) { return a.get() != b.get(); }

    template<typename T, typename U>
    bool operator< (
        const shared_ptr<T>& a,
        const shared_ptr<U>& b
    )
    {
        return a._private_less(b);
    }

    template<typename T>
    void swap(
        shared_ptr<T>& a,
        shared_ptr<T>& b
    ) { a.swap(b); }

    template<typename T, typename U>
    shared_ptr<T> static_pointer_cast(
        const shared_ptr<U>& r
    )
    {
        return shared_ptr<T>(r, shared_ptr_static_cast());
    }

    template<typename T, typename U>
    shared_ptr<T> const_pointer_cast(
        shared_ptr<U> const & r
    )
    {
        return shared_ptr<T>(r, shared_ptr_const_cast());
    }

    template<typename T, typename U>
    shared_ptr<T> dynamic_pointer_cast(
        const shared_ptr<U>& r
    )
    {
        return shared_ptr<T>(r, shared_ptr_dynamic_cast());
    }

    template<typename E, typename T, typename Y>
    std::basic_ostream<E, T> & operator<< (std::basic_ostream<E, T> & os, shared_ptr<Y> const & p)
    {
        os << p.get();
        return os;
    }

    template<typename D, typename T>
    D* get_deleter(const shared_ptr<T>& p)
    {
        return p.template _get_deleter<D>();
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SHARED_PTr_


dlib C++ Library - shared_ptr_thread_safe.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SHARED_THREAD_SAFE_PTr_
#define DLIB_SHARED_THREAD_SAFE_PTr_

#include <algorithm>
#include <memory>
#include <typeinfo>
#include <string>       // for the exceptions
#include "../algs.h"
#include "shared_ptr_thread_safe_abstract.h"
#include "../threads/threads_kernel.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    struct shared_ptr_thread_safe_deleter
    {
        virtual void del(const void* p) = 0;
        virtual ~shared_ptr_thread_safe_deleter() {}

        virtual void* get_deleter_void(const std::type_info& t) const = 0;
        /*!
            ensures
                - if (the deleter in this object has typeid() == t) then
                    - returns a pointer to the deleter
                - else
                    - return 0
        !*/
    };

    struct shared_ptr_thread_safe_node
    {
        shared_ptr_thread_safe_node(
        ) :
            ref_count(1),
            del(0)
        {}

        dlib::mutex m;
        long ref_count;
        shared_ptr_thread_safe_deleter* del;
    };

    struct shared_ptr_ts_static_cast {};
    struct shared_ptr_ts_const_cast {};
    struct shared_ptr_ts_dynamic_cast {};

// ----------------------------------------------------------------------------------------

    template<typename T>
    class shared_ptr_thread_safe
    {
        /*!
            CONVENTION
                - get() == data
                - unique() == (shared_node != 0) && (shared_node->ref_count == 1)
                - if (shared_node != 0) then
                    - use_count() == shared_node->ref_count
                    - get() == a valid pointer
                    - if (we are supposed to use the deleter) then
                        - shared_node->del == the deleter to use
                    - else
                        - shared_node->del == 0
                - else
                    - use_count() == 0
                    - get() == 0

        !*/

        template <typename D>
        struct deleter_template : public shared_ptr_thread_safe_deleter
        {
            deleter_template(const D& d_) : d(d_) {}
            void del(const void* p) { d((T*)p); }
            D d;

            void* get_deleter_void(const std::type_info& t) const
            {
                if (typeid(D) == t)
                    return (void*)&d;
                else
                    return 0;
            }
        };

    public:

        typedef T element_type;

        shared_ptr_thread_safe(
        ) : data(0), shared_node(0) {}

        template<typename Y>
        explicit shared_ptr_thread_safe(
            Y* p
        ) : data(p)
        {
            DLIB_ASSERT(p != 0,
                "\tshared_ptr::shared_ptr_thread_safe(p)"
                << "\n\tp can't be null"
                << "\n\tthis: " << this
                );
            try
            {
                shared_node = new shared_ptr_thread_safe_node;
            }
            catch (...)
            {
                delete p;
                throw;
            }
        }

        template<typename Y, typename D>
        shared_ptr_thread_safe(
            Y* p,
            const D& d
        ) :
            data(p)
        {
            DLIB_ASSERT(p != 0,
                "\tshared_ptr::shared_ptr_thread_safe(p,d)"
                << "\n\tp can't be null"
                << "\n\tthis: " << this
                );
            try
            {
                shared_node = 0;
                shared_node = new shared_ptr_thread_safe_node;
                shared_node->del = new deleter_template<D>(d);
            }
            catch (...)
            {
                if (shared_node) delete shared_node;
                d(p);
                throw;
            }
        }

        ~shared_ptr_thread_safe()
        {
            if ( shared_node != 0)
            {
                shared_node->m.lock();
                if (shared_node->ref_count == 1)
                {
                    // delete the data in the appropriate way
                    if (shared_node->del)
                    {
                        shared_node->del->del(data);

                        shared_node->m.unlock();
                        delete shared_node->del;
                    }
                    else
                    {
                        shared_node->m.unlock();
                        delete data;
                    }

                    // finally delete the shared_node
                    delete shared_node;
                }
                else
                {
                    shared_node->ref_count -= 1;
                    shared_node->m.unlock();
                }
            }
        }

        shared_ptr_thread_safe(
            const shared_ptr_thread_safe& r
        )
        {
            data = r.data;
            shared_node = r.shared_node;
            if (shared_node)
            {
                auto_mutex M(shared_node->m);
                shared_node->ref_count += 1;
            }
        }

        template<typename Y>
        shared_ptr_thread_safe(
            const shared_ptr_thread_safe<Y>& r,
            const shared_ptr_ts_static_cast&
        )
        {
            data = static_cast<T*>(r.data);
            if (data != 0)
            {
                shared_node = r.shared_node;
                auto_mutex M(shared_node->m);
                shared_node->ref_count += 1;
            }
            else
            {
                shared_node = 0;
            }
        }

        template<typename Y>
        shared_ptr_thread_safe(
            const shared_ptr_thread_safe<Y>& r,
            const shared_ptr_ts_const_cast&
        )
        {
            data = const_cast<T*>(r.data);
            if (data != 0)
            {
                shared_node = r.shared_node;
                auto_mutex M(shared_node->m);
                shared_node->ref_count += 1;
            }
            else
            {
                shared_node = 0;
            }
        }

        template<typename Y>
        shared_ptr_thread_safe(
            const shared_ptr_thread_safe<Y>& r,
            const shared_ptr_ts_dynamic_cast&
        )
        {
            data = dynamic_cast<T*>(r.data);
            if (data != 0)
            {
                shared_node = r.shared_node;
                auto_mutex M(shared_node->m);
                shared_node->ref_count += 1;
            }
            else
            {
                shared_node = 0;
            }
        }

        template<typename Y>
        shared_ptr_thread_safe(
            const shared_ptr_thread_safe<Y>& r
        )
        {
            data = r.data;
            shared_node = r.shared_node;
            if (shared_node)
            {
                auto_mutex M(shared_node->m);
                shared_node->ref_count += 1;
            }
        }

        template<typename Y>
        explicit shared_ptr_thread_safe(
            std::auto_ptr<Y>& r
        )
        {
            DLIB_ASSERT(r.get() != 0,
                "\tshared_ptr::shared_ptr_thread_safe(auto_ptr r)"
                << "\n\tr.get() can't be null"
                << "\n\tthis: " << this
                );
            shared_node = new shared_ptr_thread_safe_node;
            data = r.release();
        }

        shared_ptr_thread_safe& operator= (
            const shared_ptr_thread_safe& r
        )
        {
            shared_ptr_thread_safe(r).swap(*this);
            return *this;
        }

        template<typename Y>
        shared_ptr_thread_safe& operator= (
            const shared_ptr_thread_safe<Y>& r
        )
        {
            shared_ptr_thread_safe(r).swap(*this);
            return *this;
        }

        template<typename Y>
        shared_ptr_thread_safe& operator= (
            std::auto_ptr<Y>& r
        )
        {
            DLIB_ASSERT(r.get() != 0,
                "\tshared_ptr::operator=(auto_ptr r)"
                << "\n\tr.get() can't be null"
                << "\n\tthis: " << this
                );

            reset();
            shared_node = new shared_ptr_thread_safe_node;
            data = r.release();
            return *this;
        }

        void reset()
        {
            shared_ptr_thread_safe().swap(*this);
        }

        template<typename Y>
        void reset(Y* p)
        {
            DLIB_ASSERT(p != 0,
                "\tshared_ptr::reset(p)"
                << "\n\tp can't be null"
                << "\n\tthis: " << this
                );

            shared_ptr_thread_safe(p).swap(*this);
        }

        template<typename Y, typename D>
        void reset(
            Y* p,
            const D& d
        )
        {
            DLIB_ASSERT(p != 0,
                "\tshared_ptr::reset(p,d)"
                << "\n\tp can't be null"
                << "\n\tthis: " << this
                );

            shared_ptr_thread_safe(p,d).swap(*this);
        }

        T& operator*(
        ) const
        {
            DLIB_ASSERT(get() != 0,
                "\tshared_ptr::operator*()"
                << "\n\tget() can't be null if you are going to dereference it"
                << "\n\tthis: " << this
                );

            return *data;
        }

        T* operator->(
        ) const
        {
            DLIB_ASSERT(get() != 0,
                "\tshared_ptr::operator->()"
                << "\n\tget() can't be null"
                << "\n\tthis: " << this
                );

            return data;
        }

        T* get() const { return data; }

        bool unique() const
        {
            return use_count() == 1;
        }

        long use_count() const
        {
            if (shared_node != 0)
            {
                auto_mutex M(shared_node->m);
                return shared_node->ref_count;
            }
            else
            {
                return 0;
            }
        }

        operator bool(
        ) const { return get() != 0; }

        void swap(shared_ptr_thread_safe& b)
        {
            std::swap(data, b.data);
            std::swap(shared_node, b.shared_node);
        }

        template <typename D>
        D* _get_deleter(
        ) const
        {
            if (shared_node)
            {
                auto_mutex M(shared_node->m);
                if (shared_node->del)
                    return static_cast<D*>(shared_node->del->get_deleter_void(typeid(D)));
            }
            else
            {
                return 0;
            }
        }

        template <typename Y>
        bool _private_less (
            const shared_ptr_thread_safe<Y>& rhs
        ) const
        {
            return shared_node < rhs.shared_node;
        }

    private:

        template <typename Y> friend class shared_ptr_thread_safe;

        T* data;
        shared_ptr_thread_safe_node* shared_node;
    };

// ----------------------------------------------------------------------------------------

    template<typename T, typename U>
    bool operator== (
        const shared_ptr_thread_safe<T>& a,
        const shared_ptr_thread_safe<U>& b
    ) { return a.get() == b.get(); }

    template<typename T, typename U>
    bool operator!= (
        const shared_ptr_thread_safe<T>& a,
        const shared_ptr_thread_safe<U>& b
    ) { return a.get() != b.get(); }

    template<typename T, typename U>
    bool operator< (
        const shared_ptr_thread_safe<T>& a,
        const shared_ptr_thread_safe<U>& b
    )
    {
        return a._private_less(b);
    }

    template<typename T>
    void swap(
        shared_ptr_thread_safe<T>& a,
        shared_ptr_thread_safe<T>& b
    ) { a.swap(b); }

    template<typename T, typename U>
    shared_ptr_thread_safe<T> static_pointer_cast(
        const shared_ptr_thread_safe<U>& r
    )
    {
        return shared_ptr_thread_safe<T>(r, shared_ptr_ts_static_cast());
    }

    template<typename T, typename U>
    shared_ptr_thread_safe<T> const_pointer_cast(
        shared_ptr_thread_safe<U> const & r
    )
    {
        return shared_ptr_thread_safe<T>(r, shared_ptr_ts_const_cast());
    }

    template<typename T, typename U>
    shared_ptr_thread_safe<T> dynamic_pointer_cast(
        const shared_ptr_thread_safe<U>& r
    )
    {
        return shared_ptr_thread_safe<T>(r, shared_ptr_ts_dynamic_cast());
    }

    template<typename E, typename T, typename Y>
    std::basic_ostream<E, T> & operator<< (std::basic_ostream<E, T> & os, shared_ptr_thread_safe<Y> const & p)
    {
        os << p.get();
        return os;
    }

    template<typename D, typename T>
    D* get_deleter(const shared_ptr_thread_safe<T>& p)
    {
        return p.template _get_deleter<D>();
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SHARED_THREAD_SAFE_PTr_


dlib C++ Library - weak_ptr.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_WEAK_PTr_
#define DLIB_WEAK_PTr_

#include <algorithm>
#include <memory>
#include "shared_ptr.h"
#include "../algs.h"
#include "weak_ptr_abstract.h"

namespace dlib {

    template <
        typename T
        >
    class weak_ptr
    {

        /*!
            CONVENTION
                - if (weak_node != 0) then
                    - data == valid pointer to shared data
                    - weak_node->ref_count == the number of weak_ptrs that reference this->data
                - else
                    - data == 0

                - expired() == ((weak_node == 0) || (weak_node->shared_node == 0))
                - if (expired() == false) then
                    - use_count() == weak_node->shared_node->ref_count
                - else
                    - use_count() == 0
        !*/

    public:
        typedef T element_type;

        weak_ptr(
        ) : data(0), weak_node(0)
        {
        }

        template<typename Y>
        weak_ptr(
            const shared_ptr<Y>& r
        )
        {
            data = r.data;
            if (r.shared_node)
            {
                if (r.shared_node->weak_node)
                {
                    weak_node = r.shared_node->weak_node;
                    weak_node->ref_count += 1;
                }
                else
                {
                    weak_node = new weak_ptr_node(r.shared_node);
                    r.shared_node->weak_node = weak_node;
                }
            }
            else
            {
                weak_node = 0;
            }
        }

        weak_ptr(
            const weak_ptr& r
        )
        {
            data = r.data;
            weak_node = r.weak_node;
            if (weak_node)
                weak_node->ref_count += 1;
        }

        template<typename Y>
        weak_ptr(
            const weak_ptr<Y>& r
        )
        {
            data = r.data;
            weak_node = r.weak_node;
            if (weak_node)
                weak_node->ref_count += 1;
        }

        ~weak_ptr(
        )
        {
            if (weak_node)
            {
                // make note that this weak_ptr is being destroyed
                weak_node->ref_count -= 1;

                // if this is the last weak_ptr then we should clean up our stuff
                if (weak_node->ref_count == 0)
                {
                    if (expired() == false)
                        weak_node->shared_node->weak_node = 0;
                    delete weak_node;
                }
            }
        }

        weak_ptr& operator= (
            const weak_ptr& r
        )
        {
            weak_ptr(r).swap(*this);
            return *this;
        }

        template<typename Y>
        weak_ptr& operator= (
            const weak_ptr<Y>& r
        )
        {
            weak_ptr(r).swap(*this);
            return *this;
        }

        template<typename Y>
        weak_ptr& operator=(
            const shared_ptr<Y>& r
        )
        {
            weak_ptr(r).swap(*this);
            return *this;
        }

        long use_count(
        ) const
        {
            if (expired())
                return 0;
            else
                return weak_node->shared_node->ref_count;
        }

        bool expired() const { return weak_node == 0 || weak_node->shared_node == 0; }

        shared_ptr<T> lock(
        ) const
        {
            if (expired())
                return shared_ptr<T>();
            else
                return shared_ptr<T>(*this);
        }

        void reset(
        )
        {
            weak_ptr().swap(*this);
        }

        void swap(
            weak_ptr<T>& b
        )
        {
            std::swap(data, b.data);
            std::swap(weak_node, b.weak_node);
        }

        template <typename Y>
        bool _private_less (
            const weak_ptr<Y>& rhs
        ) const
        {
            if (expired())
            {
                if (rhs.expired())
                {
                    return false;
                }
                else
                {
                    return true;
                }
            }
            else
            {
                if (rhs.expired())
                {
                    return false;
                }
                else
                {
                    // in this case they have both not expired so lets
                    // compare the shared_node pointers
                    return (weak_node->shared_node) < (rhs.weak_node->shared_node);
                }
            }
        }

    private:

        template <typename Y> friend class shared_ptr;
        template <typename Y> friend class weak_ptr;

        T* data;
        weak_ptr_node* weak_node;
    };

    template<typename T, typename U>
    bool operator< (
        const weak_ptr<T>& a,
        const weak_ptr<U>& b
    )
    {
        return a._private_less(b);
    }

    template<typename T>
    void swap(
        weak_ptr<T>& a,
        weak_ptr<T> & b
    ) { a.swap(b); }
}

#endif // DLIB_WEAK_PTr_


dlib C++ Library - posix.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SOCKETS_KERNEl_1_
#include "sockets_kernel_2.h"
#endif


dlib C++ Library - sockets_extensions.cpp

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SOCKETS_EXTENSIONs_CPP
#define DLIB_SOCKETS_EXTENSIONs_CPP

#include <string>
#include <sstream>
#include "../sockets.h"
#include "../error.h"
#include "sockets_extensions.h"
#include "../timer.h"
#include "../algs.h"
#include "../timeout.h"
#include "../misc_api.h"
#include "../serialize.h"
#include "../string.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    network_address::
    network_address(
        const std::string& full_address
    )
    {
        std::istringstream sin(full_address);
        sin >> *this;
        if (!sin || sin.peek() != EOF)
            throw invalid_network_address("invalid network address: " + full_address);
    }

// ----------------------------------------------------------------------------------------

    void serialize(
        const network_address& item,
        std::ostream& out
    )
    {
        serialize(item.host_address, out);
        serialize(item.port, out);
    }

// ----------------------------------------------------------------------------------------

    void deserialize(
        network_address& item,
        std::istream& in
    )
    {
        deserialize(item.host_address, in);
        deserialize(item.port, in);
    }

// ----------------------------------------------------------------------------------------

    std::ostream& operator<< (
        std::ostream& out,
        const network_address& item
    )
    {
        out << item.host_address << ":" << item.port;
        return out;
    }

// ----------------------------------------------------------------------------------------

    std::istream& operator>> (
        std::istream& in,
        network_address& item
    )
    {
        std::string temp;
        in >> temp;

        std::string::size_type pos = temp.find_last_of(":");
        if (pos == std::string::npos)
        {
            in.setstate(std::ios::badbit);
            return in;
        }

        item.host_address = temp.substr(0, pos);
        try
        {
            item.port = sa = temp.substr(pos+1);
        } catch (std::exception& )
        {
            in.setstate(std::ios::badbit);
            return in;
        }

        return in;
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    connection* connect (
        const std::string& host_or_ip,
        unsigned short port
    )
    {
        std::string ip;
        connection* con;
        if (is_ip_address(host_or_ip))
        {
            ip = host_or_ip;
        }
        else
        {
            if( hostname_to_ip(host_or_ip,ip))
                throw socket_error(ERESOLVE,"unable to resolve '" + host_or_ip + "' in connect()");
        }

        if(create_connection(con,port,ip))
        {
            std::ostringstream sout;
            sout << "unable to connect to '" << host_or_ip << ":" << port << "'";
            throw socket_error(sout.str());
        }

        return con;
    }

// ----------------------------------------------------------------------------------------

    connection* connect (
        const network_address& addr
    )
    {
        return connect(addr.host_address, addr.port);
    }

// ----------------------------------------------------------------------------------------

    namespace connect_timeout_helpers
    {
        mutex connect_mutex;
        signaler connect_signaler(connect_mutex);
        timestamper ts;
        long outstanding_connects = 0;

        struct thread_data
        {
            std::string host_or_ip;
            unsigned short port;
            connection* con;
            bool connect_ended;
            bool error_occurred;
        };

        void thread(void* param)
        {
            thread_data p = *static_cast<thread_data*>(param);
            try
            {
                p.con = connect(p.host_or_ip, p.port);
            }
            catch (...)
            {
                p.error_occurred = true;
            }

            auto_mutex M(connect_mutex);
            // report the results back to the connect() call that spawned this
            // thread.
            static_cast<thread_data*>(param)->con = p.con;
            static_cast<thread_data*>(param)->error_occurred = p.error_occurred;
            connect_signaler.broadcast();

            // wait for the call to connect() that spawned this thread to terminate
            // before we delete the thread_data struct.
            while (static_cast<thread_data*>(param)->connect_ended == false)
                connect_signaler.wait();

            connect_signaler.broadcast();
            --outstanding_connects;
            delete static_cast<thread_data*>(param);
        }
    }

    connection* connect (
        const std::string& host_or_ip,
        unsigned short port,
        unsigned long timeout
    )
    {
        using namespace connect_timeout_helpers;

        auto_mutex M(connect_mutex);

        const uint64 end_time = ts.get_timestamp() + timeout*1000;

        // wait until there are less than 100 outstanding connections
        while (outstanding_connects > 100)
        {
            uint64 cur_time = ts.get_timestamp();
            if (end_time > cur_time)
            {
                timeout = static_cast<unsigned long>((end_time - cur_time)/1000);
            }
            else
            {
                throw socket_error("unable to connect to '" + host_or_ip + "' because connect timed out");
            }

            connect_signaler.wait_or_timeout(timeout);
        }

        thread_data* data = new thread_data;
        data->host_or_ip = host_or_ip.c_str();
        data->port = port;
        data->con = 0;
        data->connect_ended = false;
        data->error_occurred = false;

        if (create_new_thread(thread, data) == false)
        {
            delete data;
            throw socket_error("unable to connect to '" + host_or_ip);
        }

        ++outstanding_connects;

        // wait until we have a connection object
        while (data->con == 0)
        {
            uint64 cur_time = ts.get_timestamp();
            if (end_time > cur_time && data->error_occurred == false)
            {
                timeout = static_cast<unsigned long>((end_time - cur_time)/1000);
            }
            else
            {
                // let the thread know that it should terminate
                data->connect_ended = true;
                connect_signaler.broadcast();
                if (data->error_occurred)
                    throw socket_error("unable to connect to '" + host_or_ip);
                else
                    throw socket_error("unable to connect to '" + host_or_ip + "' because connect timed out");
            }

            connect_signaler.wait_or_timeout(timeout);
        }

        // let the thread know that it should terminate
        data->connect_ended = true;
        connect_signaler.broadcast();
        return data->con;
    }

// ----------------------------------------------------------------------------------------

    bool is_ip_address (
        std::string ip
    )
    {
        for (std::string::size_type i = 0; i < ip.size(); ++i)
        {
            if (ip[i] == '.')
                ip[i] = ' ';
        }
        std::istringstream sin(ip);

        bool bad = false;
        int num;
        for (int i = 0; i < 4; ++i)
        {
            sin >> num;
            if (!sin || num < 0 || num > 255)
            {
                bad = true;
                break;
            }
        }

        if (sin.get() != EOF)
            bad = true;

        return !bad;
    }

// ----------------------------------------------------------------------------------------

    void close_gracefully (
        connection* con,
        unsigned long timeout
    )
    {
        scoped_ptr<connection> ptr(con);
        close_gracefully(ptr,timeout);
    }

// ----------------------------------------------------------------------------------------

    void close_gracefully (
        scoped_ptr<connection>& con,
        unsigned long timeout
    )
    {
        if (!con)
            return;

        if(con->shutdown_outgoing())
        {
            // there was an error so just close it now and return
            con.reset();
            return;
        }

        try
        {
            dlib::timeout t(*con,&connection::shutdown,timeout);

            char junk[100];
            // wait for the other end to close their side
            while (con->read(junk,sizeof(junk)) > 0) ;
        }
        catch (...)
        {
            con.reset();
            throw;
        }

        con.reset();
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SOCKETS_EXTENSIONs_CPP


dlib C++ Library - sockets_extensions.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SOCKETS_EXTENSIONs_
#define DLIB_SOCKETS_EXTENSIONs_

#include <string>
#include "../sockets.h"
#include "sockets_extensions_abstract.h"
#include "../smart_pointers.h"
#include <iosfwd>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class invalid_network_address : public dlib::error
    {
    public:
        invalid_network_address(const std::string& msg) : dlib::error(msg) {};
    };

// ----------------------------------------------------------------------------------------

    struct network_address
    {
        network_address() : port(0){}

        network_address(
            const std::string& full_address
        );

        network_address (
            const char* full_address
        )
        {
            *this = network_address(std::string(full_address));
        }

        network_address(
            const std::string& host_address_,
            const unsigned short port_
        ) : host_address(host_address_), port(port_) {}

        std::string host_address;
        unsigned short port;
    };

// ----------------------------------------------------------------------------------------

    inline bool operator < (
        const network_address& a,
        const network_address& b
    )
    {
        if (a.host_address < b.host_address)
            return true;
        else if (a.host_address > b.host_address)
            return false;
        else if (a.port < b.port)
            return true;
        else
            return false;
    }

    inline bool operator== (
        const network_address& a,
        const network_address& b
    ) { return a.host_address == b.host_address && a.port == b.port; }

    inline bool operator != (
        const network_address& a,
        const network_address& b
    ) { return !(a == b); }

// ----------------------------------------------------------------------------------------

    void serialize(
        const network_address& item,
        std::ostream& out
    );

    void deserialize(
        network_address& item,
        std::istream& in
    );

    std::ostream& operator<< (
        std::ostream& out,
        const network_address& item
    );

    std::istream& operator>> (
        std::istream& in,
        network_address& item
    );

// ----------------------------------------------------------------------------------------

    connection* connect (
        const std::string& host_or_ip,
        unsigned short port
    );

// ----------------------------------------------------------------------------------------

    connection* connect (
        const network_address& addr
    );

// ----------------------------------------------------------------------------------------

    connection* connect (
        const std::string& host_or_ip,
        unsigned short port,
        unsigned long timeout
    );

// ----------------------------------------------------------------------------------------

    bool is_ip_address (
        std::string ip
    );

// ----------------------------------------------------------------------------------------

    void close_gracefully (
        connection* con,
        unsigned long timeout = 500
    );

// ----------------------------------------------------------------------------------------

    void close_gracefully (
        scoped_ptr<connection>& con,
        unsigned long timeout = 500
    );

// ----------------------------------------------------------------------------------------

}

#ifdef NO_MAKEFILE
#include "sockets_extensions.cpp"
#endif

#endif // DLIB_SOCKETS_EXTENSIONs_


dlib C++ Library - sockets_kernel_1.cpp

// Copyright (C) 2003  Davis E. King (davis@dlib.net), Miguel Grinberg
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SOCKETS_KERNEL_1_CPp_
#define DLIB_SOCKETS_KERNEL_1_CPp_
#include "../platform.h"

#ifdef WIN32

#ifndef _WINSOCKAPI_
#define _WINSOCKAPI_   /* Prevent inclusion of winsock.h in windows.h */
#endif

#include "../windows_magic.h"

#include "sockets_kernel_1.h"

#include <windows.h>
#include <winsock2.h>

#ifndef NI_MAXHOST
#define NI_MAXHOST 1025
#endif

// tell visual studio to link to the libraries we need if we are
// in fact using visual studio
#ifdef _MSC_VER
#pragma comment (lib, "ws2_32.lib")
#endif

#include "../assert.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class SOCKET_container
    {
        /*!
            This object is just a wrapper around the SOCKET type.  It exists
            so that we can #include the windows.h and Winsock2.h header files
            in this cpp file and not at all in the header file.
        !*/
    public:
        SOCKET_container (
            SOCKET s = INVALID_SOCKET
        ) : val(s) {}

        SOCKET val;
        operator SOCKET&() { return val; }

        SOCKET_container& operator= (
            const SOCKET& s
        ) { val = s; return *this; }

        bool operator== (
            const SOCKET& s
        ) const { return s == val; }
    };

// ----------------------------------------------------------------------------------------
// stuff to ensure that WSAStartup() is always called before any sockets stuff is needed

    namespace sockets_kernel_1_mutex
    {
        mutex startup_lock;
    }

    class sockets_startupdown
    {
    public:
        sockets_startupdown();
        ~sockets_startupdown() { WSACleanup( ); }

    };
    sockets_startupdown::sockets_startupdown (
    )
    {
        WSADATA wsaData;
        WSAStartup (MAKEWORD(2,0), &wsaData);
    }

    void sockets_startup()
    {
        // mutex crap to make this function thread-safe
        sockets_kernel_1_mutex::startup_lock.lock();
        static sockets_startupdown a;
        sockets_kernel_1_mutex::startup_lock.unlock();
    }

// ----------------------------------------------------------------------------------------

    // lookup functions

    int
    get_local_hostname (
        std::string& hostname
    )
    {
        // ensure that WSAStartup has been called and WSACleanup will eventually
        // be called when program ends
        sockets_startup();

        try
        {

            char temp[NI_MAXHOST];
            if (gethostname(temp,NI_MAXHOST) == SOCKET_ERROR )
            {
                return OTHER_ERROR;
            }

            hostname = temp;
        }
        catch (...)
        {
            return OTHER_ERROR;
        }

        return 0;
    }

// -----------------

    int
    hostname_to_ip (
        const std::string& hostname,
        std::string& ip,
        int n
    )
    {
        // ensure that WSAStartup has been called and WSACleanup will eventually
        // be called when program ends
        sockets_startup();

        try
        {
            // lock this mutex since gethostbyname isn't really thread safe
            auto_mutex M(sockets_kernel_1_mutex::startup_lock);

            // if no hostname was given then return error
            if ( hostname.empty())
                return OTHER_ERROR;

            hostent* address;
            address = gethostbyname(hostname.c_str());

            if (address == 0)
            {
                return OTHER_ERROR;
            }

            // find the nth address
            in_addr* addr = reinterpret_cast<in_addr*>(address->h_addr_list[0]);
            for (int i = 1; i <= n; ++i)
            {
                addr = reinterpret_cast<in_addr*>(address->h_addr_list[i]);

                // if there is no nth address then return error
                if (addr == 0)
                    return OTHER_ERROR;
            }

            char* resolved_ip = inet_ntoa(*addr);

            // check if inet_ntoa returned an error
            if (resolved_ip == NULL)
            {
                return OTHER_ERROR;
            }

            ip.assign(resolved_ip);

        }
        catch(...)
        {
            return OTHER_ERROR;
        }

        return 0;
    }

// -----------------

    int
    ip_to_hostname (
        const std::string& ip,
        std::string& hostname
    )
    {
        // ensure that WSAStartup has been called and WSACleanup will eventually
        // be called when program ends
        sockets_startup();

        try
        {
            // lock this mutex since gethostbyaddr isn't really thread safe
            auto_mutex M(sockets_kernel_1_mutex::startup_lock);

            // if no ip was given then return error
            if (ip.empty())
                return OTHER_ERROR;

            hostent* address;
            unsigned long ipnum = inet_addr(ip.c_str());

            // if inet_addr couldn't convert ip then return an error
            if (ipnum == INADDR_NONE)
            {
                return OTHER_ERROR;
            }
            address = gethostbyaddr(reinterpret_cast<char*>(&ipnum),4,AF_INET);

            // check if gethostbyaddr returned an error
            if (address == 0)
            {
                return OTHER_ERROR;
            }
            hostname.assign(address->h_name);

        }
        catch (...)
        {
            return OTHER_ERROR;
        }
        return 0;

    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // connection object
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    connection::
    connection(
        SOCKET_container sock,
        unsigned short foreign_port,
        const std::string& foreign_ip,
        unsigned short local_port,
        const std::string& local_ip
    ) :
        user_data(0),
        connection_socket(*(new SOCKET_container())),
        connection_foreign_port(foreign_port),
        connection_foreign_ip(foreign_ip),
        connection_local_port(local_port),
        connection_local_ip(local_ip),
        sd(false),
        sdo(false),
        sdr(0)
    {
       connection_socket = sock;
    }

// ----------------------------------------------------------------------------------------

    connection::
    ~connection (
    )
    {
        if (connection_socket != INVALID_SOCKET)
            closesocket(connection_socket);
        delete &connection_socket;
    }

// ----------------------------------------------------------------------------------------

    int connection::
    disable_nagle()
    {
        int flag = 1;
        int status = setsockopt( connection_socket, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag) );

        if (status == SOCKET_ERROR)
            return OTHER_ERROR;
        else
            return 0;
    }

// ----------------------------------------------------------------------------------------

    long connection::
    write (
        const char* buf,
        long num
    )
    {
        const long old_num = num;
        long status;
        const long max_send_length = 1024*1024*100;
        while (num > 0)
        {
            // Make sure to cap the max value num can take on so that if it is
            // really large (it might be big on 64bit platforms) so that the OS
            // can't possibly get upset about it being large.
            const long length = std::min(max_send_length, num);
            if ( (status = send(connection_socket,buf,length,0)) == SOCKET_ERROR)
            {
                if (sdo_called())
                    return SHUTDOWN;
                else
                    return OTHER_ERROR;
            }
            num -= status;
            buf += status;
        }
        return old_num;
    }

// ----------------------------------------------------------------------------------------

    long connection::
    read (
        char* buf,
        long num
    )
    {
        const long max_recv_length = 1024*1024*100;
        // Make sure to cap the max value num can take on so that if it is
        // really large (it might be big on 64bit platforms) so that the OS
        // can't possibly get upset about it being large.
        const long length = std::min(max_recv_length, num);
        long status = recv(connection_socket,buf,length,0);
        if (status == SOCKET_ERROR)
        {
            // if this error is the result of a shutdown call then return SHUTDOWN
            if (sd_called())
                return SHUTDOWN;
            else
                return OTHER_ERROR;
        }
        else if (status == 0 && sd_called())
        {
            return SHUTDOWN;
        }
        return status;
    }

// ----------------------------------------------------------------------------------------

    long connection::
    read (
        char* buf,
        long num,
        unsigned long timeout
    )
    {
        if (readable(timeout) == false)
            return TIMEOUT;

        const long max_recv_length = 1024*1024*100;
        // Make sure to cap the max value num can take on so that if it is
        // really large (it might be big on 64bit platforms) so that the OS
        // can't possibly get upset about it being large.
        const long length = std::min(max_recv_length, num);
        long status = recv(connection_socket,buf,length,0);
        if (status == SOCKET_ERROR)
        {
            // if this error is the result of a shutdown call then return SHUTDOWN
            if (sd_called())
                return SHUTDOWN;
            else
                return OTHER_ERROR;
        }
        else if (status == 0 && sd_called())
        {
            return SHUTDOWN;
        }
        return status;
    }

// ----------------------------------------------------------------------------------------

    bool connection::
    readable (
        unsigned long timeout
    ) const
    {
        fd_set read_set;
        // initialize read_set
        FD_ZERO(&read_set);

        // add the listening socket to read_set
        FD_SET(connection_socket, &read_set);

        // setup a timeval structure
        timeval time_to_wait;
        time_to_wait.tv_sec = static_cast<long>(timeout/1000);
        time_to_wait.tv_usec = static_cast<long>((timeout%1000)*1000);

        // wait on select
        int status = select(0,&read_set,0,0,&time_to_wait);

        // if select timed out or there was an error
        if (status <= 0)
            return false;

        // data is ready to be read
        return true;
    }

// ----------------------------------------------------------------------------------------

    int connection::
    shutdown_outgoing (
    )
    {
        sd_mutex.lock();
        if (sdo || sd)
        {
            sd_mutex.unlock();
            return sdr;
        }
        sdo = true;
        sdr = ::shutdown(connection_socket,SD_SEND);

        // convert -1 error code into the OTHER_ERROR error code
        if (sdr == -1)
            sdr = OTHER_ERROR;

        int temp = sdr;

        sd_mutex.unlock();
        return temp;
    }

// ----------------------------------------------------------------------------------------

    int connection::
    shutdown (
    )
    {
        sd_mutex.lock();
        if (sd)
        {
            sd_mutex.unlock();
            return sdr;
        }
        sd = true;
        SOCKET stemp = connection_socket;
        connection_socket = INVALID_SOCKET;
        sdr = closesocket(stemp);

        // convert SOCKET_ERROR error code into the OTHER_ERROR error code
        if (sdr == SOCKET_ERROR)
            sdr = OTHER_ERROR;

        int temp = sdr;

        sd_mutex.unlock();
        return temp;
    }

// ----------------------------------------------------------------------------------------

    connection::socket_descriptor_type connection::
    get_socket_descriptor (
    ) const
    {
        return connection_socket.val;
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // listener object
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    listener::
    listener(
        SOCKET_container sock,
        unsigned short port,
        const std::string& ip
    ) :
        listening_socket(*(new SOCKET_container)),
        listening_port(port),
        listening_ip(ip),
        inaddr_any(listening_ip.empty())
    {
        listening_socket = sock;
    }

// ----------------------------------------------------------------------------------------

    listener::
    ~listener (
    )
    {
        closesocket(listening_socket);
        delete &listening_socket;
    }

// ----------------------------------------------------------------------------------------

    int listener::
    accept (
        scoped_ptr<connection>& new_connection,
        unsigned long timeout
    )
    {
        new_connection.reset(0);
        connection* con;
        int status = this->accept(con, timeout);

        if (status == 0)
            new_connection.reset(con);

        return status;
    }

// ----------------------------------------------------------------------------------------

    int listener::
    accept (
        connection*& new_connection,
        unsigned long timeout
    )
    {
        SOCKET incoming;
        sockaddr_in incomingAddr;
        int length = sizeof(sockaddr_in);

        // implement timeout with select if timeout is > 0
        if (timeout > 0)
        {
            fd_set read_set;
            // initialize read_set
            FD_ZERO(&read_set);

            // add the listening socket to read_set
            FD_SET(listening_socket, &read_set);

            // setup a timeval structure
            timeval time_to_wait;
            time_to_wait.tv_sec = static_cast<long>(timeout/1000);
            time_to_wait.tv_usec = static_cast<long>((timeout%1000)*1000);

            // wait on select
            int status = select(0,&read_set,0,0,&time_to_wait);

            // if select timed out
            if (status == 0)
                return TIMEOUT;

            // if select returned an error
            if (status == SOCKET_ERROR)
                return OTHER_ERROR;

        }

        // call accept to get a new connection
        incoming=::accept(listening_socket,reinterpret_cast<sockaddr*>(&incomingAddr),&length);

        // if there was an error return OTHER_ERROR
        if ( incoming == INVALID_SOCKET )
            return OTHER_ERROR;

        // get the port of the foreign host into foreign_port
        int foreign_port = ntohs(incomingAddr.sin_port);

        // get the IP of the foreign host into foreign_ip
        std::string foreign_ip;
        {
            char* foreign_ip_temp = inet_ntoa(incomingAddr.sin_addr);

            // check if inet_ntoa() returned an error
            if (foreign_ip_temp == NULL)
            {
                closesocket(incoming);
                return OTHER_ERROR;
            }

            foreign_ip.assign(foreign_ip_temp);
        }

        // get the local ip
        std::string local_ip;
        if (inaddr_any == true)
        {
            sockaddr_in local_info;
            length = sizeof(sockaddr_in);
            // get the local sockaddr_in structure associated with this new connection
            if ( getsockname (
                    incoming,
                    reinterpret_cast<sockaddr*>(&local_info),
                    &length
                 ) == SOCKET_ERROR
            )
            {   // an error occurred
                closesocket(incoming);
                return OTHER_ERROR;
            }
            char* temp = inet_ntoa(local_info.sin_addr);

            // check if inet_ntoa() returned an error
            if (temp == NULL)
            {
                closesocket(incoming);
                return OTHER_ERROR;
            }
            local_ip.assign(temp);
        }
        else
        {
            local_ip = listening_ip;
        }

        // set the SO_OOBINLINE option
        int flag_value = 1;
        if (setsockopt(incoming,SOL_SOCKET,SO_OOBINLINE,reinterpret_cast<const char*>(&flag_value),sizeof(int)) == SOCKET_ERROR )
        {
            closesocket(incoming);
            return OTHER_ERROR;
        }

        // make a new connection object for this new connection
        try
        {
            new_connection = new connection (
                                    incoming,
                                    foreign_port,
                                    foreign_ip,
                                    listening_port,
                                    local_ip
                                );
        }
        catch (...) { closesocket(incoming); return OTHER_ERROR; }

        return 0;
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // socket creation functions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    int create_listener (
        scoped_ptr<listener>& new_listener,
        unsigned short port,
        const std::string& ip
    )
    {
        new_listener.reset();
        listener* temp;
        int status = create_listener(temp,port,ip);

        if (status == 0)
            new_listener.reset(temp);

        return status;
    }

    int create_listener (
        listener*& new_listener,
        unsigned short port,
        const std::string& ip
    )
    {
        // ensure that WSAStartup has been called and WSACleanup will eventually
        // be called when program ends
        sockets_startup();

        sockaddr_in sa;  // local socket structure
        ZeroMemory(&sa,sizeof(sockaddr_in)); // initialize sa

        SOCKET sock = socket (AF_INET, SOCK_STREAM, 0);  // get a new socket

        // if socket() returned an error then return OTHER_ERROR
        if (sock == INVALID_SOCKET )
        {
            return OTHER_ERROR;
        }

        // set the local socket structure
        sa.sin_family = AF_INET;
        sa.sin_port = htons(port);
        if (ip.empty())
        {
            // if the listener should listen on any IP
            sa.sin_addr.S_un.S_addr = htons(INADDR_ANY);
        }
        else
        {
            // if there is a specific ip to listen on
            sa.sin_addr.S_un.S_addr = inet_addr(ip.c_str());
            // if inet_addr couldn't convert the ip then return an error
            if ( sa.sin_addr.S_un.S_addr == INADDR_NONE )
            {
                closesocket(sock);
                return OTHER_ERROR;
            }
        }

        // set the SO_REUSEADDR option
        int flag_value = 1;
        setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,reinterpret_cast<const char*>(&flag_value),sizeof(int));

        // bind the new socket to the requested port and ip
        if (bind(sock,reinterpret_cast<sockaddr*>(&sa),sizeof(sockaddr_in))==SOCKET_ERROR)
        {
            const int err = WSAGetLastError();
            // if there was an error
            closesocket(sock);

            // if the port is already bound then return PORTINUSE
            if (err == WSAEADDRINUSE)
                return PORTINUSE;
            else
                return OTHER_ERROR;
        }

        // tell the new socket to listen
        if ( listen(sock,SOMAXCONN) == SOCKET_ERROR)
        {
            const int err = WSAGetLastError();
            // if there was an error return OTHER_ERROR
            closesocket(sock);

            // if the port is already bound then return PORTINUSE
            if (err == WSAEADDRINUSE)
                return PORTINUSE;
            else
                return OTHER_ERROR;
        }

        // determine the port used if necessary
        if (port == 0)
        {
            sockaddr_in local_info;
            int length = sizeof(sockaddr_in);
            if ( getsockname (
                        sock,
                        reinterpret_cast<sockaddr*>(&local_info),
                        &length
                 ) == SOCKET_ERROR
            )
            {
                closesocket(sock);
                return OTHER_ERROR;
            }
            port = ntohs(local_info.sin_port);
        }

        // initialize a listener object on the heap with the new socket
        try { new_listener = new listener(sock,port,ip); }
        catch(...) { closesocket(sock); return OTHER_ERROR; }

        return 0;
    }

// ----------------------------------------------------------------------------------------

    int create_connection (
        scoped_ptr<connection>& new_connection,
        unsigned short foreign_port,
        const std::string& foreign_ip,
        unsigned short local_port,
        const std::string& local_ip
    )
    {
        new_connection.reset();
        connection* temp;
        int status = create_connection(temp,foreign_port, foreign_ip, local_port, local_ip);

        if (status == 0)
            new_connection.reset(temp);

        return status;
    }

    int create_connection (
        connection*& new_connection,
        unsigned short foreign_port,
        const std::string& foreign_ip,
        unsigned short local_port,
        const std::string& local_ip
    )
    {
        // ensure that WSAStartup has been called and WSACleanup
        // will eventually be called when program ends
        sockets_startup();

        sockaddr_in local_sa;  // local socket structure
        sockaddr_in foreign_sa;  // foreign socket structure
        ZeroMemory(&local_sa,sizeof(sockaddr_in)); // initialize local_sa
        ZeroMemory(&foreign_sa,sizeof(sockaddr_in)); // initialize foreign_sa

        int length;

        SOCKET sock = socket (AF_INET, SOCK_STREAM, 0);  // get a new socket

        // if socket() returned an error then return OTHER_ERROR
        if (sock == INVALID_SOCKET )
        {
            return OTHER_ERROR;
        }

        // set the foreign socket structure
        foreign_sa.sin_family = AF_INET;
        foreign_sa.sin_port = htons(foreign_port);
        foreign_sa.sin_addr.S_un.S_addr = inet_addr(foreign_ip.c_str());

        // if inet_addr couldn't convert the ip then return an error
        if ( foreign_sa.sin_addr.S_un.S_addr == INADDR_NONE )
        {
            closesocket(sock);
            return OTHER_ERROR;
        }

        // set up the local socket structure
        local_sa.sin_family = AF_INET;

        // set the local ip
        if (local_ip.empty())
        {
            // if the listener should listen on any IP
            local_sa.sin_addr.S_un.S_addr = htons(INADDR_ANY);
        }
        else
        {
            // if there is a specific ip to listen on
            local_sa.sin_addr.S_un.S_addr = inet_addr(local_ip.c_str());

            // if inet_addr couldn't convert the ip then return an error
            if (local_sa.sin_addr.S_un.S_addr == INADDR_NONE)
            {
                closesocket(sock);
                return OTHER_ERROR;
            }
        }

        // set the local port
        local_sa.sin_port = htons(local_port);

        // bind the new socket to the requested local port and local ip
        if ( bind (
                sock,
                reinterpret_cast<sockaddr*>(&local_sa),
                sizeof(sockaddr_in)
            ) == SOCKET_ERROR
        )
        {
            const int err = WSAGetLastError();
            // if there was an error
            closesocket(sock);

            // if the port is already bound then return PORTINUSE
            if (err == WSAEADDRINUSE)
                return PORTINUSE;
            else
                return OTHER_ERROR;
        }

        // connect the socket
        if (connect (
                sock,
                reinterpret_cast<sockaddr*>(&foreign_sa),
                sizeof(sockaddr_in)
            ) == SOCKET_ERROR
        )
        {
            const int err = WSAGetLastError();
            closesocket(sock);
            // if the port is already bound then return PORTINUSE
            if (err == WSAEADDRINUSE)
                return PORTINUSE;
            else
                return OTHER_ERROR;
        }

        // determine the local port and IP and store them in used_local_ip
        // and used_local_port
        int used_local_port;
        std::string used_local_ip;
        sockaddr_in local_info;
        if (local_port == 0)
        {
            length = sizeof(sockaddr_in);
            if (getsockname (
                    sock,
                    reinterpret_cast<sockaddr*>(&local_info),
                    &length
                ) == SOCKET_ERROR
            )
            {
                closesocket(sock);
                return OTHER_ERROR;
            }
            used_local_port = ntohs(local_info.sin_port);
        }
        else
        {
            used_local_port = local_port;
        }

        // determine real local ip
        if (local_ip.empty())
        {
            // if local_port is not 0 then we must fill the local_info structure
            if (local_port != 0)
            {
                length = sizeof(sockaddr_in);
                if ( getsockname (
                        sock,
                        reinterpret_cast<sockaddr*>(&local_info),
                        &length
                    ) == SOCKET_ERROR
                )
                {
                    closesocket(sock);
                    return OTHER_ERROR;
                }
            }
            char* temp = inet_ntoa(local_info.sin_addr);

            // check if inet_ntoa returned an error
            if (temp == NULL)
            {
                closesocket(sock);
                return OTHER_ERROR;
            }
            used_local_ip.assign(temp);
        }
        else
        {
            used_local_ip = local_ip;
        }

        // set the SO_OOBINLINE option
        int flag_value = 1;
        if (setsockopt(sock,SOL_SOCKET,SO_OOBINLINE,reinterpret_cast<const char*>(&flag_value),sizeof(int)) == SOCKET_ERROR )
        {
            closesocket(sock);
            return OTHER_ERROR;
        }

        // initialize a connection object on the heap with the new socket
        try
        {
            new_connection = new connection (
                                    sock,
                                    foreign_port,
                                    foreign_ip,
                                    used_local_port,
                                    used_local_ip
                                );
        }
        catch(...) {closesocket(sock);  return OTHER_ERROR; }

        return 0;
    }

// ----------------------------------------------------------------------------------------

}

#endif // WIN32

#endif // DLIB_SOCKETS_KERNEL_1_CPp_


dlib C++ Library - sockets_kernel_1.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net), Miguel Grinberg
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SOCKETS_KERNEl_1_
#define DLIB_SOCKETS_KERNEl_1_

#ifdef DLIB_ISO_CPP_ONLY
#error "DLIB_ISO_CPP_ONLY is defined so you can't use this OS dependent code.  Turn DLIB_ISO_CPP_ONLY off if you want to use it."
#endif

#include "sockets_kernel_abstract.h"

#include "../algs.h"
#include <string>
#include "../threads.h"
#include "../smart_pointers.h"
#include "../uintn.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    // forward declarations
    class socket_factory;
    class listener;
    class SOCKET_container;

// ----------------------------------------------------------------------------------------

    // lookup functions

    int
    get_local_hostname (
        std::string& hostname
    );

// -----------------

    int
    hostname_to_ip (
        const std::string& hostname,
        std::string& ip,
        int n = 0
    );

// -----------------

    int
    ip_to_hostname (
        const std::string& ip,
        std::string& hostname
    );

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // connection object
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class connection
    {
        /*!
            INITIAL_VALUE
                - sd                      == false
                - sdo                     == false
                - sdr                     == 0

            CONVENTION
                - connection_socket       == the socket handle for this connection.
                - connection_foreign_port == the port that foreign host is using for
                  this connection.
                - connection_foreign_ip   == a string containing the IP address of the
                  foreign host.
                - connection_local_port   == the port that the local host is using for
                  this connection.
                - connection_local_ip     == a string containing the IP address of the
                  local interface being used by this connection.

                - sd == if shutdown() has been called then true else false.
                - sdo == if shutdown_outgoing() has been called then true else false.
                - sdr == the return value of shutdown() if it has been called.  if it
                  hasn't been called then 0.

        !*/

        friend class listener;                // make listener a friend of connection
        // make create_connection a friend of connection
        friend int create_connection (
            connection*& new_connection,
            unsigned short foreign_port,
            const std::string& foreign_ip,
            unsigned short local_port,
            const std::string& local_ip
        );

    public:

        ~connection (
        );

        void* user_data;

        long write (
            const char* buf,
            long num
        );

        long read (
            char* buf,
            long num
        );

        long read (
            char* buf,
            long num,
            unsigned long timeout
        );

        unsigned short get_local_port (
        ) const {  return connection_local_port; }

        unsigned short get_foreign_port (
        ) const { return connection_foreign_port; }

        const std::string& get_local_ip (
        ) const { return connection_local_ip; }

        const std::string& get_foreign_ip (
        ) const { return connection_foreign_ip; }

        int shutdown_outgoing (
        );

        int shutdown (
        );

        // I would use SOCKET here but I don't want to include the windows
        // header files since they bring in a bunch of unpleasantness.  So
        // I'm doing this instead which should ultimately be the same type
        // as the SOCKET win the windows API.
        typedef unsigned_type<void*>::type socket_descriptor_type;

        int disable_nagle(
        );

        socket_descriptor_type get_socket_descriptor (
        ) const;

    private:

        bool readable (
            unsigned long timeout
        ) const;
        /*!
            requires
                - timeout < 2000000
            ensures
                - returns true if a read call on this connection will not block.
                - returns false if a read call on this connection will block or if
                  there was an error.
        !*/

        bool sd_called (
        )const
        /*!
            ensures
                - returns true if shutdown() has been called else
                  returns false
        !*/
        {
            sd_mutex.lock();
            bool temp = sd;
            sd_mutex.unlock();
            return temp;
        }

        bool sdo_called (
        )const
        /*!
            ensures
                - returns true if shutdown_outgoing() or shutdown() has been called
                  else returns false
        !*/
        {
            sd_mutex.lock();
            bool temp = false;
            if (sdo || sd)
                temp = true;
            sd_mutex.unlock();
            return temp;
        }

        // data members
        SOCKET_container& connection_socket;
        const unsigned short connection_foreign_port;
        const std::string connection_foreign_ip;
        const unsigned short connection_local_port;
        const std::string connection_local_ip;

        bool sd;  // called shutdown
        bool sdo; // called shutdown_outgoing
        int sdr; // return value for shutdown
        mutex sd_mutex; // a lock for the three above vars

        connection(
            SOCKET_container sock,
            unsigned short foreign_port,
            const std::string& foreign_ip,
            unsigned short local_port,
            const std::string& local_ip
        );
        /*!
            requires
                sock is a socket handle and
                sock is the handle for the connection between foreign_ip:foreign_port
                and local_ip:local_port
            ensures
                *this is initialized correctly with the above parameters
        !*/

        // restricted functions
        connection(connection&);        // copy constructor
        connection& operator=(connection&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // listener object
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class listener
    {
        /*!
            CONVENTION
                if (inaddr_any == false)
                {
                    listening_ip == a string containing the address the listener is
                                    listening on
                }
                else
                {
                    the listener is listening on all interfaces
                }

                listening_port == the port the listener is listening on
                listening_socket == the listening socket handle for this object
        !*/

        // make the create_listener a friend of listener
        friend int create_listener (
            listener*& new_listener,
            unsigned short port,
            const std::string& ip
        );

    public:

        ~listener (
        );

        int accept (
            connection*& new_connection,
            unsigned long timeout = 0
        );

        int accept (
            scoped_ptr<connection>& new_connection,
            unsigned long timeout = 0
        );

        unsigned short get_listening_port (
        ) { return listening_port; }

        const std::string& get_listening_ip (
        ) { return listening_ip; }

    private:

        // data members
        SOCKET_container& listening_socket;
        const unsigned short listening_port;
        const std::string listening_ip;
        const bool inaddr_any;

        listener(
            SOCKET_container sock,
            unsigned short port,
            const std::string& ip
        );
        /*!
            requires
                sock is a socket handle                                             and
                sock is listening on the port and ip(may be "") indicated in the
                above parameters
            ensures
                *this is initialized correctly with the above parameters
        !*/

        // restricted functions
        listener(listener&);        // copy constructor
        listener& operator=(listener&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------

    int create_listener (
        listener*& new_listener,
        unsigned short port,
        const std::string& ip = ""
    );

    int create_connection (
        connection*& new_connection,
        unsigned short foreign_port,
        const std::string& foreign_ip,
        unsigned short local_port = 0,
        const std::string& local_ip = ""
    );

    int create_listener (
        scoped_ptr<listener>& new_listener,
        unsigned short port,
        const std::string& ip = ""
    );

    int create_connection (
        scoped_ptr<connection>& new_connection,
        unsigned short foreign_port,
        const std::string& foreign_ip,
        unsigned short local_port = 0,
        const std::string& local_ip = ""
    );

// ----------------------------------------------------------------------------------------

}

#ifdef NO_MAKEFILE
#include "sockets_kernel_1.cpp"
#endif

#endif // DLIB_SOCKETS_KERNEl_1_


dlib C++ Library - sockets_kernel_2.cpp

// Copyright (C) 2003  Davis E. King (davis@dlib.net), Miguel Grinberg
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SOCKETS_KERNEL_2_CPp_
#define DLIB_SOCKETS_KERNEL_2_CPp_

#include "../platform.h"

#ifdef POSIX

#include "sockets_kernel_2.h"
#include <fcntl.h>
#include "../set.h"
#include <netinet/tcp.h>

namespace dlib
{
// ----------------------------------------------------------------------------------------

#ifdef HPUX
    typedef int dsocklen_t;
#else
    typedef socklen_t dsocklen_t;
#endif

// ----------------------------------------------------------------------------------------
// stuff to ensure that the signal SIGPIPE is ignored before any connections are made
// so that when a connection object is shutdown the program won't end on a broken pipe

    namespace sockets_kernel_2_mutex
    {
        mutex startup_lock;
    }

    void sockets_startup()
    {
        // mutex crap to make this function thread safe
        sockets_kernel_2_mutex::startup_lock.lock();
        static bool init = false;
        if (init == false)
        {
            init = true;
            signal( SIGPIPE, SIG_IGN);
        }
        sockets_kernel_2_mutex::startup_lock.unlock();
    }

// ----------------------------------------------------------------------------------------

    // lookup functions

    int
    get_local_hostname (
        std::string& hostname
    )
    {
        try
        {
            char temp[MAXHOSTNAMELEN];

            if (gethostname(temp,MAXHOSTNAMELEN) == -1)
            {
                return OTHER_ERROR;
            }
            // ensure that NUL is at the end of the string
            temp[MAXHOSTNAMELEN-1] = '\0';

            hostname = temp;
        }
        catch (...)
        {
            return OTHER_ERROR;
        }

        return 0;
    }

// -----------------

// cygwin currently doesn't support the getaddrinfo stuff
#ifndef __CYGWIN__

    int
    hostname_to_ip (
        const std::string& hostname,
        std::string& ip,
        int n
    )
    {
        try
        {
            set<std::string>::kernel_1a sos;

            if (hostname.empty())
                return OTHER_ERROR;

            addrinfo* result = 0;
            if (getaddrinfo(hostname.c_str(),0,0,&result))
            {
                return OTHER_ERROR;
            }
            addrinfo* result_orig = result;

            // loop over all the addrinfo structures and add them to the set.  the reason for doing
            // this dumb crap is because different platforms return all kinds of weird garbage.  many
            // return the same ip multiple times, etc.
            while (result != 0)
            {
                char temp[16];
                inet_ntop (
                    AF_INET,
                    &((reinterpret_cast<sockaddr_in*>(result->ai_addr))->sin_addr),
                    temp,16
                    );

                result = result->ai_next;

                ip.assign(temp);
                if (sos.is_member(ip) == false && ip != "0.0.0.0")
                    sos.add(ip);
            }

            freeaddrinfo(result_orig);

            // now return the nth unique ip address
            int i = 0;
            while (sos.move_next())
            {
                if (i == n)
                {
                    ip = sos.element();
                    return 0;
                }
                ++i;
            }

            return OTHER_ERROR;
        }
        catch (...)
        {
            return OTHER_ERROR;
        }
        return 0;
    }

// -----------------

    int
    ip_to_hostname (
        const std::string& ip,
        std::string& hostname
    )
    {

        try
        {

            if (ip.empty())
                return OTHER_ERROR;

            sockaddr_in sa;
            sa.sin_family = AF_INET;
            inet_pton(AF_INET,ip.c_str(),&sa.sin_addr);

            char temp[NI_MAXHOST];
            if ( getnameinfo (
                    reinterpret_cast<sockaddr*>(&sa),sizeof(sockaddr_in),
                    temp,
                    NI_MAXHOST,
                    0,
                    0,
                    NI_NAMEREQD
                )
            )
            {
                return OTHER_ERROR;
            }

            hostname.assign(temp);

        }
        catch (...)
        {
            return OTHER_ERROR;
        }
        return 0;
    }
#else
    int
    hostname_to_ip (
        const std::string& hostname,
        std::string& ip,
        int n
    )
    {
        try
        {
            // lock this mutex since gethostbyname isn't really thread safe
            auto_mutex M(sockets_kernel_2_mutex::startup_lock);

            // if no hostname was given then return error
            if ( hostname.empty())
                return OTHER_ERROR;

            hostent* address;
            address = gethostbyname(hostname.c_str());

            if (address == 0)
            {
                return OTHER_ERROR;
            }

            // find the nth address
            in_addr* addr = reinterpret_cast<in_addr*>(address->h_addr_list[0]);
            for (int i = 1; i <= n; ++i)
            {
                addr = reinterpret_cast<in_addr*>(address->h_addr_list[i]);

                // if there is no nth address then return error
                if (addr == 0)
                    return OTHER_ERROR;
            }

            char* resolved_ip = inet_ntoa(*addr);

            // check if inet_ntoa returned an error
            if (resolved_ip == NULL)
            {
                return OTHER_ERROR;
            }

            ip.assign(resolved_ip);

        }
        catch(...)
        {
            return OTHER_ERROR;
        }

        return 0;
    }

// -----------------

    int
    ip_to_hostname (
        const std::string& ip,
        std::string& hostname
    )
    {
        try
        {
            // lock this mutex since gethostbyaddr isn't really thread safe
            auto_mutex M(sockets_kernel_2_mutex::startup_lock);

            // if no ip was given then return error
            if (ip.empty())
                return OTHER_ERROR;

            hostent* address;
            unsigned long ipnum = inet_addr(ip.c_str());

            // if inet_addr couldn't convert ip then return an error
            if (ipnum == INADDR_NONE)
            {
                return OTHER_ERROR;
            }
            address = gethostbyaddr(reinterpret_cast<char*>(&ipnum),4,AF_INET);

            // check if gethostbyaddr returned an error
            if (address == 0)
            {
                return OTHER_ERROR;
            }
            hostname.assign(address->h_name);

        }
        catch (...)
        {
            return OTHER_ERROR;
        }
        return 0;

    }

#endif // __CYGWIN__

// ----------------------------------------------------------------------------------------

    connection::
    connection(
        int sock,
        int foreign_port,
        const std::string& foreign_ip,
        int local_port,
        const std::string& local_ip
    ) :
        connection_socket(sock),
        connection_foreign_port(foreign_port),
        connection_foreign_ip(foreign_ip),
        connection_local_port(local_port),
        connection_local_ip(local_ip),
        sd(false),
        sdo(false),
        sdr(0)
    {}

// ----------------------------------------------------------------------------------------

    int connection::
    disable_nagle()
    {
        int flag = 1;
        if(setsockopt( connection_socket, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag) ))
        {
            return OTHER_ERROR;
        }

        return 0;
    }

// ----------------------------------------------------------------------------------------

    long connection::
    write (
        const char* buf,
        long num
    )
    {
        const long old_num = num;
        long status;
        const long max_send_length = 1024*1024*100;
        while (num > 0)
        {
            // Make sure to cap the max value num can take on so that if it is
            // really large (it might be big on 64bit platforms) so that the OS
            // can't possibly get upset about it being large.
            const long length = std::min(max_send_length, num);
            if ( (status = ::send(connection_socket,buf,length,0)) <=0)
            {
                // if send was interupted by a signal then restart it
                if (errno == EINTR)
                {
                    continue;
                }
                else
                {
                    // check if shutdown or shutdown_outgoing have been called
                    if (sdo_called())
                        return SHUTDOWN;
                    else
                        return OTHER_ERROR;
                }
            }
            num -= status;
            buf += status;
        }
        return old_num;
    }

// ----------------------------------------------------------------------------------------

    long connection::
    read (
        char* buf,
        long num
    )
    {
        long status;
        const long max_recv_length = 1024*1024*100;
        while (true)
        {
            // Make sure to cap the max value num can take on so that if it is
            // really large (it might be big on 64bit platforms) so that the OS
            // can't possibly get upset about it being large.
            const long length = std::min(max_recv_length, num);
            status = recv(connection_socket,buf,length,0);
            if (status == -1)
            {
                // if recv was interupted then try again
                if (errno == EINTR)
                    continue;
                else
                {
                    if (sd_called())
                        return SHUTDOWN;
                    else
                        return OTHER_ERROR;
                }
            }
            else if (status == 0 && sd_called())
            {
                return SHUTDOWN;
            }

            return status;
        } // while (true)
    }
// ----------------------------------------------------------------------------------------

    long connection::
    read (
        char* buf,
        long num,
        unsigned long timeout
    )
    {
        long status;
        const long max_recv_length = 1024*1024*100;

        if (readable(timeout) == false)
            return TIMEOUT;

        // Make sure to cap the max value num can take on so that if it is
        // really large (it might be big on 64bit platforms) so that the OS
        // can't possibly get upset about it being large.
        const long length = std::min(max_recv_length, num);
        status = recv(connection_socket,buf,length,0);
        if (status == -1)
        {
            // if recv was interupted then call this a timeout
            if (errno == EINTR)
            {
                return TIMEOUT;
            }
            else
            {
                if (sd_called())
                    return SHUTDOWN;
                else
                    return OTHER_ERROR;
            }
        }
        else if (status == 0 && sd_called())
        {
            return SHUTDOWN;
        }

        return status;
    }

// ----------------------------------------------------------------------------------------

    bool connection::
    readable (
        unsigned long timeout
    ) const
    {
        fd_set read_set;
        // initialize read_set
        FD_ZERO(&read_set);

        // add the listening socket to read_set
        FD_SET(connection_socket, &read_set);

        // setup a timeval structure
        timeval time_to_wait;
        time_to_wait.tv_sec = static_cast<long>(timeout/1000);
        time_to_wait.tv_usec = static_cast<long>((timeout%1000)*1000);

        // wait on select
        int status = select(connection_socket+1,&read_set,0,0,&time_to_wait);

        // if select timed out or there was an error
        if (status <= 0)
            return false;

        // socket is ready to be read
        return true;
    }

// ----------------------------------------------------------------------------------------

    connection::
    ~connection (
    )
    {
        while (true)
        {
            int status = ::close(connection_socket);
            if (status == -1 && errno == EINTR)
                continue;
            break;
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // listener object
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    listener::
    listener(
        int sock,
        int port,
        const std::string& ip
    ) :
        listening_socket(sock),
        listening_port(port),
        listening_ip(ip),
        inaddr_any(listening_ip.empty())
    {}

// ----------------------------------------------------------------------------------------

    listener::
    ~listener (
    )
    {
        while (true)
        {
            int status = ::close(listening_socket);
            if (status == -1 && errno == EINTR)
                continue;
            break;
        }
    }

// ----------------------------------------------------------------------------------------

    int listener::
    accept (
        scoped_ptr<connection>& new_connection,
        unsigned long timeout
    )
    {
        new_connection.reset(0);
        connection* con;
        int status = this->accept(con, timeout);

        if (status == 0)
            new_connection.reset(con);

        return status;
    }

// ----------------------------------------------------------------------------------------

    int listener::
    accept (
        connection*& new_connection,
        unsigned long timeout
    )
    {
        int incoming;
        sockaddr_in incomingAddr;
        dsocklen_t length = sizeof(sockaddr_in);

        // implement timeout with select if timeout is > 0
        if (timeout > 0)
        {

            fd_set read_set;
            // initialize read_set
            FD_ZERO(&read_set);

            // add the listening socket to read_set
            FD_SET(listening_socket, &read_set);

            timeval time_to_wait;

            // loop on select so if its interupted then we can start it again
            while (true)
            {

                // setup a timeval structure
                time_to_wait.tv_sec = static_cast<long>(timeout/1000);
                time_to_wait.tv_usec = static_cast<long>((timeout%1000)*1000);

                // wait on select
                int status = select(listening_socket+1,&read_set,0,0,&time_to_wait);

                // if select timed out
                if (status == 0)
                    return TIMEOUT;

                // if select returned an error
                if (status == -1)
                {
                    // if select was interupted or the connection was aborted
                    // then go back to select
                    if (errno == EINTR ||
                        errno == ECONNABORTED ||
#ifdef EPROTO
                        errno == EPROTO ||
#endif
                        errno == ECONNRESET
                        )
                    {
                        continue;
                    }
                    else
                    {
                        return OTHER_ERROR;
                    }
                }

                // accept the new connection
                incoming=::accept (
                    listening_socket,
                    reinterpret_cast<sockaddr*>(&incomingAddr),
                    &length
                    );

                // if there was an error return OTHER_ERROR
                if ( incoming == -1 )
                {
                    // if accept was interupted then go back to accept
                    if (errno == EINTR ||
                        errno == ECONNABORTED ||
#ifdef EPROTO
                        errno == EPROTO ||
#endif
                        errno == ECONNRESET
                        )
                    {
                        continue;
                    }
                    else
                    {
                        return OTHER_ERROR;
                    }
                }

                // if there were no errors then quit loop
                break;

            }

        }
        // else if there is no time out then just go into accept
        else
        {
            while (true)
            {
                // call accept to get a new connection
                incoming=::accept (
                    listening_socket,
                    reinterpret_cast<sockaddr*>(&incomingAddr),
                    &length
                    );

                // if there was an error return OTHER_ERROR
                if ( incoming == -1 )
                {
                    // if accept was interupted then go back to accept
                    if (errno == EINTR ||
                        errno == ECONNABORTED ||
#ifdef EPROTO
                        errno == EPROTO ||
#endif
                        errno == ECONNRESET
                        )
                    {
                        continue;
                    }
                    else
                    {
                        return OTHER_ERROR;
                    }
                }
                break;
            }

        }

        // get the port of the foreign host into foreign_port
        int foreign_port = ntohs(incomingAddr.sin_port);

        // get the IP of the foreign host into foreign_ip
        char foreign_ip[16];
        inet_ntop(AF_INET,&incomingAddr.sin_addr,foreign_ip,16);

        // get the local ip for this connection into local_ip
        char temp_local_ip[16];
        std::string local_ip;
        if (inaddr_any == true)
        {
            sockaddr_in local_info;
            length = sizeof(sockaddr_in);
            // get the local sockaddr_in structure associated with this new connection
            if ( getsockname (
                    incoming,
                    reinterpret_cast<sockaddr*>(&local_info),
                    &length
                ) == -1
            )
            {   // an error occurred
                while (true)
                {
                    int status = ::close(incoming);
                    if (status == -1 && errno == EINTR)
                        continue;
                    break;
                }
                return OTHER_ERROR;
            }
            local_ip = const_cast<char*> (
                inet_ntop(AF_INET,&local_info.sin_addr,temp_local_ip,16)
                );
        }
        else
        {
            local_ip = listening_ip;
        }

        // set the SO_OOBINLINE option
        int flag_value = 1;
        if (setsockopt(incoming,SOL_SOCKET,SO_OOBINLINE,reinterpret_cast<const void*>(&flag_value),sizeof(int)))
        {
            while (true)
            {
                int status = ::close(incoming);
                if (status == -1 && errno == EINTR)
                    continue;
                break;
            }
            return OTHER_ERROR;
        }

        // make a new connection object for this new connection
        try
        {
            new_connection = new connection (
                                    incoming,
                                    foreign_port,
                                    foreign_ip,
                                    listening_port,
                                    local_ip
                                );
        }
        catch (...)
        {
            while (true)
            {
                int status = ::close(incoming);
                if (status == -1 && errno == EINTR)
                    continue;
                break;
            }
            return OTHER_ERROR;
        }

        return 0;
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // socket creation functions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    static void
    close_socket (
        int sock
    )
    /*!
        requires
            - sock == a socket
        ensures
            - sock has been closed
    !*/
    {
        while (true)
        {
            int status = ::close(sock);
            if (status == -1 && errno == EINTR)
                continue;
            break;
        }
    }

// ----------------------------------------------------------------------------------------

    int create_listener (
        scoped_ptr<listener>& new_listener,
        unsigned short port,
        const std::string& ip
    )
    {
        new_listener.reset();
        listener* temp;
        int status = create_listener(temp,port,ip);

        if (status == 0)
            new_listener.reset(temp);

        return status;
    }

    int create_listener (
        listener*& new_listener,
        unsigned short port,
        const std::string& ip
    )
    {
        sockets_startup();

        sockaddr_in sa;  // local socket structure
        memset(&sa,'\0',sizeof(sockaddr_in)); // initialize sa

        int sock = socket (AF_INET, SOCK_STREAM, 0);  // get a new socket

        // if socket() returned an error then return OTHER_ERROR
        if (sock == -1)
        {
            return OTHER_ERROR;
        }

        // set the local socket structure
        sa.sin_family = AF_INET;
        sa.sin_port = htons(port);
        if (ip.empty())
        {
            // if the listener should listen on any IP
            sa.sin_addr.s_addr = htons(INADDR_ANY);
        }
        else
        {
            // if there is a specific ip to listen on
            sa.sin_addr.s_addr = inet_addr(ip.c_str());

            // if inet_addr couldn't convert the ip then return an error
            if ( sa.sin_addr.s_addr == ( in_addr_t)(-1))
            {
                close_socket(sock);
                return OTHER_ERROR;
            }
        }

        // set the SO_REUSEADDR option
        int flag_value = 1;
        if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,reinterpret_cast<const void*>(&flag_value),sizeof(int)))
        {
            close_socket(sock);
            return OTHER_ERROR;
        }

        // bind the new socket to the requested port and ip
        if (bind(sock,reinterpret_cast<sockaddr*>(&sa),sizeof(sockaddr_in)) == -1)
        {   // if there was an error
            close_socket(sock);

            // if the port is already bound then return PORTINUSE
            if (errno == EADDRINUSE)
                return PORTINUSE;
            else
                return OTHER_ERROR;
        }

        // tell the new socket to listen
        if ( listen(sock,SOMAXCONN) == -1)
        {
            // if there was an error return OTHER_ERROR
            close_socket(sock);

            // if the port is already bound then return PORTINUSE
            if (errno == EADDRINUSE)
                return PORTINUSE;
            else
                return OTHER_ERROR;
        }

        // determine the used local port if necessary
        if (port == 0)
        {
            sockaddr_in local_info;
            dsocklen_t length = sizeof(sockaddr_in);
            if ( getsockname(
                sock,
                reinterpret_cast<sockaddr*>(&local_info),
                &length
                ) == -1)
            {
                close_socket(sock);
                return OTHER_ERROR;
            }
            port = ntohs(local_info.sin_port);
        }

        // initialize a listener object on the heap with the new socket
        try { new_listener = new listener(sock,port,ip); }
        catch(...) { close_socket(sock); return OTHER_ERROR; }

        return 0;
    }

// ----------------------------------------------------------------------------------------

    int create_connection (
        scoped_ptr<connection>& new_connection,
        unsigned short foreign_port,
        const std::string& foreign_ip,
        unsigned short local_port,
        const std::string& local_ip
    )
    {
        new_connection.reset();
        connection* temp;
        int status = create_connection(temp,foreign_port, foreign_ip, local_port, local_ip);

        if (status == 0)
            new_connection.reset(temp);

        return status;
    }

    int
    create_connection (
        connection*& new_connection,
        unsigned short foreign_port,
        const std::string& foreign_ip,
        unsigned short local_port,
        const std::string& local_ip
    )
    {
        sockets_startup();

        sockaddr_in local_sa;  // local socket structure
        sockaddr_in foreign_sa;  // foreign socket structure
        memset(&local_sa,'\0',sizeof(sockaddr_in)); // initialize local_sa
        memset(&foreign_sa,'\0',sizeof(sockaddr_in)); // initialize foreign_sa

        dsocklen_t length;

        int sock = socket (AF_INET, SOCK_STREAM, 0);  // get a new socket

        // if socket() returned an error then return OTHER_ERROR
        if (sock == -1 )
        {
            return OTHER_ERROR;
        }

        // set the foreign socket structure
        foreign_sa.sin_family = AF_INET;
        foreign_sa.sin_port = htons(foreign_port);
        foreign_sa.sin_addr.s_addr = inet_addr(foreign_ip.c_str());

        // if inet_addr couldn't convert the ip then return an error
        if ( foreign_sa.sin_addr.s_addr == ( in_addr_t)(-1))
        {
            close_socket(sock);
            return OTHER_ERROR;
        }

        // set up the local socket structure
        local_sa.sin_family = AF_INET;

        // set the local port
        local_sa.sin_port = htons(local_port);

        // set the local ip
        if (local_ip.empty())
        {
            // if the listener should listen on any IP
            local_sa.sin_addr.s_addr = htons(INADDR_ANY);
        }
        else
        {
            // if there is a specific ip to listen on
            local_sa.sin_addr.s_addr = inet_addr(local_ip.c_str());

            // if inet_addr couldn't convert the ip then return an error
            if ( local_sa.sin_addr.s_addr == ( in_addr_t)(-1))
            {
                close_socket(sock);
                return OTHER_ERROR;
            }
        }

        // bind the new socket to the requested local port and local ip
        if ( bind(sock,reinterpret_cast<sockaddr*>(&local_sa),sizeof(sockaddr_in)) == -1)
        {   // if there was an error
            close_socket(sock);

            // if the port is already bound then return PORTINUSE
            if (errno == EADDRINUSE)
                return PORTINUSE;
            else
                return OTHER_ERROR;
        }

        // connect the socket
        if ( connect (
                sock,
                reinterpret_cast<sockaddr*>(&foreign_sa),
                sizeof(sockaddr_in)
            ) == -1
        )
        {
            close_socket(sock);
            // if the port is already bound then return PORTINUSE
            if (errno == EADDRINUSE)
                return PORTINUSE;
            else
                return OTHER_ERROR;
        }

        // determine the local port and IP and store them in used_local_ip
        // and used_local_port
        int used_local_port;
        char temp_used_local_ip[16];
        std::string used_local_ip;
        sockaddr_in local_info;

        // determine the port
        if (local_port == 0)
        {
            length = sizeof(sockaddr_in);
            if ( getsockname(
                    sock,
                    reinterpret_cast<sockaddr*>(&local_info),
                    &length
                ) == -1)
            {
                close_socket(sock);
                return OTHER_ERROR;
            }
            used_local_port = ntohs(local_info.sin_port);
        }
        else
        {
            used_local_port = local_port;
        }

        // determine the ip
        if (local_ip.empty())
        {
            // if local_port is not 0 then we must fill the local_info structure
            if (local_port != 0)
            {
                length = sizeof(sockaddr_in);
                if ( getsockname (
                        sock,
                        reinterpret_cast<sockaddr*>(&local_info),
                        &length
                    ) == -1
                )
                {
                    close_socket(sock);
                    return OTHER_ERROR;
                }
            }
            used_local_ip = inet_ntop(AF_INET,&local_info.sin_addr,temp_used_local_ip,16);
        }
        else
        {
            used_local_ip = local_ip;
        }

        // set the SO_OOBINLINE option
        int flag_value = 1;
        if (setsockopt(sock,SOL_SOCKET,SO_OOBINLINE,reinterpret_cast<const void*>(&flag_value),sizeof(int)))
        {
            close_socket(sock);
            return OTHER_ERROR;
        }

        // initialize a connection object on the heap with the new socket
        try
        {
            new_connection = new connection (
                                    sock,
                                    foreign_port,
                                    foreign_ip,
                                    used_local_port,
                                    used_local_ip
                                );
        }
        catch(...) {close_socket(sock);  return OTHER_ERROR; }

        return 0;
    }

// ----------------------------------------------------------------------------------------

}

#endif // POSIX

#endif // DLIB_SOCKETS_KERNEL_2_CPp_


dlib C++ Library - sockets_kernel_2.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net), Miguel Grinberg
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SOCKETS_KERNEl_2_
#define DLIB_SOCKETS_KERNEl_2_

#ifdef DLIB_ISO_CPP_ONLY
#error "DLIB_ISO_CPP_ONLY is defined so you can't use this OS dependent code.  Turn DLIB_ISO_CPP_ONLY off if you want to use it."
#endif

#include "../platform.h"

#include "sockets_kernel_abstract.h"

#define _BSD_SOCKLEN_T_

#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <ctime>
#ifndef HPUX
#include <sys/select.h>
#endif
#include <arpa/inet.h>
#include <signal.h>
#include <inttypes.h>
#include <netdb.h>
#include <unistd.h>
#include <sys/param.h>
#include <string>

#include <netinet/in.h>

#include "../threads.h"
#include "../algs.h"
#include "../smart_pointers.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    // forward declarations
    class socket_factory;
    class listener;

// ----------------------------------------------------------------------------------------

    // lookup functions

    int
    get_local_hostname (
        std::string& hostname
    );

// -----------------

    int
    hostname_to_ip (
        const std::string& hostname,
        std::string& ip,
        int n = 0
    );

// -----------------

    int
    ip_to_hostname (
        const std::string& ip,
        std::string& hostname
    );

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // connection object
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class connection
    {
        /*!
            INITIAL_VALUE
                sd                      == false
                sdo                     == false
                sdr                     == 0

            CONVENTION
                connection_socket       == the socket handle for this connection.
                connection_foreign_port == the port that foreign host is using for
                                           this connection
                connection_foreign_ip   == a string containing the IP address of the
                                           foreign host
                connection_local_port   == the port that the local host is using for
                                           this connection
                connection_local_ip     == a string containing the IP address of the
                                           local interface being used by this connection

                sd                      == if shutdown() has been called then true
                                           else false
                sdo                     == if shutdown_outgoing() has been called then true
                                           else false
                sdr                     == the return value of shutdown() if it has been
                                           called.  if it hasn't been called then 0

        !*/

        friend class listener;                // make listener a friend of connection
        // make create_connection a friend of connection
        friend int create_connection (
            connection*& new_connection,
            unsigned short foreign_port,
            const std::string& foreign_ip,
            unsigned short local_port,
            const std::string& local_ip
        );

    public:

        ~connection();

        void* user_data;

        long write (
            const char* buf,
            long num
        );

        long read (
            char* buf,
            long num
        );

        long read (
            char* buf,
            long num,
            unsigned long timeout
        );

        int get_local_port (
        ) const { return connection_local_port; }

        int get_foreign_port (
        ) const { return connection_foreign_port; }

        const std::string& get_local_ip (
        ) const { return connection_local_ip; }

        const std::string& get_foreign_ip (
        ) const { return connection_foreign_ip; }

        int shutdown_outgoing (
        )
        {
            sd_mutex.lock();
            if (sdo || sd)
            {
                sd_mutex.unlock();
                return sdr;
            }
            sdo = true;
            sdr = ::shutdown(connection_socket,SHUT_WR);
            int temp = sdr;
            sd_mutex.unlock();
            return temp;
        }

        int shutdown (
        )
        {
            sd_mutex.lock();
            if (sd)
            {
                sd_mutex.unlock();
                return sdr;
            }
            sd = true;
            sdr = ::shutdown(connection_socket,SHUT_RDWR);
            int temp = sdr;
            sd_mutex.unlock();
            return temp;
        }

        int disable_nagle(
        );

        typedef int socket_descriptor_type;

        socket_descriptor_type get_socket_descriptor (
        ) const { return connection_socket; }

    private:

        bool readable (
            unsigned long timeout
        ) const;
        /*!
            requires
                - timeout < 2000000
            ensures
                - returns true if a read call on this connection will not block.
                - returns false if a read call on this connection will block or if
                  there was an error.
        !*/

        bool sd_called (
        )const
        /*!
            ensures
                - returns true if shutdown() has been called else
                - returns false
        !*/
        {
            sd_mutex.lock();
            bool temp = sd;
            sd_mutex.unlock();
            return temp;
        }

        bool sdo_called (
        )const
        /*!
            ensures
                - returns true if shutdown_outgoing() or shutdown() has been called
                  else returns false
        !*/
        {
            sd_mutex.lock();
            bool temp = false;
            if (sdo || sd)
                temp = true;
            sd_mutex.unlock();
            return temp;
        }

        // data members
        int connection_socket;
        const int connection_foreign_port;
        const std::string connection_foreign_ip;
        const int connection_local_port;
        const std::string connection_local_ip;

        bool sd;  // called shutdown
        bool sdo; // called shutdown_outgoing
        int sdr; // return value for shutdown
        mutex sd_mutex; // a lock for the three above vars

        connection(
            int sock,
            int foreign_port,
            const std::string& foreign_ip,
            int local_port,
            const std::string& local_ip
        );
        /*!
            requires
                - sock is a socket handle
                - sock is the handle for the connection between foreign_ip:foreign_port
                  and local_ip:local_port
            ensures
                - *this is initialized correctly with the above parameters
        !*/

        // restricted functions
        connection();
        connection(connection&);        // copy constructor
        connection& operator=(connection&);    // assignement opertor
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // listener object
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class listener
    {
        /*!
            CONVENTION
                if (inaddr_any == false)
                {
                    listening_ip == a string containing the address the listener is
                                    listening on
                }
                else
                {
                    the listener is listening on all interfaces
                }

                listening_port == the port the listener is listening on
                listening_socket == the listening socket handle for this object
        !*/

        // make the create_listener a friend of listener
        friend int create_listener (
            listener*& new_listener,
            unsigned short port,
            const std::string& ip
        );

    public:

        ~listener();

        int accept (
            connection*& new_connection,
            unsigned long timeout = 0
        );

        int accept (
            scoped_ptr<connection>& new_connection,
            unsigned long timeout = 0
        );

        int get_listening_port (
        ) const { return listening_port; }

        const std::string& get_listening_ip (
        ) const { return listening_ip; }

    private:

        // data members
        int listening_socket;
        const int listening_port;
        const std::string listening_ip;
        const bool inaddr_any;

        listener(
            int sock,
            int port,
            const std::string& ip
        );
        /*!
            requires
                - sock is a socket handle
                - sock is listening on the port and ip(may be "") indicated in the above
                  parameters
            ensures
                - *this is initialized correctly with the above parameters
        !*/

        // restricted functions
        listener();
        listener(listener&);        // copy constructor
        listener& operator=(listener&);    // assignement opertor
    };

// ----------------------------------------------------------------------------------------

    int create_listener (
        listener*& new_listener,
        unsigned short port,
        const std::string& ip = ""
    );

    int create_connection (
        connection*& new_connection,
        unsigned short foreign_port,
        const std::string& foreign_ip,
        unsigned short local_port = 0,
        const std::string& local_ip = ""
    );

    int create_listener (
        scoped_ptr<listener>& new_listener,
        unsigned short port,
        const std::string& ip = ""
    );

    int create_connection (
        scoped_ptr<connection>& new_connection,
        unsigned short foreign_port,
        const std::string& foreign_ip,
        unsigned short local_port = 0,
        const std::string& local_ip = ""
    );

// ----------------------------------------------------------------------------------------

}

#ifdef NO_MAKEFILE
#include "sockets_kernel_2.cpp"
#endif

#endif // DLIB_SOCKETS_KERNEl_2_


dlib C++ Library - windows.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SOCKETS_KERNEl_2_
#include "sockets_kernel_1.h"
#endif


dlib C++ Library - sockstreambuf.cpp

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SOCKStREAMBUF_CPp_
#define DLIB_SOCKStREAMBUF_CPp_

#include "sockstreambuf.h"
#include "../assert.h"

#include <cstring>

namespace dlib
{

// ----------------------------------------------------------------------------------------
    // output functions
// ----------------------------------------------------------------------------------------

    sockstreambuf::int_type sockstreambuf::
    overflow (
        int_type c
    )
    {
        if (c != EOF)
        {
            *pptr() = c;
            pbump(1);
        }
        if (flush_out_buffer() == EOF)
        {
            // an error occurred
            return EOF;
        }
        return c;
    }

// ----------------------------------------------------------------------------------------

    std::streamsize sockstreambuf::
    xsputn (
        const char* s,
        std::streamsize num
    )
    {
        // Add a sanity check here
        DLIB_ASSERT(num >= 0,
            "\tstd::streamsize sockstreambuf::xsputn"
            << "\n\tThe number of bytes to write can't be negative"
            << "\n\tnum:  " << num
            << "\n\tthis: " << this
            );

        std::streamsize space_left = static_cast<std::streamsize>(epptr()-pptr());
        if (num <= space_left)
        {
            std::memcpy(pptr(),s,static_cast<size_t>(num));
            pbump(static_cast<int>(num));
            return num;
        }
        else
        {
            std::memcpy(pptr(),s,static_cast<size_t>(space_left));
            s += space_left;
            pbump(space_left);
            std::streamsize num_left = num - space_left;

            if (flush_out_buffer() == EOF)
            {
                // the write was not successful so return that 0 bytes were written
                return 0;
            }

            if (num_left < out_buffer_size)
            {
                std::memcpy(pptr(),s,static_cast<size_t>(num_left));
                pbump(num_left);
                return num;
            }
            else
            {
                if (con.write(s,num_left) != num_left)
                {
                    // the write was not successful so return that 0 bytes were written
                    return 0;
                }
                return num;
            }
        }
    }

// ----------------------------------------------------------------------------------------
    // input functions
// ----------------------------------------------------------------------------------------

    sockstreambuf::int_type sockstreambuf::
    underflow(
    )
    {
        if (gptr() < egptr())
        {
            return static_cast<unsigned char>(*gptr());
        }

        int num_put_back = static_cast<int>(gptr() - eback());
        if (num_put_back > max_putback)
        {
            num_put_back = max_putback;
        }

        // copy the putback characters into the putback end of the in_buffer
        std::memmove(in_buffer+(max_putback-num_put_back), gptr()-num_put_back, num_put_back);

        if (flushes_output_on_read())
        {
            if (flush_out_buffer() == EOF)
            {
                // an error occurred
                return EOF;
            }
        }

        int num = con.read(in_buffer+max_putback, in_buffer_size-max_putback);
        if (num <= 0)
        {
            // an error occurred or the connection is over which is EOF
            return EOF;
        }

        // reset in_buffer pointers
        setg (in_buffer+(max_putback-num_put_back),
              in_buffer+max_putback,
              in_buffer+max_putback+num);

        return static_cast<unsigned char>(*gptr());
    }

// ----------------------------------------------------------------------------------------

    std::streamsize sockstreambuf::
    xsgetn (
        char_type* s,
        std::streamsize n
    )
    {
        std::streamsize temp = n;
        while (n > 0)
        {
            int num = static_cast<int>(egptr() - gptr());
            if (num >= n)
            {
                // copy data from our buffer
                std::memcpy(s, gptr(), static_cast<size_t>(n));
                gbump(static_cast<int>(n));
                return temp;
            }

            // read more data into our buffer
            if (num == 0)
            {
                if (underflow() == EOF)
                    break;
                continue;
            }

            // copy all the data from our buffer
            std::memcpy(s, gptr(), num);
            n -= num;
            gbump(num);
            s += num;
        }
        return temp-n;
    }

// ----------------------------------------------------------------------------------------

}
#endif // DLIB_SOCKStREAMBUF_CPp_


dlib C++ Library - sockstreambuf.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SOCKStREAMBUF_Hh_
#define DLIB_SOCKStREAMBUF_Hh_

#include <iosfwd>
#include <streambuf>
#include "../sockets.h"
#include "sockstreambuf_abstract.h"
#include "sockstreambuf_unbuffered.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class sockstreambuf : public std::streambuf
    {
        /*!
            INITIAL VALUE
                - con == a connection
                - in_buffer == an array of in_buffer_size bytes
                - out_buffer == an array of out_buffer_size bytes

            CONVENTION
                - in_buffer == the input buffer used by this streambuf
                - out_buffer == the output buffer used by this streambuf
                - max_putback == the maximum number of chars to have in the put back buffer.
        !*/

    public:

        // These typedefs are here for backwards compatibility with previous versions of
        // dlib.
        typedef sockstreambuf_unbuffered kernel_1a;
        typedef sockstreambuf kernel_2a;

        sockstreambuf (
            connection* con_
        ) :
            con(*con_),
            out_buffer(0),
            in_buffer(0),
            autoflush(false)
        {
            init();
        }

        sockstreambuf (
            const scoped_ptr<connection>& con_
        ) :
            con(*con_),
            out_buffer(0),
            in_buffer(0),
            autoflush(false)
        {
            init();
        }

        virtual ~sockstreambuf (
        )
        {
            sync();
            delete [] out_buffer;
            delete [] in_buffer;
        }

        connection* get_connection (
        ) { return &con; }

        void flush_output_on_read()
        {
            autoflush = true;
        }

        bool flushes_output_on_read() const
        {
            return autoflush;
        }

        void do_not_flush_output_on_read()
        {
            autoflush = false;
        }

    protected:

        void init (
        )
        {
            try
            {
                out_buffer = new char[out_buffer_size];
                in_buffer = new char[in_buffer_size];
            }
            catch (...)
            {
                if (out_buffer) delete [] out_buffer;
                throw;
            }
            setp(out_buffer, out_buffer + (out_buffer_size-1));
            setg(in_buffer+max_putback,
                 in_buffer+max_putback,
                 in_buffer+max_putback);
        }

        int flush_out_buffer (
        )
        {
            int num = static_cast<int>(pptr()-pbase());
            if (con.write(out_buffer,num) != num)
            {
                // the write was not successful so return EOF
                return EOF;
            }
            pbump(-num);
            return num;
        }

        // output functions
        int_type overflow (
            int_type c
        );

        int sync (
        )
        {
            if (flush_out_buffer() == EOF)
            {
                // an error occurred
                return -1;
            }
            return 0;
        }

        std::streamsize xsputn (
            const char* s,
            std::streamsize num
        );

        // input functions
        int_type underflow(
        );

        std::streamsize xsgetn (
            char_type* s,
            std::streamsize n
        );

    private:

        // member data
        connection&  con;
        static const std::streamsize max_putback = 4;
        static const std::streamsize out_buffer_size = 10000;
        static const std::streamsize in_buffer_size = 10000;
        char* out_buffer;
        char* in_buffer;
        bool autoflush;

    };

// ----------------------------------------------------------------------------------------

}

#ifdef NO_MAKEFILE
#include "sockstreambuf.cpp"
#endif

#endif // DLIB_SOCKStREAMBUF_Hh_


dlib C++ Library - sockstreambuf_unbuffered.cpp

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SOCKSTrEAMBUF_UNBUFFERED_CPp_
#define DLIB_SOCKSTrEAMBUF_UNBUFFERED_CPp_

#include "sockstreambuf_unbuffered.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------
    // output functions
// ----------------------------------------------------------------------------------------

    sockstreambuf_unbuffered::int_type sockstreambuf_unbuffered::
    overflow (
        int_type c
    )
    {
        if (c != EOF)
        {
            char temp = static_cast<char>(c);
            if (con.write(&temp,1) != 1)
            {
                // if the write was not successful
                return EOF;
            }
        }
        return c;
    }

// ----------------------------------------------------------------------------------------

    std::streamsize sockstreambuf_unbuffered::
    xsputn (
        const char* s,
        std::streamsize num
    )
    {
        if (con.write(s,static_cast<int>(num)) != num)
        {
            // the write was not successful so return that 0 bytes were written
            return 0;
        }
        return num;
    }

// ----------------------------------------------------------------------------------------
    // input functions
// ----------------------------------------------------------------------------------------

    sockstreambuf_unbuffered::int_type sockstreambuf_unbuffered::
    underflow(
    )
    {
        if (lastread_next)
        {
            return lastread;
        }
        else if (peek != EOF)
        {
            return peek;
        }
        else
        {
            char temp;
            if (con.read(&temp,1) != 1)
            {
                // some error occurred
                return EOF;
            }
            peek = static_cast<unsigned char>(temp);
            return peek;
        }
    }

// ----------------------------------------------------------------------------------------

    sockstreambuf_unbuffered::int_type sockstreambuf_unbuffered::
    uflow(
    )
    {
        if (lastread_next)
        {
            lastread_next = false;
            return lastread;
        }
        else if (peek != EOF)
        {
            lastread = peek;
            peek = EOF;
            return lastread;
        }
        else
        {
            char temp;
            if (con.read(&temp,1) != 1)
            {
                // some error occurred
                return EOF;
            }
            lastread = static_cast<unsigned char>(temp);
            return lastread;
        }
    }

// ----------------------------------------------------------------------------------------

    sockstreambuf_unbuffered::int_type sockstreambuf_unbuffered::
    pbackfail(
        int_type c
    )
    {
        // if they are trying to push back a character that they didn't read last
        // that is an error
        if (c != EOF && c != lastread)
            return EOF;

        // if they are trying to push back a second character then thats an error
        if (lastread_next)
            return EOF;

        lastread_next = true;
        return 1;
    }

// ----------------------------------------------------------------------------------------

    std::streamsize sockstreambuf_unbuffered::
    xsgetn (
        char_type* s,
        std::streamsize n
    )
    {
        std::streamsize temp = n;
        if (lastread_next && n > 0)
        {
            *s = lastread;
            lastread_next = false;
            ++s;
            --n;
        }
        if (peek != EOF && n > 0)
        {
            *s = peek;
            peek = EOF;
            ++s;
            --n;
        }

        while (n>0)
        {
            int status = con.read(s,static_cast<int>(n));
            if (status < 1)
                break;
            n -= status;
            s += status;
        }

        return temp-n;
    }

// ----------------------------------------------------------------------------------------

}
#endif // DLIB_SOCKSTrEAMBUF_UNBUFFERED_CPp_


dlib C++ Library - sockstreambuf_unbuffered.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SOCKSTrEAMBUF_UNBUFFERED_Hh_
#define DLIB_SOCKSTrEAMBUF_UNBUFFERED_Hh_

#include <iosfwd>
#include <streambuf>
#include "../sockets.h"
#include "sockstreambuf_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class sockstreambuf_unbuffered : public std::streambuf
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is an implementation of the interface defined in
                sockstreambuf_abstract.h except that it doesn't do any kind of buffering at
                all.  It just writes data directly to a connection.  However, note that we
                don't implement the flushes_output_on_read() routine as this object always
                flushes immediately (since it isn't buffers.  Moreover, it should be
                pointed out that this object is deprecated and only present for backwards
                compatibility with previous versions of dlib.  So you really should use the
                sockstreambuf object instead.

            INITIAL VALUE
                con == a connection
                lastread_next == false
                peek == EOF

            CONVENTION
                if (peek != EOF) then
                    peek == the last character read from the connection object and
                            is used to store the char in the event the user peeks by
                            calling sgetc()
                if (lastread != EOF) then
                    lastread == the last character read and consumed by the user

                if (lastread_next) then
                    the next character to be returned to the user is lastread because
                    the user put it back into the buffer

        !*/

    public:

        sockstreambuf_unbuffered (
            connection* con_
        ) :
            con(*con_),
            peek(EOF),
            lastread_next(false)
        {}

        sockstreambuf_unbuffered (
            const scoped_ptr<connection>& con_
        ) :
            con(*con_),
            peek(EOF),
            lastread_next(false)
        {}

        connection* get_connection (
        ) { return &con; }

    protected:

        // output functions
        int_type overflow (
            int_type c
        );

        std::streamsize xsputn (
            const char* s,
            std::streamsize num
        );

        // input functions
        int_type underflow(
        );

        int_type uflow(
        );

        int_type pbackfail(
            int_type c
        );

        std::streamsize xsgetn (
            char_type* s,
            std::streamsize n
        );

    private:

        // member data
        connection&  con;
        int_type peek;
        int_type lastread;
        bool lastread_next;

    };

// ----------------------------------------------------------------------------------------

}

#ifdef NO_MAKEFILE
#include "sockstreambuf_unbuffered.cpp"
#endif

#endif // DLIB_SOCKSTrEAMBUF_UNBUFFERED_Hh_


dlib C++ Library - stack_kernel_1.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_STACK_KERNEl_1_
#define DLIB_STACK_KERNEl_1_

#include "stack_kernel_abstract.h"
#include "../algs.h"
#include "../interfaces/enumerable.h"
#include "../interfaces/remover.h"
#include "../serialize.h"

namespace dlib
{

    template <
        typename T,
        typename mem_manager = default_memory_manager
        >
    class stack_kernel_1 : public enumerable<T>,
                           public remover<T>
    {

        /*!
            INITIAL VALUE
                stack_size == 0
                top == 0
                current_element == 0
                _at_start == true

            CONVENTION
                at_start() == _at_start
                current_element_valid() == (current_element != 0)
                if (current_element != 0) then
                    element() == current_element->item

                stack_size == the number of elements in the stack.
                Each node points to the next node to be poped off the stack.
                The last node in the list has its next pointer is set to 0.

                if (size == 0)
                {
                    top == 0
                }
                else
                {
                    top == pointer to the last element added to the stack
                }
        !*/

        struct node
        {
            node* next;
            T item;
        };

        public:

            typedef T type;
            typedef mem_manager mem_manager_type;

            stack_kernel_1(
            ):
                top(0),
                stack_size(0),
                current_element(0),
                _at_start(true)
            {}

            virtual ~stack_kernel_1(
            );

            inline void clear(
            );

            inline void push(
                T& item
            );

            void pop(
                T& item
            );

            T& current(
            );

            const T& current(
            ) const;

            inline void swap (
                stack_kernel_1& item
            );

            // functions from the remover interface
            inline void remove_any (
                T& item
            );

            // functions from the enumerable interface
            inline unsigned long size (
            ) const;

            inline bool at_start (
            ) const;

            inline void reset (
            ) const;

            bool current_element_valid (
            ) const;

            inline const T& element (
            ) const;

            inline T& element (
            );

            bool move_next (
            ) const;

        private:

            void delete_elements_in_stack(
                node*& top
            );
            /*!
                requires
                    - top points to the top of the stack
                ensures
                    - all memory has been freed
                    - #top = 0
            !*/

            // data members
            typename mem_manager::template rebind<node>::other pool;
            node* top;
            unsigned long stack_size;
            mutable node* current_element;
            mutable bool _at_start;

            // restricted functions
            stack_kernel_1(stack_kernel_1&);        // copy constructor
            stack_kernel_1& operator=(stack_kernel_1&); // assignment operator

    };

    template <
        typename T,
        typename mem_manager
        >
    inline void swap (
        stack_kernel_1<T,mem_manager>& a,
        stack_kernel_1<T,mem_manager>& b
    ) { a.swap(b); }

    template <
        typename T,
        typename mem_manager
        >
    void deserialize (
        stack_kernel_1<T,mem_manager>& item,
        std::istream& in
    )
    {
        try
        {
            item.clear();
            unsigned long size;
            deserialize(size,in);
            T temp = T();
            stack_kernel_1<T> temp_stack;
            for (unsigned long i = 0; i < size; ++i)
            {
                deserialize(temp,in);
                temp_stack.push(temp);
            }
            while (temp_stack.size() > 0)
            {
                temp_stack.pop(temp);
                item.push(temp);
            }
        }
        catch (serialization_error e)
        {
            item.clear();
            throw serialization_error(e.info + "\n   while deserializing object of type stack_kernel_1");
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    stack_kernel_1<T,mem_manager>::
    ~stack_kernel_1(
    )
    {
        delete_elements_in_stack(top);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void stack_kernel_1<T,mem_manager>::
    clear(
    )
    {
        if (stack_size != 0)
        {
            delete_elements_in_stack(top);
            stack_size = 0;
        }
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    T& stack_kernel_1<T,mem_manager>::
    current(
    )
    {
        return top->item;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    const T& stack_kernel_1<T,mem_manager>::
    current(
    ) const
    {
        return top->item;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void stack_kernel_1<T,mem_manager>::
    swap(
        stack_kernel_1<T,mem_manager>& item
    )
    {
        pool.swap(item.pool);

        // declare temp variables
        node* top_temp;
        unsigned long stack_size_temp;

        // swap stack_size variables
        stack_size_temp = item.stack_size;
        item.stack_size = stack_size;
        stack_size = stack_size_temp;

        // swap top pointers
        top_temp = item.top;
        item.top = top;
        top = top_temp;

        exchange(current_element,item.current_element);
        exchange(_at_start,item._at_start);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void stack_kernel_1<T,mem_manager>::
    push(
        T& item
    )
    {
        // allocate memory for new node
        node* new_node = pool.allocate();

        // swap item into new_node
        exchange(new_node->item,item);

        // put new_node into stack
        new_node->next = top;
        top = new_node;
        ++stack_size;

        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void stack_kernel_1<T,mem_manager>::
    pop(
        T& item
    )
    {
        node* old_node = top;
        top = top->next;

        // swap the item from the stack into item
        exchange(old_node->item,item);

        // free the memory
        pool.deallocate(old_node);
        --stack_size;

        reset();
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // private member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void stack_kernel_1<T,mem_manager>::
    delete_elements_in_stack(
        node*& top
    )
    {
        node* temp;
        while (top != 0)
        {
            temp = top->next;
            pool.deallocate(top);
            top = temp;
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // enumerable function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    unsigned long stack_kernel_1<T,mem_manager>::
    size (
    ) const
    {
        return stack_size;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    bool stack_kernel_1<T,mem_manager>::
    at_start (
    ) const
    {
        return _at_start;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void stack_kernel_1<T,mem_manager>::
    reset (
    ) const
    {
        _at_start = true;
        current_element = 0;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    bool stack_kernel_1<T,mem_manager>::
    current_element_valid (
    ) const
    {
        return current_element != 0;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    const T& stack_kernel_1<T,mem_manager>::
    element (
    ) const
    {
        return current_element->item;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    T& stack_kernel_1<T,mem_manager>::
    element (
    )
    {
        return current_element->item;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    bool stack_kernel_1<T,mem_manager>::
    move_next (
    ) const
    {
        if (!_at_start)
        {
            if (current_element)
            {
                current_element = current_element->next;
                if (current_element)
                    return true;
                else
                    return false;
                }
            else
            {
                return false;
            }
        }
        else
        {
            _at_start = false;
            if (stack_size)
            {
                current_element = top;
                return true;
            }
            else
            {
                return false;
            }
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // remover function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename mem_manager
        >
    void stack_kernel_1<T,mem_manager>::
    remove_any (
        T& item
    )
    {
        pop(item);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_STACK_KERNEl_1_


dlib C++ Library - stack_kernel_c.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_STACK_KERNEl_C_
#define DLIB_STACK_KERNEl_C_

#include "stack_kernel_abstract.h"
#include "../algs.h"
#include "../assert.h"

namespace dlib
{

    template <
        typename stack_base
        >
    class stack_kernel_c : public stack_base
    {
        typedef typename stack_base::type T;
        public:
            void pop(
                T& item
            );

            T& current(
            );

            const T& current(
            ) const;

            const T& element(
            ) const;

            T& element(
            );

            void remove_any (
                T& item
            );

    };

    template <
        typename stack_base
        >
    inline void swap (
        stack_kernel_c<stack_base>& a,
        stack_kernel_c<stack_base>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename stack_base
        >
    void stack_kernel_c<stack_base>::
    pop(
        T& item
    )
    {

        // make sure requires clause is not broken
        DLIB_CASSERT(this->size() != 0,
            "\tvoid stack::pop"
            << "\n\tsize of stack should not be zero"
            << "\n\tthis: " << this
            );

        // call the real function
        stack_base::pop(item);

    }

// ----------------------------------------------------------------------------------------

    template <
        typename stack_base
        >
    const typename stack_base::type& stack_kernel_c<stack_base>::
    current(
    ) const
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(this->size() != 0,
            "\tconst T& stack::current"
            << "\n\tsize of stack should not be zero"
            << "\n\tthis: " << this
            );

        // call the real function
        return stack_base::current();

    }

// ----------------------------------------------------------------------------------------

    template <
        typename stack_base
        >
    typename stack_base::type& stack_kernel_c<stack_base>::
    current(
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(this->size() != 0,
            "\tT& stack::current"
            << "\n\tsize of stack should not be zero"
            << "\n\tthis: " << this
            );

        // call the real function
        return stack_base::current();

    }

// ----------------------------------------------------------------------------------------

    template <
        typename stack_base
        >
    typename stack_base::type& stack_kernel_c<stack_base>::
    element(
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(this->current_element_valid(),
            "\tT& stack::element"
            << "\n\tThe current element must be valid if you are to access it."
            << "\n\tthis: " << this
            );

        // call the real function
        return stack_base::element();

    }

// ----------------------------------------------------------------------------------------

    template <
        typename stack_base
        >
    const typename stack_base::type& stack_kernel_c<stack_base>::
    element(
    ) const
    {
        // make sure requires clause is not broken
        DLIB_CASSERT(this->current_element_valid(),
            "\tconst T& stack::element"
            << "\n\tThe current element must be valid if you are to access it."
            << "\n\tthis: " << this
            );

        // call the real function
        return stack_base::element();

    }

// ----------------------------------------------------------------------------------------

    template <
        typename stack_base
        >
    void stack_kernel_c<stack_base>::
    remove_any (
        T& item
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT( (this->size() > 0),
            "\tvoid stack::remove_any"
            << "\n\tsize() must be greater than zero if something is going to be removed"
            << "\n\tsize(): " << this->size()
            << "\n\tthis:   " << this
            );

        // call the real function
        stack_base::remove_any(item);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_STACK_KERNEl_C_


dlib C++ Library - static_map_kernel_1.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_STATIC_MAP_KERNEl_1_
#define DLIB_STATIC_MAP_KERNEl_1_

#include "static_map_kernel_abstract.h"
#include "../interfaces/map_pair.h"
#include "../interfaces/enumerable.h"
#include "../interfaces/remover.h"
#include "../algs.h"
#include "../serialize.h"
#include <functional>

namespace dlib
{

    template <
        typename domain,
        typename range,
        typename compare = std::less<domain>
        >
    class static_map_kernel_1 : public enumerable<map_pair<domain,range> >
    {

        /*!
            INITIAL VALUE
                - map_size == 0
                - d == 0
                - r == 0
                - mp.d = 0;
                - at_start_ == true

            CONVENTION
                - size() == map_size
                - if (size() > 0) then
                    - d == pointer to an array containing all the domain elements
                    - r == pointer to an array containing all the range elements
                    - for every i:  operator[](d[i]) == r[i]
                    - d is sorted according to operator<
                - else
                    - d == 0
                    - r == 0

                - current_element_valid() == (mp.d != 0)
                - at_start() == (at_start_)
                - if (current_element_valid()) then
                    - element() == mp
        !*/

        class mpair : public map_pair<domain,range>
        {
        public:
            const domain* d;
            range* r;

            const domain& key(
            ) const { return *d; }

            const range& value(
            ) const { return *r; }

            range& value(
            ) { return *r; }
        };

        // I would define this outside the class but Borland 5.5 has some problems
        // with non-inline templated friend functions.
        friend void deserialize (
            static_map_kernel_1& item,
            std::istream& in
        )
        {
            try
            {
                item.clear();
                unsigned long size;
                deserialize(size,in);
                item.map_size = size;
                item.d = new domain[size];
                item.r = new range[size];
                for (unsigned long i = 0; i < size; ++i)
                {
                    deserialize(item.d[i],in);
                    deserialize(item.r[i],in);
                }
            }
            catch (serialization_error& e)
            {
                item.map_size = 0;
                if (item.d)
                {
                    delete [] item.d;
                    item.d = 0;
                }
                if (item.r)
                {
                    delete [] item.r;
                    item.r = 0;
                }

                throw serialization_error(e.info + "\n   while deserializing object of type static_map_kernel_1");
            }
            catch (...)
            {
                item.map_size = 0;
                if (item.d)
                {
                    delete [] item.d;
                    item.d = 0;
                }
                if (item.r)
                {
                    delete [] item.r;
                    item.r = 0;
                }

                throw;
            }
        }

        public:

            typedef domain domain_type;
            typedef range range_type;
            typedef compare compare_type;

            static_map_kernel_1(
            );

            virtual ~static_map_kernel_1(
            );

            void clear (
            );

            void load (
                pair_remover<domain,range>& source
            );

            void load (
                asc_pair_remover<domain,range,compare>& source
            );

            inline const range* operator[] (
                const domain& d
            ) const;

            inline range* operator[] (
                const domain& d
            );

            inline void swap (
                static_map_kernel_1& item
            );

            // functions from the enumerable interface
            inline unsigned long size (
            ) const;

            inline bool at_start (
            ) const;

            inline void reset (
            ) const;

            inline bool current_element_valid (
            ) const;

            inline const map_pair<domain,range>& element (
            ) const;

            inline map_pair<domain,range>& element (
            );

            inline bool move_next (
            ) const;

        private:

            bool binary_search (
                const domain& item,
                unsigned long& pos
            ) const;
            /*!
                ensures
                    - if (there is an item in d equivalent to item) then
                        - returns true
                        - d[#pos] is equivalent item
                    - else
                        - returns false
            !*/

            void sort_arrays (
                unsigned long left,
                unsigned long right
            );
            /*!
                requires
                    - left and right are within the bounts of the array
                ensures
                    - everything in the convention is still true and d[left] though
                      d[right] is sorted according to operator<
            !*/

            void qsort_partition (
                unsigned long& partition_element,
                const unsigned long left,
                const unsigned long right
            );
            /*!
                requires
                    - left < right
                    - left and right are within the bounts of the array
                ensures
                    - the convention is still true
                    - left <= #partition_element <= right
                    - all elements in #d < #d[#partition_element] have
                      indices >= left and < #partition_element
                    - all elements in #d >= #d[#partition_element] have
                      indices >= #partition_element and <= right
            !*/

            unsigned long median (
                unsigned long one,
                unsigned long two,
                unsigned long three
            );
            /*!
                requires
                    - one, two, and three are valid indexes into d
                ensures
                    - returns the median of d[one], d[two], and d[three]
            !*/

            // data members
            unsigned long map_size;
            domain* d;
            range* r;
            mutable mpair mp;
            mutable bool at_start_;
            compare comp;

            // restricted functions
            static_map_kernel_1(static_map_kernel_1&);        // copy constructor
            static_map_kernel_1& operator=(static_map_kernel_1&);    // assignment operator
    };

    template <
        typename domain,
        typename range,
        typename compare
        >
    inline void swap (
        static_map_kernel_1<domain,range,compare>& a,
        static_map_kernel_1<domain,range,compare>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename compare
        >
    static_map_kernel_1<domain,range,compare>::
    static_map_kernel_1(
    ) :
        map_size(0),
        d(0),
        r(0),
        at_start_(true)
    {
        mp.d = 0;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename compare
        >
    static_map_kernel_1<domain,range,compare>::
    ~static_map_kernel_1(
    )
    {
        if (map_size > 0)
        {
            delete [] d;
            delete [] r;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename compare
        >
    void static_map_kernel_1<domain,range,compare>::
    clear (
    )
    {
        if (map_size > 0)
        {
            map_size = 0;
            delete [] d;
            delete [] r;
            d = 0;
            r = 0;
        }
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename compare
        >
    void static_map_kernel_1<domain,range,compare>::
    load (
        pair_remover<domain,range>& source
    )
    {
        if (source.size() > 0)
        {
            domain* old_d = d;
            d = new domain[source.size()];
            try { r = new range[source.size()]; }
            catch (...) { delete [] d; d = old_d; throw; }

            map_size = source.size();

            for (unsigned long i = 0; source.size() > 0; ++i)
                source.remove_any(d[i],r[i]);

            sort_arrays(0,map_size-1);
        }
        else
        {
            clear();
        }
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename compare
        >
    void static_map_kernel_1<domain,range,compare>::
    load (
        asc_pair_remover<domain,range,compare>& source
    )
    {
        if (source.size() > 0)
        {
            domain* old_d = d;
            d = new domain[source.size()];
            try { r = new range[source.size()]; }
            catch (...) { delete [] d; d = old_d; throw; }

            map_size = source.size();

            for (unsigned long i = 0; source.size() > 0; ++i)
                source.remove_any(d[i],r[i]);
        }
        else
        {
            clear();
        }
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename compare
        >
    const range* static_map_kernel_1<domain,range,compare>::
    operator[] (
        const domain& d_item
    ) const
    {
        unsigned long pos;
        if (binary_search(d_item,pos))
            return r+pos;
        else
            return 0;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename compare
        >
    range* static_map_kernel_1<domain,range,compare>::
    operator[] (
        const domain& d_item
    )
    {
        unsigned long pos;
        if (binary_search(d_item,pos))
            return r+pos;
        else
            return 0;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename compare
        >
    unsigned long static_map_kernel_1<domain,range,compare>::
    size (
    ) const
    {
        return map_size;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename compare
        >
    void static_map_kernel_1<domain,range,compare>::
    swap (
        static_map_kernel_1<domain,range,compare>& item
    )
    {
        exchange(map_size,item.map_size);
        exchange(d,item.d);
        exchange(r,item.r);
        exchange(mp,item.mp);
        exchange(at_start_,item.at_start_);
        exchange(comp,item.comp);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // enumerable function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename compare
        >
    bool static_map_kernel_1<domain,range,compare>::
    at_start (
    ) const
    {
        return (at_start_);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename compare
        >
    void static_map_kernel_1<domain,range,compare>::
    reset (
    ) const
    {
        mp.d = 0;
        at_start_ = true;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename compare
        >
    bool static_map_kernel_1<domain,range,compare>::
    current_element_valid (
    ) const
    {
        return (mp.d != 0);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename compare
        >
    const map_pair<domain,range>& static_map_kernel_1<domain,range,compare>::
    element (
    ) const
    {
        return mp;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename compare
        >
    map_pair<domain,range>& static_map_kernel_1<domain,range,compare>::
    element (
    )
    {
        return mp;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename compare
        >
    bool static_map_kernel_1<domain,range,compare>::
    move_next (
    ) const
    {
        // if at_start() && size() > 0
        if (at_start_ && map_size > 0)
        {
            at_start_ = false;
            mp.r = r;
            mp.d = d;
            return true;
        }
        // else if current_element_valid()
        else if (mp.d != 0)
        {
            ++mp.d;
            ++mp.r;
            if (static_cast<unsigned long>(mp.d - d) < map_size)
            {
                return true;
            }
            else
            {
                mp.d = 0;
                return false;
            }
        }
        else
        {
            at_start_ = false;
            return false;
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // private member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename compare
        >
    bool static_map_kernel_1<domain,range,compare>::
    binary_search (
        const domain& item,
        unsigned long& pos
    ) const
    {
        unsigned long high = map_size;
        unsigned long low = 0;
        unsigned long p = map_size;
        unsigned long idx;
        while (p > 0)
        {
            p = (high-low)>>1;
            idx = p+low;
            if (comp(item , d[idx]))
            {
                high = idx;
            }
            else if (comp(d[idx] , item))
            {
                low = idx;
            }
            else
            {
                pos = idx;
                return true;
            }
        }
        return false;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename compare
        >
    void static_map_kernel_1<domain,range,compare>::
    sort_arrays (
        unsigned long left,
        unsigned long right
    )
    {
        if ( left < right)
        {
            unsigned long partition_element;
            qsort_partition(partition_element,left,right);

            if (partition_element > 0)
                sort_arrays(left,partition_element-1);
            sort_arrays(partition_element+1,right);
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename compare
        >
    void static_map_kernel_1<domain,range,compare>::
    qsort_partition (
        unsigned long& partition_element,
        const unsigned long left,
        const unsigned long right
    )
    {
        partition_element = right;

        unsigned long med = median(partition_element,left,((right-left)>>1) +left);
        exchange(d[partition_element],d[med]);
        exchange(r[partition_element],r[med]);

        unsigned long right_scan = right-1;
        unsigned long left_scan = left;

        while (true)
        {
            // find an element to the left of partition_element that needs to be moved
            while ( comp( d[left_scan] , d[partition_element]) )
            {
                ++left_scan;
            }

            // find an element to the right of partition_element that needs to be moved
            while (
                !(comp (d[right_scan] , d[partition_element])) &&
                (right_scan > left_scan)
            )
            {
                --right_scan;
            }
            if (left_scan >= right_scan)
                break;

            exchange(d[left_scan],d[right_scan]);
            exchange(r[left_scan],r[right_scan]);

        }
        exchange(d[left_scan],d[partition_element]);
        exchange(r[left_scan],r[partition_element]);
        partition_element = left_scan;

    }

// ----------------------------------------------------------------------------------------

    template <
        typename domain,
        typename range,
        typename compare
        >
    unsigned long static_map_kernel_1<domain,range,compare>::
    median (
        unsigned long one,
        unsigned long two,
        unsigned long three
    )
    {
        if ( comp( d[one] , d[two]) )
        {
            // one < two
            if ( comp( d[two] , d[three]) )
            {
                // one < two < three : two
                return two;
            }
            else
            {
                // one < two >= three
                if (comp( d[one] , d[three]))
                {
                    // three
                    return three;
                }
            }

        }
        else
        {
            // one >= two
            if ( comp(d[three] , d[one] ))
            {
                // three <= one >= two
                if ( comp(d[three] , d[two]) )
                {
                    // two
                    return two;
                }
                else
                {
                    // three
                    return three;
                }
            }
        }
        return one;
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_STATIC_MAP_KERNEl_1_


dlib C++ Library - static_set_compare_1.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_STATIC_SET_COMPARe_1_
#define DLIB_STATIC_SET_COMPARe_1_

#include "static_set_compare_abstract.h"

#include "../algs.h"

namespace dlib
{

    template <
        typename static_set_base
        >
    class static_set_compare_1 : public static_set_base
    {

        public:

            bool operator< (
                const static_set_compare_1& rhs
            ) const;

            bool operator== (
                const static_set_compare_1& rhs
            ) const;

    };

    template <
        typename static_set_base
        >
    inline void swap (
        static_set_compare_1<static_set_base>& a,
        static_set_compare_1<static_set_base>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename static_set_base
        >
    bool static_set_compare_1<static_set_base>::
    operator< (
        const static_set_compare_1<static_set_base>& rhs
    ) const
    {
        bool result = false;
        if (static_set_base::size() < rhs.size())
            result = true;

        if (static_set_base::size() == rhs.size())
        {
            rhs.reset();
            static_set_base::reset();
            while (rhs.move_next())
            {
                static_set_base::move_next();
                if (static_set_base::element() < rhs.element())
                {
                    result = true;
                    break;
                }
                else if (rhs.element() < static_set_base::element())
                {
                    break;
                }
            }
        }

        static_set_base::reset();
        rhs.reset();

        return result;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename static_set_base
        >
    bool static_set_compare_1<static_set_base>::
    operator== (
        const static_set_compare_1<static_set_base>& rhs
    ) const
    {
        bool result = true;
        if (static_set_base::size() != rhs.size())
            result = false;

        rhs.reset();
        static_set_base::reset();
        while (rhs.move_next() && static_set_base::move_next())
        {
            if (!(rhs.element() == static_set_base::element()))
            {
                result = false;
                break;
            }
        }

        static_set_base::reset();
        rhs.reset();

        return result;
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_STATIC_SET_COMPARe_1_


dlib C++ Library - static_set_kernel_1.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_STATIC_SET_KERNEl_1_
#define DLIB_STATIC_SET_KERNEl_1_

#include "static_set_kernel_abstract.h"
#include "../interfaces/enumerable.h"
#include "../interfaces/remover.h"
#include "../algs.h"
#include "../sort.h"
#include "../serialize.h"
#include <functional>

namespace dlib
{

    template <
        typename T,
        typename compare = std::less<T>
        >
    class static_set_kernel_1 : public enumerable<const T>
    {

        /*!
            INITIAL VALUE
                - set_size == 0
                - d == 0
                - at_start_ == true
                - cur == 0

            CONVENTION
                - size() == set_size
                - if (set_size > 0) then
                    - d == pointer to an array containing all the elements of the set
                    - d is sorted according to operator<
                - else
                    - d == 0

                - current_element_valid() == (cur != 0)
                - at_start() == (at_start_)
                - if (current_element_valid()) then
                    - element() == *cur
        !*/

        // I would define this outside the class but Borland 5.5 has some problems
        // with non-inline templated friend functions.
        friend void deserialize (
            static_set_kernel_1& item,
            std::istream& in
        )
        {
            try
            {
                item.clear();
                unsigned long size;
                deserialize(size,in);
                item.set_size = size;
                item.d = new T[size];
                for (unsigned long i = 0; i < size; ++i)
                {
                    deserialize(item.d[i],in);
                }
            }
            catch (serialization_error e)
            {
                item.set_size = 0;
                if (item.d)
                {
                    delete [] item.d;
                    item.d = 0;
                }

                throw serialization_error(e.info + "\n   while deserializing object of type static_set_kernel_1");
            }
            catch (...)
            {
                item.set_size = 0;
                if (item.d)
                {
                    delete [] item.d;
                    item.d = 0;
                }

                throw;
            }
        }

        public:

            typedef T type;
            typedef compare compare_type;

            static_set_kernel_1(
            );

            virtual ~static_set_kernel_1(
            );

            void clear (
            );

            void load (
                remover<T>& source
            );

            void load (
                asc_remover<T,compare>& source
            );

            bool is_member (
                const T& item
            ) const;

            inline void swap (
                static_set_kernel_1& item
            );

            // functions from the enumerable interface
            inline unsigned long size (
            ) const;

            inline bool at_start (
            ) const;

            inline void reset (
            ) const;

            inline bool current_element_valid (
            ) const;

            inline const T& element (
            ) const;

            inline const T& element (
            );

            inline bool move_next (
            ) const;

        private:

            // data members
            unsigned long set_size;
            T* d;
            mutable T* cur;
            mutable bool at_start_;

            // restricted functions
            static_set_kernel_1(static_set_kernel_1&);        // copy constructor
            static_set_kernel_1& operator=(static_set_kernel_1&);    // assignment operator
    };

    template <
        typename T,
        typename compare
        >
    inline void swap (
        static_set_kernel_1<T,compare>& a,
        static_set_kernel_1<T,compare>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename compare
        >
    static_set_kernel_1<T,compare>::
    static_set_kernel_1(
    ) :
        set_size(0),
        d(0),
        cur(0),
        at_start_(true)
    {
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename compare
        >
    static_set_kernel_1<T,compare>::
    ~static_set_kernel_1(
    )
    {
        if (set_size > 0)
            delete [] d;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename compare
        >
    void static_set_kernel_1<T,compare>::
    clear(
    )
    {
        if (set_size > 0)
        {
            set_size = 0;
            delete [] d;
            d = 0;
        }
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename compare
        >
    void static_set_kernel_1<T,compare>::
    load (
        remover<T>& source
    )
    {
        if (source.size() > 0)
        {
            d = new T[source.size()];

            set_size = source.size();

            for (unsigned long i = 0; source.size() > 0; ++i)
                source.remove_any(d[i]);

            compare comp;
            qsort_array(d,0,set_size-1,comp);
        }
        else
        {
            clear();
        }
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename compare
        >
    void static_set_kernel_1<T,compare>::
    load (
        asc_remover<T,compare>& source
    )
    {
        if (source.size() > 0)
        {
            d = new T[source.size()];

            set_size = source.size();

            for (unsigned long i = 0; source.size() > 0; ++i)
                source.remove_any(d[i]);
        }
        else
        {
            clear();
        }
        reset();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename compare
        >
    bool static_set_kernel_1<T,compare>::
    is_member (
        const T& item
    ) const
    {
        unsigned long high = set_size;
        unsigned long low = 0;
        unsigned long p = set_size;
        unsigned long idx;
        while (p > 0)
        {
            p = (high-low)>>1;
            idx = p+low;
            if (item < d[idx])
                high = idx;
            else if (d[idx] < item)
                low = idx;
            else
                return true;
        }
        return false;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename compare
        >
    unsigned long static_set_kernel_1<T,compare>::
    size (
    ) const
    {
        return set_size;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename compare
        >
    void static_set_kernel_1<T,compare>::
    swap (
        static_set_kernel_1<T,compare>& item
    )
    {
        exchange(set_size,item.set_size);
        exchange(d,item.d);
        exchange(cur,item.cur);
        exchange(at_start_,item.at_start_);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // enumerable function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename compare
        >
    bool static_set_kernel_1<T,compare>::
    at_start (
    ) const
    {
        return at_start_;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename compare
        >
    void static_set_kernel_1<T,compare>::
    reset (
    ) const
    {
        at_start_ = true;
        cur = 0;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename compare
        >
    bool static_set_kernel_1<T,compare>::
    current_element_valid (
    ) const
    {
        return (cur != 0);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename compare
        >
    const T& static_set_kernel_1<T,compare>::
    element (
    ) const
    {
        return *cur;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename compare
        >
    const T& static_set_kernel_1<T,compare>::
    element (
    )
    {
        return *cur;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename compare
        >
    bool static_set_kernel_1<T,compare>::
    move_next (
    ) const
    {
        // if at_start() && size() > 0
        if (at_start_ && set_size > 0)
        {
            at_start_ = false;
            cur = d;
            return true;
        }
        // else if current_element_valid()
        else if (cur != 0)
        {
            ++cur;
            if (static_cast<unsigned long>(cur - d) < set_size)
            {
                return true;
            }
            else
            {
                cur = 0;
                return false;
            }
        }
        else
        {
            at_start_ = false;
            return false;
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_STATIC_SET_KERNEl_1_


dlib C++ Library - average_precision.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_AVERAGE_PREcISION_Hh_
#define DLIB_AVERAGE_PREcISION_Hh_

#include "average_precision_abstract.h"
#include <vector>

namespace dlib
{
    namespace impl
    {
        inline bool get_bool_part (
            const bool& b
        ) { return b; }

        template <typename T>
        bool get_bool_part(const std::pair<T,bool>& item) { return item.second; }
    }

// ----------------------------------------------------------------------------------------

    template <typename T, typename alloc>
    double average_precision (
        const std::vector<T,alloc>& items,
        unsigned long missing_relevant_items = 0
    )
    {
        using namespace dlib::impl;
        double relevant_count = 0;
        // find the precision values
        std::vector<double> precision;
        for (unsigned long i = 0; i < items.size(); ++i)
        {
            if (get_bool_part(items[i]))
            {
                ++relevant_count;
                precision.push_back(relevant_count / (i+1));
            }
        }

        double precision_sum = 0;
        double max_val = 0;
        // now sum over the interpolated precision values
        for (std::vector<double>::reverse_iterator i = precision.rbegin(); i != precision.rend(); ++i)
        {
            max_val = std::max(max_val, *i);
            precision_sum += max_val;
        }

        relevant_count += missing_relevant_items;

        if (relevant_count != 0)
            return precision_sum/relevant_count;
        else
            return 1;
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_AVERAGE_PREcISION_Hh_


dlib C++ Library - cca.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_CCA_hh_
#define DLIB_CCA_hh_

#include "cca_abstract.h"
#include "../algs.h"
#include "../matrix.h"
#include "../sparse_vector.h"
#include "random_subset_selector.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    matrix<typename T::type,0,1> compute_correlations (
        const matrix_exp<T>& L,
        const matrix_exp<T>& R
    )
    {
        DLIB_ASSERT( L.size() > 0 && R.size() > 0 && L.nr() == R.nr(),
            "\t matrix compute_correlations()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t L.size(): " << L.size()
            << "\n\t R.size(): " << R.size()
            << "\n\t L.nr():   " << L.nr()
            << "\n\t R.nr():   " << R.nr()
            );

        typedef typename T::type type;
        matrix<type> A, B, C;
        A = diag(trans(R)*L);
        B = sqrt(diag(trans(L)*L));
        C = sqrt(diag(trans(R)*R));
        A = pointwise_multiply(A , reciprocal(pointwise_multiply(B,C)));
        return A;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_type,
        typename T
        >
    matrix<T,0,1> impl_cca (
        const matrix_type& L,
        const matrix_type& R,
        matrix<T>& Ltrans,
        matrix<T>& Rtrans,
        unsigned long num_correlations,
        unsigned long extra_rank,
        unsigned long q,
        unsigned long num_output_correlations,
        double regularization
    )
    {
        matrix<T> Ul, Vl;
        matrix<T> Ur, Vr;
        matrix<T> U, V;
        matrix<T,0,1> Dr, Dl, D;

        // Note that we add a few more singular vectors in because it helps improve the
        // final results if we run this part with a little higher rank than the final SVD.
        svd_fast(L, Ul, Dl, Vl, num_correlations+extra_rank, q);
        svd_fast(R, Ur, Dr, Vr, num_correlations+extra_rank, q);

        // Zero out singular values that are essentially zero so they don't cause numerical
        // difficulties in the code below.
        const double eps = std::numeric_limits<T>::epsilon()*std::max(max(Dr),max(Dl))*100;
        Dl = round_zeros(Dl+regularization,eps);
        Dr = round_zeros(Dr+regularization,eps);

        // This matrix is really small so we can do a normal full SVD on it.  Note that we
        // also throw away the columns of Ul and Ur corresponding to zero singular values.
        svd3(diagm(Dl>0)*tmp(trans(Ul)*Ur)*diagm(Dr>0), U, D, V);

        // now throw away extra columns of the transformations.  We do this in a way
        // that keeps the directions that have the highest correlations.
        matrix<T,0,1> temp = D;
        rsort_columns(U, temp);
        rsort_columns(V, D);
        U = colm(U, range(0, num_output_correlations-1));
        V = colm(V, range(0, num_output_correlations-1));
        D = rowm(D, range(0, num_output_correlations-1));

        Ltrans = Vl*inv(diagm(Dl))*U;
        Rtrans = Vr*inv(diagm(Dr))*V;

        // Note that the D matrix contains the correlation values for the transformed
        // vectors.  However, when the L and R matrices have rank higher than
        // num_correlations+extra_rank then the values in D become only approximate.
        return D;
    }

// ----------------------------------------------------------------------------------------

    template <typename T>
    matrix<T,0,1> cca (
        const matrix<T>& L,
        const matrix<T>& R,
        matrix<T>& Ltrans,
        matrix<T>& Rtrans,
        unsigned long num_correlations,
        unsigned long extra_rank = 5,
        unsigned long q = 2,
        double regularization = 0
    )
    {
        DLIB_ASSERT( num_correlations > 0 && L.size() > 0 && R.size() > 0 && L.nr() == R.nr() &&
            regularization >= 0,
            "\t matrix cca()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t num_correlations: " << num_correlations
            << "\n\t regularization:   " << regularization
            << "\n\t L.size(): " << L.size()
            << "\n\t R.size(): " << R.size()
            << "\n\t L.nr():   " << L.nr()
            << "\n\t R.nr():   " << R.nr()
            );

        using std::min;
        const unsigned long n = min(num_correlations, (unsigned long)min(R.nr(),min(L.nc(), R.nc())));
        return impl_cca(L,R,Ltrans, Rtrans, num_correlations, extra_rank, q, n, regularization);
    }

// ----------------------------------------------------------------------------------------

    template <typename sparse_vector_type, typename T>
    matrix<T,0,1> cca (
        const std::vector<sparse_vector_type>& L,
        const std::vector<sparse_vector_type>& R,
        matrix<T>& Ltrans,
        matrix<T>& Rtrans,
        unsigned long num_correlations,
        unsigned long extra_rank = 5,
        unsigned long q = 2,
        double regularization = 0
    )
    {
        DLIB_ASSERT( num_correlations > 0 && L.size() == R.size() &&
                     max_index_plus_one(L) > 0 && max_index_plus_one(R) > 0 &&
                     regularization >= 0,
            "\t matrix cca()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t num_correlations: " << num_correlations
            << "\n\t regularization:   " << regularization
            << "\n\t L.size(): " << L.size()
            << "\n\t R.size(): " << R.size()
            << "\n\t max_index_plus_one(L):   " << max_index_plus_one(L)
            << "\n\t max_index_plus_one(R):   " << max_index_plus_one(R)
            );

        using std::min;
        const unsigned long n = min(max_index_plus_one(L), max_index_plus_one(R));
        const unsigned long num_output_correlations = min(num_correlations, std::min<unsigned long>(R.size(),n));
        return impl_cca(L,R,Ltrans, Rtrans, num_correlations, extra_rank, q, num_output_correlations, regularization);
    }

// ----------------------------------------------------------------------------------------

    template <typename sparse_vector_type, typename Rand_type, typename T>
    matrix<T,0,1> cca (
        const random_subset_selector<sparse_vector_type,Rand_type>& L,
        const random_subset_selector<sparse_vector_type,Rand_type>& R,
        matrix<T>& Ltrans,
        matrix<T>& Rtrans,
        unsigned long num_correlations,
        unsigned long extra_rank = 5,
        unsigned long q = 2
    )
    {
        return cca(L.to_std_vector(), R.to_std_vector(), Ltrans, Rtrans, num_correlations, extra_rank, q);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_CCA_hh_


dlib C++ Library - dpca.h

// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_DPCA_h_
#define DLIB_DPCA_h_

#include "dpca_abstract.h"
#include <limits>
#include <cmath>
#include "../algs.h"
#include "../matrix.h"
#include <iostream>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_type
        >
    class discriminant_pca
    {
        /*!
            INITIAL VALUE
                - vect_size == 0
                - total_count == 0
                - between_count == 0
                - within_count == 0
                - between_weight == 1
                - within_weight == 1

            CONVENTION
                - vect_size == in_vector_size()
                - total_count == the number of times add_to_total_variance() has been called.
                - within_count == the number of times add_to_within_class_variance() has been called.
                - between_count == the number of times add_to_between_class_variance() has been called.
                - between_weight == between_class_weight()
                - within_weight == within_class_weight()

                - if (total_count != 0)
                    - total_sum == the sum of all vectors given to add_to_total_variance()
                    - the covariance of all the elements given to add_to_total_variance() is given
                      by:
                        - let avg == total_sum/total_count
                        - covariance == total_cov/total_count - avg*trans(avg)
                - if (within_count != 0)
                    - within_cov/within_count == the normalized within class scatter matrix
                - if (between_count != 0)
                    - between_cov/between_count == the normalized between class scatter matrix
        !*/

    public:

        struct discriminant_pca_error : public error
        {
            discriminant_pca_error(const std::string& message): error(message) {}
        };

        typedef typename matrix_type::mem_manager_type mem_manager_type;
        typedef typename matrix_type::type scalar_type;
        typedef typename matrix_type::layout_type layout_type;
        typedef matrix<scalar_type,0,0,mem_manager_type,layout_type> general_matrix;
        typedef matrix<scalar_type,0,1,mem_manager_type,layout_type> column_matrix;

        discriminant_pca (
        )
        {
            clear();
        }

        void clear(
        )
        {
            total_count = 0;
            between_count = 0;
            within_count = 0;

            vect_size = 0;

            between_weight = 1;
            within_weight = 1;

            total_sum.set_size(0);
            between_cov.set_size(0,0);
            total_cov.set_size(0,0);
            within_cov.set_size(0,0);
        }

        long in_vector_size (
        ) const
        {
            return vect_size;
        }

        void set_within_class_weight (
            scalar_type weight
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(weight >= 0,
                "\t void discriminant_pca::set_within_class_weight()"
                << "\n\t You can't use negative weight values"
                << "\n\t weight: " << weight
                << "\n\t this:   " << this
                );

            within_weight = weight;
        }

        scalar_type within_class_weight (
        ) const
        {
            return within_weight;
        }

        void set_between_class_weight (
            scalar_type weight
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(weight >= 0,
                "\t void discriminant_pca::set_between_class_weight()"
                << "\n\t You can't use negative weight values"
                << "\n\t weight: " << weight
                << "\n\t this:   " << this
                );

            between_weight = weight;
        }

        scalar_type between_class_weight (
        ) const
        {
            return between_weight;
        }

        template <typename EXP1, typename EXP2>
        void add_to_within_class_variance(
            const matrix_exp<EXP1>& x,
            const matrix_exp<EXP2>& y
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(is_col_vector(x) && is_col_vector(y) &&
                         x.size() == y.size() &&
                         (in_vector_size() == 0 || x.size() == in_vector_size()),
                "\t void discriminant_pca::add_to_within_class_variance()"
                << "\n\t Invalid inputs were given to this function"
                << "\n\t is_col_vector(x): " << is_col_vector(x)
                << "\n\t is_col_vector(y): " << is_col_vector(y)
                << "\n\t x.size():         " << x.size()
                << "\n\t y.size():         " << y.size()
                << "\n\t in_vector_size(): " << in_vector_size()
                << "\n\t this:             " << this
                );

            vect_size = x.size();
            if (within_count == 0)
            {
                within_cov = (x-y)*trans(x-y);
            }
            else
            {
                within_cov += (x-y)*trans(x-y);
            }
            ++within_count;
        }

        template <typename EXP1, typename EXP2>
        void add_to_between_class_variance(
            const matrix_exp<EXP1>& x,
            const matrix_exp<EXP2>& y
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(is_col_vector(x) && is_col_vector(y) &&
                         x.size() == y.size() &&
                         (in_vector_size() == 0 || x.size() == in_vector_size()),
                "\t void discriminant_pca::add_to_between_class_variance()"
                << "\n\t Invalid inputs were given to this function"
                << "\n\t is_col_vector(x): " << is_col_vector(x)
                << "\n\t is_col_vector(y): " << is_col_vector(y)
                << "\n\t x.size():         " << x.size()
                << "\n\t y.size():         " << y.size()
                << "\n\t in_vector_size(): " << in_vector_size()
                << "\n\t this:             " << this
                );

            vect_size = x.size();
            if (between_count == 0)
            {
                between_cov = (x-y)*trans(x-y);
            }
            else
            {
                between_cov += (x-y)*trans(x-y);
            }
            ++between_count;
        }

        template <typename EXP>
        void add_to_total_variance(
            const matrix_exp<EXP>& x
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(is_col_vector(x) && (in_vector_size() == 0 || x.size() == in_vector_size()),
                "\t void discriminant_pca::add_to_total_variance()"
                << "\n\t Invalid inputs were given to this function"
                << "\n\t is_col_vector(x): " << is_col_vector(x)
                << "\n\t in_vector_size(): " << in_vector_size()
                << "\n\t x.size():         " << x.size()
                << "\n\t this:             " << this
                );

            vect_size = x.size();
            if (total_count == 0)
            {
                total_cov = x*trans(x);
                total_sum = x;
            }
            else
            {
                total_cov += x*trans(x);
                total_sum += x;
            }
            ++total_count;
        }

        const general_matrix dpca_matrix (
            const double eps = 0.99
        ) const
        {
            general_matrix dpca_mat;
            general_matrix eigenvalues;
            dpca_matrix(dpca_mat, eigenvalues, eps);
            return dpca_mat;
        }

        const general_matrix dpca_matrix_of_size (
            const long num_rows
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(0 < num_rows && num_rows <= in_vector_size(),
                "\t general_matrix discriminant_pca::dpca_matrix_of_size()"
                << "\n\t Invalid inputs were given to this function"
                << "\n\t num_rows:         " << num_rows
                << "\n\t in_vector_size(): " << in_vector_size()
                << "\n\t this:             " << this
                );

            general_matrix dpca_mat;
            general_matrix eigenvalues;
            dpca_matrix_of_size(dpca_mat, eigenvalues, num_rows);
            return dpca_mat;
        }

        void dpca_matrix (
            general_matrix& dpca_mat,
            general_matrix& eigenvalues,
            const double eps = 0.99
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(0 < eps && eps <= 1 && in_vector_size() != 0,
                "\t void discriminant_pca::dpca_matrix()"
                << "\n\t Invalid inputs were given to this function"
                << "\n\t eps:              " << eps
                << "\n\t in_vector_size(): " << in_vector_size()
                << "\n\t this:             " << this
                );

            compute_dpca_matrix(dpca_mat, eigenvalues, eps, 0);
        }

        void dpca_matrix_of_size (
            general_matrix& dpca_mat,
            general_matrix& eigenvalues,
            const long num_rows
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(0 < num_rows && num_rows <= in_vector_size(),
                "\t general_matrix discriminant_pca::dpca_matrix_of_size()"
                << "\n\t Invalid inputs were given to this function"
                << "\n\t num_rows:         " << num_rows
                << "\n\t in_vector_size(): " << in_vector_size()
                << "\n\t this:             " << this
                );

            compute_dpca_matrix(dpca_mat, eigenvalues, 1, num_rows);
        }

        void swap (
            discriminant_pca& item
        )
        {
            using std::swap;
            swap(total_cov, item.total_cov);
            swap(total_sum, item.total_sum);
            swap(total_count, item.total_count);
            swap(vect_size, item.vect_size);
            swap(between_cov, item.between_cov);

            swap(between_count, item.between_count);
            swap(between_weight, item.between_weight);
            swap(within_cov, item.within_cov);
            swap(within_count, item.within_count);
            swap(within_weight, item.within_weight);
        }

        friend void deserialize (
            discriminant_pca& item,
            std::istream& in
        )
        {
            deserialize( item.total_cov, in);
            deserialize( item.total_sum, in);
            deserialize( item.total_count, in);
            deserialize( item.vect_size, in);
            deserialize( item.between_cov, in);
            deserialize( item.between_count, in);
            deserialize( item.between_weight, in);
            deserialize( item.within_cov, in);
            deserialize( item.within_count, in);
            deserialize( item.within_weight, in);
        }

        friend void serialize (
            const discriminant_pca& item,
            std::ostream& out
        )
        {
            serialize( item.total_cov, out);
            serialize( item.total_sum, out);
            serialize( item.total_count, out);
            serialize( item.vect_size, out);
            serialize( item.between_cov, out);
            serialize( item.between_count, out);
            serialize( item.between_weight, out);
            serialize( item.within_cov, out);
            serialize( item.within_count, out);
            serialize( item.within_weight, out);
        }

        discriminant_pca operator+ (
            const discriminant_pca& item
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT((in_vector_size() == 0 || item.in_vector_size() == 0 || in_vector_size() == item.in_vector_size()) &&
                         between_class_weight() == item.between_class_weight() &&
                         within_class_weight() == item.within_class_weight(),
                "\t discriminant_pca discriminant_pca::operator+()"
                << "\n\t The two discriminant_pca objects being added must have compatible parameters"
                << "\n\t in_vector_size():            " << in_vector_size()
                << "\n\t item.in_vector_size():       " << item.in_vector_size()
                << "\n\t between_class_weight():      " << between_class_weight()
                << "\n\t item.between_class_weight(): " << item.between_class_weight()
                << "\n\t within_class_weight():       " << within_class_weight()
                << "\n\t item.within_class_weight():  " << item.within_class_weight()
                << "\n\t this:                        " << this
                );

            discriminant_pca temp(item);

            // We need to make sure to ignore empty matrices.  That's what these if statements
            // are for.

            if (total_count != 0 && temp.total_count != 0)
            {
                temp.total_cov += total_cov;
                temp.total_sum += total_sum;
                temp.total_count += total_count;
            }
            else if (total_count != 0)
            {
                temp.total_cov = total_cov;
                temp.total_sum = total_sum;
                temp.total_count = total_count;
            }

            if (between_count != 0 && temp.between_count != 0)
            {
                temp.between_cov += between_cov;
                temp.between_count += between_count;
            }
            else if (between_count != 0)
            {
                temp.between_cov = between_cov;
                temp.between_count = between_count;
            }

            if (within_count != 0 && temp.within_count != 0)
            {
                temp.within_cov += within_cov;
                temp.within_count += within_count;
            }
            else if (within_count != 0)
            {
                temp.within_cov = within_cov;
                temp.within_count = within_count;
            }

            return temp;
        }

        discriminant_pca& operator+= (
            const discriminant_pca& rhs
        )
        {
            (*this + rhs).swap(*this);
            return *this;
        }

    private:

        void compute_dpca_matrix (
            general_matrix& dpca_mat,
            general_matrix& eigenvalues,
            const double eps,
            long num_rows
        ) const
        {
            general_matrix cov;

            // now combine the three measures of variance into a single matrix by using the
            // within_weight and between_weight weights.
            cov = get_total_covariance_matrix();
            if (within_count != 0)
                cov -= within_weight*within_cov/within_count;
            if (between_count != 0)
                cov += between_weight*between_cov/between_count;

            eigenvalue_decomposition<general_matrix> eig(make_symmetric(cov));

            eigenvalues = eig.get_real_eigenvalues();
            dpca_mat = eig.get_pseudo_v();

            // sort the eigenvalues and eigenvectors so that the biggest eigenvalues come first
            rsort_columns(dpca_mat, eigenvalues);

            long num_vectors = 0;
            if (num_rows == 0)
            {
                // Some of the eigenvalues might be negative.  So first lets zero those out
                // so they won't get considered.
                eigenvalues = pointwise_multiply(eigenvalues > 0, eigenvalues);
                // figure out how many eigenvectors we want in our dpca matrix
                const double thresh = sum(eigenvalues)*eps;
                double total = 0;
                for (long r = 0; r < eigenvalues.size() && total < thresh; ++r)
                {
                    // Don't even think about looking at eigenvalues that are 0.  If we go this
                    // far then we have all we need.
                    if (eigenvalues(r) == 0)
                        break;

                    ++num_vectors;
                    total += eigenvalues(r);
                }

                if (num_vectors == 0)
                    throw discriminant_pca_error("While performing discriminant_pca, all eigenvalues were negative or 0");
            }
            else
            {
                num_vectors = num_rows;
            }

            // So now we know we want to use num_vectors of the first eigenvectors.  So
            // pull those out and discard the rest.
            dpca_mat = trans(colm(dpca_mat,range(0,num_vectors-1)));

            // also clip off the eigenvalues we aren't using
            eigenvalues = rowm(eigenvalues, range(0,num_vectors-1));

        }

        general_matrix get_total_covariance_matrix (
        ) const
        /*!
            ensures
                - returns the covariance matrix of all the data given to the add_to_total_variance()
        !*/
        {
            // if we don't even know the dimensionality of the vectors we are dealing
            // with then just return an empty matrix
            if (vect_size == 0)
                return general_matrix();

            // we know the vector size but we have zero total covariance.
            if (total_count == 0)
            {
                general_matrix temp(vect_size,vect_size);
                temp = 0;
                return temp;
            }

            // In this case we actually have something to make a total covariance matrix out of.
            // So do that.
            column_matrix avg = total_sum/total_count;

            return total_cov/total_count - avg*trans(avg);
        }

        general_matrix total_cov;
        column_matrix total_sum;
        scalar_type total_count;

        long vect_size;

        general_matrix between_cov;
        scalar_type between_count;
        scalar_type between_weight;

        general_matrix within_cov;
        scalar_type within_count;
        scalar_type within_weight;
    };

    template <
        typename matrix_type
        >
    inline void swap (
        discriminant_pca<matrix_type>& a,
        discriminant_pca<matrix_type>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_DPCA_h_


dlib C++ Library - image_feature_sampling.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_IMAGE_FEATURE_SaMPLING_Hh_
#define DLIB_IMAGE_FEATURE_SaMPLING_Hh_

#include "image_feature_sampling_abstract.h"
#include "../statistics.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename image_array_type,
        typename feature_extractor_type,
        typename pyramid_type
        >
    random_subset_selector<typename feature_extractor_type::descriptor_type> randomly_sample_image_features (
        const image_array_type& images,
        const pyramid_type& pyr,
        const feature_extractor_type& fe_,
        unsigned long num
    )
    {
        feature_extractor_type fe;
        fe.copy_configuration(fe_);
        random_subset_selector<typename feature_extractor_type::descriptor_type> basis;
        basis.set_max_size(num);

        typedef typename image_array_type::type image_type;
        image_type temp_img, temp_img2;

        for (unsigned long i = 0; i < images.size(); ++i)
        {
            bool at_pyramid_top = true;
            while (true)
            {
                if (at_pyramid_top)
                    fe.load(images[i]);
                else
                    fe.load(temp_img);

                if (fe.size() == 0)
                    break;

                for (long r = 0; r < fe.nr(); ++r)
                {
                    for (long c = 0; c < fe.nc(); ++c)
                    {
                        if (basis.next_add_accepts())
                        {
                            basis.add(fe(r,c));
                        }
                        else
                        {
                            basis.add();
                        }
                    }
                }

                if (at_pyramid_top)
                {
                    at_pyramid_top = false;
                    pyr(images[i], temp_img);
                }
                else
                {
                    pyr(temp_img, temp_img2);
                    swap(temp_img2,temp_img);
                }
            }
        }
        return basis;
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_IMAGE_FEATURE_SaMPLING_Hh_


dlib C++ Library - lda.h

// Copyright (C) 2014  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_LDA_Hh_
#define DLIB_LDA_Hh_

#include "lda_abstract.h"
#include "../algs.h"
#include <map>
#include "../matrix.h"
#include <vector>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    namespace impl
    {

        inline std::map<unsigned long,unsigned long> make_class_labels(
            const std::vector<unsigned long>& row_labels
        )
        {
            std::map<unsigned long,unsigned long> class_labels;
            for (unsigned long i = 0; i < row_labels.size(); ++i)
            {
                const unsigned long next = class_labels.size();
                if (class_labels.count(row_labels[i]) == 0)
                    class_labels[row_labels[i]] = next;
            }
            return class_labels;
        }

    // ------------------------------------------------------------------------------------

        template <
            typename T
            >
        matrix<T,0,1> center_matrix (
            matrix<T>& X
        )
        {
            matrix<T,1> mean;
            for (long r = 0; r < X.nr(); ++r)
                mean += rowm(X,r);
            mean /= X.nr();

            for (long r = 0; r < X.nr(); ++r)
                set_rowm(X,r) -= mean;

            return trans(mean);
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    void compute_lda_transform (
        matrix<T>& X,
        matrix<T,0,1>& mean,
        const std::vector<unsigned long>& row_labels,
        unsigned long lda_dims = 500,
        unsigned long extra_pca_dims = 200
    )
    {
        std::map<unsigned long,unsigned long> class_labels = impl::make_class_labels(row_labels);
        // LDA can only give out at most class_labels.size()-1 dimensions so don't try to
        // compute more than that.
        lda_dims = std::min<unsigned long>(lda_dims, class_labels.size()-1);

        // make sure requires clause is not broken
        DLIB_CASSERT(class_labels.size() > 1,
            "\t void compute_lda_transform()"
            << "\n\t You can't call this function if the number of distinct class labels is less than 2."
            );
        DLIB_CASSERT(X.size() != 0 && (long)row_labels.size() == X.nr() && lda_dims != 0,
            "\t void compute_lda_transform()"
            << "\n\t Invalid inputs were given to this function."
            << "\n\t X.size():          " << X.size()
            << "\n\t row_labels.size(): " << row_labels.size()
            << "\n\t lda_dims:          " << lda_dims
            );

        mean = impl::center_matrix(X);
        // Do PCA to reduce dims
        matrix<T> pu,pw,pv;
        svd_fast(X, pu, pw, pv, lda_dims+extra_pca_dims, 4);
        pu.set_size(0,0); // free RAM, we don't need pu.
        X = X*pv;

        matrix<T> class_means(class_labels.size(), X.nc());
        class_means = 0;
        matrix<T,0,1> class_counts(class_labels.size());
        class_counts = 0;

        // First compute the means of each class
        for (unsigned long i = 0; i < row_labels.size(); ++i)
        {
            const unsigned long class_idx = class_labels[row_labels[i]];
            set_rowm(class_means,class_idx) += rowm(X,i);
            class_counts(class_idx)++;
        }
        class_means = inv(diagm(class_counts))*class_means;
        // subtract means from the data
        for (unsigned long i = 0; i < row_labels.size(); ++i)
        {
            const unsigned long class_idx = class_labels[row_labels[i]];
            set_rowm(X,i) -= rowm(class_means,class_idx);
        }

        // Note that we are using the formulas from the paper Using Discriminant
        // Eigenfeatures for Image Retrieval by Swets and Weng.
        matrix<T> Sw = trans(X)*X;
        matrix<T> Sb = trans(class_means)*class_means;
        matrix<T> A, H;
        matrix<T,0,1> W;
        svd3(Sw, A, W, H);
        W = sqrt(W);
        W = reciprocal(lowerbound(W,max(W)*1e-5));
        A = trans(H*diagm(W))*Sb*H*diagm(W);
        matrix<T> v,s,u;
        svd3(A, v, s, u);
        matrix<T> tform = H*diagm(W)*u;
        // pick out only the number of dimensions we are supposed to for the output, unless
        // we should just keep them all, then don't do anything.
        if ((long)lda_dims <= tform.nc())
        {
            rsort_columns(tform, s);
            tform = colm(tform, range(0, lda_dims-1));
        }

        X = trans(pv*tform);
        mean = X*mean;
    }

// ----------------------------------------------------------------------------------------

    inline std::pair<double,double> equal_error_rate (
        const std::vector<double>& low_vals,
        const std::vector<double>& high_vals
    )
    {
        std::vector<std::pair<double,int> > temp;
        temp.reserve(low_vals.size()+high_vals.size());
        for (unsigned long i = 0; i < low_vals.size(); ++i)
            temp.push_back(std::make_pair(low_vals[i], -1));
        for (unsigned long i = 0; i < high_vals.size(); ++i)
            temp.push_back(std::make_pair(high_vals[i], +1));

        std::sort(temp.begin(), temp.end());

        if (temp.size() == 0)
            return std::make_pair(0,0);

        double thresh = temp[0].first;

        unsigned long num_low_wrong = low_vals.size();
        unsigned long num_high_wrong = 0;
        double low_error = num_low_wrong/(double)low_vals.size();
        double high_error = num_high_wrong/(double)high_vals.size();
        for (unsigned long i = 0; i < temp.size() && high_error < low_error; ++i)
        {
            thresh = temp[i].first;
            if (temp[i].second > 0)
            {
                num_high_wrong++;
                high_error = num_high_wrong/(double)high_vals.size();
            }
            else
            {
                num_low_wrong--;
                low_error = num_low_wrong/(double)low_vals.size();
            }
        }

        return std::make_pair((low_error+high_error)/2, thresh);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_LDA_Hh_


dlib C++ Library - random_subset_selector.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_RANDOM_SUBSeT_SELECTOR_H_
#define DLIB_RANDOM_SUBSeT_SELECTOR_H_

#include "random_subset_selector_abstract.h"
#include "../rand.h"
#include <vector>
#include "../algs.h"
#include "../string.h"
#include "../serialize.h"
#include "../matrix/matrix_mat.h"
#include <iostream>

namespace dlib
{
    template <
        typename T,
        typename Rand_type = dlib::rand
        >
    class random_subset_selector
    {
        /*!
            INITIAL VALUE
                - _max_size == 0
                - items.size() == 0
                - count == 0
                - _next_add_accepts == false

            CONVENTION
                - count == the number of times add() has been called since the last
                  time this object was empty.
                - items.size() == size()
                - max_size() == _max_size
                - next_add_accepts() == _next_add_accepts
        !*/
    public:
        typedef T type;
        typedef T value_type;
        typedef default_memory_manager mem_manager_type;
        typedef Rand_type rand_type;

        typedef typename std::vector<T>::iterator iterator;
        typedef typename std::vector<T>::const_iterator const_iterator;

        random_subset_selector (
        )
        {
            _max_size = 0;
            make_empty();
        }

        void set_seed(const std::string& value)
        {
            rnd.set_seed(value);
        }

        void make_empty (
        )
        {
            items.resize(0);
            count = 0;
            update_next_add_accepts();
        }

        const std::vector<T>& to_std_vector(
        ) const { return items; }

        unsigned long size (
        ) const
        {
            return items.size();
        }

        void set_max_size (
            unsigned long new_max_size
        )
        {
            items.reserve(new_max_size);
            make_empty();
            _max_size = new_max_size;
            update_next_add_accepts();
        }

        unsigned long max_size (
        ) const
        {
            return _max_size;
        }

        T& operator[] (
            unsigned long idx
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(idx < size(),
                "\tvoid random_subset_selector::operator[]()"
                << "\n\t idx is out of range"
                << "\n\t idx:    " << idx
                << "\n\t size(): " << size()
                << "\n\t this:   " << this
                );

            return items[idx];
        }

        const T& operator[] (
            unsigned long idx
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(idx < size(),
                "\tvoid random_subset_selector::operator[]()"
                << "\n\t idx is out of range"
                << "\n\t idx:    " << idx
                << "\n\t size(): " << size()
                << "\n\t this:   " << this
                );

            return items[idx];
        }

        iterator                begin()                         { return items.begin(); }
        const_iterator          begin() const                   { return items.begin(); }
        iterator                end()                           { return items.end(); }
        const_iterator          end() const                     { return items.end(); }

        bool next_add_accepts (
        ) const
        {
            return _next_add_accepts;
        }

        void add (
            const T& new_item
        )
        {
            if (items.size() < _max_size)
            {
                items.push_back(new_item);
                // swap into a random place
                exchange(items[rnd.get_random_32bit_number()%items.size()], items.back());
            }
            else if (_next_add_accepts)
            {
                // pick a random element of items and replace it.
                items[rnd.get_random_32bit_number()%items.size()] = new_item;
            }

            update_next_add_accepts();
            ++count;
        }

        void add (
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(next_add_accepts() == false,
                "\tvoid random_subset_selector::add()"
                << "\n\t You should be calling the version of add() that takes an argument"
                << "\n\t this: " << this
                );

            update_next_add_accepts();
            ++count;
        }

        void swap (
            random_subset_selector& a
        )
        {
            a.swap(a.items);
            std::swap(_max_size, a._max_size);
            std::swap(count, a.count);
            rnd.swap(a.rnd);
            std::swap(_next_add_accepts, a._next_add_accepts);
        }

        template <typename T1, typename T2>
        friend void serialize (
            const random_subset_selector<T1,T2>& item,
            std::ostream& out
        );

        template <typename T1, typename T2>
        friend void deserialize (
            random_subset_selector<T1,T2>& item,
            std::istream& in
        );

    private:

        void update_next_add_accepts (
        )
        {
            if (items.size() < _max_size)
            {
                _next_add_accepts = true;
            }
            else if (_max_size == 0)
            {
                _next_add_accepts = false;
            }
            else
            {
                // At this point each element of items has had an equal chance of being in this object.
                // In particular, the probability that each arrived here is currently items.size()/count.
                // We need to be able to say that, after this function ends, the probability of any
                // particular object ending up in items is items.size()/(count+1).  So this means that
                // we should decide to add a new item into items with this probability.  Also, if we do
                // so then we pick one of the current items and replace it at random with the new item.

                // Make me a random 64 bit number.   This might seem excessive but I want this object
                // to be able to handle an effectively infinite number of calls to add().  So count
                // might get very large and we need to deal with that properly.
                const unsigned long num1 = rnd.get_random_32bit_number();
                const unsigned long num2 = rnd.get_random_32bit_number();
                uint64 num = num1;
                num <<= 32;
                num |= num2;

                num %= (count+1);

                _next_add_accepts = (num < items.size());
            }

        }

        std::vector<T> items;
        unsigned long _max_size;
        uint64 count;

        rand_type rnd;

        bool _next_add_accepts;

    };

    template <
        typename T,
        typename rand_type
        >
    void swap (
        random_subset_selector<T,rand_type>& a,
        random_subset_selector<T,rand_type>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------

    template <typename T1, typename T2>
    void serialize (
        const random_subset_selector<T1,T2>& item,
        std::ostream& out
    )
    {
        serialize(item.items, out);
        serialize(item._max_size, out);
        serialize(item.count, out);
        serialize(item.rnd, out);
        serialize(item._next_add_accepts, out);
    }

    template <typename T1, typename T2>
    void deserialize (
        random_subset_selector<T1,T2>& item,
        std::istream& in
    )
    {
        deserialize(item.items, in);
        deserialize(item._max_size, in);
        deserialize(item.count, in);
        deserialize(item.rnd, in);
        deserialize(item._next_add_accepts, in);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename alloc
        >
    random_subset_selector<T> randomly_subsample (
        const std::vector<T,alloc>& samples,
        unsigned long num
    )
    {
        random_subset_selector<T> subset;
        subset.set_max_size(num);
        for (unsigned long i = 0; i < samples.size(); ++i)
            subset.add(samples[i]);
        return subset;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename alloc,
        typename U
        >
    random_subset_selector<T> randomly_subsample (
        const std::vector<T,alloc>& samples,
        unsigned long num,
        const U& random_seed
    )
    {
        random_subset_selector<T> subset;
        subset.set_seed(cast_to_string(random_seed));
        subset.set_max_size(num);
        for (unsigned long i = 0; i < samples.size(); ++i)
            subset.add(samples[i]);
        return subset;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    random_subset_selector<T> randomly_subsample (
        const random_subset_selector<T>& samples,
        unsigned long num
    )
    {
        random_subset_selector<T> subset;
        subset.set_max_size(num);
        for (unsigned long i = 0; i < samples.size(); ++i)
            subset.add(samples[i]);
        return subset;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename U
        >
    random_subset_selector<T> randomly_subsample (
        const random_subset_selector<T>& samples,
        unsigned long num,
        const U& random_seed
    )
    {
        random_subset_selector<T> subset;
        subset.set_seed(cast_to_string(random_seed));
        subset.set_max_size(num);
        for (unsigned long i = 0; i < samples.size(); ++i)
            subset.add(samples[i]);
        return subset;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    const matrix_op<op_array_to_mat<random_subset_selector<T> > > mat (
        const random_subset_selector<T>& m
    )
    {
        typedef op_array_to_mat<random_subset_selector<T> > op;
        return matrix_op<op>(op(m));
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_RANDOM_SUBSeT_SELECTOR_H_


dlib C++ Library - sammon.h

// Copyright (C) 2012  Emanuele Cesena (emanuele.cesena@gmail.com), Davis E. King
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SAMMoN_Hh_
#define DLIB_SAMMoN_Hh_

#include "sammon_abstract.h"
#include "../matrix.h"
#include "../algs.h"
#include "dpca.h"
#include <vector>

namespace dlib
{

    class sammon_projection
    {

    public:

    // ------------------------------------------------------------------------------------

        template <typename matrix_type>
        std::vector<matrix<double,0,1> > operator() (
            const std::vector<matrix_type>& data,
            const long num_dims
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(num_dims > 0,
                "\t std::vector<matrix<double,0,1> > sammon_projection::operator()"
                << "\n\t Invalid inputs were given to this function."
                << "\n\t num_dims:    " << num_dims
                );
            std::vector<matrix<double,0,1> > result;    // projections
            if (data.size() == 0)
            {
                return result;
            }

#ifdef ENABLE_ASSERTS
            DLIB_ASSERT(0 < num_dims && num_dims <= data[0].size(),
                "\t std::vector<matrix<double,0,1> > sammon_projection::operator()"
                << "\n\t Invalid inputs were given to this function."
                << "\n\t data.size():    " << data.size()
                << "\n\t num_dims:       " << num_dims
                << "\n\t data[0].size(): " << data[0].size()
                );
            for (unsigned long i = 0; i < data.size(); ++i)
            {
                DLIB_ASSERT(is_col_vector(data[i]) && data[i].size() == data[0].size(),
                        "\t std::vector<matrix<double,0,1> > sammon_projection::operator()"
                        << "\n\t Invalid inputs were given to this function."
                        << "\n\t data["<<i<<"].size():    " << data[i].size()
                        << "\n\t data[0].size(): " << data[0].size()
                        << "\n\t is_col_vector(data["<<i<<"]): " << is_col_vector(data[i])
                );
            }
#endif

            double err;                                 // error (discarded)
            do_sammon_projection(data, num_dims, result, err);
            return result;
        }

    // ------------------------------------------------------------------------------------

        template <typename matrix_type>
        void operator() (
            const std::vector<matrix_type>& data,
            const long num_dims,
            std::vector<matrix<double,0,1> >& result,
            double &err,
            const unsigned long num_iters = 1000,
            const double err_delta = 1.0e-9
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(num_dims > 0 && num_iters > 0 && err_delta > 0.0,
                "\t std::vector<matrix<double,0,1> > sammon_projection::operator()"
                << "\n\t Invalid inputs were given to this function."
                << "\n\t data.size(): " << data.size()
                << "\n\t num_dims:    " << num_dims
                << "\n\t num_iters:   " << num_iters
                << "\n\t err_delta:   " << err_delta
                );
            if (data.size() == 0)
            {
                result.clear();
                err = 0;
                return;
            }

#ifdef ENABLE_ASSERTS
            DLIB_ASSERT(0 < num_dims && num_dims <= data[0].size(),
                "\t std::vector<matrix<double,0,1> > sammon_projection::operator()"
                << "\n\t Invalid inputs were given to this function."
                << "\n\t data.size():    " << data.size()
                << "\n\t num_dims:       " << num_dims
                << "\n\t data[0].size(): " << data[0].size()
                );
            for (unsigned long i = 0; i < data.size(); ++i)
            {
                DLIB_ASSERT(is_col_vector(data[i]) && data[i].size() == data[0].size(),
                        "\t std::vector<matrix<double,0,1> > sammon_projection::operator()"
                        << "\n\t Invalid inputs were given to this function."
                        << "\n\t data["<<i<<"].size():    " << data[i].size()
                        << "\n\t data[0].size(): " << data[0].size()
                        << "\n\t is_col_vector(data["<<i<<"]): " << is_col_vector(data[i])
                );
            }
#endif

            do_sammon_projection(data, num_dims, result, err, num_iters, err_delta);
        }

        // ----------------------------------------------------------------------------------------
        // ----------------------------------------------------------------------------------------

    private:

        void compute_relative_distances(
            matrix<double,0,1>& dist,                   // relative distances (output)
            matrix<double,0,0>& data,                   // input data (matrix whose columns are the input vectors)
            double eps_ratio = 1.0e-7                   // to compute the minimum distance eps
        )
        /*!
            requires
                - dist.nc() == comb( data.nc(), 2 ), preallocated
                - eps_ratio > 0
            ensures
                - dist[k] == lenght(data[i] - data[j]) for k = j(j-1)/2 + i
        !*/
        {
            const long N = data.nc();                   // num of points
            double eps;                                 // minimum distance, forced to avoid vectors collision
                                                        // computed at runtime as eps_ration * mean(vectors distances)
            for (int k = 0, i = 1; i < N; ++i)
                for (int j = 0; j < i; ++j)
                    dist(k++) = length(colm(data, i) - colm(data, j));

            eps = eps_ratio * mean(dist);
            dist = lowerbound(dist, eps);
        }

        // ----------------------------------------------------------------------------------------

        template <typename matrix_type>
        void do_sammon_projection(
            const std::vector<matrix_type>& data,       // input data
            unsigned long num_dims,                     // dimension of the reduced space
            std::vector<matrix<double,0,1> >& result,   // projections (output)
            double &err,                                // error (output)
            unsigned long num_iters = 1000,             // max num of iterations: stop condition
            const double err_delta = 1.0e-9             // delta error: stop condition
        )
        /*!
            requires
                - matrix_type should be a kind of dlib::matrix<double,N,1>
                - num_dims > 0
                - num_iters > 0
                - err_delta > 0
            ensures
                - result == a set of matrix<double,num_dims,1> objects that represent
                  the Sammon's projections of data vectors.
                - err == the estimated error done in the projection, with the extra
                  property that err(at previous iteration) - err < err_delta
        !*/
        {
            // other params
            const double mf = 0.3;                      // magic factor

            matrix<double> mdata;                // input data as matrix
            matrix<double> projs;                // projected vectors, i.e. output data as matrix

            // std::vector<matrix> -> matrix
            mdata.set_size(data[0].size(), data.size());
            for (unsigned int i = 0; i < data.size(); i++)
                set_colm(mdata, i) = data[i];

            const long N = mdata.nc();           // num of points
            const long d = num_dims;             // size of the reduced space
            const long nd = N * (N - 1) / 2;     // num of pairs of points = size of the distances vectors

            matrix<double, 0, 1> dsij, inv_dsij; // d*_ij: pair-wise distances in the input space (and inverses)
            dsij.set_size(nd, 1);
            inv_dsij.set_size(nd, 1);
            double ic; // 1.0 / sum of dsij

            matrix<double, 0, 1> dij;            // d_ij: pair-wise distances in the reduced space
            dij.set_size(nd, 1);

            matrix<double, 0, 0> dE, dE2, dtemp; // matrices representing error partial derivatives
            dE.set_size(d, N);
            dE2.set_size(d, N);
            dtemp.set_size(d, N);

            matrix<double, 0, 1> inv_dij, alpha; // utility vectors used to compute the partial derivatives
            inv_dij.set_size(N, 1);              // inv_dij is 1.0/dij, but we only need it column-wise
            alpha.set_size(N, 1);                // (slightly wasting a bit of computation)
            // alpha = 1.0/dij - 1.0/dsij, again column-wise

            // initialize projs with PCA
            discriminant_pca<matrix<double> > dpca;
            for (int i = 0; i < mdata.nc(); ++i)
            {
                dpca.add_to_total_variance(colm(mdata, i));
            }
            matrix<double> mat = dpca.dpca_matrix_of_size(num_dims);
            projs = mat * mdata;

            // compute dsij, inv_dsij and ic
            compute_relative_distances(dsij, mdata);
            inv_dsij = 1.0 / dsij;
            ic = 1.0 / sum(dsij);

            // compute dij and err
            compute_relative_distances(dij, projs);
            err = ic * sum(pointwise_multiply(squared(dij - dsij), inv_dsij));

            // start iterating
            while (num_iters--)
            {
                // compute dE, dE2 progressively column by column
                for (int p = 0; p < N; ++p)
                {
                    // compute
                    // - alpha_p, the column vector with 1/d_pj - 1/d*_pj
                    // - dtemp, the matrix with the p-th column repeated all along
                    //TODO: optimize constructions
                    for (int i = 0; i < N; ++i)
                    {
                        int pos = (i < p) ? p * (p - 1) / 2 + i : i * (i - 1) / 2 + p;
                        inv_dij(i) = (i == p) ? 0.0 : 1.0 / dij(pos);
                        alpha(i) = (i == p) ? 0.0 : inv_dij(i) - inv_dsij(pos);
                        set_colm(dtemp, i) = colm(projs, p);
                    }

                    dtemp -= projs;
                    set_colm(dE, p) = dtemp * alpha;

                    double sum_alpha = sum(alpha);
                    set_colm(dE2, p) = abs( sum_alpha + squared(dtemp) * cubed(inv_dij) );
                }

                // compute the update projections
                projs += pointwise_multiply(dE, mf * reciprocal(dE2));

                // compute new dij and error
                compute_relative_distances(dij, projs);
                double err_new = ic * sum( pointwise_multiply(squared(dij - dsij), inv_dsij) );
                if (err - err_new < err_delta)
                    break;
                err = err_new;
            }

            // matrix -> std::vector<matrix>
            result.clear();
            for (int i = 0; i < projs.nc(); ++i)
                result.push_back(colm(projs, i));
        }

    };

} // namespace dlib

#endif // DLIB_SAMMoN_Hh_


dlib C++ Library - statistics.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net), Steve Taylor
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_STATISTICs_
#define DLIB_STATISTICs_

#include "statistics_abstract.h"
#include <limits>
#include <cmath>
#include "../algs.h"
#include "../matrix.h"
#include "../sparse_vector.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    class running_stats
    {
    public:

        running_stats()
        {
            clear();

            COMPILE_TIME_ASSERT ((
                    is_same_type<float,T>::value ||
                    is_same_type<double,T>::value ||
                    is_same_type<long double,T>::value
            ));
        }

        void clear()
        {
            sum = 0;
            sum_sqr  = 0;
            sum_cub  = 0;
            sum_four = 0;

            n = 0;
            min_value = std::numeric_limits<T>::infinity();
            max_value = -std::numeric_limits<T>::infinity();
        }

        void add (
            const T& val
        )
        {
            sum      += val;
            sum_sqr  += val*val;
            sum_cub  += cubed(val);
            sum_four += quaded(val);

            if (val < min_value)
                min_value = val;
            if (val > max_value)
                max_value = val;

            ++n;
        }

        T current_n (
        ) const
        {
            return n;
        }

        T mean (
        ) const
        {
            if (n != 0)
                return sum/n;
            else
                return 0;
        }

        T max (
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(current_n() > 0,
                "\tT running_stats::max"
                << "\n\tyou have to add some numbers to this object first"
                << "\n\tthis: " << this
                );

            return max_value;
        }

        T min (
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(current_n() > 0,
                "\tT running_stats::min"
                << "\n\tyou have to add some numbers to this object first"
                << "\n\tthis: " << this
                );

            return min_value;
        }

        T variance (
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(current_n() > 1,
                "\tT running_stats::variance"
                << "\n\tyou have to add some numbers to this object first"
                << "\n\tthis: " << this
                );

            T temp = 1/(n-1);
            temp = temp*(sum_sqr - sum*sum/n);
            // make sure the variance is never negative.  This might
            // happen due to numerical errors.
            if (temp >= 0)
                return temp;
            else
                return 0;
        }

        T stddev (
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(current_n() > 1,
                "\tT running_stats::stddev"
                << "\n\tyou have to add some numbers to this object first"
                << "\n\tthis: " << this
                );

            return std::sqrt(variance());
        }

        T skewness (
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(current_n() > 2,
                "\tT running_stats::skewness"
                << "\n\tyou have to add some numbers to this object first"
                << "\n\tthis: " << this
            );

            T temp  = 1/n;
            T temp1 = std::sqrt(n*(n-1))/(n-2);
            temp    = temp1*temp*(sum_cub - 3*sum_sqr*sum*temp + 2*cubed(sum)*temp*temp)/
                      (std::sqrt(std::pow(temp*(sum_sqr-sum*sum*temp),3)));

            return temp;
        }

        T ex_kurtosis (
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(current_n() > 3,
                "\tT running_stats::kurtosis"
                << "\n\tyou have to add some numbers to this object first"
                << "\n\tthis: " << this
            );

            T temp = 1/n;
            T m4   = temp*(sum_four - 4*sum_cub*sum*temp+6*sum_sqr*sum*sum*temp*temp
                     -3*quaded(sum)*cubed(temp));
            T m2   = temp*(sum_sqr-sum*sum*temp);
            temp   = (n-1)*((n+1)*m4/(m2*m2)-3*(n-1))/((n-2)*(n-3));

            return temp;
        }

        T scale (
            const T& val
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(current_n() > 1,
                "\tT running_stats::variance"
                << "\n\tyou have to add some numbers to this object first"
                << "\n\tthis: " << this
                );
            return (val-mean())/std::sqrt(variance());
        }

        running_stats operator+ (
            const running_stats& rhs
        ) const
        {
            running_stats temp(*this);

            temp.sum += rhs.sum;
            temp.sum_sqr += rhs.sum_sqr;
            temp.sum_cub += rhs.sum_cub;
            temp.sum_four += rhs.sum_four;
            temp.n += rhs.n;
            temp.min_value = std::min(rhs.min_value, min_value);
            temp.max_value = std::max(rhs.max_value, max_value);
            return temp;
        }

        template <typename U>
        friend void serialize (
            const running_stats<U>& item,
            std::ostream& out
        );

        template <typename U>
        friend void deserialize (
            running_stats<U>& item,
            std::istream& in
        );

    private:
        T sum;
        T sum_sqr;
        T sum_cub;
        T sum_four;
        T n;
        T min_value;
        T max_value;

        T cubed  (const T& val) const {return val*val*val; }
        T quaded (const T& val) const {return val*val*val*val; }
    };

    template <typename T>
    void serialize (
        const running_stats<T>& item,
        std::ostream& out
    )
    {
        int version = 2;
        serialize(version, out);

        serialize(item.sum, out);
        serialize(item.sum_sqr, out);
        serialize(item.sum_cub, out);
        serialize(item.sum_four, out);
        serialize(item.n, out);
        serialize(item.min_value, out);
        serialize(item.max_value, out);
    }

    template <typename T>
    void deserialize (
        running_stats<T>& item,
        std::istream& in
    )
    {
        int version = 0;
        deserialize(version, in);
        if (version != 2)
            throw dlib::serialization_error("Unexpected version number found while deserializing dlib::running_stats object.");

        deserialize(item.sum, in);
        deserialize(item.sum_sqr, in);
        deserialize(item.sum_cub, in);
        deserialize(item.sum_four, in);
        deserialize(item.n, in);
        deserialize(item.min_value, in);
        deserialize(item.max_value, in);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    class running_scalar_covariance
    {
    public:

        running_scalar_covariance()
        {
            clear();

            COMPILE_TIME_ASSERT ((
                    is_same_type<float,T>::value ||
                    is_same_type<double,T>::value ||
                    is_same_type<long double,T>::value
            ));
        }

        void clear()
        {
            sum_xy = 0;
            sum_x = 0;
            sum_y = 0;
            sum_xx = 0;
            sum_yy = 0;
            n = 0;
        }

        void add (
            const T& x,
            const T& y
        )
        {
            sum_xy += x*y;

            sum_xx += x*x;
            sum_yy += y*y;

            sum_x  += x;
            sum_y  += y;

            n += 1;
        }

        T current_n (
        ) const
        {
            return n;
        }

        T mean_x (
        ) const
        {
            if (n != 0)
                return sum_x/n;
            else
                return 0;
        }

        T mean_y (
        ) const
        {
            if (n != 0)
                return sum_y/n;
            else
                return 0;
        }

        T covariance (
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(current_n() > 1,
                "\tT running_scalar_covariance::covariance()"
                << "\n\tyou have to add some numbers to this object first"
                << "\n\tthis: " << this
                );

            return 1/(n-1) * (sum_xy - sum_y*sum_x/n);
        }

        T correlation (
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(current_n() > 1,
                "\tT running_scalar_covariance::correlation()"
                << "\n\tyou have to add some numbers to this object first"
                << "\n\tthis: " << this
                );

            return covariance() / std::sqrt(variance_x()*variance_y());
        }

        T variance_x (
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(current_n() > 1,
                "\tT running_scalar_covariance::variance_x()"
                << "\n\tyou have to add some numbers to this object first"
                << "\n\tthis: " << this
                );

            T temp = 1/(n-1) * (sum_xx - sum_x*sum_x/n);
            // make sure the variance is never negative.  This might
            // happen due to numerical errors.
            if (temp >= 0)
                return temp;
            else
                return 0;
        }

        T variance_y (
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(current_n() > 1,
                "\tT running_scalar_covariance::variance_y()"
                << "\n\tyou have to add some numbers to this object first"
                << "\n\tthis: " << this
                );

            T temp = 1/(n-1) * (sum_yy - sum_y*sum_y/n);
            // make sure the variance is never negative.  This might
            // happen due to numerical errors.
            if (temp >= 0)
                return temp;
            else
                return 0;
        }

        T stddev_x (
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(current_n() > 1,
                "\tT running_scalar_covariance::stddev_x()"
                << "\n\tyou have to add some numbers to this object first"
                << "\n\tthis: " << this
                );

            return std::sqrt(variance_x());
        }

        T stddev_y (
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(current_n() > 1,
                "\tT running_scalar_covariance::stddev_y()"
                << "\n\tyou have to add some numbers to this object first"
                << "\n\tthis: " << this
                );

            return std::sqrt(variance_y());
        }

        running_scalar_covariance operator+ (
            const running_scalar_covariance& rhs
        ) const
        {
            running_scalar_covariance temp(rhs);

            temp.sum_xy += sum_xy;
            temp.sum_x  += sum_x;
            temp.sum_y  += sum_y;
            temp.sum_xx += sum_xx;
            temp.sum_yy += sum_yy;
            temp.n      += n;
            return temp;
        }

    private:

        T sum_xy;
        T sum_x;
        T sum_y;
        T sum_xx;
        T sum_yy;
        T n;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename alloc
        >
    double mean_sign_agreement (
        const std::vector<T,alloc>& a,
        const std::vector<T,alloc>& b
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(a.size() == b.size(),
                    "\t double mean_sign_agreement(a,b)"
                    << "\n\t a and b must be the same length."
                    << "\n\t a.size(): " << a.size()
                    << "\n\t b.size(): " << b.size()
        );

        double temp = 0;
        for (unsigned long i = 0; i < a.size(); ++i)
        {
            if ((a[i] >= 0 && b[i] >= 0) ||
                (a[i] < 0  && b[i] <  0))
            {
                temp += 1;
            }
        }

        return temp/a.size();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename alloc
        >
    double correlation (
        const std::vector<T,alloc>& a,
        const std::vector<T,alloc>& b
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(a.size() == b.size() && a.size() > 1,
                    "\t double correlation(a,b)"
                    << "\n\t a and b must be the same length and have more than one element."
                    << "\n\t a.size(): " << a.size()
                    << "\n\t b.size(): " << b.size()
        );

        running_scalar_covariance<double> rs;
        for (unsigned long i = 0; i < a.size(); ++i)
        {
            rs.add(a[i], b[i]);
        }
        return rs.correlation();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename alloc
        >
    double covariance (
        const std::vector<T,alloc>& a,
        const std::vector<T,alloc>& b
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(a.size() == b.size() && a.size() > 1,
                    "\t double covariance(a,b)"
                    << "\n\t a and b must be the same length and have more than one element."
                    << "\n\t a.size(): " << a.size()
                    << "\n\t b.size(): " << b.size()
        );

        running_scalar_covariance<double> rs;
        for (unsigned long i = 0; i < a.size(); ++i)
        {
            rs.add(a[i], b[i]);
        }
        return rs.covariance();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename alloc
        >
    double r_squared (
        const std::vector<T,alloc>& a,
        const std::vector<T,alloc>& b
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(a.size() == b.size() && a.size() > 1,
                    "\t double r_squared(a,b)"
                    << "\n\t a and b must be the same length and have more than one element."
                    << "\n\t a.size(): " << a.size()
                    << "\n\t b.size(): " << b.size()
        );

        return std::pow(correlation(a,b),2.0);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename alloc
        >
    double mean_squared_error (
        const std::vector<T,alloc>& a,
        const std::vector<T,alloc>& b
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(a.size() == b.size(),
                    "\t double mean_squared_error(a,b)"
                    << "\n\t a and b must be the same length."
                    << "\n\t a.size(): " << a.size()
                    << "\n\t b.size(): " << b.size()
        );

        return mean(squared(matrix_cast<double>(mat(a))-matrix_cast<double>(mat(b))));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_type
        >
    class running_covariance
    {
        /*!
            INITIAL VALUE
                - vect_size == 0
                - total_count == 0

            CONVENTION
                - vect_size == in_vector_size()
                - total_count == current_n()

                - if (total_count != 0)
                    - total_sum == the sum of all vectors given to add()
                    - the covariance of all the elements given to add() is given
                      by:
                        - let avg == total_sum/total_count
                        - covariance == total_cov/total_count - avg*trans(avg)
        !*/
    public:

        typedef typename matrix_type::mem_manager_type mem_manager_type;
        typedef typename matrix_type::type scalar_type;
        typedef typename matrix_type::layout_type layout_type;
        typedef matrix<scalar_type,0,0,mem_manager_type,layout_type> general_matrix;
        typedef matrix<scalar_type,0,1,mem_manager_type,layout_type> column_matrix;

        running_covariance(
        )
        {
            clear();
        }

        void clear(
        )
        {
            total_count = 0;

            vect_size = 0;

            total_sum.set_size(0);
            total_cov.set_size(0,0);
        }

        long in_vector_size (
        ) const
        {
            return vect_size;
        }

        long current_n (
        ) const
        {
            return static_cast<long>(total_count);
        }

        void set_dimension (
            long size
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT( size > 0,
                "\t void running_covariance::set_dimension()"
                << "\n\t Invalid inputs were given to this function"
                << "\n\t size: " << size
                << "\n\t this: " << this
                );

            clear();
            vect_size = size;
            total_sum.set_size(size);
            total_cov.set_size(size,size);
            total_sum = 0;
            total_cov = 0;
        }

        template <typename T>
        typename disable_if<is_matrix<T> >::type add (
            const T& val
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(((long)max_index_plus_one(val) <= in_vector_size() && in_vector_size() > 0),
                "\t void running_covariance::add()"
                << "\n\t Invalid inputs were given to this function"
                << "\n\t max_index_plus_one(val): " << max_index_plus_one(val)
                << "\n\t in_vector_size():        " << in_vector_size()
                << "\n\t this:                    " << this
                );

            for (typename T::const_iterator i = val.begin(); i != val.end(); ++i)
            {
                total_sum(i->first) += i->second;
                for (typename T::const_iterator j = val.begin(); j != val.end(); ++j)
                {
                    total_cov(i->first, j->first) += i->second*j->second;
                }
            }

            ++total_count;
        }

        template <typename T>
        typename enable_if<is_matrix<T> >::type add (
            const T& val
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(is_col_vector(val) && (in_vector_size() == 0 || val.size() == in_vector_size()),
                "\t void running_covariance::add()"
                << "\n\t Invalid inputs were given to this function"
                << "\n\t is_col_vector(val): " << is_col_vector(val)
                << "\n\t in_vector_size():   " << in_vector_size()
                << "\n\t val.size():         " << val.size()
                << "\n\t this:               " << this
                );

            vect_size = val.size();
            if (total_count == 0)
            {
                total_cov = val*trans(val);
                total_sum = val;
            }
            else
            {
                total_cov += val*trans(val);
                total_sum += val;
            }
            ++total_count;
        }

        const column_matrix mean (
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT( in_vector_size() != 0,
                "\t running_covariance::mean()"
                << "\n\t This object can not execute this function in its current state."
                << "\n\t in_vector_size(): " << in_vector_size()
                << "\n\t current_n():      " << current_n()
                << "\n\t this:             " << this
                );

            return total_sum/total_count;
        }

        const general_matrix covariance (
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT( in_vector_size() != 0 && current_n() > 1,
                "\t running_covariance::covariance()"
                << "\n\t This object can not execute this function in its current state."
                << "\n\t in_vector_size(): " << in_vector_size()
                << "\n\t current_n():      " << current_n()
                << "\n\t this:             " << this
                );

            return (total_cov - total_sum*trans(total_sum)/total_count)/(total_count-1);
        }

        const running_covariance operator+ (
            const running_covariance& item
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT((in_vector_size() == 0 || item.in_vector_size() == 0 || in_vector_size() == item.in_vector_size()),
                "\t running_covariance running_covariance::operator+()"
                << "\n\t The two running_covariance objects being added must have compatible parameters"
                << "\n\t in_vector_size():            " << in_vector_size()
                << "\n\t item.in_vector_size():       " << item.in_vector_size()
                << "\n\t this:                        " << this
                );

            running_covariance temp(item);

            // make sure we ignore empty matrices
            if (total_count != 0 && temp.total_count != 0)
            {
                temp.total_cov += total_cov;
                temp.total_sum += total_sum;
                temp.total_count += total_count;
            }
            else if (total_count != 0)
            {
                temp.total_cov = total_cov;
                temp.total_sum = total_sum;
                temp.total_count = total_count;
            }

            return temp;
        }

    private:

        general_matrix total_cov;
        column_matrix total_sum;
        scalar_type total_count;

        long vect_size;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_type
        >
    class running_cross_covariance
    {
        /*!
            INITIAL VALUE
                - x_vect_size == 0
                - y_vect_size == 0
                - total_count == 0

            CONVENTION
                - x_vect_size == x_vector_size()
                - y_vect_size == y_vector_size()
                - total_count == current_n()

                - if (total_count != 0)
                    - sum_x == the sum of all x vectors given to add()
                    - sum_y == the sum of all y vectors given to add()
                    - total_cov == sum of all x*trans(y) given to add()
        !*/

    public:

        typedef typename matrix_type::mem_manager_type mem_manager_type;
        typedef typename matrix_type::type scalar_type;
        typedef typename matrix_type::layout_type layout_type;
        typedef matrix<scalar_type,0,0,mem_manager_type,layout_type> general_matrix;
        typedef matrix<scalar_type,0,1,mem_manager_type,layout_type> column_matrix;

        running_cross_covariance(
        )
        {
            clear();
        }

        void clear(
        )
        {
            total_count = 0;

            x_vect_size = 0;
            y_vect_size = 0;

            sum_x.set_size(0);
            sum_y.set_size(0);
            total_cov.set_size(0,0);
        }

        long x_vector_size (
        ) const
        {
            return x_vect_size;
        }

        long y_vector_size (
        ) const
        {
            return y_vect_size;
        }

        void set_dimensions (
            long x_size,
            long y_size
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT( x_size > 0 && y_size > 0,
                "\t void running_cross_covariance::set_dimensions()"
                << "\n\t Invalid inputs were given to this function"
                << "\n\t x_size: " << x_size
                << "\n\t y_size: " << y_size
                << "\n\t this:   " << this
                );

            clear();
            x_vect_size = x_size;
            y_vect_size = y_size;
            sum_x.set_size(x_size);
            sum_y.set_size(y_size);
            total_cov.set_size(x_size,y_size);

            sum_x = 0;
            sum_y = 0;
            total_cov = 0;
        }

        long current_n (
        ) const
        {
            return static_cast<long>(total_count);
        }

        template <typename T, typename U>
        typename enable_if_c<!is_matrix<T>::value && !is_matrix<U>::value>::type add (
            const T& x,
            const U& y
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT( ((long)max_index_plus_one(x) <= x_vector_size() && x_vector_size() > 0) &&
                         ((long)max_index_plus_one(y) <= y_vector_size() && y_vector_size() > 0) ,
                "\t void running_cross_covariance::add()"
                << "\n\t Invalid inputs were given to this function"
                << "\n\t max_index_plus_one(x): " << max_index_plus_one(x)
                << "\n\t max_index_plus_one(y): " << max_index_plus_one(y)
                << "\n\t x_vector_size():       " << x_vector_size()
                << "\n\t y_vector_size():       " << y_vector_size()
                << "\n\t this:                  " << this
                );

            for (typename T::const_iterator i = x.begin(); i != x.end(); ++i)
            {
                sum_x(i->first) += i->second;
                for (typename U::const_iterator j = y.begin(); j != y.end(); ++j)
                {
                    total_cov(i->first, j->first) += i->second*j->second;
                }
            }

            // do sum_y += y
            for (typename U::const_iterator j = y.begin(); j != y.end(); ++j)
            {
                sum_y(j->first) += j->second;
            }

            ++total_count;
        }

        template <typename T, typename U>
        typename enable_if_c<is_matrix<T>::value && !is_matrix<U>::value>::type add (
            const T& x,
            const U& y
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT( (is_col_vector(x) && x.size() == x_vector_size() && x_vector_size() > 0) &&
                         ((long)max_index_plus_one(y) <= y_vector_size() && y_vector_size() > 0) ,
                "\t void running_cross_covariance::add()"
                << "\n\t Invalid inputs were given to this function"
                << "\n\t is_col_vector(x):      " << is_col_vector(x)
                << "\n\t x.size():              " << x.size()
                << "\n\t max_index_plus_one(y): " << max_index_plus_one(y)
                << "\n\t x_vector_size():       " << x_vector_size()
                << "\n\t y_vector_size():       " << y_vector_size()
                << "\n\t this:                  " << this
                );

            sum_x += x;

            for (long i = 0; i < x.size(); ++i)
            {
                for (typename U::const_iterator j = y.begin(); j != y.end(); ++j)
                {
                    total_cov(i, j->first) += x(i)*j->second;
                }
            }

            // do sum_y += y
            for (typename U::const_iterator j = y.begin(); j != y.end(); ++j)
            {
                sum_y(j->first) += j->second;
            }

            ++total_count;
        }

        template <typename T, typename U>
        typename enable_if_c<!is_matrix<T>::value && is_matrix<U>::value>::type add (
            const T& x,
            const U& y
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT( ((long)max_index_plus_one(x) <= x_vector_size() && x_vector_size() > 0) &&
                         (is_col_vector(y) && y.size() == (long)y_vector_size() && y_vector_size() > 0) ,
                "\t void running_cross_covariance::add()"
                << "\n\t Invalid inputs were given to this function"
                << "\n\t max_index_plus_one(x): " << max_index_plus_one(x)
                << "\n\t is_col_vector(y):      " << is_col_vector(y)
                << "\n\t y.size():              " << y.size()
                << "\n\t x_vector_size():       " << x_vector_size()
                << "\n\t y_vector_size():       " << y_vector_size()
                << "\n\t this:                  " << this
                );

            for (typename T::const_iterator i = x.begin(); i != x.end(); ++i)
            {
                sum_x(i->first) += i->second;
                for (long j = 0; j < y.size(); ++j)
                {
                    total_cov(i->first, j) += i->second*y(j);
                }
            }

            sum_y += y;

            ++total_count;
        }

        template <typename T, typename U>
        typename enable_if_c<is_matrix<T>::value && is_matrix<U>::value>::type add (
            const T& x,
            const U& y
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(is_col_vector(x) && (x_vector_size() == 0 || x.size() == x_vector_size()) &&
                        is_col_vector(y) && (y_vector_size() == 0 || y.size() == y_vector_size()) &&
                        x.size() != 0 &&
                        y.size() != 0,
                "\t void running_cross_covariance::add()"
                << "\n\t Invalid inputs were given to this function"
                << "\n\t is_col_vector(x): " << is_col_vector(x)
                << "\n\t x_vector_size():  " << x_vector_size()
                << "\n\t x.size():         " << x.size()
                << "\n\t is_col_vector(y): " << is_col_vector(y)
                << "\n\t y_vector_size():  " << y_vector_size()
                << "\n\t y.size():         " << y.size()
                << "\n\t this:             " << this
                );

            x_vect_size = x.size();
            y_vect_size = y.size();
            if (total_count == 0)
            {
                total_cov = x*trans(y);
                sum_x = x;
                sum_y = y;
            }
            else
            {
                total_cov += x*trans(y);
                sum_x += x;
                sum_y += y;
            }
            ++total_count;
        }

        const column_matrix mean_x (
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT( current_n() != 0,
                "\t running_cross_covariance::mean()"
                << "\n\t This object can not execute this function in its current state."
                << "\n\t current_n():      " << current_n()
                << "\n\t this:             " << this
                );

            return sum_x/total_count;
        }

        const column_matrix mean_y (
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT( current_n() != 0,
                "\t running_cross_covariance::mean()"
                << "\n\t This object can not execute this function in its current state."
                << "\n\t current_n():      " << current_n()
                << "\n\t this:             " << this
                );

            return sum_y/total_count;
        }

        const general_matrix covariance_xy (
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT( current_n() > 1,
                "\t running_cross_covariance::covariance()"
                << "\n\t This object can not execute this function in its current state."
                << "\n\t x_vector_size(): " << x_vector_size()
                << "\n\t y_vector_size(): " << y_vector_size()
                << "\n\t current_n():     " << current_n()
                << "\n\t this:            " << this
                );

            return (total_cov - sum_x*trans(sum_y)/total_count)/(total_count-1);
        }

        const running_cross_covariance operator+ (
            const running_cross_covariance& item
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT((x_vector_size() == 0 || item.x_vector_size() == 0 || x_vector_size() == item.x_vector_size()) &&
                        (y_vector_size() == 0 || item.y_vector_size() == 0 || y_vector_size() == item.y_vector_size()),
                "\t running_cross_covariance running_cross_covariance::operator+()"
                << "\n\t The two running_cross_covariance objects being added must have compatible parameters"
                << "\n\t x_vector_size():            " << x_vector_size()
                << "\n\t item.x_vector_size():       " << item.x_vector_size()
                << "\n\t y_vector_size():            " << y_vector_size()
                << "\n\t item.y_vector_size():       " << item.y_vector_size()
                << "\n\t this:                       " << this
                );

            running_cross_covariance temp(item);

            // make sure we ignore empty matrices
            if (total_count != 0 && temp.total_count != 0)
            {
                temp.total_cov += total_cov;
                temp.sum_x += sum_x;
                temp.sum_y += sum_y;
                temp.total_count += total_count;
            }
            else if (total_count != 0)
            {
                temp.total_cov = total_cov;
                temp.sum_x = sum_x;
                temp.sum_y = sum_y;
                temp.total_count = total_count;
            }

            return temp;
        }

    private:

        general_matrix total_cov;
        column_matrix sum_x;
        column_matrix sum_y;
        scalar_type total_count;

        long x_vect_size;
        long y_vect_size;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_type
        >
    class vector_normalizer
    {
    public:
        typedef typename matrix_type::mem_manager_type mem_manager_type;
        typedef typename matrix_type::type scalar_type;
        typedef matrix_type result_type;

        template <typename vector_type>
        void train (
            const vector_type& samples
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(samples.size() > 0,
                "\tvoid vector_normalizer::train()"
                << "\n\tyou have to give a nonempty set of samples to this function"
                << "\n\tthis: " << this
                );

            m = mean(mat(samples));
            sd = reciprocal(sqrt(variance(mat(samples))));

            DLIB_ASSERT(is_finite(m), "Some of the input vectors to vector_normalizer::train() have infinite or NaN values");
        }

        long in_vector_size (
        ) const
        {
            return m.nr();
        }

        long out_vector_size (
        ) const
        {
            return m.nr();
        }

        const matrix_type& means (
        ) const
        {
            return m;
        }

        const matrix_type& std_devs (
        ) const
        {
            return sd;
        }

        const result_type& operator() (
            const matrix_type& x
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(x.nr() == in_vector_size() && x.nc() == 1,
                "\tmatrix vector_normalizer::operator()"
                << "\n\t you have given invalid arguments to this function"
                << "\n\t x.nr():           " << x.nr()
                << "\n\t in_vector_size(): " << in_vector_size()
                << "\n\t x.nc():           " << x.nc()
                << "\n\t this:             " << this
                );

            temp_out = pointwise_multiply(x-m, sd);
            return temp_out;
        }

        void swap (
            vector_normalizer& item
        )
        {
            m.swap(item.m);
            sd.swap(item.sd);
            temp_out.swap(item.temp_out);
        }

        template <typename mt>
        friend void deserialize (
            vector_normalizer<mt>& item,
            std::istream& in
        );

        template <typename mt>
        friend void serialize (
            const vector_normalizer<mt>& item,
            std::ostream& out
        );

    private:

        // ------------------- private data members -------------------

        matrix_type m, sd;

        // This is just a temporary variable that doesn't contribute to the
        // state of this object.
        mutable matrix_type temp_out;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_type
        >
    inline void swap (
        vector_normalizer<matrix_type>& a,
        vector_normalizer<matrix_type>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_type
        >
    void deserialize (
        vector_normalizer<matrix_type>& item,
        std::istream& in
    )
    {
        deserialize(item.m, in);
        deserialize(item.sd, in);
        // Keep deserializing the pca matrix for backwards compatibility.
        matrix<double> pca;
        deserialize(pca, in);

        if (pca.size() != 0)
            throw serialization_error("Error deserializing object of type vector_normalizer\n"
                                        "It looks like a serialized vector_normalizer_pca was accidentally deserialized into \n"
                                        "a vector_normalizer object.");
    }

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_type
        >
    void serialize (
        const vector_normalizer<matrix_type>& item,
        std::ostream& out
    )
    {
        serialize(item.m, out);
        serialize(item.sd, out);
        // Keep serializing the pca matrix for backwards compatibility.
        matrix<double> pca;
        serialize(pca, out);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename matrix_type
        >
    class vector_normalizer_pca
    {
    public:
        typedef typename matrix_type::mem_manager_type mem_manager_type;
        typedef typename matrix_type::type scalar_type;
        typedef matrix<scalar_type,0,1,mem_manager_type> result_type;

        template <typename vector_type>
        void train (
            const vector_type& samples,
            const double eps = 0.99
        )
        {
            // You are getting an error here because you are trying to apply PCA
            // to a vector of fixed length.  But PCA is going to try and do
            // dimensionality reduction so you can't use a vector with a fixed dimension.
            COMPILE_TIME_ASSERT(matrix_type::NR == 0);

            // make sure requires clause is not broken
            DLIB_ASSERT(samples.size() > 0,
                "\tvoid vector_normalizer_pca::train_pca()"
                << "\n\tyou have to give a nonempty set of samples to this function"
                << "\n\tthis: " << this
                );
            DLIB_ASSERT(0 < eps && eps <= 1,
                "\tvoid vector_normalizer_pca::train_pca()"
                << "\n\tyou have to give a nonempty set of samples to this function"
                << "\n\tthis: " << this
                );
            train_pca_impl(mat(samples),eps);

            DLIB_ASSERT(is_finite(m), "Some of the input vectors to vector_normalizer_pca::train() have infinite or NaN values");
        }

        long in_vector_size (
        ) const
        {
            return m.nr();
        }

        long out_vector_size (
        ) const
        {
            return pca.nr();
        }

        const matrix<scalar_type,0,1,mem_manager_type>& means (
        ) const
        {
            return m;
        }

        const matrix<scalar_type,0,1,mem_manager_type>& std_devs (
        ) const
        {
            return sd;
        }

        const matrix<scalar_type,0,0,mem_manager_type>& pca_matrix (
        ) const
        {
            return pca;
        }

        const result_type& operator() (
            const matrix_type& x
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(x.nr() == in_vector_size() && x.nc() == 1,
                "\tmatrix vector_normalizer_pca::operator()"
                << "\n\t you have given invalid arguments to this function"
                << "\n\t x.nr():           " << x.nr()
                << "\n\t in_vector_size(): " << in_vector_size()
                << "\n\t x.nc():           " << x.nc()
                << "\n\t this:             " << this
                );

            // If we have a pca transform matrix on hand then
            // also apply that.
            temp_out = pca*pointwise_multiply(x-m, sd);

            return temp_out;
        }

        void swap (
            vector_normalizer_pca& item
        )
        {
            m.swap(item.m);
            sd.swap(item.sd);
            pca.swap(item.pca);
            temp_out.swap(item.temp_out);
        }

        template <typename T>
        friend void deserialize (
            vector_normalizer_pca<T>& item,
            std::istream& in
        );

        template <typename T>
        friend void serialize (
            const vector_normalizer_pca<T>& item,
            std::ostream& out
        );

    private:

        template <typename mat_type>
        void train_pca_impl (
            const mat_type& samples,
            const double eps
        )
        {
            m = mean(samples);
            sd = reciprocal(sqrt(variance(samples)));

            // fill x with the normalized version of the input samples
            matrix<typename mat_type::type,0,1,mem_manager_type> x(samples);
            for (long r = 0; r < x.size(); ++r)
                x(r) = pointwise_multiply(x(r)-m, sd);

            matrix<scalar_type,0,0,mem_manager_type> temp, eigen;
            matrix<scalar_type,0,1,mem_manager_type> eigenvalues;

            // Compute the svd of the covariance matrix of the normalized inputs
            svd(covariance(x), temp, eigen, pca);
            eigenvalues = diag(eigen);

            rsort_columns(pca, eigenvalues);

            // figure out how many eigenvectors we want in our pca matrix
            const double thresh = sum(eigenvalues)*eps;
            long num_vectors = 0;
            double total = 0;
            for (long r = 0; r < eigenvalues.size() && total < thresh; ++r)
            {
                ++num_vectors;
                total += eigenvalues(r);
            }

            // So now we know we want to use num_vectors of the first eigenvectors.  So
            // pull those out and discard the rest.
            pca = trans(colm(pca,range(0,num_vectors-1)));

            // Apply the pca transform to the data in x.  Then we will normalize the
            // pca matrix below.
            for (long r = 0; r < x.nr(); ++r)
            {
                x(r) = pca*x(r);
            }

            // Here we just scale the output features from the pca transform so
            // that the variance of each feature is 1.  So this doesn't really change
            // what the pca is doing, it just makes sure the output features are
            // normalized.
            pca = trans(scale_columns(trans(pca), reciprocal(sqrt(variance(x)))));
        }

        // ------------------- private data members -------------------

        matrix<scalar_type,0,1,mem_manager_type> m, sd;
        matrix<scalar_type,0,0,mem_manager_type> pca;

        // This is just a temporary variable that doesn't contribute to the
        // state of this object.
        mutable result_type temp_out;
    };

    template <
        typename matrix_type
        >
    inline void swap (
        vector_normalizer_pca<matrix_type>& a,
        vector_normalizer_pca<matrix_type>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_type
        >
    void deserialize (
        vector_normalizer_pca<matrix_type>& item,
        std::istream& in
    )
    {
        deserialize(item.m, in);
        deserialize(item.sd, in);
        deserialize(item.pca, in);
        if (item.pca.nc() != item.m.nr())
            throw serialization_error("Error deserializing object of type vector_normalizer_pca\n"
                                        "It looks like a serialized vector_normalizer was accidentally deserialized into \n"
                                        "a vector_normalizer_pca object.");
    }

    template <
        typename matrix_type
        >
    void serialize (
        const vector_normalizer_pca<matrix_type>& item,
        std::ostream& out
    )
    {
        serialize(item.m, out);
        serialize(item.sd, out);
        serialize(item.pca, out);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_STATISTICs_


dlib C++ Library - vector_normalizer_frobmetric.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_VECTOR_NORMALIZER_FRoBMETRIC_Hh_
#define DLIB_VECTOR_NORMALIZER_FRoBMETRIC_Hh_

#include "vector_normalizer_frobmetric_abstract.h"
#include "../matrix.h"
#include "../optimization.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_type
        >
    struct frobmetric_training_sample
    {
        matrix_type anchor_vect;
        std::vector<matrix_type> near_vects;
        std::vector<matrix_type> far_vects;

        unsigned long num_triples (
        ) const { return near_vects.size() * far_vects.size(); }

        void clear()
        {
            near_vects.clear();
            far_vects.clear();
        }
    };

    template <
        typename matrix_type
        >
    void serialize(const frobmetric_training_sample<matrix_type>& item, std::ostream& out)
    {
        int version = 1;
        serialize(version, out);
        serialize(item.anchor_vect, out);
        serialize(item.near_vects, out);
        serialize(item.far_vects, out);
    }

    template <
        typename matrix_type
        >
    void deserialize(frobmetric_training_sample<matrix_type>& item, std::istream& in)
    {
        int version = 0;
        deserialize(version, in);
        if (version != 1)
            throw serialization_error("Unexpected version found while deserializing dlib::frobmetric_training_sample.");
        deserialize(item.anchor_vect, in);
        deserialize(item.near_vects, in);
        deserialize(item.far_vects, in);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_type
        >
    class vector_normalizer_frobmetric
    {

    public:
        typedef typename matrix_type::mem_manager_type mem_manager_type;
        typedef typename matrix_type::type scalar_type;
        typedef matrix_type result_type;

    private:
        struct compact_frobmetric_training_sample
        {
            std::vector<matrix_type> near_vects;
            std::vector<matrix_type> far_vects;
        };

        struct objective
        {
            objective (
                const std::vector<compact_frobmetric_training_sample>& samples_,
                matrix<double,0,0,mem_manager_type>& Aminus_,
                const matrix<double,0,1,mem_manager_type>& bias_
            ) : samples(samples_), Aminus(Aminus_), bias(bias_) {}

            double operator()(const matrix<double,0,1,mem_manager_type>& u) const
            {
                long idx = 0;
                const long dims = samples[0].far_vects[0].size();
                // Here we compute \hat A from the paper, which we refer to as just A in
                // the code.
                matrix<double,0,0,mem_manager_type> A(dims,dims);
                A = 0;
                std::vector<double> ufar, unear;
                for (unsigned long i = 0; i < samples.size(); ++i)
                {
                    ufar.assign(samples[i].far_vects.size(),0);
                    unear.assign(samples[i].near_vects.size(),0);
                    for (unsigned long j = 0; j < unear.size(); ++j)
                    {
                        for (unsigned long k = 0; k < ufar.size(); ++k)
                        {
                            const double val = u(idx++);
                            ufar[k] -= val;
                            unear[j] += val;
                        }
                    }
                    for (unsigned long j = 0; j < unear.size(); ++j)
                        A += unear[j]*samples[i].near_vects[j]*trans(samples[i].near_vects[j]);
                    for (unsigned long j = 0; j < ufar.size(); ++j)
                        A += ufar[j]*samples[i].far_vects[j]*trans(samples[i].far_vects[j]);
                }

                eigenvalue_decomposition<matrix<double,0,0,mem_manager_type> > ed(make_symmetric(A));
                Aminus = ed.get_pseudo_v()*diagm(upperbound(ed.get_real_eigenvalues(),0))*trans(ed.get_pseudo_v());
                // Do this to avoid numeric instability later on since the above
                // computation can make Aminus slightly non-symmetric.
                Aminus = make_symmetric(Aminus);

                return dot(u,bias) - 0.5*sum(squared(Aminus));
            }

        private:
            const std::vector<compact_frobmetric_training_sample>& samples;
            matrix<double,0,0,mem_manager_type>& Aminus;
            const matrix<double,0,1,mem_manager_type>& bias;
        };

        struct derivative
        {
            derivative (
                unsigned long num_triples_,
                const std::vector<compact_frobmetric_training_sample>& samples_,
                matrix<double,0,0,mem_manager_type>& Aminus_,
                const matrix<double,0,1,mem_manager_type>& bias_
            ) : num_triples(num_triples_), samples(samples_), Aminus(Aminus_), bias(bias_) {}

            matrix<double,0,1,mem_manager_type> operator()(const matrix<double,0,1,mem_manager_type>& ) const
            {
                // Note that Aminus is a function of u (the argument to this function), but
                // since Aminus will have been computed already by the most recent call to
                // the objective function we don't need to do anything with u.  We can just
                // use Aminus right away.
                matrix<double,0,1,mem_manager_type> grad(num_triples);

                long idx = 0;
                std::vector<double> ufar, unear;
                for (unsigned long i = 0; i < samples.size(); ++i)
                {
                    ufar.resize(samples[i].far_vects.size());
                    unear.resize(samples[i].near_vects.size());

                    for (unsigned long j = 0; j < unear.size(); ++j)
                        unear[j] = sum(pointwise_multiply(Aminus, samples[i].near_vects[j]*trans(samples[i].near_vects[j])));
                    for (unsigned long j = 0; j < ufar.size(); ++j)
                        ufar[j] = sum(pointwise_multiply(Aminus, samples[i].far_vects[j]*trans(samples[i].far_vects[j])));

                    for (unsigned long j = 0; j < samples[i].near_vects.size(); ++j)
                    {
                        for (unsigned long k = 0; k < samples[i].far_vects.size(); ++k)
                        {
                            grad(idx) = bias(idx) + ufar[k]-unear[j];
                            idx++;
                        }
                    }
                }

                return grad;
            }

        private:
            const unsigned long num_triples;
            const std::vector<compact_frobmetric_training_sample>& samples;
            matrix<double,0,0,mem_manager_type>& Aminus;
            const matrix<double,0,1,mem_manager_type>& bias;
        };

        class custom_stop_strategy
        {
        public:
            custom_stop_strategy(
                double C_,
                double eps_,
                bool be_verbose_,
                unsigned long max_iter_
            )
            {
                _c = C_;

                _cur_iter = 0;
                _gradient_thresh = eps_;
                _max_iter = max_iter_;
                _verbose = be_verbose_;
            }

            template <typename T>
            bool should_continue_search (
                const T& u,
                const double ,
                const T& grad
            )
            {
                ++_cur_iter;

                double max_gradient = 0;
                for (long i = 0; i < grad.size(); ++i)
                {
                    const bool at_lower_bound = (0 >= u(i) && grad(i) > 0);
                    const bool at_upper_bound = (_c/grad.size() <= u(i) && grad(i) < 0);
                    if (!at_lower_bound && !at_upper_bound)
                        max_gradient = std::max(std::abs(grad(i)), max_gradient);
                }

                if (_verbose)
                {
                    std::cout << "iteration: " << _cur_iter << "   max_gradient: "<< max_gradient << std::endl;
                }

                // Only stop when the largest non-bound-constrained element of the gradient
                // is lower than the threshold.
                if (max_gradient < _gradient_thresh)
                    return false;

                // Check if we have hit the max allowable number of iterations.
                if (_cur_iter > _max_iter)
                {
                    return false;
                }

                return true;
            }

        private:
            bool _verbose;

            unsigned long _max_iter;
            unsigned long _cur_iter;
            double _c;
            double _gradient_thresh;
        };

    public:
        vector_normalizer_frobmetric (
        )
        {
            verbose = false;
            eps = 0.1;
            C = 1;
            max_iter = 5000;
            _use_identity_matrix_prior = false;
        }

        bool uses_identity_matrix_prior (
        ) const
        {
            return _use_identity_matrix_prior;
        }

        void set_uses_identity_matrix_prior (
            bool use_prior
        )
        {
            _use_identity_matrix_prior = use_prior;
        }

        void be_verbose(
        )
        {
            verbose = true;
        }

        void set_epsilon (
            double eps_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(eps_ > 0,
                "\t void vector_normalizer_frobmetric::set_epsilon(eps_)"
                << "\n\t invalid inputs were given to this function"
                << "\n\t eps: " << eps_
                );
            eps = eps_;
        }

        double get_epsilon (
        ) const
        {
            return eps;
        }

        void set_c (
            double C_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(C_ > 0,
                "\t void vector_normalizer_frobmetric::set_c()"
                << "\n\t C_ must be greater than 0"
                << "\n\t C_:    " << C_
                << "\n\t this: " << this
                );

            C = C_;
        }

        void set_max_iterations (
            unsigned long max_iterations
        )
        {
            max_iter = max_iterations;
        }

        unsigned long get_max_iterations (
        ) const
        {
            return max_iter;
        }

        double get_c (
        ) const
        {
            return C;
        }

        void be_quiet (
        )
        {
            verbose = false;
        }

        void train (
            const std::vector<frobmetric_training_sample<matrix_type> >& samples
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(samples.size() > 0,
                "\tvoid vector_normalizer_frobmetric::train()"
                << "\n\t you have to give a nonempty set of samples to this function"
                );
#ifdef ENABLE_ASSERTS
            {
                const long dims = samples[0].anchor_vect.size();
                DLIB_ASSERT(dims != 0,
                    "\tvoid vector_normalizer_frobmetric::train()"
                    << "\n\t The dimension of the input vectors can't be zero."
                    );
                for (unsigned long i = 0; i < samples.size(); ++i)
                {
                    DLIB_ASSERT(is_col_vector(samples[i].anchor_vect),
                        "\tvoid vector_normalizer_frobmetric::train()"
                        << "\n\t Invalid inputs were given to this function."
                        << "\n\t i: " << i
                        );
                    DLIB_ASSERT(samples[i].anchor_vect.size() == dims,
                        "\tvoid vector_normalizer_frobmetric::train()"
                        << "\n\t Invalid inputs were given to this function."
                        << "\n\t i:    " << i
                        << "\n\t dims: " << dims
                        << "\n\t samples[i].anchor_vect.size(): " << samples[i].anchor_vect.size()
                        );

                    DLIB_ASSERT(samples[i].num_triples() != 0,
                        "\tvoid vector_normalizer_frobmetric::train()"
                        << "\n\t It is illegal for a training sample to have no data in it"
                        << "\n\t i:    " << i
                    );
                    for (unsigned long j = 0; j < samples[i].near_vects.size(); ++j)
                    {
                        DLIB_ASSERT(is_col_vector(samples[i].near_vects[j]),
                            "\tvoid vector_normalizer_frobmetric::train()"
                            << "\n\t Invalid inputs were given to this function."
                            << "\n\t i: " << i
                            << "\n\t j: " << j
                            );
                        DLIB_ASSERT(samples[i].near_vects[j].size() == dims,
                            "\tvoid vector_normalizer_frobmetric::train()"
                            << "\n\t Invalid inputs were given to this function."
                            << "\n\t i:    " << i
                            << "\n\t j:    " << j
                            << "\n\t dims: " << dims
                            << "\n\t samples[i].near_vects[j].size(): " << samples[i].near_vects[j].size()
                            );
                    }
                    for (unsigned long j = 0; j < samples[i].far_vects.size(); ++j)
                    {
                        DLIB_ASSERT(is_col_vector(samples[i].far_vects[j]),
                            "\tvoid vector_normalizer_frobmetric::train()"
                            << "\n\t Invalid inputs were given to this function."
                            << "\n\t i: " << i
                            << "\n\t j: " << j
                            );
                        DLIB_ASSERT(samples[i].far_vects[j].size() == dims,
                            "\tvoid vector_normalizer_frobmetric::train()"
                            << "\n\t Invalid inputs were given to this function."
                            << "\n\t i:    " << i
                            << "\n\t j:    " << j
                            << "\n\t dims: " << dims
                            << "\n\t samples[i].far_vects[j].size(): " << samples[i].far_vects[j].size()
                            );
                    }
                }
            }
#endif // end ENABLE_ASSERTS

            // compute the mean sample
            m = 0;
            for (unsigned long i = 0; i < samples.size(); ++i)
                m += samples[i].anchor_vect;
            m /= samples.size();

            DLIB_ASSERT(is_finite(m), "Some of the input vectors to vector_normalizer_frobmetric::train() have infinite or NaN values");

            // Now we need to find tform.  So we setup the optimization problem and run it
            // over the next few lines of code.
            unsigned long num_triples = 0;
            for (unsigned long i = 0; i < samples.size(); ++i)
                num_triples += samples[i].near_vects.size()*samples[i].far_vects.size();

            matrix<double,0,1,mem_manager_type> u(num_triples);
            matrix<double,0,1,mem_manager_type> bias(num_triples);
            u = 0;
            bias = 1;

            // precompute all the anchor_vect to far_vects/near_vects pairs
            std::vector<compact_frobmetric_training_sample> data(samples.size());
            unsigned long cnt = 0;
            std::vector<double> far_norm, near_norm;
            for (unsigned long i = 0; i < data.size(); ++i)
            {
                far_norm.clear();
                near_norm.clear();
                data[i].far_vects.reserve(samples[i].far_vects.size());
                data[i].near_vects.reserve(samples[i].near_vects.size());
                for (unsigned long j = 0; j < samples[i].far_vects.size(); ++j)
                {
                    data[i].far_vects.push_back(samples[i].anchor_vect - samples[i].far_vects[j]);
                    if (_use_identity_matrix_prior)
                        far_norm.push_back(length_squared(data[i].far_vects.back()));
                }
                for (unsigned long j = 0; j < samples[i].near_vects.size(); ++j)
                {
                    data[i].near_vects.push_back(samples[i].anchor_vect - samples[i].near_vects[j]);
                    if (_use_identity_matrix_prior)
                        near_norm.push_back(length_squared(data[i].near_vects.back()));
                }

                // Note that this loop only executes if _use_identity_matrix_prior == true.
                for (unsigned long j = 0; j < near_norm.size(); ++j)
                {
                    for (unsigned long k = 0; k < far_norm.size(); ++k)
                    {
                        bias(cnt++) = 1 - (far_norm[k] - near_norm[j]);
                    }
                }
            }

            // Now run the main part of the algorithm
            matrix<double,0,0,mem_manager_type> Aminus;
            find_max_box_constrained(lbfgs_search_strategy(10),
                                     custom_stop_strategy(C, eps, verbose, max_iter),
                                     objective(data, Aminus, bias),
                                     derivative(num_triples, data, Aminus, bias),
                                     u, 0, C/num_triples);

            // What we need is the optimal Aminus which is a function of u.  So we already
            // have what we need and just need to put it into tform.
            eigenvalue_decomposition<matrix<double,0,0,mem_manager_type> > ed(make_symmetric(-Aminus));
            matrix<double,0,1,mem_manager_type> eigs = ed.get_real_eigenvalues();
            // But first, discard the components that are zero to within the machine epsilon.
            const double tol = max(eigs)*std::numeric_limits<double>::epsilon();
            for (long i = 0; i < eigs.size(); ++i)
            {
                if (eigs(i) < tol)
                    eigs(i) = 0;
            }
            if (_use_identity_matrix_prior)
                tform = matrix_cast<scalar_type>(identity_matrix(Aminus) + diagm(sqrt(eigs))*trans(ed.get_pseudo_v()));
            else
                tform = matrix_cast<scalar_type>(diagm(sqrt(eigs))*trans(ed.get_pseudo_v()));

            // Pre-apply the transform to m so we don't have to do it inside operator()
            // every time it's called.
            m = tform*m;
        }

        long in_vector_size (
        ) const
        {
            return m.nr();
        }

        long out_vector_size (
        ) const
        {
            return m.nr();
        }

        const matrix<scalar_type,0,1,mem_manager_type>& transformed_means (
        ) const
        {
            return m;
        }

        const matrix<scalar_type,0,0,mem_manager_type>& transform (
        ) const
        {
            return tform;
        }

        const result_type& operator() (
            const matrix_type& x
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(in_vector_size() != 0 && in_vector_size() == x.size() &&
                is_col_vector(x) == true,
                "\tmatrix vector_normalizer_frobmetric::operator()"
                << "\n\t you have given invalid arguments to this function"
                << "\n\t in_vector_size(): " << in_vector_size()
                << "\n\t x.size():         " << x.size()
                << "\n\t is_col_vector(x): " << is_col_vector(x)
                << "\n\t this:             " << this
                );

            temp_out = tform*x-m;
            return temp_out;
        }

        template <typename mt>
        friend void deserialize (
            vector_normalizer_frobmetric<mt>& item,
            std::istream& in
        );

        template <typename mt>
        friend void serialize (
            const vector_normalizer_frobmetric<mt>& item,
            std::ostream& out
        );

    private:

        // ------------------- private data members -------------------

        matrix_type m;
        matrix<scalar_type,0,0,mem_manager_type> tform;
        bool verbose;
        double eps;
        double C;
        unsigned long max_iter;
        bool _use_identity_matrix_prior;

        // This is just a temporary variable that doesn't contribute to the
        // state of this object.
        mutable matrix_type temp_out;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_type
        >
    void serialize (
        const vector_normalizer_frobmetric<matrix_type>& item,
        std::ostream& out
    )
    {
        const int version = 2;
        serialize(version, out);

        serialize(item.m, out);
        serialize(item.tform, out);
        serialize(item.verbose, out);
        serialize(item.eps, out);
        serialize(item.C, out);
        serialize(item.max_iter, out);
        serialize(item._use_identity_matrix_prior, out);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_type
        >
    void deserialize (
        vector_normalizer_frobmetric<matrix_type>& item,
        std::istream& in
    )
    {
        int version = 0;
        deserialize(version, in);
        if (version != 1 && version != 2)
            throw serialization_error("Unsupported version found while deserializing dlib::vector_normalizer_frobmetric.");

        deserialize(item.m, in);
        deserialize(item.tform, in);
        deserialize(item.verbose, in);
        deserialize(item.eps, in);
        deserialize(item.C, in);
        deserialize(item.max_iter, in);
        if (version == 2)
            deserialize(item._use_identity_matrix_prior, in);
        else
            item._use_identity_matrix_prior = false;
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_VECTOR_NORMALIZER_FRoBMETRIC_Hh_


dlib C++ Library - std_vector_c.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_STD_VECTOr_C_H_
#define DLIB_STD_VECTOr_C_H_

#include <vector>
#include <algorithm>
#include "../assert.h"
#include "std_vector_c_abstract.h"
#include "../serialize.h"
#include "../is_kind.h"

namespace dlib
{

    template <
        typename T,
        typename Allocator = std::allocator<T>
        >
    class std_vector_c : public std::vector<T,Allocator>
    {
        typedef typename std::vector<T,Allocator> base_type;
    public:
        // types:
        typedef typename Allocator::reference         reference;
        typedef typename Allocator::const_reference   const_reference;
        typedef typename base_type::iterator          iterator;       // See 23.1
        typedef typename base_type::const_iterator    const_iterator; // See 23.1
        typedef typename base_type::size_type         size_type;      // See 23.1
        typedef typename base_type::difference_type   difference_type;// See 23.1
        typedef T                                     value_type;
        typedef Allocator                             allocator_type;
        typedef typename Allocator::pointer           pointer;
        typedef typename Allocator::const_pointer     const_pointer;
        typedef std::reverse_iterator<iterator>       reverse_iterator;
        typedef std::reverse_iterator<const_iterator> const_reverse_iterator;

        // 23.2.4.1 construct/copy/destroy:
        explicit std_vector_c(const Allocator& alloc= Allocator()) : base_type(alloc) {}

        explicit std_vector_c(size_type n, const T& value = T(),
                              const Allocator& alloc= Allocator()) : base_type(n, value, alloc) {}

        template <typename InputIterator>
        std_vector_c(InputIterator first, InputIterator last,
                     const Allocator& alloc= Allocator()) : base_type(first,last,alloc) {}

        std_vector_c(const std::vector<T,Allocator>& x) : base_type(x) {}

        std_vector_c<T,Allocator>& operator=(const std::vector<T,Allocator>& x)
        {
            static_cast<base_type&>(*this) = x;
            return *this;
        }

        template <typename InputIterator>
        void assign(InputIterator first, InputIterator last)    { base_type::assign(first,last); }
        void assign(size_type n, const T& u)                    { base_type::assign(n,u); }
        allocator_type          get_allocator() const           { return base_type::get_allocator(); }
        // iterators:
        iterator                begin()                         { return base_type::begin(); }
        const_iterator          begin() const                   { return base_type::begin(); }
        iterator                end()                           { return base_type::end(); }
        const_iterator          end() const                     { return base_type::end(); }
        reverse_iterator        rbegin()                        { return base_type::rbegin(); }
        const_reverse_iterator  rbegin() const                  { return base_type::rbegin(); }
        reverse_iterator        rend()                          { return base_type::rend(); }
        const_reverse_iterator  rend() const                    { return base_type::rend(); }
        // 23.2.4.2 capacity:
        size_type               size() const                    { return base_type::size(); }
        size_type               max_size() const                { return base_type::max_size(); }
        void                    resize(size_type sz, T c = T()) { base_type::resize(sz,c); }
        size_type               capacity() const                { return base_type::capacity(); }
        bool                    empty() const                   { return base_type::empty(); }
        void                    reserve(size_type n)            { base_type::reserve(n); }

        // element access:
        const_reference         at(size_type n) const           { return base_type::at(n); }
        reference               at(size_type n)                 { return base_type::at(n); }

        // 23.2.4.3 modifiers:
        void     push_back(const T& x) { base_type::push_back(x); }
        void     swap(std_vector_c<T,Allocator>& x) { base_type::swap(x); }
        void     clear() { base_type::clear(); }

    // ------------------------------------------------------
    // Things that have preconditions that should be checked.
    // ------------------------------------------------------

        reference operator[](
            size_type n
        )
        {
            DLIB_CASSERT(n < size(),
                "\treference std_vector_c::operator[](n)"
                << "\n\tYou have supplied an invalid index"
                << "\n\tthis:   " << this
                << "\n\tn:      " << n
                << "\n\tsize(): " << size()
            );
            return static_cast<base_type&>(*this)[n];
        }

    // ------------------------------------------------------

        const_reference operator[](
            size_type n
        ) const
        {
            DLIB_CASSERT(n < size(),
                "\tconst_reference std_vector_c::operator[](n)"
                << "\n\tYou have supplied an invalid index"
                << "\n\tthis:   " << this
                << "\n\tn:      " << n
                << "\n\tsize(): " << size()
            );
            return static_cast<const base_type&>(*this)[n];
        }

    // ------------------------------------------------------

        reference front(
        )
        {
            DLIB_CASSERT(size() > 0,
                "\treference std_vector_c::front()"
                << "\n\tYou can't call front() on an empty vector"
                << "\n\tthis:   " << this
            );
            return base_type::front();
        }

    // ------------------------------------------------------

        const_reference front(
        ) const
        {
            DLIB_CASSERT(size() > 0,
                "\tconst_reference std_vector_c::front()"
                << "\n\tYou can't call front() on an empty vector"
                << "\n\tthis:   " << this
            );
            return base_type::front();
        }

    // ------------------------------------------------------

        reference back(
        )
        {
            DLIB_CASSERT(size() > 0,
                "\treference std_vector_c::back()"
                << "\n\tYou can't call back() on an empty vector"
                << "\n\tthis:   " << this
            );
            return base_type::back();
        }

    // ------------------------------------------------------

        const_reference back(
        ) const
        {
            DLIB_CASSERT(size() > 0,
                "\tconst_reference std_vector_c::back()"
                << "\n\tYou can't call back() on an empty vector"
                << "\n\tthis:   " << this
            );
            return base_type::back();
        }

    // ------------------------------------------------------

        void pop_back(
        )
        {
            DLIB_CASSERT(size() > 0,
                "\tconst_reference std_vector_c::pop_back()"
                << "\n\tYou can't call pop_back() on an empty vector"
                << "\n\tthis:   " << this
            );
            base_type::pop_back();
        }

    // ------------------------------------------------------

        iterator insert(
            iterator position,
            const T& x
        )
        {
            DLIB_CASSERT( begin() <= position && position <= end(),
                "\titerator std_vector_c::insert(position,x)"
                << "\n\tYou have called insert() with an invalid position"
                << "\n\tthis:   " << this
            );
            return base_type::insert(position, x);
        }

    // ------------------------------------------------------

        void insert(
            iterator position,
            size_type n,
            const T& x
        )
        {
            DLIB_CASSERT( begin() <= position && position <= end(),
                "\tvoid std_vector_c::insert(position,n,x)"
                << "\n\tYou have called insert() with an invalid position"
                << "\n\tthis:   " << this
            );
            base_type::insert(position, n, x);
        }

    // ------------------------------------------------------

        template <typename InputIterator>
        void insert(
            iterator position,
            InputIterator first,
            InputIterator last
        )
        {
            DLIB_CASSERT( begin() <= position && position <= end(),
                "\tvoid std_vector_c::insert(position,first,last)"
                << "\n\tYou have called insert() with an invalid position"
                << "\n\tthis:   " << this
            );
            base_type::insert(position, first, last);
        }

    // ------------------------------------------------------

        iterator erase(
            iterator position
        )
        {
            DLIB_CASSERT( begin() <= position && position < end(),
                "\titerator std_vector_c::erase(position)"
                << "\n\tYou have called erase() with an invalid position"
                << "\n\tthis:   " << this
            );
            return base_type::erase(position);
        }

    // ------------------------------------------------------

        iterator erase(
            iterator first,
            iterator last
        )
        {
            DLIB_CASSERT( begin() <= first && first <= last && last <= end(),
                "\titerator std_vector_c::erase(first,last)"
                << "\n\tYou have called erase() with an invalid range of iterators"
                << "\n\tthis:   " << this
            );
            return base_type::erase(first,last);
        }

    // ------------------------------------------------------

    };

// ----------------------------------------------------------------------------------------

// Add these swaps just to make absolutely sure the specialized swap always gets called even
// if the compiler is crappy and would otherwise mess it up.
    template <typename T, typename Allocator>
    void swap(std_vector_c<T,Allocator>& x, std_vector_c<T,Allocator>& y) { x.swap(y); }

    template <typename T, typename Allocator>
    void swap(std::vector<T,Allocator>& x, std_vector_c<T,Allocator>& y) { x.swap(y); }

    template <typename T, typename Allocator>
    void swap(std_vector_c<T,Allocator>& x, std::vector<T,Allocator>& y) { y.swap(x); }

// ----------------------------------------------------------------------------------------

    template <typename T, typename alloc>
    void serialize (
        const std_vector_c<T,alloc>& item,
        std::ostream& out
    )
    {
        try
        {
            const unsigned long size = static_cast<unsigned long>(item.size());

            serialize(size,out);
            for (unsigned long i = 0; i < item.size(); ++i)
                serialize(item[i],out);
        }
        catch (serialization_error& e)
        { throw serialization_error(e.info + "\n   while serializing object of type std_vector_c"); }
    }

// ----------------------------------------------------------------------------------------

    template <typename T, typename alloc>
    void deserialize (
        std_vector_c<T, alloc>& item,
        std::istream& in
    )
    {
        try
        {
            unsigned long size;
            deserialize(size,in);
            item.resize(size);
            for (unsigned long i = 0; i < size; ++i)
                deserialize(item[i],in);
        }
        catch (serialization_error& e)
        { throw serialization_error(e.info + "\n   while deserializing object of type std_vector_c"); }
    }

// ----------------------------------------------------------------------------------------

    template <typename T, typename alloc>
    struct is_std_vector<std_vector_c<T,alloc> >        { const static bool value = true; };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_STD_VECTOr_C_H_


dlib C++ Library - string.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_STRINg_
#define DLIB_STRINg_

#include "string_abstract.h"
#include <sstream>
#include "../algs.h"
#include <string>
#include <iostream>
#include <iomanip>
#include "../error.h"
#include "../assert.h"
#include "../uintn.h"
#include <cctype>
#include <algorithm>
#include <vector>
#include "../enable_if.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    inline const typename disable_if<is_same_type<charT,char>,std::string>::type narrow (
        const std::basic_string<charT,traits,alloc>& str
    )
    {
        std::string temp;
        temp.reserve(str.size());
        std::string::size_type i;
        for (i = 0; i < str.size(); ++i)
        {
            if (zero_extend_cast<unsigned long>(str[i]) > 255)
                temp += ' ';
            else
                temp += zero_extend_cast<char>(str[i]);
        }
        return temp;
    }

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    inline const typename enable_if<is_same_type<charT,char>,std::string>::type narrow (
        const std::basic_string<charT,traits,alloc>& str
    )
    {
        return str;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename traits,
        typename alloc
        >
    const std::basic_string<char,traits,alloc> tolower (
        const std::basic_string<char,traits,alloc>& str
    )
    {
        std::basic_string<char,traits,alloc> temp;

        temp.resize(str.size());

        for (typename std::basic_string<char,traits,alloc>::size_type i = 0; i < str.size(); ++i)
            temp[i] = (char)std::tolower(str[i]);

        return temp;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename traits,
        typename alloc
        >
    const std::basic_string<char,traits,alloc> toupper (
        const std::basic_string<char,traits,alloc>& str
    )
    {
        std::basic_string<char,traits,alloc> temp;

        temp.resize(str.size());

        for (typename std::basic_string<char,traits,alloc>::size_type i = 0; i < str.size(); ++i)
            temp[i] = (char)std::toupper(str[i]);

        return temp;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename traits,
        typename alloc
        >
    bool strings_equal_ignore_case (
        const std::basic_string<char,traits,alloc>& str1,
        const std::basic_string<char,traits,alloc>& str2
    )
    {
        if (str1.size() != str2.size())
            return false;

        for (typename std::basic_string<char,traits,alloc>::size_type i = 0; i < str1.size(); ++i)
        {
            if (std::tolower(str1[i]) != std::tolower(str2[i]))
                return false;
        }

        return true;
    }

    template <
        typename traits,
        typename alloc
        >
    bool strings_equal_ignore_case (
        const std::basic_string<char,traits,alloc>& str1,
        const char* str2
    )
    {
        typename std::basic_string<char,traits,alloc>::size_type i;
        for (i = 0; i < str1.size(); ++i)
        {
            // if we hit the end of str2 then the strings aren't the same length
            if (str2[i] == '\0')
                return false;

            if (std::tolower(str1[i]) != std::tolower(str2[i]))
                return false;
        }

        // This happens when str2 is longer than str1
        if (str2[i] != '\0')
            return false;

        return true;
    }

    template <
        typename traits,
        typename alloc
        >
    bool strings_equal_ignore_case (
        const char* str1,
        const std::basic_string<char,traits,alloc>& str2
    )
    {
        return strings_equal_ignore_case(str2, str1);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename traits,
        typename alloc
        >
    bool strings_equal_ignore_case (
        const std::basic_string<char,traits,alloc>& str1,
        const std::basic_string<char,traits,alloc>& str2,
        unsigned long num
    )
    {
        if (str1.size() != str2.size() && (str1.size() < num || str2.size() < num))
            return false;

        for (typename std::basic_string<char,traits,alloc>::size_type i = 0; i < str1.size() && i < num; ++i)
        {
            if (std::tolower(str1[i]) != std::tolower(str2[i]))
                return false;
        }

        return true;
    }

    template <
        typename traits,
        typename alloc
        >
    bool strings_equal_ignore_case (
        const std::basic_string<char,traits,alloc>& str1,
        const char* str2,
        unsigned long num
    )
    {
        typename std::basic_string<char,traits,alloc>::size_type i;
        for (i = 0; i < str1.size() && i < num; ++i)
        {
            // if we hit the end of str2 then the strings aren't the same length
            if (str2[i] == '\0')
                return false;

            if (std::tolower(str1[i]) != std::tolower(str2[i]))
                return false;
        }

        return true;
    }

    template <
        typename traits,
        typename alloc
        >
    bool strings_equal_ignore_case (
        const char* str1,
        const std::basic_string<char,traits,alloc>& str2,
        unsigned long num
    )
    {
        return strings_equal_ignore_case(str2, str1, num);
    }

// ----------------------------------------------------------------------------------------

    class cast_to_string_error : public error
    {
    public:
        cast_to_string_error():error(ECAST_TO_STRING) {}
    };

    template <
        typename T
        >
    const std::string cast_to_string (
        const T& item
    )
    {
        std::ostringstream sout;
        sout << item;
        if (!sout)
            throw cast_to_string_error();
        return sout.str();
    }

    // don't declare this if we are using mingw because it apparently doesn't
    // support iostreams with wchar_t?
#if !(defined(__MINGW32__) && (__GNUC__ < 4))
    template <
        typename T
        >
    const std::wstring cast_to_wstring (
        const T& item
    )
    {
        std::basic_ostringstream<wchar_t> sout;
        sout << item;
        if (!sout)
            throw cast_to_string_error();
        return sout.str();
    }
#endif

// ----------------------------------------------------------------------------------------

    inline std::string pad_int_with_zeros (
        int i,
        unsigned long width = 6
    )
    {
        std::ostringstream sout;
        sout << std::setw(width) << std::setfill('0') << i;
        return sout.str();
    }

// ----------------------------------------------------------------------------------------

    class string_cast_error : public error
    {
    public:
        string_cast_error(const std::string& str):
            error(ESTRING_CAST,"string cast error: invalid string = '" + str + "'") {}
    };

    template <
        typename T
        >
    struct string_cast_helper
    {
        template < typename charT, typename traits, typename alloc >
        static const T cast (
            const std::basic_string<charT,traits,alloc>& str
        )
        {
            using namespace std;
            basic_istringstream<charT,traits,alloc> sin(str);
            T temp;
            sin >> temp;
            if (!sin) throw string_cast_error(narrow(str));
            if (sin.get() != std::char_traits<charT>::eof()) throw string_cast_error(narrow(str));
            return temp;
        }
    };

    template <typename C, typename T, typename A>
    struct string_cast_helper<std::basic_string<C,T,A> >
    {
        template < typename charT, typename traits, typename alloc >
        static const std::basic_string<C,T,A> cast (
            const std::basic_string<charT,traits,alloc>& str
        )
        {
            std::basic_string<C,T,A> temp;
            temp.resize(str.size());
            for (unsigned long i = 0; i < str.size(); ++i)
                temp[i] = zero_extend_cast<C>(str[i]);
            return temp;
        }
    };

    template <>
    struct string_cast_helper<bool>
    {
        template < typename charT, typename traits, typename alloc >
        static bool cast (
            const std::basic_string<charT,traits,alloc>& str
        )
        {
            using namespace std;
            if (str.size() == 1 && str[0] == '1')
                return true;
            if (str.size() == 1 && str[0] == '0')
                return false;
            if (tolower(narrow(str)) == "true")
                return true;
            if (tolower(narrow(str)) == "false")
                return false;

            throw string_cast_error(narrow(str));
        }
    };

#define DLIB_STRING_CAST_INTEGRAL(type)                             \
    template <>                                                     \
    struct string_cast_helper<type>                                 \
    {                                                               \
        template < typename charT, typename traits, typename alloc> \
        static type cast (                                    \
            const std::basic_string<charT,traits,alloc>& str        \
        )                                                           \
        {                                                           \
            using namespace std;                                    \
            basic_istringstream<charT,traits,alloc> sin(str);       \
            type temp;                                              \
            if (str.size() > 2 && str[0] == _dT(charT,'0') && str[1] == _dT(charT,'x'))   \
                sin >> hex >> temp;                                 \
            else                                                    \
                sin >> temp;                                        \
            if (!sin) throw string_cast_error(narrow(str));                 \
            if (sin.get() != std::char_traits<charT>::eof()) throw string_cast_error(narrow(str));     \
            return temp;                                            \
        }                                                           \
    };

    DLIB_STRING_CAST_INTEGRAL(unsigned short)
    DLIB_STRING_CAST_INTEGRAL(short)
    DLIB_STRING_CAST_INTEGRAL(unsigned int)
    DLIB_STRING_CAST_INTEGRAL(int)
    DLIB_STRING_CAST_INTEGRAL(unsigned long)
    DLIB_STRING_CAST_INTEGRAL(long)
    DLIB_STRING_CAST_INTEGRAL(uint64)

    template <
        typename T,
        typename charT,
        typename traits,
        typename alloc
        >
    inline const T string_cast (
        const std::basic_string<charT,traits,alloc>& str
    )
    {
        COMPILE_TIME_ASSERT(is_pointer_type<T>::value == false);
        return string_cast_helper<T>::cast(str);
    }

    template <typename T>
    inline const T string_cast (const char* str){ return string_cast<T>(std::string(str)); }
    template <typename T>
    inline const T string_cast (const wchar_t* str){ return string_cast<T>(std::wstring(str)); }

// ----------------------------------------------------------------------------------------

    class string_assign
    {
        template <
            typename charT,
            typename traits,
            typename alloc
            >
        class string_assign_helper
        {
        public:
            string_assign_helper (
                const std::basic_string<charT,traits,alloc>& str_
            ) : str(str_) {}

            template <typename T>
            operator T () const
            {
                return string_cast<T>(str);
            }

        private:

            const std::basic_string<charT,traits,alloc>& str;
        };

    // -------------

        class char_assign_helper
        {
        public:
            char_assign_helper (
                const char* str_
            ) : str(str_) {}

            template <typename T>
            operator T () const
            {
                return string_cast<T>(str);
            }

        private:

            const char* str;
        };

    // -------------

        class wchar_t_assign_helper
        {
        public:
            wchar_t_assign_helper (
                const wchar_t* str_
            ) : str(str_) {}

            template <typename T>
            operator T () const
            {
                return string_cast<T>(str);
            }

        private:

            const wchar_t* str;
        };

    // -------------

    public:

        template <
            typename charT,
            typename traits,
            typename alloc
            >
        string_assign_helper<charT,traits,alloc> operator=(
            const std::basic_string<charT,traits,alloc>& str
        ) const
        {
            return string_assign_helper<charT,traits,alloc>(str);
        }

        char_assign_helper operator= (
            const char* str
        ) const
        {
            return char_assign_helper(str);
        }

        wchar_t_assign_helper operator= (
            const wchar_t* str
        ) const
        {
            return wchar_t_assign_helper(str);
        }
    };

    const string_assign sa = string_assign();

// ----------------------------------------------------------------------------------------

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    const std::basic_string<charT,traits,alloc> wrap_string (
        const std::basic_string<charT,traits,alloc>& str,
        const unsigned long first_pad = 0,
        const unsigned long rest_pad = 0,
        const unsigned long max_per_line = 79
    )
    {
        DLIB_ASSERT ( first_pad < max_per_line && rest_pad < max_per_line &&
                 rest_pad >= first_pad,
                 "\tconst std::basic_string<charT,traits,alloc> wrap_string()"
                 << "\n\tfirst_pad:    " << first_pad
                 << "\n\trest_pad:     " << rest_pad
                 << "\n\tmax_per_line: " << max_per_line  );

        using namespace std;

        basic_ostringstream<charT,traits,alloc> sout;
        basic_istringstream<charT,traits,alloc> sin(str);

        for (unsigned long i = 0; i < rest_pad; ++i)
            sout << _dT(charT," ");
        const basic_string<charT,traits,alloc> pad(sout.str());
        sout.str(_dT(charT,""));

        for (unsigned long i = 0; i < first_pad; ++i)
            sout << _dT(charT," ");

        typename basic_string<charT,traits,alloc>::size_type remaining = max_per_line - rest_pad;

        basic_string<charT,traits,alloc> temp;

        sin >> temp;
        while (sin)
        {
            if (temp.size() > remaining)
            {
                if (temp.size() + rest_pad >= max_per_line)
                {
                    string::size_type i = 0;
                    for (; i < temp.size(); ++i)
                    {
                        sout << temp[i];
                        --remaining;
                        if (remaining == 0)
                        {
                            sout << _dT(charT,"\n") << pad;
                            remaining = max_per_line - rest_pad;
                        }
                    }
                }
                else
                {
                    sout << _dT(charT,"\n") << pad << temp;
                    remaining = max_per_line - rest_pad - temp.size();
                }
            }
            else if (temp.size() == remaining)
            {
                sout << temp;
                remaining = 0;
            }
            else
            {
                sout << temp;
                remaining -= temp.size();
            }

            sin >> temp;
            if (remaining == 0 && sin)
            {
                sout << _dT(charT,"\n") << pad;
                remaining = max_per_line - rest_pad;
            }
            else
            {
                sout << _dT(charT," ");
                --remaining;
            }
        }

        return sout.str();
    }

    template <
        typename charT
        >
    const std::basic_string<charT> wrap_string (
        const charT* str,
        const unsigned long first_pad = 0,
        const unsigned long rest_pad = 0,
        const unsigned long max_per_line = 79
    ) { return wrap_string(std::basic_string<charT>(str),first_pad,rest_pad,max_per_line); }

// ----------------------------------------------------------------------------------------

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    const std::basic_string<charT,traits,alloc> ltrim (
        const std::basic_string<charT,traits,alloc>& str,
        const std::basic_string<charT,traits,alloc>& trim_chars
    )
    {
        typedef std::basic_string<charT,traits,alloc> string;
        typename string::size_type pos = str.find_first_not_of(trim_chars);
        if (pos != string::npos)
            return str.substr(pos);
        else
            return std::basic_string<charT,traits,alloc>();
    }

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    const std::basic_string<charT,traits,alloc> ltrim (
        const std::basic_string<charT,traits,alloc>& str,
        const charT* trim_chars = _dT(charT," \t\r\n")
    ) { return ltrim(str,std::basic_string<charT,traits,alloc>(trim_chars)); }

// ----------------------------------------------------------------------------------------

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    const std::basic_string<charT,traits,alloc> rtrim (
        const std::basic_string<charT,traits,alloc>& str,
        const std::basic_string<charT,traits,alloc>& trim_chars
    )
    {
        typedef std::basic_string<charT,traits,alloc> string;

        typename string::size_type pos = str.find_last_not_of(trim_chars);
        if (pos != string::npos)
            return str.substr(0,pos+1);
        else
            return std::basic_string<charT,traits,alloc>();
    }

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    const std::basic_string<charT,traits,alloc> rtrim (
        const std::basic_string<charT,traits,alloc>& str,
        const charT* trim_chars = _dT(charT," \t\r\n")
    ) { return rtrim(str,std::basic_string<charT,traits,alloc>(trim_chars)); }

// ----------------------------------------------------------------------------------------

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    const std::basic_string<charT,traits,alloc> trim (
        const std::basic_string<charT,traits,alloc>& str,
        const std::basic_string<charT,traits,alloc>& trim_chars
    )
    {
        typedef std::basic_string<charT,traits,alloc> string;
        typename string::size_type lpos = str.find_first_not_of(trim_chars);
        if (lpos != string::npos)
        {
            typename string::size_type rpos = str.find_last_not_of(trim_chars);
            return str.substr(lpos,rpos-lpos+1);
        }
        else
        {
            return std::basic_string<charT,traits,alloc>();
        }
    }

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    const std::basic_string<charT,traits,alloc> trim (
        const std::basic_string<charT,traits,alloc>& str,
        const charT* trim_chars = _dT(charT," \t\r\n")
    ) { return trim(str,std::basic_string<charT,traits,alloc>(trim_chars)); }

// ----------------------------------------------------------------------------------------

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    const std::basic_string<charT,traits,alloc> rpad (
        const std::basic_string<charT,traits,alloc>& str,
        long pad_length,
        const std::basic_string<charT,traits,alloc>& pad_string
    )
    {
        typedef std::basic_string<charT,traits,alloc> string;
        // if str is too big then just return str
        if (pad_length <= static_cast<long>(str.size()))
            return str;

        // make the string we will padd onto the string
        string P;
        while (P.size() < pad_length - str.size())
            P += pad_string;
        P = P.substr(0,pad_length - str.size());

        // return the padded string
        return str + P;
    }

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    const std::basic_string<charT,traits,alloc> rpad (
        const std::basic_string<charT,traits,alloc>& str,
        long pad_length,
        const charT* pad_string = _dT(charT," ")
    ) { return rpad(str,pad_length,std::basic_string<charT,traits,alloc>(pad_string)); }

// ----------------------------------------------------------------------------------------

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    const std::basic_string<charT,traits,alloc> lpad (
        const std::basic_string<charT,traits,alloc>& str,
        long pad_length,
        const std::basic_string<charT,traits,alloc>& pad_string
    )
    {
        typedef std::basic_string<charT,traits,alloc> string;
        // if str is too big then just return str
        if (pad_length <= static_cast<long>(str.size()))
            return str;

        // make the string we will padd onto the string
        string P;
        while (P.size() < pad_length - str.size())
            P += pad_string;
        P = P.substr(0,pad_length - str.size());

        // return the padded string
        return P + str;
    }

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    const std::basic_string<charT,traits,alloc> lpad (
        const std::basic_string<charT,traits,alloc>& str,
        long pad_length,
        const charT* pad_string = _dT(charT," ")
    ) { return lpad(str,pad_length,std::basic_string<charT,traits,alloc>(pad_string)); }

// ----------------------------------------------------------------------------------------

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    const std::basic_string<charT,traits,alloc> pad (
        const std::basic_string<charT,traits,alloc>& str,
        long pad_length,
        const std::basic_string<charT,traits,alloc>& pad_string
    )
    {
        const long str_size = static_cast<long>(str.size());
        return rpad(lpad(str,(pad_length-str_size)/2 + str_size,pad_string),
                    pad_length,
                    pad_string);
    }

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    const std::basic_string<charT,traits,alloc> pad (
        const std::basic_string<charT,traits,alloc>& str,
        long pad_length,
        const charT* pad_string = _dT(charT," ")
    ) { return pad(str,pad_length,std::basic_string<charT,traits,alloc>(pad_string)); }

// ----------------------------------------------------------------------------------------

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    const std::basic_string<charT,traits,alloc> left_substr (
        const std::basic_string<charT,traits,alloc>& str,
        const std::basic_string<charT,traits,alloc>& delim
    )
    {
        return str.substr(0,str.find_first_of(delim));
    }

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    const std::basic_string<charT,traits,alloc> left_substr (
        const std::basic_string<charT,traits,alloc>& str,
        const charT* delim = _dT(charT," \n\r\t")
    )
    {
        return str.substr(0,str.find_first_of(delim));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    const std::basic_string<charT,traits,alloc> right_substr (
        const std::basic_string<charT,traits,alloc>& str,
        const std::basic_string<charT,traits,alloc>& delim
    )
    {
        typename std::basic_string<charT,traits,alloc>::size_type delim_pos = str.find_last_of(delim);
        if (delim_pos != std::basic_string<charT,traits,alloc>::npos)
            return str.substr(delim_pos+1);
        else
            return _dT(charT,"");
    }

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    const std::basic_string<charT,traits,alloc> right_substr (
        const std::basic_string<charT,traits,alloc>& str,
        const charT* delim = _dT(charT," \n\r\t")
    )
    {
        typename std::basic_string<charT,traits,alloc>::size_type delim_pos = str.find_last_of(delim);
        if (delim_pos != std::basic_string<charT,traits,alloc>::npos)
            return str.substr(delim_pos+1);
        else
            return _dT(charT,"");
    }

// ----------------------------------------------------------------------------------------

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    std::pair<std::basic_string<charT,traits,alloc>, std::basic_string<charT,traits,alloc> >
    split_on_first (
        const std::basic_string<charT,traits,alloc>& str,
        const charT* delim = _dT(charT," \n\r\t")
    )
    {
        typename std::basic_string<charT,traits,alloc>::size_type delim_pos = str.find_first_of(delim);
        if (delim_pos != std::basic_string<charT,traits,alloc>::npos)
            return std::make_pair(str.substr(0, delim_pos), str.substr(delim_pos+1));
        else
            return std::make_pair(str, _dT(charT,""));
    }

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    inline std::pair<std::basic_string<charT,traits,alloc>, std::basic_string<charT,traits,alloc> >
    split_on_first (
        const std::basic_string<charT,traits,alloc>& str,
        const std::basic_string<charT,traits,alloc>& delim
    )
    {
        return split_on_first(str, delim.c_str());
    }

// ----------------------------------------------------------------------------------------

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    std::pair<std::basic_string<charT,traits,alloc>, std::basic_string<charT,traits,alloc> >
    split_on_last (
        const std::basic_string<charT,traits,alloc>& str,
        const charT* delim = _dT(charT," \n\r\t")
    )
    {
        typename std::basic_string<charT,traits,alloc>::size_type delim_pos = str.find_last_of(delim);
        if (delim_pos != std::basic_string<charT,traits,alloc>::npos)
            return std::make_pair(str.substr(0, delim_pos), str.substr(delim_pos+1));
        else
            return std::make_pair(str, _dT(charT,""));
    }

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    inline std::pair<std::basic_string<charT,traits,alloc>, std::basic_string<charT,traits,alloc> >
    split_on_last (
        const std::basic_string<charT,traits,alloc>& str,
        const std::basic_string<charT,traits,alloc>& delim
    )
    {
        return split_on_last(str, delim.c_str());
    }

// ----------------------------------------------------------------------------------------

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    const std::vector<std::basic_string<charT,traits,alloc> > split (
        const std::basic_string<charT,traits,alloc>& str,
        const charT* delim = _dT(charT," \n\r\t")
    )
    {
        std::basic_string<charT,traits,alloc> temp;

        std::vector<std::basic_string<charT,traits,alloc> > res;

        for (unsigned long i = 0; i < str.size(); ++i)
        {
            // check if delim contains the character str[i]
            bool hit = false;
            const charT* d = delim;
            while (*d != '\0')
            {
                if (str[i] == *d)
                {
                    hit = true;
                    break;
                }
                ++d;
            }

            if (hit)
            {
                if (temp.size() != 0)
                {
                    res.push_back(temp);
                    temp.clear();
                }
            }
            else
            {
                temp.push_back(str[i]);
            }
        }

        if (temp.size() != 0)
            res.push_back(temp);

        return res;
    }

    template <
        typename charT,
        typename traits,
        typename alloc
        >
    const std::vector<std::basic_string<charT,traits,alloc> > split (
        const std::basic_string<charT,traits,alloc>& str,
        const std::basic_string<charT,traits,alloc>& delim
    )
    {
        return split(str,delim.c_str());
    }

    inline const std::vector<std::string> split (
        const char* str,
        const char* delim = " \n\r\t"
    )
    {
        return split(std::string(str),delim);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_STRINg_


dlib C++ Library - active_learning.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ACTIVE_LEARnING_Hh_
#define DLIB_ACTIVE_LEARnING_Hh_

#include "active_learning_abstract.h"

#include "svm_c_linear_dcd_trainer.h"
#include <vector>

namespace dlib
{

    enum active_learning_mode
    {
        max_min_margin,
        ratio_margin
    };

// ----------------------------------------------------------------------------------------

    template <
        typename kernel_type,
        typename in_sample_vector_type,
        typename in_scalar_vector_type,
        typename in_sample_vector_type2
        >
    std::vector<unsigned long> impl_rank_unlabeled_training_samples (
        const svm_c_linear_dcd_trainer<kernel_type>& trainer,
        const in_sample_vector_type& samples,
        const in_scalar_vector_type& labels,
        const in_sample_vector_type2& unlabeled_samples,
        const active_learning_mode mode
    )
    {
        DLIB_ASSERT(is_vector(unlabeled_samples) &&
                     (samples.size() == 0 || is_learning_problem(samples, labels)) ,
                "\t std::vector<unsigned long> rank_unlabeled_training_samples()"
                << "\n\t Invalid inputs were given to this function"
                << "\n\t is_vector(unlabeled_samples):         " << is_vector(unlabeled_samples)
                << "\n\t is_learning_problem(samples, labels): " << is_learning_problem(samples, labels)
                << "\n\t samples.size(): " << samples.size()
                << "\n\t labels.size():  " << labels.size()
                );

        // If there aren't any training samples then all unlabeled_samples are equally good.
        // So just report an arbitrary ordering.
        if (samples.size() == 0 || unlabeled_samples.size() == 0)
        {
            std::vector<unsigned long> ret(unlabeled_samples.size());
            for (unsigned long i = 0; i < ret.size(); ++i)
                ret[i] = i;

            return ret;
        }

        // We are going to score each unlabeled sample and put the score and index into
        // results.  Then at the end of this function we just sort it and return the indices.
        std::vector<std::pair<double, unsigned long> > results;
        results.resize(unlabeled_samples.size());

        // make sure we use this trainer's ability to warm start itself since that will make
        // this whole function run a lot faster.  But first, we need to find out what the state
        // we will be warm starting from is.
        typedef typename svm_c_linear_dcd_trainer<kernel_type>::optimizer_state optimizer_state;
        optimizer_state state;
        trainer.train(samples, labels, state); // call train() just to get state

        decision_function<kernel_type> df;

        std::vector<typename kernel_type::sample_type> temp_samples;
        std::vector<typename kernel_type::scalar_type> temp_labels;
        temp_samples.reserve(samples.size()+1);
        temp_labels.reserve(labels.size()+1);
        temp_samples.assign(samples.begin(), samples.end());
        temp_labels.assign(labels.begin(), labels.end());
        temp_samples.resize(temp_samples.size()+1);
        temp_labels.resize(temp_labels.size()+1);

        for (long i = 0; i < unlabeled_samples.size(); ++i)
        {
            temp_samples.back() = unlabeled_samples(i);
            // figure out the margin for each possible labeling of this sample.

            optimizer_state temp(state);
            temp_labels.back() = +1;
            df = trainer.train(temp_samples, temp_labels, temp);
            const double margin_p = temp_labels.back()*df(temp_samples.back());

            temp = state;
            temp_labels.back() = -1;
            df = trainer.train(temp_samples, temp_labels, temp);
            const double margin_n = temp_labels.back()*df(temp_samples.back());

            if (mode == max_min_margin)
            {
                // The score for this sample is its min possible margin over possible labels.
                // Therefore, this score measures how much flexibility we have to label this
                // sample however we want.  The intuition being that the most useful points to
                // label are the ones that are still free to obtain either label.
                results[i] = std::make_pair(std::min(margin_p, margin_n), i);
            }
            else
            {
                // In this case, the score for the sample is a ratio that tells how close the
                // two margin values are to each other.  The closer they are the better.  So in
                // this case we are saying we are looking for samples that have the same
                // preference for either class label.
                if (std::abs(margin_p) >= std::abs(margin_n))
                {
                    if (margin_p != 0)
                        results[i] = std::make_pair(margin_n/margin_p, i);
                    else // if both are == 0 then say 0/0 == 1
                        results[i] = std::make_pair(1, i);
                }
                else
                {
                    results[i] = std::make_pair(margin_p/margin_n, i);
                }
            }
        }

        // sort the results so the highest scoring samples come first.
        std::sort(results.rbegin(), results.rend());

        // transfer results into a vector with just sample indices so we can return it.
        std::vector<unsigned long> ret(results.size());
        for (unsigned long i = 0; i < ret.size(); ++i)
            ret[i] = results[i].second;
        return ret;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename kernel_type,
        typename in_sample_vector_type,
        typename in_scalar_vector_type,
        typename in_sample_vector_type2
        >
    std::vector<unsigned long> rank_unlabeled_training_samples (
        const svm_c_linear_dcd_trainer<kernel_type>& trainer,
        const in_sample_vector_type& samples,
        const in_scalar_vector_type& labels,
        const in_sample_vector_type2& unlabeled_samples,
        const active_learning_mode mode = max_min_margin
    )
    {
        return impl_rank_unlabeled_training_samples(trainer,
                                                    mat(samples),
                                                    mat(labels),
                                                    mat(unlabeled_samples),
                                                    mode);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_ACTIVE_LEARnING_Hh_


dlib C++ Library - assignment_function.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ASSIGNMENT_FuNCTION_Hh_
#define DLIB_ASSIGNMENT_FuNCTION_Hh_

#include "assignment_function_abstract.h"
#include "../matrix.h"
#include <vector>
#include "../optimization/max_cost_assignment.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    class assignment_function
    {
    public:

        typedef typename feature_extractor::lhs_element lhs_element;
        typedef typename feature_extractor::rhs_element rhs_element;

        typedef std::pair<std::vector<lhs_element>, std::vector<rhs_element> > sample_type;

        typedef std::vector<long> label_type;
        typedef label_type result_type;

        assignment_function()
        {
            weights.set_size(fe.num_features());
            weights = 0;
            bias = 0;
            force_assignment = false;
        }

        explicit assignment_function(
            const matrix<double,0,1>& weights_,
            double bias_
        ) :
            weights(weights_),
            bias(bias_),
            force_assignment(false)
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(fe.num_features() == static_cast<unsigned long>(weights_.size()),
                "\t assignment_function::assignment_function(weights_)"
                << "\n\t These sizes should match"
                << "\n\t fe.num_features(): " << fe.num_features()
                << "\n\t weights_.size():   " << weights_.size()
                << "\n\t this: " << this
                );

        }

        assignment_function(
            const matrix<double,0,1>& weights_,
            double bias_,
            const feature_extractor& fe_
        ) :
            fe(fe_),
            weights(weights_),
            bias(bias_),
            force_assignment(false)
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(fe_.num_features() == static_cast<unsigned long>(weights_.size()),
                "\t assignment_function::assignment_function(weights_,fe_)"
                << "\n\t These sizes should match"
                << "\n\t fe_.num_features(): " << fe_.num_features()
                << "\n\t weights_.size():    " << weights_.size()
                << "\n\t this: " << this
                );
        }

        assignment_function(
            const matrix<double,0,1>& weights_,
            double bias_,
            const feature_extractor& fe_,
            bool force_assignment_
        ) :
            fe(fe_),
            weights(weights_),
            bias(bias_),
            force_assignment(force_assignment_)
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(fe_.num_features() == static_cast<unsigned long>(weights_.size()),
                "\t assignment_function::assignment_function(weights_,fe_,force_assignment_)"
                << "\n\t These sizes should match"
                << "\n\t fe_.num_features(): " << fe_.num_features()
                << "\n\t weights_.size():    " << weights_.size()
                << "\n\t this: " << this
                );
        }

        const feature_extractor& get_feature_extractor (
        ) const { return fe; }

        const matrix<double,0,1>& get_weights (
        ) const { return weights; }

        double get_bias (
        ) const { return bias; }

        bool forces_assignment (
        ) const { return force_assignment; }

        void predict_assignments (
            const std::vector<lhs_element>& lhs,
            const std::vector<rhs_element>& rhs,
            result_type& assignment
        ) const
        {
            assignment.clear();

            matrix<double> cost;
            unsigned long size;
            if (force_assignment)
            {
                size = std::max(lhs.size(), rhs.size());
            }
            else
            {
                size = rhs.size() + lhs.size();
            }
            cost.set_size(size, size);

            typedef typename feature_extractor::feature_vector_type feature_vector_type;
            feature_vector_type feats;

            // now fill out the cost assignment matrix
            for (long r = 0; r < cost.nr(); ++r)
            {
                for (long c = 0; c < cost.nc(); ++c)
                {
                    if (r < (long)lhs.size() && c < (long)rhs.size())
                    {
                        fe.get_features(lhs[r], rhs[c], feats);
                        cost(r,c) = dot(weights, feats) + bias;
                    }
                    else
                    {
                        cost(r,c) = 0;
                    }
                }
            }

            if (cost.size() != 0)
            {
                // max_cost_assignment() only works with integer matrices, so convert from
                // double to integer.
                const double scale = (std::numeric_limits<dlib::int64>::max()/1000)/max(abs(cost));
                matrix<dlib::int64> int_cost = matrix_cast<dlib::int64>(round(cost*scale));
                assignment = max_cost_assignment(int_cost);
                assignment.resize(lhs.size());
            }

            // adjust assignment so that non-assignments have a value of -1
            for (unsigned long i = 0; i < assignment.size(); ++i)
            {
                if (assignment[i] >= (long)rhs.size())
                    assignment[i] = -1;
            }
        }

        void predict_assignments (
            const sample_type& item,
            result_type& assignment
        ) const
        {
            predict_assignments(item.first, item.second, assignment);
        }

        result_type operator()(
            const std::vector<lhs_element>& lhs,
            const std::vector<rhs_element>& rhs
        ) const
        {
            result_type temp;
            predict_assignments(lhs,rhs,temp);
            return temp;
        }

        result_type operator() (
            const sample_type& item
        ) const
        {
            return (*this)(item.first, item.second);
        }

    private:

        feature_extractor fe;
        matrix<double,0,1> weights;
        double bias;
        bool force_assignment;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    void serialize (
        const assignment_function<feature_extractor>& item,
        std::ostream& out
    )
    {
        int version = 2;
        serialize(version, out);
        serialize(item.get_feature_extractor(), out);
        serialize(item.get_weights(), out);
        serialize(item.get_bias(), out);
        serialize(item.forces_assignment(), out);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    void deserialize (
        assignment_function<feature_extractor>& item,
        std::istream& in
    )
    {
        feature_extractor fe;
        matrix<double,0,1> weights;
        double bias;
        bool force_assignment;
        int version = 0;
        deserialize(version, in);
        if (version != 2)
            throw serialization_error("Unexpected version found while deserializing dlib::assignment_function.");

        deserialize(fe, in);
        deserialize(weights, in);
        deserialize(bias, in);
        deserialize(force_assignment, in);

        item = assignment_function<feature_extractor>(weights, bias, fe, force_assignment);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_ASSIGNMENT_FuNCTION_Hh_


dlib C++ Library - cross_validate_assignment_trainer.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_CROSS_VALIDATE_ASSiGNEMNT_TRAINER_Hh_
#define DLIB_CROSS_VALIDATE_ASSiGNEMNT_TRAINER_Hh_

#include "cross_validate_assignment_trainer_abstract.h"
#include <vector>
#include "../matrix.h"
#include "svm.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename assignment_function
        >
    double test_assignment_function (
        const assignment_function& assigner,
        const std::vector<typename assignment_function::sample_type>& samples,
        const std::vector<typename assignment_function::label_type>& labels
    )
    {
        // make sure requires clause is not broken
#ifdef ENABLE_ASSERTS
        if (assigner.forces_assignment())
        {
            DLIB_ASSERT(is_forced_assignment_problem(samples, labels),
                "\t double test_assignment_function()"
                << "\n\t invalid inputs were given to this function"
                << "\n\t is_forced_assignment_problem(samples,labels): " << is_forced_assignment_problem(samples,labels)
                << "\n\t is_assignment_problem(samples,labels):        " << is_assignment_problem(samples,labels)
                << "\n\t is_learning_problem(samples,labels):          " << is_learning_problem(samples,labels)
                );
        }
        else
        {
            DLIB_ASSERT(is_assignment_problem(samples, labels),
                "\t double test_assignment_function()"
                << "\n\t invalid inputs were given to this function"
                << "\n\t is_assignment_problem(samples,labels): " << is_assignment_problem(samples,labels)
                << "\n\t is_learning_problem(samples,labels):   " << is_learning_problem(samples,labels)
                );
        }
#endif
        double total_right = 0;
        double total = 0;
        for (unsigned long i = 0; i < samples.size(); ++i)
        {
            const std::vector<long>& out = assigner(samples[i]);
            for (unsigned long j = 0; j < out.size(); ++j)
            {
                if (out[j] == labels[i][j])
                    ++total_right;

                ++total;
            }
        }

        if (total != 0)
            return total_right/total;
        else
            return 1;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type
        >
    double cross_validate_assignment_trainer (
        const trainer_type& trainer,
        const std::vector<typename trainer_type::sample_type>& samples,
        const std::vector<typename trainer_type::label_type>& labels,
        const long folds
    )
    {
        // make sure requires clause is not broken
#ifdef ENABLE_ASSERTS
        if (trainer.forces_assignment())
        {
            DLIB_ASSERT(is_forced_assignment_problem(samples, labels) &&
                        1 < folds && folds <= static_cast<long>(samples.size()),
                "\t double cross_validate_assignment_trainer()"
                << "\n\t invalid inputs were given to this function"
                << "\n\t samples.size(): " << samples.size()
                << "\n\t folds:  " << folds
                << "\n\t is_forced_assignment_problem(samples,labels): " << is_forced_assignment_problem(samples,labels)
                << "\n\t is_assignment_problem(samples,labels):        " << is_assignment_problem(samples,labels)
                << "\n\t is_learning_problem(samples,labels):          " << is_learning_problem(samples,labels)
                );
        }
        else
        {
            DLIB_ASSERT(is_assignment_problem(samples, labels) &&
                        1 < folds && folds <= static_cast<long>(samples.size()),
                "\t double cross_validate_assignment_trainer()"
                << "\n\t invalid inputs were given to this function"
                << "\n\t samples.size(): " << samples.size()
                << "\n\t folds:  " << folds
                << "\n\t is_assignment_problem(samples,labels): " << is_assignment_problem(samples,labels)
                << "\n\t is_learning_problem(samples,labels):   " << is_learning_problem(samples,labels)
                );
        }
#endif

        typedef typename trainer_type::sample_type sample_type;
        typedef typename trainer_type::label_type label_type;

        const long num_in_test  = samples.size()/folds;
        const long num_in_train = samples.size() - num_in_test;

        std::vector<sample_type> samples_test, samples_train;
        std::vector<label_type> labels_test, labels_train;

        long next_test_idx = 0;
        double total_right = 0;
        double total = 0;

        for (long i = 0; i < folds; ++i)
        {
            samples_test.clear();
            labels_test.clear();
            samples_train.clear();
            labels_train.clear();

            // load up the test samples
            for (long cnt = 0; cnt < num_in_test; ++cnt)
            {
                samples_test.push_back(samples[next_test_idx]);
                labels_test.push_back(labels[next_test_idx]);
                next_test_idx = (next_test_idx + 1)%samples.size();
            }

            // load up the training samples
            long next = next_test_idx;
            for (long cnt = 0; cnt < num_in_train; ++cnt)
            {
                samples_train.push_back(samples[next]);
                labels_train.push_back(labels[next]);
                next = (next + 1)%samples.size();
            }

            const typename trainer_type::trained_function_type& df = trainer.train(samples_train,labels_train);

            // check how good df is on the test data
            for (unsigned long i = 0; i < samples_test.size(); ++i)
            {
                const std::vector<long>& out = df(samples_test[i]);
                for (unsigned long j = 0; j < out.size(); ++j)
                {
                    if (out[j] == labels_test[i][j])
                        ++total_right;

                    ++total;
                }
            }

        } // for (long i = 0; i < folds; ++i)

        if (total != 0)
            return total_right/total;
        else
            return 1;

    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_CROSS_VALIDATE_ASSiGNEMNT_TRAINER_Hh_


dlib C++ Library - cross_validate_multiclass_trainer.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_CROSS_VALIDATE_MULTICLASS_TRaINER_Hh_
#define DLIB_CROSS_VALIDATE_MULTICLASS_TRaINER_Hh_

#include <vector>
#include "../matrix.h"
#include "cross_validate_multiclass_trainer_abstract.h"
#include <sstream>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename dec_funct_type,
        typename sample_type,
        typename label_type
        >
    const matrix<double> test_multiclass_decision_function (
        const dec_funct_type& dec_funct,
        const std::vector<sample_type>& x_test,
        const std::vector<label_type>& y_test
    )
    {

        // make sure requires clause is not broken
        DLIB_ASSERT( is_learning_problem(x_test,y_test) == true,
                    "\tmatrix test_multiclass_decision_function()"
                    << "\n\t invalid inputs were given to this function"
                    << "\n\t is_learning_problem(x_test,y_test): "
                    << is_learning_problem(x_test,y_test));

        const std::vector<label_type> all_labels = dec_funct.get_labels();

        // make a lookup table that maps from labels to their index in all_labels
        std::map<label_type,unsigned long> label_to_int;
        for (unsigned long i = 0; i < all_labels.size(); ++i)
            label_to_int[all_labels[i]] = i;

        matrix<double, 0, 0, typename dec_funct_type::mem_manager_type> res;
        res.set_size(all_labels.size(), all_labels.size());

        res = 0;

        typename std::map<label_type,unsigned long>::const_iterator iter;

        // now test this trained object
        for (unsigned long i = 0; i < x_test.size(); ++i)
        {
            iter = label_to_int.find(y_test[i]);
            // ignore samples with labels that the decision function doesn't know about.
            if (iter == label_to_int.end())
                continue;

            const unsigned long truth = iter->second;
            const unsigned long pred  = label_to_int[dec_funct(x_test[i])];

            res(truth,pred) += 1;
        }

        return res;
    }

// ----------------------------------------------------------------------------------------

    class cross_validation_error : public dlib::error
    {
    public:
        cross_validation_error(const std::string& msg) : dlib::error(msg){};
    };

    template <
        typename trainer_type,
        typename sample_type,
        typename label_type
        >
    const matrix<double> cross_validate_multiclass_trainer (
        const trainer_type& trainer,
        const std::vector<sample_type>& x,
        const std::vector<label_type>& y,
        const long folds
    )
    {
        typedef typename trainer_type::mem_manager_type mem_manager_type;

        // make sure requires clause is not broken
        DLIB_ASSERT(is_learning_problem(x,y) == true &&
                    1 < folds && folds <= static_cast<long>(x.size()),
            "\tmatrix cross_validate_multiclass_trainer()"
            << "\n\t invalid inputs were given to this function"
            << "\n\t x.size(): " << x.size()
            << "\n\t folds:  " << folds
            << "\n\t is_learning_problem(x,y): " << is_learning_problem(x,y)
            );

        const std::vector<label_type> all_labels = select_all_distinct_labels(y);

        // count the number of times each label shows up
        std::map<label_type,long> label_counts;
        for (unsigned long i = 0; i < y.size(); ++i)
            label_counts[y[i]] += 1;

        // figure out how many samples from each class will be in the test and train splits
        std::map<label_type,long> num_in_test, num_in_train;
        for (typename std::map<label_type,long>::iterator i = label_counts.begin(); i != label_counts.end(); ++i)
        {
            const long in_test = i->second/folds;
            if (in_test == 0)
            {
                std::ostringstream sout;
                sout << "In dlib::cross_validate_multiclass_trainer(), the number of folds was larger" << std::endl;
                sout << "than the number of elements of one of the training classes." << std::endl;
                sout << "  folds: "<< folds << std::endl;
                sout << "  size of class " << i->first << ": "<< i->second << std::endl;
                throw cross_validation_error(sout.str());
            }
            num_in_test[i->first] = in_test;
            num_in_train[i->first] = i->second - in_test;
        }

        std::vector<sample_type> x_test, x_train;
        std::vector<label_type> y_test, y_train;

        matrix<double, 0, 0, mem_manager_type> res;

        std::map<label_type,long> next_test_idx;
        for (unsigned long i = 0; i < all_labels.size(); ++i)
            next_test_idx[all_labels[i]] = 0;

        label_type label;

        for (long i = 0; i < folds; ++i)
        {
            x_test.clear();
            y_test.clear();
            x_train.clear();
            y_train.clear();

            // load up the test samples
            for (unsigned long j = 0; j < all_labels.size(); ++j)
            {
                label = all_labels[j];
                long next = next_test_idx[label];

                long cur = 0;
                const long num_needed = num_in_test[label];
                while (cur < num_needed)
                {
                    if (y[next] == label)
                    {
                        x_test.push_back(x[next]);
                        y_test.push_back(label);
                        ++cur;
                    }
                    next = (next + 1)%x.size();
                }

                next_test_idx[label] = next;
            }

            // load up the training samples
            for (unsigned long j = 0; j < all_labels.size(); ++j)
            {
                label = all_labels[j];
                long next = next_test_idx[label];

                long cur = 0;
                const long num_needed = num_in_train[label];
                while (cur < num_needed)
                {
                    if (y[next] == label)
                    {
                        x_train.push_back(x[next]);
                        y_train.push_back(label);
                        ++cur;
                    }
                    next = (next + 1)%x.size();
                }
            }

            try
            {
                // do the training and testing
                res += test_multiclass_decision_function(trainer.train(x_train,y_train),x_test,y_test);
            }
            catch (invalid_nu_error&)
            {
                // just ignore cases which result in an invalid nu
            }

        } // for (long i = 0; i < folds; ++i)

        return res;
    }

}

// ----------------------------------------------------------------------------------------

#endif // DLIB_CROSS_VALIDATE_MULTICLASS_TRaINER_Hh_


dlib C++ Library - cross_validate_object_detection_trainer.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_CROSS_VALIDATE_OBJECT_DETECTION_TRaINER_Hh_
#define DLIB_CROSS_VALIDATE_OBJECT_DETECTION_TRaINER_Hh_

#include "cross_validate_object_detection_trainer_abstract.h"
#include <vector>
#include "../matrix.h"
#include "svm.h"
#include "../geometry.h"
#include "../image_processing/full_object_detection.h"
#include "../image_processing/box_overlap_testing.h"
#include "../statistics.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    namespace impl
    {
        inline unsigned long number_of_truth_hits (
            const std::vector<full_object_detection>& truth_boxes,
            const std::vector<rectangle>& ignore,
            const std::vector<std::pair<double,rectangle> >& boxes,
            const test_box_overlap& overlap_tester,
            std::vector<std::pair<double,bool> >& all_dets,
            unsigned long& missing_detections
        )
        /*!
            ensures
                - returns the number of elements in truth_boxes which are overlapped by an
                  element of boxes.  In this context, two boxes, A and B, overlap if and only if
                  overlap_tester(A,B) == true.
                - No element of boxes is allowed to account for more than one element of truth_boxes.
                - The returned number is in the range [0,truth_boxes.size()]
                - Adds the score for each box from boxes into all_dets and labels each with
                  a bool indicating if it hit a truth box.  Note that we skip boxes that
                  don't hit any truth boxes and match an ignore box.
                - Adds the number of truth boxes which didn't have any hits into
                  missing_detections.
        !*/
        {
            if (boxes.size() == 0)
            {
                missing_detections += truth_boxes.size();
                return 0;
            }

            unsigned long count = 0;
            std::vector<bool> used(boxes.size(),false);
            for (unsigned long i = 0; i < truth_boxes.size(); ++i)
            {
                bool found_match = false;
                // Find the first box that hits truth_boxes[i]
                for (unsigned long j = 0; j < boxes.size(); ++j)
                {
                    if (used[j])
                        continue;

                    if (overlap_tester(truth_boxes[i].get_rect(), boxes[j].second))
                    {
                        used[j] = true;
                        ++count;
                        found_match = true;
                        break;
                    }
                }

                if (!found_match)
                    ++missing_detections;
            }

            for (unsigned long i = 0; i < boxes.size(); ++i)
            {
                // only out put boxes if they match a truth box or are not ignored.
                if (used[i] || !overlaps_any_box(overlap_tester, ignore, boxes[i].second))
                {
                    all_dets.push_back(std::make_pair(boxes[i].first, used[i]));
                }
            }

            return count;
        }

    // ------------------------------------------------------------------------------------

    }

// ----------------------------------------------------------------------------------------

    template <
        typename object_detector_type,
        typename image_array_type
        >
    const matrix<double,1,3> test_object_detection_function (
        object_detector_type& detector,
        const image_array_type& images,
        const std::vector<std::vector<full_object_detection> >& truth_dets,
        const std::vector<std::vector<rectangle> >& ignore,
        const test_box_overlap& overlap_tester = test_box_overlap(),
        const double adjust_threshold = 0
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT( is_learning_problem(images,truth_dets) == true &&
                        ignore.size() == images.size(),
                    "\t matrix test_object_detection_function()"
                    << "\n\t invalid inputs were given to this function"
                    << "\n\t is_learning_problem(images,truth_dets): " << is_learning_problem(images,truth_dets)
                    << "\n\t ignore.size(): " << ignore.size()
                    << "\n\t images.size(): " << images.size()
                    );

        double correct_hits = 0;
        double total_true_targets = 0;

        std::vector<std::pair<double,bool> > all_dets;
        unsigned long missing_detections = 0;

        for (unsigned long i = 0; i < images.size(); ++i)
        {
            std::vector<std::pair<double,rectangle> > hits;
            detector(images[i], hits, adjust_threshold);

            correct_hits += impl::number_of_truth_hits(truth_dets[i], ignore[i], hits, overlap_tester, all_dets, missing_detections);
            total_true_targets += truth_dets[i].size();
        }

        std::sort(all_dets.rbegin(), all_dets.rend());

        double precision, recall;

        double total_hits = all_dets.size();

        if (total_hits == 0)
            precision = 1;
        else
            precision = correct_hits / total_hits;

        if (total_true_targets == 0)
            recall = 1;
        else
            recall = correct_hits / total_true_targets;

        matrix<double, 1, 3> res;
        res = precision, recall, average_precision(all_dets, missing_detections);
        return res;
    }

    template <
        typename object_detector_type,
        typename image_array_type
        >
    const matrix<double,1,3> test_object_detection_function (
        object_detector_type& detector,
        const image_array_type& images,
        const std::vector<std::vector<rectangle> >& truth_dets,
        const std::vector<std::vector<rectangle> >& ignore,
        const test_box_overlap& overlap_tester = test_box_overlap(),
        const double adjust_threshold = 0
    )
    {
        // convert into a list of regular rectangles.
        std::vector<std::vector<full_object_detection> > rects(truth_dets.size());
        for (unsigned long i = 0; i < truth_dets.size(); ++i)
        {
            for (unsigned long j = 0; j < truth_dets[i].size(); ++j)
            {
                rects[i].push_back(full_object_detection(truth_dets[i][j]));
            }
        }

        return test_object_detection_function(detector, images, rects, ignore, overlap_tester, adjust_threshold);
    }

    template <
        typename object_detector_type,
        typename image_array_type
        >
    const matrix<double,1,3> test_object_detection_function (
        object_detector_type& detector,
        const image_array_type& images,
        const std::vector<std::vector<rectangle> >& truth_dets,
        const test_box_overlap& overlap_tester = test_box_overlap(),
        const double adjust_threshold = 0
    )
    {
        std::vector<std::vector<rectangle> > ignore(images.size());
        return test_object_detection_function(detector,images,truth_dets,ignore, overlap_tester, adjust_threshold);
    }

    template <
        typename object_detector_type,
        typename image_array_type
        >
    const matrix<double,1,3> test_object_detection_function (
        object_detector_type& detector,
        const image_array_type& images,
        const std::vector<std::vector<full_object_detection> >& truth_dets,
        const test_box_overlap& overlap_tester = test_box_overlap(),
        const double adjust_threshold = 0
    )
    {
        std::vector<std::vector<rectangle> > ignore(images.size());
        return test_object_detection_function(detector,images,truth_dets,ignore, overlap_tester, adjust_threshold);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    namespace impl
    {
        template <
            typename array_type
            >
        struct array_subset_helper
        {
            typedef typename array_type::mem_manager_type mem_manager_type;

            array_subset_helper (
                const array_type& array_,
                const std::vector<unsigned long>& idx_set_
            ) :
                array(array_),
                idx_set(idx_set_)
            {
            }

            unsigned long size() const { return idx_set.size(); }

            typedef typename array_type::type type;
            const type& operator[] (
                unsigned long idx
            ) const { return array[idx_set[idx]]; }

        private:
            const array_type& array;
            const std::vector<unsigned long>& idx_set;
        };

        template <
            typename T
            >
        const matrix_op<op_array_to_mat<array_subset_helper<T> > > mat (
            const array_subset_helper<T>& m
        )
        {
            typedef op_array_to_mat<array_subset_helper<T> > op;
            return matrix_op<op>(op(m));
        }

    }

// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type,
        typename image_array_type
        >
    const matrix<double,1,3> cross_validate_object_detection_trainer (
        const trainer_type& trainer,
        const image_array_type& images,
        const std::vector<std::vector<full_object_detection> >& truth_dets,
        const std::vector<std::vector<rectangle> >& ignore,
        const long folds,
        const test_box_overlap& overlap_tester = test_box_overlap(),
        const double adjust_threshold = 0
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT( is_learning_problem(images,truth_dets) == true &&
                     ignore.size() == images.size() &&
                     1 < folds && folds <= static_cast<long>(images.size()),
                    "\t matrix cross_validate_object_detection_trainer()"
                    << "\n\t invalid inputs were given to this function"
                    << "\n\t is_learning_problem(images,truth_dets): " << is_learning_problem(images,truth_dets)
                    << "\n\t folds: "<< folds
                    << "\n\t ignore.size(): " << ignore.size()
                    << "\n\t images.size(): " << images.size()
                    );

        double correct_hits = 0;
        double total_true_targets = 0;

        const long test_size = images.size()/folds;

        std::vector<std::pair<double,bool> > all_dets;
        unsigned long missing_detections = 0;
        unsigned long test_idx = 0;
        for (long iter = 0; iter < folds; ++iter)
        {
            std::vector<unsigned long> train_idx_set;
            std::vector<unsigned long> test_idx_set;

            for (long i = 0; i < test_size; ++i)
                test_idx_set.push_back(test_idx++);

            unsigned long train_idx = test_idx%images.size();
            std::vector<std::vector<full_object_detection> > training_rects;
            std::vector<std::vector<rectangle> > training_ignores;
            for (unsigned long i = 0; i < images.size()-test_size; ++i)
            {
                training_rects.push_back(truth_dets[train_idx]);
                training_ignores.push_back(ignore[train_idx]);
                train_idx_set.push_back(train_idx);
                train_idx = (train_idx+1)%images.size();
            }

            impl::array_subset_helper<image_array_type> array_subset(images, train_idx_set);
            typename trainer_type::trained_function_type detector = trainer.train(array_subset, training_rects, training_ignores, overlap_tester);
            for (unsigned long i = 0; i < test_idx_set.size(); ++i)
            {
                std::vector<std::pair<double,rectangle> > hits;
                detector(images[test_idx_set[i]], hits, adjust_threshold);

                correct_hits += impl::number_of_truth_hits(truth_dets[test_idx_set[i]], ignore[i], hits, overlap_tester, all_dets, missing_detections);
                total_true_targets += truth_dets[test_idx_set[i]].size();
            }

        }

        std::sort(all_dets.rbegin(), all_dets.rend());

        double precision, recall;

        double total_hits = all_dets.size();

        if (total_hits == 0)
            precision = 1;
        else
            precision = correct_hits / total_hits;

        if (total_true_targets == 0)
            recall = 1;
        else
            recall = correct_hits / total_true_targets;

        matrix<double, 1, 3> res;
        res = precision, recall, average_precision(all_dets, missing_detections);
        return res;
    }

    template <
        typename trainer_type,
        typename image_array_type
        >
    const matrix<double,1,3> cross_validate_object_detection_trainer (
        const trainer_type& trainer,
        const image_array_type& images,
        const std::vector<std::vector<rectangle> >& truth_dets,
        const std::vector<std::vector<rectangle> >& ignore,
        const long folds,
        const test_box_overlap& overlap_tester = test_box_overlap(),
        const double adjust_threshold = 0
    )
    {
        // convert into a list of regular rectangles.
        std::vector<std::vector<full_object_detection> > dets(truth_dets.size());
        for (unsigned long i = 0; i < truth_dets.size(); ++i)
        {
            for (unsigned long j = 0; j < truth_dets[i].size(); ++j)
            {
                dets[i].push_back(full_object_detection(truth_dets[i][j]));
            }
        }

        return cross_validate_object_detection_trainer(trainer, images, dets, ignore, folds, overlap_tester, adjust_threshold);
    }

    template <
        typename trainer_type,
        typename image_array_type
        >
    const matrix<double,1,3> cross_validate_object_detection_trainer (
        const trainer_type& trainer,
        const image_array_type& images,
        const std::vector<std::vector<rectangle> >& truth_dets,
        const long folds,
        const test_box_overlap& overlap_tester = test_box_overlap(),
        const double adjust_threshold = 0
    )
    {
        const std::vector<std::vector<rectangle> > ignore(images.size());
        return cross_validate_object_detection_trainer(trainer,images,truth_dets,ignore,folds,overlap_tester,adjust_threshold);
    }

    template <
        typename trainer_type,
        typename image_array_type
        >
    const matrix<double,1,3> cross_validate_object_detection_trainer (
        const trainer_type& trainer,
        const image_array_type& images,
        const std::vector<std::vector<full_object_detection> >& truth_dets,
        const long folds,
        const test_box_overlap& overlap_tester = test_box_overlap(),
        const double adjust_threshold = 0
    )
    {
        const std::vector<std::vector<rectangle> > ignore(images.size());
        return cross_validate_object_detection_trainer(trainer,images,truth_dets,ignore,folds,overlap_tester,adjust_threshold);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_CROSS_VALIDATE_OBJECT_DETECTION_TRaINER_Hh_


dlib C++ Library - cross_validate_regression_trainer.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_CROSS_VALIDATE_REGRESSION_TRaINER_Hh_
#define DLIB_CROSS_VALIDATE_REGRESSION_TRaINER_Hh_

#include <vector>
#include "../matrix.h"
#include "../statistics.h"
#include "cross_validate_regression_trainer_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename reg_funct_type,
        typename sample_type,
        typename label_type
        >
    matrix<double,1,2>
    test_regression_function (
        const reg_funct_type& reg_funct,
        const std::vector<sample_type>& x_test,
        const std::vector<label_type>& y_test
    )
    {

        // make sure requires clause is not broken
        DLIB_ASSERT( is_learning_problem(x_test,y_test) == true,
                    "\tmatrix test_regression_function()"
                    << "\n\t invalid inputs were given to this function"
                    << "\n\t is_learning_problem(x_test,y_test): "
                    << is_learning_problem(x_test,y_test));

        running_stats<double> rs;
        running_scalar_covariance<double> rc;

        for (unsigned long i = 0; i < x_test.size(); ++i)
        {
            // compute error
            const double output = reg_funct(x_test[i]);
            const double temp = output - y_test[i];

            rs.add(temp*temp);
            rc.add(output, y_test[i]);
        }

        matrix<double,1,2> result;
        result = rs.mean(), std::pow(rc.correlation(),2);
        return result;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type,
        typename sample_type,
        typename label_type
        >
    matrix<double,1,2>
    cross_validate_regression_trainer (
        const trainer_type& trainer,
        const std::vector<sample_type>& x,
        const std::vector<label_type>& y,
        const long folds
    )
    {

        // make sure requires clause is not broken
        DLIB_ASSERT(is_learning_problem(x,y) == true &&
                    1 < folds && folds <= static_cast<long>(x.size()),
            "\tmatrix cross_validate_regression_trainer()"
            << "\n\t invalid inputs were given to this function"
            << "\n\t x.size(): " << x.size()
            << "\n\t folds:  " << folds
            << "\n\t is_learning_problem(x,y): " << is_learning_problem(x,y)
            );

        const long num_in_test = x.size()/folds;
        const long num_in_train = x.size() - num_in_test;

        running_stats<double> rs;
        running_scalar_covariance<double> rc;

        std::vector<sample_type> x_test, x_train;
        std::vector<label_type> y_test, y_train;

        long next_test_idx = 0;

        for (long i = 0; i < folds; ++i)
        {
            x_test.clear();
            y_test.clear();
            x_train.clear();
            y_train.clear();

            // load up the test samples
            for (long cnt = 0; cnt < num_in_test; ++cnt)
            {
                x_test.push_back(x[next_test_idx]);
                y_test.push_back(y[next_test_idx]);
                next_test_idx = (next_test_idx + 1)%x.size();
            }

            // load up the training samples
            long next = next_test_idx;
            for (long cnt = 0; cnt < num_in_train; ++cnt)
            {
                x_train.push_back(x[next]);
                y_train.push_back(y[next]);
                next = (next + 1)%x.size();
            }

            try
            {
                const typename trainer_type::trained_function_type& df = trainer.train(x_train,y_train);

                // do the training and testing
                for (unsigned long j = 0; j < x_test.size(); ++j)
                {
                    // compute error
                    const double output = df(x_test[j]);
                    const double temp = output - y_test[j];

                    rs.add(temp*temp);
                    rc.add(output, y_test[j]);
                }
            }
            catch (invalid_nu_error&)
            {
                // just ignore cases which result in an invalid nu
            }

        } // for (long i = 0; i < folds; ++i)

        matrix<double,1,2> result;
        result = rs.mean(), std::pow(rc.correlation(),2);
        return result;
    }

}

// ----------------------------------------------------------------------------------------

#endif // DLIB_CROSS_VALIDATE_REGRESSION_TRaINER_Hh_


dlib C++ Library - cross_validate_sequence_labeler.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_CROSS_VALIDATE_SEQUENCE_LABeLER_Hh_
#define DLIB_CROSS_VALIDATE_SEQUENCE_LABeLER_Hh_

#include "cross_validate_sequence_labeler_abstract.h"
#include <vector>
#include "../matrix.h"
#include "svm.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename sequence_labeler_type,
        typename sequence_type
        >
    const matrix<double> test_sequence_labeler (
        const sequence_labeler_type& labeler,
        const std::vector<sequence_type>& samples,
        const std::vector<std::vector<unsigned long> >& labels
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( is_sequence_labeling_problem(samples, labels) == true,
                    "\tmatrix test_sequence_labeler()"
                    << "\n\t invalid inputs were given to this function"
                    << "\n\t is_sequence_labeling_problem(samples, labels): "
                    << is_sequence_labeling_problem(samples, labels));

        matrix<double> res(labeler.num_labels(), labeler.num_labels());
        res = 0;

        std::vector<unsigned long> pred;
        for (unsigned long i = 0; i < samples.size(); ++i)
        {
            labeler.label_sequence(samples[i], pred);

            for (unsigned long j = 0; j < pred.size(); ++j)
            {
                const unsigned long truth = labels[i][j];
                if (truth >= static_cast<unsigned long>(res.nr()))
                {
                    // ignore labels the labeler doesn't know about.
                    continue;
                }

                res(truth, pred[j]) += 1;
            }
        }

        return res;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type,
        typename sequence_type
        >
    const matrix<double> cross_validate_sequence_labeler (
        const trainer_type& trainer,
        const std::vector<sequence_type>& samples,
        const std::vector<std::vector<unsigned long> >& labels,
        const long folds
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(is_sequence_labeling_problem(samples,labels) == true &&
                    1 < folds && folds <= static_cast<long>(samples.size()),
            "\tmatrix cross_validate_sequence_labeler()"
            << "\n\t invalid inputs were given to this function"
            << "\n\t samples.size(): " << samples.size()
            << "\n\t folds:  " << folds
            << "\n\t is_sequence_labeling_problem(samples,labels): " << is_sequence_labeling_problem(samples,labels)
            );

#ifdef ENABLE_ASSERTS
        for (unsigned long i = 0; i < labels.size(); ++i)
        {
            for (unsigned long j = 0; j < labels[i].size(); ++j)
            {
                // make sure requires clause is not broken
                DLIB_ASSERT(labels[i][j] < trainer.num_labels(),
                            "\t matrix cross_validate_sequence_labeler()"
                            << "\n\t The labels are invalid."
                            << "\n\t labels[i][j]: " << labels[i][j]
                            << "\n\t trainer.num_labels(): " << trainer.num_labels()
                            << "\n\t i: " << i
                            << "\n\t j: " << j
                );
            }
        }
#endif

        const long num_in_test = samples.size()/folds;
        const long num_in_train = samples.size() - num_in_test;

        std::vector<sequence_type> x_test, x_train;
        std::vector<std::vector<unsigned long> > y_test, y_train;

        long next_test_idx = 0;

        matrix<double> res;

        for (long i = 0; i < folds; ++i)
        {
            x_test.clear();
            y_test.clear();
            x_train.clear();
            y_train.clear();

            // load up the test samples
            for (long cnt = 0; cnt < num_in_test; ++cnt)
            {
                x_test.push_back(samples[next_test_idx]);
                y_test.push_back(labels[next_test_idx]);
                next_test_idx = (next_test_idx + 1)%samples.size();
            }

            // load up the training samples
            long next = next_test_idx;
            for (long cnt = 0; cnt < num_in_train; ++cnt)
            {
                x_train.push_back(samples[next]);
                y_train.push_back(labels[next]);
                next = (next + 1)%samples.size();
            }

            res += test_sequence_labeler(trainer.train(x_train,y_train), x_test, y_test);

        } // for (long i = 0; i < folds; ++i)

        return res;
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_CROSS_VALIDATE_SEQUENCE_LABeLER_Hh_


dlib C++ Library - cross_validate_sequence_segmenter.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_CROSS_VALIDATE_SEQUENCE_sEGMENTER_Hh_
#define DLIB_CROSS_VALIDATE_SEQUENCE_sEGMENTER_Hh_

#include "cross_validate_sequence_segmenter_abstract.h"
#include "sequence_segmenter.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    namespace impl
    {
        template <
            typename sequence_segmenter_type,
            typename sequence_type
            >
        const matrix<double,1,3> raw_metrics_test_sequence_segmenter (
            const sequence_segmenter_type& segmenter,
            const std::vector<sequence_type>& samples,
            const std::vector<std::vector<std::pair<unsigned long,unsigned long> > >& segments
        )
        {
            std::vector<std::pair<unsigned long,unsigned long> > truth;
            std::vector<std::pair<unsigned long,unsigned long> > pred;

            double true_hits = 0;
            double total_detections = 0;
            double total_true_segments = 0;

            for (unsigned long i = 0; i < samples.size(); ++i)
            {
                segmenter.segment_sequence(samples[i], pred);
                truth = segments[i];
                // sort the segments so they will be in the same orders
                std::sort(truth.begin(), truth.end());
                std::sort(pred.begin(), pred.end());

                total_true_segments += truth.size();
                total_detections += pred.size();

                unsigned long j=0,k=0;
                while (j < pred.size() && k < truth.size())
                {
                    if (pred[j].first == truth[k].first &&
                        pred[j].second == truth[k].second)
                    {
                        ++true_hits;
                        ++j;
                        ++k;
                    }
                    else if (pred[j].first < truth[k].first)
                    {
                        ++j;
                    }
                    else
                    {
                        ++k;
                    }
                }
            }

            matrix<double,1,3> res;
            res = total_detections, total_true_segments, true_hits;
            return res;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename sequence_segmenter_type,
        typename sequence_type
        >
    const matrix<double,1,3> test_sequence_segmenter (
        const sequence_segmenter_type& segmenter,
        const std::vector<sequence_type>& samples,
        const std::vector<std::vector<std::pair<unsigned long,unsigned long> > >& segments
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( is_sequence_segmentation_problem(samples, segments) == true,
                    "\tmatrix test_sequence_segmenter()"
                    << "\n\t invalid inputs were given to this function"
                    << "\n\t is_sequence_segmentation_problem(samples, segments): "
                    << is_sequence_segmentation_problem(samples, segments));

        const matrix<double,1,3> metrics = impl::raw_metrics_test_sequence_segmenter(segmenter, samples, segments);

        const double total_detections    = metrics(0);
        const double total_true_segments = metrics(1);
        const double true_hits           = metrics(2);

        const double precision = (total_detections   ==0) ? 1 : true_hits/total_detections;
        const double recall    = (total_true_segments==0) ? 1 : true_hits/total_true_segments;
        const double f1        = (precision+recall   ==0) ? 0 : 2*precision*recall/(precision+recall);

        matrix<double,1,3> res;
        res = precision, recall, f1;
        return res;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type,
        typename sequence_type
        >
    const matrix<double,1,3> cross_validate_sequence_segmenter (
        const trainer_type& trainer,
        const std::vector<sequence_type>& samples,
        const std::vector<std::vector<std::pair<unsigned long,unsigned long> > >& segments,
        const long folds
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT( is_sequence_segmentation_problem(samples, segments) == true &&
                    1 < folds && folds <= static_cast<long>(samples.size()),
                    "\tmatrix cross_validate_sequence_segmenter()"
                    << "\n\t invalid inputs were given to this function"
                    << "\n\t folds:  " << folds
                    << "\n\t is_sequence_segmentation_problem(samples, segments): "
                    << is_sequence_segmentation_problem(samples, segments));

        const long num_in_test = samples.size()/folds;
        const long num_in_train = samples.size() - num_in_test;

        std::vector<sequence_type> x_test, x_train;
        std::vector<std::vector<std::pair<unsigned long,unsigned long> > > y_test, y_train;

        long next_test_idx = 0;

        matrix<double,1,3> metrics;
        metrics = 0;

        for (long i = 0; i < folds; ++i)
        {
            x_test.clear();
            y_test.clear();
            x_train.clear();
            y_train.clear();

            // load up the test samples
            for (long cnt = 0; cnt < num_in_test; ++cnt)
            {
                x_test.push_back(samples[next_test_idx]);
                y_test.push_back(segments[next_test_idx]);
                next_test_idx = (next_test_idx + 1)%samples.size();
            }

            // load up the training samples
            long next = next_test_idx;
            for (long cnt = 0; cnt < num_in_train; ++cnt)
            {
                x_train.push_back(samples[next]);
                y_train.push_back(segments[next]);
                next = (next + 1)%samples.size();
            }

            metrics += impl::raw_metrics_test_sequence_segmenter(trainer.train(x_train,y_train), x_test, y_test);
        } // for (long i = 0; i < folds; ++i)

        const double total_detections    = metrics(0);
        const double total_true_segments = metrics(1);
        const double true_hits           = metrics(2);

        const double precision = (total_detections   ==0) ? 1 : true_hits/total_detections;
        const double recall    = (total_true_segments==0) ? 1 : true_hits/total_true_segments;
        const double f1        = (precision+recall   ==0) ? 0 : 2*precision*recall/(precision+recall);

        matrix<double,1,3> res;
        res = precision, recall, f1;
        return res;
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_CROSS_VALIDATE_SEQUENCE_sEGMENTER_Hh_


dlib C++ Library - empirical_kernel_map.h

// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_EMPIRICAL_KERNEl_MAP_H_
#define DLIB_EMPIRICAL_KERNEl_MAP_H_

#include "../matrix.h"
#include "empirical_kernel_map_abstract.h"
#include "linearly_independent_subset_finder.h"
#include <vector>
#include "../algs.h"
#include "kernel_matrix.h"
#include "function.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <typename kernel_type, typename EXP>
    const decision_function<kernel_type> convert_to_decision_function (
        const projection_function<kernel_type>& project_funct,
        const matrix_exp<EXP>& vect
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(project_funct.out_vector_size() > 0 && is_vector(vect) &&
                    project_funct.out_vector_size() == vect.size() && project_funct.weights.nc() == project_funct.basis_vectors.size(),
            "\t const decision_function convert_to_decision_function()"
            << "\n\t Invalid inputs to this function."
            << "\n\t project_funct.out_vector_size():    " << project_funct.out_vector_size()
            << "\n\t project_funct.weights.nc():         " << project_funct.weights.nc()
            << "\n\t project_funct.basis_vectors.size(): " << project_funct.basis_vectors.size()
            << "\n\t is_vector(vect):                    " << is_vector(vect)
            << "\n\t vect.size():                        " << vect.size()
            );

        return decision_function<kernel_type>(trans(project_funct.weights)*vect,
                                              0,
                                              project_funct.kernel_function,
                                              project_funct.basis_vectors);
    }

// ----------------------------------------------------------------------------------------

    template <typename kern_type>
    class empirical_kernel_map
    {
    public:

        struct empirical_kernel_map_error : public error
        {
            empirical_kernel_map_error(const std::string& message): error(message) {}
        };

        typedef kern_type kernel_type;
        typedef typename kernel_type::sample_type sample_type;
        typedef typename kernel_type::scalar_type scalar_type;
        typedef typename kernel_type::mem_manager_type mem_manager_type;

        void clear (
        )
        {
            empirical_kernel_map().swap(*this);
        }

        template <typename T>
        void load(
            const kernel_type& kernel_,
            const T& basis_samples
        )
        {
            load_impl(kernel_, mat(basis_samples));
        }

        void load(
            const linearly_independent_subset_finder<kernel_type>& lisf
        )
        {
            if (lisf.size() == 0)
            {
                std::ostringstream sout;
                sout << "An empty linearly_independent_subset_finder was supplied to the\n"
                     << "empirical_kernel_map::load() function.  One reason this might occur\n"
                     << "is if your dataset contains only zero vectors (or vectors \n"
                     << "approximately zero).\n";
                clear();
                throw empirical_kernel_map_error(sout.str());
            }

            kernel = lisf.get_kernel();
            weights = trans(chol(lisf.get_inv_kernel_marix()));
            basis.resize(lisf.size());
            for (unsigned long i = 0; i < basis.size(); ++i)
                basis[i] = lisf[i];

        }

        const kernel_type get_kernel (
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(out_vector_size() > 0,
                "\tconst kernel_type empirical_kernel_map::get_kernel()"
                << "\n\t You have to load this object with a kernel before you can call this function"
                << "\n\t this: " << this
                );

            return kernel;
        }

        long out_vector_size (
        ) const
        {
            return weights.nr();
        }

        unsigned long basis_size (
        ) const
        {
            return basis.size();
        }

        const sample_type& operator[] (
            unsigned long idx
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT( idx < basis_size(),
                "\t const sample_type& empirical_kernel_map::operator[](idx)"
                << "\n\t Invalid inputs to this function."
                << "\n\t basis_size(): " << basis_size()
                << "\n\t this:         " << this
                );

            return basis[idx];
        }

        template <typename EXP>
        const decision_function<kernel_type> convert_to_decision_function (
            const matrix_exp<EXP>& vect
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(out_vector_size() != 0 && is_vector(vect) && out_vector_size() == vect.size(),
                "\t const decision_function empirical_kernel_map::convert_to_decision_function()"
                << "\n\t Invalid inputs to this function."
                << "\n\t out_vector_size(): " << out_vector_size()
                << "\n\t is_vector(vect):   " << is_vector(vect)
                << "\n\t vect.size():       " << vect.size()
                << "\n\t this: " << this
                );

            return decision_function<kernel_type>(trans(weights)*vect, 0, kernel, mat(basis));
        }

        template <typename EXP>
        const distance_function<kernel_type> convert_to_distance_function (
            const matrix_exp<EXP>& vect
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(out_vector_size() != 0 && is_vector(vect) && out_vector_size() == vect.size(),
                "\t const distance_function empirical_kernel_map::convert_to_distance_function()"
                << "\n\t Invalid inputs to this function."
                << "\n\t out_vector_size(): " << out_vector_size()
                << "\n\t is_vector(vect):   " << is_vector(vect)
                << "\n\t vect.size():       " << vect.size()
                << "\n\t this: " << this
                );

            return distance_function<kernel_type>(trans(weights)*vect, dot(vect,vect), kernel, mat(basis));
        }

        const projection_function<kernel_type> get_projection_function (
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(out_vector_size() != 0,
                "\tconst projection_function empirical_kernel_map::get_projection_function()"
                << "\n\t You have to load this object with data before you can call this function"
                << "\n\t this: " << this
                );

            return projection_function<kernel_type>(weights, kernel, mat(basis));
        }

        const matrix<scalar_type,0,0,mem_manager_type> get_transformation_to (
            const empirical_kernel_map& target
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(out_vector_size() != 0 &&
                        target.out_vector_size() != 0 &&
                        get_kernel() == target.get_kernel(),
                "\t const matrix empirical_kernel_map::get_transformation_to(target)"
                << "\n\t Invalid inputs were given to this function"
                << "\n\t out_vector_size():                 " << out_vector_size()
                << "\n\t target.out_vector_size():          " << target.out_vector_size()
                << "\n\t get_kernel()==target.get_kernel(): " << (get_kernel()==target.get_kernel())
                << "\n\t this: " << this
                );

            return target.weights * kernel_matrix(target.get_kernel(),target.basis, basis)*trans(weights);
        }

        void get_transformation_to (
            const empirical_kernel_map& target,
            matrix<scalar_type, 0, 0, mem_manager_type>& tmat,
            projection_function<kernel_type>& partial_projection
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(out_vector_size() != 0 &&
                        target.out_vector_size() != 0 &&
                        get_kernel() == target.get_kernel() &&
                        basis_size() < target.basis_size(),
                "\t void empirical_kernel_map::get_transformation_to(target, tmat, partial_projection)"
                << "\n\t Invalid inputs were given to this function"
                << "\n\t out_vector_size():                 " << out_vector_size()
                << "\n\t target.out_vector_size():          " << target.out_vector_size()
                << "\n\t basis_size():                      " << basis_size()
                << "\n\t target.basis_size():               " << target.basis_size()
                << "\n\t get_kernel()==target.get_kernel(): " << (get_kernel()==target.get_kernel())
                << "\n\t this: " << this
                );

#ifdef ENABLE_ASSERTS
            for (unsigned long i = 0; i < basis_size(); ++i)
            {
                DLIB_ASSERT(dlib::equal((*this)[i], target[i]),
                    "\t const matrix empirical_kernel_map::get_transformation_to(target, tmat, partial_projection)"
                    << "\n\t target must contain a superset of the basis vectors in *this"
                    << "\n\t i: " << i
                    << "\n\t this: " << this
                    );
            }
#endif

            const unsigned long num1 = basis.size();
            const unsigned long num2 = target.basis.size();

            tmat = colm(target.weights, range(0,num1-1))*kernel_matrix(kernel, basis)*trans(weights);

            empirical_kernel_map temp_ekm;
            temp_ekm.load(kernel, rowm(mat(target.basis), range(num1,num2-1)));

            partial_projection = temp_ekm.get_projection_function();

            partial_projection.weights = colm(target.weights,range(num1,num2-1))*
                                   kernel_matrix(kernel, temp_ekm.basis)*
                                   trans(temp_ekm.weights)*
                                   partial_projection.weights;
        }

        const matrix<scalar_type,0,1,mem_manager_type>& project (
            const sample_type& samp
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(out_vector_size() != 0,
                "\tconst matrix empirical_kernel_map::project()"
                << "\n\t You have to load this object with data before you can call this function"
                << "\n\t this: " << this
                );

            temp1 = kernel_matrix(kernel, basis, samp);
            temp2 = weights*temp1;
            return temp2;
        }

        const matrix<scalar_type,0,1,mem_manager_type>& project (
            const sample_type& samp,
            scalar_type& projection_error
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(out_vector_size() != 0,
                "\tconst matrix empirical_kernel_map::project()"
                << "\n\t You have to load this object with data before you can call this function"
                << "\n\t this: " << this
                );

            temp1 = kernel_matrix(kernel, basis, samp);
            temp2 = weights*temp1;
            // This value should never be negative (it measures squared distance) but I'm putting the abs()
            // here just for good measure since rounding error might push it slightly negative.
            projection_error = std::abs( kernel(samp,samp) - dot(temp2,temp2));

            return temp2;
        }

        void swap (
            empirical_kernel_map& item
        )
        {
            basis.swap(item.basis);
            weights.swap(item.weights);
            std::swap(kernel, item.kernel);

            temp1.swap(item.temp1);
            temp2.swap(item.temp2);
        }

        friend void serialize (
            const empirical_kernel_map& item,
            std::ostream& out
        )
        {
            serialize(item.basis, out);
            serialize(item.weights, out);
            serialize(item.kernel, out);
        }

        friend void deserialize (
            empirical_kernel_map& item,
            std::istream& in
        )
        {
            deserialize(item.basis, in);
            deserialize(item.weights, in);
            deserialize(item.kernel, in);
        }

    private:

        template <typename T>
        void load_impl(
            const kernel_type& kernel_,
            const T& basis_samples
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(basis_samples.size() > 0 && is_vector(basis_samples),
                "\tvoid empirical_kernel_map::load(kernel,basis_samples)"
                << "\n\t You have to give a non-empty set of basis_samples and it must be a vector"
                << "\n\t basis_samples.size():     " << basis_samples.size()
                << "\n\t is_vector(basis_samples): " << is_vector(basis_samples)
                << "\n\t this: " << this
                );

            // clear out the weights before we begin.  This way if an exception throws
            // this object will already be in the right state.
            weights.set_size(0,0);
            kernel = kernel_;
            basis.clear();
            basis.reserve(basis_samples.size());

            // find out the value of the largest norm of the elements in basis_samples.
            const scalar_type max_norm = max(diag(kernel_matrix(kernel, basis_samples)));
            // we will consider anything less than or equal to this number to be 0
            const scalar_type eps = max_norm*100*std::numeric_limits<scalar_type>::epsilon();

            // Copy all the basis_samples into basis but make sure we don't copy any samples
            // that have length 0
            for (long i = 0; i < basis_samples.size(); ++i)
            {
                const scalar_type norm = kernel(basis_samples(i), basis_samples(i));
                if (norm > eps)
                {
                    basis.push_back(basis_samples(i));
                }
            }

            if (basis.size() == 0)
            {
                clear();
                throw empirical_kernel_map_error("All basis_samples given to empirical_kernel_map::load() were zero vectors");
            }

            matrix<scalar_type,0,0,mem_manager_type> K(kernel_matrix(kernel, basis)), U,W,V;

            if (svd2(false,true,K,U,W,V))
            {
                clear();
                throw empirical_kernel_map_error("While loading empirical_kernel_map with data, SVD failed to converge.");
            }

            // now count how many elements of W are non-zero
            const long num_not_zero = static_cast<long>(sum(W>eps));

            // Really, this should never happen.  But I'm checking for good measure.
            if (num_not_zero == 0)
            {
                clear();
                throw empirical_kernel_map_error("While loading empirical_kernel_map with data, SVD failed");
            }

            weights.set_size(num_not_zero, basis.size());

            // now fill the weights matrix with the output of the SVD
            long counter = 0;
            for (long i =0; i < W.size(); ++i)
            {
                double val = W(i);
                if (val > eps)
                {
                    val = std::sqrt(val);
                    set_rowm(weights,counter) = rowm(trans(V),i)/val;
                    ++counter;
                }
            }

        }

        std::vector<sample_type> basis;
        matrix<scalar_type,0,0,mem_manager_type> weights;
        kernel_type kernel;

        // These members don't contribute to the logical state of this object.  They are
        // just here so that they don't have to be reallocated every time the project() function
        // is called.
        mutable matrix<scalar_type,0,1,mem_manager_type> temp1, temp2;

    };

    template <typename kernel_type>
    void swap (
        empirical_kernel_map<kernel_type>& a,
        empirical_kernel_map<kernel_type>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_EMPIRICAL_KERNEl_MAP_H_


dlib C++ Library - feature_ranking.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_KERNEL_FEATURE_RANKINg_H_
#define DLIB_KERNEL_FEATURE_RANKINg_H_

#include <vector>
#include <limits>

#include "feature_ranking_abstract.h"
#include "kcentroid.h"
#include "../optimization.h"
#include "../statistics.h"
#include <iostream>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename kernel_type,
        typename sample_matrix_type,
        typename label_matrix_type
        >
    matrix<typename kernel_type::scalar_type,0,2,typename kernel_type::mem_manager_type> rank_features_impl (
        const kcentroid<kernel_type>& kc,
        const sample_matrix_type& samples,
        const label_matrix_type& labels
    )
    {
        /*
            This function ranks features by doing recursive feature elimination

        */
        typedef typename kernel_type::scalar_type scalar_type;
        typedef typename kernel_type::mem_manager_type mm;

        // make sure requires clause is not broken
        DLIB_ASSERT(is_binary_classification_problem(samples, labels) == true,
            "\tmatrix rank_features()"
            << "\n\t you have given invalid arguments to this function"
            );

        matrix<scalar_type,0,2,mm> results(samples(0).nr(), 2);
        matrix<scalar_type,sample_matrix_type::type::NR,1,mm> mask(samples(0).nr());
        set_all_elements(mask,1);

        // figure out what the separation is between the two centroids when all the features are
        // present.
        scalar_type first_separation;
        {
            kcentroid<kernel_type> c1(kc);
            kcentroid<kernel_type> c2(kc);
            // find the centers of each class
            for (long s = 0; s < samples.size(); ++s)
            {
                if (labels(s) < 0)
                {
                    c1.train(samples(s));
                }
                else
                {
                    c2.train(samples(s));
                }

            }
            first_separation = c1(c2);
        }

        using namespace std;

        for (long i = results.nr()-1; i >= 0; --i)
        {
            long worst_feature_idx = 0;
            scalar_type worst_feature_score = -std::numeric_limits<scalar_type>::infinity();

            // figure out which feature to remove next
            for (long j = 0; j < mask.size(); ++j)
            {
                // skip features we have already removed
                if (mask(j) == 0)
                    continue;

                kcentroid<kernel_type> c1(kc);
                kcentroid<kernel_type> c2(kc);

                // temporarily remove this feature from the working set of features
                mask(j) = 0;

                // find the centers of each class
                for (long s = 0; s < samples.size(); ++s)
                {
                    if (labels(s) < 0)
                    {
                        c1.train(pointwise_multiply(samples(s),mask));
                    }
                    else
                    {
                        c2.train(pointwise_multiply(samples(s),mask));
                    }

                }

                // find the distance between the two centroids and use that
                // as the score
                const double score = c1(c2);

                if (score > worst_feature_score)
                {
                    worst_feature_score = score;
                    worst_feature_idx = j;
                }

                // add this feature back to the working set of features
                mask(j) = 1;

            }

            // now that we know what the next worst feature is record it
            mask(worst_feature_idx) = 0;
            results(i,0) = worst_feature_idx;
            results(i,1) = worst_feature_score;
        }

        // now normalize the results
        const scalar_type max_separation = std::max(max(colm(results,1)), first_separation);
        set_colm(results,1) = colm(results,1)/max_separation;
        for (long r = 0; r < results.nr()-1; ++r)
        {
            results(r,1) = results(r+1,1);
        }
        results(results.nr()-1,1) = first_separation/max_separation;

        return results;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename kernel_type,
        typename sample_matrix_type,
        typename label_matrix_type
        >
    matrix<typename kernel_type::scalar_type,0,2,typename kernel_type::mem_manager_type> rank_features (
        const kcentroid<kernel_type>& kc,
        const sample_matrix_type& samples,
        const label_matrix_type& labels
    )
    {
        return rank_features_impl(kc, mat(samples), mat(labels));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename kernel_type,
        typename sample_matrix_type,
        typename label_matrix_type
        >
    matrix<typename kernel_type::scalar_type,0,2,typename kernel_type::mem_manager_type> rank_features_impl (
        const kcentroid<kernel_type>& kc,
        const sample_matrix_type& samples,
        const label_matrix_type& labels,
        const long num_features
    )
    {
        /*
            This function ranks features by doing recursive feature addition

        */
        typedef typename kernel_type::scalar_type scalar_type;
        typedef typename kernel_type::mem_manager_type mm;

        // make sure requires clause is not broken
        DLIB_ASSERT(is_binary_classification_problem(samples, labels) == true,
            "\tmatrix rank_features()"
            << "\n\t you have given invalid arguments to this function"
            );
        DLIB_ASSERT(0 < num_features && num_features <= samples(0).nr(),
            "\tmatrix rank_features()"
            << "\n\t you have given invalid arguments to this function"
            << "\n\t num_features:    " << num_features
            << "\n\t samples(0).nr(): " << samples(0).nr()
            );

        matrix<scalar_type,0,2,mm> results(num_features, 2);
        matrix<scalar_type,sample_matrix_type::type::NR,1,mm> mask(samples(0).nr());
        set_all_elements(mask,0);

        using namespace std;

        for (long i = 0; i < results.nr(); ++i)
        {
            long best_feature_idx = 0;
            scalar_type best_feature_score = -std::numeric_limits<scalar_type>::infinity();

            // figure out which feature to add next
            for (long j = 0; j < mask.size(); ++j)
            {
                // skip features we have already added
                if (mask(j) == 1)
                    continue;

                kcentroid<kernel_type> c1(kc);
                kcentroid<kernel_type> c2(kc);

                // temporarily add this feature to the working set of features
                mask(j) = 1;

                // find the centers of each class
                for (long s = 0; s < samples.size(); ++s)
                {
                    if (labels(s) < 0)
                    {
                        c1.train(pointwise_multiply(samples(s),mask));
                    }
                    else
                    {
                        c2.train(pointwise_multiply(samples(s),mask));
                    }

                }

                // find the distance between the two centroids and use that
                // as the score
                const double score = c1(c2);

                if (score > best_feature_score)
                {
                    best_feature_score = score;
                    best_feature_idx = j;
                }

                // take this feature back out of the working set of features
                mask(j) = 0;

            }

            // now that we know what the next best feature is record it
            mask(best_feature_idx) = 1;
            results(i,0) = best_feature_idx;
            results(i,1) = best_feature_score;
        }

        // now normalize the results
        set_colm(results,1) = colm(results,1)/max(colm(results,1));

        return results;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename kernel_type,
        typename sample_matrix_type,
        typename label_matrix_type
        >
    matrix<typename kernel_type::scalar_type,0,2,typename kernel_type::mem_manager_type> rank_features (
        const kcentroid<kernel_type>& kc,
        const sample_matrix_type& samples,
        const label_matrix_type& labels,
        const long num_features
    )
    {
        if (mat(samples).nr() > 0 && num_features == mat(samples)(0).nr())
        {
            // if we are going to rank them all then might as well do the recursive feature elimination version
            return rank_features_impl(kc, mat(samples), mat(labels));
        }
        else
        {
            return rank_features_impl(kc, mat(samples), mat(labels), num_features);
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    namespace rank_features_helpers
    {
        template <
            typename K,
            typename sample_matrix_type,
            typename label_matrix_type
            >
        typename K::scalar_type centroid_gap (
            const kcentroid<K>& kc,
            const sample_matrix_type& samples,
            const label_matrix_type& labels
        )
        {
            kcentroid<K> kc1(kc);
            kcentroid<K> kc2(kc);

            // toss all the samples into our kcentroids
            for (long i = 0; i < samples.size(); ++i)
            {
                if (labels(i) > 0)
                    kc1.train(samples(i));
                else
                    kc2.train(samples(i));
            }

            // now return the separation between the mean of these two centroids
            return kc1(kc2);
        }

        template <
            typename sample_matrix_type,
            typename label_matrix_type
            >
        class test
        {
            typedef typename sample_matrix_type::type sample_type;
            typedef typename sample_type::type scalar_type;
            typedef typename sample_type::mem_manager_type mem_manager_type;

        public:
            test (
                const sample_matrix_type& samples_,
                const label_matrix_type& labels_,
                unsigned long num_sv_,
                bool verbose_
            ) : samples(samples_), labels(labels_), num_sv(num_sv_), verbose(verbose_)
            {
            }

            double operator() (
                double gamma
            ) const
            {
                using namespace std;

                // we are doing the optimization in log space so don't forget to convert back to normal space
                gamma = std::exp(gamma);

                typedef radial_basis_kernel<sample_type> kernel_type;
                // Make a kcentroid and find out what the gap is at the current gamma.  Try to pick a reasonable
                // tolerance.
                const double tolerance = std::min(gamma*0.01, 0.01);
                const kernel_type kern(gamma);
                kcentroid<kernel_type> kc(kern, tolerance, num_sv);
                scalar_type temp = centroid_gap(kc, samples, labels);

                if (verbose)
                {
                    cout << "\rChecking goodness of gamma = " << gamma << ".  Goodness = "
                         << temp << "                    " << flush;
                }
                return temp;
            }

            const sample_matrix_type& samples;
            const label_matrix_type& labels;
            unsigned long num_sv;
            bool verbose;

        };

        template <
            typename sample_matrix_type,
            typename label_matrix_type
            >
        double find_gamma_with_big_centroid_gap_impl (
            const sample_matrix_type& samples,
            const label_matrix_type& labels,
            double initial_gamma,
            unsigned long num_sv,
            bool verbose
        )
        {
            using namespace std;

            if (verbose)
            {
                cout << endl;
            }

            test<sample_matrix_type, label_matrix_type> funct(samples, labels, num_sv, verbose);
            double best_gamma = std::log(initial_gamma);
            double goodness = find_max_single_variable(funct, best_gamma, -15, 15, 1e-3, 100);

            if (verbose)
            {
                cout << "\rBest gamma = " << std::exp(best_gamma) << ".  Goodness = "
                    << goodness << "                    " << endl;
            }

            return std::exp(best_gamma);
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename sample_matrix_type,
        typename label_matrix_type
        >
    double find_gamma_with_big_centroid_gap (
        const sample_matrix_type& samples,
        const label_matrix_type& labels,
        double initial_gamma = 0.1,
        unsigned long num_sv = 40
    )
    {
        DLIB_ASSERT(initial_gamma > 0 && num_sv > 0 && is_binary_classification_problem(samples, labels),
            "\t double find_gamma_with_big_centroid_gap()"
            << "\n\t initial_gamma: " << initial_gamma
            << "\n\t num_sv:        " << num_sv
            << "\n\t is_binary_classification_problem(): " << is_binary_classification_problem(samples, labels)
            );

        return rank_features_helpers::find_gamma_with_big_centroid_gap_impl(mat(samples),
                                                             mat(labels),
                                                             initial_gamma,
                                                             num_sv,
                                                             false);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename sample_matrix_type,
        typename label_matrix_type
        >
    double verbose_find_gamma_with_big_centroid_gap (
        const sample_matrix_type& samples,
        const label_matrix_type& labels,
        double initial_gamma = 0.1,
        unsigned long num_sv = 40
    )
    {
        DLIB_ASSERT(initial_gamma > 0 && num_sv > 0 && is_binary_classification_problem(samples, labels),
            "\t double verbose_find_gamma_with_big_centroid_gap()"
            << "\n\t initial_gamma: " << initial_gamma
            << "\n\t num_sv:        " << num_sv
            << "\n\t is_binary_classification_problem(): " << is_binary_classification_problem(samples, labels)
            );

        return rank_features_helpers::find_gamma_with_big_centroid_gap_impl(mat(samples),
                                                             mat(labels),
                                                             initial_gamma,
                                                             num_sv,
                                                             true);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type
        >
    double compute_mean_squared_distance (
        const vector_type& samples
    )
    {
        running_stats<double> rs;
        for (unsigned long i = 0; i < samples.size(); ++i)
        {
            for (unsigned long j = i+1; j < samples.size(); ++j)
            {
                rs.add(length_squared(samples[i] - samples[j]));
            }
        }

        return rs.mean();
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_KERNEL_FEATURE_RANKINg_H_


dlib C++ Library - function.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SVm_FUNCTION
#define DLIB_SVm_FUNCTION

#include "function_abstract.h"
#include <cmath>
#include <limits>
#include <sstream>
#include "../matrix.h"
#include "../algs.h"
#include "../serialize.h"
#include "../rand.h"
#include "../statistics.h"
#include "kernel_matrix.h"
#include "kernel.h"
#include "sparse_kernel.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename K
        >
    struct decision_function
    {
        typedef K kernel_type;
        typedef typename K::scalar_type scalar_type;
        typedef typename K::scalar_type result_type;
        typedef typename K::sample_type sample_type;
        typedef typename K::mem_manager_type mem_manager_type;

        typedef matrix<scalar_type,0,1,mem_manager_type> scalar_vector_type;
        typedef matrix<sample_type,0,1,mem_manager_type> sample_vector_type;

        scalar_vector_type alpha;
        scalar_type b;
        K kernel_function;
        sample_vector_type basis_vectors;

        decision_function (
        ) : b(0), kernel_function(K()) {}

        decision_function (
            const decision_function& d
        ) :
            alpha(d.alpha),
            b(d.b),
            kernel_function(d.kernel_function),
            basis_vectors(d.basis_vectors)
        {}

        decision_function (
            const scalar_vector_type& alpha_,
            const scalar_type& b_,
            const K& kernel_function_,
            const sample_vector_type& basis_vectors_
        ) :
            alpha(alpha_),
            b(b_),
            kernel_function(kernel_function_),
            basis_vectors(basis_vectors_)
        {}

        result_type operator() (
            const sample_type& x
        ) const
        {
            result_type temp = 0;
            for (long i = 0; i < alpha.nr(); ++i)
                temp += alpha(i) * kernel_function(x,basis_vectors(i));

            return temp - b;
        }
    };

    template <
        typename K
        >
    void serialize (
        const decision_function<K>& item,
        std::ostream& out
    )
    {
        try
        {
            serialize(item.alpha, out);
            serialize(item.b,     out);
            serialize(item.kernel_function, out);
            serialize(item.basis_vectors, out);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while serializing object of type decision_function");
        }
    }

    template <
        typename K
        >
    void deserialize (
        decision_function<K>& item,
        std::istream& in
    )
    {
        try
        {
            deserialize(item.alpha, in);
            deserialize(item.b, in);
            deserialize(item.kernel_function, in);
            deserialize(item.basis_vectors, in);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while deserializing object of type decision_function");
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename function_type
        >
    struct probabilistic_function
    {
        typedef typename function_type::scalar_type scalar_type;
        typedef typename function_type::result_type result_type;
        typedef typename function_type::sample_type sample_type;
        typedef typename function_type::mem_manager_type mem_manager_type;

        scalar_type alpha;
        scalar_type beta;
        function_type decision_funct;

        probabilistic_function (
        ) : alpha(0), beta(0), decision_funct(function_type()) {}

        probabilistic_function (
            const probabilistic_function& d
        ) :
            alpha(d.alpha),
            beta(d.beta),
            decision_funct(d.decision_funct)
        {}

        probabilistic_function (
            const scalar_type a_,
            const scalar_type b_,
            const function_type& decision_funct_
        ) :
            alpha(a_),
            beta(b_),
            decision_funct(decision_funct_)
        {}

        result_type operator() (
            const sample_type& x
        ) const
        {
            result_type f = decision_funct(x);
            return 1/(1 + std::exp(alpha*f + beta));
        }
    };

    template <
        typename function_type
        >
    void serialize (
        const probabilistic_function<function_type>& item,
        std::ostream& out
    )
    {
        try
        {
            serialize(item.alpha, out);
            serialize(item.beta, out);
            serialize(item.decision_funct, out);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while serializing object of type probabilistic_function");
        }
    }

    template <
        typename function_type
        >
    void deserialize (
        probabilistic_function<function_type>& item,
        std::istream& in
    )
    {
        try
        {
            deserialize(item.alpha, in);
            deserialize(item.beta, in);
            deserialize(item.decision_funct, in);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while deserializing object of type probabilistic_function");
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename K
        >
    struct probabilistic_decision_function
    {
        typedef K kernel_type;
        typedef typename K::scalar_type scalar_type;
        typedef typename K::scalar_type result_type;
        typedef typename K::sample_type sample_type;
        typedef typename K::mem_manager_type mem_manager_type;

        scalar_type alpha;
        scalar_type beta;
        decision_function<K> decision_funct;

        probabilistic_decision_function (
        ) : alpha(0), beta(0), decision_funct(decision_function<K>()) {}

        probabilistic_decision_function (
            const probabilistic_function<decision_function<K> >& d
        ) :
            alpha(d.alpha),
            beta(d.beta),
            decision_funct(d.decision_funct)
        {}

        probabilistic_decision_function (
            const probabilistic_decision_function& d
        ) :
            alpha(d.alpha),
            beta(d.beta),
            decision_funct(d.decision_funct)
        {}

        probabilistic_decision_function (
            const scalar_type a_,
            const scalar_type b_,
            const decision_function<K>& decision_funct_
        ) :
            alpha(a_),
            beta(b_),
            decision_funct(decision_funct_)
        {}

        result_type operator() (
            const sample_type& x
        ) const
        {
            result_type f = decision_funct(x);
            return 1/(1 + std::exp(alpha*f + beta));
        }
    };

    template <
        typename K
        >
    void serialize (
        const probabilistic_decision_function<K>& item,
        std::ostream& out
    )
    {
        try
        {
            serialize(item.alpha, out);
            serialize(item.beta, out);
            serialize(item.decision_funct, out);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while serializing object of type probabilistic_decision_function");
        }
    }

    template <
        typename K
        >
    void deserialize (
        probabilistic_decision_function<K>& item,
        std::istream& in
    )
    {
        try
        {
            deserialize(item.alpha, in);
            deserialize(item.beta, in);
            deserialize(item.decision_funct, in);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while deserializing object of type probabilistic_decision_function");
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename K
        >
    class distance_function
    {
    public:
        typedef K kernel_type;
        typedef typename K::scalar_type scalar_type;
        typedef typename K::scalar_type result_type;
        typedef typename K::sample_type sample_type;
        typedef typename K::mem_manager_type mem_manager_type;

        typedef matrix<scalar_type,0,1,mem_manager_type> scalar_vector_type;
        typedef matrix<sample_type,0,1,mem_manager_type> sample_vector_type;

        distance_function (
        ) : b(0), kernel_function(K()) {}

        explicit distance_function (
            const kernel_type& kern
        ) : b(0), kernel_function(kern) {}

        distance_function (
            const kernel_type& kern,
            const sample_type& samp
        ) :
            alpha(ones_matrix<scalar_type>(1,1)),
            b(kern(samp,samp)),
            kernel_function(kern)
        {
            basis_vectors.set_size(1,1);
            basis_vectors(0) = samp;
        }

        distance_function (
            const decision_function<K>& f
        ) :
            alpha(f.alpha),
            b(trans(f.alpha)*kernel_matrix(f.kernel_function,f.basis_vectors)*f.alpha),
            kernel_function(f.kernel_function),
            basis_vectors(f.basis_vectors)
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(f.alpha.size() == f.basis_vectors.size(),
                "\t distance_function(f)"
                << "\n\t The supplied decision_function is invalid."
                << "\n\t f.alpha.size(): " << f.alpha.size()
                << "\n\t f.basis_vectors.size(): " << f.basis_vectors.size()
                );
        }

        distance_function (
            const distance_function& d
        ) :
            alpha(d.alpha),
            b(d.b),
            kernel_function(d.kernel_function),
            basis_vectors(d.basis_vectors)
        {
        }

        distance_function (
            const scalar_vector_type& alpha_,
            const scalar_type& b_,
            const K& kernel_function_,
            const sample_vector_type& basis_vectors_
        ) :
            alpha(alpha_),
            b(b_),
            kernel_function(kernel_function_),
            basis_vectors(basis_vectors_)
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(alpha_.size() == basis_vectors_.size(),
                "\t distance_function()"
                << "\n\t The supplied arguments are invalid."
                << "\n\t alpha_.size(): " << alpha_.size()
                << "\n\t basis_vectors_.size(): " << basis_vectors_.size()
                );
        }

        distance_function (
            const scalar_vector_type& alpha_,
            const K& kernel_function_,
            const sample_vector_type& basis_vectors_
        ) :
            alpha(alpha_),
            b(trans(alpha)*kernel_matrix(kernel_function_,basis_vectors_)*alpha),
            kernel_function(kernel_function_),
            basis_vectors(basis_vectors_)
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(alpha_.size() == basis_vectors_.size(),
                "\t distance_function()"
                << "\n\t The supplied arguments are invalid."
                << "\n\t alpha_.size(): " << alpha_.size()
                << "\n\t basis_vectors_.size(): " << basis_vectors_.size()
                );
        }

        const scalar_vector_type& get_alpha (
        ) const { return alpha; }

        const scalar_type& get_squared_norm (
        ) const { return b; }

        const K& get_kernel(
        ) const { return kernel_function; }

        const sample_vector_type& get_basis_vectors (
        ) const { return basis_vectors; }

        result_type operator() (
            const sample_type& x
        ) const
        {
            result_type temp = 0;
            for (long i = 0; i < alpha.nr(); ++i)
                temp += alpha(i) * kernel_function(x,basis_vectors(i));

            temp = b + kernel_function(x,x) - 2*temp;
            if (temp > 0)
                return std::sqrt(temp);
            else
                return 0;
        }

        result_type operator() (
            const distance_function& x
        ) const
        {
            result_type temp = 0;
            for (long i = 0; i < alpha.nr(); ++i)
                for (long j = 0; j < x.alpha.nr(); ++j)
                    temp += alpha(i)*x.alpha(j) * kernel_function(basis_vectors(i), x.basis_vectors(j));

            temp = b + x.b - 2*temp;
            if (temp > 0)
                return std::sqrt(temp);
            else
                return 0;
        }

        distance_function operator* (
            const scalar_type& val
        ) const
        {
            return distance_function(val*alpha,
                                     val*val*b,
                                     kernel_function,
                                     basis_vectors);
        }

        distance_function operator/ (
            const scalar_type& val
        ) const
        {
            return distance_function(alpha/val,
                                     b/val/val,
                                     kernel_function,
                                     basis_vectors);
        }

        distance_function operator+ (
            const distance_function& rhs
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(get_kernel() == rhs.get_kernel(),
                "\t distance_function distance_function::operator+()"
                << "\n\t You can only add two distance_functions together if they use the same kernel."
                );

            if (alpha.size() == 0)
                return rhs;
            else if (rhs.alpha.size() == 0)
                return *this;
            else
                return distance_function(join_cols(alpha, rhs.alpha),
                                        b + rhs.b + 2*trans(alpha)*kernel_matrix(kernel_function,basis_vectors,rhs.basis_vectors)*rhs.alpha,
                                        kernel_function,
                                        join_cols(basis_vectors, rhs.basis_vectors));
        }

        distance_function operator- (
            const distance_function& rhs
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(get_kernel() == rhs.get_kernel(),
                "\t distance_function distance_function::operator-()"
                << "\n\t You can only subtract two distance_functions if they use the same kernel."
                );

            if (alpha.size() == 0 && rhs.alpha.size() == 0)
                return distance_function(kernel_function);
            else if (alpha.size() != 0 && rhs.alpha.size() == 0)
                return *this;
            else if (alpha.size() == 0 && rhs.alpha.size() != 0)
                return -1*rhs;
            else
                return distance_function(join_cols(alpha, -rhs.alpha),
                                        b + rhs.b - 2*trans(alpha)*kernel_matrix(kernel_function,basis_vectors,rhs.basis_vectors)*rhs.alpha,
                                        kernel_function,
                                        join_cols(basis_vectors, rhs.basis_vectors));
        }

    private:

        scalar_vector_type alpha;
        scalar_type b;
        K kernel_function;
        sample_vector_type basis_vectors;

    };

    template <
        typename K
        >
    distance_function<K> operator* (
        const typename K::scalar_type& val,
        const distance_function<K>& df
    ) { return df*val; }

    template <
        typename K
        >
    void serialize (
        const distance_function<K>& item,
        std::ostream& out
    )
    {
        try
        {
            serialize(item.alpha, out);
            serialize(item.b,     out);
            serialize(item.kernel_function, out);
            serialize(item.basis_vectors, out);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while serializing object of type distance_function");
        }
    }

    template <
        typename K
        >
    void deserialize (
        distance_function<K>& item,
        std::istream& in
    )
    {
        try
        {
            deserialize(item.alpha, in);
            deserialize(item.b, in);
            deserialize(item.kernel_function, in);
            deserialize(item.basis_vectors, in);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while deserializing object of type distance_function");
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename function_type,
        typename normalizer_type = vector_normalizer<typename function_type::sample_type>
        >
    struct normalized_function
    {
        typedef typename function_type::result_type result_type;
        typedef typename function_type::sample_type sample_type;
        typedef typename function_type::mem_manager_type mem_manager_type;

        normalizer_type normalizer;
        function_type function;

        normalized_function (
        ){}

        normalized_function (
            const normalized_function& f
        ) :
            normalizer(f.normalizer),
            function(f.function)
        {}

        const std::vector<result_type> get_labels(
        ) const { return function.get_labels(); }

        unsigned long number_of_classes (
        ) const { return function.number_of_classes(); }

        normalized_function (
            const vector_normalizer<sample_type>& normalizer_,
            const function_type& funct
        ) : normalizer(normalizer_), function(funct) {}

        result_type operator() (
            const sample_type& x
        ) const { return function(normalizer(x)); }
    };

    template <
        typename function_type,
        typename normalizer_type
        >
    void serialize (
        const normalized_function<function_type,normalizer_type>& item,
        std::ostream& out
    )
    {
        try
        {
            serialize(item.normalizer, out);
            serialize(item.function,     out);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while serializing object of type normalized_function");
        }
    }

    template <
        typename function_type,
        typename normalizer_type
        >
    void deserialize (
        normalized_function<function_type,normalizer_type>& item,
        std::istream& in
    )
    {
        try
        {
            deserialize(item.normalizer, in);
            deserialize(item.function, in);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while deserializing object of type normalized_function");
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename K
        >
    struct projection_function
    {
        typedef K kernel_type;
        typedef typename K::scalar_type scalar_type;
        typedef typename K::sample_type sample_type;
        typedef typename K::mem_manager_type mem_manager_type;

        typedef matrix<scalar_type,0,1,mem_manager_type> scalar_vector_type;
        typedef matrix<scalar_type,0,0,mem_manager_type> scalar_matrix_type;
        typedef matrix<sample_type,0,1,mem_manager_type> sample_vector_type;
        typedef scalar_vector_type result_type;

        scalar_matrix_type weights;
        K                  kernel_function;
        sample_vector_type basis_vectors;

        projection_function (
        ) {}

        projection_function (
            const projection_function& f
        ) : weights(f.weights), kernel_function(f.kernel_function), basis_vectors(f.basis_vectors) {}

        projection_function (
            const scalar_matrix_type& weights_,
            const K& kernel_function_,
            const sample_vector_type& basis_vectors_
        ) : weights(weights_), kernel_function(kernel_function_), basis_vectors(basis_vectors_) {}

        long out_vector_size (
        ) const { return weights.nr(); }

        const result_type& operator() (
            const sample_type& x
        ) const
        {
            // Run the x sample through all the basis functions we have and then
            // multiply it by the weights matrix and return the result.  Note that
            // the temp vectors are here to avoid reallocating their memory every
            // time this function is called.
            temp1 = kernel_matrix(kernel_function, basis_vectors, x);
            temp2 = weights*temp1;
            return temp2;
        }

    private:
        mutable result_type temp1, temp2;
    };

    template <
        typename K
        >
    void serialize (
        const projection_function<K>& item,
        std::ostream& out
    )
    {
        try
        {
            serialize(item.weights, out);
            serialize(item.kernel_function,     out);
            serialize(item.basis_vectors,     out);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while serializing object of type projection_function");
        }
    }

    template <
        typename K
        >
    void deserialize (
        projection_function<K>& item,
        std::istream& in
    )
    {
        try
        {
            deserialize(item.weights, in);
            deserialize(item.kernel_function,     in);
            deserialize(item.basis_vectors,     in);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while deserializing object of type projection_function");
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename K,
        typename result_type_ = typename K::scalar_type
        >
    struct multiclass_linear_decision_function
    {
        typedef result_type_ result_type;

        typedef K kernel_type;
        typedef typename K::scalar_type scalar_type;
        typedef typename K::sample_type sample_type;
        typedef typename K::mem_manager_type mem_manager_type;

        typedef matrix<scalar_type,0,1,mem_manager_type> scalar_vector_type;
        typedef matrix<scalar_type,0,0,mem_manager_type> scalar_matrix_type;

        // You are getting a compiler error on this line because you supplied a non-linear kernel
        // to the multiclass_linear_decision_function object.  You have to use one of the linear
        // kernels with this object.
        COMPILE_TIME_ASSERT((is_same_type<K, linear_kernel<sample_type> >::value ||
                             is_same_type<K, sparse_linear_kernel<sample_type> >::value ));

        scalar_matrix_type       weights;
        scalar_vector_type       b;
        std::vector<result_type> labels;

        const std::vector<result_type>& get_labels(
        ) const { return labels; }

        unsigned long number_of_classes (
        ) const { return labels.size(); }

        std::pair<result_type, scalar_type> predict (
            const sample_type& x
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(weights.size() > 0 &&
                        weights.nr() == (long)number_of_classes() &&
                        weights.nr() == b.size(),
                "\t pair<result_type,scalar_type> multiclass_linear_decision_function::predict(x)"
                << "\n\t This object must be properly initialized before you can use it."
                << "\n\t weights.size():      " << weights.size()
                << "\n\t weights.nr():        " << weights.nr()
                << "\n\t number_of_classes(): " << number_of_classes()
                );

            // Rather than doing something like, best_idx = index_of_max(weights*x-b)
            // we do the following somewhat more complex thing because this supports
            // both sparse and dense samples.
            scalar_type best_val = dot(rowm(weights,0),x) - b(0);
            unsigned long best_idx = 0;

            for (unsigned long i = 1; i < labels.size(); ++i)
            {
                scalar_type temp = dot(rowm(weights,i),x) - b(i);
                if (temp > best_val)
                {
                    best_val = temp;
                    best_idx = i;
                }
            }

            return std::make_pair(labels[best_idx], best_val);
        }

        result_type operator() (
            const sample_type& x
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(weights.size() > 0 &&
                        weights.nr() == (long)number_of_classes() &&
                        weights.nr() == b.size(),
                "\t result_type multiclass_linear_decision_function::operator()(x)"
                << "\n\t This object must be properly initialized before you can use it."
                << "\n\t weights.size():      " << weights.size()
                << "\n\t weights.nr():        " << weights.nr()
                << "\n\t number_of_classes(): " << number_of_classes()
                );

            return predict(x).first;
        }
    };

    template <
        typename K,
        typename result_type_
        >
    void serialize (
        const multiclass_linear_decision_function<K,result_type_>& item,
        std::ostream& out
    )
    {
        try
        {
            serialize(item.weights,         out);
            serialize(item.b,               out);
            serialize(item.labels,          out);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while serializing object of type multiclass_linear_decision_function");
        }
    }

    template <
        typename K,
        typename result_type_
        >
    void deserialize (
        multiclass_linear_decision_function<K,result_type_>& item,
        std::istream& in
    )
    {
        try
        {
            deserialize(item.weights,         in);
            deserialize(item.b,               in);
            deserialize(item.labels,          in);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while deserializing object of type multiclass_linear_decision_function");
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SVm_FUNCTION


dlib C++ Library - kcentroid.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_KCENTROId_
#define DLIB_KCENTROId_

#include <vector>

#include "kcentroid_abstract.h"
#include "../matrix.h"
#include "function.h"
#include "../std_allocator.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <typename kernel_type>
    class kcentroid
    {
        /*!
            This object represents a weighted sum of sample points in a kernel induced
            feature space.  It can be used to kernelize any algorithm that requires only
            the ability to perform vector addition, subtraction, scalar multiplication,
            and inner products.  It uses the sparsification technique described in the
            paper The Kernel Recursive Least Squares Algorithm by Yaakov Engel.

            To understand the code it would also be useful to consult page 114 of the book
            Kernel Methods for Pattern Analysis by Taylor and Cristianini as well as page 554
            (particularly equation 18.31) of the book Learning with Kernels by Scholkopf and
            Smola.  Everything you really need to know is in the Engel paper.  But the other
            books help give more perspective on the issues involved.

            INITIAL VALUE
                - min_strength == 0
                - min_vect_idx == 0
                - K_inv.size() == 0
                - K.size() == 0
                - dictionary.size() == 0
                - bias == 0
                - bias_is_stale == false

            CONVENTION
                - max_dictionary_size() == my_max_dictionary_size
                - get_kernel() == kernel

                - K.nr() == dictionary.size()
                - K.nc() == dictionary.size()
                - for all valid r,c:
                    - K(r,c) == kernel(dictionary[r], dictionary[c])
                - K_inv == inv(K)

                - if (dictionary.size() == my_max_dictionary_size && my_remove_oldest_first == false) then
                    - for all valid 0 < i < dictionary.size():
                        - Let STRENGTHS[i] == the delta you would get for dictionary[i] (i.e. Approximately
                          Linearly Dependent value) if you removed dictionary[i] from this object and then
                          tried to add it back in.
                        - min_strength == the minimum value from STRENGTHS
                        - min_vect_idx == the index of the element in STRENGTHS with the smallest value

        !*/

    public:
        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;

        kcentroid (
        ) :
            my_remove_oldest_first(false),
            my_tolerance(0.001),
            my_max_dictionary_size(1000000),
            bias(0),
            bias_is_stale(false)
        {
            clear_dictionary();
        }

        explicit kcentroid (
            const kernel_type& kernel_,
            scalar_type tolerance_ = 0.001,
            unsigned long max_dictionary_size_ = 1000000,
            bool remove_oldest_first_ = false
        ) :
            my_remove_oldest_first(remove_oldest_first_),
            kernel(kernel_),
            my_tolerance(tolerance_),
            my_max_dictionary_size(max_dictionary_size_),
            bias(0),
            bias_is_stale(false)
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(tolerance_ > 0 && max_dictionary_size_ > 1,
                "\tkcentroid::kcentroid()"
                << "\n\t You have to give a positive tolerance"
                << "\n\t this:                 " << this
                << "\n\t tolerance_:           " << tolerance_
                << "\n\t max_dictionary_size_: " << max_dictionary_size_
                );

            clear_dictionary();
        }

        scalar_type tolerance() const
        {
            return my_tolerance;
        }

        unsigned long max_dictionary_size() const
        {
            return my_max_dictionary_size;
        }

        bool remove_oldest_first (
        ) const
        {
            return my_remove_oldest_first;
        }

        const kernel_type& get_kernel (
        ) const
        {
            return kernel;
        }

        void clear_dictionary ()
        {
            dictionary.clear();
            alpha.clear();

            min_strength = 0;
            min_vect_idx = 0;
            K_inv.set_size(0,0);
            K.set_size(0,0);
            samples_seen = 0;
            bias = 0;
            bias_is_stale = false;
        }

        scalar_type operator() (
            const kcentroid& x
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(x.get_kernel() == get_kernel(),
                "\tscalar_type kcentroid::operator()(const kcentroid& x)"
                << "\n\tYou can only compare two kcentroid objects if they use the same kernel"
                << "\n\tthis: " << this
                );

            // make sure the bias terms are up to date
            refresh_bias();
            x.refresh_bias();

            scalar_type temp = x.bias + bias - 2*inner_product(x);

            if (temp > 0)
                return std::sqrt(temp);
            else
                return 0;
        }

        scalar_type inner_product (
            const sample_type& x
        ) const
        {
            scalar_type temp = 0;
            for (unsigned long i = 0; i < alpha.size(); ++i)
                temp += alpha[i]*kernel(dictionary[i], x);
            return temp;
        }

        scalar_type inner_product (
            const kcentroid& x
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(x.get_kernel() == get_kernel(),
                "\tscalar_type kcentroid::inner_product(const kcentroid& x)"
                << "\n\tYou can only compare two kcentroid objects if they use the same kernel"
                << "\n\tthis: " << this
                );

            scalar_type temp = 0;
            for (unsigned long i = 0; i < alpha.size(); ++i)
            {
                for (unsigned long j = 0; j < x.alpha.size(); ++j)
                {
                    temp += alpha[i]*x.alpha[j]*kernel(dictionary[i], x.dictionary[j]);
                }
            }
            return temp;
        }

        scalar_type squared_norm (
        ) const
        {
            refresh_bias();
            return bias;
        }

        scalar_type operator() (
            const sample_type& x
        ) const
        {
            // make sure the bias terms are up to date
            refresh_bias();

            const scalar_type kxx = kernel(x,x);

            scalar_type temp = kxx + bias - 2*inner_product(x);
            if (temp > 0)
                return std::sqrt(temp);
            else
                return 0;
        }

        scalar_type samples_trained (
        ) const
        {
            return samples_seen;
        }

        scalar_type test_and_train (
            const sample_type& x
        )
        {
            ++samples_seen;
            const scalar_type xscale = 1/samples_seen;
            const scalar_type cscale = 1-xscale;
            return train_and_maybe_test(x,cscale,xscale,true);
        }

        void train (
            const sample_type& x
        )
        {
            ++samples_seen;
            const scalar_type xscale = 1/samples_seen;
            const scalar_type cscale = 1-xscale;
            train_and_maybe_test(x,cscale,xscale,false);
        }

        scalar_type test_and_train (
            const sample_type& x,
            scalar_type cscale,
            scalar_type xscale
        )
        {
            ++samples_seen;
            return train_and_maybe_test(x,cscale,xscale,true);
        }

        void scale_by (
            scalar_type cscale
        )
        {
            for (unsigned long i = 0; i < alpha.size(); ++i)
            {
                alpha[i] = cscale*alpha[i];
            }
        }

        void train (
            const sample_type& x,
            scalar_type cscale,
            scalar_type xscale
        )
        {
            ++samples_seen;
            train_and_maybe_test(x,cscale,xscale,false);
        }

        void swap (
            kcentroid& item
        )
        {
            exchange(min_strength, item.min_strength);
            exchange(min_vect_idx, item.min_vect_idx);
            exchange(my_remove_oldest_first, item.my_remove_oldest_first);

            exchange(kernel, item.kernel);
            dictionary.swap(item.dictionary);
            alpha.swap(item.alpha);
            K_inv.swap(item.K_inv);
            K.swap(item.K);
            exchange(my_tolerance, item.my_tolerance);
            exchange(samples_seen, item.samples_seen);
            exchange(bias, item.bias);
            a.swap(item.a);
            k.swap(item.k);
            exchange(bias_is_stale, item.bias_is_stale);
            exchange(my_max_dictionary_size, item.my_max_dictionary_size);
        }

        unsigned long dictionary_size (
        ) const { return dictionary.size(); }

        friend void serialize(const kcentroid& item, std::ostream& out)
        {
            serialize(item.min_strength, out);
            serialize(item.min_vect_idx, out);
            serialize(item.my_remove_oldest_first, out);

            serialize(item.kernel, out);
            serialize(item.dictionary, out);
            serialize(item.alpha, out);
            serialize(item.K_inv, out);
            serialize(item.K, out);
            serialize(item.my_tolerance, out);
            serialize(item.samples_seen, out);
            serialize(item.bias, out);
            serialize(item.bias_is_stale, out);
            serialize(item.my_max_dictionary_size, out);
        }

        friend void deserialize(kcentroid& item, std::istream& in)
        {
            deserialize(item.min_strength, in);
            deserialize(item.min_vect_idx, in);
            deserialize(item.my_remove_oldest_first, in);

            deserialize(item.kernel, in);
            deserialize(item.dictionary, in);
            deserialize(item.alpha, in);
            deserialize(item.K_inv, in);
            deserialize(item.K, in);
            deserialize(item.my_tolerance, in);
            deserialize(item.samples_seen, in);
            deserialize(item.bias, in);
            deserialize(item.bias_is_stale, in);
            deserialize(item.my_max_dictionary_size, in);
        }

        distance_function<kernel_type> get_distance_function (
        ) const
        {
            refresh_bias();
            return distance_function<kernel_type>(mat(alpha),
                                                  bias,
                                                  kernel,
                                                  mat(dictionary));
        }

    private:

        void refresh_bias (
        ) const
        {
            if (bias_is_stale)
            {
                bias_is_stale = false;
                // recompute the bias term
                bias = sum(pointwise_multiply(K, mat(alpha)*trans(mat(alpha))));
            }
        }

        scalar_type train_and_maybe_test (
            const sample_type& x,
            scalar_type cscale,
            scalar_type xscale,
            bool do_test
        )
        {
            scalar_type test_result = 0;
            const scalar_type kx = kernel(x,x);
            if (alpha.size() == 0)
            {
                // just ignore this sample if it is the zero vector (or really close to being zero)
                if (std::abs(kx) > std::numeric_limits<scalar_type>::epsilon())
                {
                    // set initial state since this is the first training example we have seen

                    K_inv.set_size(1,1);
                    K_inv(0,0) = 1/kx;
                    K.set_size(1,1);
                    K(0,0) = kx;

                    alpha.push_back(xscale);
                    dictionary.push_back(x);
                }
                else
                {
                    // the distance from an empty kcentroid and the zero vector is zero by definition.
                    return 0;
                }
            }
            else
            {
                // fill in k
                k.set_size(alpha.size());
                for (long r = 0; r < k.nr(); ++r)
                    k(r) = kernel(x,dictionary[r]);

                if (do_test)
                {
                    refresh_bias();
                    test_result = std::sqrt(kx + bias - 2*trans(mat(alpha))*k);
                }

                // compute the error we would have if we approximated the new x sample
                // with the dictionary.  That is, do the ALD test from the KRLS paper.
                a = K_inv*k;
                scalar_type delta = kx - trans(k)*a;

                // if this new vector isn't approximately linearly dependent on the vectors
                // in our dictionary.
                if (delta > min_strength && delta > my_tolerance)
                {
                    bool need_to_update_min_strength = false;
                    if (dictionary.size() >= my_max_dictionary_size)
                    {
                        // We need to remove one of the old members of the dictionary before
                        // we proceed with adding a new one.
                        long idx_to_remove;
                        if (my_remove_oldest_first)
                        {
                            // remove the oldest one
                            idx_to_remove = 0;
                        }
                        else
                        {
                            // if we have never computed the min_strength then we should compute it
                            if (min_strength == 0)
                                recompute_min_strength();

                            // select the dictionary vector that is most linearly dependent for removal
                            idx_to_remove = min_vect_idx;
                            need_to_update_min_strength = true;
                        }

                        remove_dictionary_vector(idx_to_remove);

                        // recompute these guys since they were computed with the old
                        // kernel matrix
                        k = remove_row(k,idx_to_remove);
                        a = K_inv*k;
                        delta = kx - trans(k)*a;
                    }

                    // add x to the dictionary
                    dictionary.push_back(x);

                    // update K_inv by computing the new one in the temp matrix (equation 3.14)
                    matrix<scalar_type,0,0,mem_manager_type> temp(K_inv.nr()+1, K_inv.nc()+1);
                    // update the middle part of the matrix
                    set_subm(temp, get_rect(K_inv)) = K_inv + a*trans(a)/delta;
                    // update the right column of the matrix
                    set_subm(temp, 0, K_inv.nr(),K_inv.nr(),1) = -a/delta;
                    // update the bottom row of the matrix
                    set_subm(temp, K_inv.nr(), 0, 1, K_inv.nr()) = trans(-a/delta);
                    // update the bottom right corner of the matrix
                    temp(K_inv.nr(), K_inv.nc()) = 1/delta;
                    // put temp into K_inv
                    temp.swap(K_inv);

                    // update K (the kernel matrix)
                    temp.set_size(K.nr()+1, K.nc()+1);
                    set_subm(temp, get_rect(K)) = K;
                    // update the right column of the matrix
                    set_subm(temp, 0, K.nr(),K.nr(),1) = k;
                    // update the bottom row of the matrix
                    set_subm(temp, K.nr(), 0, 1, K.nr()) = trans(k);
                    temp(K.nr(), K.nc()) = kx;
                    // put temp into K
                    temp.swap(K);

                    // now update the alpha vector
                    for (unsigned long i = 0; i < alpha.size(); ++i)
                    {
                        alpha[i] *= cscale;
                    }
                    alpha.push_back(xscale);

                    if (need_to_update_min_strength)
                    {
                        // now we have to recompute the min_strength in this case
                        recompute_min_strength();
                    }
                }
                else
                {
                    // update the alpha vector so that this new sample has been added into
                    // the mean vector we are accumulating
                    for (unsigned long i = 0; i < alpha.size(); ++i)
                    {
                        alpha[i] = cscale*alpha[i] + xscale*a(i);
                    }
                }
            }

            bias_is_stale = true;

            return test_result;
        }

        void remove_dictionary_vector (
            long i
        )
        /*!
            requires
                - 0 <= i < dictionary.size()
            ensures
                - #dictionary.size() == dictionary.size() - 1
                - #alpha.size() == alpha.size() - 1
                - updates the K_inv matrix so that it is still a proper inverse of the
                  kernel matrix
                - also removes the necessary row and column from the K matrix
                - uses the this->a variable so after this function runs that variable
                  will contain a different value.
        !*/
        {
            // remove the dictionary vector
            dictionary.erase(dictionary.begin()+i);

            // remove the i'th vector from the inverse kernel matrix.  This formula is basically
            // just the reverse of the way K_inv is updated by equation 3.14 during normal training.
            K_inv = removerc(K_inv,i,i) - remove_row(colm(K_inv,i)/K_inv(i,i),i)*remove_col(rowm(K_inv,i),i);

            // now compute the updated alpha values to take account that we just removed one of
            // our dictionary vectors
            a = (K_inv*remove_row(K,i)*mat(alpha));

            // now copy over the new alpha values
            alpha.resize(alpha.size()-1);
            for (unsigned long k = 0; k < alpha.size(); ++k)
            {
                alpha[k] = a(k);
            }

            // update the K matrix as well
            K = removerc(K,i,i);
        }

        void recompute_min_strength (
        )
        /*!
            ensures
                - recomputes the min_strength and min_vect_idx values
                  so that they are correct with respect to the CONVENTION
                - uses the this->a variable so after this function runs that variable
                  will contain a different value.
        !*/
        {
            min_strength = std::numeric_limits<scalar_type>::max();

            // here we loop over each dictionary vector and compute what its delta would be if
            // we were to remove it from the dictionary and then try to add it back in.
            for (unsigned long i = 0; i < dictionary.size(); ++i)
            {
                // compute a = K_inv*k but where dictionary vector i has been removed
                a = (removerc(K_inv,i,i) - remove_row(colm(K_inv,i)/K_inv(i,i),i)*remove_col(rowm(K_inv,i),i)) *
                    (remove_row(colm(K,i),i));
                scalar_type delta = K(i,i) - trans(remove_row(colm(K,i),i))*a;

                if (delta < min_strength)
                {
                    min_strength = delta;
                    min_vect_idx = i;
                }
            }
        }

        typedef std_allocator<sample_type, mem_manager_type> alloc_sample_type;
        typedef std_allocator<scalar_type, mem_manager_type> alloc_scalar_type;
        typedef std::vector<sample_type,alloc_sample_type> dictionary_vector_type;
        typedef std::vector<scalar_type,alloc_scalar_type> alpha_vector_type;

        scalar_type min_strength;
        unsigned long min_vect_idx;
        bool my_remove_oldest_first;

        kernel_type kernel;
        dictionary_vector_type dictionary;
        alpha_vector_type alpha;

        matrix<scalar_type,0,0,mem_manager_type> K_inv;
        matrix<scalar_type,0,0,mem_manager_type> K;

        scalar_type my_tolerance;
        unsigned long my_max_dictionary_size;
        scalar_type samples_seen;
        mutable scalar_type bias;
        mutable bool bias_is_stale;

        // temp variables here just so we don't have to reconstruct them over and over.  Thus,
        // they aren't really part of the state of this object.
        matrix<scalar_type,0,1,mem_manager_type> a;
        matrix<scalar_type,0,1,mem_manager_type> k;

    };

// ----------------------------------------------------------------------------------------

    template <typename kernel_type>
    void swap(kcentroid<kernel_type>& a, kcentroid<kernel_type>& b)
    { a.swap(b); }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_KCENTROId_


dlib C++ Library - kcentroid_overloads.h

// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_KCENTROId_OVERLOADS_
#define DLIB_KCENTROId_OVERLOADS_

#include "kcentroid_abstract.h"
#include "sparse_kernel.h"
#include "sparse_vector.h"
#include <map>

namespace dlib
{
    /*
        This file contains optimized overloads of the kcentroid object for the following
        linear cases:
            kcentroid<linear_kernel<T>>
            kcentroid<sparse_linear_kernel<T>>
            kcentroid<offset_kernel<linear_kernel<T>>>
            kcentroid<offset_kernel<sparse_linear_kernel<T>>>
    */

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                     Overloads for when kernel_type == linear_kernel
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <typename T>
    class kcentroid<linear_kernel<T> >
    {

        typedef linear_kernel<T> kernel_type;
    public:
        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;

        explicit kcentroid (
            const kernel_type& kernel_,
            scalar_type tolerance_ = 0.001,
            unsigned long max_dictionary_size_ = 1000000,
            bool remove_oldest_first_ = false
        ) :
            my_remove_oldest_first(remove_oldest_first_),
            kernel(kernel_),
            my_tolerance(tolerance_),
            my_max_dictionary_size(max_dictionary_size_)
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(tolerance_ >= 0 && max_dictionary_size_ > 0,
                "\tkcentroid::kcentroid()"
                << "\n\t You have to give a positive tolerance"
                << "\n\t this:                 " << this
                << "\n\t tolerance_:           " << tolerance_
                << "\n\t max_dictionary_size_: " << max_dictionary_size_
                );

            clear_dictionary();
        }

        scalar_type     tolerance() const               { return my_tolerance; }
        unsigned long   max_dictionary_size() const     { return my_max_dictionary_size; }
        bool            remove_oldest_first () const    { return my_remove_oldest_first; }
        const kernel_type& get_kernel () const          { return kernel; }
        scalar_type     samples_trained () const        { return samples_seen; }

        void clear_dictionary ()
        {
            samples_seen = 0;
            set_all_elements(w, 0);
            alpha = 0;
        }

        scalar_type operator() (
            const kcentroid& x
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(x.get_kernel() == get_kernel(),
                "\tscalar_type kcentroid::operator()(const kcentroid& x)"
                << "\n\tYou can only compare two kcentroid objects if they use the same kernel"
                << "\n\tthis: " << this
                );

            if (w.size() > 0)
            {
                if (x.w.size() > 0)
                    return length(alpha*w - x.alpha*x.w);
                else
                    return alpha*length(w);
            }
            else
            {
                if (x.w.size() > 0)
                    return x.alpha*length(x.w);
                else
                    return 0;
            }
        }

        scalar_type inner_product (
            const sample_type& x
        ) const
        {
            if (w.size() > 0)
                return alpha*trans(w)*x;
            else
                return 0;
        }

        scalar_type inner_product (
            const kcentroid& x
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(x.get_kernel() == get_kernel(),
                "\tscalar_type kcentroid::inner_product(const kcentroid& x)"
                << "\n\tYou can only compare two kcentroid objects if they use the same kernel"
                << "\n\tthis: " << this
                );

            if (w.size() > 0 && x.w.size() > 0)
                return alpha*x.alpha*trans(w)*x.w;
            else
                return 0;
        }

        scalar_type squared_norm (
        ) const
        {
            if (w.size() > 0)
                return alpha*alpha*trans(w)*w;
            else
                return 0;
        }

        scalar_type operator() (
            const sample_type& x
        ) const
        {
            if (w.size() > 0)
                return length(x-alpha*w);
            else
                return length(x);
        }

        scalar_type test_and_train (
            const sample_type& x
        )
        {
            ++samples_seen;
            const scalar_type xscale = 1/samples_seen;
            const scalar_type cscale = 1-xscale;

            do_train(x, cscale, xscale);

            return (*this)(x);
        }

        void train (
            const sample_type& x
        )
        {
            ++samples_seen;
            const scalar_type xscale = 1/samples_seen;
            const scalar_type cscale = 1-xscale;

            do_train(x, cscale, xscale);
        }

        scalar_type test_and_train (
            const sample_type& x,
            scalar_type cscale,
            scalar_type xscale
        )
        {
            ++samples_seen;

            do_train(x, cscale, xscale);

            return (*this)(x);
        }

        void scale_by (
            scalar_type cscale
        )
        {
            alpha *= cscale;
        }

        void train (
            const sample_type& x,
            scalar_type cscale,
            scalar_type xscale
        )
        {
            ++samples_seen;
            do_train(x, cscale, xscale);
        }

        void swap (
            kcentroid& item
        )
        {
            exchange(my_remove_oldest_first, item.my_remove_oldest_first);
            exchange(kernel, item.kernel);
            exchange(w, item.w);
            exchange(alpha, item.alpha);
            exchange(my_tolerance, item.my_tolerance);
            exchange(my_max_dictionary_size, item.my_max_dictionary_size);
            exchange(samples_seen, item.samples_seen);
        }

        unsigned long dictionary_size (
        ) const
        {
            if (samples_seen > 0)
                return 1;
            else
                return 0;
        }

        friend void serialize(const kcentroid& item, std::ostream& out)
        {
            serialize(item.my_remove_oldest_first, out);
            serialize(item.kernel, out);
            serialize(item.w, out);
            serialize(item.alpha, out);
            serialize(item.my_tolerance, out);
            serialize(item.my_max_dictionary_size, out);
            serialize(item.samples_seen, out);
        }

        friend void deserialize(kcentroid& item, std::istream& in)
        {
            deserialize(item.my_remove_oldest_first, in);
            deserialize(item.kernel, in);
            deserialize(item.w, in);
            deserialize(item.alpha, in);
            deserialize(item.my_tolerance, in);
            deserialize(item.my_max_dictionary_size, in);
            deserialize(item.samples_seen, in);
        }

        distance_function<kernel_type> get_distance_function (
        ) const
        {
            if (samples_seen > 0)
            {
                typename distance_function<kernel_type>::sample_vector_type temp_basis_vectors;
                typename distance_function<kernel_type>::scalar_vector_type temp_alpha;

                temp_basis_vectors.set_size(1);
                temp_basis_vectors(0) = w;
                temp_alpha.set_size(1);
                temp_alpha(0) = alpha;

                return distance_function<kernel_type>(temp_alpha, squared_norm(), kernel, temp_basis_vectors);
            }
            else
            {
                return distance_function<kernel_type>(kernel);
            }
        }

    private:

        void do_train (
            const sample_type& x,
            scalar_type cscale,
            scalar_type xscale
        )
        {
            set_size_of_w(x);

            const scalar_type temp = cscale*alpha;

            if (temp != 0)
            {
                w = w + xscale*x/temp;
                alpha = temp;
            }
            else
            {
                w = cscale*alpha*w + xscale*x;
                alpha = 1;
            }
        }

        void set_size_of_w (
            const sample_type& x
        )
        {
            if (x.size() != w.size())
            {
                w.set_size(x.nr(), x.nc());
                set_all_elements(w, 0);
                alpha = 0;
            }
        }

        bool my_remove_oldest_first;

        kernel_type kernel;

        sample_type w;
        scalar_type alpha;

        scalar_type my_tolerance;
        unsigned long my_max_dictionary_size;
        scalar_type samples_seen;

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//               Overloads for when kernel_type == offset_kernel<linear_kernel>
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <typename T>
    class kcentroid<offset_kernel<linear_kernel<T> > >
    {

        /*!
            INITIAL VALUE
                - x_extra == sqrt(kernel.offset)

            CONVENTION
                - x_extra == sqrt(kernel.offset)
                - w_extra == the value of the extra dimension tacked onto the
                  end of the w vector
        !*/

        typedef offset_kernel<linear_kernel<T> > kernel_type;
    public:
        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;

        explicit kcentroid (
            const kernel_type& kernel_,
            scalar_type tolerance_ = 0.001,
            unsigned long max_dictionary_size_ = 1000000,
            bool remove_oldest_first_ = false
        ) :
            my_remove_oldest_first(remove_oldest_first_),
            kernel(kernel_),
            my_tolerance(tolerance_),
            my_max_dictionary_size(max_dictionary_size_)
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(tolerance_ >= 0 && max_dictionary_size_ > 0,
                "\tkcentroid::kcentroid()"
                << "\n\t You have to give a positive tolerance"
                << "\n\t this:                 " << this
                << "\n\t tolerance_:           " << tolerance_
                << "\n\t max_dictionary_size_: " << max_dictionary_size_
                );

            x_extra = std::sqrt(kernel.offset);

            clear_dictionary();
        }

        scalar_type     tolerance() const               { return my_tolerance; }
        unsigned long   max_dictionary_size() const     { return my_max_dictionary_size; }
        bool            remove_oldest_first () const    { return my_remove_oldest_first; }
        const kernel_type& get_kernel () const          { return kernel; }
        scalar_type     samples_trained () const        { return samples_seen; }

        void clear_dictionary ()
        {
            samples_seen = 0;
            set_all_elements(w, 0);
            alpha = 0;
            w_extra = x_extra;
        }

        scalar_type operator() (
            const kcentroid& x
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(x.get_kernel() == get_kernel(),
                "\tscalar_type kcentroid::operator()(const kcentroid& x)"
                << "\n\tYou can only compare two kcentroid objects if they use the same kernel"
                << "\n\tthis: " << this
                );

            if (w.size() > 0)
            {
                if (x.w.size() > 0)
                {
                    scalar_type temp1 = length_squared(alpha*w - x.alpha*x.w);
                    scalar_type temp2 = alpha*w_extra - x.alpha*x.w_extra;
                    return std::sqrt(temp1 + temp2*temp2);
                }
                else
                {
                    return alpha*std::sqrt(length_squared(w) + w_extra*w_extra);
                }
            }
            else
            {
                if (x.w.size() > 0)
                    return x.alpha*std::sqrt(length_squared(x.w) + x.w_extra*x.w_extra);
                else
                    return 0;
            }
        }

        scalar_type inner_product (
            const sample_type& x
        ) const
        {
            if (w.size() > 0)
                return alpha*(trans(w)*x + w_extra*x_extra);
            else
                return 0;
        }

        scalar_type inner_product (
            const kcentroid& x
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(x.get_kernel() == get_kernel(),
                "\tscalar_type kcentroid::inner_product(const kcentroid& x)"
                << "\n\tYou can only compare two kcentroid objects if they use the same kernel"
                << "\n\tthis: " << this
                );

            if (w.size() > 0 && x.w.size() > 0)
                return alpha*x.alpha*(trans(w)*x.w + w_extra*x.w_extra);
            else
                return 0;
        }

        scalar_type squared_norm (
        ) const
        {
            if (w.size() > 0)
                return alpha*alpha*(trans(w)*w + w_extra*w_extra);
            else
                return 0;
        }

        scalar_type operator() (
            const sample_type& x
        ) const
        {
            if (w.size() > 0)
            {
                scalar_type temp1 = length_squared(x-alpha*w);
                scalar_type temp2 = x_extra - alpha*w_extra;
                return std::sqrt(temp1 + temp2*temp2);
            }
            else
            {
                return std::sqrt(length_squared(x) + x_extra*x_extra);
            }
        }

        scalar_type test_and_train (
            const sample_type& x
        )
        {
            ++samples_seen;
            const scalar_type xscale = 1/samples_seen;
            const scalar_type cscale = 1-xscale;

            do_train(x, cscale, xscale);

            return (*this)(x);
        }

        void train (
            const sample_type& x
        )
        {
            ++samples_seen;
            const scalar_type xscale = 1/samples_seen;
            const scalar_type cscale = 1-xscale;

            do_train(x, cscale, xscale);
        }

        scalar_type test_and_train (
            const sample_type& x,
            scalar_type cscale,
            scalar_type xscale
        )
        {
            ++samples_seen;

            do_train(x, cscale, xscale);

            return (*this)(x);
        }

        void scale_by (
            scalar_type cscale
        )
        {
            alpha *= cscale;
            w_extra *= cscale;
        }

        void train (
            const sample_type& x,
            scalar_type cscale,
            scalar_type xscale
        )
        {
            ++samples_seen;
            do_train(x, cscale, xscale);
        }

        void swap (
            kcentroid& item
        )
        {
            exchange(my_remove_oldest_first, item.my_remove_oldest_first);
            exchange(kernel, item.kernel);
            exchange(w, item.w);
            exchange(alpha, item.alpha);
            exchange(w_extra, item.w_extra);
            exchange(x_extra, item.x_extra);
            exchange(my_tolerance, item.my_tolerance);
            exchange(my_max_dictionary_size, item.my_max_dictionary_size);
            exchange(samples_seen, item.samples_seen);
        }

        unsigned long dictionary_size (
        ) const
        {
            if (samples_seen > 0)
            {
                if (std::abs(w_extra) > std::numeric_limits<scalar_type>::epsilon())
                    return 1;
                else
                    return 2;
            }
            else
                return 0;
        }

        friend void serialize(const kcentroid& item, std::ostream& out)
        {
            serialize(item.my_remove_oldest_first, out);
            serialize(item.kernel, out);
            serialize(item.w, out);
            serialize(item.alpha, out);
            serialize(item.w_extra, out);
            serialize(item.x_extra, out);
            serialize(item.my_tolerance, out);
            serialize(item.my_max_dictionary_size, out);
            serialize(item.samples_seen, out);
        }

        friend void deserialize(kcentroid& item, std::istream& in)
        {
            deserialize(item.my_remove_oldest_first, in);
            deserialize(item.kernel, in);
            deserialize(item.w, in);
            deserialize(item.alpha, in);
            deserialize(item.w_extra, in);
            deserialize(item.x_extra, in);
            deserialize(item.my_tolerance, in);
            deserialize(item.my_max_dictionary_size, in);
            deserialize(item.samples_seen, in);
        }

        distance_function<kernel_type> get_distance_function (
        ) const
        {

            if (samples_seen > 0)
            {
                typename distance_function<kernel_type>::sample_vector_type temp_basis_vectors;
                typename distance_function<kernel_type>::scalar_vector_type temp_alpha;

                // What we are doing here needs a bit of explanation.  The w vector
                // has an implicit extra dimension tacked on to it with the value of w_extra.
                // The kernel we are using takes normal vectors and implicitly tacks the value
                // x_extra onto their end.  So what we are doing here is scaling w so that
                // the value it should have tacked onto it is x_scale.  Note that we also
                // adjust alpha so that the combination of alpha*w stays the same.
                scalar_type scale;

                // if w_extra is basically greater than 0
                if (std::abs(w_extra) > std::numeric_limits<scalar_type>::epsilon())
                {
                    scale = (x_extra/w_extra);
                    temp_basis_vectors.set_size(1);
                    temp_alpha.set_size(1);
                    temp_basis_vectors(0) = w*scale;
                    temp_alpha(0) = alpha/scale;
                }
                else
                {
                    // In this case w_extra is zero. So the only way we can get the same
                    // thing in the output basis vector set is by using two vectors
                    temp_basis_vectors.set_size(2);
                    temp_alpha.set_size(2);
                    temp_basis_vectors(0) = 2*w;
                    temp_alpha(0) = alpha;
                    temp_basis_vectors(1) = w;
                    temp_alpha(1) = -alpha;
                }

                return distance_function<kernel_type>(temp_alpha, squared_norm(), kernel, temp_basis_vectors);
            }
            else
            {
                return distance_function<kernel_type>(kernel);
            }
        }

    private:

        void do_train (
            const sample_type& x,
            scalar_type cscale,
            scalar_type xscale
        )
        {
            set_size_of_w(x);

            const scalar_type temp = cscale*alpha;

            if (temp != 0)
            {
                w = w + xscale*x/temp;
                w_extra = w_extra + xscale*x_extra/temp;
                alpha = temp;
            }
            else
            {
                w = cscale*alpha*w + xscale*x;
                w_extra = cscale*alpha*w_extra + xscale*x_extra;
                alpha = 1;
            }
        }

        void set_size_of_w (
            const sample_type& x
        )
        {
            if (x.size() != w.size())
            {
                w.set_size(x.nr(), x.nc());
                set_all_elements(w, 0);
                alpha = 0;
                w_extra = x_extra;
            }
        }

        bool my_remove_oldest_first;

        kernel_type kernel;

        sample_type w;
        scalar_type alpha;

        scalar_type w_extra;
        scalar_type x_extra;

        scalar_type my_tolerance;
        unsigned long my_max_dictionary_size;
        scalar_type samples_seen;

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                     Overloads for when kernel_type == sparse_linear_kernel
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <typename T>
    class kcentroid<sparse_linear_kernel<T> >
    {

        typedef sparse_linear_kernel<T> kernel_type;
    public:
        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;

        explicit kcentroid (
            const kernel_type& kernel_,
            scalar_type tolerance_ = 0.001,
            unsigned long max_dictionary_size_ = 1000000,
            bool remove_oldest_first_ = false
        ) :
            my_remove_oldest_first(remove_oldest_first_),
            kernel(kernel_),
            my_tolerance(tolerance_),
            my_max_dictionary_size(max_dictionary_size_)
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(tolerance_ >= 0 && max_dictionary_size_ > 0,
                "\tkcentroid::kcentroid()"
                << "\n\t You have to give a positive tolerance"
                << "\n\t this:                 " << this
                << "\n\t tolerance_:           " << tolerance_
                << "\n\t max_dictionary_size_: " << max_dictionary_size_
                );

            clear_dictionary();
        }

        scalar_type     tolerance() const               { return my_tolerance; }
        unsigned long   max_dictionary_size() const     { return my_max_dictionary_size; }
        bool            remove_oldest_first () const    { return my_remove_oldest_first; }
        const kernel_type& get_kernel () const          { return kernel; }
        scalar_type     samples_trained () const        { return samples_seen; }

        void clear_dictionary ()
        {
            samples_seen = 0;
            w.clear();
            alpha = 0;
        }

        scalar_type operator() (
            const kcentroid& x
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(x.get_kernel() == get_kernel(),
                "\tscalar_type kcentroid::operator()(const kcentroid& x)"
                << "\n\tYou can only compare two kcentroid objects if they use the same kernel"
                << "\n\tthis: " << this
                );

            return distance(alpha,w , x.alpha,x.w);
        }

        scalar_type inner_product (
            const sample_type& x
        ) const
        {
            return alpha*dot(w,x);
        }

        scalar_type inner_product (
            const kcentroid& x
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(x.get_kernel() == get_kernel(),
                "\tscalar_type kcentroid::inner_product(const kcentroid& x)"
                << "\n\tYou can only compare two kcentroid objects if they use the same kernel"
                << "\n\tthis: " << this
                );

            return alpha*x.alpha*dot(w,x.w);
        }

        scalar_type squared_norm (
        ) const
        {
            return alpha*alpha*length_squared(w);
        }

        scalar_type operator() (
            const sample_type& x
        ) const
        {
            return distance(static_cast<scalar_type>(1), x, alpha, w);
        }

        scalar_type test_and_train (
            const sample_type& x
        )
        {
            ++samples_seen;
            const scalar_type xscale = 1/samples_seen;
            const scalar_type cscale = 1-xscale;

            do_train(x, cscale, xscale);

            return (*this)(x);
        }

        void train (
            const sample_type& x
        )
        {
            ++samples_seen;
            const scalar_type xscale = 1/samples_seen;
            const scalar_type cscale = 1-xscale;

            do_train(x, cscale, xscale);
        }

        scalar_type test_and_train (
            const sample_type& x,
            scalar_type cscale,
            scalar_type xscale
        )
        {
            ++samples_seen;

            do_train(x, cscale, xscale);

            return (*this)(x);
        }

        void scale_by (
            scalar_type cscale
        )
        {
            alpha *= cscale;
        }

        void train (
            const sample_type& x,
            scalar_type cscale,
            scalar_type xscale
        )
        {
            ++samples_seen;
            do_train(x, cscale, xscale);
        }

        void swap (
            kcentroid& item
        )
        {
            exchange(my_remove_oldest_first, item.my_remove_oldest_first);
            exchange(kernel, item.kernel);
            exchange(w, item.w);
            exchange(alpha, item.alpha);
            exchange(my_tolerance, item.my_tolerance);
            exchange(my_max_dictionary_size, item.my_max_dictionary_size);
            exchange(samples_seen, item.samples_seen);
        }

        unsigned long dictionary_size (
        ) const
        {
            if (samples_seen > 0)
                return 1;
            else
                return 0;
        }

        friend void serialize(const kcentroid& item, std::ostream& out)
        {
            serialize(item.my_remove_oldest_first, out);
            serialize(item.kernel, out);
            serialize(item.w, out);
            serialize(item.alpha, out);
            serialize(item.my_tolerance, out);
            serialize(item.my_max_dictionary_size, out);
            serialize(item.samples_seen, out);
        }

        friend void deserialize(kcentroid& item, std::istream& in)
        {
            deserialize(item.my_remove_oldest_first, in);
            deserialize(item.kernel, in);
            deserialize(item.w, in);
            deserialize(item.alpha, in);
            deserialize(item.my_tolerance, in);
            deserialize(item.my_max_dictionary_size, in);
            deserialize(item.samples_seen, in);
        }

        distance_function<kernel_type> get_distance_function (
        ) const
        {
            if (samples_seen > 0)
            {
                typename distance_function<kernel_type>::sample_vector_type temp_basis_vectors;
                typename distance_function<kernel_type>::scalar_vector_type temp_alpha;

                temp_basis_vectors.set_size(1);
                temp_basis_vectors(0) = sample_type(w.begin(), w.end());
                temp_alpha.set_size(1);
                temp_alpha(0) = alpha;

                return distance_function<kernel_type>(temp_alpha, squared_norm(), kernel, temp_basis_vectors);
            }
            else
            {
                return distance_function<kernel_type>(kernel);
            }
        }

    private:

        void do_train (
            const sample_type& x,
            scalar_type cscale,
            scalar_type xscale
        )
        {
            const scalar_type temp = cscale*alpha;

            if (temp != 0)
            {
                // compute w += xscale*x/temp
                typename sample_type::const_iterator i;
                for (i = x.begin(); i != x.end(); ++i)
                {
                    w[i->first] += xscale*(i->second)/temp;
                }

                alpha = temp;
            }
            else
            {
                // first compute w = cscale*alpha*w
                for (typename std::map<unsigned long,scalar_type>::iterator i = w.begin(); i != w.end(); ++i)
                {
                    i->second *= cscale*alpha;
                }

                // now compute w += xscale*x
                for (typename sample_type::const_iterator i = x.begin(); i != x.end(); ++i)
                {
                    w[i->first] += xscale*(i->second);
                }

                alpha = 1;
            }
        }

        bool my_remove_oldest_first;

        kernel_type kernel;

        std::map<unsigned long,scalar_type> w;
        scalar_type alpha;

        scalar_type my_tolerance;
        unsigned long my_max_dictionary_size;
        scalar_type samples_seen;

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//               Overloads for when kernel_type == offset_kernel<sparse_linear_kernel>
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <typename T>
    class kcentroid<offset_kernel<sparse_linear_kernel<T> > >
    {

        /*!
            INITIAL VALUE
                - x_extra == sqrt(kernel.offset)

            CONVENTION
                - x_extra == sqrt(kernel.offset)
                - w_extra == the value of the extra dimension tacked onto the
                  end of the w vector
        !*/

        typedef offset_kernel<sparse_linear_kernel<T> > kernel_type;
    public:
        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;

        explicit kcentroid (
            const kernel_type& kernel_,
            scalar_type tolerance_ = 0.001,
            unsigned long max_dictionary_size_ = 1000000,
            bool remove_oldest_first_ = false
        ) :
            my_remove_oldest_first(remove_oldest_first_),
            kernel(kernel_),
            my_tolerance(tolerance_),
            my_max_dictionary_size(max_dictionary_size_)
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(tolerance_ >= 0 && max_dictionary_size_ > 0,
                "\tkcentroid::kcentroid()"
                << "\n\t You have to give a positive tolerance"
                << "\n\t this:                 " << this
                << "\n\t tolerance_:           " << tolerance_
                << "\n\t max_dictionary_size_: " << max_dictionary_size_
                );

            x_extra = std::sqrt(kernel.offset);

            clear_dictionary();
        }

        scalar_type     tolerance() const               { return my_tolerance; }
        unsigned long   max_dictionary_size() const     { return my_max_dictionary_size; }
        bool            remove_oldest_first () const    { return my_remove_oldest_first; }
        const kernel_type& get_kernel () const          { return kernel; }
        scalar_type     samples_trained () const        { return samples_seen; }

        void clear_dictionary ()
        {
            samples_seen = 0;
            w.clear();
            alpha = 0;
            w_extra = x_extra;
        }

        scalar_type operator() (
            const kcentroid& x
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(x.get_kernel() == get_kernel(),
                "\tscalar_type kcentroid::operator()(const kcentroid& x)"
                << "\n\tYou can only compare two kcentroid objects if they use the same kernel"
                << "\n\tthis: " << this
                );

            if (samples_seen > 0)
            {
                scalar_type temp1 = distance_squared(alpha,w , x.alpha,x.w);
                scalar_type temp2 = alpha*w_extra - x.alpha*x.w_extra;
                return std::sqrt(temp1 + temp2*temp2);
            }
            else
            {
                return 0;
            }
        }

        scalar_type inner_product (
            const sample_type& x
        ) const
        {
            if (samples_seen > 0)
                return alpha*(dot(w,x) + w_extra*x_extra);
            else
                return 0;
        }

        scalar_type inner_product (
            const kcentroid& x
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(x.get_kernel() == get_kernel(),
                "\tscalar_type kcentroid::inner_product(const kcentroid& x)"
                << "\n\tYou can only compare two kcentroid objects if they use the same kernel"
                << "\n\tthis: " << this
                );

            if (samples_seen > 0 && x.samples_seen > 0)
                return alpha*x.alpha*(dot(w,x.w) + w_extra*x.w_extra);
            else
                return 0;
        }

        scalar_type squared_norm (
        ) const
        {
            if (samples_seen > 0)
                return alpha*alpha*(length_squared(w) + w_extra*w_extra);
            else
                return 0;
        }

        scalar_type operator() (
            const sample_type& x
        ) const
        {
            if (samples_seen > 0)
            {
                scalar_type temp1 = distance_squared(1,x,alpha,w);
                scalar_type temp2 = x_extra - alpha*w_extra;
                return std::sqrt(temp1 + temp2*temp2);
            }
            else
            {
                return std::sqrt(length_squared(x) + x_extra*x_extra);
            }
        }

        scalar_type test_and_train (
            const sample_type& x
        )
        {
            ++samples_seen;
            const scalar_type xscale = 1/samples_seen;
            const scalar_type cscale = 1-xscale;

            do_train(x, cscale, xscale);

            return (*this)(x);
        }

        void train (
            const sample_type& x
        )
        {
            ++samples_seen;
            const scalar_type xscale = 1/samples_seen;
            const scalar_type cscale = 1-xscale;

            do_train(x, cscale, xscale);
        }

        scalar_type test_and_train (
            const sample_type& x,
            scalar_type cscale,
            scalar_type xscale
        )
        {
            ++samples_seen;

            do_train(x, cscale, xscale);

            return (*this)(x);
        }

        void scale_by (
            scalar_type cscale
        )
        {
            alpha *= cscale;
            w_extra *= cscale;
        }

        void train (
            const sample_type& x,
            scalar_type cscale,
            scalar_type xscale
        )
        {
            ++samples_seen;
            do_train(x, cscale, xscale);
        }

        void swap (
            kcentroid& item
        )
        {
            exchange(my_remove_oldest_first, item.my_remove_oldest_first);
            exchange(kernel, item.kernel);
            exchange(w, item.w);
            exchange(alpha, item.alpha);
            exchange(w_extra, item.w_extra);
            exchange(x_extra, item.x_extra);
            exchange(my_tolerance, item.my_tolerance);
            exchange(my_max_dictionary_size, item.my_max_dictionary_size);
            exchange(samples_seen, item.samples_seen);
        }

        unsigned long dictionary_size (
        ) const
        {
            if (samples_seen > 0)
            {
                if (std::abs(w_extra) > std::numeric_limits<scalar_type>::epsilon())
                    return 1;
                else
                    return 2;
            }
            else
            {
                return 0;
            }
        }

        friend void serialize(const kcentroid& item, std::ostream& out)
        {
            serialize(item.my_remove_oldest_first, out);
            serialize(item.kernel, out);
            serialize(item.w, out);
            serialize(item.alpha, out);
            serialize(item.w_extra, out);
            serialize(item.x_extra, out);
            serialize(item.my_tolerance, out);
            serialize(item.my_max_dictionary_size, out);
            serialize(item.samples_seen, out);
        }

        friend void deserialize(kcentroid& item, std::istream& in)
        {
            deserialize(item.my_remove_oldest_first, in);
            deserialize(item.kernel, in);
            deserialize(item.w, in);
            deserialize(item.alpha, in);
            deserialize(item.w_extra, in);
            deserialize(item.x_extra, in);
            deserialize(item.my_tolerance, in);
            deserialize(item.my_max_dictionary_size, in);
            deserialize(item.samples_seen, in);
        }

        distance_function<kernel_type> get_distance_function (
        ) const
        {
            if (samples_seen > 0)
            {
                typename distance_function<kernel_type>::sample_vector_type temp_basis_vectors;
                typename distance_function<kernel_type>::scalar_vector_type temp_alpha;

                // What we are doing here needs a bit of explanation.  The w vector
                // has an implicit extra dimension tacked on to it with the value of w_extra.
                // The kernel we are using takes normal vectors and implicitly tacks the value
                // x_extra onto their end.  So what we are doing here is scaling w so that
                // the value it should have tacked onto it is x_scale.  Note that we also
                // adjust alpha so that the combination of alpha*w stays the same.
                scalar_type scale;

                // if w_extra is basically greater than 0
                if (std::abs(w_extra) > std::numeric_limits<scalar_type>::epsilon())
                {
                    scale = (x_extra/w_extra);
                    temp_basis_vectors.set_size(1);
                    temp_alpha.set_size(1);
                    temp_basis_vectors(0) = sample_type(w.begin(), w.end());
                    dlib::scale_by(temp_basis_vectors(0), scale);
                    temp_alpha(0) = alpha/scale;
                }
                else
                {
                    // In this case w_extra is zero. So the only way we can get the same
                    // thing in the output basis vector set is by using two vectors
                    temp_basis_vectors.set_size(2);
                    temp_alpha.set_size(2);
                    temp_basis_vectors(0) = sample_type(w.begin(), w.end());
                    dlib::scale_by(temp_basis_vectors(0), 2);
                    temp_alpha(0) = alpha;
                    temp_basis_vectors(1) = sample_type(w.begin(), w.end());
                    temp_alpha(1) = -alpha;
                }

                return distance_function<kernel_type>(temp_alpha, squared_norm(), kernel, temp_basis_vectors);

            }
            else
            {
                return distance_function<kernel_type>(kernel);
            }

        }

    private:

        void do_train (
            const sample_type& x,
            scalar_type cscale,
            scalar_type xscale
        )
        {

            const scalar_type temp = cscale*alpha;

            if (temp != 0)
            {
                // compute w += xscale*x/temp
                typename sample_type::const_iterator i;
                for (i = x.begin(); i != x.end(); ++i)
                {
                    w[i->first] += xscale*(i->second)/temp;
                }

                w_extra = w_extra + xscale*x_extra/temp;
                alpha = temp;
            }
            else
            {
                // first compute w = cscale*alpha*w
                for (typename std::map<unsigned long,scalar_type>::iterator i = w.begin(); i != w.end(); ++i)
                {
                    i->second *= cscale*alpha;
                }

                // now compute w += xscale*x
                for (typename sample_type::const_iterator i = x.begin(); i != x.end(); ++i)
                {
                    w[i->first] += xscale*(i->second);
                }

                w_extra = cscale*alpha*w_extra + xscale*x_extra;
                alpha = 1;
            }
        }

        bool my_remove_oldest_first;

        kernel_type kernel;

        std::map<unsigned long,scalar_type> w;
        scalar_type alpha;

        scalar_type w_extra;
        scalar_type x_extra;

        scalar_type my_tolerance;
        unsigned long my_max_dictionary_size;
        scalar_type samples_seen;

    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_KCENTROId_OVERLOADS_


dlib C++ Library - kernel.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SVm_KERNEL
#define DLIB_SVm_KERNEL

#include "kernel_abstract.h"
#include <cmath>
#include <limits>
#include <sstream>
#include "../matrix.h"
#include "../algs.h"
#include "../serialize.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template < typename kernel_type > struct kernel_derivative;

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    struct radial_basis_kernel
    {
        typedef typename T::type scalar_type;
        typedef T sample_type;
        typedef typename T::mem_manager_type mem_manager_type;

        // T must be capable of representing a column vector.
        COMPILE_TIME_ASSERT(T::NC == 1 || T::NC == 0);

        radial_basis_kernel(const scalar_type g) : gamma(g) {}
        radial_basis_kernel() : gamma(0.1) {}
        radial_basis_kernel(
            const radial_basis_kernel& k
        ) : gamma(k.gamma) {}

        const scalar_type gamma;

        scalar_type operator() (
            const sample_type& a,
            const sample_type& b
        ) const
        {
            const scalar_type d = trans(a-b)*(a-b);
            return std::exp(-gamma*d);
        }

        radial_basis_kernel& operator= (
            const radial_basis_kernel& k
        )
        {
            const_cast<scalar_type&>(gamma) = k.gamma;
            return *this;
        }

        bool operator== (
            const radial_basis_kernel& k
        ) const
        {
            return gamma == k.gamma;
        }
    };

    template <
        typename T
        >
    void serialize (
        const radial_basis_kernel<T>& item,
        std::ostream& out
    )
    {
        try
        {
            serialize(item.gamma, out);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while serializing object of type radial_basis_kernel");
        }
    }

    template <
        typename T
        >
    void deserialize (
        radial_basis_kernel<T>& item,
        std::istream& in
    )
    {
        typedef typename T::type scalar_type;
        try
        {
            deserialize(const_cast<scalar_type&>(item.gamma), in);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while deserializing object of type radial_basis_kernel");
        }
    }

    template <
        typename T
        >
    struct kernel_derivative<radial_basis_kernel<T> >
    {
        typedef typename T::type scalar_type;
        typedef T sample_type;
        typedef typename T::mem_manager_type mem_manager_type;

        kernel_derivative(const radial_basis_kernel<T>& k_) : k(k_){}

        const sample_type& operator() (const sample_type& x, const sample_type& y) const
        {
            // return the derivative of the rbf kernel
            temp = 2*k.gamma*(x-y)*k(x,y);
            return temp;
        }

        const radial_basis_kernel<T>& k;
        mutable sample_type temp;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    struct polynomial_kernel
    {
        typedef typename T::type scalar_type;
        typedef T sample_type;
        typedef typename T::mem_manager_type mem_manager_type;

        // T must be capable of representing a column vector.
        COMPILE_TIME_ASSERT(T::NC == 1 || T::NC == 0);

        polynomial_kernel(const scalar_type g, const scalar_type c, const scalar_type d) : gamma(g), coef(c), degree(d) {}
        polynomial_kernel() : gamma(1), coef(0), degree(1) {}
        polynomial_kernel(
            const polynomial_kernel& k
        ) : gamma(k.gamma), coef(k.coef), degree(k.degree) {}

        typedef T type;
        const scalar_type gamma;
        const scalar_type coef;
        const scalar_type degree;

        scalar_type operator() (
            const sample_type& a,
            const sample_type& b
        ) const
        {
            return std::pow(gamma*(trans(a)*b) + coef, degree);
        }

        polynomial_kernel& operator= (
            const polynomial_kernel& k
        )
        {
            const_cast<scalar_type&>(gamma) = k.gamma;
            const_cast<scalar_type&>(coef) = k.coef;
            const_cast<scalar_type&>(degree) = k.degree;
            return *this;
        }

        bool operator== (
            const polynomial_kernel& k
        ) const
        {
            return (gamma == k.gamma) && (coef == k.coef) && (degree == k.degree);
        }
    };

    template <
        typename T
        >
    void serialize (
        const polynomial_kernel<T>& item,
        std::ostream& out
    )
    {
        try
        {
            serialize(item.gamma, out);
            serialize(item.coef, out);
            serialize(item.degree, out);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while serializing object of type polynomial_kernel");
        }
    }

    template <
        typename T
        >
    void deserialize (
        polynomial_kernel<T>& item,
        std::istream& in
    )
    {
        typedef typename T::type scalar_type;
        try
        {
            deserialize(const_cast<scalar_type&>(item.gamma), in);
            deserialize(const_cast<scalar_type&>(item.coef), in);
            deserialize(const_cast<scalar_type&>(item.degree), in);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while deserializing object of type polynomial_kernel");
        }
    }

    template <
        typename T
        >
    struct kernel_derivative<polynomial_kernel<T> >
    {
        typedef typename T::type scalar_type;
        typedef T sample_type;
        typedef typename T::mem_manager_type mem_manager_type;

        kernel_derivative(const polynomial_kernel<T>& k_) : k(k_){}

        const sample_type& operator() (const sample_type& x, const sample_type& y) const
        {
            // return the derivative of the rbf kernel
            temp = k.degree*k.gamma*x*std::pow(k.gamma*(trans(x)*y) + k.coef, k.degree-1);
            return temp;
        }

        const polynomial_kernel<T>& k;
        mutable sample_type temp;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    struct sigmoid_kernel
    {
        typedef typename T::type scalar_type;
        typedef T sample_type;
        typedef typename T::mem_manager_type mem_manager_type;

        // T must be capable of representing a column vector.
        COMPILE_TIME_ASSERT(T::NC == 1 || T::NC == 0);

        sigmoid_kernel(const scalar_type g, const scalar_type c) : gamma(g), coef(c) {}
        sigmoid_kernel() : gamma(0.1), coef(-1.0) {}
        sigmoid_kernel(
            const sigmoid_kernel& k
        ) : gamma(k.gamma), coef(k.coef) {}

        typedef T type;
        const scalar_type gamma;
        const scalar_type coef;

        scalar_type operator() (
            const sample_type& a,
            const sample_type& b
        ) const
        {
            return std::tanh(gamma*(trans(a)*b) + coef);
        }

        sigmoid_kernel& operator= (
            const sigmoid_kernel& k
        )
        {
            const_cast<scalar_type&>(gamma) = k.gamma;
            const_cast<scalar_type&>(coef) = k.coef;
            return *this;
        }

        bool operator== (
            const sigmoid_kernel& k
        ) const
        {
            return (gamma == k.gamma) && (coef == k.coef);
        }
    };

    template <
        typename T
        >
    void serialize (
        const sigmoid_kernel<T>& item,
        std::ostream& out
    )
    {
        try
        {
            serialize(item.gamma, out);
            serialize(item.coef, out);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while serializing object of type sigmoid_kernel");
        }
    }

    template <
        typename T
        >
    void deserialize (
        sigmoid_kernel<T>& item,
        std::istream& in
    )
    {
        typedef typename T::type scalar_type;
        try
        {
            deserialize(const_cast<scalar_type&>(item.gamma), in);
            deserialize(const_cast<scalar_type&>(item.coef), in);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while deserializing object of type sigmoid_kernel");
        }
    }

    template <
        typename T
        >
    struct kernel_derivative<sigmoid_kernel<T> >
    {
        typedef typename T::type scalar_type;
        typedef T sample_type;
        typedef typename T::mem_manager_type mem_manager_type;

        kernel_derivative(const sigmoid_kernel<T>& k_) : k(k_){}

        const sample_type& operator() (const sample_type& x, const sample_type& y) const
        {
            // return the derivative of the rbf kernel
            temp = k.gamma*x*(1-std::pow(k(x,y),2));
            return temp;
        }

        const sigmoid_kernel<T>& k;
        mutable sample_type temp;
    };

// ----------------------------------------------------------------------------------------

    template <typename T>
    struct linear_kernel
    {
        typedef typename T::type scalar_type;
        typedef T sample_type;
        typedef typename T::mem_manager_type mem_manager_type;

        // T must be capable of representing a column vector.
        COMPILE_TIME_ASSERT(T::NC == 1 || T::NC == 0);

        scalar_type operator() (
            const sample_type& a,
            const sample_type& b
        ) const
        {
            return trans(a)*b;
        }

        bool operator== (
            const linear_kernel&
        ) const
        {
            return true;
        }
    };

    template <
        typename T
        >
    void serialize (
        const linear_kernel<T>& ,
        std::ostream&
    ){}

    template <
        typename T
        >
    void deserialize (
        linear_kernel<T>& ,
        std::istream&
    ){}

    template <
        typename T
        >
    struct kernel_derivative<linear_kernel<T> >
    {
        typedef typename T::type scalar_type;
        typedef T sample_type;
        typedef typename T::mem_manager_type mem_manager_type;

        kernel_derivative(const linear_kernel<T>& k_) : k(k_){}

        const sample_type& operator() (const sample_type& x, const sample_type& ) const
        {
            return x;
        }

        const linear_kernel<T>& k;
    };

// ----------------------------------------------------------------------------------------

    template <typename T>
    struct histogram_intersection_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
        {
            scalar_type temp = 0;
            for (long i = 0; i < a.size(); ++i)
            {
                temp += std::min(a(i), b(i));
            }
            return temp;
        }

        bool operator== (
            const histogram_intersection_kernel&
        ) const
        {
            return true;
        }
    };

    template <
        typename T
        >
    void serialize (
        const histogram_intersection_kernel<T>& ,
        std::ostream&
    ){}

    template <
        typename T
        >
    void deserialize (
        histogram_intersection_kernel<T>& ,
        std::istream&
    ){}

// ----------------------------------------------------------------------------------------

    template <typename T>
    struct offset_kernel
    {
        typedef typename T::scalar_type scalar_type;
        typedef typename T::sample_type sample_type;
        typedef typename T::mem_manager_type mem_manager_type;

        offset_kernel(const T& k, const scalar_type& offset_
        ) : kernel(k), offset(offset_) {}
        offset_kernel() : kernel(T()), offset(0.01) {}
        offset_kernel(
            const offset_kernel& k
        ) : kernel(k.kernel), offset(k.offset) {}

        const T kernel;
        const scalar_type offset;

        scalar_type operator() (
            const sample_type& a,
            const sample_type& b
        ) const
        {
            return kernel(a,b) + offset;
        }

        offset_kernel& operator= (
            const offset_kernel& k
        )
        {
            const_cast<T&>(kernel) = k.kernel;
            const_cast<scalar_type&>(offset) = k.offset;
            return *this;
        }

        bool operator== (
            const offset_kernel& k
        ) const
        {
            return k.kernel == kernel && offset == k.offset;
        }
    };

    template <
        typename T
        >
    void serialize (
        const offset_kernel<T>& item,
        std::ostream& out
    )
    {
        try
        {
            serialize(item.offset, out);
            serialize(item.kernel, out);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while serializing object of type offset_kernel");
        }
    }

    template <
        typename T
        >
    void deserialize (
        offset_kernel<T>& item,
        std::istream& in
    )
    {
        typedef typename offset_kernel<T>::scalar_type scalar_type;
        try
        {
            deserialize(const_cast<scalar_type&>(item.offset), in);
            deserialize(const_cast<T&>(item.kernel), in);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while deserializing object of type offset_kernel");
        }
    }

    template <
        typename T
        >
    struct kernel_derivative<offset_kernel<T> >
    {
        typedef typename T::scalar_type scalar_type;
        typedef typename T::sample_type sample_type;
        typedef typename T::mem_manager_type mem_manager_type;

        kernel_derivative(const offset_kernel<T>& k) : der(k.kernel){}

        const sample_type operator() (const sample_type& x, const sample_type& y) const
        {
            return der(x,y);
        }

        kernel_derivative<T> der;
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SVm_KERNEL


dlib C++ Library - kernel_matrix.h

// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SVm_KERNEL_MATRIX_
#define DLIB_SVm_KERNEL_MATRIX_

#include <vector>
#include "kernel_matrix_abstract.h"
#include "../matrix.h"
#include "../algs.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    namespace impl
    {
        template <typename kernel_type, typename T>
        inline const typename T::type& access ( const matrix_exp<T>& m, long i)
        {
            return m(i);
        }

        // bind to anything that looks like an array and isn't a matrix
        template <typename kernel_type, typename T>
        inline const typename disable_if<is_matrix<T>,typename T::type>::type& access ( const T& m, long i)
        {
            return m[i];
        }

        // Only use this function if T isn't a std::pair because in that case the entire vector is
        // probably itself a sparse sample.
        template <typename kernel_type, typename T, typename alloc>
        inline typename disable_if<is_pair<T>,const T&>::type access ( const std::vector<T,alloc>& m, long i)
        {
            return m[i];
        }

        // Only use this function if T isn't a std::pair because in that case the entire vector is
        // probably a sparse sample.
        template <typename kernel_type, typename T, typename alloc>
        inline typename disable_if<is_pair<T>,const T&>::type access ( const std_vector_c<T,alloc>& m, long i)
        {
            return m[i];
        }

        template <typename kernel_type>
        inline const typename kernel_type::sample_type& access (
            const typename kernel_type::sample_type& samp,
            long
        )
        {
            return samp;
        }

        // --------------------------------------------

        template <typename kernel_type, typename T>
        inline typename disable_if<is_same_type<T,typename kernel_type::sample_type>,unsigned long>::type
        size ( const T& m)
        {
            return m.size();
        }

        template <typename kernel_type>
        inline unsigned long size (
            const typename kernel_type::sample_type&
        )
        {
            return 1;
        }

        // --------------------------------------------

        template <typename T>
        typename disable_if<is_matrix<T> >::type assert_is_vector(const T&)
        {}

        template <typename T>
        // This funny #ifdef thing is here because gcc sometimes gives a warning
        // about v being unused otherwise.
#ifdef ENABLE_ASSERTS
        void assert_is_vector(const matrix_exp<T>& v)
#else
        void assert_is_vector(const matrix_exp<T>& )
#endif
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(is_vector(v) == true,
                "\tconst matrix_exp kernel_matrix()"
                << "\n\t You have to supply this function with row or column vectors"
                << "\n\t v.nr(): " << v.nr()
                << "\n\t v.nc(): " << v.nc()
                );
        }

    }

    template <typename K, typename vect_type1, typename vect_type2>
    struct op_kern_mat
    {
        op_kern_mat(
            const K& kern_,
            const vect_type1& vect1_,
            const vect_type2& vect2_
        ) :
            kern(kern_),
            vect1(vect1_),
            vect2(vect2_)
        {
            // make sure the requires clauses get checked eventually
            impl::assert_is_vector(vect1);
            impl::assert_is_vector(vect2);
        }

        const K& kern;
        const vect_type1& vect1;
        const vect_type2& vect2;

        typedef typename K::scalar_type type;

        const static long cost = 100;
        const static long NR = (is_same_type<vect_type1,typename K::sample_type>::value) ? 1 : 0;
        const static long NC = (is_same_type<vect_type2,typename K::sample_type>::value) ? 1 : 0;

        typedef const type const_ret_type;
        typedef typename K::mem_manager_type mem_manager_type;
        typedef row_major_layout layout_type;

        const_ret_type apply (long r, long c ) const
        {
            return kern(impl::access<K>(vect1,r), impl::access<K>(vect2,c));
        }

        long nr () const { return impl::size<K>(vect1); }
        long nc () const { return impl::size<K>(vect2); }

        template <typename U> bool aliases               ( const matrix_exp<U>& item ) const { return alias_helper(item.ref()); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item ) const { return alias_helper(item.ref()); }

        template <typename U> bool alias_helper  ( const U& ) const { return false; }

        typedef typename K::sample_type samp_type;

        // Say we destructively alias if one of the vect* objects is actually item.
        bool alias_helper                   (const samp_type& item ) const { return are_same(item, vect1) || are_same(item, vect2); }
        template <typename U> bool are_same (const samp_type& , const U& )         const { return false; }
        bool are_same                       (const samp_type& a, const samp_type& b) const { return (&a == &b); }
    };

// ----------------------------------------------------------------------------------------

    template <
        typename K,
        typename V1,
        typename V2
        >
    const matrix_op<op_kern_mat<K,V1,V2> > kernel_matrix (
        const K& kern,
        const V1& v1,
        const V2& v2
        )
    {
        typedef op_kern_mat<K,V1,V2> op;
        return matrix_op<op>(op(kern,v1,v2));
    }

// ----------------------------------------------------------------------------------------

    /*
        It is possible to implement the kernel_matrix() operator with just one operator
        class but treating the version that takes only a single vector separately
        leads to more efficient output by gcc in certain instances.
    */
    template <typename K, typename vect_type1>
    struct op_kern_mat_single
    {
        op_kern_mat_single(
            const K& kern_,
            const vect_type1& vect1_
        ) :
            kern(kern_),
            vect1(vect1_)
        {
            // make sure the requires clauses get checked eventually
            impl::assert_is_vector(vect1);
        }

        const K& kern;
        const vect_type1& vect1;

        typedef typename K::scalar_type type;

        const static long cost = 100;
        const static long NR = (is_same_type<vect_type1,typename K::sample_type>::value) ? 1 : 0;
        const static long NC = (is_same_type<vect_type1,typename K::sample_type>::value) ? 1 : 0;

        typedef const type const_ret_type;
        typedef typename K::mem_manager_type mem_manager_type;
        typedef row_major_layout layout_type;

        const_ret_type apply (long r, long c ) const
        {
            return kern(impl::access<K>(vect1,r), impl::access<K>(vect1,c));
        }

        long nr () const { return impl::size<K>(vect1); }
        long nc () const { return impl::size<K>(vect1); }

        template <typename U> bool aliases               ( const matrix_exp<U>& item ) const { return alias_helper(item.ref()); }
        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item ) const { return alias_helper(item.ref()); }

        template <typename U> bool alias_helper  ( const U& ) const { return false; }

        typedef typename K::sample_type samp_type;

        // Say we destructively alias if vect1 is actually item.
        bool alias_helper                   (const samp_type& item ) const { return are_same(item, vect1); }
        template <typename U> bool are_same (const samp_type& , const U& )         const { return false; }
        bool are_same                       (const samp_type& a, const samp_type& b) const { return (&a == &b); }
    };

    template <
        typename K,
        typename V
        >
    const matrix_op<op_kern_mat_single<K,V> > kernel_matrix (
        const K& kern,
        const V& v
        )
    {
        typedef op_kern_mat_single<K,V> op;
        return matrix_op<op>(op(kern,v));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_dest_type,
        typename K,
        typename V
        >
    inline void matrix_assign (
        matrix_dest_type& dest,
        const matrix_exp<matrix_op<op_kern_mat_single<K,V> > >& src
    )
    /*!
        Overload matrix assignment so that when a kernel_matrix expression
        gets assigned it only evaluates half the kernel matrix (since it is symmetric)
    !*/
    {
        for (long r = 0; r < src.nr(); ++r)
        {
            for (long c = r; c < src.nc(); ++c)
            {
                dest(r,c) = dest(c,r) = src(r,c);
            }
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SVm_KERNEL_MATRIX_


dlib C++ Library - kkmeans.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_KKMEANs_
#define DLIB_KKMEANs_

#include <cmath>
#include "../matrix/matrix_abstract.h"
#include "../algs.h"
#include "../serialize.h"
#include "kernel.h"
#include "../array.h"
#include "kcentroid.h"
#include "kkmeans_abstract.h"
#include "../noncopyable.h"
#include "../smart_pointers.h"
#include <vector>

namespace dlib
{

    template <
        typename kernel_type
        >
    class kkmeans : public noncopyable
    {
    public:
        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;

        kkmeans (
            const kcentroid<kernel_type>& kc_
        ):
            kc(kc_),
            min_change(0.01)
        {
            set_number_of_centers(1);
        }

        ~kkmeans()
        {
        }

        const kernel_type& get_kernel (
        ) const
        {
            return kc.get_kernel();
        }

        void set_kcentroid (
            const kcentroid<kernel_type>& kc_
        )
        {
            kc = kc_;
            set_number_of_centers(number_of_centers());
        }

        const kcentroid<kernel_type>& get_kcentroid (
            unsigned long i
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(i < number_of_centers(),
                "\tkcentroid kkmeans::get_kcentroid(i)"
                << "\n\tYou have given an invalid value for i"
                << "\n\ti:                   " << i
                << "\n\tnumber_of_centers(): " << number_of_centers()
                << "\n\tthis:                " << this
                );

            return *centers[i];
        }

        void set_number_of_centers (
            unsigned long num
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(num > 0,
                "\tvoid kkmeans::set_number_of_centers()"
                << "\n\tYou can't set the number of centers to zero"
                << "\n\tthis: " << this
                );

            centers.set_max_size(num);
            centers.set_size(num);

            for (unsigned long i = 0; i < centers.size(); ++i)
            {
                centers[i].reset(new kcentroid<kernel_type>(kc));
            }
        }

        unsigned long number_of_centers (
        ) const
        {
            return centers.size();
        }

        template <typename T, typename U>
        void train (
            const T& samples,
            const U& initial_centers,
            long max_iter = 1000
        )
        {
            do_train(mat(samples),mat(initial_centers),max_iter);
        }

        unsigned long operator() (
            const sample_type& sample
        ) const
        {
            unsigned long label = 0;
            scalar_type best_score = (*centers[0])(sample);

            // figure out which center the given sample is closest too
            for (unsigned long i = 1; i < centers.size(); ++i)
            {
                scalar_type temp = (*centers[i])(sample);
                if (temp < best_score)
                {
                    label = i;
                    best_score = temp;
                }
            }

            return label;
        }

        void set_min_change (
            scalar_type min_change_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT( 0 <= min_change_ < 1,
                "\tvoid kkmeans::set_min_change()"
                << "\n\tInvalid arguments to this function"
                << "\n\tthis: " << this
                << "\n\tmin_change_: " << min_change_
                );
            min_change = min_change_;
        }

        const scalar_type get_min_change (
        ) const
        {
            return min_change;
        }

        void swap (
            kkmeans& item
        )
        {
            centers.swap(item.centers);
            kc.swap(item.kc);
            assignments.swap(item.assignments);
            exchange(min_change, item.min_change);
        }

        friend void serialize(const kkmeans& item, std::ostream& out)
        {
            serialize(item.centers.size(),out);
            for (unsigned long i = 0; i < item.centers.size(); ++i)
            {
                serialize(*item.centers[i], out);
            }
            serialize(item.kc, out);
            serialize(item.min_change, out);
        }

        friend void deserialize(kkmeans& item, std::istream& in)
        {
            unsigned long num;
            deserialize(num, in);
            item.centers.resize(num);
            for (unsigned long i = 0; i < item.centers.size(); ++i)
            {
                scoped_ptr<kcentroid<kernel_type> > temp(new kcentroid<kernel_type>(kernel_type()));
                deserialize(*temp, in);
                item.centers[i].swap(temp);
            }

            deserialize(item.kc, in);
            deserialize(item.min_change, in);
        }

    private:

        template <typename matrix_type, typename matrix_type2>
        void do_train (
            const matrix_type& samples,
            const matrix_type2& initial_centers,
            long max_iter = 1000
        )
        {
            COMPILE_TIME_ASSERT((is_same_type<typename matrix_type::type, sample_type>::value));
            COMPILE_TIME_ASSERT((is_same_type<typename matrix_type2::type, sample_type>::value));

            // make sure requires clause is not broken
            DLIB_ASSERT(samples.nc() == 1 && initial_centers.nc() == 1 &&
                         initial_centers.nr() == static_cast<long>(number_of_centers()),
                "\tvoid kkmeans::train()"
                << "\n\tInvalid arguments to this function"
                << "\n\tthis: " << this
                << "\n\tsamples.nc(): " << samples.nc()
                << "\n\tinitial_centers.nc(): " << initial_centers.nc()
                << "\n\tinitial_centers.nr(): " << initial_centers.nr()
                );

            // clear out the old data and initialize the centers
            for (unsigned long i = 0; i < centers.size(); ++i)
            {
                centers[i]->clear_dictionary();
                centers[i]->train(initial_centers(i));
            }

            assignments.resize(samples.size());

            bool assignment_changed = true;

            // loop until the centers stabilize
            long count = 0;
            const unsigned long min_num_change = static_cast<unsigned long>(min_change*samples.size());
            unsigned long num_changed = min_num_change;
            while (assignment_changed && count < max_iter && num_changed >= min_num_change)
            {
                ++count;
                assignment_changed = false;
                num_changed = 0;

                // loop over all the samples and assign them to their closest centers
                for (long i = 0; i < samples.size(); ++i)
                {
                    // find the best center
                    unsigned long best_center = 0;
                    scalar_type best_score = (*centers[0])(samples(i));
                    for (unsigned long c = 1; c < centers.size(); ++c)
                    {
                        scalar_type temp = (*centers[c])(samples(i));
                        if (temp < best_score)
                        {
                            best_score = temp;
                            best_center = c;
                        }
                    }

                    // if the current sample changed centers then make note of that
                    if (assignments[i] != best_center)
                    {
                        assignments[i] = best_center;
                        assignment_changed = true;
                        ++num_changed;
                    }
                }

                if (assignment_changed)
                {
                    // now clear out the old data
                    for (unsigned long i = 0; i < centers.size(); ++i)
                        centers[i]->clear_dictionary();

                    // recalculate the cluster centers
                    for (unsigned long i = 0; i < assignments.size(); ++i)
                        centers[assignments[i]]->train(samples(i));
                }

            }

        }

        array<scoped_ptr<kcentroid<kernel_type> > > centers;
        kcentroid<kernel_type> kc;
        scalar_type min_change;

        // temp variables
        array<unsigned long> assignments;
    };

// ----------------------------------------------------------------------------------------

    template <typename kernel_type>
    void swap(kkmeans<kernel_type>& a, kkmeans<kernel_type>& b)
    { a.swap(b); }

// ----------------------------------------------------------------------------------------

    struct dlib_pick_initial_centers_data
    {
        dlib_pick_initial_centers_data():idx(0), dist(std::numeric_limits<double>::infinity()){}
        long idx;
        double dist;
        bool operator< (const dlib_pick_initial_centers_data& d) const { return dist < d.dist; }
    };

    template <
        typename vector_type1,
        typename vector_type2,
        typename kernel_type
        >
    void pick_initial_centers(
        long num_centers,
        vector_type1& centers,
        const vector_type2& samples,
        const kernel_type& k,
        double percentile = 0.01
    )
    {
        /*
            This function is basically just a non-randomized version of the kmeans++ algorithm
            described in the paper:
                kmeans++: The Advantages of Careful Seeding by Arthur and Vassilvitskii

        */

        // make sure requires clause is not broken
        DLIB_ASSERT(num_centers > 1 && 0 <= percentile && percentile < 1 && samples.size() > 1,
            "\tvoid pick_initial_centers()"
            << "\n\tYou passed invalid arguments to this function"
            << "\n\tnum_centers: " << num_centers
            << "\n\tpercentile: " << percentile
            << "\n\tsamples.size(): " << samples.size()
            );

        std::vector<dlib_pick_initial_centers_data> scores(samples.size());
        std::vector<dlib_pick_initial_centers_data> scores_sorted(samples.size());
        centers.clear();

        // pick the first sample as one of the centers
        centers.push_back(samples[0]);

        const long best_idx = static_cast<long>(std::max(0.0,samples.size() - samples.size()*percentile - 1));

        // pick the next center
        for (long i = 0; i < num_centers-1; ++i)
        {
            // Loop over the samples and compare them to the most recent center.  Store
            // the distance from each sample to its closest center in scores.
            const double k_cc = k(centers[i], centers[i]);
            for (unsigned long s = 0; s < samples.size(); ++s)
            {
                // compute the distance between this sample and the current center
                const double dist = k_cc + k(samples[s],samples[s]) - 2*k(samples[s], centers[i]);

                if (dist < scores[s].dist)
                {
                    scores[s].dist = dist;
                    scores[s].idx = s;
                }
            }

            scores_sorted = scores;

            // now find the winning center and add it to centers.  It is the one that is
            // far away from all the other centers.
            sort(scores_sorted.begin(), scores_sorted.end());
            centers.push_back(samples[scores_sorted[best_idx].idx]);
        }

    }

// ----------------------------------------------------------------------------------------

    template <
        typename vector_type1,
        typename vector_type2
        >
    void pick_initial_centers(
        long num_centers,
        vector_type1& centers,
        const vector_type2& samples,
        double percentile = 0.01
    )
    {
        typedef typename vector_type1::value_type sample_type;
        linear_kernel<sample_type> kern;
        pick_initial_centers(num_centers, centers, samples, kern, percentile);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename array_type,
        typename sample_type,
        typename alloc
        >
    void find_clusters_using_kmeans (
        const array_type& samples,
        std::vector<sample_type, alloc>& centers,
        unsigned long max_iter = 1000
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(samples.size() > 0 && centers.size() > 0,
            "\tvoid find_clusters_using_kmeans()"
            << "\n\tYou passed invalid arguments to this function"
            << "\n\t samples.size(): " << samples.size()
            << "\n\t centers.size(): " << centers.size()
            );

#ifdef ENABLE_ASSERTS
        {
        const long nr = samples[0].nr();
        const long nc = samples[0].nc();
        for (unsigned long i = 0; i < samples.size(); ++i)
        {
            DLIB_ASSERT(is_vector(samples[i]) && samples[i].nr() == nr && samples[i].nc() == nc,
                "\tvoid find_clusters_using_kmeans()"
                << "\n\t You passed invalid arguments to this function"
                << "\n\t is_vector(samples[i]): " << is_vector(samples[i])
                << "\n\t samples[i].nr():       " << samples[i].nr()
                << "\n\t nr:                    " << nr
                << "\n\t samples[i].nc():       " << samples[i].nc()
                << "\n\t nc:                    " << nc
                << "\n\t i:                     " << i
                );
        }
        }
#endif

        typedef typename sample_type::type scalar_type;

        sample_type zero(centers[0]);
        set_all_elements(zero, 0);

        std::vector<unsigned long> center_element_count;

        // tells which center a sample belongs to
        std::vector<unsigned long> assignments(samples.size(), samples.size());

        unsigned long iter = 0;
        bool centers_changed = true;
        while (centers_changed && iter < max_iter)
        {
            ++iter;
            centers_changed = false;
            center_element_count.assign(centers.size(), 0);

            // loop over each sample and see which center it is closest to
            for (unsigned long i = 0; i < samples.size(); ++i)
            {
                // find the best center for sample[i]
                scalar_type best_dist = std::numeric_limits<scalar_type>::max();
                unsigned long best_center = 0;
                for (unsigned long j = 0; j < centers.size(); ++j)
                {
                    scalar_type dist = length(centers[j] - samples[i]);
                    if (dist < best_dist)
                    {
                        best_dist = dist;
                        best_center = j;
                    }
                }

                if (assignments[i] != best_center)
                {
                    centers_changed = true;
                    assignments[i] = best_center;
                }

                center_element_count[best_center] += 1;
            }

            // now update all the centers
            centers.assign(centers.size(), zero);
            for (unsigned long i = 0; i < samples.size(); ++i)
            {
                centers[assignments[i]] += samples[i];
            }
            for (unsigned long i = 0; i < centers.size(); ++i)
            {
                if (center_element_count[i] != 0)
                    centers[i] /= center_element_count[i];
            }
        }

    }

// ----------------------------------------------------------------------------------------

    template <
        typename array_type,
        typename sample_type,
        typename alloc
        >
    void find_clusters_using_angular_kmeans (
        const array_type& samples,
        std::vector<sample_type, alloc>& centers,
        unsigned long max_iter = 1000
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(samples.size() > 0 && centers.size() > 0,
            "\tvoid find_clusters_using_angular_kmeans()"
            << "\n\tYou passed invalid arguments to this function"
            << "\n\t samples.size(): " << samples.size()
            << "\n\t centers.size(): " << centers.size()
            );

#ifdef ENABLE_ASSERTS
        {
        const long nr = samples[0].nr();
        const long nc = samples[0].nc();
        for (unsigned long i = 0; i < samples.size(); ++i)
        {
            DLIB_ASSERT(is_vector(samples[i]) && samples[i].nr() == nr && samples[i].nc() == nc,
                "\tvoid find_clusters_using_angular_kmeans()"
                << "\n\t You passed invalid arguments to this function"
                << "\n\t is_vector(samples[i]): " << is_vector(samples[i])
                << "\n\t samples[i].nr():       " << samples[i].nr()
                << "\n\t nr:                    " << nr
                << "\n\t samples[i].nc():       " << samples[i].nc()
                << "\n\t nc:                    " << nc
                << "\n\t i:                     " << i
                );
        }
        }
#endif

        typedef typename sample_type::type scalar_type;

        sample_type zero(centers[0]);
        set_all_elements(zero, 0);

        unsigned long seed = 0;

        // tells which center a sample belongs to
        std::vector<unsigned long> assignments(samples.size(), samples.size());
        std::vector<double> lengths;
        for (unsigned long i = 0; i < samples.size(); ++i)
        {
            lengths.push_back(length(samples[i]));
            // If there are zero vectors in samples then just say their length is 1 so we
            // can avoid a division by zero check later on.  Also, this doesn't matter
            // since zero vectors can be assigned to any cluster randomly as there is no
            // basis for picking one based on angle.
            if (lengths.back() == 0)
                lengths.back() = 1;
        }

        // We will keep the centers as unit vectors at all times throughout the processing.
        for (unsigned long i = 0; i < centers.size(); ++i)
        {
            double len = length(centers[i]);
            // Avoid having length 0 centers.  If that is the case then pick another center
            // at random.
            while(len == 0)
            {
                centers[i] = matrix_cast<scalar_type>(gaussian_randm(centers[i].nr(), centers[i].nc(), seed++));
                len = length(centers[i]);
            }
            centers[i] /= len;
        }

        unsigned long iter = 0;
        bool centers_changed = true;
        while (centers_changed && iter < max_iter)
        {
            ++iter;
            centers_changed = false;

            // loop over each sample and see which center it is closest to
            for (unsigned long i = 0; i < samples.size(); ++i)
            {
                // find the best center for sample[i]
                scalar_type best_angle = std::numeric_limits<scalar_type>::max();
                unsigned long best_center = 0;
                for (unsigned long j = 0; j < centers.size(); ++j)
                {
                    scalar_type angle = -dot(centers[j],samples[i])/lengths[i];

                    if (angle < best_angle)
                    {
                        best_angle = angle;
                        best_center = j;
                    }
                }

                if (assignments[i] != best_center)
                {
                    centers_changed = true;
                    assignments[i] = best_center;
                }
            }

            // now update all the centers
            centers.assign(centers.size(), zero);
            for (unsigned long i = 0; i < samples.size(); ++i)
            {
                centers[assignments[i]] += samples[i];
            }
            // Now length normalize all the centers.
            for (unsigned long i = 0; i < centers.size(); ++i)
            {
                double len = length(centers[i]);
                // Avoid having length 0 centers.  If that is the case then pick another center
                // at random.
                while(len == 0)
                {
                    centers[i] = matrix_cast<scalar_type>(gaussian_randm(centers[i].nr(), centers[i].nc(), seed++));
                    len = length(centers[i]);
                    centers_changed = true;
                }
                centers[i] /= len;
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename array_type,
        typename EXP
        >
    unsigned long nearest_center (
        const array_type& centers,
        const matrix_exp<EXP>& sample
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(centers.size() > 0 && sample.size() > 0 && is_vector(sample),
            "\t unsigned long nearest_center()"
            << "\n\t You have given invalid inputs to this function."
            << "\n\t centers.size():    " << centers.size()
            << "\n\t sample.size():     " << sample.size()
            << "\n\t is_vector(sample): " << is_vector(sample)
            );

        double best_dist = length_squared(centers[0] - sample);
        unsigned long best_idx = 0;
        for (unsigned long i = 1; i < centers.size(); ++i)
        {
            const double dist = length_squared(centers[i] - sample);
            if (dist < best_dist)
            {
                best_dist = dist;
                best_idx = i;
            }
        }
        return best_idx;
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_KKMEANs_


dlib C++ Library - krls.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_KRLs_
#define DLIB_KRLs_

#include <vector>

#include "krls_abstract.h"
#include "../matrix.h"
#include "function.h"
#include "../std_allocator.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <typename kernel_type>
    class krls
    {
        /*!
            This is an implementation of the kernel recursive least squares algorithm described in the paper:
            The Kernel Recursive Least Squares Algorithm by Yaakov Engel.
        !*/

    public:
        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;

        explicit krls (
            const kernel_type& kernel_,
            scalar_type tolerance_ = 0.001,
            unsigned long max_dictionary_size_ = 1000000
        ) :
            kernel(kernel_),
            my_tolerance(tolerance_),
            my_max_dictionary_size(max_dictionary_size_)
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(tolerance_ >= 0,
                "\tkrls::krls()"
                << "\n\t You have to give a positive tolerance"
                << "\n\t this: " << this
                << "\n\t tolerance: " << tolerance_
                );

            clear_dictionary();
        }

        scalar_type tolerance() const
        {
            return my_tolerance;
        }

        unsigned long max_dictionary_size() const
        {
            return my_max_dictionary_size;
        }

        const kernel_type& get_kernel (
        ) const
        {
            return kernel;
        }

        void clear_dictionary ()
        {
            dictionary.clear();
            alpha.clear();

            K_inv.set_size(0,0);
            K.set_size(0,0);
            P.set_size(0,0);
        }

        scalar_type operator() (
            const sample_type& x
        ) const
        {
            scalar_type temp = 0;
            for (unsigned long i = 0; i < alpha.size(); ++i)
                temp += alpha[i]*kern(dictionary[i], x);

            return temp;
        }

        void train (
            const sample_type& x,
            scalar_type y
        )
        {
            const scalar_type kx = kern(x,x);
            if (alpha.size() == 0)
            {
                // just ignore this sample if it is the zero vector (or really close to being zero)
                if (std::abs(kx) > std::numeric_limits<scalar_type>::epsilon())
                {
                    // set initial state since this is the first training example we have seen

                    K_inv.set_size(1,1);
                    K_inv(0,0) = 1/kx;
                    K.set_size(1,1);
                    K(0,0) = kx;

                    alpha.push_back(y/kx);
                    dictionary.push_back(x);
                    P.set_size(1,1);
                    P(0,0) = 1;
                }
            }
            else
            {
                // fill in k
                k.set_size(alpha.size());
                for (long r = 0; r < k.nr(); ++r)
                    k(r) = kern(x,dictionary[r]);

                // compute the error we would have if we approximated the new x sample
                // with the dictionary.  That is, do the ALD test from the KRLS paper.
                a = K_inv*k;
                scalar_type delta = kx - trans(k)*a;

                // if this new vector isn't approximately linearly dependent on the vectors
                // in our dictionary.
                if (delta > my_tolerance)
                {
                    if (dictionary.size() >= my_max_dictionary_size)
                    {
                        // We need to remove one of the old members of the dictionary before
                        // we proceed with adding a new one.  So remove the oldest one.
                        remove_dictionary_vector(0);

                        // recompute these guys since they were computed with the old
                        // kernel matrix
                        k = remove_row(k,0);
                        a = K_inv*k;
                        delta = kx - trans(k)*a;
                    }

                    // add x to the dictionary
                    dictionary.push_back(x);

                    // update K_inv by computing the new one in the temp matrix (equation 3.14)
                    matrix<scalar_type,0,0,mem_manager_type> temp(K_inv.nr()+1, K_inv.nc()+1);
                    // update the middle part of the matrix
                    set_subm(temp, get_rect(K_inv)) = K_inv + a*trans(a)/delta;
                    // update the right column of the matrix
                    set_subm(temp, 0, K_inv.nr(),K_inv.nr(),1) = -a/delta;
                    // update the bottom row of the matrix
                    set_subm(temp, K_inv.nr(), 0, 1, K_inv.nr()) = trans(-a/delta);
                    // update the bottom right corner of the matrix
                    temp(K_inv.nr(), K_inv.nc()) = 1/delta;
                    // put temp into K_inv
                    temp.swap(K_inv);

                    // update K (the kernel matrix)
                    temp.set_size(K.nr()+1, K.nc()+1);
                    set_subm(temp, get_rect(K)) = K;
                    // update the right column of the matrix
                    set_subm(temp, 0, K.nr(),K.nr(),1) = k;
                    // update the bottom row of the matrix
                    set_subm(temp, K.nr(), 0, 1, K.nr()) = trans(k);
                    temp(K.nr(), K.nc()) = kx;
                    // put temp into K
                    temp.swap(K);

                    // Now update the P matrix (equation 3.15)
                    temp.set_size(P.nr()+1, P.nc()+1);
                    set_subm(temp, get_rect(P)) = P;
                    // initialize the new sides of P
                    set_rowm(temp,P.nr()) = 0;
                    set_colm(temp,P.nr()) = 0;
                    temp(P.nr(), P.nc()) = 1;
                    temp.swap(P);

                    // now update the alpha vector (equation 3.16)
                    const scalar_type k_a = (y-trans(k)*mat(alpha))/delta;
                    for (unsigned long i = 0; i < alpha.size(); ++i)
                    {
                        alpha[i] -= a(i)*k_a;
                    }
                    alpha.push_back(k_a);
                }
                else
                {
                    q = P*a/(1+trans(a)*P*a);

                    // update P (equation 3.12)
                    temp_matrix = trans(a)*P;
                    P -= q*temp_matrix;

                    // update the alpha vector (equation 3.13)
                    const scalar_type k_a = y-trans(k)*mat(alpha);
                    for (unsigned long i = 0; i < alpha.size(); ++i)
                    {
                        alpha[i] += (K_inv*q*k_a)(i);
                    }
                }
            }
        }

        void swap (
            krls& item
        )
        {
            exchange(kernel, item.kernel);
            dictionary.swap(item.dictionary);
            alpha.swap(item.alpha);
            K_inv.swap(item.K_inv);
            K.swap(item.K);
            P.swap(item.P);
            exchange(my_tolerance, item.my_tolerance);
            q.swap(item.q);
            a.swap(item.a);
            k.swap(item.k);
            temp_matrix.swap(item.temp_matrix);
            exchange(my_max_dictionary_size, item.my_max_dictionary_size);
        }

        unsigned long dictionary_size (
        ) const { return dictionary.size(); }

        decision_function<kernel_type> get_decision_function (
        ) const
        {
            return decision_function<kernel_type>(
                mat(alpha),
                -sum(mat(alpha))*tau,
                kernel,
                mat(dictionary)
            );
        }

        friend void serialize(const krls& item, std::ostream& out)
        {
            serialize(item.kernel, out);
            serialize(item.dictionary, out);
            serialize(item.alpha, out);
            serialize(item.K_inv, out);
            serialize(item.K, out);
            serialize(item.P, out);
            serialize(item.my_tolerance, out);
            serialize(item.my_max_dictionary_size, out);
        }

        friend void deserialize(krls& item, std::istream& in)
        {
            deserialize(item.kernel, in);
            deserialize(item.dictionary, in);
            deserialize(item.alpha, in);
            deserialize(item.K_inv, in);
            deserialize(item.K, in);
            deserialize(item.P, in);
            deserialize(item.my_tolerance, in);
            deserialize(item.my_max_dictionary_size, in);
        }

    private:

        inline scalar_type kern (const sample_type& m1, const sample_type& m2) const
        {
            return kernel(m1,m2) + tau;
        }

        void remove_dictionary_vector (
            long i
        )
        /*!
            requires
                - 0 <= i < dictionary.size()
            ensures
                - #dictionary.size() == dictionary.size() - 1
                - #alpha.size() == alpha.size() - 1
                - updates the K_inv matrix so that it is still a proper inverse of the
                  kernel matrix
                - also removes the necessary row and column from the K matrix
                - uses the this->a variable so after this function runs that variable
                  will contain a different value.
        !*/
        {
            // remove the dictionary vector
            dictionary.erase(dictionary.begin()+i);

            // remove the i'th vector from the inverse kernel matrix.  This formula is basically
            // just the reverse of the way K_inv is updated by equation 3.14 during normal training.
            K_inv = removerc(K_inv,i,i) - remove_row(colm(K_inv,i)/K_inv(i,i),i)*remove_col(rowm(K_inv,i),i);

            // now compute the updated alpha values to take account that we just removed one of
            // our dictionary vectors
            a = (K_inv*remove_row(K,i)*mat(alpha));

            // now copy over the new alpha values
            alpha.resize(alpha.size()-1);
            for (unsigned long k = 0; k < alpha.size(); ++k)
            {
                alpha[k] = a(k);
            }

            // update the P matrix as well
            P = removerc(P,i,i);

            // update the K matrix as well
            K = removerc(K,i,i);
        }

        kernel_type kernel;

        typedef std_allocator<sample_type, mem_manager_type> alloc_sample_type;
        typedef std_allocator<scalar_type, mem_manager_type> alloc_scalar_type;
        typedef std::vector<sample_type,alloc_sample_type> dictionary_vector_type;
        typedef std::vector<scalar_type,alloc_scalar_type> alpha_vector_type;

        dictionary_vector_type dictionary;
        alpha_vector_type alpha;

        matrix<scalar_type,0,0,mem_manager_type> K_inv;
        matrix<scalar_type,0,0,mem_manager_type> K;
        matrix<scalar_type,0,0,mem_manager_type> P;

        scalar_type my_tolerance;
        unsigned long my_max_dictionary_size;

        // temp variables here just so we don't have to reconstruct them over and over.  Thus,
        // they aren't really part of the state of this object.
        matrix<scalar_type,0,1,mem_manager_type> q;
        matrix<scalar_type,0,1,mem_manager_type> a;
        matrix<scalar_type,0,1,mem_manager_type> k;
        matrix<scalar_type,1,0,mem_manager_type> temp_matrix;

        const static scalar_type tau;

    };

    template <typename kernel_type>
    const typename kernel_type::scalar_type krls<kernel_type>::tau = static_cast<typename kernel_type::scalar_type>(0.01);

// ----------------------------------------------------------------------------------------

    template <typename kernel_type>
    void swap(krls<kernel_type>& a, krls<kernel_type>& b)
    { a.swap(b); }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_KRLs_


dlib C++ Library - krr_trainer.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_KRR_TRAInER_Hh_
#define DLIB_KRR_TRAInER_Hh_

#include "../algs.h"
#include "function.h"
#include "kernel.h"
#include "empirical_kernel_map.h"
#include "linearly_independent_subset_finder.h"
#include "../statistics.h"
#include "rr_trainer.h"
#include "krr_trainer_abstract.h"
#include <vector>
#include <iostream>

namespace dlib
{
    template <
        typename K
        >
    class krr_trainer
    {

    public:
        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 decision_function<kernel_type> trained_function_type;

        krr_trainer (
        ) :
            verbose(false),
            max_basis_size(400),
            ekm_stale(true)
        {
        }

        void be_verbose (
        )
        {
            verbose = true;
            trainer.be_verbose();
        }

        void be_quiet (
        )
        {
            verbose = false;
            trainer.be_quiet();
        }

        void use_regression_loss_for_loo_cv (
        )
        {
            trainer.use_regression_loss_for_loo_cv();
        }

        void use_classification_loss_for_loo_cv (
        )
        {
            trainer.use_classification_loss_for_loo_cv();
        }

        bool will_use_regression_loss_for_loo_cv (
        ) const
        {
            return trainer.will_use_regression_loss_for_loo_cv();
        }

        const kernel_type get_kernel (
        ) const
        {
            return kern;
        }

        void set_kernel (
            const kernel_type& k
        )
        {
            kern = k;
        }

        template <typename T>
        void set_basis (
            const T& basis_samples
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(basis_samples.size() > 0 && is_vector(mat(basis_samples)),
                "\tvoid krr_trainer::set_basis(basis_samples)"
                << "\n\t You have to give a non-empty set of basis_samples and it must be a vector"
                << "\n\t basis_samples.size():                       " << basis_samples.size()
                << "\n\t is_vector(mat(basis_samples)): " << is_vector(mat(basis_samples))
                << "\n\t this: " << this
                );

            basis = mat(basis_samples);
            ekm_stale = true;
        }

        bool basis_loaded (
        ) const
        {
            return (basis.size() != 0);
        }

        void clear_basis (
        )
        {
            basis.set_size(0);
            ekm.clear();
            ekm_stale = true;
        }

        unsigned long get_max_basis_size (
        ) const
        {
            return max_basis_size;
        }

        void set_max_basis_size (
            unsigned long max_basis_size_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(max_basis_size_ > 0,
                "\t void krr_trainer::set_max_basis_size()"
                << "\n\t max_basis_size_ must be greater than 0"
                << "\n\t max_basis_size_: " << max_basis_size_
                << "\n\t this:            " << this
                );

            max_basis_size = max_basis_size_;
        }

        void set_lambda (
            scalar_type lambda_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(lambda_ >= 0,
                "\t void krr_trainer::set_lambda()"
                << "\n\t lambda must be greater than or equal to 0"
                << "\n\t lambda_: " << lambda_
                << "\n\t this:   " << this
                );

            trainer.set_lambda(lambda_);
        }

        const scalar_type get_lambda (
        ) const
        {
            return trainer.get_lambda();
        }

        template <typename EXP>
        void set_search_lambdas (
            const matrix_exp<EXP>& lambdas
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(is_vector(lambdas) && lambdas.size() > 0 && min(lambdas) > 0,
                "\t void krr_trainer::set_search_lambdas()"
                << "\n\t lambdas must be a non-empty vector of values"
                << "\n\t is_vector(lambdas): " << is_vector(lambdas)
                << "\n\t lambdas.size():     " << lambdas.size()
                << "\n\t min(lambdas):       " << min(lambdas)
                << "\n\t this:   " << this
                );

            trainer.set_search_lambdas(lambdas);
        }

        const matrix<scalar_type,0,0,mem_manager_type>& get_search_lambdas (
        ) const
        {
            return trainer.get_search_lambdas();
        }

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y
        ) const
        {
            std::vector<scalar_type> temp;
            scalar_type temp2;
            return do_train(mat(x), mat(y), false, temp, temp2);
        }

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y,
            std::vector<scalar_type>& loo_values
        ) const
        {
            scalar_type temp;
            return do_train(mat(x), mat(y), true, loo_values, temp);
        }

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y,
            std::vector<scalar_type>& loo_values,
            scalar_type& lambda_used
        ) const
        {
            return do_train(mat(x), mat(y), true, loo_values, lambda_used);
        }

    private:

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> do_train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y,
            const bool output_loo_values,
            std::vector<scalar_type>& loo_values,
            scalar_type& the_lambda
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(is_learning_problem(x,y),
                "\t decision_function krr_trainer::train(x,y)"
                << "\n\t invalid inputs were given to this function"
                << "\n\t is_vector(x): " << is_vector(x)
                << "\n\t is_vector(y): " << is_vector(y)
                << "\n\t x.size():     " << x.size()
                << "\n\t y.size():     " << y.size()
                );

#ifdef ENABLE_ASSERTS
            if (get_lambda() == 0 && will_use_regression_loss_for_loo_cv() == false)
            {
                // make sure requires clause is not broken
                DLIB_ASSERT(is_binary_classification_problem(x,y),
                    "\t decision_function krr_trainer::train(x,y)"
                    << "\n\t invalid inputs were given to this function"
                    );
            }
#endif

            // The first thing we do is make sure we have an appropriate ekm ready for use below.
            if (basis_loaded())
            {
                if (ekm_stale)
                {
                    ekm.load(kern, basis);
                    ekm_stale = false;
                }
            }
            else
            {
                linearly_independent_subset_finder<kernel_type> lisf(kern, max_basis_size);
                fill_lisf(lisf, x);
                ekm.load(lisf);
            }

            if (verbose)
            {
                std::cout << "\nNumber of basis vectors used: " << ekm.out_vector_size() << std::endl;
            }

            typedef matrix<scalar_type,0,1,mem_manager_type> column_matrix_type;

            running_stats<scalar_type> rs;

            // Now we project all the x samples into kernel space using our EKM
            matrix<column_matrix_type,0,1,mem_manager_type > proj_x;
            proj_x.set_size(x.size());
            for (long i = 0; i < proj_x.size(); ++i)
            {
                scalar_type err;
                // Note that we also append a 1 to the end of the vectors because this is
                // a convenient way of dealing with the bias term later on.
                if (verbose == false)
                {
                    proj_x(i) = ekm.project(x(i));
                }
                else
                {
                    proj_x(i) = ekm.project(x(i),err);
                    rs.add(err);
                }
            }

            if (verbose)
            {
                std::cout << "Mean EKM projection error:                  " << rs.mean() << std::endl;
                std::cout << "Standard deviation of EKM projection error: " << rs.stddev() << std::endl;
            }

            decision_function<linear_kernel<matrix<scalar_type,0,0,mem_manager_type> > > lin_df;

            if (output_loo_values)
                lin_df = trainer.train(proj_x,y, loo_values, the_lambda);
            else
                lin_df = trainer.train(proj_x,y);

            // convert the linear decision function into a kernelized one.
            decision_function<kernel_type> df;
            df = ekm.convert_to_decision_function(lin_df.basis_vectors(0));
            df.b = lin_df.b;

            // If we used an automatically derived basis then there isn't any point in
            // keeping the ekm around.  So free its memory.
            if (basis_loaded() == false)
            {
                ekm.clear();
            }

            return df;
        }

        /*!
            CONVENTION
                - if (ekm_stale) then
                    - kern or basis have changed since the last time
                      they were loaded into the ekm

                - get_lambda() == trainer.get_lambda()
                - get_kernel() == kern
                - get_max_basis_size() == max_basis_size
                - will_use_regression_loss_for_loo_cv() == trainer.will_use_regression_loss_for_loo_cv()
                - get_search_lambdas() == trainer.get_search_lambdas()

                - basis_loaded() == (basis.size() != 0)
        !*/

        rr_trainer<linear_kernel<matrix<scalar_type,0,0,mem_manager_type> > > trainer;

        bool verbose;

        kernel_type kern;
        unsigned long max_basis_size;

        matrix<sample_type,0,1,mem_manager_type> basis;
        mutable empirical_kernel_map<kernel_type> ekm;
        mutable bool ekm_stale;

    };

}

#endif // DLIB_KRR_TRAInER_Hh_


dlib C++ Library - linearly_independent_subset_finder.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_LISfh_
#define DLIB_LISfh_

#include <vector>

#include "linearly_independent_subset_finder_abstract.h"
#include "../matrix.h"
#include "function.h"
#include "../std_allocator.h"
#include "../algs.h"
#include "../serialize.h"
#include "../is_kind.h"
#include "../string.h"
#include "../rand.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <typename kernel_type>
    class linearly_independent_subset_finder
    {
        /*!
            INITIAL VALUE
                - min_strength == 0
                - min_vect_idx == 0
                - K_inv.size() == 0
                - K.size() == 0
                - dictionary.size() == 0

            CONVENTION
                - max_dictionary_size() == my_max_dictionary_size
                - get_kernel() == kernel
                - minimum_tolerance() == min_tolerance
                - size() == dictionary.size()
                - get_dictionary() == mat(dictionary)
                - K.nr() == dictionary.size()
                - K.nc() == dictionary.size()
                - for all valid r,c:
                    - K(r,c) == kernel(dictionary[r], dictionary[c])
                - K_inv == inv(K)

                - if (dictionary.size() == my_max_dictionary_size) then
                    - for all valid 0 < i < dictionary.size():
                        - Let STRENGTHS[i] == the delta you would get for dictionary[i] (i.e. Approximately
                          Linearly Dependent value) if you removed dictionary[i] from this object and then
                          tried to add it back in.
                        - min_strength == the minimum value from STRENGTHS
                        - min_vect_idx == the index of the element in STRENGTHS with the smallest value
        !*/

    public:
        typedef typename kernel_type::scalar_type scalar_type;
        typedef typename kernel_type::sample_type sample_type;
        typedef typename kernel_type::sample_type type;
        typedef typename kernel_type::mem_manager_type mem_manager_type;

        linearly_independent_subset_finder (
        ) :
            my_max_dictionary_size(100),
            min_tolerance(0.001)
        {
            clear_dictionary();
        }

        linearly_independent_subset_finder (
            const kernel_type& kernel_,
            unsigned long max_dictionary_size_,
            scalar_type min_tolerance_ = 0.001
        ) :
            kernel(kernel_),
            my_max_dictionary_size(max_dictionary_size_),
            min_tolerance(min_tolerance_)
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(min_tolerance_ > 0 && max_dictionary_size_ > 1,
                "\tlinearly_independent_subset_finder()"
                << "\n\tinvalid argument to constructor"
                << "\n\tmin_tolerance_: " << min_tolerance_
                << "\n\tmax_dictionary_size_: " << max_dictionary_size_
                << "\n\tthis:           " << this
                );
            clear_dictionary();
        }

        unsigned long max_dictionary_size() const
        {
            return my_max_dictionary_size;
        }

        const kernel_type& get_kernel (
        ) const
        {
            return kernel;
        }

        scalar_type minimum_tolerance(
        ) const
        {
            return min_tolerance;
        }

        void set_minimum_tolerance (
            scalar_type min_tol
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(min_tol > 0,
                "\tlinearly_independent_subset_finder::set_minimum_tolerance()"
                << "\n\tinvalid argument to this function"
                << "\n\tmin_tol: " << min_tol
                << "\n\tthis:    " << this
                );
            min_tolerance = min_tol;
        }

        void clear_dictionary ()
        {
            dictionary.clear();
            min_strength = 0;
            min_vect_idx = 0;

            K_inv.set_size(0,0);
            K.set_size(0,0);
        }

        scalar_type projection_error (
            const sample_type& x
        ) const
        {
            const scalar_type kx = kernel(x,x);
            if (dictionary.size() == 0)
            {
                return kx;
            }
            else
            {
                // fill in k
                k.set_size(dictionary.size());
                for (long r = 0; r < k.nr(); ++r)
                    k(r) = kernel(x,dictionary[r]);

                // compute the error we would have if we approximated the new x sample
                // with the dictionary.  That is, do the ALD test from the KRLS paper.
                a = K_inv*k;
                scalar_type delta = kx - trans(k)*a;

                return delta;
            }
        }

        bool add (
            const sample_type& x
        )
        {
            const scalar_type kx = kernel(x,x);
            if (dictionary.size() == 0)
            {
                // just ignore this sample if it is the zero vector (or really close to being zero)
                if (std::abs(kx) > std::numeric_limits<scalar_type>::epsilon())
                {
                    // set initial state since this is the first sample we have seen
                    K_inv.set_size(1,1);
                    K_inv(0,0) = 1/kx;

                    K.set_size(1,1);
                    K(0,0) = kx;

                    dictionary.push_back(x);
                    return true;
                }
                return false;
            }
            else
            {
                // fill in k
                k.set_size(dictionary.size());
                for (long r = 0; r < k.nr(); ++r)
                    k(r) = kernel(x,dictionary[r]);

                // compute the error we would have if we approximated the new x sample
                // with the dictionary.  That is, do the ALD test from the KRLS paper.
                a = K_inv*k;
                scalar_type delta = kx - trans(k)*a;

                // if this new vector is approximately linearly independent of the vectors
                // in our dictionary.
                if (delta > min_strength && delta > min_tolerance)
                {
                    if (dictionary.size() == my_max_dictionary_size)
                    {
                        // if we have never computed the min_strength then we should compute it
                        if (min_strength == 0)
                            recompute_min_strength();

                        const long i = min_vect_idx;

                        // replace the min strength vector with x.  Put the new vector onto the end of
                        // dictionary and remove the vector at position i.
                        dictionary.erase(dictionary.begin()+i);
                        dictionary.push_back(x);

                        // compute reduced K_inv.
                        // Remove the i'th vector from the inverse kernel matrix.  This formula is basically
                        // just the reverse of the way K_inv is updated by equation 3.14 below.
                        temp = removerc(K_inv,i,i) - remove_row(colm(K_inv,i)/K_inv(i,i),i)*remove_col(rowm(K_inv,i),i);

                        // recompute these guys since they were computed with the old
                        // kernel matrix
                        k2 = remove_row(k,i);
                        a2 = temp*k2;
                        delta = kx - trans(k2)*a2;

                        // now update temp with the new dictionary vector
                        // update the middle part of the matrix
                        set_subm(K_inv, get_rect(temp)) = temp + a2*trans(a2)/delta;
                        // update the right column of the matrix
                        set_subm(K_inv, 0, temp.nr(),temp.nr(),1) = -a2/delta;
                        // update the bottom row of the matrix
                        set_subm(K_inv, temp.nr(), 0, 1, temp.nr()) = trans(-a2/delta);
                        // update the bottom right corner of the matrix
                        K_inv(temp.nr(), temp.nc()) = 1/delta;

                        // now update the kernel matrix K
                        set_subm(K,get_rect(temp)) = removerc(K, i,i);
                        set_subm(K, 0, K.nr()-1,K.nr()-1,1) = k2;
                        // update the bottom row of the matrix
                        set_subm(K, K.nr()-1, 0, 1, K.nr()-1) = trans(k2);
                        K(K.nr()-1, K.nc()-1) = kx;

                        // now we have to recompute the min_strength in this case
                        recompute_min_strength();
                    }
                    else
                    {
                        // update K_inv by computing the new one in the temp matrix (equation 3.14 from Engel)
                        temp.set_size(K_inv.nr()+1, K_inv.nc()+1);
                        // update the middle part of the matrix
                        set_subm(temp, get_rect(K_inv)) = K_inv + a*trans(a)/delta;
                        // update the right column of the matrix
                        set_subm(temp, 0, K_inv.nr(),K_inv.nr(),1) = -a/delta;
                        // update the bottom row of the matrix
                        set_subm(temp, K_inv.nr(), 0, 1, K_inv.nr()) = trans(-a/delta);
                        // update the bottom right corner of the matrix
                        temp(K_inv.nr(), K_inv.nc()) = 1/delta;
                        // put temp into K_inv
                        temp.swap(K_inv);

                        // update K (the kernel matrix)
                        temp.set_size(K.nr()+1, K.nc()+1);
                        set_subm(temp, get_rect(K)) = K;
                        // update the right column of the matrix
                        set_subm(temp, 0, K.nr(),K.nr(),1) = k;
                        // update the bottom row of the matrix
                        set_subm(temp, K.nr(), 0, 1, K.nr()) = trans(k);
                        temp(K.nr(), K.nc()) = kx;
                        // put temp into K
                        temp.swap(K);

                        // add x to the dictionary
                        dictionary.push_back(x);

                    }
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }

        void swap (
            linearly_independent_subset_finder& item
        )
        {
            exchange(kernel, item.kernel);
            dictionary.swap(item.dictionary);
            exchange(min_strength, item.min_strength);
            exchange(min_vect_idx, item.min_vect_idx);
            K_inv.swap(item.K_inv);
            K.swap(item.K);
            exchange(my_max_dictionary_size, item.my_max_dictionary_size);
            exchange(min_tolerance, item.min_tolerance);

            // non-state temp members
            a.swap(item.a);
            k.swap(item.k);
            a2.swap(item.a2);
            k2.swap(item.k2);
            temp.swap(item.temp);
        }

        unsigned long size (
        ) const { return dictionary.size(); }

        const matrix<sample_type,0,1,mem_manager_type> get_dictionary (
        ) const
        {
            return mat(dictionary);
        }

        friend void serialize(const linearly_independent_subset_finder& item, std::ostream& out)
        {
            serialize(item.kernel, out);
            serialize(item.dictionary, out);
            serialize(item.min_strength, out);
            serialize(item.min_vect_idx, out);
            serialize(item.K_inv, out);
            serialize(item.K, out);
            serialize(item.my_max_dictionary_size, out);
            serialize(item.min_tolerance, out);
        }

        friend void deserialize(linearly_independent_subset_finder& item, std::istream& in)
        {
            deserialize(item.kernel, in);
            deserialize(item.dictionary, in);
            deserialize(item.min_strength, in);
            deserialize(item.min_vect_idx, in);
            deserialize(item.K_inv, in);
            deserialize(item.K, in);
            deserialize(item.my_max_dictionary_size, in);
            deserialize(item.min_tolerance, in);
        }

        const sample_type& operator[] (
            unsigned long index
        ) const
        {
            return dictionary[index];
        }

        const matrix<scalar_type,0,0,mem_manager_type>& get_kernel_matrix (
        ) const
        {
            return K;
        }

        const matrix<scalar_type,0,0,mem_manager_type>& get_inv_kernel_marix (
        ) const
        {
            return K_inv;
        }

    private:

        typedef std_allocator<sample_type, mem_manager_type> alloc_sample_type;
        typedef std_allocator<scalar_type, mem_manager_type> alloc_scalar_type;
        typedef std::vector<sample_type,alloc_sample_type> dictionary_vector_type;
        typedef std::vector<scalar_type,alloc_scalar_type> scalar_vector_type;

        void recompute_min_strength (
        )
        /*!
            ensures
                - recomputes the min_strength and min_vect_idx values
                  so that they are correct with respect to the CONVENTION
        !*/
        {
            min_strength = std::numeric_limits<scalar_type>::max();

            // here we loop over each dictionary vector and compute what its delta would be if
            // we were to remove it from the dictionary and then try to add it back in.
            for (unsigned long i = 0; i < dictionary.size(); ++i)
            {
                // compute a2 = K_inv*k but where dictionary vector i has been removed
                a2 = (removerc(K_inv,i,i) - remove_row(colm(K_inv,i)/K_inv(i,i),i)*remove_col(rowm(K_inv,i),i)) *
                    (remove_row(colm(K,i),i));
                scalar_type delta = K(i,i) - trans(remove_row(colm(K,i),i))*a2;

                if (delta < min_strength)
                {
                    min_strength = delta;
                    min_vect_idx = i;
                }
            }
        }

        kernel_type kernel;
        dictionary_vector_type dictionary;
        scalar_type min_strength;
        unsigned long min_vect_idx;

        matrix<scalar_type,0,0,mem_manager_type> K_inv;
        matrix<scalar_type,0,0,mem_manager_type> K;

        unsigned long my_max_dictionary_size;
        scalar_type min_tolerance;

        // temp variables here just so we don't have to reconstruct them over and over.  Thus,
        // they aren't really part of the state of this object.
        mutable matrix<scalar_type,0,1,mem_manager_type> a, a2;
        mutable matrix<scalar_type,0,1,mem_manager_type> k, k2;
        mutable matrix<scalar_type,0,0,mem_manager_type> temp;

    };

// ----------------------------------------------------------------------------------------

    template <typename kernel_type>
    void swap(linearly_independent_subset_finder<kernel_type>& a, linearly_independent_subset_finder<kernel_type>& b)
    { a.swap(b); }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    const matrix_op<op_array_to_mat<linearly_independent_subset_finder<T> > > mat (
        const linearly_independent_subset_finder<T>& m
    )
    {
        typedef op_array_to_mat<linearly_independent_subset_finder<T> > op;
        return matrix_op<op>(op(m));
    }

// ----------------------------------------------------------------------------------------
    namespace impl
    {
        template <
            typename kernel_type,
            typename vector_type,
            typename rand_type
            >
        void fill_lisf (
            linearly_independent_subset_finder<kernel_type>& lisf,
            const vector_type& samples,
            rand_type& rnd,
            int sampling_size
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(is_vector(samples) && sampling_size > 0,
                "\t void fill_lisf()"
                << "\n\t invalid arguments to this function"
                << "\n\t is_vector(samples): " << is_vector(samples)
                << "\n\t sampling_size: " << sampling_size
                );

            // no need to do anything if there aren't any samples
            if (samples.size() == 0)
                return;

            typedef typename kernel_type::scalar_type scalar_type;

            // Start out by guessing what a reasonable projection error tolerance is. We will use
            // the biggest projection error we see in a small sample.
            scalar_type tol = 0;
            for (int i = 0; i < sampling_size; ++i)
            {
                const unsigned long idx = rnd.get_random_32bit_number()%samples.size();
                const scalar_type temp = lisf.projection_error(samples(idx));
                if (temp > tol)
                    tol = temp;
            }

            const scalar_type min_tol = lisf.minimum_tolerance();

            // run many rounds of random sampling.  In each round we drop the tolerance lower.
            while (tol >= min_tol && lisf.size() < lisf.max_dictionary_size())
            {
                tol *= 0.5;
                lisf.set_minimum_tolerance(std::max(tol, min_tol));
                int add_failures = 0;

                // Keep picking random samples and adding them into the lisf.  Stop when we either
                // fill it up or can't find any more samples with projection error larger than the
                // current tolerance.
                while (lisf.size() < lisf.max_dictionary_size() && add_failures < sampling_size)
                {
                    if (lisf.add(samples(rnd.get_random_32bit_number()%samples.size())) == false)
                    {
                        ++add_failures;
                    }
                }
            }

            // set this back to its original value
            lisf.set_minimum_tolerance(min_tol);
        }
    }

    template <
        typename kernel_type,
        typename vector_type
        >
    void fill_lisf (
        linearly_independent_subset_finder<kernel_type>& lisf,
        const vector_type& samples
    )
    {
        dlib::rand rnd;
        impl::fill_lisf(lisf, mat(samples),rnd, 2000);
    }

    template <
        typename kernel_type,
        typename vector_type,
        typename rand_type
        >
    typename enable_if<is_rand<rand_type> >::type fill_lisf (
        linearly_independent_subset_finder<kernel_type>& lisf,
        const vector_type& samples,
        rand_type& rnd,
        const int sampling_size = 2000
    )
    {
        impl::fill_lisf(lisf, mat(samples),rnd, sampling_size);
    }

    template <
        typename kernel_type,
        typename vector_type,
        typename rand_type
        >
    typename disable_if<is_rand<rand_type> >::type fill_lisf (
        linearly_independent_subset_finder<kernel_type>& lisf,
        const vector_type& samples,
        rand_type random_seed,
        const int sampling_size = 2000
    )
    {
        dlib::rand rnd;
        rnd.set_seed(cast_to_string(random_seed));
        impl::fill_lisf(lisf, mat(samples), rnd, sampling_size);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_LISfh_


dlib C++ Library - multiclass_tools.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MULTICLASS_TOoLS_Hh_
#define DLIB_MULTICLASS_TOoLS_Hh_

#include "multiclass_tools_abstract.h"

#include <vector>
#include <set>
#include "../unordered_pair.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <typename label_type>
    std::vector<label_type> select_all_distinct_labels (
        const std::vector<label_type>& labels
    )
    {
        std::set<label_type> temp;
        temp.insert(labels.begin(), labels.end());
        return std::vector<label_type>(temp.begin(), temp.end());
    }

// ----------------------------------------------------------------------------------------

    template <typename label_type, typename U>
    std::vector<unordered_pair<label_type> > find_missing_pairs (
        const std::map<unordered_pair<label_type>,U>& bdfs
    )
    {
        typedef std::map<unordered_pair<label_type>,U> map_type;

        // find all the labels
        std::set<label_type> temp;
        for (typename map_type::const_iterator i = bdfs.begin(); i != bdfs.end(); ++i)
        {
            temp.insert(i->first.first);
            temp.insert(i->first.second);
        }

        std::vector<unordered_pair<label_type> > missing_pairs;

        // now make sure all label pairs are present
        typename std::set<label_type>::const_iterator i, j;
        for (i = temp.begin(); i != temp.end(); ++i)
        {
            for (j = i, ++j; j != temp.end(); ++j)
            {
                const unordered_pair<label_type> p(*i, *j);

                if (bdfs.count(p) == 0)
                    missing_pairs.push_back(p);
            }
        }

        return missing_pairs;
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MULTICLASS_TOoLS_Hh_


dlib C++ Library - null_df.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_NULL_DECISION_FUnCTION_Hh_
#define DLIB_NULL_DECISION_FUnCTION_Hh_

#include <iostream>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    struct null_df
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is a type used to represent an unused field in the list of template
                arguments of the one_vs_one_decision_function and one_vs_all_decision_function
                templates.  As such, null_df doesn't actually do anything.
        !*/
        template <typename T>
        double operator() ( const T&) const { return 0; }
    };

    inline void serialize(const null_df&, std::ostream&) {}
    inline void deserialize(null_df&, std::istream&) {}

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_NULL_DECISION_FUnCTION_Hh_


dlib C++ Library - null_trainer.h

// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_NULL_TRAINERs_H_
#define DLIB_NULL_TRAINERs_H_

#include "null_trainer_abstract.h"
#include "../algs.h"
#include "function_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename dec_funct_type
        >
    class null_trainer_type
    {
    public:
        typedef typename dec_funct_type::kernel_type kernel_type;
        typedef typename dec_funct_type::scalar_type scalar_type;
        typedef typename dec_funct_type::sample_type sample_type;
        typedef typename dec_funct_type::mem_manager_type mem_manager_type;
        typedef dec_funct_type trained_function_type;

        null_trainer_type (
        ){}

        null_trainer_type (
            const dec_funct_type& dec_funct_
        ) : dec_funct(dec_funct_) {}

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const dec_funct_type& train (
            const in_sample_vector_type& ,
            const in_scalar_vector_type&
        ) const { return dec_funct; }

    private:
        dec_funct_type dec_funct;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename dec_funct_type
        >
    const null_trainer_type<dec_funct_type> null_trainer (
        const dec_funct_type& dec_funct
    ) { return null_trainer_type<dec_funct_type>(dec_funct); }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_NULL_TRAINERs_H_


dlib C++ Library - one_vs_all_decision_function.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ONE_VS_ALL_DECISION_FUnCTION_Hh_
#define DLIB_ONE_VS_ALL_DECISION_FUnCTION_Hh_

#include "one_vs_all_decision_function_abstract.h"

#include "../serialize.h"
#include "../type_safe_union.h"
#include <sstream>
#include <map>
#include "../any.h"
#include "null_df.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename one_vs_all_trainer,
        typename DF1 = null_df, typename DF2 = null_df, typename DF3 = null_df,
        typename DF4 = null_df, typename DF5 = null_df, typename DF6 = null_df,
        typename DF7 = null_df, typename DF8 = null_df, typename DF9 = null_df,
        typename DF10 = null_df
        >
    class one_vs_all_decision_function
    {
    public:

        typedef typename one_vs_all_trainer::label_type result_type;
        typedef typename one_vs_all_trainer::sample_type sample_type;
        typedef typename one_vs_all_trainer::scalar_type scalar_type;
        typedef typename one_vs_all_trainer::mem_manager_type mem_manager_type;

        typedef std::map<result_type, any_decision_function<sample_type, scalar_type> > binary_function_table;

        one_vs_all_decision_function() :num_classes(0) {}

        explicit one_vs_all_decision_function(
            const binary_function_table& dfs_
        ) : dfs(dfs_)
        {
            num_classes = dfs.size();
        }

        const binary_function_table& get_binary_decision_functions (
        ) const
        {
            return dfs;
        }

        const std::vector<result_type> get_labels (
        ) const
        {
            std::vector<result_type> temp;
            temp.reserve(dfs.size());
            for (typename binary_function_table::const_iterator i = dfs.begin(); i != dfs.end(); ++i)
            {
                temp.push_back(i->first);
            }
            return temp;
        }

        template <
            typename df1, typename df2, typename df3, typename df4, typename df5,
            typename df6, typename df7, typename df8, typename df9, typename df10
            >
        one_vs_all_decision_function (
            const one_vs_all_decision_function<one_vs_all_trainer,
                                               df1, df2, df3, df4, df5,
                                               df6, df7, df8, df9, df10>& item
        ) : dfs(item.get_binary_decision_functions()), num_classes(item.number_of_classes()) {}

        unsigned long number_of_classes (
        ) const
        {
            return num_classes;
        }

        std::pair<result_type, scalar_type> predict (
            const sample_type& sample
        ) const
        {
            DLIB_ASSERT(number_of_classes() != 0,
                "\t pair<result_type,scalar_type> one_vs_all_decision_function::predict()"
                << "\n\t You can't make predictions with an empty decision function."
                << "\n\t this: " << this
                );

            result_type best_label = result_type();
            scalar_type best_score = -std::numeric_limits<scalar_type>::infinity();

            // run all the classifiers over the sample and find the best one
            for(typename binary_function_table::const_iterator i = dfs.begin(); i != dfs.end(); ++i)
            {
                const scalar_type score = i->second(sample);

                if (score > best_score)
                {
                    best_score = score;
                    best_label = i->first;
                }
            }

            return std::make_pair(best_label, best_score);
        }

        result_type operator() (
            const sample_type& sample
        ) const
        {
            DLIB_ASSERT(number_of_classes() != 0,
                "\t result_type one_vs_all_decision_function::operator()"
                << "\n\t You can't make predictions with an empty decision function."
                << "\n\t this: " << this
                );

            return predict(sample).first;
        }

    private:
        binary_function_table dfs;
        unsigned long num_classes;

    };

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename DF1, typename DF2, typename DF3,
        typename DF4, typename DF5, typename DF6,
        typename DF7, typename DF8, typename DF9,
        typename DF10
        >
    void serialize(
        const one_vs_all_decision_function<T,DF1,DF2,DF3,DF4,DF5,DF6,DF7,DF8,DF9,DF10>& item,
        std::ostream& out
    )
    {
        try
        {
            type_safe_union<DF1,DF2,DF3,DF4,DF5,DF6,DF7,DF8,DF9,DF10> temp;
            typedef typename T::label_type result_type;
            typedef typename T::sample_type sample_type;
            typedef typename T::scalar_type scalar_type;
            typedef std::map<result_type, any_decision_function<sample_type, scalar_type> > binary_function_table;

            const unsigned long version = 1;
            serialize(version, out);

            const unsigned long size = item.get_binary_decision_functions().size();
            serialize(size, out);

            for(typename binary_function_table::const_iterator i = item.get_binary_decision_functions().begin();
                i != item.get_binary_decision_functions().end(); ++i)
            {
                serialize(i->first, out);

                if      (i->second.template contains<DF1>()) temp.template get<DF1>() = any_cast<DF1>(i->second);
                else if (i->second.template contains<DF2>()) temp.template get<DF2>() = any_cast<DF2>(i->second);
                else if (i->second.template contains<DF3>()) temp.template get<DF3>() = any_cast<DF3>(i->second);
                else if (i->second.template contains<DF4>()) temp.template get<DF4>() = any_cast<DF4>(i->second);
                else if (i->second.template contains<DF5>()) temp.template get<DF5>() = any_cast<DF5>(i->second);
                else if (i->second.template contains<DF6>()) temp.template get<DF6>() = any_cast<DF6>(i->second);
                else if (i->second.template contains<DF7>()) temp.template get<DF7>() = any_cast<DF7>(i->second);
                else if (i->second.template contains<DF8>()) temp.template get<DF8>() = any_cast<DF8>(i->second);
                else if (i->second.template contains<DF9>()) temp.template get<DF9>() = any_cast<DF9>(i->second);
                else if (i->second.template contains<DF10>()) temp.template get<DF10>() = any_cast<DF10>(i->second);
                else throw serialization_error("Can't serialize one_vs_all_decision_function.  Not all decision functions defined.");

                serialize(temp,out);
            }
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while serializing an object of type one_vs_all_decision_function");
        }

    }

// ----------------------------------------------------------------------------------------

    namespace impl_ova
    {
        template <typename sample_type, typename scalar_type>
        struct copy_to_df_helper
        {
            copy_to_df_helper(any_decision_function<sample_type, scalar_type>& target_) : target(target_) {}

            any_decision_function<sample_type, scalar_type>& target;

            template <typename T>
            void operator() (
                const T& item
            ) const
            {
                target = item;
            }
        };
    }

    template <
        typename T,
        typename DF1, typename DF2, typename DF3,
        typename DF4, typename DF5, typename DF6,
        typename DF7, typename DF8, typename DF9,
        typename DF10
        >
    void deserialize(
        one_vs_all_decision_function<T,DF1,DF2,DF3,DF4,DF5,DF6,DF7,DF8,DF9,DF10>& item,
        std::istream& in
    )
    {
        try
        {
            type_safe_union<DF1,DF2,DF3,DF4,DF5,DF6,DF7,DF8,DF9,DF10> temp;
            typedef typename T::label_type result_type;
            typedef typename T::sample_type sample_type;
            typedef typename T::scalar_type scalar_type;
            typedef impl_ova::copy_to_df_helper<sample_type, scalar_type> copy_to;

            unsigned long version;
            deserialize(version, in);

            if (version != 1)
                throw serialization_error("Can't deserialize one_vs_all_decision_function.  Wrong version.");

            unsigned long size;
            deserialize(size, in);

            typedef std::map<result_type, any_decision_function<sample_type, scalar_type> > binary_function_table;
            binary_function_table dfs;

            result_type l;
            for (unsigned long i = 0; i < size; ++i)
            {
                deserialize(l, in);
                deserialize(temp, in);
                if (temp.template contains<null_df>())
                    throw serialization_error("A sub decision function of unknown type was encountered.");

                temp.apply_to_contents(copy_to(dfs[l]));
            }

            item = one_vs_all_decision_function<T,DF1,DF2,DF3,DF4,DF5,DF6,DF7,DF8,DF9,DF10>(dfs);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while deserializing an object of type one_vs_all_decision_function");
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_ONE_VS_ALL_DECISION_FUnCTION_Hh_


dlib C++ Library - one_vs_one_decision_function.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ONE_VS_ONE_DECISION_FUnCTION_Hh_
#define DLIB_ONE_VS_ONE_DECISION_FUnCTION_Hh_

#include "one_vs_one_decision_function_abstract.h"

#include "../serialize.h"
#include "../type_safe_union.h"
#include <iostream>
#include <sstream>
#include <set>
#include <map>
#include "../any.h"
#include "../unordered_pair.h"
#include "null_df.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename one_vs_one_trainer,
        typename DF1 = null_df, typename DF2 = null_df, typename DF3 = null_df,
        typename DF4 = null_df, typename DF5 = null_df, typename DF6 = null_df,
        typename DF7 = null_df, typename DF8 = null_df, typename DF9 = null_df,
        typename DF10 = null_df
        >
    class one_vs_one_decision_function
    {
    public:

        typedef typename one_vs_one_trainer::label_type result_type;
        typedef typename one_vs_one_trainer::sample_type sample_type;
        typedef typename one_vs_one_trainer::scalar_type scalar_type;
        typedef typename one_vs_one_trainer::mem_manager_type mem_manager_type;

        typedef std::map<unordered_pair<result_type>, any_decision_function<sample_type, scalar_type> > binary_function_table;

        one_vs_one_decision_function() :num_classes(0) {}

        explicit one_vs_one_decision_function(
            const binary_function_table& dfs_
        ) : dfs(dfs_)
        {
#ifdef ENABLE_ASSERTS
            {
                const std::vector<unordered_pair<result_type> > missing_pairs = find_missing_pairs(dfs_);
                if (missing_pairs.size() != 0)
                {
                    std::ostringstream sout;
                    for (unsigned long i = 0; i < missing_pairs.size(); ++i)
                    {
                        sout << "\t      (" << missing_pairs[i].first << ", " << missing_pairs[i].second << ")\n";
                    }
                    DLIB_ASSERT(missing_pairs.size() == 0,
                        "\t void one_vs_one_decision_function::one_vs_one_decision_function()"
                        << "\n\t The supplied set of binary decision functions is incomplete."
                        << "\n\t this: " << this
                        << "\n\t Classifiers are missing for the following label pairs: \n" << sout.str()
                                );
                }
            }
#endif

            // figure out how many labels are covered by this set of binary decision functions
            std::set<result_type> labels;
            for (typename binary_function_table::const_iterator i = dfs.begin(); i != dfs.end(); ++i)
            {
                labels.insert(i->first.first);
                labels.insert(i->first.second);
            }
            num_classes = labels.size();
        }

        const binary_function_table& get_binary_decision_functions (
        ) const
        {
            return dfs;
        }

        const std::vector<result_type> get_labels (
        ) const
        {
            std::set<result_type> labels;
            for (typename binary_function_table::const_iterator i = dfs.begin(); i != dfs.end(); ++i)
            {
                labels.insert(i->first.first);
                labels.insert(i->first.second);
            }
            return std::vector<result_type>(labels.begin(), labels.end());
        }

        template <
            typename df1, typename df2, typename df3, typename df4, typename df5,
            typename df6, typename df7, typename df8, typename df9, typename df10
            >
        one_vs_one_decision_function (
            const one_vs_one_decision_function<one_vs_one_trainer,
                                               df1, df2, df3, df4, df5,
                                               df6, df7, df8, df9, df10>& item
        ) : dfs(item.get_binary_decision_functions()), num_classes(item.number_of_classes()) {}

        unsigned long number_of_classes (
        ) const
        {
            return num_classes;
        }

        result_type operator() (
            const sample_type& sample
        ) const
        {
            DLIB_ASSERT(number_of_classes() != 0,
                "\t void one_vs_one_decision_function::operator()"
                << "\n\t You can't make predictions with an empty decision function."
                << "\n\t this: " << this
                );

            std::map<result_type,int> votes;

            // run all the classifiers over the sample
            for(typename binary_function_table::const_iterator i = dfs.begin(); i != dfs.end(); ++i)
            {
                const scalar_type score = i->second(sample);

                if (score > 0)
                    votes[i->first.first] += 1;
                else
                    votes[i->first.second] += 1;
            }

            // now figure out who had the most votes
            result_type best_label = result_type();
            int best_votes = 0;
            for (typename std::map<result_type,int>::iterator i = votes.begin(); i != votes.end(); ++i)
            {
                if (i->second > best_votes)
                {
                    best_votes = i->second;
                    best_label = i->first;
                }
            }

            return best_label;
        }

    private:
        binary_function_table dfs;
        unsigned long num_classes;

    };

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename DF1, typename DF2, typename DF3,
        typename DF4, typename DF5, typename DF6,
        typename DF7, typename DF8, typename DF9,
        typename DF10
        >
    void serialize(
        const one_vs_one_decision_function<T,DF1,DF2,DF3,DF4,DF5,DF6,DF7,DF8,DF9,DF10>& item,
        std::ostream& out
    )
    {
        try
        {
            type_safe_union<DF1,DF2,DF3,DF4,DF5,DF6,DF7,DF8,DF9,DF10> temp;
            typedef typename T::label_type result_type;
            typedef typename T::sample_type sample_type;
            typedef typename T::scalar_type scalar_type;
            typedef std::map<unordered_pair<result_type>, any_decision_function<sample_type, scalar_type> > binary_function_table;

            const unsigned long version = 1;
            serialize(version, out);

            const unsigned long size = item.get_binary_decision_functions().size();
            serialize(size, out);

            for(typename binary_function_table::const_iterator i = item.get_binary_decision_functions().begin();
                i != item.get_binary_decision_functions().end(); ++i)
            {
                serialize(i->first, out);

                if      (i->second.template contains<DF1>()) temp.template get<DF1>() = any_cast<DF1>(i->second);
                else if (i->second.template contains<DF2>()) temp.template get<DF2>() = any_cast<DF2>(i->second);
                else if (i->second.template contains<DF3>()) temp.template get<DF3>() = any_cast<DF3>(i->second);
                else if (i->second.template contains<DF4>()) temp.template get<DF4>() = any_cast<DF4>(i->second);
                else if (i->second.template contains<DF5>()) temp.template get<DF5>() = any_cast<DF5>(i->second);
                else if (i->second.template contains<DF6>()) temp.template get<DF6>() = any_cast<DF6>(i->second);
                else if (i->second.template contains<DF7>()) temp.template get<DF7>() = any_cast<DF7>(i->second);
                else if (i->second.template contains<DF8>()) temp.template get<DF8>() = any_cast<DF8>(i->second);
                else if (i->second.template contains<DF9>()) temp.template get<DF9>() = any_cast<DF9>(i->second);
                else if (i->second.template contains<DF10>()) temp.template get<DF10>() = any_cast<DF10>(i->second);
                else throw serialization_error("Can't serialize one_vs_one_decision_function.  Not all decision functions defined.");

                serialize(temp,out);
            }
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while serializing an object of type one_vs_one_decision_function");
        }

    }

// ----------------------------------------------------------------------------------------

    namespace impl
    {
        template <typename sample_type, typename scalar_type>
        struct copy_to_df_helper
        {
            copy_to_df_helper(any_decision_function<sample_type, scalar_type>& target_) : target(target_) {}

            any_decision_function<sample_type, scalar_type>& target;

            template <typename T>
            void operator() (
                const T& item
            ) const
            {
                target = item;
            }
        };
    }

    template <
        typename T,
        typename DF1, typename DF2, typename DF3,
        typename DF4, typename DF5, typename DF6,
        typename DF7, typename DF8, typename DF9,
        typename DF10
        >
    void deserialize(
        one_vs_one_decision_function<T,DF1,DF2,DF3,DF4,DF5,DF6,DF7,DF8,DF9,DF10>& item,
        std::istream& in
    )
    {
        try
        {
            type_safe_union<DF1,DF2,DF3,DF4,DF5,DF6,DF7,DF8,DF9,DF10> temp;
            typedef typename T::label_type result_type;
            typedef typename T::sample_type sample_type;
            typedef typename T::scalar_type scalar_type;
            typedef impl::copy_to_df_helper<sample_type, scalar_type> copy_to;

            unsigned long version;
            deserialize(version, in);

            if (version != 1)
                throw serialization_error("Can't deserialize one_vs_one_decision_function.  Wrong version.");

            unsigned long size;
            deserialize(size, in);

            typedef std::map<unordered_pair<result_type>, any_decision_function<sample_type, scalar_type> > binary_function_table;
            binary_function_table dfs;

            unordered_pair<result_type> p;
            for (unsigned long i = 0; i < size; ++i)
            {
                deserialize(p, in);
                deserialize(temp, in);
                if (temp.template contains<null_df>())
                    throw serialization_error("A sub decision function of unknown type was encountered.");

                temp.apply_to_contents(copy_to(dfs[p]));
            }

            item = one_vs_one_decision_function<T,DF1,DF2,DF3,DF4,DF5,DF6,DF7,DF8,DF9,DF10>(dfs);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while deserializing an object of type one_vs_one_decision_function");
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_ONE_VS_ONE_DECISION_FUnCTION_Hh_


dlib C++ Library - pegasos.h

// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_PEGASoS_
#define DLIB_PEGASoS_

#include "pegasos_abstract.h"
#include <cmath>
#include "../algs.h"
#include "function.h"
#include "kernel.h"
#include "kcentroid.h"
#include <iostream>
#include "../smart_pointers.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename K
        >
    class svm_pegasos
    {
        typedef kcentroid<offset_kernel<K> > kc_type;

    public:
        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 decision_function<kernel_type> trained_function_type;

        template <typename K_>
        struct rebind {
            typedef svm_pegasos<K_> other;
        };

        svm_pegasos (
        ) :
            max_sv(40),
            lambda_c1(0.0001),
            lambda_c2(0.0001),
            tau(0.01),
            tolerance(0.01),
            train_count(0),
            w(offset_kernel<kernel_type>(kernel,tau),tolerance, max_sv, false)
        {
        }

        svm_pegasos (
            const kernel_type& kernel_,
            const scalar_type& lambda_,
            const scalar_type& tolerance_,
            unsigned long max_num_sv
        ) :
            max_sv(max_num_sv),
            kernel(kernel_),
            lambda_c1(lambda_),
            lambda_c2(lambda_),
            tau(0.01),
            tolerance(tolerance_),
            train_count(0),
            w(offset_kernel<kernel_type>(kernel,tau),tolerance, max_sv, false)
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(lambda_ > 0 && tolerance > 0 && max_num_sv > 0,
                        "\tsvm_pegasos::svm_pegasos(kernel,lambda,tolerance)"
                        << "\n\t invalid inputs were given to this function"
                        << "\n\t lambda_: " << lambda_
                        << "\n\t max_num_sv: " << max_num_sv
            );
        }

        void clear (
        )
        {
            // reset the w vector back to its initial state
            w = kc_type(offset_kernel<kernel_type>(kernel,tau),tolerance, max_sv, false);
            train_count = 0;
        }

        void set_kernel (
            kernel_type k
        )
        {
            kernel = k;
            clear();
        }

        void set_max_num_sv (
            unsigned long max_num_sv
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(max_num_sv > 0,
                        "\tvoid svm_pegasos::set_max_num_sv(max_num_sv)"
                        << "\n\t invalid inputs were given to this function"
                        << "\n\t max_num_sv: " << max_num_sv
            );
            max_sv = max_num_sv;
            clear();
        }

        unsigned long get_max_num_sv (
        ) const
        {
            return max_sv;
        }

        void set_tolerance (
            double tol
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(0 < tol,
                        "\tvoid svm_pegasos::set_tolerance(tol)"
                        << "\n\t invalid inputs were given to this function"
                        << "\n\t tol: " << tol
            );
            tolerance = tol;
            clear();
        }

        void set_lambda (
            scalar_type lambda_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(0 < lambda_,
                        "\tvoid svm_pegasos::set_lambda(lambda_)"
                        << "\n\t invalid inputs were given to this function"
                        << "\n\t lambda_: " << lambda_
            );
            lambda_c1 = lambda_;
            lambda_c2 = lambda_;

            max_wnorm = 1/std::sqrt(std::min(lambda_c1, lambda_c2));
            clear();
        }

        void set_lambda_class1 (
            scalar_type lambda_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(0 < lambda_,
                        "\tvoid svm_pegasos::set_lambda_class1(lambda_)"
                        << "\n\t invalid inputs were given to this function"
                        << "\n\t lambda_: " << lambda_
            );
            lambda_c1 = lambda_;
            max_wnorm = 1/std::sqrt(std::min(lambda_c1, lambda_c2));
            clear();
        }

        void set_lambda_class2 (
            scalar_type lambda_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(0 < lambda_,
                        "\tvoid svm_pegasos::set_lambda_class2(lambda_)"
                        << "\n\t invalid inputs were given to this function"
                        << "\n\t lambda_: " << lambda_
            );
            lambda_c2 = lambda_;
            max_wnorm = 1/std::sqrt(std::min(lambda_c1, lambda_c2));
            clear();
        }

        const scalar_type get_lambda_class1 (
        ) const
        {
            return lambda_c1;
        }

        const scalar_type get_lambda_class2 (
        ) const
        {
            return lambda_c2;
        }

        const scalar_type get_tolerance (
        ) const
        {
            return tolerance;
        }

        const kernel_type get_kernel (
        ) const
        {
            return kernel;
        }

        unsigned long get_train_count (
        ) const
        {
            return static_cast<unsigned long>(train_count);
        }

        scalar_type train (
            const sample_type& x,
            const scalar_type& y
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(y == -1 || y == 1,
                        "\tscalar_type svm_pegasos::train(x,y)"
                        << "\n\t invalid inputs were given to this function"
                        << "\n\t y: " << y
            );

            const double lambda = (y==+1)? lambda_c1 : lambda_c2;

            ++train_count;
            const scalar_type learning_rate = 1/(lambda*train_count);

            // if this sample point is within the margin of the current hyperplane
            if (y*w.inner_product(x) < 1)
            {

                // compute: w = (1-learning_rate*lambda)*w + y*learning_rate*x
                w.train(x,  1 - learning_rate*lambda,  y*learning_rate);

                scalar_type wnorm = std::sqrt(w.squared_norm());
                scalar_type temp = max_wnorm/wnorm;
                if (temp < 1)
                    w.scale_by(temp);
            }
            else
            {
                w.scale_by(1 - learning_rate*lambda);
            }

            // return the current learning rate
            return 1/(std::min(lambda_c1,lambda_c2)*train_count);
        }

        scalar_type operator() (
            const sample_type& x
        ) const
        {
            return w.inner_product(x);
        }

        const decision_function<kernel_type> get_decision_function (
        ) const
        {
            distance_function<offset_kernel<kernel_type> > df = w.get_distance_function();
            return decision_function<kernel_type>(df.get_alpha(), -tau*sum(df.get_alpha()), kernel, df.get_basis_vectors());
        }

        void swap (
            svm_pegasos& item
        )
        {
            exchange(max_sv,         item.max_sv);
            exchange(kernel,         item.kernel);
            exchange(lambda_c1,      item.lambda_c1);
            exchange(lambda_c2,      item.lambda_c2);
            exchange(max_wnorm,      item.max_wnorm);
            exchange(tau,            item.tau);
            exchange(tolerance,      item.tolerance);
            exchange(train_count,    item.train_count);
            exchange(w,              item.w);
        }

        friend void serialize(const svm_pegasos& item, std::ostream& out)
        {
            serialize(item.max_sv, out);
            serialize(item.kernel, out);
            serialize(item.lambda_c1, out);
            serialize(item.lambda_c2, out);
            serialize(item.max_wnorm, out);
            serialize(item.tau, out);
            serialize(item.tolerance, out);
            serialize(item.train_count, out);
            serialize(item.w, out);
        }

        friend void deserialize(svm_pegasos& item, std::istream& in)
        {
            deserialize(item.max_sv, in);
            deserialize(item.kernel, in);
            deserialize(item.lambda_c1, in);
            deserialize(item.lambda_c2, in);
            deserialize(item.max_wnorm, in);
            deserialize(item.tau, in);
            deserialize(item.tolerance, in);
            deserialize(item.train_count, in);
            deserialize(item.w, in);
        }

    private:

        unsigned long max_sv;
        kernel_type kernel;
        scalar_type lambda_c1;
        scalar_type lambda_c2;
        scalar_type max_wnorm;
        scalar_type tau;
        scalar_type tolerance;
        scalar_type train_count;
        kc_type w;

    }; // end of class svm_pegasos

    template <
        typename K
        >
    void swap (
        svm_pegasos<K>& a,
        svm_pegasos<K>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename U
        >
    void replicate_settings (
        const svm_pegasos<T>& source,
        svm_pegasos<U>& dest
    )
    {
        dest.set_tolerance(source.get_tolerance());
        dest.set_lambda_class1(source.get_lambda_class1());
        dest.set_lambda_class2(source.get_lambda_class2());
        dest.set_max_num_sv(source.get_max_num_sv());
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type
        >
    class batch_trainer
    {

    // ------------------------------------------------------------------------------------

        template <
            typename K,
            typename sample_vector_type
            >
        class caching_kernel
        {
        public:
            typedef typename K::scalar_type scalar_type;
            typedef long sample_type;
            //typedef typename K::sample_type sample_type;
            typedef typename K::mem_manager_type mem_manager_type;

            caching_kernel () : samples(0), counter(0), counter_threshold(0) {}

            caching_kernel (
                const K& kern,
                const sample_vector_type& samps,
                long cache_size_
            ) : real_kernel(kern), samples(&samps), counter(0)
            {
                cache_size = std::min<long>(cache_size_, samps.size());

                cache.reset(new cache_type);
                cache->frequency_of_use.resize(samps.size());
                for (long i = 0; i < samps.size(); ++i)
                    cache->frequency_of_use[i] = std::make_pair(0, i);

                // Set the cache build/rebuild threshold so that we have to have
                // as many cache misses as there are entries in the cache before
                // we build/rebuild.
                counter_threshold = samps.size()*cache_size;
                cache->sample_location.assign(samples->size(), -1);
            }

            scalar_type operator() (
                const sample_type& a,
                const sample_type& b
            )  const
            {
                // rebuild the cache every so often
                if (counter > counter_threshold )
                {
                    build_cache();
                }

                const long a_loc = cache->sample_location[a];
                const long b_loc = cache->sample_location[b];

                cache->frequency_of_use[a].first += 1;
                cache->frequency_of_use[b].first += 1;

                if (a_loc != -1)
                {
                    return cache->kernel(a_loc, b);
                }
                else if (b_loc != -1)
                {
                    return cache->kernel(b_loc, a);
                }
                else
                {
                    ++counter;
                    return real_kernel((*samples)(a), (*samples)(b));
                }
            }

            bool operator== (
                const caching_kernel& item
            ) const
            {
                return item.real_kernel == real_kernel &&
                    item.samples == samples;
            }

        private:
            K real_kernel;

            void build_cache (
            ) const
            {
                std::sort(cache->frequency_of_use.rbegin(), cache->frequency_of_use.rend());
                counter = 0;

                cache->kernel.set_size(cache_size, samples->size());
                cache->sample_location.assign(samples->size(), -1);

                // loop over all the samples in the cache
                for (long i = 0; i < cache_size; ++i)
                {
                    const long cur = cache->frequency_of_use[i].second;
                    cache->sample_location[cur] = i;

                    // now populate all possible kernel products with the current sample
                    for (long j = 0; j < samples->size(); ++j)
                    {
                        cache->kernel(i, j) = real_kernel((*samples)(cur), (*samples)(j));
                    }

                }

                // reset the frequency of use metrics
                for (long i = 0; i < samples->size(); ++i)
                    cache->frequency_of_use[i] = std::make_pair(0, i);
            }

            struct cache_type
            {
                matrix<scalar_type> kernel;

                std::vector<long> sample_location; // where in the cache a sample is.  -1 means not in cache
                std::vector<std::pair<long,long> > frequency_of_use;
            };

            const sample_vector_type* samples;

            shared_ptr<cache_type> cache;
            mutable unsigned long counter;
            unsigned long counter_threshold;
            long cache_size;
        };

    // ------------------------------------------------------------------------------------

    public:
        typedef typename trainer_type::kernel_type kernel_type;
        typedef typename trainer_type::scalar_type scalar_type;
        typedef typename trainer_type::sample_type sample_type;
        typedef typename trainer_type::mem_manager_type mem_manager_type;
        typedef typename trainer_type::trained_function_type trained_function_type;

        batch_trainer (
        ) :
            min_learning_rate(0.1),
            use_cache(false),
            cache_size(100)
        {
        }

        batch_trainer (
            const trainer_type& trainer_,
            const scalar_type min_learning_rate_,
            bool verbose_,
            bool use_cache_,
            long cache_size_ = 100
        ) :
            trainer(trainer_),
            min_learning_rate(min_learning_rate_),
            verbose(verbose_),
            use_cache(use_cache_),
            cache_size(cache_size_)
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(0 < min_learning_rate_ &&
                        cache_size_ > 0,
                        "\tbatch_trainer::batch_trainer()"
                        << "\n\t invalid inputs were given to this function"
                        << "\n\t min_learning_rate_: " << min_learning_rate_
                        << "\n\t cache_size_: " << cache_size_
            );

            trainer.clear();
        }

        const scalar_type get_min_learning_rate (
        ) const
        {
            return min_learning_rate;
        }

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y
        ) const
        {
            if (use_cache)
                return do_train_cached(mat(x), mat(y));
            else
                return do_train(mat(x), mat(y));
        }

    private:

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> do_train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y
        ) const
        {

            dlib::rand rnd;

            trainer_type my_trainer(trainer);

            scalar_type cur_learning_rate = min_learning_rate + 10;
            unsigned long count = 0;

            while (cur_learning_rate > min_learning_rate)
            {
                const long i = rnd.get_random_32bit_number()%x.size();
                // keep feeding the trainer data until its learning rate goes below our threshold
                cur_learning_rate = my_trainer.train(x(i), y(i));

                if (verbose)
                {
                    if ( (count&0x7FF) == 0)
                    {
                        std::cout << "\rbatch_trainer(): Percent complete: "
                                  << 100*min_learning_rate/cur_learning_rate << "             " << std::flush;
                    }
                    ++count;
                }
            }

            if (verbose)
            {
                decision_function<kernel_type> df = my_trainer.get_decision_function();
                std::cout << "\rbatch_trainer(): Percent complete: 100           " << std::endl;
                std::cout << "    Num sv: " << df.basis_vectors.size() << std::endl;
                std::cout << "    bias:   " << df.b << std::endl;
                return df;
            }
            else
            {
                return my_trainer.get_decision_function();
            }
        }

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> do_train_cached (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y
        ) const
        {

            dlib::rand rnd;

            // make a caching kernel
            typedef caching_kernel<kernel_type, in_sample_vector_type> ckernel_type;
            ckernel_type ck(trainer.get_kernel(), x, cache_size);

            // now rebind the trainer to use the caching kernel
            typedef typename trainer_type::template rebind<ckernel_type>::other rebound_trainer_type;
            rebound_trainer_type my_trainer;
            my_trainer.set_kernel(ck);
            replicate_settings(trainer, my_trainer);

            scalar_type cur_learning_rate = min_learning_rate + 10;
            unsigned long count = 0;

            while (cur_learning_rate > min_learning_rate)
            {
                const long i = rnd.get_random_32bit_number()%x.size();
                // keep feeding the trainer data until its learning rate goes below our threshold
                cur_learning_rate = my_trainer.train(i, y(i));

                if (verbose)
                {
                    if ( (count&0x7FF) == 0)
                    {
                        std::cout << "\rbatch_trainer(): Percent complete: "
                                  << 100*min_learning_rate/cur_learning_rate << "             " << std::flush;
                    }
                    ++count;
                }
            }

            if (verbose)
            {
                decision_function<ckernel_type> cached_df;
                cached_df = my_trainer.get_decision_function();

                std::cout << "\rbatch_trainer(): Percent complete: 100           " << std::endl;
                std::cout << "    Num sv: " << cached_df.basis_vectors.size() << std::endl;
                std::cout << "    bias:   " << cached_df.b << std::endl;

                return decision_function<kernel_type> (
                        cached_df.alpha,
                        cached_df.b,
                        trainer.get_kernel(),
                        rowm(x, cached_df.basis_vectors)
                        );
            }
            else
            {
                decision_function<ckernel_type> cached_df;
                cached_df = my_trainer.get_decision_function();

                return decision_function<kernel_type> (
                        cached_df.alpha,
                        cached_df.b,
                        trainer.get_kernel(),
                        rowm(x, cached_df.basis_vectors)
                        );
            }
        }

        trainer_type trainer;
        scalar_type min_learning_rate;
        bool verbose;
        bool use_cache;
        long cache_size;

    }; // end of class batch_trainer

// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type
        >
    const batch_trainer<trainer_type> batch (
        const trainer_type& trainer,
        const typename trainer_type::scalar_type min_learning_rate = 0.1
    ) { return batch_trainer<trainer_type>(trainer, min_learning_rate, false, false); }

// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type
        >
    const batch_trainer<trainer_type> verbose_batch (
        const trainer_type& trainer,
        const typename trainer_type::scalar_type min_learning_rate = 0.1
    ) { return batch_trainer<trainer_type>(trainer, min_learning_rate, true, false); }

// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type
        >
    const batch_trainer<trainer_type> batch_cached (
        const trainer_type& trainer,
        const typename trainer_type::scalar_type min_learning_rate = 0.1,
        long cache_size = 100
    ) { return batch_trainer<trainer_type>(trainer, min_learning_rate, false, true, cache_size); }

// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type
        >
    const batch_trainer<trainer_type> verbose_batch_cached (
        const trainer_type& trainer,
        const typename trainer_type::scalar_type min_learning_rate = 0.1,
        long cache_size = 100
    ) { return batch_trainer<trainer_type>(trainer, min_learning_rate, true, true, cache_size); }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_PEGASoS_


dlib C++ Library - ranking_tools.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_RANKING_ToOLS_Hh_
#define DLIB_RANKING_ToOLS_Hh_

#include "ranking_tools_abstract.h"

#include "../algs.h"
#include "../matrix.h"
#include <vector>
#include <utility>
#include <algorithm>
#include "sparse_vector.h"
#include "../statistics.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    struct ranking_pair
    {
        ranking_pair() {}

        ranking_pair(
            const std::vector<T>& r,
            const std::vector<T>& nr
        ) :
            relevant(r), nonrelevant(nr)
        {}

        std::vector<T> relevant;
        std::vector<T> nonrelevant;
    };

    template <
        typename T
        >
    void serialize (
        const ranking_pair<T>& item,
        std::ostream& out
    )
    {
        int version = 1;
        serialize(version, out);
        serialize(item.relevant, out);
        serialize(item.nonrelevant, out);
    }

    template <
        typename T
        >
    void deserialize (
        ranking_pair<T>& item,
        std::istream& in
    )
    {
        int version = 0;
        deserialize(version, in);
        if (version != 1)
            throw dlib::serialization_error("Wrong version found while deserializing dlib::ranking_pair");

        deserialize(item.relevant, in);
        deserialize(item.nonrelevant, in);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    typename disable_if<is_matrix<T>,bool>::type is_ranking_problem (
        const std::vector<ranking_pair<T> >& samples
    )
    {
        if (samples.size() == 0)
            return false;

        for (unsigned long i = 0; i < samples.size(); ++i)
        {
            if (samples[i].relevant.size() == 0)
                return false;
            if (samples[i].nonrelevant.size() == 0)
                return false;
        }

        return true;
    }

    template <
        typename T
        >
    typename enable_if<is_matrix<T>,bool>::type is_ranking_problem (
        const std::vector<ranking_pair<T> >& samples
    )
    {
        if (samples.size() == 0)
            return false;

        for (unsigned long i = 0; i < samples.size(); ++i)
        {
            if (samples[i].relevant.size() == 0)
                return false;
            if (samples[i].nonrelevant.size() == 0)
                return false;
        }

        // If these are dense vectors then they must all have the same dimensionality.
        const long dims = max_index_plus_one(samples[0].relevant);
        for (unsigned long i = 0; i < samples.size(); ++i)
        {
            for (unsigned long j = 0; j < samples[i].relevant.size(); ++j)
            {
                if (is_vector(samples[i].relevant[j]) == false)
                    return false;

                if (samples[i].relevant[j].size() != dims)
                    return false;
            }
            for (unsigned long j = 0; j < samples[i].nonrelevant.size(); ++j)
            {
                if (is_vector(samples[i].nonrelevant[j]) == false)
                    return false;

                if (samples[i].nonrelevant[j].size() != dims)
                    return false;
            }
        }

        return true;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    unsigned long max_index_plus_one (
        const ranking_pair<T>& item
    )
    {
        return std::max(max_index_plus_one(item.relevant), max_index_plus_one(item.nonrelevant));
    }

    template <
        typename T
        >
    unsigned long max_index_plus_one (
        const std::vector<ranking_pair<T> >& samples
    )
    {
        unsigned long dims = 0;
        for (unsigned long i = 0; i < samples.size(); ++i)
        {
            dims = std::max(dims, max_index_plus_one(samples[i]));
        }
        return dims;
    }

// ----------------------------------------------------------------------------------------

    template <typename T>
    void 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);

        if (x.size() == 0 || y.size() == 0)
            return;

        std::vector<std::pair<T,unsigned long> > xsort(x.size());
        std::vector<std::pair<T,unsigned long> > ysort(y.size());
        for (unsigned long i = 0; i < x.size(); ++i)
            xsort[i] = std::make_pair(x[i], i);
        for (unsigned long j = 0; j < y.size(); ++j)
            ysort[j] = std::make_pair(y[j], j);

        std::sort(xsort.begin(), xsort.end());
        std::sort(ysort.begin(), ysort.end());

        unsigned long i, j;

        // Do the counting for the x values.
        for (i = 0, j = 0; i < x_count.size(); ++i)
        {
            // Skip past y values that are in the correct order with respect to xsort[i].
            while (j < ysort.size() && ysort[j].first < xsort[i].first)
                ++j;

            x_count[xsort[i].second] = ysort.size() - j;
        }

        // Now do the counting for the y values.
        for (i = 0, j = 0; j < y_count.size(); ++j)
        {
            // Skip past x values that are in the incorrect order with respect to ysort[j].
            while (i < xsort.size() && !(ysort[j].first < xsort[i].first))
                ++i;

            y_count[ysort[j].second] = i;
        }
    }

// ----------------------------------------------------------------------------------------

    namespace impl
    {
        inline bool compare_first_reverse_second (
            const std::pair<double,bool>& a,
            const std::pair<double,bool>& b
        )
        {
            if (a.first < b.first)
                return true;
            else if (a.first > b.first)
                return false;
            else if (a.second && !b.second)
                return true;
            else
                return false;
        }
    }

    template <
        typename ranking_function,
        typename T
        >
    matrix<double,1,2> test_ranking_function (
        const ranking_function& funct,
        const std::vector<ranking_pair<T> >& samples
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(is_ranking_problem(samples),
            "\t double test_ranking_function()"
            << "\n\t invalid inputs were given to this function"
            << "\n\t samples.size(): " << samples.size()
            << "\n\t is_ranking_problem(samples): " << is_ranking_problem(samples)
            );

        unsigned long total_pairs = 0;
        unsigned long total_wrong = 0;

        std::vector<double> rel_scores;
        std::vector<double> nonrel_scores;
        std::vector<unsigned long> rel_counts;
        std::vector<unsigned long> nonrel_counts;

        running_stats<double> rs;
        std::vector<std::pair<double,bool> > total_scores;
        std::vector<bool> total_ranking;

        for (unsigned long i = 0; i < samples.size(); ++i)
        {
            rel_scores.resize(samples[i].relevant.size());
            nonrel_scores.resize(samples[i].nonrelevant.size());
            total_scores.clear();

            for (unsigned long k = 0; k < rel_scores.size(); ++k)
            {
                rel_scores[k] = funct(samples[i].relevant[k]);
                total_scores.push_back(std::make_pair(rel_scores[k], true));
            }

            for (unsigned long k = 0; k < nonrel_scores.size(); ++k)
            {
                nonrel_scores[k] = funct(samples[i].nonrelevant[k]);
                total_scores.push_back(std::make_pair(nonrel_scores[k], false));
            }

            // Now compute the average precision for this sample.  We need to sort the
            // results and the back them into total_ranking.  Note that we sort them so
            // that, if you get a block of ranking values that are all equal, the elements
            // marked as true will come last.  This prevents a ranking from outputting a
            // constant value for everything and still getting a good MAP score.
            std::sort(total_scores.rbegin(), total_scores.rend(), impl::compare_first_reverse_second);
            total_ranking.clear();
            for (unsigned long i = 0; i < total_scores.size(); ++i)
                total_ranking.push_back(total_scores[i].second);
            rs.add(average_precision(total_ranking));

            count_ranking_inversions(rel_scores, nonrel_scores, rel_counts, nonrel_counts);

            total_pairs += rel_scores.size()*nonrel_scores.size();

            // Note that we don't need to look at nonrel_counts since it is redundant with
            // the information in rel_counts in this case.
            total_wrong += sum(mat(rel_counts));
        }

        const double rank_swaps = static_cast<double>(total_pairs - total_wrong) / total_pairs;
        const double mean_average_precision = rs.mean();
        matrix<double,1,2> res;
        res = rank_swaps, mean_average_precision;
        return res;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename ranking_function,
        typename T
        >
    matrix<double,1,2> test_ranking_function (
        const ranking_function& funct,
        const ranking_pair<T>& sample
    )
    {
        return test_ranking_function(funct, std::vector<ranking_pair<T> >(1,sample));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type,
        typename T
        >
    matrix<double,1,2> cross_validate_ranking_trainer (
        const trainer_type& trainer,
        const std::vector<ranking_pair<T> >& samples,
        const long folds
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(is_ranking_problem(samples) &&
                    1 < folds && folds <= static_cast<long>(samples.size()),
            "\t double cross_validate_ranking_trainer()"
            << "\n\t invalid inputs were given to this function"
            << "\n\t samples.size(): " << samples.size()
            << "\n\t folds:  " << folds
            << "\n\t is_ranking_problem(samples): " << is_ranking_problem(samples)
            );

        const long num_in_test  = samples.size()/folds;
        const long num_in_train = samples.size() - num_in_test;

        std::vector<ranking_pair<T> > samples_test, samples_train;

        long next_test_idx = 0;

        unsigned long total_pairs = 0;
        unsigned long total_wrong = 0;

        std::vector<double> rel_scores;
        std::vector<double> nonrel_scores;
        std::vector<unsigned long> rel_counts;
        std::vector<unsigned long> nonrel_counts;

        running_stats<double> rs;
        std::vector<std::pair<double,bool> > total_scores;
        std::vector<bool> total_ranking;

        for (long i = 0; i < folds; ++i)
        {
            samples_test.clear();
            samples_train.clear();

            // load up the test samples
            for (long cnt = 0; cnt < num_in_test; ++cnt)
            {
                samples_test.push_back(samples[next_test_idx]);
                next_test_idx = (next_test_idx + 1)%samples.size();
            }

            // load up the training samples
            long next = next_test_idx;
            for (long cnt = 0; cnt < num_in_train; ++cnt)
            {
                samples_train.push_back(samples[next]);
                next = (next + 1)%samples.size();
            }

            const typename trainer_type::trained_function_type& df = trainer.train(samples_train);

            // check how good df is on the test data
            for (unsigned long i = 0; i < samples_test.size(); ++i)
            {
                rel_scores.resize(samples_test[i].relevant.size());
                nonrel_scores.resize(samples_test[i].nonrelevant.size());

                total_scores.clear();

                for (unsigned long k = 0; k < rel_scores.size(); ++k)
                {
                    rel_scores[k] = df(samples_test[i].relevant[k]);
                    total_scores.push_back(std::make_pair(rel_scores[k], true));
                }

                for (unsigned long k = 0; k < nonrel_scores.size(); ++k)
                {
                    nonrel_scores[k] = df(samples_test[i].nonrelevant[k]);
                    total_scores.push_back(std::make_pair(nonrel_scores[k], false));
                }

                // Now compute the average precision for this sample.  We need to sort the
                // results and the back them into total_ranking.  Note that we sort them so
                // that, if you get a block of ranking values that are all equal, the elements
                // marked as true will come last.  This prevents a ranking from outputting a
                // constant value for everything and still getting a good MAP score.
                std::sort(total_scores.rbegin(), total_scores.rend(), impl::compare_first_reverse_second);
                total_ranking.clear();
                for (unsigned long i = 0; i < total_scores.size(); ++i)
                    total_ranking.push_back(total_scores[i].second);
                rs.add(average_precision(total_ranking));

                count_ranking_inversions(rel_scores, nonrel_scores, rel_counts, nonrel_counts);

                total_pairs += rel_scores.size()*nonrel_scores.size();

                // Note that we don't need to look at nonrel_counts since it is redundant with
                // the information in rel_counts in this case.
                total_wrong += sum(mat(rel_counts));
            }

        } // for (long i = 0; i < folds; ++i)

        const double rank_swaps = static_cast<double>(total_pairs - total_wrong) / total_pairs;
        const double mean_average_precision = rs.mean();
        matrix<double,1,2> res;
        res = rank_swaps, mean_average_precision;
        return res;
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_RANKING_ToOLS_Hh_


dlib C++ Library - rbf_network.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_RBf_NETWORK_
#define DLIB_RBf_NETWORK_

#include "../matrix.h"
#include "rbf_network_abstract.h"
#include "kernel.h"
#include "linearly_independent_subset_finder.h"
#include "function.h"
#include "../algs.h"

namespace dlib
{

// ------------------------------------------------------------------------------

    template <
        typename Kern
        >
    class rbf_network_trainer
    {
        /*!
            This is an implementation of an RBF network trainer that follows
            the directions right off Wikipedia basically.  So nothing
            particularly fancy.  Although the way the centers are selected
            is somewhat unique.
        !*/

    public:
        typedef Kern 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 decision_function<kernel_type> trained_function_type;

        rbf_network_trainer (
        ) :
            num_centers(10)
        {
        }

        void set_kernel (
            const kernel_type& k
        )
        {
            kernel = k;
        }

        const kernel_type& get_kernel (
        ) const
        {
            return kernel;
        }

        void set_num_centers (
            const unsigned long num
        )
        {
            num_centers = num;
        }

        unsigned long get_num_centers (
        ) const
        {
            return num_centers;
        }

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y
        ) const
        {
            return do_train(mat(x), mat(y));
        }

        void swap (
            rbf_network_trainer& item
        )
        {
            exchange(kernel, item.kernel);
            exchange(num_centers, item.num_centers);
        }

    private:

    // ------------------------------------------------------------------------------------

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> do_train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y
        ) const
        {
            typedef typename decision_function<kernel_type>::scalar_vector_type scalar_vector_type;

            // make sure requires clause is not broken
            DLIB_ASSERT(is_learning_problem(x,y),
                "\tdecision_function rbf_network_trainer::train(x,y)"
                << "\n\t invalid inputs were given to this function"
                << "\n\t x.nr(): " << x.nr()
                << "\n\t y.nr(): " << y.nr()
                << "\n\t x.nc(): " << x.nc()
                << "\n\t y.nc(): " << y.nc()
                );

            // use the linearly_independent_subset_finder object to select the centers.  So here
            // we show it all the data samples so it can find the best centers.
            linearly_independent_subset_finder<kernel_type> lisf(kernel, num_centers);
            fill_lisf(lisf, x);

            const long num_centers = lisf.size();

            // fill the K matrix with the output of the kernel for all the center and sample point pairs
            matrix<scalar_type,0,0,mem_manager_type> K(x.nr(), num_centers+1);
            for (long r = 0; r < x.nr(); ++r)
            {
                for (long c = 0; c < num_centers; ++c)
                {
                    K(r,c) = kernel(x(r), lisf[c]);
                }
                // This last column of the K matrix takes care of the bias term
                K(r,num_centers) = 1;
            }

            // compute the best weights by using the pseudo-inverse
            scalar_vector_type weights(pinv(K)*y);

            // now put everything into a decision_function object and return it
            return decision_function<kernel_type> (remove_row(weights,num_centers),
                                                   -weights(num_centers),
                                                   kernel,
                                                   lisf.get_dictionary());

        }

        kernel_type kernel;
        unsigned long num_centers;

    }; // end of class rbf_network_trainer

// ----------------------------------------------------------------------------------------

    template <typename sample_type>
    void swap (
        rbf_network_trainer<sample_type>& a,
        rbf_network_trainer<sample_type>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_RBf_NETWORK_


dlib C++ Library - reduced.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_REDUCEd_TRAINERS_
#define DLIB_REDUCEd_TRAINERS_

#include "reduced_abstract.h"
#include "../matrix.h"
#include "../algs.h"
#include "function.h"
#include "kernel.h"
#include "kcentroid.h"
#include "linearly_independent_subset_finder.h"
#include "../optimization.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type
        >
    class reduced_decision_function_trainer
    {
    public:
        typedef typename trainer_type::kernel_type kernel_type;
        typedef typename trainer_type::scalar_type scalar_type;
        typedef typename trainer_type::sample_type sample_type;
        typedef typename trainer_type::mem_manager_type mem_manager_type;
        typedef typename trainer_type::trained_function_type trained_function_type;

        reduced_decision_function_trainer (
        ) :num_bv(0) {}

        reduced_decision_function_trainer (
            const trainer_type& trainer_,
            const unsigned long num_sb_
        ) :
            trainer(trainer_),
            num_bv(num_sb_)
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(num_bv > 0,
                        "\t reduced_decision_function_trainer()"
                        << "\n\t you have given invalid arguments to this function"
                        << "\n\t num_bv: " << num_bv
            );
        }

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(num_bv > 0,
                        "\t reduced_decision_function_trainer::train(x,y)"
                        << "\n\t You have tried to use an uninitialized version of this object"
                        << "\n\t num_bv: " << num_bv );
            return do_train(mat(x), mat(y));
        }

    private:

    // ------------------------------------------------------------------------------------

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> do_train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y
        ) const
        {
            // get the decision function object we are going to try and approximate
            const decision_function<kernel_type>& dec_funct = trainer.train(x,y);

            // now find a linearly independent subset of the training points of num_bv points.
            linearly_independent_subset_finder<kernel_type> lisf(dec_funct.kernel_function, num_bv);
            fill_lisf(lisf, x);

            // The next few statements just find the best weights with which to approximate
            // the dec_funct object with the smaller set of vectors in the lisf dictionary.  This
            // is really just a simple application of some linear algebra.  For the details
            // see page 554 of Learning with kernels by Scholkopf and Smola where they talk
            // about "Optimal Expansion Coefficients."

            const kernel_type kern(dec_funct.kernel_function);

            matrix<scalar_type,0,1,mem_manager_type> alpha;

            alpha = lisf.get_inv_kernel_marix()*(kernel_matrix(kern,lisf,dec_funct.basis_vectors)*dec_funct.alpha);

            decision_function<kernel_type> new_df(alpha,
                                                  0,
                                                  kern,
                                                  lisf.get_dictionary());

            // now we have to figure out what the new bias should be.  It might be a little
            // different since we just messed with all the weights and vectors.
            double bias = 0;
            for (long i = 0; i < x.nr(); ++i)
            {
                bias += new_df(x(i)) - dec_funct(x(i));
            }

            new_df.b = bias/x.nr();

            return new_df;
        }

    // ------------------------------------------------------------------------------------

        trainer_type trainer;
        unsigned long num_bv;

    }; // end of class reduced_decision_function_trainer

    template <typename trainer_type>
    const reduced_decision_function_trainer<trainer_type> reduced (
        const trainer_type& trainer,
        const unsigned long num_bv
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(num_bv > 0,
                    "\tconst reduced_decision_function_trainer reduced()"
                    << "\n\t you have given invalid arguments to this function"
                    << "\n\t num_bv: " << num_bv
        );

        return reduced_decision_function_trainer<trainer_type>(trainer, num_bv);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    namespace red_impl
    {

    // ------------------------------------------------------------------------------------

        template <typename kernel_type>
        class objective
        {
            /*
                This object represents the objective function we will try to
                minimize in approximate_distance_function().

                The objective is the distance, in kernel induced feature space, between
                the original distance function and the approximated version.

            */
            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;
        public:
            objective(
                const distance_function<kernel_type>& dist_funct_,
                matrix<scalar_type,0,1,mem_manager_type>& b_,
                matrix<sample_type,0,1,mem_manager_type>& out_vectors_
            ) :
                dist_funct(dist_funct_),
                b(b_),
                out_vectors(out_vectors_)
            {
            }

            const matrix<scalar_type, 0, 1, mem_manager_type> state_to_vector (
            ) const
            /*!
                ensures
                    - returns a vector that contains all the information necessary to
                      reproduce the current state of the approximated distance function
            !*/
            {
                matrix<scalar_type, 0, 1, mem_manager_type> z(b.nr() + out_vectors.size()*out_vectors(0).nr());
                long i = 0;
                for (long j = 0; j < b.nr(); ++j)
                {
                    z(i) = b(j);
                    ++i;
                }

                for (long j = 0; j < out_vectors.size(); ++j)
                {
                    for (long k = 0; k < out_vectors(j).size(); ++k)
                    {
                        z(i) = out_vectors(j)(k);
                        ++i;
                    }
                }
                return z;
            }

            void vector_to_state (
                const matrix<scalar_type, 0, 1, mem_manager_type>& z
            ) const
            /*!
                requires
                    - z came from the state_to_vector() function or has a compatible format
                ensures
                    - loads the vector z into the state variables of the approximate
                      distance function (i.e. b and out_vectors)
            !*/
            {
                long i = 0;
                for (long j = 0; j < b.nr(); ++j)
                {
                    b(j) = z(i);
                    ++i;
                }

                for (long j = 0; j < out_vectors.size(); ++j)
                {
                    for (long k = 0; k < out_vectors(j).size(); ++k)
                    {
                        out_vectors(j)(k) = z(i);
                        ++i;
                    }
                }
            }

            double operator() (
                const matrix<scalar_type, 0, 1, mem_manager_type>& z
            ) const
            /*!
                ensures
                    - loads the current approximate distance function with z
                    - returns the distance between the original distance function
                      and the approximate one.
            !*/
            {
                vector_to_state(z);
                const kernel_type k(dist_funct.get_kernel());

                double temp = 0;
                for (long i = 0; i < out_vectors.size(); ++i)
                {
                    for (long j = 0; j < dist_funct.get_basis_vectors().nr(); ++j)
                    {
                        temp -= b(i)*dist_funct.get_alpha()(j)*k(out_vectors(i), dist_funct.get_basis_vectors()(j));
                    }
                }

                temp *= 2;

                for (long i = 0; i < out_vectors.size(); ++i)
                {
                    for (long j = 0; j < out_vectors.size(); ++j)
                    {
                        temp += b(i)*b(j)*k(out_vectors(i), out_vectors(j));
                    }
                }

                return temp + dist_funct.get_squared_norm();
            }

        private:

            const distance_function<kernel_type>& dist_funct;
            matrix<scalar_type,0,1,mem_manager_type>& b;
            matrix<sample_type,0,1,mem_manager_type>& out_vectors;

        };

    // ------------------------------------------------------------------------------------

        template <typename kernel_type>
        class objective_derivative
        {
            /*!
                This object represents the derivative of the objective object
            !*/
            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;
        public:

            objective_derivative(
                const distance_function<kernel_type>& dist_funct_,
                matrix<scalar_type,0,1,mem_manager_type>& b_,
                matrix<sample_type,0,1,mem_manager_type>& out_vectors_
            ) :
                dist_funct(dist_funct_),
                b(b_),
                out_vectors(out_vectors_)
            {
            }

            void vector_to_state (
                const matrix<scalar_type, 0, 1, mem_manager_type>& z
            ) const
            /*!
                requires
                    - z came from the state_to_vector() function or has a compatible format
                ensures
                    - loads the vector z into the state variables of the approximate
                      distance function (i.e. b and out_vectors)
            !*/
            {
                long i = 0;
                for (long j = 0; j < b.nr(); ++j)
                {
                    b(j) = z(i);
                    ++i;
                }

                for (long j = 0; j < out_vectors.size(); ++j)
                {
                    for (long k = 0; k < out_vectors(j).size(); ++k)
                    {
                        out_vectors(j)(k) = z(i);
                        ++i;
                    }
                }
            }

            const matrix<scalar_type,0,1,mem_manager_type>& operator() (
                const matrix<scalar_type, 0, 1, mem_manager_type>& z
            ) const
            /*!
                ensures
                    - loads the current approximate distance function with z
                    - returns the derivative of the distance between the original
                      distance function and the approximate one.
            !*/
            {
                vector_to_state(z);
                res.set_size(z.nr());
                set_all_elements(res,0);
                const kernel_type k(dist_funct.get_kernel());
                const kernel_derivative<kernel_type> K_der(k);

                // first compute the gradient for the beta weights
                for (long i = 0; i < out_vectors.size(); ++i)
                {
                    for (long j = 0; j < out_vectors.size(); ++j)
                    {
                        res(i) += b(j)*k(out_vectors(i), out_vectors(j));
                    }
                }
                for (long i = 0; i < out_vectors.size(); ++i)
                {
                    for (long j = 0; j < dist_funct.get_basis_vectors().size(); ++j)
                    {
                        res(i) -= dist_funct.get_alpha()(j)*k(out_vectors(i), dist_funct.get_basis_vectors()(j));
                    }
                }

                // now compute the gradient of the actual vectors that go into the kernel functions
                long pos = out_vectors.size();
                const long num = out_vectors(0).nr();
                temp.set_size(num,1);
                for (long i = 0; i < out_vectors.size(); ++i)
                {
                    set_all_elements(temp,0);
                    for (long j = 0; j < out_vectors.size(); ++j)
                    {
                        temp += b(j)*K_der(out_vectors(j), out_vectors(i));
                    }
                    for (long j = 0; j < dist_funct.get_basis_vectors().nr(); ++j)
                    {
                        temp -= dist_funct.get_alpha()(j)*K_der(dist_funct.get_basis_vectors()(j), out_vectors(i) );
                    }

                    // store the gradient for out_vectors(i) into result in the proper spot
                    set_subm(res,pos,0,num,1) = b(i)*temp;
                    pos += num;
                }

                res *= 2;
                return res;
            }

        private:

            mutable matrix<scalar_type, 0, 1, mem_manager_type> res;
            mutable sample_type temp;

            const distance_function<kernel_type>& dist_funct;
            matrix<scalar_type,0,1,mem_manager_type>& b;
            matrix<sample_type,0,1,mem_manager_type>& out_vectors;

        };

    // ------------------------------------------------------------------------------------

    }

    template <
        typename K,
        typename stop_strategy_type,
        typename T
        >
    distance_function<K> approximate_distance_function (
        stop_strategy_type stop_strategy,
        const distance_function<K>& target,
        const T& starting_basis
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(target.get_basis_vectors().size() > 0 &&
                    starting_basis.size() > 0,
                    "\t  distance_function approximate_distance_function()"
                    << "\n\t Invalid inputs were given to this function."
                    << "\n\t target.get_basis_vectors().size(): " << target.get_basis_vectors().size()
                    << "\n\t starting_basis.size():             " << starting_basis.size()
        );

        using namespace red_impl;
        // The next few statements just find the best weights with which to approximate
        // the target object with the set of basis vectors in starting_basis.  This
        // is really just a simple application of some linear algebra.  For the details
        // see page 554 of Learning with kernels by Scholkopf and Smola where they talk
        // about "Optimal Expansion Coefficients."

        const K kern(target.get_kernel());
        typedef typename K::scalar_type scalar_type;
        typedef typename K::sample_type sample_type;
        typedef typename K::mem_manager_type mem_manager_type;

        matrix<scalar_type,0,1,mem_manager_type> beta;

        // Now we compute the fist approximate distance function.
        beta = pinv(kernel_matrix(kern,starting_basis)) *
            (kernel_matrix(kern,starting_basis,target.get_basis_vectors())*target.get_alpha());
        matrix<sample_type,0,1,mem_manager_type> out_vectors(mat(starting_basis));

        // Now setup to do a global optimization of all the parameters in the approximate
        // distance function.
        const objective<K> obj(target, beta, out_vectors);
        const objective_derivative<K> obj_der(target, beta, out_vectors);
        matrix<scalar_type,0,1,mem_manager_type> opt_starting_point(obj.state_to_vector());

        // perform a full optimization of all the parameters (i.e. both beta and the basis vectors together)
        find_min(lbfgs_search_strategy(20),
                 stop_strategy,
                 obj, obj_der, opt_starting_point, 0);

        // now make sure that the final optimized value is loaded into the beta and
        // out_vectors matrices
        obj.vector_to_state(opt_starting_point);

        // Do a final reoptimization of beta just to make sure it is optimal given the new
        // set of basis vectors.
        beta = pinv(kernel_matrix(kern,out_vectors))*(kernel_matrix(kern,out_vectors,target.get_basis_vectors())*target.get_alpha());

        // It is possible that some of the beta weights will be very close to zero.  Lets remove
        // the basis vectors with these essentially zero weights.
        const scalar_type eps = max(abs(beta))*std::numeric_limits<scalar_type>::epsilon();
        for (long i = 0; i < beta.size(); ++i)
        {
            // if beta(i) is zero (but leave at least one beta no matter what)
            if (std::abs(beta(i)) < eps && beta.size() > 1)
            {
                beta = remove_row(beta, i);
                out_vectors = remove_row(out_vectors, i);
                --i;
            }
        }

        return distance_function<K>(beta, kern, out_vectors);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type
        >
    class reduced_decision_function_trainer2
    {
    public:
        typedef typename trainer_type::kernel_type kernel_type;
        typedef typename trainer_type::scalar_type scalar_type;
        typedef typename trainer_type::sample_type sample_type;
        typedef typename trainer_type::mem_manager_type mem_manager_type;
        typedef typename trainer_type::trained_function_type trained_function_type;

        reduced_decision_function_trainer2 () : num_bv(0) {}
        reduced_decision_function_trainer2 (
            const trainer_type& trainer_,
            const long num_sb_,
            const double eps_ = 1e-3
        ) :
            trainer(trainer_),
            num_bv(num_sb_),
            eps(eps_)
        {
            COMPILE_TIME_ASSERT(is_matrix<sample_type>::value);

            // make sure requires clause is not broken
            DLIB_ASSERT(num_bv > 0 && eps > 0,
                        "\t reduced_decision_function_trainer2()"
                        << "\n\t you have given invalid arguments to this function"
                        << "\n\t num_bv: " << num_bv
                        << "\n\t eps:    " << eps
            );
        }

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(num_bv > 0,
                        "\t reduced_decision_function_trainer2::train(x,y)"
                        << "\n\t You have tried to use an uninitialized version of this object"
                        << "\n\t num_bv: " << num_bv );
            return do_train(mat(x), mat(y));
        }

    private:

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> do_train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y
        ) const
        {
            // get the decision function object we are going to try and approximate
            const decision_function<kernel_type>& dec_funct = trainer.train(x,y);
            const kernel_type kern(dec_funct.kernel_function);

            // now find a linearly independent subset of the training points of num_bv points.
            linearly_independent_subset_finder<kernel_type> lisf(kern, num_bv);
            fill_lisf(lisf,x);

            distance_function<kernel_type> approx, target;
            target = dec_funct;
            approx = approximate_distance_function(objective_delta_stop_strategy(eps), target, lisf);

            decision_function<kernel_type> new_df(approx.get_alpha(),
                                                  0,
                                                  kern,
                                                  approx.get_basis_vectors());

            // now we have to figure out what the new bias should be.  It might be a little
            // different since we just messed with all the weights and vectors.
            double bias = 0;
            for (long i = 0; i < x.nr(); ++i)
            {
                bias += new_df(x(i)) - dec_funct(x(i));
            }

            new_df.b = bias/x.nr();

            return new_df;

        }

    // ------------------------------------------------------------------------------------

        trainer_type trainer;
        long num_bv;
        double eps;

    }; // end of class reduced_decision_function_trainer2

    template <typename trainer_type>
    const reduced_decision_function_trainer2<trainer_type> reduced2 (
        const trainer_type& trainer,
        const long num_bv,
        double eps = 1e-3
    )
    {
        COMPILE_TIME_ASSERT(is_matrix<typename trainer_type::sample_type>::value);

        // make sure requires clause is not broken
        DLIB_ASSERT(num_bv > 0 && eps > 0,
                    "\tconst reduced_decision_function_trainer2 reduced2()"
                    << "\n\t you have given invalid arguments to this function"
                    << "\n\t num_bv: " << num_bv
                    << "\n\t eps:    " << eps
        );

        return reduced_decision_function_trainer2<trainer_type>(trainer, num_bv, eps);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

}

#endif // DLIB_REDUCEd_TRAINERS_


dlib C++ Library - rls.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_RLs_Hh_
#define DLIB_RLs_Hh_

#include "rls_abstract.h"
#include "../matrix.h"
#include "function.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class rls
    {

    public:

        explicit rls(
            double forget_factor_,
            double C_ = 1000
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(0 < forget_factor_ && forget_factor_ <= 1 &&
                        0 < C_,
                "\t rls::rls()"
                << "\n\t invalid arguments were given to this function"
                << "\n\t forget_factor_: " << forget_factor_
                << "\n\t C_:   " << C_
                << "\n\t this: " << this
                );

            C = C_;
            forget_factor = forget_factor_;
        }

        rls(
        )
        {
            C = 1000;
            forget_factor = 1;
        }

        double get_c(
        ) const
        {
            return C;
        }

        double get_forget_factor(
        ) const
        {
            return forget_factor;
        }

        template <typename EXP>
        void train (
            const matrix_exp<EXP>& x,
            double y
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(is_col_vector(x) &&
                        (get_w().size() == 0 || get_w().size() == x.size()),
                "\t void rls::train()"
                << "\n\t invalid arguments were given to this function"
                << "\n\t is_col_vector(x): " << is_col_vector(x)
                << "\n\t x.size():         " << x.size()
                << "\n\t get_w().size():   " << get_w().size()
                << "\n\t this: " << this
                );

            if (R.size() == 0)
            {
                R = identity_matrix<double>(x.size())*C;
                w.set_size(x.size());
                w = 0;
            }

            // multiply by forget factor and incorporate x*trans(x) into R.
            const double l = 1.0/forget_factor;
            const double temp = 1 + l*trans(x)*R*x;
            matrix<double,0,1> tmp = R*x;
            R = l*R - l*l*(tmp*trans(tmp))/temp;

            // Since we multiplied by the forget factor, we need to add (1-forget_factor) of the
            // identity matrix back in to keep the regularization alive.
            add_eye_to_inv(R, (1-forget_factor)/C);

            // R should always be symmetric.  This line improves numeric stability of this algorithm.
            R = 0.5*(R + trans(R));

            w = w + R*x*(y - trans(x)*w);

        }

        const matrix<double,0,1>& get_w(
        ) const
        {
            return w;
        }

        template <typename EXP>
        double operator() (
            const matrix_exp<EXP>& x
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(is_col_vector(x) && get_w().size() == x.size(),
                "\t double rls::operator()()"
                << "\n\t invalid arguments were given to this function"
                << "\n\t is_col_vector(x): " << is_col_vector(x)
                << "\n\t x.size():         " << x.size()
                << "\n\t get_w().size():   " << get_w().size()
                << "\n\t this: " << this
                );

            return dot(x,w);
        }

        decision_function<linear_kernel<matrix<double,0,1> > > get_decision_function (
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(get_w().size() != 0,
                "\t decision_function rls::get_decision_function()"
                << "\n\t invalid arguments were given to this function"
                << "\n\t get_w().size():   " << get_w().size()
                << "\n\t this: " << this
                );

            decision_function<linear_kernel<matrix<double,0,1> > > df;
            df.alpha.set_size(1);
            df.basis_vectors.set_size(1);
            df.b = 0;
            df.alpha = 1;
            df.basis_vectors(0) = w;

            return df;
        }

        friend inline void serialize(const rls& item, std::ostream& out)
        {
            int version = 1;
            serialize(version, out);
            serialize(item.w, out);
            serialize(item.R, out);
            serialize(item.C, out);
            serialize(item.forget_factor, out);
        }

        friend inline void deserialize(rls& item, std::istream& in)
        {
            int version = 0;
            deserialize(version, in);
            if (version != 1)
                throw dlib::serialization_error("Unknown version number found while deserializing rls object.");

            deserialize(item.w, in);
            deserialize(item.R, in);
            deserialize(item.C, in);
            deserialize(item.forget_factor, in);
        }

    private:

        void add_eye_to_inv(
            matrix<double>& m,
            double C
        )
        /*!
            ensures
                - Let m == inv(M)
                - this function returns inv(M + C*identity_matrix<double>(m.nr()))
        !*/
        {
            for (long r = 0; r < m.nr(); ++r)
            {
                m = m - colm(m,r)*trans(colm(m,r))/(1/C + m(r,r));
            }
        }

        matrix<double,0,1> w;
        matrix<double> R;
        double C;
        double forget_factor;
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_RLs_Hh_


dlib C++ Library - roc_trainer.h

// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_ROC_TRAINEr_H_
#define DLIB_ROC_TRAINEr_H_

#include "roc_trainer_abstract.h"
#include "../algs.h"
#include <limits>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type
        >
    class roc_trainer_type
    {
    public:
        typedef typename trainer_type::kernel_type kernel_type;
        typedef typename trainer_type::scalar_type scalar_type;
        typedef typename trainer_type::sample_type sample_type;
        typedef typename trainer_type::mem_manager_type mem_manager_type;
        typedef typename trainer_type::trained_function_type trained_function_type;

        roc_trainer_type (
        ) : desired_accuracy(0), class_selection(0){}

        roc_trainer_type (
            const trainer_type& trainer_,
            const scalar_type& desired_accuracy_,
            const scalar_type& class_selection_
        ) : trainer(trainer_), desired_accuracy(desired_accuracy_), class_selection(class_selection_)
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(0 <= desired_accuracy && desired_accuracy <= 1 &&
                         (class_selection == -1 || class_selection == +1),
                        "\t roc_trainer_type::roc_trainer_type()"
                        << "\n\t invalid inputs were given to this function"
                        << "\n\t desired_accuracy: " << desired_accuracy
                        << "\n\t class_selection:  " << class_selection
                        );
        }

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const trained_function_type train (
            const in_sample_vector_type& samples,
            const in_scalar_vector_type& labels
        ) const
        /*!
            requires
                - is_binary_classification_problem(samples, labels) == true
        !*/
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(is_binary_classification_problem(samples, labels),
                        "\t roc_trainer_type::train()"
                        << "\n\t invalid inputs were given to this function"
                        );

            return do_train(mat(samples), mat(labels));
        }

    private:

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const trained_function_type do_train (
            const in_sample_vector_type& samples,
            const in_scalar_vector_type& labels
        ) const
        {
            trained_function_type df = trainer.train(samples, labels);

            // clear out the old bias
            df.b = 0;

            // obtain all the scores from the df using all the class_selection labeled samples
            std::vector<double> scores;
            for (long i = 0; i < samples.size(); ++i)
            {
                if (labels(i) == class_selection)
                    scores.push_back(df(samples(i)));
            }

            if (class_selection == +1)
                std::sort(scores.rbegin(), scores.rend());
            else
                std::sort(scores.begin(), scores.end());

            // now pick out the index that gives us the desired accuracy with regards to selected class
            unsigned long idx = static_cast<unsigned long>(desired_accuracy*scores.size() + 0.5);
            if (idx >= scores.size())
                idx = scores.size()-1;

            df.b = scores[idx];

            // In this case add a very small extra amount to the bias so that all the samples
            // with the class_selection label are classified correctly.
            if (desired_accuracy == 1)
            {
                if (class_selection == +1)
                    df.b -= std::numeric_limits<scalar_type>::epsilon()*df.b;
                else
                    df.b += std::numeric_limits<scalar_type>::epsilon()*df.b;
            }

            return df;
        }

        trainer_type trainer;
        scalar_type desired_accuracy;
        scalar_type class_selection;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type
        >
    const roc_trainer_type<trainer_type> roc_c1_trainer (
        const trainer_type& trainer,
        const typename trainer_type::scalar_type& desired_accuracy
    ) { return roc_trainer_type<trainer_type>(trainer, desired_accuracy, +1); }

// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type
        >
    const roc_trainer_type<trainer_type> roc_c2_trainer (
        const trainer_type& trainer,
        const typename trainer_type::scalar_type& desired_accuracy
    ) { return roc_trainer_type<trainer_type>(trainer, desired_accuracy, -1); }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_ROC_TRAINEr_H_


dlib C++ Library - rr_trainer.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_RR_TRAInER_Hh_
#define DLIB_RR_TRAInER_Hh_

#include "../algs.h"
#include "function.h"
#include "kernel.h"
#include "empirical_kernel_map.h"
#include "linearly_independent_subset_finder.h"
#include "../statistics.h"
#include "rr_trainer_abstract.h"
#include <vector>
#include <iostream>

namespace dlib
{
    template <
        typename K
        >
    class rr_trainer
    {

    public:
        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 decision_function<kernel_type> trained_function_type;

        // You are getting a compiler error on this line because you supplied a non-linear or
        // sparse kernel to the rr_trainer object.  You have to use dlib::linear_kernel with this trainer.
        COMPILE_TIME_ASSERT((is_same_type<K, linear_kernel<sample_type> >::value));

        rr_trainer (
        ) :
            verbose(false),
            use_regression_loss(true),
            lambda(0)
        {
            // default lambda search list
            lams = matrix_cast<scalar_type>(logspace(-9, 2, 50));
        }

        void be_verbose (
        )
        {
            verbose = true;
        }

        void be_quiet (
        )
        {
            verbose = false;
        }

        void use_regression_loss_for_loo_cv (
        )
        {
            use_regression_loss = true;
        }

        void use_classification_loss_for_loo_cv (
        )
        {
            use_regression_loss = false;
        }

        bool will_use_regression_loss_for_loo_cv (
        ) const
        {
            return use_regression_loss;
        }

        const kernel_type get_kernel (
        ) const
        {
            return kernel_type();
        }

        void set_lambda (
            scalar_type lambda_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(lambda_ >= 0,
                "\t void rr_trainer::set_lambda()"
                << "\n\t lambda must be greater than or equal to 0"
                << "\n\t lambda: " << lambda
                << "\n\t this:   " << this
                );

            lambda = lambda_;
        }

        const scalar_type get_lambda (
        ) const
        {
            return lambda;
        }

        template <typename EXP>
        void set_search_lambdas (
            const matrix_exp<EXP>& lambdas
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(is_vector(lambdas) && lambdas.size() > 0 && min(lambdas) > 0,
                "\t void rr_trainer::set_search_lambdas()"
                << "\n\t lambdas must be a non-empty vector of values"
                << "\n\t is_vector(lambdas): " << is_vector(lambdas)
                << "\n\t lambdas.size():     " << lambdas.size()
                << "\n\t min(lambdas):       " << min(lambdas)
                << "\n\t this:   " << this
                );

            lams = matrix_cast<scalar_type>(lambdas);
        }

        const matrix<scalar_type,0,0,mem_manager_type>& get_search_lambdas (
        ) const
        {
            return lams;
        }

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y
        ) const
        {
            std::vector<scalar_type> temp;
            scalar_type temp2;
            return do_train(mat(x), mat(y), false, temp, temp2);
        }

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y,
            std::vector<scalar_type>& loo_values
        ) const
        {
            scalar_type temp;
            return do_train(mat(x), mat(y), true, loo_values, temp);
        }

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y,
            std::vector<scalar_type>& loo_values,
            scalar_type& lambda_used
        ) const
        {
            return do_train(mat(x), mat(y), true, loo_values, lambda_used);
        }

    private:

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> do_train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y,
            const bool output_loo_values,
            std::vector<scalar_type>& loo_values,
            scalar_type& the_lambda
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(is_learning_problem(x,y),
                "\t decision_function rr_trainer::train(x,y)"
                << "\n\t invalid inputs were given to this function"
                << "\n\t is_vector(x): " << is_vector(x)
                << "\n\t is_vector(y): " << is_vector(y)
                << "\n\t x.size():     " << x.size()
                << "\n\t y.size():     " << y.size()
                );

#ifdef ENABLE_ASSERTS
            if (get_lambda() == 0 && will_use_regression_loss_for_loo_cv() == false)
            {
                // make sure requires clause is not broken
                DLIB_ASSERT(is_binary_classification_problem(x,y),
                    "\t decision_function rr_trainer::train(x,y)"
                    << "\n\t invalid inputs were given to this function"
                    );
            }
#endif

            typedef matrix<scalar_type,0,1,mem_manager_type> column_matrix_type;
            typedef matrix<scalar_type,0,0,mem_manager_type> general_matrix_type;

            const long dims = x(0).size();

            /*
                Notes on the solution of ridge regression

                Let A = an x.size() by dims matrix which contains all the data samples.

                Let I = an identity matrix

                Let C = trans(A)*A
                Let L = trans(A)*y

                Then the optimal w is given by:
                    w = inv(C + lambda*I) * L

                There is a trick to compute leave one out cross validation results for many different
                lambda values quickly.  The following paper has a detailed discussion of various
                approaches:

                    Notes on Regularized Least Squares by Ryan M. Rifkin and Ross A. Lippert.

                    In the implementation of the rr_trainer I'm only using two simple equations
                    from the above paper.

                    First note that inv(C + lambda*I) can be computed for many different lambda
                    values in an efficient way by using an eigen decomposition of C.  So we use
                    the fact that:
                        inv(C + lambda*I) == V*inv(D + lambda*I)*trans(V)
                        where V*D*trans(V) == C

                    Also, via some simple linear algebra the above paper works out that the leave one out
                    value for a sample x(i) is equal to the following:
                        Let G = inv(C + lambda*I)
                        let val = trans(x(i))*G*x(i);

                        leave one out value for sample x(i):
                        LOOV = (trans(w)*x(i) - y(i)*val) / (1 - val)

                        leave one out error for sample x(i):
                        LOOE = loss(y(i), LOOV)

                Finally, note that we will pretend there was a 1 appended to the end of each
                vector in x.  We won't actually do that though because we don't want to
                have to make a copy of all the samples.  So throughout the following code
                I have explicitly dealt with this.
            */

            general_matrix_type C, tempm, G;
            column_matrix_type  L, tempv, w;

            // compute C and L
            for (long i = 0; i < x.size(); ++i)
            {
                C += x(i)*trans(x(i));
                L += y(i)*x(i);
                tempv += x(i);
            }

            // Account for the extra 1 that we pretend is appended to x
            // Make C = [C      tempv
            //           tempv' x.size()]
            C = join_cols(join_rows(C, tempv),
                          join_rows(trans(tempv), uniform_matrix<scalar_type>(1,1, x.size())));
            L = join_cols(L, uniform_matrix<scalar_type>(1,1, sum(y)));

            eigenvalue_decomposition<general_matrix_type> eig(make_symmetric(C));
            const general_matrix_type V = eig.get_pseudo_v();
            const column_matrix_type  D = eig.get_real_eigenvalues();

            // We can save some work by pre-multiplying the x vectors by trans(V)
            // and saving the result so we don't have to recompute it over and over later.
            matrix<column_matrix_type,0,1,mem_manager_type > Vx;
            if (lambda == 0 || output_loo_values)
            {
                // Save the transpose of V into a temporary because the subsequent matrix
                // vector multiplies will be faster (because of better cache locality).
                const general_matrix_type transV( colm(trans(V),range(0,dims-1))  );
                // Remember the pretend 1 at the end of x(*).  We want to multiply trans(V)*x(*)
                // so to do this we pull the last column off trans(V) and store it separately.
                const column_matrix_type lastV = colm(trans(V), dims);
                Vx.set_size(x.size());
                for (long i = 0; i < x.size(); ++i)
                {
                    Vx(i) = transV*x(i);
                    Vx(i) = squared(Vx(i) + lastV);
                }
            }

            the_lambda = lambda;

            // If we need to automatically select a lambda then do so using the LOOE trick described
            // above.
            bool did_loov = false;
            scalar_type best_looe = std::numeric_limits<scalar_type>::max();
            if (lambda == 0)
            {
                did_loov = true;

                // Compute leave one out errors for a bunch of different lambdas and pick the best one.
                for (long idx = 0; idx < lams.size(); ++idx)
                {
                    // first compute G
                    tempv = 1.0/(D + lams(idx));
                    tempm = scale_columns(V,tempv);
                    G = tempm*trans(V);

                    // compute the solution w for the current lambda
                    w = G*L;

                    // make w have the same length as the x vectors.
                    const scalar_type b = w(dims);
                    w = colm(w,0,dims);

                    scalar_type looe = 0;
                    for (long i = 0; i < x.size(); ++i)
                    {
                        // perform equivalent of: val = trans(x(i))*G*x(i);
                        const scalar_type val = dot(tempv, Vx(i));
                        const scalar_type temp = (1 - val);
                        scalar_type loov;
                        if (temp != 0)
                            loov = (trans(w)*x(i) + b - y(i)*val) / temp;
                        else
                            loov = 0;

                        looe += loss(loov, y(i));
                    }

                    // Keep track of the lambda which gave the lowest looe.  If two lambdas
                    // have the same looe then pick the biggest lambda.
                    if (looe < best_looe || (looe == best_looe && lams(idx) > the_lambda))
                    {
                        best_looe = looe;
                        the_lambda = lams(idx);
                    }
                }

                best_looe /= x.size();
            }

            // Now perform the main training.  That is, find w.
            // first, compute G = inv(C + the_lambda*I)
            tempv = 1.0/(D + the_lambda);
            tempm = scale_columns(V,tempv);
            G = tempm*trans(V);
            w = G*L;

            // make w have the same length as the x vectors.
            const scalar_type b = w(dims);
            w = colm(w,0,dims);

            // If we haven't done this already and we are supposed to then compute the LOO error rate for
            // the current lambda and store the result in best_looe.
            if (output_loo_values)
            {
                loo_values.resize(x.size());
                did_loov = true;
                best_looe = 0;
                for (long i = 0; i < x.size(); ++i)
                {
                    // perform equivalent of: val = trans(x(i))*G*x(i);
                    const scalar_type val = dot(tempv, Vx(i));
                    const scalar_type temp = (1 - val);
                    scalar_type loov;
                    if (temp != 0)
                        loov = (trans(w)*x(i) + b - y(i)*val) / temp;
                    else
                        loov = 0;

                    best_looe += loss(loov, y(i));
                    loo_values[i] = loov;
                }

                best_looe /= x.size();

            }
            else
            {
                loo_values.clear();
            }

            if (verbose && did_loov)
            {
                using namespace std;
                cout << "Using lambda:             " << the_lambda << endl;
                if (use_regression_loss)
                    cout << "LOO Mean Squared Error:   " << best_looe << endl;
                else
                    cout << "LOO Classification Error: " << best_looe << endl;
            }

            // convert w into a proper decision function
            decision_function<kernel_type> df;
            df.alpha.set_size(1);
            df.alpha = 1;
            df.basis_vectors.set_size(1);
            df.basis_vectors(0) = w;
            df.b = -b; // don't forget about the bias we stuck onto all the vectors

            return df;
        }

        inline scalar_type loss (
            const scalar_type& a,
            const scalar_type& b
        ) const
        {
            if (use_regression_loss)
            {
                return (a-b)*(a-b);
            }
            else
            {
                // if a and b have the same sign then no loss
                if (a*b >= 0)
                    return 0;
                else
                    return 1;
            }
        }

        /*!
            CONVENTION
                - get_lambda() == lambda
                - get_kernel() == kernel_type()
                - will_use_regression_loss_for_loo_cv() == use_regression_loss
                - get_search_lambdas() == lams
        !*/

        bool verbose;
        bool use_regression_loss;

        scalar_type lambda;

        matrix<scalar_type,0,0,mem_manager_type> lams;
    };

}

#endif // DLIB_RR_TRAInER_Hh_


dlib C++ Library - rvm.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_RVm_
#define DLIB_RVm_

#include "rvm_abstract.h"
#include <cmath>
#include <limits>
#include "../matrix.h"
#include "../algs.h"
#include "function.h"
#include "kernel.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    namespace rvm_helpers
    {

    // ------------------------------------------------------------------------------------

        template <typename scalar_vector_type, typename mem_manager_type>
        long find_next_best_alpha_to_update (
            const scalar_vector_type& S,
            const scalar_vector_type& Q,
            const scalar_vector_type& alpha,
            const matrix<long,0,1,mem_manager_type>& active_bases,
            const bool search_all_alphas,
            typename scalar_vector_type::type eps
        )
        /*!
            ensures
                - if (we can find another alpha to update) then
                    - returns the index of said alpha
                - else
                    - returns -1
        !*/
        {
            typedef typename scalar_vector_type::type scalar_type;
            // now use S and Q to find next alpha to update.  What
            // we want to do here is select the alpha to update that gives us
            // the greatest improvement in marginal likelihood.
            long selected_idx = -1;
            scalar_type greatest_improvement = -1;
            for (long i = 0; i < S.nr(); ++i)
            {
                scalar_type value = -1;

                // if i is currently in the active set
                if (active_bases(i) >= 0)
                {
                    const long idx = active_bases(i);
                    const scalar_type s = alpha(idx)*S(i)/(alpha(idx) - S(i));
                    const scalar_type q = alpha(idx)*Q(i)/(alpha(idx) - S(i));

                    if (q*q-s > 0)
                    {
                        // only update an existing alpha if this is a narrow search
                        if (search_all_alphas == false)
                        {
                            // choosing this sample would mean doing an update of an
                            // existing alpha value.
                            scalar_type new_alpha = s*s/(q*q-s);
                            scalar_type cur_alpha = alpha(idx);
                            new_alpha = 1/new_alpha;
                            cur_alpha = 1/cur_alpha;

                            // from equation 32 in the Tipping paper
                            value = Q(i)*Q(i)/(S(i) +  1/(new_alpha - cur_alpha) ) -
                                std::log(1 + S(i)*(new_alpha - cur_alpha));
                        }

                    }
                    // we only pick an alpha to remove if this is a wide search and it wasn't one of the recently added ones
                    else if (search_all_alphas && idx+2 < alpha.size() )
                    {
                        // choosing this sample would mean the alpha value is infinite
                        // so we would remove the selected sample from our model.

                        // from equation 37 in the Tipping paper
                        value = Q(i)*Q(i)/(S(i) - alpha(idx)) -
                            std::log(1-S(i)/alpha(idx));

                    }
                }
                else if (search_all_alphas)
                {
                    const scalar_type s = S(i);
                    const scalar_type q = Q(i);

                    if (q*q-s > 0)
                    {
                        // choosing this sample would mean we would add the selected
                        // sample to our model.

                        // from equation 27 in the Tipping paper
                        value = (Q(i)*Q(i)-S(i))/S(i) + std::log(S(i)/(Q(i)*Q(i)));
                    }
                }

                if (value > greatest_improvement)
                {
                    greatest_improvement = value;
                    selected_idx = i;
                }
            }

            // If the greatest_improvement in marginal likelihood we would get is less
            // than our epsilon then report that there isn't anything else to do.  But
            // if it is big enough then return the selected_idx.
            if (greatest_improvement > eps)
                return selected_idx;
            else
                return -1;
        }

    } // end namespace rvm_helpers

    // ------------------------------------------------------------------------------------

    template <
        typename kern_type
        >
    class rvm_trainer
    {
        /*!
            This is an implementation of the binary classifier version of the
            relevance vector machine algorithm described in the paper:
                Tipping, M. E. and A. C. Faul (2003). Fast marginal likelihood maximisation
                for sparse Bayesian models. In C. M. Bishop and B. J. Frey (Eds.), Proceedings
                of the Ninth International Workshop on Artificial Intelligence and Statistics,
                Key West, FL, Jan 3-6.

            This code mostly does what is described in the above paper with the exception
            that here we use a different stopping condition as well as a modified alpha
            selection rule.  See the code for the exact details.
        !*/

    public:
        typedef kern_type 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 decision_function<kernel_type> trained_function_type;

        rvm_trainer (
        ) : eps(0.001), max_iterations(2000)
        {
        }

        void set_max_iterations (
            unsigned long max_iterations_
        )
        {
            max_iterations = max_iterations_;
        }

        unsigned long get_max_iterations (
        ) const
        {
            return max_iterations;
        }

        void set_epsilon (
            scalar_type eps_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(eps_ > 0,
                "\tvoid rvm_trainer::set_epsilon(eps_)"
                << "\n\t invalid inputs were given to this function"
                << "\n\t eps: " << eps_
                );
            eps = eps_;
        }

        const scalar_type get_epsilon (
        ) const
        {
            return eps;
        }

        void set_kernel (
            const kernel_type& k
        )
        {
            kernel = k;
        }

        const kernel_type& get_kernel (
        ) const
        {
            return kernel;
        }

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y
        ) const
        {
            return do_train(mat(x), mat(y));
        }

        void swap (
            rvm_trainer& item
        )
        {
            exchange(kernel, item.kernel);
            exchange(eps, item.eps);
        }

    private:

    // ------------------------------------------------------------------------------------

        typedef matrix<scalar_type,0,1,mem_manager_type> scalar_vector_type;
        typedef matrix<scalar_type,0,0,mem_manager_type> scalar_matrix_type;

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> do_train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y
        ) const
        {

            // make sure requires clause is not broken
            DLIB_ASSERT(is_binary_classification_problem(x,y) == true,
                "\tdecision_function rvm_trainer::train(x,y)"
                << "\n\t invalid inputs were given to this function"
                << "\n\t x.nr(): " << x.nr()
                << "\n\t y.nr(): " << y.nr()
                << "\n\t x.nc(): " << x.nc()
                << "\n\t y.nc(): " << y.nc()
                << "\n\t is_binary_classification_problem(x,y): " << ((is_binary_classification_problem(x,y))? "true":"false")
                );

            // make a target vector where +1 examples have value 1 and -1 examples
            // have a value of 0.
            scalar_vector_type t(y.size());
            for (long i = 0; i < y.size(); ++i)
            {
                if (y(i) == 1)
                    t(i) = 1;
                else
                    t(i) = 0;
            }

            /*! This is the convention for the active_bases variable in the function:
                - if (active_bases(i) >= 0) then
                    - alpha(active_bases(i)) == the alpha value associated with sample x(i)
                    - weights(active_bases(i)) == the weight value associated with sample x(i)
                    - colm(phi, active_bases(i)) == the column of phi associated with sample x(i)
                    - colm(phi, active_bases(i)) == kernel column i (from get_kernel_colum())
                - else
                    - the i'th sample isn't in the model and notionally has an alpha of infinity and
                      a weight of 0.
            !*/
            matrix<long,0,1,mem_manager_type> active_bases(x.nr());
            scalar_matrix_type phi(x.nr(),1);
            scalar_vector_type alpha(1), prev_alpha;
            scalar_vector_type weights(1), prev_weights;

            scalar_vector_type tempv, K_col;

            // set the initial values of these guys
            set_all_elements(active_bases, -1);
            long first_basis = pick_initial_vector(x,t);
            get_kernel_colum(first_basis, x, K_col);
            active_bases(first_basis) = 0;
            set_colm(phi,0) = K_col;
            alpha(0) = compute_initial_alpha(phi, t);
            weights(0) = 1;

            // now declare a bunch of other variables we will be using below
            scalar_vector_type mu, t_hat, Q, S;
            scalar_matrix_type sigma;

            matrix<scalar_type,1,0,mem_manager_type> tempv2, tempv3;
            scalar_matrix_type tempm;

            scalar_vector_type t_estimate;
            scalar_vector_type beta;

            Q.set_size(x.nr());
            S.set_size(x.nr());

            bool recompute_beta = true;

            bool search_all_alphas = false;
            unsigned long ticker = 0;
            const unsigned long rounds_of_narrow_search = 100;
            unsigned long iterations = 0;

            while (iterations != max_iterations)
            {
                iterations++;
                if (recompute_beta)
                {
                    // calculate the current t_estimate. (this is the predicted t value for each sample according to the
                    // current state of the classifier)
                    t_estimate = phi*weights;

                    // calculate the current beta
                    beta = sigmoid(t_estimate);
                    beta = pointwise_multiply(beta,(uniform_matrix<scalar_type>(beta.nr(),beta.nc(),1)-beta));
                    recompute_beta = false;
                }

                // Compute optimal weights and sigma for current alpha using IRLS.  This is the same
                // technique documented in the paper by equations 12-14.
                scalar_type weight_delta = std::numeric_limits<scalar_type>::max();
                int count = 0;
                while (weight_delta > 0.0001)
                {
                    // This is a sanity check to make sure we never get stuck in this
                    // loop to do some degenerate numerical condition
                    ++count;
                    if (count > 100)
                    {
                        // jump us to where search_all_alphas will be set to true
                        ticker = rounds_of_narrow_search;
                        break;
                    }

                    // compute the updated sigma matrix
                    sigma = scale_columns(trans(phi),beta)*phi;
                    for (long r = 0; r < alpha.nr(); ++r)
                        sigma(r,r) += alpha(r);
                    sigma = inv(sigma);

                    // compute the updated weights vector (t_hat = phi*mu_mp + inv(B)*(t-y))
                    t_hat = t_estimate + trans(scale_columns(trans(t-sigmoid(t_estimate)),reciprocal(beta)));

                    // mu = sigma*trans(phi)*b*t_hat
                    mu = sigma*tmp(trans(phi)* trans(scale_columns(trans(t_hat), beta)));

                    // now compute how much the weights vector changed during this iteration
                    // through this loop.
                    weight_delta = max(abs(mu-weights));

                    // put mu into the weights vector
                    mu.swap(weights);

                    // calculate the current t_estimate
                    t_estimate = phi*weights;

                    // calculate the current beta
                    beta = sigmoid(t_estimate);
                    beta = pointwise_multiply(beta, uniform_matrix<scalar_type>(beta.nr(),beta.nc(),1)-beta);

                }

                // check if we should do a full search for the best alpha to optimize
                if (ticker >= rounds_of_narrow_search)
                {
                    // if the current alpha and weights are equal to what they were
                    // at the last time we were about to start a wide search then
                    // we are done.
                    if (equal(prev_alpha, alpha, eps) && equal(prev_weights, weights, eps))
                        break;

                    prev_alpha = alpha;
                    prev_weights = weights;
                    search_all_alphas = true;
                    ticker = 0;
                }
                else
                {
                    search_all_alphas = false;
                }
                ++ticker;

                // compute S and Q using equations 24 and 25 (tempv = phi*sigma*trans(phi)*B*t_hat)
                tempv = phi*tmp(sigma*tmp(trans(phi)*trans(scale_columns(trans(t_hat),beta))));
                for (long i = 0; i < S.size(); ++i)
                {
                    // if we are currently limiting the search for the next alpha to update
                    // to the set in the active set then skip a non-active vector.
                    if (search_all_alphas == false && active_bases(i) == -1)
                        continue;

                    // get the column for this sample out of the kernel matrix.  If it is
                    // something in the active set then just get it right out of phi, otherwise
                    // we have to calculate it.
                    if (active_bases(i) != -1)
                        K_col = colm(phi,active_bases(i));
                    else
                        get_kernel_colum(i, x, K_col);

                    // tempv2 = trans(phi_m)*B
                    tempv2 = scale_columns(trans(K_col), beta);
                    tempv3 = tempv2*phi;
                    S(i) = tempv2*K_col - tempv3*sigma*trans(tempv3);
                    Q(i) = tempv2*t_hat - tempv2*tempv;
                }

                const long selected_idx = rvm_helpers::find_next_best_alpha_to_update(S,Q,alpha,active_bases, search_all_alphas, eps);

                // if find_next_best_alpha_to_update didn't find any good alpha to update
                if (selected_idx == -1)
                {
                    if (search_all_alphas == false)
                    {
                        // jump us to where search_all_alphas will be set to true and try again
                        ticker = rounds_of_narrow_search;
                        continue;
                    }
                    else
                    {
                        // we are really done so quit the main loop
                        break;
                    }
                }

                // next we update the selected alpha.

                // if the selected alpha is in the active set
                if (active_bases(selected_idx) >= 0)
                {
                    const long idx = active_bases(selected_idx);
                    const scalar_type s = alpha(idx)*S(selected_idx)/(alpha(idx) - S(selected_idx));
                    const scalar_type q = alpha(idx)*Q(selected_idx)/(alpha(idx) - S(selected_idx));

                    if (q*q-s > 0)
                    {
                        // reestimate the value of alpha
                        alpha(idx) = s*s/(q*q-s);

                    }
                    else
                    {
                        // the new alpha value is infinite so remove the selected alpha from our model
                        active_bases(selected_idx) = -1;
                        phi = remove_col(phi, idx);
                        weights = remove_row(weights, idx);
                        alpha = remove_row(alpha, idx);

                        // fix the index values in active_bases
                        for (long i = 0; i < active_bases.size(); ++i)
                        {
                            if (active_bases(i) > idx)
                            {
                                active_bases(i) -= 1;
                            }
                        }

                        // we changed the number of weights so we need to remember to
                        // recompute the beta vector next time around the main loop.
                        recompute_beta = true;
                    }
                }
                else
                {
                    const scalar_type s = S(selected_idx);
                    const scalar_type q = Q(selected_idx);

                    if (q*q-s > 0)
                    {
                        // add the selected alpha to our model

                        active_bases(selected_idx) = phi.nc();

                        // update alpha
                        tempv.set_size(alpha.size()+1);
                        set_subm(tempv, get_rect(alpha)) = alpha;
                        tempv(phi.nc()) = s*s/(q*q-s);
                        tempv.swap(alpha);

                        // update weights
                        tempv.set_size(weights.size()+1);
                        set_subm(tempv, get_rect(weights)) = weights;
                        tempv(phi.nc()) = 0;
                        tempv.swap(weights);

                        // update phi by adding the new sample's kernel matrix column in as one of phi's columns
                        tempm.set_size(phi.nr(), phi.nc()+1);
                        set_subm(tempm, get_rect(phi)) = phi;
                        get_kernel_colum(selected_idx, x, K_col);
                        set_colm(tempm, phi.nc()) = K_col;
                        tempm.swap(phi);

                        // we changed the number of weights so we need to remember to
                        // recompute the beta vector next time around the main loop.
                        recompute_beta = true;
                    }
                }

            } // end while(true).  So we have converged on the final answer.

            // now put everything into a decision_function object and return it
            std_vector_c<sample_type> dictionary;
            std_vector_c<scalar_type> final_weights;
            for (long i = 0; i < active_bases.size(); ++i)
            {
                if (active_bases(i) >= 0)
                {
                    dictionary.push_back(x(i));
                    final_weights.push_back(weights(active_bases(i)));
                }
            }

            return decision_function<kernel_type> ( mat(final_weights),
                                                    -sum(mat(final_weights))*tau,
                                                    kernel,
                                                    mat(dictionary));

        }

    // ------------------------------------------------------------------------------------

        template <typename M1, typename M2>
        long pick_initial_vector (
            const M1& x,
            const M2& t
        ) const
        {
            scalar_vector_type K_col;
            double max_projection = -std::numeric_limits<scalar_type>::infinity();
            long max_idx = 0;
            // find the row in the kernel matrix that has the biggest normalized projection onto the t vector
            for (long r = 0; r < x.nr(); ++r)
            {
                get_kernel_colum(r,x,K_col);
                double temp = trans(K_col)*t;
                temp = temp*temp/length_squared(K_col);

                if (temp > max_projection)
                {
                    max_projection = temp;
                    max_idx = r;
                }
            }

            return max_idx;
        }

    // ------------------------------------------------------------------------------------

        template <typename T>
        void get_kernel_colum (
            long idx,
            const T& x,
            scalar_vector_type& col
        ) const
        {
            col.set_size(x.nr());
            for (long i = 0; i < col.size(); ++i)
            {
                col(i) = kernel(x(idx), x(i)) + tau;
            }
        }

    // ------------------------------------------------------------------------------------

        template <typename M1, typename M2>
        scalar_type compute_initial_alpha (
            const M1& phi,
            const M2& t
        ) const
        {
            const double temp = length_squared(phi);
            const double temp2 = trans(phi)*t;

            return temp/( temp2*temp2/temp + variance(t)*0.1);
        }

    // ------------------------------------------------------------------------------------

    // private member variables
        kernel_type kernel;
        scalar_type eps;
        unsigned long max_iterations;

        const static scalar_type tau;

    }; // end of class rvm_trainer

    template <typename kernel_type>
    const typename kernel_type::scalar_type rvm_trainer<kernel_type>::tau = static_cast<typename kernel_type::scalar_type>(0.001);

// ----------------------------------------------------------------------------------------

    template <typename K>
    void swap (
        rvm_trainer<K>& a,
        rvm_trainer<K>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename kern_type
        >
    class rvm_regression_trainer
    {
        /*!
            This is an implementation of the regression version of the
            relevance vector machine algorithm described in the paper:
                Tipping, M. E. and A. C. Faul (2003). Fast marginal likelihood maximisation
                for sparse Bayesian models. In C. M. Bishop and B. J. Frey (Eds.), Proceedings
                of the Ninth International Workshop on Artificial Intelligence and Statistics,
                Key West, FL, Jan 3-6.

            This code mostly does what is described in the above paper with the exception
            that here we use a different stopping condition as well as a modified alpha
            selection rule.  See the code for the exact details.
        !*/

    public:
        typedef kern_type 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 decision_function<kernel_type> trained_function_type;

        rvm_regression_trainer (
        ) : eps(0.001)
        {
        }

        void set_epsilon (
            scalar_type eps_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(eps_ > 0,
                "\tvoid rvm_regression_trainer::set_epsilon(eps_)"
                << "\n\t invalid inputs were given to this function"
                << "\n\t eps: " << eps_
                );
            eps = eps_;
        }

        const scalar_type get_epsilon (
        ) const
        {
            return eps;
        }

        void set_kernel (
            const kernel_type& k
        )
        {
            kernel = k;
        }

        const kernel_type& get_kernel (
        ) const
        {
            return kernel;
        }

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& t
        ) const
        {
            return do_train(mat(x), mat(t));
        }

        void swap (
            rvm_regression_trainer& item
        )
        {
            exchange(kernel, item.kernel);
            exchange(eps, item.eps);
        }

    private:

    // ------------------------------------------------------------------------------------

        typedef matrix<scalar_type,0,1,mem_manager_type> scalar_vector_type;
        typedef matrix<scalar_type,0,0,mem_manager_type> scalar_matrix_type;

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> do_train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& t
        ) const
        {

            // make sure requires clause is not broken
            DLIB_ASSERT(is_learning_problem(x,t) && x.size() > 0,
                "\tdecision_function rvm_regression_trainer::train(x,t)"
                << "\n\t invalid inputs were given to this function"
                << "\n\t x.nr(): " << x.nr()
                << "\n\t t.nr(): " << t.nr()
                << "\n\t x.nc(): " << x.nc()
                << "\n\t t.nc(): " << t.nc()
                );

            /*! This is the convention for the active_bases variable in the function:
                - if (active_bases(i) >= 0) then
                    - alpha(active_bases(i)) == the alpha value associated with sample x(i)
                    - weights(active_bases(i)) == the weight value associated with sample x(i)
                    - colm(phi, active_bases(i)) == the column of phi associated with sample x(i)
                    - colm(phi, active_bases(i)) == kernel column i (from get_kernel_colum())
                - else
                    - the i'th sample isn't in the model and notionally has an alpha of infinity and
                      a weight of 0.
            !*/
            matrix<long,0,1,mem_manager_type> active_bases(x.nr());
            scalar_matrix_type phi(x.nr(),1);
            scalar_vector_type alpha(1), prev_alpha;
            scalar_vector_type weights(1), prev_weights;

            scalar_vector_type tempv, K_col;
            scalar_type var = variance(t)*0.1;

            // set the initial values of these guys
            set_all_elements(active_bases, -1);
            long first_basis = pick_initial_vector(x,t);
            get_kernel_colum(first_basis, x, K_col);
            active_bases(first_basis) = 0;
            set_colm(phi,0) = K_col;
            alpha(0) = compute_initial_alpha(phi, t, var);
            weights(0) = 1;

            // now declare a bunch of other variables we will be using below
            scalar_vector_type Q, S;
            scalar_matrix_type sigma;

            matrix<scalar_type,1,0,mem_manager_type> tempv2, tempv3;
            scalar_matrix_type tempm;

            Q.set_size(x.nr());
            S.set_size(x.nr());

            bool search_all_alphas = false;
            unsigned long ticker = 0;
            const unsigned long rounds_of_narrow_search = 100;

            while (true)
            {
                // Compute optimal weights and sigma for current alpha using equation 6.
                sigma = trans(phi)*phi/var;
                for (long r = 0; r < alpha.nr(); ++r)
                    sigma(r,r) += alpha(r);
                sigma = inv(sigma);
                weights = sigma*trans(phi)*t/var;

                // check if we should do a full search for the best alpha to optimize
                if (ticker == rounds_of_narrow_search)
                {
                    // if the current alpha and weights are equal to what they were
                    // at the last time we were about to start a wide search then
                    // we are done.
                    if (equal(prev_alpha, alpha, eps) && equal(prev_weights, weights, eps))
                        break;

                    prev_alpha = alpha;
                    prev_weights = weights;
                    search_all_alphas = true;
                    ticker = 0;
                }
                else
                {
                    search_all_alphas = false;
                }
                ++ticker;

                // compute S and Q using equations 24 and 25 (tempv = phi*sigma*trans(phi)*B*t)
                tempv = phi*tmp(sigma*tmp(trans(phi)*t/var));
                for (long i = 0; i < S.size(); ++i)
                {
                    // if we are currently limiting the search for the next alpha to update
                    // to the set in the active set then skip a non-active vector.
                    if (search_all_alphas == false && active_bases(i) == -1)
                        continue;

                    // get the column for this sample out of the kernel matrix.  If it is
                    // something in the active set then just get it right out of phi, otherwise
                    // we have to calculate it.
                    if (active_bases(i) != -1)
                        K_col = colm(phi,active_bases(i));
                    else
                        get_kernel_colum(i, x, K_col);

                    // tempv2 = trans(phi_m)*B
                    tempv2 = trans(K_col)/var;
                    tempv3 = tempv2*phi;
                    S(i) = tempv2*K_col - tempv3*sigma*trans(tempv3);
                    Q(i) = tempv2*t - tempv2*tempv;
                }

                const long selected_idx = rvm_helpers::find_next_best_alpha_to_update(S,Q,alpha,active_bases, search_all_alphas, eps);

                // if find_next_best_alpha_to_update didn't find any good alpha to update
                if (selected_idx == -1)
                {
                    if (search_all_alphas == false)
                    {
                        // jump us to where search_all_alphas will be set to true and try again
                        ticker = rounds_of_narrow_search;
                        continue;
                    }
                    else
                    {
                        // we are really done so quit the main loop
                        break;
                    }
                }

                // recompute the variance
                var = length_squared(t - phi*weights)/(x.nr() - weights.size() + trans(alpha)*diag(sigma));

                // next we update the selected alpha.

                // if the selected alpha is in the active set
                if (active_bases(selected_idx) >= 0)
                {
                    const long idx = active_bases(selected_idx);
                    const scalar_type s = alpha(idx)*S(selected_idx)/(alpha(idx) - S(selected_idx));
                    const scalar_type q = alpha(idx)*Q(selected_idx)/(alpha(idx) - S(selected_idx));

                    if (q*q-s > 0)
                    {
                        // reestimate the value of alpha
                        alpha(idx) = s*s/(q*q-s);

                    }
                    else
                    {
                        // the new alpha value is infinite so remove the selected alpha from our model
                        active_bases(selected_idx) = -1;
                        phi = remove_col(phi, idx);
                        weights = remove_row(weights, idx);
                        alpha = remove_row(alpha, idx);

                        // fix the index values in active_bases
                        for (long i = 0; i < active_bases.size(); ++i)
                        {
                            if (active_bases(i) > idx)
                            {
                                active_bases(i) -= 1;
                            }
                        }
                    }
                }
                else
                {
                    const scalar_type s = S(selected_idx);
                    const scalar_type q = Q(selected_idx);

                    if (q*q-s > 0)
                    {
                        // add the selected alpha to our model

                        active_bases(selected_idx) = phi.nc();

                        // update alpha
                        tempv.set_size(alpha.size()+1);
                        set_subm(tempv, get_rect(alpha)) = alpha;
                        tempv(phi.nc()) = s*s/(q*q-s);
                        tempv.swap(alpha);

                        // update weights
                        tempv.set_size(weights.size()+1);
                        set_subm(tempv, get_rect(weights)) = weights;
                        tempv(phi.nc()) = 0;
                        tempv.swap(weights);

                        // update phi by adding the new sample's kernel matrix column in as one of phi's columns
                        tempm.set_size(phi.nr(), phi.nc()+1);
                        set_subm(tempm, get_rect(phi)) = phi;
                        get_kernel_colum(selected_idx, x, K_col);
                        set_colm(tempm, phi.nc()) = K_col;
                        tempm.swap(phi);

                    }
                }

            } // end while(true).  So we have converged on the final answer.

            // now put everything into a decision_function object and return it
            std_vector_c<sample_type> dictionary;
            std_vector_c<scalar_type> final_weights;
            for (long i = 0; i < active_bases.size(); ++i)
            {
                if (active_bases(i) >= 0)
                {
                    dictionary.push_back(x(i));
                    final_weights.push_back(weights(active_bases(i)));
                }
            }

            return decision_function<kernel_type> ( mat(final_weights),
                                                    -sum(mat(final_weights))*tau,
                                                    kernel,
                                                    mat(dictionary));

        }

    // ------------------------------------------------------------------------------------

        template <typename T>
        void get_kernel_colum (
            long idx,
            const T& x,
            scalar_vector_type& col
        ) const
        {
            col.set_size(x.nr());
            for (long i = 0; i < col.size(); ++i)
            {
                col(i) = kernel(x(idx), x(i)) + tau;
            }
        }

    // ------------------------------------------------------------------------------------

        template <typename M1, typename M2>
        scalar_type compute_initial_alpha (
            const M1& phi,
            const M2& t,
            const scalar_type& var
        ) const
        {
            const double temp = length_squared(phi);
            const double temp2 = trans(phi)*t;

            return temp/( temp2*temp2/temp + var);
        }

    // ------------------------------------------------------------------------------------

        template <typename M1, typename M2>
        long pick_initial_vector (
            const M1& x,
            const M2& t
        ) const
        {
            scalar_vector_type K_col;
            double max_projection = -std::numeric_limits<scalar_type>::infinity();
            long max_idx = 0;
            // find the row in the kernel matrix that has the biggest normalized projection onto the t vector
            for (long r = 0; r < x.nr(); ++r)
            {
                get_kernel_colum(r,x,K_col);
                double temp = trans(K_col)*t;
                temp = temp*temp/length_squared(K_col);

                if (temp > max_projection)
                {
                    max_projection = temp;
                    max_idx = r;
                }
            }

            return max_idx;
        }

    // ------------------------------------------------------------------------------------

    // private member variables
        kernel_type kernel;
        scalar_type eps;

        const static scalar_type tau;

    }; // end of class rvm_regression_trainer

    template <typename kernel_type>
    const typename kernel_type::scalar_type rvm_regression_trainer<kernel_type>::tau = static_cast<typename kernel_type::scalar_type>(0.001);

// ----------------------------------------------------------------------------------------

    template <typename K>
    void swap (
        rvm_regression_trainer<K>& a,
        rvm_regression_trainer<K>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_RVm_


dlib C++ Library - sequence_labeler.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SEQUENCE_LAbELER_H_h_
#define DLIB_SEQUENCE_LAbELER_H_h_

#include "sequence_labeler_abstract.h"
#include "../matrix.h"
#include <vector>
#include "../optimization/find_max_factor_graph_viterbi.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    namespace fe_helpers
    {
        template <typename EXP>
        struct dot_functor
        {
            dot_functor(const matrix_exp<EXP>& lambda_) : lambda(lambda_), value(0) {}

            inline void operator() (
                unsigned long feat_index
            )
            {
                value += lambda(feat_index);
            }

            inline void operator() (
                unsigned long feat_index,
                double feat_value
            )
            {
                value += feat_value*lambda(feat_index);
            }

            const matrix_exp<EXP>& lambda;
            double value;
        };

        template <typename feature_extractor, typename EXP, typename sequence_type, typename EXP2>
        double dot(
            const matrix_exp<EXP>& lambda,
            const feature_extractor& fe,
            const sequence_type& sequence,
            const matrix_exp<EXP2>& candidate_labeling,
            unsigned long position
        )
        {
            dot_functor<EXP> dot(lambda);
            fe.get_features(dot, sequence, candidate_labeling, position);
            return dot.value;
        }

    }

// ----------------------------------------------------------------------------------------

    namespace impl
    {
        DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST(
            has_reject_labeling,
            bool,
            template reject_labeling<matrix<unsigned long> >,
            (const typename T::sequence_type&, const matrix_exp<matrix<unsigned long> >&, unsigned long)const
        );

        template <typename feature_extractor, typename EXP, typename sequence_type>
        typename enable_if<has_reject_labeling<feature_extractor>,bool>::type call_reject_labeling_if_exists (
            const feature_extractor& fe,
            const sequence_type& x,
            const matrix_exp<EXP>& y,
            unsigned long position
        )
        {
            return fe.reject_labeling(x, y, position);
        }

        template <typename feature_extractor, typename EXP, typename sequence_type>
        typename disable_if<has_reject_labeling<feature_extractor>,bool>::type call_reject_labeling_if_exists (
            const feature_extractor& ,
            const sequence_type& ,
            const matrix_exp<EXP>& ,
            unsigned long
        )
        {
            return false;
        }
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    typename enable_if<dlib::impl::has_reject_labeling<feature_extractor>,bool>::type contains_invalid_labeling (
        const feature_extractor& fe,
        const typename feature_extractor::sequence_type& x,
        const std::vector<unsigned long>& y
    )
    {
        if (x.size() != y.size())
            return true;

        matrix<unsigned long,0,1> node_states;

        for (unsigned long i = 0; i < x.size(); ++i)
        {
            node_states.set_size(std::min(fe.order(),i) + 1);
            for (unsigned long j = 0; j < (unsigned long)node_states.size(); ++j)
                node_states(j) = y[i-j];

            if (fe.reject_labeling(x, node_states, i))
                return true;
        }

        return false;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    typename disable_if<dlib::impl::has_reject_labeling<feature_extractor>,bool>::type contains_invalid_labeling (
        const feature_extractor& ,
        const typename feature_extractor::sequence_type& x,
        const std::vector<unsigned long>& y
    )
    {
        if (x.size() != y.size())
            return true;

        return false;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    bool contains_invalid_labeling (
        const feature_extractor& fe,
        const std::vector<typename feature_extractor::sequence_type>& x,
        const std::vector<std::vector<unsigned long> >& y
    )
    {
        if (x.size() != y.size())
            return true;

        for (unsigned long i = 0; i < x.size(); ++i)
        {
            if (contains_invalid_labeling(fe,x[i],y[i]))
                return true;
        }
        return false;
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    class sequence_labeler
    {
    public:
        typedef typename feature_extractor::sequence_type sample_sequence_type;
        typedef std::vector<unsigned long> labeled_sequence_type;

    private:
        class map_prob
        {
        public:
            unsigned long order() const { return fe.order(); }
            unsigned long num_states() const { return fe.num_labels(); }

            map_prob(
                const sample_sequence_type& x_,
                const feature_extractor& fe_,
                const matrix<double,0,1>& weights_
            ) :
                sequence(x_),
                fe(fe_),
                weights(weights_)
            {
            }

            unsigned long number_of_nodes(
            ) const
            {
                return sequence.size();
            }

            template <
                typename EXP
                >
            double factor_value (
                unsigned long node_id,
                const matrix_exp<EXP>& node_states
            ) const
            {
                if (dlib::impl::call_reject_labeling_if_exists(fe, sequence,  node_states, node_id))
                    return -std::numeric_limits<double>::infinity();

                return fe_helpers::dot(weights, fe, sequence, node_states, node_id);
            }

            const sample_sequence_type& sequence;
            const feature_extractor& fe;
            const matrix<double,0,1>& weights;
        };
    public:

        sequence_labeler()
        {
            weights.set_size(fe.num_features());
            weights = 0;
        }

        explicit sequence_labeler(
            const matrix<double,0,1>& weights_
        ) :
            weights(weights_)
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(fe.num_features() == static_cast<unsigned long>(weights_.size()),
                "\t sequence_labeler::sequence_labeler(weights_)"
                << "\n\t These sizes should match"
                << "\n\t fe.num_features(): " << fe.num_features()
                << "\n\t weights_.size():   " << weights_.size()
                << "\n\t this: " << this
                );
        }

        sequence_labeler(
            const matrix<double,0,1>& weights_,
            const feature_extractor& fe_
        ) :
            fe(fe_),
            weights(weights_)
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(fe_.num_features() == static_cast<unsigned long>(weights_.size()),
                "\t sequence_labeler::sequence_labeler(weights_,fe_)"
                << "\n\t These sizes should match"
                << "\n\t fe_.num_features(): " << fe_.num_features()
                << "\n\t weights_.size():    " << weights_.size()
                << "\n\t this: " << this
                );
        }

        const feature_extractor& get_feature_extractor (
        ) const { return fe; }

        const matrix<double,0,1>& get_weights (
        ) const { return weights; }

        unsigned long num_labels (
        ) const { return fe.num_labels(); }

        labeled_sequence_type operator() (
            const sample_sequence_type& x
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(num_labels() > 0,
                "\t labeled_sequence_type sequence_labeler::operator()(x)"
                << "\n\t You can't have no labels."
                << "\n\t this: " << this
                );

            labeled_sequence_type y;
            find_max_factor_graph_viterbi(map_prob(x,fe,weights), y);
            return y;
        }

        void label_sequence (
            const sample_sequence_type& x,
            labeled_sequence_type& y
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(num_labels() > 0,
                "\t void sequence_labeler::label_sequence(x,y)"
                << "\n\t You can't have no labels."
                << "\n\t this: " << this
                );

            find_max_factor_graph_viterbi(map_prob(x,fe,weights), y);
        }

    private:

        feature_extractor fe;
        matrix<double,0,1> weights;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    void serialize (
        const sequence_labeler<feature_extractor>& item,
        std::ostream& out
    )
    {
        serialize(item.get_feature_extractor(), out);
        serialize(item.get_weights(), out);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    void deserialize (
        sequence_labeler<feature_extractor>& item,
        std::istream& in
    )
    {
        feature_extractor fe;
        matrix<double,0,1> weights;

        deserialize(fe, in);
        deserialize(weights, in);

        item = sequence_labeler<feature_extractor>(weights, fe);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SEQUENCE_LAbELER_H_h_


dlib C++ Library - sequence_segmenter.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SEQUENCE_SeGMENTER_H_h_
#define DLIB_SEQUENCE_SeGMENTER_H_h_

#include "sequence_segmenter_abstract.h"
#include "../matrix.h"
#include "sequence_labeler.h"
#include <vector>

namespace dlib
{
    // This namespace contains implementation details for the sequence_segmenter.
    namespace impl_ss
    {

    // ------------------------------------------------------------------------------------

        // BIO/BILOU labels
        const unsigned int BEGIN   = 0;
        const unsigned int INSIDE  = 1;
        const unsigned int OUTSIDE = 2;
        const unsigned int LAST    = 3;
        const unsigned int UNIT    = 4;

    // ------------------------------------------------------------------------------------

        template <typename ss_feature_extractor>
        class feature_extractor
        {
            /*!
                WHAT THIS OBJECT REPRESENTS
                    This is a feature extractor for a sequence_labeler.  It serves to map
                    the interface defined by a sequence_labeler into the kind of interface
                    defined for a sequence_segmenter.
            !*/

        public:
            typedef typename ss_feature_extractor::sequence_type sequence_type;

            ss_feature_extractor fe;

            feature_extractor() {}
            feature_extractor(const ss_feature_extractor& ss_fe_) : fe(ss_fe_) {}

            unsigned long num_nonnegative_weights (
            ) const
            {
                const unsigned long NL = ss_feature_extractor::use_BIO_model ? 3 : 5;
                if (ss_feature_extractor::allow_negative_weights)
                {
                    return 0;
                }
                else
                {
                    // We make everything non-negative except for the label transition
                    // and bias features.
                    return num_features() - NL*NL - NL;
                }
            }

            friend void serialize(const feature_extractor& item, std::ostream& out)
            {
                serialize(item.fe, out);
            }

            friend void deserialize(feature_extractor& item, std::istream& in)
            {
                deserialize(item.fe, in);
            }

            unsigned long num_features() const
            {
                const unsigned long NL = ss_feature_extractor::use_BIO_model ? 3 : 5;
                if (ss_feature_extractor::use_high_order_features)
                    return NL + NL*NL + (NL*NL+NL)*fe.num_features()*fe.window_size();
                else
                    return NL + NL*NL + NL*fe.num_features()*fe.window_size();
            }

            unsigned long order() const
            {
                return 1;
            }

            unsigned long num_labels() const
            {
                if (ss_feature_extractor::use_BIO_model)
                    return 3;
                else
                    return 5;
            }

        private:

            template <typename feature_setter>
            struct dot_functor
            {
                /*!
                    WHAT THIS OBJECT REPRESENTS
                        This class wraps the feature_setter used by a sequence_labeler
                        and turns it into the kind needed by a sequence_segmenter.
                !*/

                dot_functor(feature_setter& set_feature_, unsigned long offset_) :
                    set_feature(set_feature_), offset(offset_) {}

                feature_setter& set_feature;
                unsigned long offset;

                inline void operator() (
                    unsigned long feat_index
                )
                {
                    set_feature(offset+feat_index);
                }

                inline void operator() (
                    unsigned long feat_index,
                    double feat_value
                )
                {
                    set_feature(offset+feat_index, feat_value);
                }
            };

        public:

            template <typename EXP>
            bool reject_labeling (
                const sequence_type& x,
                const matrix_exp<EXP>& y,
                unsigned long pos
            ) const
            {
                if (ss_feature_extractor::use_BIO_model)
                {
                    // Don't allow BIO label patterns that don't correspond to a sensical
                    // segmentation.
                    if (y.size() > 1 && y(0) == INSIDE && y(1) == OUTSIDE)
                        return true;
                    if (y.size() == 1 && y(0) == INSIDE)
                        return true;
                }
                else
                {
                    // Don't allow BILOU label patterns that don't correspond to a sensical
                    // segmentation.
                    if (y.size() > 1)
                    {
                        if (y(1) == BEGIN && y(0) == OUTSIDE)
                            return true;
                        if (y(1) == BEGIN && y(0) == UNIT)
                            return true;
                        if (y(1) == BEGIN && y(0) == BEGIN)
                            return true;

                        if (y(1) == INSIDE && y(0) == BEGIN)
                            return true;
                        if (y(1) == INSIDE && y(0) == OUTSIDE)
                            return true;
                        if (y(1) == INSIDE && y(0) == UNIT)
                            return true;

                        if (y(1) == OUTSIDE && y(0) == INSIDE)
                            return true;
                        if (y(1) == OUTSIDE && y(0) == LAST)
                            return true;

                        if (y(1) == LAST && y(0) == INSIDE)
                            return true;
                        if (y(1) == LAST && y(0) == LAST)
                            return true;

                        if (y(1) == UNIT && y(0) == INSIDE)
                            return true;
                        if (y(1) == UNIT && y(0) == LAST)
                            return true;

                        // if at the end of the sequence
                        if (pos == x.size()-1)
                        {
                            if (y(0) == BEGIN)
                                return true;
                            if (y(0) == INSIDE)
                                return true;
                        }
                    }
                    else
                    {
                        if (y(0) == INSIDE)
                            return true;
                        if (y(0) == LAST)
                            return true;

                        // if at the end of the sequence
                        if (pos == x.size()-1)
                        {
                            if (y(0) == BEGIN)
                                return 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
            {
                unsigned long offset = 0;

                const int window_size = fe.window_size();

                const int base_dims = fe.num_features();
                for (int i = 0; i < window_size; ++i)
                {
                    const long pos = i-window_size/2 + static_cast<long>(position);
                    if (0 <= pos && pos < (long)x.size())
                    {
                        const unsigned long off1 = y(0)*base_dims;
                        dot_functor<feature_setter> fs1(set_feature, offset+off1);
                        fe.get_features(fs1, x, pos);

                        if (ss_feature_extractor::use_high_order_features && y.size() > 1)
                        {
                            const unsigned long off2 = num_labels()*base_dims + (y(0)*num_labels()+y(1))*base_dims;
                            dot_functor<feature_setter> fs2(set_feature, offset+off2);
                            fe.get_features(fs2, x, pos);
                        }
                    }

                    if (ss_feature_extractor::use_high_order_features)
                        offset += num_labels()*base_dims + num_labels()*num_labels()*base_dims;
                    else
                        offset += num_labels()*base_dims;
                }

                // Pull out an indicator feature for the type of transition between the
                // previous label and the current label.
                if (y.size() > 1)
                    set_feature(offset + y(1)*num_labels() + y(0));

                offset += num_labels()*num_labels();
                // pull out an indicator feature for the current label.  This is the per
                // label bias.
                set_feature(offset + y(0));
            }
        };

    } // end namespace impl_ss

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    unsigned long total_feature_vector_size (
        const feature_extractor& fe
    )
    {
        const unsigned long NL = feature_extractor::use_BIO_model ? 3 : 5;
        if (feature_extractor::use_high_order_features)
            return NL + NL*NL + (NL*NL+NL)*fe.num_features()*fe.window_size();
        else
            return NL + NL*NL + NL*fe.num_features()*fe.window_size();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    class sequence_segmenter
    {
    public:
        typedef typename feature_extractor::sequence_type sample_sequence_type;
        typedef std::vector<std::pair<unsigned long, unsigned long> > segmented_sequence_type;

        sequence_segmenter()
        {
#ifdef ENABLE_ASSERTS
            const feature_extractor& fe = labeler.get_feature_extractor().fe;
            DLIB_ASSERT(fe.window_size() >= 1 && fe.num_features() >= 1,
                "\t sequence_segmenter::sequence_segmenter()"
                << "\n\t An invalid feature extractor was supplied."
                << "\n\t fe.window_size():  " << fe.window_size()
                << "\n\t fe.num_features(): " << fe.num_features()
                << "\n\t this: " << this
            );
#endif
        }

        explicit sequence_segmenter(
            const matrix<double,0,1>& weights
        ) :
            labeler(weights)
        {
#ifdef ENABLE_ASSERTS
            const feature_extractor& fe = labeler.get_feature_extractor().fe;
            // make sure requires clause is not broken
            DLIB_ASSERT(total_feature_vector_size(fe) == (unsigned long)weights.size(),
                "\t sequence_segmenter::sequence_segmenter(weights)"
                << "\n\t These sizes should match"
                << "\n\t total_feature_vector_size(fe):  " << total_feature_vector_size(fe)
                << "\n\t weights.size(): " << weights.size()
                << "\n\t this: " << this
                );
            DLIB_ASSERT(fe.window_size() >= 1 && fe.num_features() >= 1,
                "\t sequence_segmenter::sequence_segmenter()"
                << "\n\t An invalid feature extractor was supplied."
                << "\n\t fe.window_size():  " << fe.window_size()
                << "\n\t fe.num_features(): " << fe.num_features()
                << "\n\t this: " << this
            );
#endif
        }

        sequence_segmenter(
            const matrix<double,0,1>& weights,
            const feature_extractor& fe
        ) :
            labeler(weights, impl_ss::feature_extractor<feature_extractor>(fe))
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(total_feature_vector_size(fe) == (unsigned long)weights.size(),
                "\t sequence_segmenter::sequence_segmenter(weights,fe)"
                << "\n\t These sizes should match"
                << "\n\t total_feature_vector_size(fe):  " << total_feature_vector_size(fe)
                << "\n\t weights.size(): " << weights.size()
                << "\n\t this: " << this
                );
            DLIB_ASSERT(fe.window_size() >= 1 && fe.num_features() >= 1,
                "\t sequence_segmenter::sequence_segmenter()"
                << "\n\t An invalid feature extractor was supplied."
                << "\n\t fe.window_size():  " << fe.window_size()
                << "\n\t fe.num_features(): " << fe.num_features()
                << "\n\t this: " << this
            );
        }

        const feature_extractor& get_feature_extractor (
        ) const { return labeler.get_feature_extractor().fe; }

        const matrix<double,0,1>& get_weights (
        ) const { return labeler.get_weights(); }

        segmented_sequence_type operator() (
            const sample_sequence_type& x
        ) const
        {
            segmented_sequence_type y;
            segment_sequence(x,y);
            return y;
        }

        void segment_sequence (
            const sample_sequence_type& x,
            segmented_sequence_type& y
        ) const
        {
            y.clear();
            std::vector<unsigned long> labels;
            labeler.label_sequence(x, labels);

            if (feature_extractor::use_BIO_model)
            {
                // Convert from BIO tagging to the explicit segments representation.
                for (unsigned long i = 0; i < labels.size(); ++i)
                {
                    if (labels[i] == impl_ss::BEGIN)
                    {
                        const unsigned long begin = i;
                        ++i;
                        while (i < labels.size() && labels[i] == impl_ss::INSIDE)
                            ++i;

                        y.push_back(std::make_pair(begin, i));
                        --i;
                    }
                }
            }
            else
            {
                // Convert from BILOU tagging to the explicit segments representation.
                for (unsigned long i = 0; i < labels.size(); ++i)
                {
                    if (labels[i] == impl_ss::BEGIN)
                    {
                        const unsigned long begin = i;
                        ++i;
                        while (i < labels.size() && labels[i] == impl_ss::INSIDE)
                            ++i;

                        y.push_back(std::make_pair(begin, i+1));
                    }
                    else if (labels[i] == impl_ss::UNIT)
                    {
                        y.push_back(std::make_pair(i, i+1));
                    }
                }
            }
        }

        friend void serialize(const sequence_segmenter& item, std::ostream& out)
        {
            int version = 1;
            serialize(version, out);

            // Save these just so we can compare them when we deserialize and make
            // sure the feature_extractor being used is compatible with the model being
            // loaded.
            serialize(feature_extractor::use_BIO_model, out);
            serialize(feature_extractor::use_high_order_features, out);
            serialize(total_feature_vector_size(item.get_feature_extractor()), out);

            serialize(item.labeler, out);
        }

        friend void deserialize(sequence_segmenter& item, std::istream& in)
        {
            int version = 0;
            deserialize(version, in);
            if (version != 1)
                throw serialization_error("Unexpected version found while deserializing dlib::sequence_segmenter.");

            // Try to check if the saved model is compatible with the current feature
            // extractor.
            bool use_BIO_model, use_high_order_features;
            unsigned long dims;
            deserialize(use_BIO_model, in);
            deserialize(use_high_order_features, in);
            deserialize(dims, in);
            deserialize(item.labeler, in);
            if (use_BIO_model != feature_extractor::use_BIO_model)
            {
                throw serialization_error("Incompatible feature extractor found while deserializing "
                    "dlib::sequence_segmenter. Wrong value of use_BIO_model.");
            }
            if (use_high_order_features != feature_extractor::use_high_order_features)
            {
                throw serialization_error("Incompatible feature extractor found while deserializing "
                    "dlib::sequence_segmenter. Wrong value of use_high_order_features.");
            }
            if (dims != total_feature_vector_size(item.get_feature_extractor()))
            {
                throw serialization_error("Incompatible feature extractor found while deserializing "
                    "dlib::sequence_segmenter. Wrong value of total_feature_vector_size().");
            }
        }

    private:
        sequence_labeler<impl_ss::feature_extractor<feature_extractor> > labeler;
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SEQUENCE_SeGMENTER_H_h_


dlib C++ Library - simplify_linear_decision_function.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SIMPLIFY_LINEAR_DECiSION_FUNCTION_Hh_
#define DLIB_SIMPLIFY_LINEAR_DECiSION_FUNCTION_Hh_

#include "simplify_linear_decision_function_abstract.h"
#include "../algs.h"
#include "function.h"
#include "sparse_kernel.h"
#include "kernel.h"
#include <map>
#include <vector>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    decision_function<sparse_linear_kernel<T> > simplify_linear_decision_function (
        const decision_function<sparse_linear_kernel<T> >& df
    )
    {
        // don't do anything if we don't have to
        if (df.basis_vectors.size() <= 1)
            return df;

        decision_function<sparse_linear_kernel<T> > new_df;

        new_df.b = df.b;
        new_df.basis_vectors.set_size(1);
        new_df.alpha.set_size(1);
        new_df.alpha(0) = 1;

        // now compute the weighted sum of all the sparse basis_vectors in df
        typedef typename T::value_type pair_type;
        typedef typename pair_type::first_type key_type;
        typedef typename pair_type::second_type value_type;
        std::map<key_type, value_type> accum;
        for (long i = 0; i < df.basis_vectors.size(); ++i)
        {
            typename T::const_iterator j = df.basis_vectors(i).begin();
            const typename T::const_iterator end = df.basis_vectors(i).end();
            for (; j != end; ++j)
            {
                accum[j->first] += df.alpha(i) * (j->second);
            }
        }

        new_df.basis_vectors(0) = T(accum.begin(), accum.end());

        return new_df;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    decision_function<linear_kernel<T> > simplify_linear_decision_function (
        const decision_function<linear_kernel<T> >& df
    )
    {
        // don't do anything if we don't have to
        if (df.basis_vectors.size() <= 1)
            return df;

        decision_function<linear_kernel<T> > new_df;

        new_df.b = df.b;
        new_df.basis_vectors.set_size(1);
        new_df.alpha.set_size(1);
        new_df.alpha(0) = 1;

        // now compute the weighted sum of all the basis_vectors in df
        new_df.basis_vectors(0) = 0;
        for (long i = 0; i < df.basis_vectors.size(); ++i)
        {
            new_df.basis_vectors(0) += df.alpha(i) * df.basis_vectors(i);
        }

        return new_df;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    decision_function<linear_kernel<T> > simplify_linear_decision_function (
        const normalized_function<decision_function<linear_kernel<T> >, vector_normalizer<T> >& df
    )
    {
        decision_function<linear_kernel<T> > new_df = simplify_linear_decision_function(df.function);

        // now incorporate the normalization stuff into new_df
        new_df.basis_vectors(0) = pointwise_multiply(new_df.basis_vectors(0), df.normalizer.std_devs());
        new_df.b += dot(new_df.basis_vectors(0), df.normalizer.means());

        return new_df;
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SIMPLIFY_LINEAR_DECiSION_FUNCTION_Hh_


dlib C++ Library - sort_basis_vectors.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SORT_BASIS_VECTORs_Hh_
#define DLIB_SORT_BASIS_VECTORs_Hh_

#include <vector>

#include "sort_basis_vectors_abstract.h"
#include "../matrix.h"
#include "../statistics.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    namespace bs_impl
    {
        template <typename EXP>
        typename EXP::matrix_type invert (
            const matrix_exp<EXP>& m
        )
        {
            eigenvalue_decomposition<EXP> eig(make_symmetric(m));

            typedef typename EXP::type scalar_type;
            typedef typename EXP::mem_manager_type mm_type;

            matrix<scalar_type,0,1,mm_type> vals = eig.get_real_eigenvalues();

            const scalar_type max_eig = max(abs(vals));
            const scalar_type thresh = max_eig*std::sqrt(std::numeric_limits<scalar_type>::epsilon());

            // Since m might be singular or almost singular we need to do something about
            // any very small eigenvalues.  So here we set the smallest eigenvalues to
            // be equal to a large value to make the inversion stable.  We can't just set
            // them to zero like in a normal pseudo-inverse since we want the resulting
            // inverse matrix to be full rank.
            for (long i = 0; i < vals.size(); ++i)
            {
                if (std::abs(vals(i)) < thresh)
                    vals(i) = max_eig;
            }

            // Build the inverse matrix.  This is basically a pseudo-inverse.
            return make_symmetric(eig.get_pseudo_v()*diagm(reciprocal(vals))*trans(eig.get_pseudo_v()));
        }

// ----------------------------------------------------------------------------------------

        template <
            typename kernel_type,
            typename vect1_type,
            typename vect2_type,
            typename vect3_type
            >
        const std::vector<typename kernel_type::sample_type> sort_basis_vectors_impl (
            const kernel_type& kern,
            const vect1_type& samples,
            const vect2_type& labels,
            const vect3_type& basis,
            double eps
        )
        {
            DLIB_ASSERT(is_binary_classification_problem(samples, labels) &&
                        0 < eps && eps <= 1 &&
                        basis.size() > 0,
                        "\t void sort_basis_vectors()"
                        << "\n\t Invalid arguments were given to this function."
                        << "\n\t is_binary_classification_problem(samples, labels): " << is_binary_classification_problem(samples, labels)
                        << "\n\t basis.size(): " << basis.size()
                        << "\n\t eps:          " << eps
            );

            typedef typename kernel_type::scalar_type scalar_type;
            typedef typename kernel_type::mem_manager_type mm_type;

            typedef matrix<scalar_type,0,1,mm_type> col_matrix;
            typedef matrix<scalar_type,0,0,mm_type> gen_matrix;

            col_matrix c1_mean, c2_mean, temp, delta;

            col_matrix weights;

            running_covariance<gen_matrix> cov;

            // compute the covariance matrix and the means of the two classes.
            for (long i = 0; i < samples.size(); ++i)
            {
                temp = kernel_matrix(kern, basis, samples(i));
                cov.add(temp);
                if (labels(i) > 0)
                    c1_mean += temp;
                else
                    c2_mean += temp;
            }

            c1_mean /= sum(labels > 0);
            c2_mean /= sum(labels < 0);

            delta = c1_mean - c2_mean;

            gen_matrix cov_inv = bs_impl::invert(cov.covariance());

            matrix<long,0,1,mm_type> total_perm = trans(range(0, delta.size()-1));
            matrix<long,0,1,mm_type> perm = total_perm;

            std::vector<std::pair<scalar_type,long> > sorted_feats(delta.size());

            long best_size = delta.size();
            long misses = 0;
            matrix<long,0,1,mm_type> best_total_perm = perm;

            // Now we basically find fisher's linear discriminant over and over.  Each
            // time sorting the features so that the most important ones pile up together.
            weights = trans(chol(cov_inv))*delta;
            while (true)
            {

                for (unsigned long i = 0; i < sorted_feats.size(); ++i)
                    sorted_feats[i] = make_pair(std::abs(weights(i)), i);

                std::sort(sorted_feats.begin(), sorted_feats.end());

                // make a permutation vector according to the sorting
                for (long i = 0; i < perm.size(); ++i)
                    perm(i) = sorted_feats[i].second;

                // Apply the permutation.  Doing this gives the same result as permuting all the
                // features and then recomputing the delta and cov_inv from scratch.
                cov_inv = subm(cov_inv,perm,perm);
                delta = rowm(delta,perm);

                // Record all the permutations we have done so we will know how the final
                // weights match up with the original basis vectors when we are done.
                total_perm = rowm(total_perm, perm);

                // compute new Fisher weights for sorted features.
                weights = trans(chol(cov_inv))*delta;

                // Measure how many features it takes to account for eps% of the weights vector.
                const scalar_type total_weight = length_squared(weights);
                scalar_type weight_accum = 0;
                long size = 0;
                // figure out how to get eps% of the weights
                for (long i = weights.size()-1; i >= 0; --i)
                {
                    ++size;
                    weight_accum += weights(i)*weights(i);
                    if (weight_accum/total_weight > eps)
                        break;
                }

                // loop until the best_size stops dropping
                if (size < best_size)
                {
                    misses = 0;
                    best_size = size;
                    best_total_perm = total_perm;
                }
                else
                {
                    ++misses;

                    // Give up once we have had 10 rounds where we didn't find a weights vector with
                    // a smaller concentration of good features.
                    if (misses >= 10)
                        break;
                }

            }

            // make sure best_size isn't zero
            if (best_size == 0)
                best_size = 1;

            std::vector<typename kernel_type::sample_type> sorted_basis;

            // permute the basis so that it matches up with the contents of the best weights
            sorted_basis.resize(best_size);
            for (unsigned long i = 0; i < sorted_basis.size(); ++i)
            {
                // Note that we load sorted_basis backwards so that the most important
                // basis elements come first.
                sorted_basis[i] = basis(best_total_perm(basis.size()-i-1));
            }

            return sorted_basis;
        }

    }

// ----------------------------------------------------------------------------------------

    template <
        typename kernel_type,
        typename vect1_type,
        typename vect2_type,
        typename vect3_type
        >
    const std::vector<typename kernel_type::sample_type> sort_basis_vectors (
        const kernel_type& kern,
        const vect1_type& samples,
        const vect2_type& labels,
        const vect3_type& basis,
        double eps = 0.99
    )
    {
        return bs_impl::sort_basis_vectors_impl(kern,
                                                mat(samples),
                                                mat(labels),
                                                mat(basis),
                                                eps);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SORT_BASIS_VECTORs_Hh_


dlib C++ Library - sparse_kernel.h

// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SVm_SPARSE_KERNEL
#define DLIB_SVm_SPARSE_KERNEL

#include "sparse_kernel_abstract.h"
#include <cmath>
#include <limits>
#include "../algs.h"
#include "../serialize.h"
#include "sparse_vector.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    struct sparse_radial_basis_kernel
    {
        typedef typename T::value_type::second_type scalar_type;
        typedef T sample_type;
        typedef default_memory_manager mem_manager_type;

        sparse_radial_basis_kernel(const scalar_type g) : gamma(g) {}
        sparse_radial_basis_kernel() : gamma(0.1) {}
        sparse_radial_basis_kernel(
            const sparse_radial_basis_kernel& k
        ) : gamma(k.gamma) {}

        const scalar_type gamma;

        scalar_type operator() (
            const sample_type& a,
            const sample_type& b
        ) const
        {
            const scalar_type d = distance_squared(a,b);
            return std::exp(-gamma*d);
        }

        sparse_radial_basis_kernel& operator= (
            const sparse_radial_basis_kernel& k
        )
        {
            const_cast<scalar_type&>(gamma) = k.gamma;
            return *this;
        }

        bool operator== (
            const sparse_radial_basis_kernel& k
        ) const
        {
            return gamma == k.gamma;
        }
    };

    template <
        typename T
        >
    void serialize (
        const sparse_radial_basis_kernel<T>& item,
        std::ostream& out
    )
    {
        try
        {
            serialize(item.gamma, out);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while serializing object of type sparse_radial_basis_kernel");
        }
    }

    template <
        typename T
        >
    void deserialize (
        sparse_radial_basis_kernel<T>& item,
        std::istream& in
    )
    {
        typedef typename T::value_type::second_type scalar_type;
        try
        {
            deserialize(const_cast<scalar_type&>(item.gamma), in);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while deserializing object of type sparse_radial_basis_kernel");
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    struct sparse_polynomial_kernel
    {
        typedef typename T::value_type::second_type scalar_type;
        typedef T sample_type;
        typedef default_memory_manager mem_manager_type;

        sparse_polynomial_kernel(const scalar_type g, const scalar_type c, const scalar_type d) : gamma(g), coef(c), degree(d) {}
        sparse_polynomial_kernel() : gamma(1), coef(0), degree(1) {}
        sparse_polynomial_kernel(
            const sparse_polynomial_kernel& k
        ) : gamma(k.gamma), coef(k.coef), degree(k.degree) {}

        typedef T type;
        const scalar_type gamma;
        const scalar_type coef;
        const scalar_type degree;

        scalar_type operator() (
            const sample_type& a,
            const sample_type& b
        ) const
        {
            return std::pow(gamma*(dot(a,b)) + coef, degree);
        }

        sparse_polynomial_kernel& operator= (
            const sparse_polynomial_kernel& k
        )
        {
            const_cast<scalar_type&>(gamma) = k.gamma;
            const_cast<scalar_type&>(coef) = k.coef;
            const_cast<scalar_type&>(degree) = k.degree;
            return *this;
        }

        bool operator== (
            const sparse_polynomial_kernel& k
        ) const
        {
            return (gamma == k.gamma) && (coef == k.coef) && (degree == k.degree);
        }
    };

    template <
        typename T
        >
    void serialize (
        const sparse_polynomial_kernel<T>& item,
        std::ostream& out
    )
    {
        try
        {
            serialize(item.gamma, out);
            serialize(item.coef, out);
            serialize(item.degree, out);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while serializing object of type sparse_polynomial_kernel");
        }
    }

    template <
        typename T
        >
    void deserialize (
        sparse_polynomial_kernel<T>& item,
        std::istream& in
    )
    {
        typedef typename T::value_type::second_type scalar_type;
        try
        {
            deserialize(const_cast<scalar_type&>(item.gamma), in);
            deserialize(const_cast<scalar_type&>(item.coef), in);
            deserialize(const_cast<scalar_type&>(item.degree), in);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while deserializing object of type sparse_polynomial_kernel");
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    struct sparse_sigmoid_kernel
    {
        typedef typename T::value_type::second_type scalar_type;
        typedef T sample_type;
        typedef default_memory_manager mem_manager_type;

        sparse_sigmoid_kernel(const scalar_type g, const scalar_type c) : gamma(g), coef(c) {}
        sparse_sigmoid_kernel() : gamma(0.1), coef(-1.0) {}
        sparse_sigmoid_kernel(
            const sparse_sigmoid_kernel& k
        ) : gamma(k.gamma), coef(k.coef) {}

        typedef T type;
        const scalar_type gamma;
        const scalar_type coef;

        scalar_type operator() (
            const sample_type& a,
            const sample_type& b
        ) const
        {
            return std::tanh(gamma*(dot(a,b)) + coef);
        }

        sparse_sigmoid_kernel& operator= (
            const sparse_sigmoid_kernel& k
        )
        {
            const_cast<scalar_type&>(gamma) = k.gamma;
            const_cast<scalar_type&>(coef) = k.coef;
            return *this;
        }

        bool operator== (
            const sparse_sigmoid_kernel& k
        ) const
        {
            return (gamma == k.gamma) && (coef == k.coef);
        }
    };

    template <
        typename T
        >
    void serialize (
        const sparse_sigmoid_kernel<T>& item,
        std::ostream& out
    )
    {
        try
        {
            serialize(item.gamma, out);
            serialize(item.coef, out);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while serializing object of type sparse_sigmoid_kernel");
        }
    }

    template <
        typename T
        >
    void deserialize (
        sparse_sigmoid_kernel<T>& item,
        std::istream& in
    )
    {
        typedef typename T::value_type::second_type scalar_type;
        try
        {
            deserialize(const_cast<scalar_type&>(item.gamma), in);
            deserialize(const_cast<scalar_type&>(item.coef), in);
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while deserializing object of type sparse_sigmoid_kernel");
        }
    }

// ----------------------------------------------------------------------------------------

    template <typename T>
    struct 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 sparse_linear_kernel&
        ) const
        {
            return true;
        }
    };

    template <
        typename T
        >
    void serialize (
        const sparse_linear_kernel<T>& ,
        std::ostream&
    ){}

    template <
        typename T
        >
    void deserialize (
        sparse_linear_kernel<T>& ,
        std::istream&
    ){}

// ----------------------------------------------------------------------------------------

    template <typename T>
    struct sparse_histogram_intersection_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
        {
            typename sample_type::const_iterator ai = a.begin();
            typename sample_type::const_iterator bi = b.begin();

            scalar_type sum = 0;
            while (ai != a.end() && bi != b.end())
            {
                if (ai->first == bi->first)
                {
                    sum += std::min(ai->second , bi->second);
                    ++ai;
                    ++bi;
                }
                else if (ai->first < bi->first)
                {
                    ++ai;
                }
                else
                {
                    ++bi;
                }
            }

            return sum;
        }

        bool operator== (
            const sparse_histogram_intersection_kernel&
        ) const
        {
            return true;
        }
    };

    template <
        typename T
        >
    void serialize (
        const sparse_histogram_intersection_kernel<T>& ,
        std::ostream&
    ){}

    template <
        typename T
        >
    void deserialize (
        sparse_histogram_intersection_kernel<T>& ,
        std::istream&
    ){}

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SVm_SPARSE_KERNEL


dlib C++ Library - sparse_vector.h

// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SVm_SPARSE_VECTOR
#define DLIB_SVm_SPARSE_VECTOR

#include "sparse_vector_abstract.h"
#include <cmath>
#include <limits>
#include "../algs.h"
#include <vector>
#include <map>
#include "../graph_utils/edge_list_graphs.h"
#include "../matrix.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <typename T, typename U>
    typename T::value_type::second_type distance_squared (
        const T& a,
        const U& b
    )
    {
        typedef typename T::value_type::second_type scalar_type;
        typedef typename U::value_type::second_type scalar_typeU;
        // Both T and U must contain the same kinds of elements
        COMPILE_TIME_ASSERT((is_same_type<scalar_type, scalar_typeU>::value));

        typename T::const_iterator ai = a.begin();
        typename U::const_iterator bi = b.begin();

        scalar_type sum = 0, temp = 0;
        while (ai != a.end() && bi != b.end())
        {
            if (ai->first == bi->first)
            {
                temp = ai->second - bi->second;
                ++ai;
                ++bi;
            }
            else if (ai->first < bi->first)
            {
                temp = ai->second;
                ++ai;
            }
            else
            {
                temp = bi->second;
                ++bi;
            }

            sum += temp*temp;
        }

        while (ai != a.end())
        {
            sum += ai->second*ai->second;
            ++ai;
        }
        while (bi != b.end())
        {
            sum += bi->second*bi->second;
            ++bi;
        }

        return sum;
    }

// ------------------------------------------------------------------------------------

    template <typename T, typename U, typename V, typename W>
    typename T::value_type::second_type distance_squared (
        const V& a_scale,
        const T& a,
        const W& b_scale,
        const U& b
    )
    {
        typedef typename T::value_type::second_type scalar_type;
        typedef typename U::value_type::second_type scalar_typeU;
        // Both T and U must contain the same kinds of elements
        COMPILE_TIME_ASSERT((is_same_type<scalar_type, scalar_typeU>::value));

        typename T::const_iterator ai = a.begin();
        typename U::const_iterator bi = b.begin();

        scalar_type sum = 0, temp = 0;
        while (ai != a.end() && bi != b.end())
        {
            if (ai->first == bi->first)
            {
                temp = a_scale*ai->second - b_scale*bi->second;
                ++ai;
                ++bi;
            }
            else if (ai->first < bi->first)
            {
                temp = a_scale*ai->second;
                ++ai;
            }
            else
            {
                temp = b_scale*bi->second;
                ++bi;
            }

            sum += temp*temp;
        }

        while (ai != a.end())
        {
            sum += a_scale*a_scale*ai->second*ai->second;
            ++ai;
        }
        while (bi != b.end())
        {
            sum += b_scale*b_scale*bi->second*bi->second;
            ++bi;
        }

        return sum;
    }

// ------------------------------------------------------------------------------------

    template <typename T, typename U>
    typename T::value_type::second_type distance (
        const T& a,
        const U& b
    )
    {
        return std::sqrt(distance_squared(a,b));
    }

// ------------------------------------------------------------------------------------

    template <typename T, typename U, typename V, typename W>
    typename T::value_type::second_type distance (
        const V& a_scale,
        const T& a,
        const W& b_scale,
        const U& b
    )
    {
        return std::sqrt(distance_squared(a_scale,a,b_scale,b));
    }

// ------------------------------------------------------------------------------------
    // ------------------------------------------------------------------------------------

    template <typename T, typename EXP>
    typename enable_if<is_matrix<T> >::type assign (
        T& dest,
        const matrix_exp<EXP>& src
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(is_vector(src),
                    "\t void assign(dest,src)"
                    << "\n\t the src matrix must be a row or column vector"
        );

        dest = src;
    }

    template <typename T, typename EXP>
    typename disable_if<is_matrix<T> >::type assign (
        T& dest,
        const matrix_exp<EXP>& src
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(is_vector(src),
                    "\t void assign(dest,src)"
                    << "\n\t the src matrix must be a row or column vector"
        );

        dest.clear();
        typedef typename T::value_type item_type;
        for (long i = 0; i < src.size(); ++i)
        {
            dest.insert(dest.end(),item_type(i, src(i)));
        }
    }

    template <typename T, typename U>
    typename disable_if_c<is_matrix<T>::value || is_matrix<U>::value>::type assign (
        T& dest,        // sparse
        const U& src    // sparse
    )
    {
        dest.assign(src.begin(), src.end());
    }

    template <typename T, typename U, typename Comp, typename Alloc, typename S>
    typename disable_if<is_matrix<S> >::type assign (
        std::map<T,U,Comp,Alloc>& dest, // sparse
        const S& src                    // sparse
    )
    {
        dest.clear();
        dest.insert(src.begin(), src.end());
    }

// ------------------------------------------------------------------------------------
    // ------------------------------------------------------------------------------------

    template <typename T>
    struct has_unsigned_keys
    {
        static const bool value = is_unsigned_type<typename T::value_type::first_type>::value;
    };

// ------------------------------------------------------------------------------------

    namespace impl
    {
        template <typename T, typename U>
        typename T::value_type::second_type general_dot (
            const T& a,
            const U& b
        )
        {
            typedef typename T::value_type::second_type scalar_type;

            typename T::const_iterator ai = a.begin();
            typename U::const_iterator bi = b.begin();

            scalar_type sum = 0;
            while (ai != a.end() && bi != b.end())
            {
                if (ai->first == bi->first)
                {
                    sum += ai->second * bi->second;
                    ++ai;
                    ++bi;
                }
                else if (ai->first < bi->first)
                {
                    ++ai;
                }
                else
                {
                    ++bi;
                }
            }

            return sum;
        }

        template <typename T, typename U>
        inline typename T::value_type::second_type dot (
            const T& a,
            const U& b
        )
        {
            return general_dot(a,b);
        }

        template <typename T, typename U, typename alloc>
        U dot (
            const std::vector<std::pair<T,U>,alloc>& a,
            const std::vector<std::pair<T,U>,alloc>& b
        )
        {
            // You are getting this error because you are attempting to use sparse sample vectors
            // but you aren't using an unsigned integer as your key type in the sparse vectors.
            COMPILE_TIME_ASSERT(is_unsigned_type<T>::value);

            if (a.size() == 0 || b.size() == 0)
                return 0;

            // if a is really a dense vector but just represented in a sparse container
            if (a.back().first == a.size()-1)
            {
                double sum = 0;
                for (unsigned long i = 0; i < b.size(); ++i)
                {
                    if (b[i].first >= a.size())
                        break;
                    sum += a[b[i].first].second * b[i].second;
                }
                return sum;
            }
            // if b is really a dense vector but just represented in a sparse container
            else if (b.back().first == b.size()-1)
            {
                double sum = 0;
                for (unsigned long i = 0; i < a.size(); ++i)
                {
                    if (a[i].first >= b.size())
                        break;
                    sum += b[a[i].first].second * a[i].second;
                }
                return sum;
            }
            else
            {
                return general_dot(a,b);
            }
        }
    }

    template <typename T>
    inline typename T::value_type::second_type dot (
        const T& a,
        const T& b
    )
    {
        return impl::dot(a,b);
    }

    template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
    inline T4 dot (
        const std::vector<T1,T2>& a,
        const std::map<T3,T4,T5,T6>& b
    )
    {
        return impl::dot(a,b);
    }

    template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
    inline T4 dot (
        const std::map<T3,T4,T5,T6>& a,
        const std::vector<T1,T2>& b
    )
    {
        return impl::dot(a,b);
    }

// ------------------------------------------------------------------------------------

    template <typename T, typename EXP>
    typename T::value_type::second_type dot (
        const T& a,
        const matrix_exp<EXP>& b
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(is_vector(b),
                    "\t scalar_type dot(sparse_vector a, dense_vector b)"
                    << "\n\t 'b' must be a vector to be used in a dot product."
        );

        typedef typename T::value_type::second_type scalar_type;
        typedef typename T::value_type::first_type first_type;

        scalar_type sum = 0;
        for (typename T::const_iterator ai = a.begin();
             (ai != a.end()) && (ai->first < static_cast<first_type>(b.size()));
             ++ai)
        {
            sum += ai->second * b(ai->first);
        }

        return sum;
    }

// ------------------------------------------------------------------------------------

    template <typename T, typename EXP>
    typename T::value_type::second_type dot (
        const matrix_exp<EXP>& b,
        const T& a
    )
    {
        return dot(a,b);
    }

// ------------------------------------------------------------------------------------

    template <typename T>
    typename T::value_type::second_type length_squared (
        const T& a
    )
    {
        typedef typename T::value_type::second_type scalar_type;

        typename T::const_iterator i;

        scalar_type sum = 0;

        for (i = a.begin(); i != a.end(); ++i)
        {
            sum += i->second * i->second;
        }

        return sum;
    }

// ------------------------------------------------------------------------------------

    template <typename T>
    typename T::value_type::second_type length (
        const T& a
    )
    {
        return std::sqrt(length_squared(a));
    }

// ------------------------------------------------------------------------------------

    template <typename T, typename U>
    typename disable_if<is_matrix<T>,void>::type scale_by (
        T& a,
        const U& value
    )
    {
        for (typename T::iterator i = a.begin(); i != a.end(); ++i)
        {
            i->second *= value;
        }
    }

    template <typename T, typename U>
    typename enable_if<is_matrix<T>,void>::type scale_by (
        T& a,
        const U& value
    )
    {
        a *= value;
    }

// ------------------------------------------------------------------------------------

    template <typename T>
    typename disable_if<is_matrix<T>,T>::type add (
        const T& a,
        const T& b
    )
    {
        T temp;

        typename T::const_iterator i = a.begin();
        typename T::const_iterator j = b.begin();
        while (i != a.end() && j != b.end())
        {
            if (i->first == j->first)
            {
                temp.insert(temp.end(), std::make_pair(i->first, i->second + j->second));
                ++i;
                ++j;
            }
            else if (i->first < j->first)
            {
                temp.insert(temp.end(), *i);
                ++i;
            }
            else
            {
                temp.insert(temp.end(), *j);
                ++j;
            }
        }

        while (i != a.end())
        {
            temp.insert(temp.end(), *i);
            ++i;
        }
        while (j != b.end())
        {
            temp.insert(temp.end(), *j);
            ++j;
        }

        return temp;
    }

    template <typename T, typename U>
    typename enable_if_c<is_matrix<T>::value && is_matrix<U>::value, matrix_add_exp<T,U> >::type add (
        const T& a,
        const U& b
    )
    {
        return matrix_add_exp<T,U>(a.ref(),b.ref());
    }

// ------------------------------------------------------------------------------------

    template <typename T>
    typename disable_if<is_matrix<T>,T>::type subtract (
        const T& a,
        const T& b
    )
    {
        T temp;

        typename T::const_iterator i = a.begin();
        typename T::const_iterator j = b.begin();
        while (i != a.end() && j != b.end())
        {
            if (i->first == j->first)
            {
                temp.insert(temp.end(), std::make_pair(i->first, i->second - j->second));
                ++i;
                ++j;
            }
            else if (i->first < j->first)
            {
                temp.insert(temp.end(), *i);
                ++i;
            }
            else
            {
                temp.insert(temp.end(), std::make_pair(j->first, -j->second));
                ++j;
            }
        }

        while (i != a.end())
        {
            temp.insert(temp.end(), *i);
            ++i;
        }
        while (j != b.end())
        {
            temp.insert(temp.end(), std::make_pair(j->first, -j->second));
            ++j;
        }

        return temp;
    }

    template <typename T, typename U>
    typename enable_if_c<is_matrix<T>::value && is_matrix<U>::value, matrix_subtract_exp<T,U> >::type subtract (
        const T& a,
        const U& b
    )
    {
        return matrix_subtract_exp<T,U>(a.ref(),b.ref());
    }

// ------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------

    namespace impl
    {
        template <typename T>
        typename enable_if<is_matrix<typename T::type>,unsigned long>::type max_index_plus_one (
            const T& samples
        )
        {
            if (samples.size() > 0)
                return samples(0).size();
            else
                return 0;
        }

        template <typename T>
        typename enable_if<is_built_in_scalar_type<typename T::type>,unsigned long>::type max_index_plus_one (
            const T& sample
        )
        {
            return sample.size();
        }

        // This !is_built_in_scalar_type<typename T::type>::value is here to avoid an inexplicable bug in Vistual Studio 2005
        template <typename T>
        typename enable_if_c<(!is_built_in_scalar_type<typename T::type>::value) && (is_pair<typename T::type::value_type>::value) ,unsigned long>::type
        max_index_plus_one (
            const T& samples
        )
        {
            typedef typename T::type sample_type;
            // You are getting this error because you are attempting to use sparse sample vectors
            // but you aren't using an unsigned integer as your key type in the sparse vectors.
            COMPILE_TIME_ASSERT(has_unsigned_keys<sample_type>::value);

            // these should be sparse samples so look over all them to find the max index.
            unsigned long max_dim = 0;
            for (long i = 0; i < samples.size(); ++i)
            {
                if (samples(i).size() > 0)
                    max_dim = std::max<unsigned long>(max_dim, (--samples(i).end())->first + 1);
            }

            return max_dim;
        }
    }

    template <typename T>
    typename enable_if<is_pair<typename T::value_type>,unsigned long>::type max_index_plus_one (
        const T& sample
    )
    {
        if (sample.size() > 0)
            return (--sample.end())->first + 1;
        return 0;
    }

    template <typename T>
    typename disable_if_c<is_pair<typename T::value_type>::value ||
                          is_same_type<typename T::value_type,sample_pair>::value ||
                          is_same_type<typename T::value_type,ordered_sample_pair>::value , unsigned long>::type
    max_index_plus_one (
        const T& samples
    )
    {
        return impl::max_index_plus_one(mat(samples));
    }

// ------------------------------------------------------------------------------------

    template <typename T, long NR, long NC, typename MM, typename L, typename EXP>
    inline void add_to (
        matrix<T,NR,NC,MM,L>& dest,
        const matrix_exp<EXP>& src
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(is_vector(dest) && max_index_plus_one(src) <= static_cast<unsigned long>(dest.size()),
                    "\t void add_to(dest,src)"
                    << "\n\t dest must be a vector large enough to hold the src vector."
                    << "\n\t is_vector(dest):         " << is_vector(dest)
                    << "\n\t max_index_plus_one(src): " << max_index_plus_one(src)
                    << "\n\t dest.size():             " << dest.size()
        );

        for (long r = 0; r < src.size(); ++r)
            dest(r) += src(r);
    }

    template <typename T, long NR, long NC, typename MM, typename L, typename EXP>
    inline typename disable_if<is_matrix<EXP> >::type add_to (
        matrix<T,NR,NC,MM,L>& dest,
        const EXP& src
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(is_vector(dest) && max_index_plus_one(src) <= static_cast<unsigned long>(dest.size()),
                    "\t void add_to(dest,src)"
                    << "\n\t dest must be a vector large enough to hold the src vector."
                    << "\n\t is_vector(dest):         " << is_vector(dest)
                    << "\n\t max_index_plus_one(src): " << max_index_plus_one(src)
                    << "\n\t dest.size():             " << dest.size()
        );

        for (typename EXP::const_iterator i = src.begin(); i != src.end(); ++i)
            dest(i->first) += i->second;
    }

// ------------------------------------------------------------------------------------

    template <typename T, long NR, long NC, typename MM, typename L, typename EXP, typename U>
    inline void add_to (
        matrix<T,NR,NC,MM,L>& dest,
        const matrix_exp<EXP>& src,
        const U& C
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(is_vector(dest) && max_index_plus_one(src) <= static_cast<unsigned long>(dest.size()),
                    "\t void add_to(dest,src)"
                    << "\n\t dest must be a vector large enough to hold the src vector."
                    << "\n\t is_vector(dest):         " << is_vector(dest)
                    << "\n\t max_index_plus_one(src): " << max_index_plus_one(src)
                    << "\n\t dest.size():             " << dest.size()
        );

        for (long r = 0; r < src.size(); ++r)
            dest(r) += C*src(r);
    }

    template <typename T, long NR, long NC, typename MM, typename L, typename EXP, typename U>
    inline typename disable_if<is_matrix<EXP> >::type add_to (
        matrix<T,NR,NC,MM,L>& dest,
        const EXP& src,
        const U& C
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(is_vector(dest) && max_index_plus_one(src) <= static_cast<unsigned long>(dest.size()),
                    "\t void add_to(dest,src)"
                    << "\n\t dest must be a vector large enough to hold the src vector."
                    << "\n\t is_vector(dest):         " << is_vector(dest)
                    << "\n\t max_index_plus_one(src): " << max_index_plus_one(src)
                    << "\n\t dest.size():             " << dest.size()
        );

        for (typename EXP::const_iterator i = src.begin(); i != src.end(); ++i)
            dest(i->first) += C*i->second;
    }

// ------------------------------------------------------------------------------------

    template <typename T, long NR, long NC, typename MM, typename L, typename EXP>
    inline void subtract_from (
        matrix<T,NR,NC,MM,L>& dest,
        const matrix_exp<EXP>& src
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(is_vector(dest) && max_index_plus_one(src) <= static_cast<unsigned long>(dest.size()),
                    "\t void subtract_from(dest,src)"
                    << "\n\t dest must be a vector large enough to hold the src vector."
                    << "\n\t is_vector(dest):         " << is_vector(dest)
                    << "\n\t max_index_plus_one(src): " << max_index_plus_one(src)
                    << "\n\t dest.size():             " << dest.size()
        );

        for (long r = 0; r < src.size(); ++r)
            dest(r) -= src(r);
    }

    template <typename T, long NR, long NC, typename MM, typename L, typename EXP>
    inline typename disable_if<is_matrix<EXP> >::type subtract_from (
        matrix<T,NR,NC,MM,L>& dest,
        const EXP& src
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(is_vector(dest) && max_index_plus_one(src) <= static_cast<unsigned long>(dest.size()),
                    "\t void subtract_from(dest,src)"
                    << "\n\t dest must be a vector large enough to hold the src vector."
                    << "\n\t is_vector(dest):         " << is_vector(dest)
                    << "\n\t max_index_plus_one(src): " << max_index_plus_one(src)
                    << "\n\t dest.size():             " << dest.size()
        );

        for (typename EXP::const_iterator i = src.begin(); i != src.end(); ++i)
            dest(i->first) -= i->second;
    }

// ------------------------------------------------------------------------------------

    template <typename T, long NR, long NC, typename MM, typename L, typename EXP, typename U>
    inline void subtract_from (
        matrix<T,NR,NC,MM,L>& dest,
        const matrix_exp<EXP>& src,
        const U& C
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(is_vector(dest) && max_index_plus_one(src) <= static_cast<unsigned long>(dest.size()),
                    "\t void subtract_from(dest,src)"
                    << "\n\t dest must be a vector large enough to hold the src vector."
                    << "\n\t is_vector(dest):         " << is_vector(dest)
                    << "\n\t max_index_plus_one(src): " << max_index_plus_one(src)
                    << "\n\t dest.size():             " << dest.size()
        );

        for (long r = 0; r < src.size(); ++r)
            dest(r) -= C*src(r);
    }

    template <typename T, long NR, long NC, typename MM, typename L, typename EXP, typename U>
    inline typename disable_if<is_matrix<EXP> >::type subtract_from (
        matrix<T,NR,NC,MM,L>& dest,
        const EXP& src,
        const U& C
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(is_vector(dest) && max_index_plus_one(src) <= static_cast<unsigned long>(dest.size()),
                    "\t void subtract_from(dest,src)"
                    << "\n\t dest must be a vector large enough to hold the src vector."
                    << "\n\t is_vector(dest):         " << is_vector(dest)
                    << "\n\t max_index_plus_one(src): " << max_index_plus_one(src)
                    << "\n\t dest.size():             " << dest.size()
        );

        for (typename EXP::const_iterator i = src.begin(); i != src.end(); ++i)
            dest(i->first) -= C*i->second;
    }

// ------------------------------------------------------------------------------------

    template <typename T>
    typename T::value_type::second_type min (
        const T& a
    )
    {
        typedef typename T::value_type::second_type type;

        type temp = 0;
        for (typename T::const_iterator i = a.begin(); i != a.end(); ++i)
        {
            if (temp > i->second)
                temp = i->second;
        }
        return temp;
    }

// ------------------------------------------------------------------------------------

    template <typename T>
    typename T::value_type::second_type max (
        const T& a
    )
    {
        typedef typename T::value_type::second_type type;

        type temp = 0;
        for (typename T::const_iterator i = a.begin(); i != a.end(); ++i)
        {
            if (temp < i->second)
                temp = i->second;
        }
        return temp;
    }

// ----------------------------------------------------------------------------------------

    namespace impl
    {
        template <typename sparse_vector_type>
        inline matrix<typename sparse_vector_type::value_type::second_type,0,1> sparse_to_dense (
            const sparse_vector_type& vect,
            unsigned long num_dimensions
        )
        {
            // You must use unsigned integral key types in your sparse vectors
            typedef typename sparse_vector_type::value_type::first_type idx_type;
            typedef typename sparse_vector_type::value_type::second_type value_type;
            COMPILE_TIME_ASSERT(is_unsigned_type<idx_type>::value);

            matrix<value_type,0,1> result;

            if (vect.size() == 0)
                return result;

            result.set_size(num_dimensions);
            result = 0;

            for (typename sparse_vector_type::const_iterator j = vect.begin(); j != vect.end(); ++j)
            {
                if ((long)(j->first) < result.size())
                {
                    result(j->first) += j->second;
                }
            }

            return result;
        }
    }

// ----------------------------------------------------------------------------------------

    template <typename idx_type, typename value_type, typename alloc>
    matrix<value_type,0,1> sparse_to_dense (
        const std::vector<std::pair<idx_type,value_type>,alloc>& vect,
        unsigned long num_dimensions
    )
    {
        return impl::sparse_to_dense(vect,num_dimensions);
    }

// ----------------------------------------------------------------------------------------

    template <typename idx_type, typename value_type, typename alloc>
    matrix<value_type,0,1> sparse_to_dense (
        const std::vector<std::pair<idx_type,value_type>,alloc>& vect
    )
    {
        return impl::sparse_to_dense(vect, max_index_plus_one(vect));
    }

// ----------------------------------------------------------------------------------------

    template <typename T1, typename T2, typename T3, typename T4>
    matrix<T2,0,1> sparse_to_dense (
        const std::map<T1,T2,T3,T4>& vect,
        unsigned long num_dimensions
    )
    {
        return impl::sparse_to_dense(vect,num_dimensions);
    }

// ----------------------------------------------------------------------------------------

    template <typename T1, typename T2, typename T3, typename T4>
    matrix<T2,0,1> sparse_to_dense (
        const std::map<T1,T2,T3,T4>& vect
    )
    {
        return impl::sparse_to_dense(vect, max_index_plus_one(vect));
    }

// ----------------------------------------------------------------------------------------

    template <typename T>
    typename enable_if<is_matrix<T>,T&>::type sparse_to_dense(
        T& item
    ) { return item; }

    template <typename EXP>
    matrix<typename EXP::type,0,1> sparse_to_dense(
        const matrix_exp<EXP>& item,
        unsigned long num
    )
    {
        typedef typename EXP::type type;
        if (item.size() == (long)num)
            return item;
        else if (item.size() < (long)num)
            return join_cols(item, zeros_matrix<type>((long)num-item.size(),1));
        else
            return colm(item,0,(long)num);
    }

// ----------------------------------------------------------------------------------------

    template <typename sample_type, typename alloc>
    std::vector<matrix<typename sample_type::value_type::second_type,0,1> > sparse_to_dense (
        const std::vector<sample_type, alloc>& samples,
        unsigned long num_dimensions
    )
    {
        typedef typename sample_type::value_type pair_type;
        typedef typename pair_type::second_type value_type;

        std::vector< matrix<value_type,0,1> > result;

        // now turn all the samples into dense samples
        result.resize(samples.size());

        for (unsigned long i = 0; i < samples.size(); ++i)
        {
            result[i] = sparse_to_dense(samples[i],num_dimensions);
        }

        return result;
    }

// ----------------------------------------------------------------------------------------

    template <typename sample_type, typename alloc>
    std::vector<matrix<typename sample_type::value_type::second_type,0,1> > sparse_to_dense (
        const std::vector<sample_type, alloc>& samples
    )
    {
        return sparse_to_dense(samples, max_index_plus_one(samples));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    T make_sparse_vector (
        const T& v
    )
    {
        // You must use unsigned integral key types in your sparse vectors
        typedef typename T::value_type::first_type idx_type;
        typedef typename T::value_type::second_type value_type;
        COMPILE_TIME_ASSERT(is_unsigned_type<idx_type>::value);
        std::map<idx_type,value_type> temp;
        for (typename T::const_iterator i = v.begin(); i != v.end(); ++i)
        {
            temp[i->first] += i->second;
        }

        return T(temp.begin(), temp.end());
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    void make_sparse_vector_inplace(
        T& vect
    )
    {
        vect = make_sparse_vector(vect);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename U,
        typename alloc
        >
    void make_sparse_vector_inplace (
        std::vector<std::pair<T,U>,alloc>& vect
    )
    {
        if (vect.size() > 0)
        {
            std::sort(vect.begin(), vect.end());

            // merge duplicates
            for (unsigned long i = 1; i < vect.size(); ++i)
            {
                // if we found a duplicate
                if (vect[i-1].first == vect[i].first)
                {
                    // now start collapsing and merging the vector
                    unsigned long j = i-1;
                    for (unsigned long k = i; k < vect.size(); ++k)
                    {
                        if (vect[j].first == vect[k].first)
                        {
                            vect[j].second += vect[k].second;
                        }
                        else
                        {
                            ++j;
                            vect[j] = vect[k];
                        }
                    }

                    // we removed elements when we merged so we need to adjust the size.
                    vect.resize(j+1);
                    return;
                }
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <typename EXP, typename T, long NR, long NC, typename MM, typename L>
    void sparse_matrix_vector_multiply (
        const std::vector<sample_pair>& edges,
        const matrix_exp<EXP>& v,
        matrix<T,NR,NC,MM,L>& result
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(max_index_plus_one(edges) <= (unsigned long)v.size() &&
                    is_col_vector(v),
                    "\t void sparse_matrix_vector_multiply()"
                    << "\n\t Invalid inputs were given to this function"
                    << "\n\t max_index_plus_one(edges): " << max_index_plus_one(edges)
                    << "\n\t v.size():                  " << v.size()
                    << "\n\t is_col_vector(v):          " << is_col_vector(v)
        );

        result.set_size(v.nr(),v.nc());
        result = 0;

        for (unsigned long k = 0; k < edges.size(); ++k)
        {
            const long i = edges[k].index1();
            const long j = edges[k].index2();
            const double d = edges[k].distance();

            result(i) += v(j)*d;
            if (i != j)
                result(j) += v(i)*d;
        }
    }

// ----------------------------------------------------------------------------------------

    template <typename EXP>
    matrix<typename EXP::type,0,1> sparse_matrix_vector_multiply (
        const std::vector<sample_pair>& edges,
        const matrix_exp<EXP>& v
    )
    {
        matrix<typename EXP::type,0,1> result;
        sparse_matrix_vector_multiply(edges,v,result);
        return result;
    }

// ----------------------------------------------------------------------------------------

    template <typename EXP, typename T, long NR, long NC, typename MM, typename L>
    void sparse_matrix_vector_multiply (
        const std::vector<ordered_sample_pair>& edges,
        const matrix_exp<EXP>& v,
        matrix<T,NR,NC,MM,L>& result
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(max_index_plus_one(edges) <= (unsigned long)v.size() &&
                    is_col_vector(v),
                    "\t void sparse_matrix_vector_multiply()"
                    << "\n\t Invalid inputs were given to this function"
                    << "\n\t max_index_plus_one(edges): " << max_index_plus_one(edges)
                    << "\n\t v.size():                  " << v.size()
                    << "\n\t is_col_vector(v):          " << is_col_vector(v)
        );

        result.set_size(v.nr(),v.nc());
        result = 0;

        for (unsigned long k = 0; k < edges.size(); ++k)
        {
            const long i = edges[k].index1();
            const long j = edges[k].index2();
            const double d = edges[k].distance();

            result(i) += v(j)*d;
        }
    }

// ----------------------------------------------------------------------------------------

    template <typename EXP>
    matrix<typename EXP::type,0,1> sparse_matrix_vector_multiply (
        const std::vector<ordered_sample_pair>& edges,
        const matrix_exp<EXP>& v
    )
    {
        matrix<typename EXP::type,0,1> result;
        sparse_matrix_vector_multiply(edges,v,result);
        return result;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP,
        typename sparse_vector_type,
        typename T,
        long NR,
        long NC,
        typename MM,
        typename L
        >
    void sparse_matrix_vector_multiply (
        const matrix_exp<EXP>& m,
        const sparse_vector_type& v,
        matrix<T,NR,NC,MM,L>& result
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(max_index_plus_one(v) <= (unsigned long)m.nc(),
                    "\t void sparse_matrix_vector_multiply()"
                    << "\n\t Invalid inputs were given to this function"
                    << "\n\t max_index_plus_one(v): " << max_index_plus_one(v)
                    << "\n\t m.size():              " << m.size()
        );

        result.set_size(m.nr(),1);
        result = 0;

        for (typename sparse_vector_type::const_iterator i = v.begin(); i != v.end(); ++i)
        {
            for (long r = 0; r < result.nr(); ++r)
            {
                result(r) += m(r, i->first)*i->second;
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename EXP,
        typename sparse_vector_type
        >
    matrix<typename EXP::type,0,1> sparse_matrix_vector_multiply (
        const matrix_exp<EXP>& m,
        const sparse_vector_type& v
    )
    {
        matrix<typename EXP::type,0,1> result;
        sparse_matrix_vector_multiply(m,v,result);
        return result;
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SVm_SPARSE_VECTOR


dlib C++ Library - structural_object_detection_trainer.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_STRUCTURAL_OBJECT_DETECTION_TRAiNER_Hh_
#define DLIB_STRUCTURAL_OBJECT_DETECTION_TRAiNER_Hh_

#include "structural_object_detection_trainer_abstract.h"
#include "../algs.h"
#include "../optimization.h"
#include "structural_svm_object_detection_problem.h"
#include "../image_processing/object_detector.h"
#include "../image_processing/box_overlap_testing.h"
#include "../image_processing/full_object_detection.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename image_scanner_type,
        typename svm_struct_prob_type
        >
    void configure_nuclear_norm_regularizer (
        const image_scanner_type&,
        svm_struct_prob_type&
    )
    {
        // does nothing by default.  Specific scanner types overload this function to do
        // whatever is appropriate.
    }

// ----------------------------------------------------------------------------------------

    template <
        typename image_scanner_type
        >
    class structural_object_detection_trainer : noncopyable
    {

    public:
        typedef double scalar_type;
        typedef default_memory_manager mem_manager_type;
        typedef object_detector<image_scanner_type> trained_function_type;

        explicit structural_object_detection_trainer (
            const image_scanner_type& scanner_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(scanner_.get_num_detection_templates() > 0,
                "\t structural_object_detection_trainer::structural_object_detection_trainer(scanner_)"
                << "\n\t You can't have zero detection templates"
                << "\n\t this: " << this
                );

            C = 1;
            verbose = false;
            eps = 0.1;
            num_threads = 2;
            max_cache_size = 5;
            match_eps = 0.5;
            loss_per_missed_target = 1;
            loss_per_false_alarm = 1;

            scanner.copy_configuration(scanner_);

            auto_overlap_tester = true;
        }

        const image_scanner_type& get_scanner (
        ) const
        {
            return scanner;
        }

        bool auto_set_overlap_tester (
        ) const
        {
            return auto_overlap_tester;
        }

        void set_overlap_tester (
            const test_box_overlap& tester
        )
        {
            overlap_tester = tester;
            auto_overlap_tester = false;
        }

        test_box_overlap get_overlap_tester (
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(auto_set_overlap_tester() == false,
                "\t test_box_overlap structural_object_detection_trainer::get_overlap_tester()"
                << "\n\t You can't call this function if the overlap tester is generated dynamically."
                << "\n\t this: " << this
                );

            return overlap_tester;
        }

        void set_num_threads (
            unsigned long num
        )
        {
            num_threads = num;
        }

        unsigned long get_num_threads (
        ) const
        {
            return num_threads;
        }

        void set_epsilon (
            scalar_type eps_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(eps_ > 0,
                "\t void structural_object_detection_trainer::set_epsilon()"
                << "\n\t eps_ must be greater than 0"
                << "\n\t eps_: " << eps_
                << "\n\t this: " << this
                );

            eps = eps_;
        }

        scalar_type get_epsilon (
        ) const { return eps; }

        void set_max_cache_size (
            unsigned long max_size
        )
        {
            max_cache_size = max_size;
        }

        unsigned long get_max_cache_size (
        ) const
        {
            return max_cache_size;
        }

        void be_verbose (
        )
        {
            verbose = true;
        }

        void be_quiet (
        )
        {
            verbose = false;
        }

        void set_oca (
            const oca& item
        )
        {
            solver = item;
        }

        const oca get_oca (
        ) const
        {
            return solver;
        }

        void set_c (
            scalar_type C_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(C_ > 0,
                "\t void structural_object_detection_trainer::set_c()"
                << "\n\t C_ must be greater than 0"
                << "\n\t C_:    " << C_
                << "\n\t this: " << this
                );

            C = C_;
        }

        scalar_type get_c (
        ) const
        {
            return C;
        }

        void set_match_eps (
            double eps
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(0 < eps && eps < 1,
                "\t void structural_object_detection_trainer::set_match_eps(eps)"
                << "\n\t Invalid inputs were given to this function "
                << "\n\t eps:  " << eps
                << "\n\t this: " << this
                );

            match_eps = eps;
        }

        double get_match_eps (
        ) const
        {
            return match_eps;
        }

        double get_loss_per_missed_target (
        ) const
        {
            return loss_per_missed_target;
        }

        void set_loss_per_missed_target (
            double loss
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(loss > 0,
                "\t void structural_object_detection_trainer::set_loss_per_missed_target(loss)"
                << "\n\t Invalid inputs were given to this function "
                << "\n\t loss: " << loss
                << "\n\t this: " << this
                );

            loss_per_missed_target = loss;
        }

        double get_loss_per_false_alarm (
        ) const
        {
            return loss_per_false_alarm;
        }

        void set_loss_per_false_alarm (
            double loss
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(loss > 0,
                "\t void structural_object_detection_trainer::set_loss_per_false_alarm(loss)"
                << "\n\t Invalid inputs were given to this function "
                << "\n\t loss: " << loss
                << "\n\t this: " << this
                );

            loss_per_false_alarm = loss;
        }

        template <
            typename image_array_type
            >
        const trained_function_type train (
            const image_array_type& images,
            const std::vector<std::vector<full_object_detection> >& truth_object_detections
        ) const
        {
            std::vector<std::vector<rectangle> > empty_ignore(images.size());
            return train_impl(images, truth_object_detections, empty_ignore, test_box_overlap());
        }

        template <
            typename image_array_type
            >
        const trained_function_type train (
            const image_array_type& images,
            const std::vector<std::vector<full_object_detection> >& truth_object_detections,
            const std::vector<std::vector<rectangle> >& ignore,
            const test_box_overlap& ignore_overlap_tester = test_box_overlap()
        ) const
        {
            return train_impl(images, truth_object_detections, ignore, ignore_overlap_tester);
        }

        template <
            typename image_array_type
            >
        const trained_function_type train (
            const image_array_type& images,
            const std::vector<std::vector<rectangle> >& truth_object_detections
        ) const
        {
            std::vector<std::vector<rectangle> > empty_ignore(images.size());
            return train(images, truth_object_detections, empty_ignore, test_box_overlap());
        }

        template <
            typename image_array_type
            >
        const trained_function_type train (
            const image_array_type& images,
            const std::vector<std::vector<rectangle> >& truth_object_detections,
            const std::vector<std::vector<rectangle> >& ignore,
            const test_box_overlap& ignore_overlap_tester = test_box_overlap()
        ) const
        {
            std::vector<std::vector<full_object_detection> > truth_dets(truth_object_detections.size());
            for (unsigned long i = 0; i < truth_object_detections.size(); ++i)
            {
                for (unsigned long j = 0; j < truth_object_detections[i].size(); ++j)
                {
                    truth_dets[i].push_back(full_object_detection(truth_object_detections[i][j]));
                }
            }

            return train_impl(images, truth_dets, ignore, ignore_overlap_tester);
        }

    private:

        template <
            typename image_array_type
            >
        const trained_function_type train_impl (
            const image_array_type& images,
            const std::vector<std::vector<full_object_detection> >& truth_object_detections,
            const std::vector<std::vector<rectangle> >& ignore,
            const test_box_overlap& ignore_overlap_tester
        ) const
        {
#ifdef ENABLE_ASSERTS
            // make sure requires clause is not broken
            DLIB_ASSERT(is_learning_problem(images,truth_object_detections) == true && images.size() == ignore.size(),
                "\t trained_function_type structural_object_detection_trainer::train()"
                << "\n\t invalid inputs were given to this function"
                << "\n\t images.size():      " << images.size()
                << "\n\t ignore.size():      " << ignore.size()
                << "\n\t truth_object_detections.size(): " << truth_object_detections.size()
                << "\n\t is_learning_problem(images,truth_object_detections): " << is_learning_problem(images,truth_object_detections)
                );
            for (unsigned long i = 0; i < truth_object_detections.size(); ++i)
            {
                for (unsigned long j = 0; j < truth_object_detections[i].size(); ++j)
                {
                    DLIB_ASSERT(truth_object_detections[i][j].num_parts() == get_scanner().get_num_movable_components_per_detection_template() &&
                                all_parts_in_rect(truth_object_detections[i][j]) == true,
                        "\t trained_function_type structural_object_detection_trainer::train()"
                        << "\n\t invalid inputs were given to this function"
                        << "\n\t truth_object_detections["<<i<<"]["<<j<<"].num_parts():                " <<
                            truth_object_detections[i][j].num_parts()
                        << "\n\t get_scanner().get_num_movable_components_per_detection_template(): " <<
                            get_scanner().get_num_movable_components_per_detection_template()
                        << "\n\t all_parts_in_rect(truth_object_detections["<<i<<"]["<<j<<"]): " << all_parts_in_rect(truth_object_detections[i][j])
                    );
                }
            }
#endif

            structural_svm_object_detection_problem<image_scanner_type,image_array_type >
                svm_prob(scanner, overlap_tester, auto_overlap_tester, images,
                    truth_object_detections, ignore, ignore_overlap_tester, num_threads);

            if (verbose)
                svm_prob.be_verbose();

            svm_prob.set_c(C);
            svm_prob.set_epsilon(eps);
            svm_prob.set_max_cache_size(max_cache_size);
            svm_prob.set_match_eps(match_eps);
            svm_prob.set_loss_per_missed_target(loss_per_missed_target);
            svm_prob.set_loss_per_false_alarm(loss_per_false_alarm);
            configure_nuclear_norm_regularizer(scanner, svm_prob);
            matrix<double,0,1> w;

            // Run the optimizer to find the optimal w.
            solver(svm_prob,w);

            // report the results of the training.
            return object_detector<image_scanner_type>(scanner, svm_prob.get_overlap_tester(), w);
        }

        image_scanner_type scanner;
        test_box_overlap overlap_tester;

        double C;
        oca solver;
        double eps;
        double match_eps;
        bool verbose;
        unsigned long num_threads;
        unsigned long max_cache_size;
        double loss_per_missed_target;
        double loss_per_false_alarm;
        bool auto_overlap_tester;

    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_STRUCTURAL_OBJECT_DETECTION_TRAiNER_Hh_


dlib C++ Library - structural_svm_assignment_problem.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_STRUCTURAL_SVM_ASSiGNMENT_PROBLEM_Hh_
#define DLIB_STRUCTURAL_SVM_ASSiGNMENT_PROBLEM_Hh_

#include "structural_svm_assignment_problem_abstract.h"
#include "../matrix.h"
#include <vector>
#include <iterator>
#include "structural_svm_problem_threaded.h"

// ----------------------------------------------------------------------------------------

namespace dlib
{
    template <long n, typename T>
    struct column_matrix_static_resize
    {
        typedef T type;
    };

    template <long n, typename T, long NR, long NC, typename MM, typename L>
    struct column_matrix_static_resize<n, matrix<T,NR,NC,MM,L> >
    {
        typedef matrix<T,NR+n,NC,MM,L> type;
    };

    template <long n, typename T, long NC, typename MM, typename L>
    struct column_matrix_static_resize<n, matrix<T,0,NC,MM,L> >
    {
        typedef matrix<T,0,NC,MM,L> type;
    };

    template <typename T>
    struct add_one_to_static_feat_size
    {
        typedef typename column_matrix_static_resize<1,typename T::feature_vector_type>::type type;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename feature_extractor
        >
    class structural_svm_assignment_problem : noncopyable,
        public structural_svm_problem_threaded<matrix<double,0,1>, typename add_one_to_static_feat_size<feature_extractor>::type >
    {
    public:
        typedef matrix<double,0,1> matrix_type;
        typedef typename add_one_to_static_feat_size<feature_extractor>::type feature_vector_type;

        typedef typename feature_extractor::lhs_element lhs_element;
        typedef typename feature_extractor::rhs_element rhs_element;

        typedef std::pair<std::vector<lhs_element>, std::vector<rhs_element> > sample_type;

        typedef std::vector<long> label_type;

        structural_svm_assignment_problem(
            const std::vector<sample_type>& samples_,
            const std::vector<label_type>& labels_,
            const feature_extractor& fe_,
            bool force_assignment_,
            unsigned long num_threads,
            const double loss_per_false_association_,
            const double loss_per_missed_association_
        ) :
            structural_svm_problem_threaded<matrix_type,feature_vector_type>(num_threads),
            samples(samples_),
            labels(labels_),
            fe(fe_),
            force_assignment(force_assignment_),
            loss_per_false_association(loss_per_false_association_),
            loss_per_missed_association(loss_per_missed_association_)
        {
            // make sure requires clause is not broken
#ifdef ENABLE_ASSERTS
            DLIB_ASSERT(loss_per_false_association > 0 && loss_per_missed_association > 0,
                "\t structural_svm_assignment_problem::structural_svm_assignment_problem()"
                << "\n\t invalid inputs were given to this function"
                << "\n\t loss_per_false_association:  " << loss_per_false_association
                << "\n\t loss_per_missed_association: " << loss_per_missed_association
                << "\n\t this: " << this
            );
            if (force_assignment)
            {
                DLIB_ASSERT(is_forced_assignment_problem(samples, labels),
                            "\t structural_svm_assignment_problem::structural_svm_assignment_problem()"
                            << "\n\t invalid inputs were given to this function"
                            << "\n\t is_forced_assignment_problem(samples,labels): " << is_forced_assignment_problem(samples,labels)
                            << "\n\t is_assignment_problem(samples,labels):        " << is_assignment_problem(samples,labels)
                            << "\n\t is_learning_problem(samples,labels):          " << is_learning_problem(samples,labels)
                            << "\n\t this: " << this
                            );
            }
            else
            {
                DLIB_ASSERT(is_assignment_problem(samples, labels),
                            "\t structural_svm_assignment_problem::structural_svm_assignment_problem()"
                            << "\n\t invalid inputs were given to this function"
                            << "\n\t is_assignment_problem(samples,labels): " << is_assignment_problem(samples,labels)
                            << "\n\t is_learning_problem(samples,labels):   " << is_learning_problem(samples,labels)
                            << "\n\t this: " << this
                            );
            }
#endif

        }

    private:
        virtual long get_num_dimensions (
        ) const
        {
            return fe.num_features()+1; // +1 for the bias term
        }

        virtual long get_num_samples (
        ) const
        {
            return samples.size();
        }

        template <typename psi_type>
        typename enable_if<is_matrix<psi_type> >::type get_joint_feature_vector (
            const sample_type& sample,
            const label_type& label,
            psi_type& psi
        ) const
        {
            typename feature_extractor::feature_vector_type feats;
            psi.set_size(get_num_dimensions());
            psi = 0;
            for (unsigned long i = 0; i < sample.first.size(); ++i)
            {
                if (label[i] != -1)
                {
                    fe.get_features(sample.first[i], sample.second[label[i]], feats);
                    set_rowm(psi,range(0,feats.size()-1)) += feats;
                    psi(get_num_dimensions()-1) += 1;
                }
            }
        }

        template <typename T>
        void append_to_sparse_vect (
            T& psi,
            const T& vect
        ) const
        {
            std::copy(vect.begin(), vect.end(), std::back_inserter(psi));
        }

        template <typename psi_type>
        typename disable_if<is_matrix<psi_type> >::type get_joint_feature_vector (
            const sample_type& sample,
            const label_type& label,
            psi_type& psi
        ) const
        {
            psi.clear();
            feature_vector_type feats;
            int num_assignments = 0;
            for (unsigned long i = 0; i < sample.first.size(); ++i)
            {
                if (label[i] != -1)
                {
                    fe.get_features(sample.first[i], sample.second[label[i]], feats);
                    append_to_sparse_vect(psi, feats);
                    ++num_assignments;
                }
            }
            psi.push_back(std::make_pair(get_num_dimensions()-1,num_assignments));
        }

        virtual void get_truth_joint_feature_vector (
            long idx,
            feature_vector_type& psi
        ) const
        {
            get_joint_feature_vector(samples[idx], labels[idx], psi);
        }

        virtual void separation_oracle (
            const long idx,
            const matrix_type& current_solution,
            double& loss,
            feature_vector_type& psi
        ) const
        {
            matrix<double> cost;
            unsigned long size;
            if (force_assignment)
            {
                unsigned long lhs_size = samples[idx].first.size();
                unsigned long rhs_size = samples[idx].second.size();
                size = std::max(lhs_size, rhs_size);
            }
            else
            {
                unsigned long rhs_size = samples[idx].second.size() + samples[idx].first.size();
                size = rhs_size;
            }
            cost.set_size(size, size);

            typename feature_extractor::feature_vector_type feats;

            // now fill out the cost assignment matrix
            for (long r = 0; r < cost.nr(); ++r)
            {
                for (long c = 0; c < cost.nc(); ++c)
                {
                    if (r < (long)samples[idx].first.size())
                    {
                        if (c < (long)samples[idx].second.size())
                        {
                            fe.get_features(samples[idx].first[r], samples[idx].second[c], feats);
                            const double bias = current_solution(current_solution.size()-1);
                            cost(r,c) = dot(colm(current_solution,0,current_solution.size()-1), feats) + bias;

                            // add in the loss since this corresponds to an incorrect prediction.
                            if (c != labels[idx][r])
                            {
                                cost(r,c) += loss_per_false_association;
                            }
                        }
                        else
                        {
                            if (labels[idx][r] == -1)
                                cost(r,c) = 0;
                            else
                                cost(r,c) = loss_per_missed_association;
                        }

                    }
                    else
                    {
                        cost(r,c) = 0;
                    }
                }
            }

            std::vector<long> assignment;

            if (cost.size() != 0)
            {
                // max_cost_assignment() only works with integer matrices, so convert from
                // double to integer.
                const double scale = (std::numeric_limits<dlib::int64>::max()/1000)/max(abs(cost));
                matrix<dlib::int64> int_cost = matrix_cast<dlib::int64>(round(cost*scale));
                assignment = max_cost_assignment(int_cost);
                assignment.resize(samples[idx].first.size());
            }

            loss = 0;
            // adjust assignment so that non-assignments have a value of -1. Also compute loss.
            for (unsigned long i = 0; i < assignment.size(); ++i)
            {
                if (assignment[i] >= (long)samples[idx].second.size())
                    assignment[i] = -1;

                if (assignment[i] != labels[idx][i])
                {
                    if (assignment[i] == -1)
                        loss += loss_per_missed_association;
                    else
                        loss += loss_per_false_association;
                }
            }

            get_joint_feature_vector(samples[idx], assignment, psi);
        }

        const std::vector<sample_type>& samples;
        const std::vector<label_type>& labels;
        const feature_extractor& fe;
        bool force_assignment;
        const double loss_per_false_association;
        const double loss_per_missed_association;
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_STRUCTURAL_SVM_ASSiGNMENT_PROBLEM_Hh_


dlib C++ Library - structural_svm_object_detection_problem.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_STRUCTURAL_SVM_ObJECT_DETECTION_PROBLEM_Hh_
#define DLIB_STRUCTURAL_SVM_ObJECT_DETECTION_PROBLEM_Hh_

#include "structural_svm_object_detection_problem_abstract.h"
#include "../matrix.h"
#include "structural_svm_problem_threaded.h"
#include <sstream>
#include "../string.h"
#include "../array.h"
#include "../image_processing/full_object_detection.h"
#include "../image_processing/box_overlap_testing.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class impossible_labeling_error : public dlib::error
    {
    public:
        impossible_labeling_error(const std::string& msg) : dlib::error(msg) {};
    };

// ----------------------------------------------------------------------------------------

    template <
        typename image_scanner_type,
        typename image_array_type
        >
    class structural_svm_object_detection_problem : public structural_svm_problem_threaded<matrix<double,0,1> >,
                                                    noncopyable
    {
    public:

        structural_svm_object_detection_problem(
            const image_scanner_type& scanner,
            const test_box_overlap& overlap_tester,
            const bool auto_overlap_tester,
            const image_array_type& images_,
            const std::vector<std::vector<full_object_detection> >& truth_object_detections_,
            const std::vector<std::vector<rectangle> >& ignore_,
            const test_box_overlap& ignore_overlap_tester_,
            unsigned long num_threads = 2
        ) :
            structural_svm_problem_threaded<matrix<double,0,1> >(num_threads),
            boxes_overlap(overlap_tester),
            images(images_),
            truth_object_detections(truth_object_detections_),
            ignore(ignore_),
            ignore_overlap_tester(ignore_overlap_tester_),
            match_eps(0.5),
            loss_per_false_alarm(1),
            loss_per_missed_target(1)
        {
#ifdef ENABLE_ASSERTS
            // make sure requires clause is not broken
            DLIB_ASSERT(is_learning_problem(images_, truth_object_detections_) &&
                        ignore_.size() == images_.size() &&
                         scanner.get_num_detection_templates() > 0,
                "\t structural_svm_object_detection_problem::structural_svm_object_detection_problem()"
                << "\n\t Invalid inputs were given to this function "
                << "\n\t scanner.get_num_detection_templates(): " << scanner.get_num_detection_templates()
                << "\n\t is_learning_problem(images_,truth_object_detections_): " << is_learning_problem(images_,truth_object_detections_)
                << "\n\t ignore.size(): " << ignore.size()
                << "\n\t images.size(): " << images.size()
                << "\n\t this: " << this
                );
            for (unsigned long i = 0; i < truth_object_detections.size(); ++i)
            {
                for (unsigned long j = 0; j < truth_object_detections[i].size(); ++j)
                {
                    DLIB_ASSERT(truth_object_detections[i][j].num_parts() == scanner.get_num_movable_components_per_detection_template(),
                        "\t trained_function_type structural_object_detection_trainer::train()"
                        << "\n\t invalid inputs were given to this function"
                        << "\n\t truth_object_detections["<<i<<"]["<<j<<"].num_parts():          " <<
                            truth_object_detections[i][j].num_parts()
                        << "\n\t scanner.get_num_movable_components_per_detection_template(): " <<
                            scanner.get_num_movable_components_per_detection_template()
                        << "\n\t all_parts_in_rect(truth_object_detections["<<i<<"]["<<j<<"]): " << all_parts_in_rect(truth_object_detections[i][j])
                    );
                }
            }
#endif
            // The purpose of the max_num_dets member variable is to give us a reasonable
            // upper limit on the number of detections we can expect from a single image.
            // This is used in the separation_oracle to put a hard limit on the number of
            // detections we will consider.  We do this purely for computational reasons
            // since otherwise we can end up wasting large amounts of time on certain
            // pathological cases during optimization which ultimately do not influence the
            // result.  Therefore, we force the separation oracle to only consider the
            // max_num_dets strongest detections.
            max_num_dets = 0;
            for (unsigned long i = 0; i < truth_object_detections.size(); ++i)
            {
                if (truth_object_detections[i].size() > max_num_dets)
                    max_num_dets = truth_object_detections[i].size();
            }
            max_num_dets = max_num_dets*3 + 10;

            initialize_scanners(scanner, num_threads);

            if (auto_overlap_tester)
            {
                auto_configure_overlap_tester();
            }
        }

        test_box_overlap get_overlap_tester (
        ) const
        {
            return boxes_overlap;
        }

        void set_match_eps (
            double eps
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(0 < eps && eps < 1,
                "\t void structural_svm_object_detection_problem::set_match_eps(eps)"
                << "\n\t Invalid inputs were given to this function "
                << "\n\t eps:  " << eps
                << "\n\t this: " << this
                );

            match_eps = eps;
        }

        double get_match_eps (
        ) const
        {
            return match_eps;
        }

        double get_loss_per_missed_target (
        ) const
        {
            return loss_per_missed_target;
        }

        void set_loss_per_missed_target (
            double loss
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(loss > 0,
                "\t void structural_svm_object_detection_problem::set_loss_per_missed_target(loss)"
                << "\n\t Invalid inputs were given to this function "
                << "\n\t loss: " << loss
                << "\n\t this: " << this
                );

            loss_per_missed_target = loss;
        }

        double get_loss_per_false_alarm (
        ) const
        {
            return loss_per_false_alarm;
        }

        void set_loss_per_false_alarm (
            double loss
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(loss > 0,
                "\t void structural_svm_object_detection_problem::set_loss_per_false_alarm(loss)"
                << "\n\t Invalid inputs were given to this function "
                << "\n\t loss: " << loss
                << "\n\t this: " << this
                );

            loss_per_false_alarm = loss;
        }

    private:

        void auto_configure_overlap_tester(
        )
        {
            std::vector<std::vector<rectangle> > mapped_rects(truth_object_detections.size());
            for (unsigned long i = 0; i < truth_object_detections.size(); ++i)
            {
                mapped_rects[i].resize(truth_object_detections[i].size());
                for (unsigned long j = 0; j < truth_object_detections[i].size(); ++j)
                {
                    mapped_rects[i][j] = scanners[i].get_best_matching_rect(truth_object_detections[i][j].get_rect());
                }
            }

            boxes_overlap = find_tight_overlap_tester(mapped_rects);
        }

        virtual long get_num_dimensions (
        ) const
        {
            return scanners[0].get_num_dimensions() +
                1;// for threshold
        }

        virtual long get_num_samples (
        ) const
        {
            return images.size();
        }

        virtual void get_truth_joint_feature_vector (
            long idx,
            feature_vector_type& psi
        ) const
        {
            const image_scanner_type& scanner = scanners[idx];

            psi.set_size(get_num_dimensions());
            std::vector<rectangle> mapped_rects;

            psi = 0;
            for (unsigned long i = 0; i < truth_object_detections[idx].size(); ++i)
            {
                mapped_rects.push_back(scanner.get_best_matching_rect(truth_object_detections[idx][i].get_rect()));
                scanner.get_feature_vector(truth_object_detections[idx][i], psi);
            }
            psi(scanner.get_num_dimensions()) = -1.0*truth_object_detections[idx].size();

            // check if any of the boxes overlap.  If they do then it is impossible for
            // us to learn to correctly classify this sample
            for (unsigned long i = 0; i < mapped_rects.size(); ++i)
            {
                for (unsigned long j = i+1; j < mapped_rects.size(); ++j)
                {
                    if (boxes_overlap(mapped_rects[i], mapped_rects[j]))
                    {
                        const double area_overlap = mapped_rects[i].intersect(mapped_rects[j]).area();
                        const double match_amount = area_overlap/(double)( mapped_rects[i]+mapped_rects[j]).area();
                        const double overlap_amount = area_overlap/std::min(mapped_rects[i].area(),mapped_rects[j].area());

                        using namespace std;
                        ostringstream sout;
                        sout << "An impossible set of object labels was detected. This is happening because ";
                        sout << "the truth labels for an image contain rectangles which overlap according to the ";
                        sout << "test_box_overlap object supplied for non-max suppression.  To resolve this, you ";
                        sout << "either need to relax the test_box_overlap object so it doesn't mark these rectangles as ";
                        sout << "overlapping or adjust the truth rectangles. ";

                        // make sure the above string fits nicely into a command prompt window.
                        string temp = sout.str();
                        sout.str(""); sout << wrap_string(temp,0,0) << endl << endl;

                        sout << "image index: "<< idx << endl;
                        sout << "The offending rectangles are:\n";
                        sout << "rect1: "<< mapped_rects[i] << endl;
                        sout << "rect2: "<< mapped_rects[j] << endl;
                        sout << "match amount:   " << match_amount << endl;
                        sout << "overlap amount: " << overlap_amount << endl;
                        throw dlib::impossible_labeling_error(sout.str());
                    }
                }
            }

            // make sure the mapped rectangles are within match_eps of the
            // truth rectangles.
            for (unsigned long i = 0; i < mapped_rects.size(); ++i)
            {
                const double area = (truth_object_detections[idx][i].get_rect().intersect(mapped_rects[i])).area();
                const double total_area = (truth_object_detections[idx][i].get_rect() + mapped_rects[i]).area();
                if (area/total_area <= match_eps)
                {
                    using namespace std;
                    ostringstream sout;
                    sout << "An impossible set of object labels was detected.  This is happening because ";
                    sout << "none of the object locations checked by the supplied image scanner is a close ";
                    sout << "enough match to one of the truth boxes.  To resolve this you need to either lower the match_eps ";
                    sout << "or adjust the settings of the image scanner so that it hits this truth box.  ";
                    sout << "Or you could adjust the ";
                    sout << "offending truth rectangle so it can be matched by the current image scanner.  Also, if you ";
                    sout << "are using the scan_image_pyramid object then you could try using a finer image pyramid ";
                    sout << "or adding more detection templates.  E.g. if one of ";
                    sout << "your existing detection templates has a matching width/height ratio and smaller area ";
                    sout << "than the offending rectangle then a finer image pyramid would probably help.";

                    // make sure the above string fits nicely into a command prompt window.
                    string temp = sout.str();
                    sout.str(""); sout << wrap_string(temp,0,0) << endl << endl;

                    sout << "image index              "<< idx << endl;
                    sout << "match_eps:               "<< match_eps << endl;
                    sout << "best possible match:     "<< area/total_area << endl;
                    sout << "truth rect:              "<< truth_object_detections[idx][i].get_rect() << endl;
                    sout << "truth rect width/height: "<< truth_object_detections[idx][i].get_rect().width()/(double)truth_object_detections[idx][i].get_rect().height() << endl;
                    sout << "truth rect area:         "<< truth_object_detections[idx][i].get_rect().area() << endl;
                    sout << "nearest detection template rect:              "<< mapped_rects[i] << endl;
                    sout << "nearest detection template rect width/height: "<< mapped_rects[i].width()/(double)mapped_rects[i].height() << endl;
                    sout << "nearest detection template rect area:         "<< mapped_rects[i].area() << endl;
                    throw dlib::impossible_labeling_error(sout.str());
                }

            }
        }

        virtual void separation_oracle (
            const long idx,
            const matrix_type& current_solution,
            scalar_type& loss,
            feature_vector_type& psi
        ) const
        {
            const image_scanner_type& scanner = scanners[idx];

            std::vector<std::pair<double, rectangle> > dets;
            const double thresh = current_solution(scanner.get_num_dimensions());

            scanner.detect(current_solution, dets, thresh-loss_per_false_alarm);

            // The loss will measure the number of incorrect detections.  A detection is
            // incorrect if it doesn't hit a truth rectangle or if it is a duplicate detection
            // on a truth rectangle.
            loss = truth_object_detections[idx].size()*loss_per_missed_target;

            // Measure the loss augmented score for the detections which hit a truth rect.
            std::vector<double> truth_score_hits(truth_object_detections[idx].size(), 0);

            // keep track of which truth boxes we have hit so far.
            std::vector<bool> hit_truth_table(truth_object_detections[idx].size(), false);

            std::vector<rectangle> final_dets;
            // The point of this loop is to fill out the truth_score_hits array.
            for (unsigned long i = 0; i < dets.size() && final_dets.size() < max_num_dets; ++i)
            {
                if (overlaps_any_box(boxes_overlap, final_dets, dets[i].second))
                    continue;

                const std::pair<double,unsigned int> truth = find_best_match(truth_object_detections[idx], dets[i].second);

                final_dets.push_back(dets[i].second);

                const double truth_match = truth.first;
                // if hit truth rect
                if (truth_match > match_eps)
                {
                    // if this is the first time we have seen a detect which hit truth_object_detections[truth.second]
                    const double score = dets[i].first - thresh;
                    if (hit_truth_table[truth.second] == false)
                    {
                        hit_truth_table[truth.second] = true;
                        truth_score_hits[truth.second] += score;
                    }
                    else
                    {
                        truth_score_hits[truth.second] += score + loss_per_false_alarm;
                    }
                }
            }

            hit_truth_table.assign(hit_truth_table.size(), false);

            final_dets.clear();
#ifdef ENABLE_ASSERTS
            double total_score = 0;
#endif
            // Now figure out which detections jointly maximize the loss and detection score sum.  We
            // need to take into account the fact that allowing a true detection in the output, while
            // initially reducing the loss, may allow us to increase the loss later with many duplicate
            // detections.
            for (unsigned long i = 0; i < dets.size() && final_dets.size() < max_num_dets; ++i)
            {
                if (overlaps_any_box(boxes_overlap, final_dets, dets[i].second))
                    continue;

                const std::pair<double,unsigned int> truth = find_best_match(truth_object_detections[idx], dets[i].second);

                const double truth_match = truth.first;
                if (truth_match > match_eps)
                {
                    if (truth_score_hits[truth.second] > loss_per_missed_target)
                    {
                        if (!hit_truth_table[truth.second])
                        {
                            hit_truth_table[truth.second] = true;
                            final_dets.push_back(dets[i].second);
#ifdef ENABLE_ASSERTS
                            total_score += dets[i].first;
#endif
                            loss -= loss_per_missed_target;
                        }
                        else
                        {
                            final_dets.push_back(dets[i].second);
#ifdef ENABLE_ASSERTS
                            total_score += dets[i].first;
#endif
                            loss += loss_per_false_alarm;
                        }
                    }
                }
                else if (!overlaps_ignore_box(idx,dets[i].second))
                {
                    // didn't hit anything
                    final_dets.push_back(dets[i].second);
#ifdef ENABLE_ASSERTS
                    total_score += dets[i].first;
#endif
                    loss += loss_per_false_alarm;
                }
            }

            psi.set_size(get_num_dimensions());
            psi = 0;
            for (unsigned long i = 0; i < final_dets.size(); ++i)
                scanner.get_feature_vector(scanner.get_full_object_detection(final_dets[i], current_solution), psi);

#ifdef ENABLE_ASSERTS
            const double psi_score = dot(psi, current_solution);
            DLIB_CASSERT(std::abs(psi_score-total_score) <= 1e-4 * std::max(1.0,std::max(std::abs(psi_score),std::abs(total_score))),
                        "\t The get_feature_vector() and detect() methods of image_scanner_type are not in sync."
                        << "\n\t The relative error is too large to be attributed to rounding error."
                        << "\n\t error:       " << std::abs(psi_score-total_score)
                        << "\n\t psi_score:   " << psi_score
                        << "\n\t total_score: " << total_score
            );
#endif

            psi(scanner.get_num_dimensions()) = -1.0*final_dets.size();
        }

        bool overlaps_ignore_box (
            const long idx,
            const dlib::rectangle& rect
        ) const
        {
            for (unsigned long i = 0; i < ignore[idx].size(); ++i)
            {
                if (ignore_overlap_tester(ignore[idx][i], rect))
                    return true;
            }
            return false;
        }

        std::pair<double,unsigned int> find_best_match(
            const std::vector<full_object_detection>& boxes,
            const rectangle rect
        ) const
        /*!
            ensures
                - determines which rectangle in boxes matches rect the most and
                  returns the amount of this match.  Specifically, the match is
                  a number O with the following properties:
                    - 0 <= O <= 1
                    - Let R be the maximum matching rectangle in boxes, then
                      O == (R.intersect(rect)).area() / (R + rect).area()
                    - O == 0 if there is no match with any rectangle.
        !*/
        {
            double match = 0;
            unsigned int best_idx = 0;
            for (unsigned long i = 0; i < boxes.size(); ++i)
            {

                const unsigned long area = rect.intersect(boxes[i].get_rect()).area();
                if (area != 0)
                {
                    const double new_match = area / static_cast<double>((rect + boxes[i].get_rect()).area());
                    if (new_match > match)
                    {
                        match = new_match;
                        best_idx = i;
                    }
                }
            }

            return std::make_pair(match,best_idx);
        }

        struct init_scanners_helper
        {
            init_scanners_helper (
                array<image_scanner_type>& scanners_,
                const image_array_type& images_
            ) :
                scanners(scanners_),
                images(images_)
            {}

            array<image_scanner_type>& scanners;
            const image_array_type& images;

            void operator() (long i ) const
            {
                scanners[i].load(images[i]);
            }
        };

        void initialize_scanners (
            const image_scanner_type& scanner,
            unsigned long num_threads
        )
        {
            scanners.set_max_size(images.size());
            scanners.set_size(images.size());

            for (unsigned long i = 0; i < scanners.size(); ++i)
                scanners[i].copy_configuration(scanner);

            // now load the images into all the scanners
            parallel_for(num_threads, 0, scanners.size(), init_scanners_helper(scanners, images));
        }

        test_box_overlap boxes_overlap;

        mutable array<image_scanner_type> scanners;

        const image_array_type& images;
        const std::vector<std::vector<full_object_detection> >& truth_object_detections;
        const std::vector<std::vector<rectangle> >& ignore;
        const test_box_overlap ignore_overlap_tester;

        unsigned long max_num_dets;
        double match_eps;
        double loss_per_false_alarm;
        double loss_per_missed_target;
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_STRUCTURAL_SVM_ObJECT_DETECTION_PROBLEM_Hh_


dlib C++ Library - structural_svm_problem.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_STRUCTURAL_SVM_PRObLEM_Hh_
#define DLIB_STRUCTURAL_SVM_PRObLEM_Hh_

#include "structural_svm_problem_abstract.h"
#include "../algs.h"
#include <vector>
#include "../optimization/optimization_oca.h"
#include "../matrix.h"
#include "sparse_vector.h"
#include <iostream>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    namespace impl
    {
        struct nuclear_norm_regularizer
        {
            long first_dimension;
            long nr;
            long nc;
            double regularization_strength;
        };
    }

// ----------------------------------------------------------------------------------------

    template <
        typename structural_svm_problem
        >
    class cache_element_structural_svm
    {
    public:

        cache_element_structural_svm (
        ) : prob(0), sample_idx(0), last_true_risk_computed(std::numeric_limits<double>::infinity()) {}

        typedef typename structural_svm_problem::scalar_type scalar_type;
        typedef typename structural_svm_problem::matrix_type matrix_type;
        typedef typename structural_svm_problem::feature_vector_type feature_vector_type;

        void init (
            const structural_svm_problem* prob_,
            const long idx
        )
        /*!
            ensures
                - This object will be a cache for the idx-th sample in the given
                  structural_svm_problem.
        !*/
        {
            prob = prob_;
            sample_idx = idx;

            loss.clear();
            psi.clear();
            lru_count.clear();

            if (prob->get_max_cache_size() != 0)
            {
                prob->get_truth_joint_feature_vector(idx, true_psi);
                compact_sparse_vector(true_psi);
            }
        }

        void get_truth_joint_feature_vector_cached (
            feature_vector_type& psi
        ) const
        {
            if (prob->get_max_cache_size() != 0)
                psi = true_psi;
            else
                prob->get_truth_joint_feature_vector(sample_idx, psi);

            if (is_matrix<feature_vector_type>::value)
            {
                DLIB_CASSERT((long)psi.size() == prob->get_num_dimensions(),
                    "The dimensionality of your PSI vector doesn't match get_num_dimensions()");
            }
        }

        void separation_oracle_cached (
            const bool use_only_cache,
            const bool skip_cache,
            const scalar_type& saved_current_risk_gap,
            const matrix_type& current_solution,
            scalar_type& out_loss,
            feature_vector_type& out_psi
        ) const
        {
            const bool cache_enabled = prob->get_max_cache_size() != 0;

            // Don't waste time computing this if the cache isn't going to be used.
            const scalar_type dot_true_psi = cache_enabled ? dot(true_psi, current_solution) : 0;

            scalar_type best_risk = -std::numeric_limits<scalar_type>::infinity();
            unsigned long best_idx = 0;
            long max_lru_count = 0;
            if (cache_enabled)
            {
                // figure out which element in the cache is the best (i.e. has the biggest risk)
                for (unsigned long i = 0; i < loss.size(); ++i)
                {
                    const scalar_type risk = loss[i] + dot(psi[i], current_solution) - dot_true_psi;
                    if (risk > best_risk)
                    {
                        best_risk = risk;
                        out_loss = loss[i];
                        best_idx = i;
                    }
                    if (lru_count[i] > max_lru_count)
                        max_lru_count = lru_count[i];
                }

                if (!skip_cache)
                {
                    // Check if the best psi vector in the cache is still good enough to use as
                    // a proxy for the true separation oracle.  If the risk value has dropped
                    // by enough to get into the stopping condition then the best psi isn't
                    // good enough.
                    if ((best_risk + saved_current_risk_gap > last_true_risk_computed &&
                        best_risk >= 0) || use_only_cache)
                    {
                        out_psi = psi[best_idx];
                        lru_count[best_idx] = max_lru_count + 1;
                        return;
                    }
                }
            }

            prob->separation_oracle(sample_idx, current_solution, out_loss, out_psi);
            if (is_matrix<feature_vector_type>::value)
            {
                DLIB_CASSERT((long)out_psi.size() == prob->get_num_dimensions(),
                    "The dimensionality of your PSI vector doesn't match get_num_dimensions()");
            }

            if (!cache_enabled)
                return;

            compact_sparse_vector(out_psi);

            last_true_risk_computed = out_loss + dot(out_psi, current_solution) - dot_true_psi;

            // If the separation oracle is only solved approximately then the result might
            // not be as good as just selecting true_psi as the output.  So here we check
            // if that is the case.
            if (last_true_risk_computed < 0 && best_risk < 0)
            {
                out_psi = true_psi;
                out_loss = 0;
            }
            // Alternatively, an approximate separation oracle might not do as well as just
            // selecting from the cache.  So if that is the case when just take the best
            // element from the cache.
            else if (last_true_risk_computed < best_risk)
            {
                out_psi = psi[best_idx];
                out_loss = loss[best_idx];
                lru_count[best_idx] = max_lru_count + 1;
            }
            // if the cache is full
            else if (loss.size() >= prob->get_max_cache_size())
            {
                // find least recently used cache entry for idx-th sample
                const long i       = index_of_min(mat(lru_count));

                // save our new data in the cache
                loss[i] = out_loss;
                psi[i]  = out_psi;

                const long max_use = max(mat(lru_count));
                // Make sure this new cache entry has the best lru count since we have used
                // it most recently.
                lru_count[i] = max_use + 1;
            }
            else
            {
                // In this case we just append the new psi into the cache.

                loss.push_back(out_loss);
                psi.push_back(out_psi);
                long max_use = 1;
                if (lru_count.size() != 0)
                    max_use = max(mat(lru_count)) + 1;
                lru_count.push_back(max_use);
            }
        }

    private:
        // Do nothing if T isn't actually a sparse vector
        template <typename T> void compact_sparse_vector( T& ) const { }

        template <
            typename T,
            typename U,
            typename alloc
            >
        void compact_sparse_vector (
            std::vector<std::pair<T,U>,alloc>& vect
        ) const
        {
            // If the sparse vector has more entires than dimensions then it must have some
            // duplicate elements.  So compact them using make_sparse_vector_inplace().
            if (vect.size() > (unsigned long)prob->get_num_dimensions())
            {
                make_sparse_vector_inplace(vect);
                // make sure the vector doesn't use more RAM than is necessary
                std::vector<std::pair<T,U>,alloc>(vect).swap(vect);
            }
        }

        const structural_svm_problem* prob;

        long sample_idx;

        mutable feature_vector_type true_psi;
        mutable std::vector<scalar_type> loss;
        mutable std::vector<feature_vector_type> psi;
        mutable std::vector<long> lru_count;
        mutable double last_true_risk_computed;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_type_,
        typename feature_vector_type_ = matrix_type_
        >
    class structural_svm_problem : public oca_problem<matrix_type_>
    {
    public:
        /*!
            CONVENTION
                - C == get_c()
                - eps == get_epsilon()
                - max_iterations == get_max_iterations()
                - if (skip_cache) then
                    - we won't use the oracle cache when we need to evaluate the separation
                      oracle. Instead, we will directly call the user supplied separation_oracle().

                - get_max_cache_size() == max_cache_size

                - if (cache.size() != 0) then
                    - cache.size() == get_num_samples()
                    - for all i: cache[i] == the cached results of calls to separation_oracle()
                      for the i-th sample.
        !*/

        typedef matrix_type_ matrix_type;
        typedef typename matrix_type::type scalar_type;
        typedef feature_vector_type_ feature_vector_type;

        structural_svm_problem (
        ) :
            saved_current_risk_gap(0),
            eps(0.001),
            max_iterations(10000),
            verbose(false),
            skip_cache(true),
            count_below_eps(0),
            max_cache_size(5),
            converged(false),
            nuclear_norm_part(0),
            cache_based_eps(std::numeric_limits<scalar_type>::infinity()),
            C(1)
        {}

        scalar_type get_cache_based_epsilon (
        ) const
        {
            return cache_based_eps;
        }

        void set_cache_based_epsilon (
            scalar_type eps_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(eps_ > 0,
                "\t void structural_svm_problem::set_cache_based_epsilon()"
                << "\n\t eps_ must be greater than 0"
                << "\n\t eps_: " << eps_
                << "\n\t this: " << this
                );

            cache_based_eps = eps_;
        }

        void set_epsilon (
            scalar_type eps_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(eps_ > 0,
                "\t void structural_svm_problem::set_epsilon()"
                << "\n\t eps_ must be greater than 0"
                << "\n\t eps_: " << eps_
                << "\n\t this: " << this
                );

            eps = eps_;
        }

        const scalar_type get_epsilon (
        ) const { return eps; }

        unsigned long get_max_iterations (
        ) const { return max_iterations; }

        void set_max_iterations (
            unsigned long max_iter
        )
        {
            max_iterations = max_iter;
        }

        void set_max_cache_size (
            unsigned long max_size
        )
        {
            max_cache_size = max_size;
        }

        unsigned long get_max_cache_size (
        ) const { return max_cache_size; }

        void be_verbose (
        )
        {
            verbose = true;
        }

        void be_quiet(
        )
        {
            verbose = false;
        }

        scalar_type get_c (
        ) const { return C; }

        void set_c (
            scalar_type C_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(C_ > 0,
                "\t void structural_svm_problem::set_c()"
                << "\n\t C_ must be greater than 0"
                << "\n\t C_:    " << C_
                << "\n\t this: " << this
                );

            C = C_;
        }

        void add_nuclear_norm_regularizer (
            long first_dimension,
            long rows,
            long cols,
            double regularization_strength
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(0 <= first_dimension && first_dimension < get_num_dimensions() &&
                0 <= rows && 0 <= cols && rows*cols+first_dimension <= get_num_dimensions() &&
                0 < regularization_strength,
                "\t void structural_svm_problem::add_nuclear_norm_regularizer()"
                << "\n\t Invalid arguments were given to this function."
                << "\n\t first_dimension:         " << first_dimension
                << "\n\t rows:                    " << rows
                << "\n\t cols:                    " << cols
                << "\n\t get_num_dimensions():    " << get_num_dimensions()
                << "\n\t regularization_strength: " << regularization_strength
                << "\n\t this: " << this
                );

            impl::nuclear_norm_regularizer temp;
            temp.first_dimension = first_dimension;
            temp.nr = rows;
            temp.nc = cols;
            temp.regularization_strength = regularization_strength;
            nuclear_norm_regularizers.push_back(temp);
        }

        unsigned long num_nuclear_norm_regularizers (
        ) const { return nuclear_norm_regularizers.size(); }

        void clear_nuclear_norm_regularizers (
        ) { nuclear_norm_regularizers.clear(); }

        virtual long get_num_dimensions (
        ) const = 0;

        virtual long get_num_samples (
        ) const = 0;

        virtual void get_truth_joint_feature_vector (
            long idx,
            feature_vector_type& psi
        ) const = 0;

        virtual void separation_oracle (
            const long idx,
            const matrix_type& current_solution,
            scalar_type& loss,
            feature_vector_type& psi
        ) const = 0;

    private:

        virtual bool risk_has_lower_bound (
            scalar_type& lower_bound
        ) const
        {
            lower_bound = 0;
            return true;
        }

        virtual bool optimization_status (
            scalar_type current_objective_value,
            scalar_type current_error_gap,
            scalar_type current_risk_value,
            scalar_type current_risk_gap,
            unsigned long num_cutting_planes,
            unsigned long num_iterations
        ) const
        {
            if (verbose)
            {
                using namespace std;
                if (nuclear_norm_regularizers.size() != 0)
                {
                    cout << "objective:             " << current_objective_value << endl;
                    cout << "objective gap:         " << current_error_gap << endl;
                    cout << "risk:                  " << current_risk_value-nuclear_norm_part << endl;
                    cout << "risk+nuclear norm:     " << current_risk_value << endl;
                    cout << "risk+nuclear norm gap: " << current_risk_gap << endl;
                    cout << "num planes:            " << num_cutting_planes << endl;
                    cout << "iter:                  " << num_iterations << endl;
                }
                else
                {
                    cout << "objective:     " << current_objective_value << endl;
                    cout << "objective gap: " << current_error_gap << endl;
                    cout << "risk:          " << current_risk_value << endl;
                    cout << "risk gap:      " << current_risk_gap << endl;
                    cout << "num planes:    " << num_cutting_planes << endl;
                    cout << "iter:          " << num_iterations << endl;
                }
                cout << endl;
            }

            if (num_iterations >= max_iterations)
                return true;

            saved_current_risk_gap = current_risk_gap;

            if (converged)
            {
                return (current_risk_gap < std::max(cache_based_eps,cache_based_eps*current_risk_value)) ||
                       (current_risk_gap == 0);
            }

            if (current_risk_gap < eps)
            {
                // Only stop when we see that the risk gap is small enough on a non-cached
                // iteration.  But even then, if we are supposed to do the cache based
                // refinement then we just mark that we have "converged" to avoid further
                // calls to the separation oracle and run all subsequent iterations off the
                // cache.
                if (skip_cache || max_cache_size == 0)
                {
                    converged = true;
                    skip_cache = false;
                    return (current_risk_gap < std::max(cache_based_eps,cache_based_eps*current_risk_value)) ||
                           (current_risk_gap == 0);
                }

                ++count_below_eps;

                // Only disable the cache if we have seen a few consecutive iterations that
                // look to have converged.
                if (count_below_eps > 1)
                {
                    // Instead of stopping we shouldn't use the cache on the next iteration.  This way
                    // we can be sure to have the best solution rather than assuming the cache is up-to-date
                    // enough.
                    skip_cache = true;
                    count_below_eps = 0;
                }
            }
            else
            {
                count_below_eps = 0;
                skip_cache = false;
            }

            return false;
        }

        virtual void get_risk (
            matrix_type& w,
            scalar_type& risk,
            matrix_type& subgradient
        ) const
        {
            feature_vector_type ftemp;
            const unsigned long num = get_num_samples();

            // initialize the cache and compute psi_true.
            if (cache.size() == 0)
            {
                cache.resize(get_num_samples());
                for (unsigned long i = 0; i < cache.size(); ++i)
                    cache[i].init(this,i);

                psi_true.set_size(w.size(),1);
                psi_true = 0;

                for (unsigned long i = 0; i < num; ++i)
                {
                    cache[i].get_truth_joint_feature_vector_cached(ftemp);

                    subtract_from(psi_true, ftemp);
                }
            }

            subgradient = psi_true;
            scalar_type total_loss = 0;
            call_separation_oracle_on_all_samples(w,subgradient,total_loss);

            subgradient /= num;
            total_loss /= num;
            risk = total_loss + dot(subgradient,w);

            if (nuclear_norm_regularizers.size() != 0)
            {
                matrix_type grad;
                scalar_type obj;
                compute_nuclear_norm_parts(w, grad, obj);
                risk += obj;
                subgradient += grad;
            }
        }

        virtual void call_separation_oracle_on_all_samples (
            const matrix_type& w,
            matrix_type& subgradient,
            scalar_type& total_loss
        ) const
        {
            feature_vector_type ftemp;
            const unsigned long num = get_num_samples();
            for (unsigned long i = 0; i < num; ++i)
            {
                scalar_type loss;
                separation_oracle_cached(i, w, loss, ftemp);
                total_loss += loss;
                add_to(subgradient, ftemp);
            }
        }

    protected:

        void compute_nuclear_norm_parts(
            const matrix_type& m,
            matrix_type& grad,
            scalar_type& obj
        ) const
        {
            obj = 0;
            grad.set_size(m.size(), 1);
            grad = 0;

            matrix<double> u,v,w,f;
            nuclear_norm_part = 0;
            for (unsigned long i = 0; i < nuclear_norm_regularizers.size(); ++i)
            {
                const long nr = nuclear_norm_regularizers[i].nr;
                const long nc = nuclear_norm_regularizers[i].nc;
                const long size = nr*nc;
                const long idx = nuclear_norm_regularizers[i].first_dimension;
                const double strength = nuclear_norm_regularizers[i].regularization_strength;

                f = matrix_cast<double>(reshape(rowm(m, range(idx, idx+size-1)), nr, nc));
                svd3(f, u,w,v);

                const double norm = sum(w);
                obj += strength*norm;
                nuclear_norm_part += strength*norm/C;

                f = u*trans(v);

                set_rowm(grad, range(idx, idx+size-1)) = matrix_cast<double>(strength*reshape_to_column_vector(f));
            }

            obj /= C;
            grad /= C;
        }

        void separation_oracle_cached (
            const long idx,
            const matrix_type& current_solution,
            scalar_type& loss,
            feature_vector_type& psi
        ) const
        {
            cache[idx].separation_oracle_cached(converged,
                                                skip_cache,
                                                saved_current_risk_gap,
                                                current_solution,
                                                loss,
                                                psi);
        }

        std::vector<impl::nuclear_norm_regularizer> nuclear_norm_regularizers;

        mutable scalar_type saved_current_risk_gap;
        mutable matrix_type psi_true;
        scalar_type eps;
        unsigned long max_iterations;
        mutable bool verbose;

        mutable std::vector<cache_element_structural_svm<structural_svm_problem> > cache;
        mutable bool skip_cache;
        mutable int count_below_eps;
        unsigned long max_cache_size;
        mutable bool converged;
        mutable double nuclear_norm_part;
        scalar_type cache_based_eps;

        scalar_type C;
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_STRUCTURAL_SVM_PRObLEM_Hh_


dlib C++ Library - structural_svm_problem_threaded.h

// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_STRUCTURAL_SVM_PRObLEM_THREADED_Hh_
#define DLIB_STRUCTURAL_SVM_PRObLEM_THREADED_Hh_

#include "structural_svm_problem_threaded_abstract.h"
#include "../algs.h"
#include <vector>
#include "structural_svm_problem.h"
#include "../matrix.h"
#include "sparse_vector.h"
#include <iostream>
#include "../threads.h"
#include "../misc_api.h"
#include "../statistics.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_type_,
        typename feature_vector_type_ = matrix_type_
        >
    class structural_svm_problem_threaded : public structural_svm_problem<matrix_type_,feature_vector_type_>
    {
    public:

        typedef matrix_type_ matrix_type;
        typedef typename matrix_type::type scalar_type;
        typedef feature_vector_type_ feature_vector_type;

        explicit structural_svm_problem_threaded (
            unsigned long num_threads
        ) :
            tp(num_threads),
            num_iterations_executed(0)
        {}

        unsigned long get_num_threads (
        ) const { return tp.num_threads_in_pool(); }

    private:

        struct binder
        {
            binder (
                const structural_svm_problem_threaded& self_,
                const matrix_type& w_,
                matrix_type& subgradient_,
                scalar_type& total_loss_,
                bool buffer_subgradients_locally_
            ) : self(self_), w(w_), subgradient(subgradient_), total_loss(total_loss_),
                buffer_subgradients_locally(buffer_subgradients_locally_){}

            void call_oracle (
                long begin,
                long end
            )
            {
                // If we are only going to call the separation oracle once then don't run
                // the slightly more complex for loop version of this code.  Or if we just
                // don't want to run the complex buffering one.  The code later on decides
                // if we should do the buffering based on how long it takes to execute.  We
                // do this because, when the subgradient is really high dimensional it can
                // take a lot of time to add them together.  So we might want to avoid
                // doing that.
                if (end-begin <= 1 || !buffer_subgradients_locally)
                {
                    scalar_type loss;
                    feature_vector_type ftemp;
                    for (long i = begin; i < end; ++i)
                    {
                        self.separation_oracle_cached(i, w, loss, ftemp);

                        auto_mutex lock(self.accum_mutex);
                        total_loss += loss;
                        add_to(subgradient, ftemp);
                    }
                }
                else
                {
                    scalar_type loss = 0;
                    matrix_type faccum(subgradient.size(),1);
                    faccum = 0;

                    feature_vector_type ftemp;

                    for (long i = begin; i < end; ++i)
                    {
                        scalar_type loss_temp;
                        self.separation_oracle_cached(i, w, loss_temp, ftemp);
                        loss += loss_temp;
                        add_to(faccum, ftemp);
                    }

                    auto_mutex lock(self.accum_mutex);
                    total_loss += loss;
                    add_to(subgradient, faccum);
                }
            }

            const structural_svm_problem_threaded& self;
            const matrix_type& w;
            matrix_type& subgradient;
            scalar_type& total_loss;
            bool buffer_subgradients_locally;
        };

        virtual void call_separation_oracle_on_all_samples (
            const matrix_type& w,
            matrix_type& subgradient,
            scalar_type& total_loss
        ) const
        {
            ++num_iterations_executed;

            const uint64 start_time = ts.get_timestamp();

            bool buffer_subgradients_locally = with_buffer_time.mean() < without_buffer_time.mean();

            // every 50 iterations we should try to flip the buffering scheme to see if
            // doing it the other way might be better.
            if ((num_iterations_executed%50) == 0)
            {
                buffer_subgradients_locally = !buffer_subgradients_locally;
            }

            binder b(*this, w, subgradient, total_loss, buffer_subgradients_locally);
            parallel_for_blocked(tp, 0, this->get_num_samples(), b, &binder::call_oracle);

            const uint64 stop_time = ts.get_timestamp();

            if (buffer_subgradients_locally)
                with_buffer_time.add(stop_time-start_time);
            else
                without_buffer_time.add(stop_time-start_time);

        }

        mutable thread_pool tp;
        mutable mutex accum_mutex;
        mutable timestamper ts;
        mutable running_stats<double> with_buffer_time;
        mutable running_stats<double> without_buffer_time;
        mutable unsigned long num_iterations_executed;
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_STRUCTURAL_SVM_PRObLEM_THREADED_Hh_


dlib C++ Library - svm.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SVm_
#define DLIB_SVm_

#include "svm_abstract.h"
#include <cmath>
#include <limits>
#include <sstream>
#include "../matrix.h"
#include "../algs.h"
#include "../serialize.h"
#include "../rand.h"
#include "../std_allocator.h"
#include "function.h"
#include "kernel.h"
#include "../enable_if.h"
#include "../optimization.h"
#include "svm_nu_trainer.h"
#include <vector>
#include <set>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename U
        >
    inline bool is_learning_problem_impl (
        const T& x,
        const U& x_labels
    )
    {
        return is_col_vector(x) &&
               is_col_vector(x_labels) &&
               x.size() == x_labels.size() &&
               x.size() > 0;
    }

    template <
        typename T,
        typename U
        >
    inline bool is_learning_problem (
        const T& x,
        const U& x_labels
    )
    {
        return is_learning_problem_impl(mat(x), mat(x_labels));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename U
        >
    bool is_binary_classification_problem_impl (
        const T& x,
        const U& x_labels
    )
    {
        bool seen_neg_class = false;
        bool seen_pos_class = false;

        if (is_learning_problem_impl(x,x_labels) == false)
            return false;

        if (x.size() <= 1) return false;

        for (long r = 0; r < x_labels.nr(); ++r)
        {
            if (x_labels(r) != -1 && x_labels(r) != 1)
                return false;

            if (x_labels(r) == 1)
                seen_pos_class = true;
            if (x_labels(r) == -1)
                seen_neg_class = true;
        }

        return seen_pos_class && seen_neg_class;
    }

    template <
        typename T,
        typename U
        >
    bool is_binary_classification_problem (
        const T& x,
        const U& x_labels
    )
    {
        return is_binary_classification_problem_impl(mat(x), mat(x_labels));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename dec_funct_type,
        typename in_sample_vector_type,
        typename in_scalar_vector_type
        >
    const matrix<double,1,2> test_binary_decision_function_impl (
        const dec_funct_type& dec_funct,
        const in_sample_vector_type& x_test,
        const in_scalar_vector_type& y_test
    )
    {

        // make sure requires clause is not broken
        DLIB_ASSERT( is_binary_classification_problem(x_test,y_test) == true,
                    "\tmatrix test_binary_decision_function()"
                    << "\n\t invalid inputs were given to this function"
                    << "\n\t is_binary_classification_problem(x_test,y_test): "
                    << ((is_binary_classification_problem(x_test,y_test))? "true":"false"));

        // count the number of positive and negative examples
        long num_pos = 0;
        long num_neg = 0;

        long num_pos_correct = 0;
        long num_neg_correct = 0;

        // now test this trained object
        for (long i = 0; i < x_test.nr(); ++i)
        {
            // if this is a positive example
            if (y_test(i) == +1.0)
            {
                ++num_pos;
                if (dec_funct(x_test(i)) >= 0)
                    ++num_pos_correct;
            }
            else if (y_test(i) == -1.0)
            {
                ++num_neg;
                if (dec_funct(x_test(i)) < 0)
                    ++num_neg_correct;
            }
            else
            {
                throw dlib::error("invalid input labels to the test_binary_decision_function() function");
            }
        }

        matrix<double, 1, 2> res;
        res(0) = (double)num_pos_correct/(double)(num_pos);
        res(1) = (double)num_neg_correct/(double)(num_neg);
        return res;
    }

    template <
        typename dec_funct_type,
        typename in_sample_vector_type,
        typename in_scalar_vector_type
        >
    const matrix<double,1,2> test_binary_decision_function (
        const dec_funct_type& dec_funct,
        const in_sample_vector_type& x_test,
        const in_scalar_vector_type& y_test
    )
    {
        return test_binary_decision_function_impl(dec_funct,
                                 mat(x_test),
                                 mat(y_test));
    }

// ----------------------------------------------------------------------------------------

    template <
        typename sequence_type
        >
    bool is_sequence_labeling_problem (
        const std::vector<sequence_type>& samples,
        const std::vector<std::vector<unsigned long> >& labels
    )
    {
        if (is_learning_problem(samples, labels))
        {
            for (unsigned long i = 0; i < samples.size(); ++i)
            {
                if (samples[i].size() != labels[i].size())
                    return false;
            }
            return true;
        }

        return false;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename sequence_type
        >
    bool is_sequence_segmentation_problem (
        const std::vector<sequence_type>& samples,
        const std::vector<std::vector<std::pair<unsigned long,unsigned long> > >& segments
    )
    {
        if (is_learning_problem(samples, segments))
        {
            for (unsigned long i = 0; i < samples.size(); ++i)
            {
                // Make sure the segments are inside samples[i] and don't overlap with each
                // other.
                std::vector<bool> hits(samples[i].size(), false);
                for (unsigned long j = 0; j < segments[i].size(); ++j)
                {
                    const unsigned long begin = segments[i][j].first;
                    const unsigned long end = segments[i][j].second;
                    // if the segment is outside the sequence
                    if (end > samples[i].size())
                        return false;

                    if (begin >= end)
                        return false;

                    // check for overlap
                    for (unsigned long k = begin; k < end; ++k)
                    {
                        if (hits[k])
                            return false;
                        hits[k] = true;
                    }
                }
            }
            return true;
        }

        return false;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename lhs_type,
        typename rhs_type
        >
    bool is_assignment_problem (
        const std::vector<std::pair<std::vector<lhs_type>, std::vector<rhs_type> > >& samples,
        const std::vector<std::vector<long> >& labels
    )
    {
        std::vector<bool> seen_label;

        if (is_learning_problem(samples, labels))
        {
            for (unsigned long i = 0; i < samples.size(); ++i)
            {
                if (samples[i].first.size() != labels[i].size())
                    return false;

                seen_label.assign(samples[i].second.size(), false);

                for (unsigned long j = 0; j < labels[i].size(); ++j)
                {
                    if (!(-1 <= labels[i][j] && labels[i][j] < (long)samples[i].second.size()))
                        return false;

                    if (labels[i][j] != -1)
                    {
                        // check label uniqueness
                        if (seen_label[labels[i][j]])
                            return false;

                        seen_label[labels[i][j]] = true;
                    }
                }
            }
            return true;
        }

        return false;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename lhs_type,
        typename rhs_type
        >
    bool is_forced_assignment_problem (
        const std::vector<std::pair<std::vector<lhs_type>, std::vector<rhs_type> > >& samples,
        const std::vector<std::vector<long> >& labels
    )
    {
        if (is_assignment_problem(samples, labels))
        {
            for (unsigned long i = 0; i < samples.size(); ++i)
            {
                const unsigned long N = sum(mat(labels[i]) != -1);
                if (std::min(samples[i].first.size(), samples[i].second.size()) != N)
                    return false;
            }
            return true;
        }

        return false;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename detection_type_,
        typename label_type_ = long
        >
    struct labeled_detection
    {
        typedef detection_type_ detection_type;
        typedef label_type_ label_type;
        detection_type det;
        label_type label;
    };

    template <
        typename detection_type_,
        typename label_type_
        >
    inline void serialize ( const labeled_detection<detection_type_,label_type_>& item, std::ostream& out)
    {
        serialize(item.det, out);
        serialize(item.label, out);
    }

    template <
        typename detection_type_,
        typename label_type_
        >
    inline void deserialize (labeled_detection<detection_type_,label_type_>& item, std::istream& in)
    {
        deserialize(item.det, in);
        deserialize(item.label, in);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename detection_type,
        typename label_type
        >
    bool is_track_association_problem (
        const std::vector<std::vector<labeled_detection<detection_type,label_type> > >& samples
    )
    {
        if (samples.size() == 0)
            return false;

        unsigned long num_nonzero_elements = 0;
        for (unsigned long i = 0; i < samples.size(); ++i)
        {
            if (samples.size() > 0)
                ++num_nonzero_elements;
        }
        if (num_nonzero_elements < 2)
            return false;

        // now make sure the label_type values are unique within each time step.
        for (unsigned long i = 0; i < samples.size(); ++i)
        {
            std::set<label_type> vals;
            for (unsigned long j = 0; j < samples[i].size(); ++j)
                vals.insert(samples[i][j].label);
            if (vals.size() != samples[i].size())
                return false;
        }

        // passed all tests so it's good
        return true;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename detection_type,
        typename label_type
        >
    bool is_track_association_problem (
        const std::vector<std::vector<std::vector<labeled_detection<detection_type,label_type> > > >& samples
    )
    {
        for (unsigned long i = 0; i < samples.size(); ++i)
        {
            if (!is_track_association_problem(samples[i]))
                return false;
        }

        // passed all tests so it's good
        return true;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type,
        typename in_sample_vector_type,
        typename in_scalar_vector_type
        >
    const matrix<double, 1, 2, typename trainer_type::mem_manager_type>
    cross_validate_trainer_impl (
        const trainer_type& trainer,
        const in_sample_vector_type& x,
        const in_scalar_vector_type& y,
        const long folds
    )
    {
        typedef typename in_scalar_vector_type::value_type scalar_type;
        typedef typename trainer_type::mem_manager_type mem_manager_type;
        typedef matrix<scalar_type,0,1,mem_manager_type> scalar_vector_type;

        // make sure requires clause is not broken
        DLIB_ASSERT(is_binary_classification_problem(x,y) == true &&
                    1 < folds && folds <= std::min(sum(y>0),sum(y<0)),
            "\tmatrix cross_validate_trainer()"
            << "\n\t invalid inputs were given to this function"
            << "\n\t std::min(sum(y>0),sum(y<0)): " << std::min(sum(y>0),sum(y<0))
            << "\n\t folds:  " << folds
            << "\n\t is_binary_classification_problem(x,y): " << ((is_binary_classification_problem(x,y))? "true":"false")
            );

        // count the number of positive and negative examples
        long num_pos = 0;
        long num_neg = 0;
        for (long r = 0; r < y.nr(); ++r)
        {
            if (y(r) == +1.0)
                ++num_pos;
            else
                ++num_neg;
        }

        // figure out how many positive and negative examples we will have in each fold
        const long num_pos_test_samples = num_pos/folds;
        const long num_pos_train_samples = num_pos - num_pos_test_samples;
        const long num_neg_test_samples = num_neg/folds;
        const long num_neg_train_samples = num_neg - num_neg_test_samples;

        matrix<long,0,1> x_test, x_train;
        scalar_vector_type y_test, y_train;
        x_test.set_size (num_pos_test_samples  + num_neg_test_samples);
        y_test.set_size (num_pos_test_samples  + num_neg_test_samples);
        x_train.set_size(num_pos_train_samples + num_neg_train_samples);
        y_train.set_size(num_pos_train_samples + num_neg_train_samples);

        long pos_idx = 0;
        long neg_idx = 0;

        matrix<double, 1, 2, mem_manager_type> res;
        set_all_elements(res,0);

        for (long i = 0; i < folds; ++i)
        {
            long cur = 0;

            // load up our positive test samples
            while (cur < num_pos_test_samples)
            {
                if (y(pos_idx) == +1.0)
                {
                    x_test(cur) = pos_idx;
                    y_test(cur) = +1.0;
                    ++cur;
                }
                pos_idx = (pos_idx+1)%x.nr();
            }

            // load up our negative test samples
            while (cur < x_test.nr())
            {
                if (y(neg_idx) == -1.0)
                {
                    x_test(cur) = neg_idx;
                    y_test(cur) = -1.0;
                    ++cur;
                }
                neg_idx = (neg_idx+1)%x.nr();
            }

            // load the training data from the data following whatever we loaded
            // as the testing data
            long train_pos_idx = pos_idx;
            long train_neg_idx = neg_idx;
            cur = 0;

            // load up our positive train samples
            while (cur < num_pos_train_samples)
            {
                if (y(train_pos_idx) == +1.0)
                {
                    x_train(cur) = train_pos_idx;
                    y_train(cur) = +1.0;
                    ++cur;
                }
                train_pos_idx = (train_pos_idx+1)%x.nr();
            }

            // load up our negative train samples
            while (cur < x_train.nr())
            {
                if (y(train_neg_idx) == -1.0)
                {
                    x_train(cur) = train_neg_idx;
                    y_train(cur) = -1.0;
                    ++cur;
                }
                train_neg_idx = (train_neg_idx+1)%x.nr();
            }

            try
            {
                // do the training and testing
                res += test_binary_decision_function(trainer.train(rowm(x,x_train),y_train),rowm(x,x_test),y_test);
            }
            catch (invalid_nu_error&)
            {
                // Just ignore the error in this case since we are going to
                // interpret an invalid nu value the same as generating a decision
                // function that miss-classifies everything.
            }

        } // for (long i = 0; i < folds; ++i)

        return res/(double)folds;
    }

    template <
        typename trainer_type,
        typename in_sample_vector_type,
        typename in_scalar_vector_type
        >
    const matrix<double, 1, 2, typename trainer_type::mem_manager_type>
    cross_validate_trainer (
        const trainer_type& trainer,
        const in_sample_vector_type& x,
        const in_scalar_vector_type& y,
        const long folds
    )
    {
        return cross_validate_trainer_impl(trainer,
                                           mat(x),
                                           mat(y),
                                           folds);
    }

// ----------------------------------------------------------------------------------------

    namespace prob_impl
    {
        template <typename vect_type>
        struct objective
        {
            objective (
                const vect_type& f_,
                const vect_type& t_
            ) : f(f_), t(t_) {}

            double operator() (
                const matrix<double,2,1>& x
            ) const
            {
                const double A = x(0);
                const double B = x(1);

                double res = 0;
                for (unsigned long i = 0; i < f.size(); ++i)
                {
                    const double val = A*f[i]+B;
                    // See the paper "A Note on Platt's Probabilistic Outputs for Support Vector Machines"
                    // for an explanation of why this code looks the way it does (rather than being the
                    // obvious formula).
                    if (val < 0)
                        res += (t[i] - 1)*val + std::log(1 + std::exp(val));
                    else
                        res += t[i]*val + std::log(1 + std::exp(-val));
                }

                return res;
            }

            const vect_type& f;
            const vect_type& t;
        };

        template <typename vect_type>
        struct der
        {
            der (
                const vect_type& f_,
                const vect_type& t_
            ) : f(f_), t(t_) {}

            matrix<double,2,1> operator() (
                const matrix<double,2,1>& x
            ) const
            {
                const double A = x(0);
                const double B = x(1);

                double derA = 0;
                double derB = 0;

                for (unsigned long i = 0; i < f.size(); ++i)
                {
                    const double val = A*f[i]+B;
                    double p;
                    // compute p = 1/(1+exp(val))
                    // but do so in a way that avoids numerical overflow.
                    if (val < 0)
                        p = 1.0/(1 + std::exp(val));
                    else
                        p = std::exp(-val)/(1 + std::exp(-val));

                    derA += f[i]*(t[i] - p);
                    derB +=      (t[i] - p);
                }

                matrix<double,2,1> res;
                res = derA, derB;
                return res;
            }

            const vect_type& f;
            const vect_type& t;
        };

        template <typename vect_type>
        struct hessian
        {
            hessian (
                const vect_type& f_,
                const vect_type& t_
            ) : f(f_), t(t_) {}

            matrix<double,2,2> operator() (
                const matrix<double,2,1>& x
            ) const
            {
                const double A = x(0);
                const double B = x(1);

                matrix<double,2,2> h;
                h = 0;

                for (unsigned long i = 0; i < f.size(); ++i)
                {
                    const double val = A*f[i]+B;
                    // compute pp = 1/(1+exp(val)) and
                    // compute pn = 1 - pp
                    // but do so in a way that avoids numerical overflow and catastrophic cancellation.
                    double pp, pn;
                    if (val < 0)
                    {
                        const double temp = std::exp(val);
                        pp = 1.0/(1 + temp);
                        pn = temp*pp;
                    }
                    else
                    {
                        const double temp = std::exp(-val);
                        pn = 1.0/(1 + temp);
                        pp = temp*pn;
                    }

                    h(0,0) += f[i]*f[i]*pp*pn;
                    const double temp2 = f[i]*pp*pn;
                    h(0,1) += temp2;
                    h(1,0) += temp2;
                    h(1,1) += pp*pn;
                }

                return h;
            }

            const vect_type& f;
            const vect_type& t;
        };
    }

// ----------------------------------------------------------------------------------------

    inline double platt_scale (
        const std::pair<double,double>& params,
        const double score
    )
    {
        return 1/(1 + std::exp(params.first*score + params.second));
    }

// ----------------------------------------------------------------------------------------

    template <typename T, typename alloc>
    std::pair<double,double> learn_platt_scaling (
        const std::vector<T,alloc>& scores,
        const std::vector<T,alloc>& labels
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(is_binary_classification_problem(scores,labels) == true,
            "\t std::pair<T,T> learn_platt_scaling()"
            << "\n\t invalid inputs were given to this function"
            << "\n\t scores.size(): " << scores.size()
            << "\n\t labels.size(): " << labels.size()
            << "\n\t is_binary_classification_problem(scores,labels): " << is_binary_classification_problem(scores,labels)
            );

        const T num_pos = sum(mat(labels)>0);
        const T num_neg = sum(mat(labels)<0);
        const T hi_target = (num_pos+1)/(num_pos+2);
        const T lo_target = 1.0/(num_neg+2);

        std::vector<T,alloc> target;
        for (unsigned long i = 0; i < labels.size(); ++i)
        {
            // if this was a positive example
            if (labels[i] == +1.0)
            {
                target.push_back(hi_target);
            }
            else if (labels[i] == -1.0)
            {
                target.push_back(lo_target);
            }
            else
            {
                throw dlib::error("invalid input labels to the learn_platt_scaling() function.");
            }
        }

        // Now find the maximum likelihood parameters of the sigmoid.

        prob_impl::objective<std::vector<T,alloc> > obj(scores, target);
        prob_impl::der<std::vector<T,alloc> > obj_der(scores, target);
        prob_impl::hessian<std::vector<T,alloc> > obj_hessian(scores, target);

        matrix<double,2,1> val;
        val = 0;
        find_min(newton_search_strategy(obj_hessian),
                 objective_delta_stop_strategy(),
                 obj,
                 obj_der,
                 val,
                 0);

        const double A = val(0);
        const double B = val(1);

        return std::make_pair(A,B);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename trainer_type,
        typename sample_vector_type,
        typename label_vector_type
        >
    const probabilistic_function<typename trainer_type::trained_function_type>
    train_probabilistic_decision_function (
        const trainer_type& trainer,
        const sample_vector_type& x,
        const label_vector_type& y,
        const long folds
    )
    {
        typedef typename sample_vector_type::value_type sample_type;
        typedef typename label_vector_type::value_type scalar_type;

        /*
            This function fits a sigmoid function to the output of the
            svm trained by svm_nu_trainer or a similar trainer.  The
            technique used is the one described in the papers:

                Probabilistic Outputs for Support Vector Machines and
                Comparisons to Regularized Likelihood Methods by
                John C. Platt.  March 26, 1999

                A Note on Platt's Probabilistic Outputs for Support Vector Machines
                by Hsuan-Tien Lin, Chih-Jen Lin, and Ruby C. Weng
        */

        // make sure requires clause is not broken
        DLIB_ASSERT(is_binary_classification_problem(x,y) == true &&
                    1 < folds && folds <= (long)x.size(),
            "\tprobabilistic_decision_function train_probabilistic_decision_function()"
            << "\n\t invalid inputs were given to this function"
            << "\n\t x.size(): " << x.size()
            << "\n\t y.size(): " << y.size()
            << "\n\t folds:  " << folds
            << "\n\t is_binary_classification_problem(x,y): " << is_binary_classification_problem(x,y)
            );

        // count the number of positive and negative examples
        const long num_pos = (long)sum(mat(y) > 0);
        const long num_neg = (long)sum(mat(y) < 0);

        // figure out how many positive and negative examples we will have in each fold
        const long num_pos_test_samples = num_pos/folds;
        const long num_pos_train_samples = num_pos - num_pos_test_samples;
        const long num_neg_test_samples = num_neg/folds;
        const long num_neg_train_samples = num_neg - num_neg_test_samples;

        typename trainer_type::trained_function_type d;
        std::vector<sample_type> x_test, x_train;
        std::vector<scalar_type> y_test, y_train;
        x_test.resize (num_pos_test_samples  + num_neg_test_samples);
        y_test.resize (num_pos_test_samples  + num_neg_test_samples);
        x_train.resize(num_pos_train_samples + num_neg_train_samples);
        y_train.resize(num_pos_train_samples + num_neg_train_samples);

        std::vector<scalar_type> out, out_label;

        long pos_idx = 0;
        long neg_idx = 0;

        for (long i = 0; i < folds; ++i)
        {
            long cur = 0;

            // load up our positive test samples
            while (cur < num_pos_test_samples)
            {
                if (y[pos_idx] == +1.0)
                {
                    x_test[cur] = x[pos_idx];
                    y_test[cur] = +1.0;
                    ++cur;
                }
                pos_idx = (pos_idx+1)%x.size();
            }

            // load up our negative test samples
            while (cur < (long)x_test.size())
            {
                if (y[neg_idx] == -1.0)
                {
                    x_test[cur] = x[neg_idx];
                    y_test[cur] = -1.0;
                    ++cur;
                }
                neg_idx = (neg_idx+1)%x.size();
            }

            // load the training data from the data following whatever we loaded
            // as the testing data
            long train_pos_idx = pos_idx;
            long train_neg_idx = neg_idx;
            cur = 0;

            // load up our positive train samples
            while (cur < num_pos_train_samples)
            {
                if (y[train_pos_idx] == +1.0)
                {
                    x_train[cur] = x[train_pos_idx];
                    y_train[cur] = +1.0;
                    ++cur;
                }
                train_pos_idx = (train_pos_idx+1)%x.size();
            }

            // load up our negative train samples
            while (cur < (long)x_train.size())
            {
                if (y[train_neg_idx] == -1.0)
                {
                    x_train[cur] = x[train_neg_idx];
                    y_train[cur] = -1.0;
                    ++cur;
                }
                train_neg_idx = (train_neg_idx+1)%x.size();
            }

            // do the training
            d = trainer.train (x_train,y_train);

            // now test this fold
            for (unsigned long i = 0; i < x_test.size(); ++i)
            {
                out.push_back(d(x_test[i]));
                out_label.push_back(y_test[i]);
            }

        } // for (long i = 0; i < folds; ++i)

        std::pair<double,double> params = learn_platt_scaling(out, out_label);

        const double A = params.first;
        const double B = params.second;

        return probabilistic_function<typename trainer_type::trained_function_type>( A, B, trainer.train(x,y) );
    }

// ----------------------------------------------------------------------------------------

    template <typename trainer_type>
    struct trainer_adapter_probabilistic
    {
        typedef probabilistic_function<typename trainer_type::trained_function_type> trained_function_type;

        const trainer_type trainer;
        const long folds;

        trainer_adapter_probabilistic (
            const trainer_type& trainer_,
            const long folds_
        ) : trainer(trainer_),folds(folds_) {}

        template <
            typename T,
            typename U
            >
        const trained_function_type train (
            const T& samples,
            const U& labels
        ) const
        {
            return train_probabilistic_decision_function(trainer, samples, labels, folds);
        }

    };

    template <
        typename trainer_type
        >
    trainer_adapter_probabilistic<trainer_type> probabilistic (
        const trainer_type& trainer,
        const long folds
    )
    {
        return trainer_adapter_probabilistic<trainer_type>(trainer,folds);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename U,
        typename V,
        typename rand_type
        >
    typename enable_if<is_matrix<T>,void>::type randomize_samples (
        T& t,
        U& u,
        V& v,
        rand_type& r
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(is_vector(t) && is_vector(u) && is_vector(v) && u.size() == t.size() &&
                    u.size() == v.size(),
            "\t randomize_samples(t,u,v)"
            << "\n\t invalid inputs were given to this function"
            << "\n\t t.size(): " << t.size()
            << "\n\t u.size(): " << u.size()
            << "\n\t v.size(): " << v.size()
            << "\n\t is_vector(t): " << is_vector(t)
            << "\n\t is_vector(u): " << is_vector(u)
            << "\n\t is_vector(v): " << is_vector(v)
            );

        long n = t.size()-1;
        while (n > 0)
        {
            // pick a random index to swap into t[n]
            const unsigned long idx = r.get_random_32bit_number()%(n+1);

            // swap our randomly selected index into the n position
            exchange(t(idx), t(n));
            exchange(u(idx), u(n));
            exchange(v(idx), v(n));

            --n;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename U,
        typename V,
        typename rand_type
        >
    typename disable_if<is_matrix<T>,void>::type randomize_samples (
        T& t,
        U& u,
        V& v,
        rand_type& r
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(u.size() == t.size() && u.size() == v.size(),
            "\t randomize_samples(t,u,v)"
            << "\n\t invalid inputs were given to this function"
            << "\n\t t.size(): " << t.size()
            << "\n\t u.size(): " << u.size()
            << "\n\t v.size(): " << v.size()
            );

        long n = t.size()-1;
        while (n > 0)
        {
            // pick a random index to swap into t[n]
            const unsigned long idx = r.get_random_32bit_number()%(n+1);

            // swap our randomly selected index into the n position
            exchange(t[idx], t[n]);
            exchange(u[idx], u[n]);
            exchange(v[idx], v[n]);

            --n;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename U,
        typename V
        >
    typename disable_if<is_rand<V>,void>::type randomize_samples (
        T& t,
        U& u,
        V& v
    )
    {
        rand r;
        randomize_samples(t,u,v,r);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename U,
        typename rand_type
        >
    typename enable_if_c<is_matrix<T>::value && is_rand<rand_type>::value,void>::type randomize_samples (
        T& t,
        U& u,
        rand_type& r
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(is_vector(t) && is_vector(u) && u.size() == t.size(),
            "\t randomize_samples(t,u)"
            << "\n\t invalid inputs were given to this function"
            << "\n\t t.size(): " << t.size()
            << "\n\t u.size(): " << u.size()
            << "\n\t is_vector(t): " << (is_vector(t)? "true" : "false")
            << "\n\t is_vector(u): " << (is_vector(u)? "true" : "false")
            );

        long n = t.size()-1;
        while (n > 0)
        {
            // pick a random index to swap into t[n]
            const unsigned long idx = r.get_random_32bit_number()%(n+1);

            // swap our randomly selected index into the n position
            exchange(t(idx), t(n));
            exchange(u(idx), u(n));

            --n;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename U,
        typename rand_type
        >
    typename disable_if_c<is_matrix<T>::value || !is_rand<rand_type>::value,void>::type randomize_samples (
        T& t,
        U& u,
        rand_type& r
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(u.size() == t.size(),
            "\t randomize_samples(t,u)"
            << "\n\t invalid inputs were given to this function"
            << "\n\t t.size(): " << t.size()
            << "\n\t u.size(): " << u.size()
            );

        long n = t.size()-1;
        while (n > 0)
        {
            // pick a random index to swap into t[n]
            const unsigned long idx = r.get_random_32bit_number()%(n+1);

            // swap our randomly selected index into the n position
            exchange(t[idx], t[n]);
            exchange(u[idx], u[n]);

            --n;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename U
        >
    typename disable_if<is_rand<U>,void>::type randomize_samples (
        T& t,
        U& u
    )
    {
        rand r;
        randomize_samples(t,u,r);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename rand_type
        >
    typename enable_if_c<is_matrix<T>::value && is_rand<rand_type>::value,void>::type randomize_samples (
        T& t,
        rand_type& r
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(is_vector(t),
            "\t randomize_samples(t)"
            << "\n\t invalid inputs were given to this function"
            << "\n\t is_vector(t): " << (is_vector(t)? "true" : "false")
            );

        long n = t.size()-1;
        while (n > 0)
        {
            // pick a random index to swap into t[n]
            const unsigned long idx = r.get_random_32bit_number()%(n+1);

            // swap our randomly selected index into the n position
            exchange(t(idx), t(n));

            --n;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        typename rand_type
        >
    typename disable_if_c<(is_matrix<T>::value==true)||(is_rand<rand_type>::value==false),void>::type randomize_samples (
        T& t,
        rand_type& r
    )
    {
        long n = t.size()-1;
        while (n > 0)
        {
            // pick a random index to swap into t[n]
            const unsigned long idx = r.get_random_32bit_number()%(n+1);

            // swap our randomly selected index into the n position
            exchange(t[idx], t[n]);

            --n;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    void randomize_samples (
        T& t
    )
    {
        rand r;
        randomize_samples(t,r);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SVm_


dlib C++ Library - svm_c_ekm_trainer.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SVM_C_EKm_TRAINER_Hh_
#define DLIB_SVM_C_EKm_TRAINER_Hh_

#include "../algs.h"
#include "function.h"
#include "kernel.h"
#include "empirical_kernel_map.h"
#include "svm_c_linear_trainer.h"
#include "svm_c_ekm_trainer_abstract.h"
#include "../statistics.h"
#include "../rand.h"
#include <vector>

namespace dlib
{
    template <
        typename K
        >
    class svm_c_ekm_trainer
    {

    public:
        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 decision_function<kernel_type> trained_function_type;

        svm_c_ekm_trainer (
        )
        {
            verbose = false;
            ekm_stale = true;

            initial_basis_size = 10;
            basis_size_increment = 50;
            max_basis_size = 300;
        }

        explicit svm_c_ekm_trainer (
            const scalar_type& C
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(C > 0,
                "\t svm_c_ekm_trainer::svm_c_ekm_trainer()"
                << "\n\t C must be greater than 0"
                << "\n\t C:    " << C
                << "\n\t this: " << this
                );

            ocas.set_c(C);
            verbose = false;
            ekm_stale = true;

            initial_basis_size = 10;
            basis_size_increment = 50;
            max_basis_size = 300;
        }

        void set_epsilon (
            scalar_type eps
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(eps > 0,
                "\t void svm_c_ekm_trainer::set_epsilon()"
                << "\n\t eps must be greater than 0"
                << "\n\t eps: " << eps
                << "\n\t this: " << this
                );

            ocas.set_epsilon(eps);
        }

        const scalar_type get_epsilon (
        ) const
        {
            return ocas.get_epsilon();
        }

        void set_max_iterations (
            unsigned long max_iter
        )
        {
            ocas.set_max_iterations(max_iter);
        }

        unsigned long get_max_iterations (
        )
        {
            return ocas.get_max_iterations();
        }

        void be_verbose (
        )
        {
            verbose = true;
            ocas.be_quiet();
        }

        void be_very_verbose (
        )
        {
            verbose = true;
            ocas.be_verbose();
        }

        void be_quiet (
        )
        {
            verbose = false;
            ocas.be_quiet();
        }

        void set_oca (
            const oca& item
        )
        {
            ocas.set_oca(item);
        }

        const oca get_oca (
        ) const
        {
            return ocas.get_oca();
        }

        const kernel_type get_kernel (
        ) const
        {
            return kern;
        }

        void set_kernel (
            const kernel_type& k
        )
        {
            kern = k;
            ekm_stale = true;
        }

        template <typename T>
        void set_basis (
            const T& basis_samples
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(basis_samples.size() > 0 && is_vector(mat(basis_samples)),
                "\tvoid svm_c_ekm_trainer::set_basis(basis_samples)"
                << "\n\t You have to give a non-empty set of basis_samples and it must be a vector"
                << "\n\t basis_samples.size():                       " << basis_samples.size()
                << "\n\t is_vector(mat(basis_samples)): " << is_vector(mat(basis_samples))
                << "\n\t this: " << this
                );

            basis = mat(basis_samples);
            ekm_stale = true;
        }

        bool basis_loaded(
        ) const
        {
            return (basis.size() != 0);
        }

        void clear_basis (
        )
        {
            basis.set_size(0);
            ekm.clear();
            ekm_stale = true;
        }

        unsigned long get_max_basis_size (
        ) const
        {
            return max_basis_size;
        }

        void set_max_basis_size (
            unsigned long max_basis_size_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(max_basis_size_ > 0,
                "\t void svm_c_ekm_trainer::set_max_basis_size()"
                << "\n\t max_basis_size_ must be greater than 0"
                << "\n\t max_basis_size_: " << max_basis_size_
                << "\n\t this:            " << this
                );

            max_basis_size = max_basis_size_;
            if (initial_basis_size > max_basis_size)
                initial_basis_size = max_basis_size;
        }

        unsigned long get_initial_basis_size (
        ) const
        {
            return initial_basis_size;
        }

        void set_initial_basis_size (
            unsigned long initial_basis_size_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(initial_basis_size_ > 0,
                "\t void svm_c_ekm_trainer::set_initial_basis_size()"
                << "\n\t initial_basis_size_ must be greater than 0"
                << "\n\t initial_basis_size_: " << initial_basis_size_
                << "\n\t this:                " << this
                );

            initial_basis_size = initial_basis_size_;

            if (initial_basis_size > max_basis_size)
                max_basis_size = initial_basis_size;
        }

        unsigned long get_basis_size_increment (
        ) const
        {
            return basis_size_increment;
        }

        void set_basis_size_increment (
            unsigned long basis_size_increment_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(basis_size_increment_ > 0,
                "\t void svm_c_ekm_trainer::set_basis_size_increment()"
                << "\n\t basis_size_increment_ must be greater than 0"
                << "\n\t basis_size_increment_: " << basis_size_increment_
                << "\n\t this:                  " << this
                );

            basis_size_increment = basis_size_increment_;
        }

        void set_c (
            scalar_type C
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(C > 0,
                "\t void svm_c_ekm_trainer::set_c()"
                << "\n\t C must be greater than 0"
                << "\n\t C:    " << C
                << "\n\t this: " << this
                );

            ocas.set_c(C);
        }

        const scalar_type get_c_class1 (
        ) const
        {
            return ocas.get_c_class1();
        }

        const scalar_type get_c_class2 (
        ) const
        {
            return ocas.get_c_class2();
        }

        void set_c_class1 (
            scalar_type C
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(C > 0,
                "\t void svm_c_ekm_trainer::set_c_class1()"
                << "\n\t C must be greater than 0"
                << "\n\t C:    " << C
                << "\n\t this: " << this
                );

            ocas.set_c_class1(C);
        }

        void set_c_class2 (
            scalar_type C
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(C > 0,
                "\t void svm_c_ekm_trainer::set_c_class2()"
                << "\n\t C must be greater than 0"
                << "\n\t C:    " << C
                << "\n\t this: " << this
                );

            ocas.set_c_class2(C);
        }

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y
        ) const
        {
            scalar_type obj;
            if (basis_loaded())
                return do_train_user_basis(mat(x),mat(y),obj);
            else
                return do_train_auto_basis(mat(x),mat(y),obj);
        }

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y,
            scalar_type& svm_objective
        ) const
        {
            if (basis_loaded())
                return do_train_user_basis(mat(x),mat(y),svm_objective);
            else
                return do_train_auto_basis(mat(x),mat(y),svm_objective);
        }

    private:

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> do_train_user_basis (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y,
            scalar_type& svm_objective
        ) const
        /*!
            requires
                - basis_loaded() == true
            ensures
                - trains an SVM with the user supplied basis
        !*/
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(is_binary_classification_problem(x,y) == true,
                "\t decision_function svm_c_ekm_trainer::train(x,y)"
                << "\n\t invalid inputs were given to this function"
                << "\n\t x.nr(): " << x.nr()
                << "\n\t y.nr(): " << y.nr()
                << "\n\t x.nc(): " << x.nc()
                << "\n\t y.nc(): " << y.nc()
                << "\n\t is_binary_classification_problem(x,y): " << is_binary_classification_problem(x,y)
                );

            if (ekm_stale)
            {
                ekm.load(kern, basis);
                ekm_stale = false;
            }

            // project all the samples with the ekm
            running_stats<scalar_type> rs;
            std::vector<matrix<scalar_type,0,1, mem_manager_type> > proj_samples;
            proj_samples.reserve(x.size());
            for (long i = 0; i < x.size(); ++i)
            {
                if (verbose)
                {
                    scalar_type err;
                    proj_samples.push_back(ekm.project(x(i), err));
                    rs.add(err);
                }
                else
                {
                    proj_samples.push_back(ekm.project(x(i)));
                }
            }

            if (verbose)
            {
                std::cout << "\nMean EKM projection error:                  " << rs.mean() << std::endl;
                std::cout << "Standard deviation of EKM projection error: " << rs.stddev() << std::endl;
            }

            // now do the training
            decision_function<linear_kernel<matrix<scalar_type,0,1, mem_manager_type> > > df;
            df = ocas.train(proj_samples, y, svm_objective);

            if (verbose)
            {
                std::cout << "Final svm objective: " << svm_objective << std::endl;
            }

            decision_function<kernel_type> final_df;
            final_df = ekm.convert_to_decision_function(df.basis_vectors(0));
            final_df.b = df.b;
            return final_df;
        }

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> do_train_auto_basis (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y,
            scalar_type& svm_objective
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(is_binary_classification_problem(x,y) == true,
                "\t decision_function svm_c_ekm_trainer::train(x,y)"
                << "\n\t invalid inputs were given to this function"
                << "\n\t x.nr(): " << x.nr()
                << "\n\t y.nr(): " << y.nr()
                << "\n\t x.nc(): " << x.nc()
                << "\n\t y.nc(): " << y.nc()
                << "\n\t is_binary_classification_problem(x,y): " << is_binary_classification_problem(x,y)
                );

            std::vector<matrix<scalar_type,0,1, mem_manager_type> > proj_samples(x.size());
            decision_function<linear_kernel<matrix<scalar_type,0,1, mem_manager_type> > > df;

            // we will use a linearly_independent_subset_finder to store our basis set.
            linearly_independent_subset_finder<kernel_type> lisf(get_kernel(), max_basis_size);

            dlib::rand rnd;

            // first pick the initial basis set randomly
            for (unsigned long i = 0; i < 10*initial_basis_size && lisf.size() < initial_basis_size; ++i)
            {
                lisf.add(x(rnd.get_random_32bit_number()%x.size()));
            }

            ekm.load(lisf);

            // first project all samples into the span of the current basis
            for (long i = 0; i < x.size(); ++i)
            {
                proj_samples[i] = ekm.project(x(i));
            }

            svm_c_linear_trainer<linear_kernel<matrix<scalar_type,0,1,mem_manager_type> > > trainer(ocas);

            const scalar_type min_epsilon = trainer.get_epsilon();
            // while we are determining what the basis set will be we are going to use a very
            // lose stopping condition.  We will tighten it back up before producing the
            // final decision_function.
            trainer.set_epsilon(0.2);

            scalar_type prev_svm_objective = std::numeric_limits<scalar_type>::max();

            empirical_kernel_map<kernel_type> prev_ekm;

            // This loop is where we try to generate a basis for SVM training.  We will
            // do this by repeatedly training the SVM and adding a few points which violate the
            // margin to the basis in each iteration.
            while (true)
            {
                // if the basis is already as big as it's going to get then just do the most
                // accurate training right now.
                if (lisf.size() == max_basis_size)
                    trainer.set_epsilon(min_epsilon);

                while (true)
                {
                    // now do the training.
                    df = trainer.train(proj_samples, y, svm_objective);

                    if (svm_objective < prev_svm_objective)
                        break;

                    // If the training didn't reduce the objective more than last time then
                    // try lowering the epsilon and doing it again.
                    if (trainer.get_epsilon() > min_epsilon)
                    {
                        trainer.set_epsilon(std::max(trainer.get_epsilon()*0.5, min_epsilon));
                        if (verbose)
                            std::cout << " *** Reducing epsilon to " << trainer.get_epsilon() << std::endl;
                    }
                    else
                        break;
                }

                if (verbose)
                {
                    std::cout << "svm objective: " << svm_objective << std::endl;
                    std::cout << "basis size: " << lisf.size() << std::endl;
                }

                // if we failed to make progress on this iteration then we are done
                if (svm_objective >= prev_svm_objective)
                    break;

                prev_svm_objective = svm_objective;

                // now add more elements to the basis
                unsigned long count = 0;
                for (unsigned long j = 0;
                     (j < 100*basis_size_increment) && (count < basis_size_increment) && (lisf.size() < max_basis_size);
                     ++j)
                {
                    // pick a random sample
                    const unsigned long idx = rnd.get_random_32bit_number()%x.size();
                    // If it is a margin violator then it is useful to add it into the basis set.
                    if (df(proj_samples[idx])*y(idx) < 1)
                    {
                        // Add the sample into the basis set if it is linearly independent of all the
                        // vectors already in the basis set.
                        if (lisf.add(x(idx)))
                        {
                            ++count;
                        }
                    }
                }
                // if we couldn't add any more basis vectors then stop
                if (count == 0)
                {
                    if (verbose)
                        std::cout << "Stopping, couldn't add more basis vectors." << std::endl;
                    break;
                }

                // Project all the samples into the span of our newly enlarged basis.  We will do this
                // using the special transformation in the EKM that lets us project from a smaller
                // basis set to a larger without needing to reevaluate kernel functions we have already
                // computed.
                ekm.swap(prev_ekm);
                ekm.load(lisf);
                projection_function<kernel_type> proj_part;
                matrix<double> prev_to_new;
                prev_ekm.get_transformation_to(ekm, prev_to_new, proj_part);

                matrix<scalar_type,0,1, mem_manager_type> temp;
                for (long i = 0; i < x.size(); ++i)
                {
                    // assign to temporary to avoid memory allocation that would result if we
                    // assigned this expression straight into proj_samples[i]
                    temp = prev_to_new*proj_samples[i] + proj_part(x(i));
                    proj_samples[i] = temp;

                }
            }

            // Reproject all the data samples using the final basis.  We could just use what we
            // already have but the recursive thing done above to compute the proj_samples
            // might have accumulated a little numerical error.  So lets just be safe.
            running_stats<scalar_type> rs, rs_margin;
            for (long i = 0; i < x.size(); ++i)
            {
                if (verbose)
                {
                    scalar_type err;
                    proj_samples[i] = ekm.project(x(i),err);
                    rs.add(err);
                    // if this point is within the margin
                    if (df(proj_samples[i])*y(i) < 1)
                        rs_margin.add(err);
                }
                else
                {
                    proj_samples[i] = ekm.project(x(i));
                }
            }

            // do the final training
            trainer.set_epsilon(min_epsilon);
            df = trainer.train(proj_samples, y, svm_objective);

            if (verbose)
            {
                std::cout << "\nMean EKM projection error:                  " << rs.mean() << std::endl;
                std::cout << "Standard deviation of EKM projection error: " << rs.stddev() << std::endl;
                std::cout << "Mean EKM projection error for margin violators:                  " << rs_margin.mean() << std::endl;
                std::cout << "Standard deviation of EKM projection error for margin violators: " << ((rs_margin.current_n()>1)?rs_margin.stddev():0) << std::endl;

                std::cout << "Final svm objective: " << svm_objective << std::endl;
            }

            decision_function<kernel_type> final_df;
            final_df = ekm.convert_to_decision_function(df.basis_vectors(0));
            final_df.b = df.b;

            // we don't need the ekm anymore so clear it out
            ekm.clear();

            return final_df;
        }

        /*!
            CONVENTION
                - if (ekm_stale) then
                    - kern or basis have changed since the last time
                      they were loaded into the ekm
        !*/

        svm_c_linear_trainer<linear_kernel<matrix<scalar_type,0,1,mem_manager_type> > > ocas;
        bool verbose;

        kernel_type kern;
        unsigned long max_basis_size;
        unsigned long basis_size_increment;
        unsigned long initial_basis_size;

        matrix<sample_type,0,1,mem_manager_type> basis;
        mutable empirical_kernel_map<kernel_type> ekm;
        mutable bool ekm_stale;

    };

}

#endif // DLIB_SVM_C_EKm_TRAINER_Hh_


dlib C++ Library - svm_c_linear_dcd_trainer.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SVm_C_LINEAR_DCD_TRAINER_Hh_
#define DLIB_SVm_C_LINEAR_DCD_TRAINER_Hh_

#include "svm_c_linear_dcd_trainer_abstract.h"
#include <cmath>
#include <limits>
#include "../matrix.h"
#include "../algs.h"
#include "../rand.h"

#include "function.h"
#include "kernel.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename K
        >
    class svm_c_linear_dcd_trainer
    {
    public:
        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 decision_function<kernel_type> trained_function_type;
        typedef typename decision_function<K>::sample_vector_type sample_vector_type;
        typedef typename decision_function<K>::scalar_vector_type scalar_vector_type;

        // You are getting a compiler error on this line because you supplied a non-linear
        // kernel to the svm_c_linear_dcd_trainer object.  You have to use one of the
        // linear kernels with this trainer.
        COMPILE_TIME_ASSERT((is_same_type<K, linear_kernel<sample_type> >::value ||
                             is_same_type<K, sparse_linear_kernel<sample_type> >::value ));

        svm_c_linear_dcd_trainer (
        ) :
            Cpos(1),
            Cneg(1),
            eps(0.1),
            max_iterations(10000),
            verbose(false),
            have_bias(true),
            last_weight_1(false),
            do_shrinking(true)
        {
        }

        explicit svm_c_linear_dcd_trainer (
            const scalar_type& C_
        ) :
            Cpos(C_),
            Cneg(C_),
            eps(0.1),
            max_iterations(10000),
            verbose(false),
            have_bias(true),
            last_weight_1(false),
            do_shrinking(true)
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(0 < C_,
                "\tsvm_c_trainer::svm_c_linear_dcd_trainer(kernel,C)"
                << "\n\t invalid inputs were given to this function"
                << "\n\t C_: " << C_
                );
        }

        bool includes_bias (
        ) const
        {
            return have_bias;
        }

        void include_bias (
            bool should_have_bias
        )
        {
            have_bias = should_have_bias;
        }

        bool forces_last_weight_to_1 (
        ) const
        {
            return last_weight_1;
        }

        void force_last_weight_to_1 (
            bool should_last_weight_be_1
        )
        {
            last_weight_1 = should_last_weight_be_1;
        }

        bool shrinking_enabled (
        ) const { return do_shrinking; }

        void enable_shrinking (
            bool enabled
        ) { do_shrinking = enabled; }

        void be_verbose (
        )
        {
            verbose = true;
        }

        void be_quiet (
        )
        {
            verbose = false;
        }

        void set_epsilon (
            scalar_type eps_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(eps_ > 0,
                "\tvoid svm_c_linear_dcd_trainer::set_epsilon(eps_)"
                << "\n\t invalid inputs were given to this function"
                << "\n\t eps_: " << eps_
                );
            eps = eps_;
        }

        const scalar_type get_epsilon (
        ) const
        {
            return eps;
        }

        const kernel_type& get_kernel (
        ) const
        {
            return kernel_type();
        }

        unsigned long get_max_iterations (
        ) const { return max_iterations; }

        void set_max_iterations (
            unsigned long max_iter
        )
        {
            max_iterations = max_iter;
        }

        void set_c (
            scalar_type C
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(C > 0,
                "\t void svm_c_linear_dcd_trainer::set_c()"
                << "\n\t C must be greater than 0"
                << "\n\t C:    " << C
                << "\n\t this: " << this
                );

            Cpos = C;
            Cneg = C;
        }

        const scalar_type get_c_class1 (
        ) const
        {
            return Cpos;
        }

        const scalar_type get_c_class2 (
        ) const
        {
            return Cneg;
        }

        void set_c_class1 (
            scalar_type C
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(C > 0,
                "\t void svm_c_linear_dcd_trainer::set_c_class1()"
                << "\n\t C must be greater than 0"
                << "\n\t C:    " << C
                << "\n\t this: " << this
                );

            Cpos = C;
        }

        void set_c_class2 (
            scalar_type C
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(C > 0,
                "\t void svm_c_linear_dcd_trainer::set_c_class2()"
                << "\n\t C must be greater than 0"
                << "\n\t C:    " << C
                << "\n\t this: " << this
                );

            Cneg = C;
        }

        class optimizer_state
        {
            friend class svm_c_linear_dcd_trainer;

        public:
            optimizer_state() : did_init(false) {}

        private:

            template <
                typename in_sample_vector_type
                >
            void init(
                const in_sample_vector_type& x,
                bool have_bias_,
                bool last_weight_1_
            )
            {
                const long new_dims = max_index_plus_one(x);
                long new_idx = 0;

                if (did_init)
                {
                    DLIB_CASSERT(have_bias_ == have_bias &&
                                 last_weight_1_ == last_weight_1,
                                "\t decision_function svm_c_linear_dcd_trainer::train(x,y,state)"
                                << "\n\t The given state object is invalid because the previous trainer was configured differently."
                                << "\n\t have_bias_:     " << have_bias_
                                << "\n\t have_bias:      " << have_bias
                                << "\n\t last_weight_1_: " << last_weight_1_
                                << "\n\t last_weight_1:  " << last_weight_1
                                 );

                    DLIB_CASSERT( new_dims >= dims,
                                "\t decision_function svm_c_linear_dcd_trainer::train(x,y,state)"
                                << "\n\t The given state object is invalid because the training data dimensions have shrunk."
                                << "\n\t new_dims:  " << new_dims
                                << "\n\t dims:      " << dims
                        );

                    DLIB_CASSERT( x.size() >= static_cast<long>(alpha.size()),
                                "\t decision_function svm_c_linear_dcd_trainer::train(x,y,state)"
                                << "\n\t The given state object is invalid because the training data has fewer samples than previously."
                                << "\n\t x.size():     " << x.size()
                                << "\n\t alpha.size(): " << alpha.size()
                        );

                    // make sure we amortize the cost of growing the alpha vector.
                    if (alpha.capacity() < static_cast<unsigned long>(x.size()))
                        alpha.reserve(x.size()*2);

                    new_idx = alpha.size();

                    // Make sure alpha has the same length as x.  So pad with extra zeros if
                    // necessary to make this happen.
                    alpha.resize(x.size(),0);

                    if (new_dims != dims)
                    {
                        // The only valid way the dimensions can be different here is if
                        // you are using a sparse vector type.  This is because we might
                        // have had training samples which just happened to not include all
                        // the features previously.  Therefore, max_index_plus_one() would
                        // have given too low of a result.  But for dense vectors it is
                        // definitely a user error if the dimensions don't match.

                        DLIB_CASSERT(is_matrix<sample_type>::value == false,
                                "\t decision_function svm_c_linear_dcd_trainer::train(x,y,state)"
                                << "\n\t The given state object is invalid because the training data dimensions have changed."
                                << "\n\t new_dims:  " << new_dims
                                << "\n\t dims:      " << dims
                            );

                        // extend w by the right number of elements
                        if (have_bias && !last_weight_1)
                        {
                            // Splice some zeros into the w vector so it will have the
                            // right length.  Here we are being careful to move the bias
                            // weight to the end of the resulting vector.
                            w = join_cols(join_cols(
                                    colm(w,0,dims),
                                    zeros_matrix<scalar_type>(new_dims-dims,1)),
                                    uniform_matrix<scalar_type>(1,1,w(dims))
                                    );
                        }
                        else
                        {
                            // Just concatenate the right number of zeros.
                            w = join_cols(w, zeros_matrix<scalar_type>(new_dims-dims,1));
                        }
                        dims = new_dims;
                    }

                }
                else
                {
                    did_init = true;
                    have_bias = have_bias_;
                    last_weight_1 = last_weight_1_;
                    dims = new_dims;

                    alpha.resize(x.size());

                    index.reserve(x.size());
                    Q.reserve(x.size());

                    if (have_bias && !last_weight_1)
                        w.set_size(dims+1);
                    else
                        w.set_size(dims);

                    w = 0;
                }

                for (long i = new_idx; i < x.size(); ++i)
                {
                    Q.push_back(length_squared(x(i)));

                    if (have_bias && !last_weight_1)
                    {
                        index.push_back(i);
                        Q.back() += 1;
                    }
                    else if (Q.back() != 0)
                    {
                        index.push_back(i);
                    }
                }

                if (last_weight_1)
                    w(dims-1) = 1;
            }

            template <typename T>
            typename enable_if<is_matrix<T>,scalar_type>::type length_squared (const T& x) const
            {
                if (!last_weight_1)
                {
                    return dlib::dot(x,x);
                }
                else
                {
                    // skip the last dimension
                    return dlib::dot(colm(x,0,x.size()-1),
                                     colm(x,0,x.size()-1));
                }

            }

            template <typename T>
            typename disable_if<is_matrix<T>,scalar_type>::type length_squared (const T& x) const
            {
                if (!last_weight_1)
                {
                    return dlib::dot(x,x);
                }
                else
                {
                    scalar_type temp = 0;
                    typename T::const_iterator i;
                    for (i = x.begin(); i != x.end(); ++i)
                    {
                        // skip the last dimension
                        if (static_cast<long>(i->first) < dims-1)
                            temp += i->second*i->second;
                    }
                    return temp;
                }
            }

            bool did_init;
            bool have_bias;
            bool last_weight_1;
            std::vector<scalar_type> alpha;
            scalar_vector_type w;
            std::vector<scalar_type> Q;
            std::vector<long> index;
            long dims;
            dlib::rand rnd;

        public:
            friend void serialize(const optimizer_state& item, std::ostream& out)
            {
                const int version = 1;
                dlib::serialize(version, out);
                dlib::serialize(item.did_init, out);
                dlib::serialize(item.have_bias, out);
                dlib::serialize(item.last_weight_1, out);
                dlib::serialize(item.alpha, out);
                dlib::serialize(item.w, out);
                dlib::serialize(item.Q, out);
                dlib::serialize(item.index, out);
                dlib::serialize(item.dims, out);
                dlib::serialize(item.rnd, out);
            }

            friend void deserialize(optimizer_state& item, std::istream& in)
            {
                int version = 0;
                dlib::deserialize(version, in);
                if (version != 1)
                {
                    throw dlib::serialization_error(
                        "Error while deserializing dlib::svm_c_linear_dcd_trainer::optimizer_state, unexpected version."
                        );
                }

                dlib::deserialize(item.did_init, in);
                dlib::deserialize(item.have_bias, in);
                dlib::deserialize(item.last_weight_1, in);
                dlib::deserialize(item.alpha, in);
                dlib::deserialize(item.w, in);
                dlib::deserialize(item.Q, in);
                dlib::deserialize(item.index, in);
                dlib::deserialize(item.dims, in);
                dlib::deserialize(item.rnd, in);
            }

        };

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y
        ) const
        {
            optimizer_state state;
            return do_train(mat(x), mat(y), state);
        }

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y,
            optimizer_state& state
        ) const
        {
            return do_train(mat(x), mat(y), state);
        }

    private:

    // ------------------------------------------------------------------------------------

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> do_train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y,
            optimizer_state& state
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(is_learning_problem(x,y) == true,
                "\t decision_function svm_c_linear_dcd_trainer::train(x,y)"
                << "\n\t invalid inputs were given to this function"
                << "\n\t x.size(): " << x.size()
                << "\n\t y.size(): " << y.size()
                << "\n\t is_learning_problem(x,y): " << is_learning_problem(x,y)
                );
#ifdef ENABLE_ASSERTS
            for (long i = 0; i < x.size(); ++i)
            {
                DLIB_ASSERT(y(i) == +1 || y(i) == -1,
                    "\t decision_function svm_c_linear_dcd_trainer::train(x,y)"
                    << "\n\t invalid inputs were given to this function"
                    << "\n\t y("<<i<<"): " << y(i)
                );
            }
#endif

            state.init(x,have_bias,last_weight_1);

            std::vector<scalar_type>& alpha = state.alpha;
            scalar_vector_type& w = state.w;
            std::vector<long>& index = state.index;
            const long dims = state.dims;

            unsigned long active_size = index.size();

            scalar_type PG_max_prev = std::numeric_limits<scalar_type>::infinity();
            scalar_type PG_min_prev = -std::numeric_limits<scalar_type>::infinity();

            // main loop
            for (unsigned long iter = 0; iter < max_iterations; ++iter)
            {
                scalar_type PG_max = -std::numeric_limits<scalar_type>::infinity();
                scalar_type PG_min = std::numeric_limits<scalar_type>::infinity();

                // randomly shuffle the indices
                for (unsigned long i = 0; i < active_size; ++i)
                {
                    // pick a random index >= i
                    const long j = i + state.rnd.get_random_32bit_number()%(active_size-i);
                    std::swap(index[i], index[j]);
                }

                // for all the active training samples
                for (unsigned long ii = 0; ii < active_size; ++ii)
                {
                    const long i = index[ii];

                    const scalar_type G = y(i)*dot(w, x(i)) - 1;
                    const scalar_type C = (y(i) > 0) ? Cpos : Cneg;

                    scalar_type PG = 0;
                    if (alpha[i] == 0)
                    {
                        if (G > PG_max_prev)
                        {
                            // shrink the active set of training examples
                            --active_size;
                            std::swap(index[ii], index[active_size]);
                            --ii;
                            continue;
                        }

                        if (G < 0)
                            PG = G;
                    }
                    else if (alpha[i] == C)
                    {
                        if (G < PG_min_prev)
                        {
                            // shrink the active set of training examples
                            --active_size;
                            std::swap(index[ii], index[active_size]);
                            --ii;
                            continue;
                        }

                        if (G > 0)
                            PG = G;
                    }
                    else
                    {
                        PG = G;
                    }

                    if (PG > PG_max)
                        PG_max = PG;
                    if (PG < PG_min)
                        PG_min = PG;

                    // if PG != 0
                    if (std::abs(PG) > 1e-12)
                    {
                        const scalar_type alpha_old = alpha[i];
                        alpha[i] = std::min(std::max(alpha[i] - G/state.Q[i], (scalar_type)0.0), C);
                        const scalar_type delta = (alpha[i]-alpha_old)*y(i);
                        add_to(w, x(i), delta);
                        if (have_bias && !last_weight_1)
                            w(w.size()-1) -= delta;

                        if (last_weight_1)
                            w(dims-1) = 1;
                    }

                }

                if (verbose)
                {
                    using namespace std;
                    cout << "gap:         " << PG_max - PG_min << endl;
                    cout << "active_size: " << active_size << endl;
                    cout << "iter:        " << iter << endl;
                    cout << endl;
                }

                if (PG_max - PG_min <= eps)
                {
                    // stop if we are within eps tolerance and the last iteration
                    // was over all the samples
                    if (active_size == index.size())
                        break;

                    // Turn of shrinking on the next iteration.  We will stop if the
                    // tolerance is still <= eps when shrinking is off.
                    active_size = index.size();
                    PG_max_prev = std::numeric_limits<scalar_type>::infinity();
                    PG_min_prev = -std::numeric_limits<scalar_type>::infinity();
                }
                else if (do_shrinking)
                {
                    PG_max_prev = PG_max;
                    PG_min_prev = PG_min;
                    if (PG_max_prev <= 0)
                        PG_max_prev = std::numeric_limits<scalar_type>::infinity();
                    if (PG_min_prev >= 0)
                        PG_min_prev = -std::numeric_limits<scalar_type>::infinity();
                }

            } // end of main optimization loop

            // put the solution into a decision function and then return it
            decision_function<kernel_type> df;
            if (have_bias && !last_weight_1)
                df.b = w(w.size()-1);
            else
                df.b = 0;

            df.basis_vectors.set_size(1);
            // Copy the plane normal into the output basis vector.  The output vector might
            // be a sparse vector container so we need to use this special kind of copy to
            // handle that case.
            assign(df.basis_vectors(0), colm(w, 0, dims));
            df.alpha.set_size(1);
            df.alpha(0) = 1;

            return df;
        }

        scalar_type dot (
            const scalar_vector_type& w,
            const sample_type& sample
        ) const
        {
            if (have_bias && !last_weight_1)
            {
                const long w_size_m1 = w.size()-1;
                return dlib::dot(colm(w,0,w_size_m1), sample) - w(w_size_m1);
            }
            else
            {
                return dlib::dot(w, sample);
            }
        }

    // ------------------------------------------------------------------------------------

        scalar_type Cpos;
        scalar_type Cneg;
        scalar_type eps;
        unsigned long max_iterations;
        bool verbose;
        bool have_bias; // having a bias means we pretend all x vectors have an extra element which is always -1.
        bool last_weight_1;
        bool do_shrinking;

    }; // end of class svm_c_linear_dcd_trainer

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SVm_C_LINEAR_DCD_TRAINER_Hh_


dlib C++ Library - svm_c_linear_trainer.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SVM_C_LiNEAR_TRAINER_Hh_
#define DLIB_SVM_C_LiNEAR_TRAINER_Hh_

#include "svm_c_linear_trainer_abstract.h"
#include "../algs.h"
#include "../optimization.h"
#include "../matrix.h"
#include "function.h"
#include "kernel.h"
#include <iostream>
#include <vector>
#include "sparse_vector.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_type,
        typename in_sample_vector_type,
        typename in_scalar_vector_type
        >
    class oca_problem_c_svm : public oca_problem<matrix_type >
    {
    public:
        /*
            This class is used as part of the implementation of the svm_c_linear_trainer
            defined towards the end of this file.

            The bias parameter is dealt with by imagining that each sample vector has -1
            as its last element.
        */

        typedef typename matrix_type::type scalar_type;

        oca_problem_c_svm(
            const scalar_type C_pos,
            const scalar_type C_neg,
            const in_sample_vector_type& samples_,
            const in_scalar_vector_type& labels_,
            const bool be_verbose_,
            const scalar_type eps_,
            const unsigned long max_iter,
            const unsigned long dims_
        ) :
            samples(samples_),
            labels(labels_),
            C(std::min(C_pos,C_neg)),
            Cpos(C_pos/C),
            Cneg(C_neg/C),
            be_verbose(be_verbose_),
            eps(eps_),
            max_iterations(max_iter),
            dims(dims_)
        {
            dot_prods.resize(samples.size());
            is_first_call = true;
        }

        virtual scalar_type get_c (
        ) const
        {
            return C;
        }

        virtual long get_num_dimensions (
        ) const
        {
            // plus 1 for the bias term
            return dims + 1;
        }

        virtual bool optimization_status (
            scalar_type current_objective_value,
            scalar_type current_error_gap,
            scalar_type current_risk_value,
            scalar_type current_risk_gap,
            unsigned long num_cutting_planes,
            unsigned long num_iterations
        ) const
        {
            if (be_verbose)
            {
                using namespace std;
                cout << "objective:     " << current_objective_value << endl;
                cout << "objective gap: " << current_error_gap << endl;
                cout << "risk:          " << current_risk_value << endl;
                cout << "risk gap:      " << current_risk_gap << endl;
                cout << "num planes:    " << num_cutting_planes << endl;
                cout << "iter:          " << num_iterations << endl;
                cout << endl;
            }

            if (num_iterations >= max_iterations)
                return true;

            if (current_risk_gap < eps)
                return true;

            return false;
        }

        virtual bool risk_has_lower_bound (
            scalar_type& lower_bound
        ) const
        {
            lower_bound = 0;
            return true;
        }

        virtual void get_risk (
            matrix_type& w,
            scalar_type& risk,
            matrix_type& subgradient
        ) const
        {
            line_search(w);

            subgradient.set_size(w.size(),1);
            subgradient = 0;
            risk = 0;

            // loop over all the samples and compute the risk and its subgradient at the current solution point w
            for (long i = 0; i < samples.size(); ++i)
            {
                // multiply current SVM output for the ith sample by its label
                const scalar_type df_val = labels(i)*dot_prods[i];

                if (labels(i) > 0)
                    risk += Cpos*std::max<scalar_type>(0.0,1 - df_val);
                else
                    risk += Cneg*std::max<scalar_type>(0.0,1 - df_val);

                if (df_val < 1)
                {
                    if (labels(i) > 0)
                    {
                        subtract_from(subgradient, samples(i), Cpos);

                        subgradient(subgradient.size()-1) += Cpos;
                    }
                    else
                    {
                        add_to(subgradient, samples(i), Cneg);

                        subgradient(subgradient.size()-1) -= Cneg;
                    }
                }
            }

            scalar_type scale = 1.0/samples.size();

            risk *= scale;
            subgradient = scale*subgradient;
        }

    private:

    // -----------------------------------------------------
    // -----------------------------------------------------

        void line_search (
            matrix_type& w
        ) const
        /*!
            ensures
                - does a line search to find a better w
                - for all i: #dot_prods[i] == dot(colm(#w,0,w.size()-1), samples(i)) - #w(w.size()-1)
        !*/
        {
            // The reason for using w_size_m1 and not just w.size()-1 is because
            // doing it this way avoids an inane warning from gcc that can occur in some cases.
            const long w_size_m1 = w.size()-1;
            for (long i = 0; i < samples.size(); ++i)
                dot_prods[i] = dot(colm(w,0,w_size_m1), samples(i)) - w(w_size_m1);

            if (is_first_call)
            {
                is_first_call = false;
                best_so_far = w;
                dot_prods_best = dot_prods;
            }
            else
            {
                // do line search going from best_so_far to w.  Store results in w.
                // Here we use the line search algorithm presented in section 3.1.1 of Franc and Sonnenburg.

                const scalar_type A0 = length_squared(best_so_far - w);
                const scalar_type BB0 = dot(best_so_far, w - best_so_far);

                const scalar_type scale_pos = (get_c()*Cpos)/samples.size();
                const scalar_type scale_neg = (get_c()*Cneg)/samples.size();

                ks.clear();
                ks.reserve(samples.size());

                scalar_type f0 = BB0;
                for (long i = 0; i < samples.size(); ++i)
                {
                    const scalar_type& scale = (labels(i)>0) ? scale_pos : scale_neg;

                    const scalar_type B = scale*labels(i) * ( dot_prods_best[i] - dot_prods[i]);
                    const scalar_type C = scale*(1 - labels(i)* dot_prods_best[i]);
                    // Note that if B is 0 then it doesn't matter what k is set to.  So 0 is fine.
                    scalar_type k = 0;
                    if (B != 0)
                        k = -C/B;

                    if (k > 0)
                        ks.push_back(helper(k, std::abs(B)));

                    if ( (B < 0 && k > 0) || (B > 0 && k <= 0) )
                        f0 += B;
                }

                scalar_type opt_k = 1;
                // ks.size() == 0 shouldn't happen but check anyway
                if (f0 >= 0 || ks.size() == 0)
                {
                    // Getting here means that we aren't searching in a descent direction.
                    // We could take a zero step but instead lets just assign w to the new best
                    // so far point just to make sure we don't get stuck coming back to this
                    // case over and over.  This might happen if we never move the best point
                    // seen so far.

                    // So we let opt_k be 1
                }
                else
                {
                    std::sort(ks.begin(), ks.end());

                    // figure out where f0 goes positive.
                    for (unsigned long i = 0; i < ks.size(); ++i)
                    {
                        f0 += ks[i].B;
                        if (f0 + A0*ks[i].k >= 0)
                        {
                            opt_k = ks[i].k;
                            break;
                        }
                    }

                }

                // Don't let the step size get too big.  Otherwise we might pick huge steps
                // over and over that don't improve the cutting plane approximation.
                if (opt_k > 1.0)
                {
                    opt_k = 1.0;
                }

                // take the step suggested by the line search
                best_so_far = (1-opt_k)*best_so_far + opt_k*w;

                // update best_so_far dot products
                for (unsigned long i = 0; i < dot_prods_best.size(); ++i)
                    dot_prods_best[i] = (1-opt_k)*dot_prods_best[i] + opt_k*dot_prods[i];

                const scalar_type mu = 0.1;
                // Make sure we always take a little bit of a step towards w regardless of what the
                // line search says to do.  We do this since it is possible that some steps won't
                // advance the best_so_far point. So this ensures we always make some progress each
                // iteration.
                w = (1-mu)*best_so_far + mu*w;

                // update dot products
                for (unsigned long i = 0; i < dot_prods.size(); ++i)
                    dot_prods[i] = (1-mu)*dot_prods_best[i] + mu*dot_prods[i];
            }
        }

        struct helper
        {
            helper(scalar_type k_, scalar_type B_) : k(k_), B(B_) {}
            scalar_type k;
            scalar_type B;

            bool operator< (const helper& item) const { return k < item.k; }
        };

        mutable std::vector<helper> ks;

        mutable bool is_first_call;
        mutable std::vector<scalar_type> dot_prods;

        mutable matrix_type best_so_far;  // best w seen so far
        mutable std::vector<scalar_type> dot_prods_best; // dot products between best_so_far and samples

        const in_sample_vector_type& samples;
        const in_scalar_vector_type& labels;
        const scalar_type C;
        const scalar_type Cpos;
        const scalar_type Cneg;

        const bool be_verbose;
        const scalar_type eps;
        const unsigned long max_iterations;
        const unsigned long dims;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_type,
        typename in_sample_vector_type,
        typename in_scalar_vector_type,
        typename scalar_type
        >
    oca_problem_c_svm<matrix_type, in_sample_vector_type, in_scalar_vector_type> make_oca_problem_c_svm (
        const scalar_type C_pos,
        const scalar_type C_neg,
        const in_sample_vector_type& samples,
        const in_scalar_vector_type& labels,
        const bool be_verbose,
        const scalar_type eps,
        const unsigned long max_iterations,
        const unsigned long dims
    )
    {
        return oca_problem_c_svm<matrix_type, in_sample_vector_type, in_scalar_vector_type>(
            C_pos, C_neg, samples, labels, be_verbose, eps, max_iterations, dims);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename K
        >
    class svm_c_linear_trainer
    {

    public:
        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 decision_function<kernel_type> trained_function_type;

        // You are getting a compiler error on this line because you supplied a non-linear kernel
        // to the svm_c_linear_trainer object.  You have to use one of the linear kernels with this
        // trainer.
        COMPILE_TIME_ASSERT((is_same_type<K, linear_kernel<sample_type> >::value ||
                             is_same_type<K, sparse_linear_kernel<sample_type> >::value ));

        svm_c_linear_trainer (
        )
        {
            Cpos = 1;
            Cneg = 1;
            verbose = false;
            eps = 0.001;
            max_iterations = 10000;
            learn_nonnegative_weights = false;
            last_weight_1 = false;
        }

        explicit svm_c_linear_trainer (
            const scalar_type& C
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(C > 0,
                "\t svm_c_linear_trainer::svm_c_linear_trainer()"
                << "\n\t C must be greater than 0"
                << "\n\t C:    " << C
                << "\n\t this: " << this
                );

            Cpos = C;
            Cneg = C;
            verbose = false;
            eps = 0.001;
            max_iterations = 10000;
            learn_nonnegative_weights = false;
            last_weight_1 = false;
        }

        void set_epsilon (
            scalar_type eps_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(eps_ > 0,
                "\t void svm_c_linear_trainer::set_epsilon()"
                << "\n\t eps_ must be greater than 0"
                << "\n\t eps_: " << eps_
                << "\n\t this: " << this
                );

            eps = eps_;
        }

        const scalar_type get_epsilon (
        ) const { return eps; }

        unsigned long get_max_iterations (
        ) const { return max_iterations; }

        void set_max_iterations (
            unsigned long max_iter
        )
        {
            max_iterations = max_iter;
        }

        void be_verbose (
        )
        {
            verbose = true;
        }

        void be_quiet (
        )
        {
            verbose = false;
        }

        void set_oca (
            const oca& item
        )
        {
            solver = item;
        }

        const oca get_oca (
        ) const
        {
            return solver;
        }

        const kernel_type get_kernel (
        ) const
        {
            return kernel_type();
        }

        bool learns_nonnegative_weights (
        ) const { return learn_nonnegative_weights; }

        void set_learns_nonnegative_weights (
            bool value
        )
        {
            learn_nonnegative_weights = value;
            if (learn_nonnegative_weights)
                prior.set_size(0);
        }

        bool forces_last_weight_to_1 (
        ) const
        {
            return last_weight_1;
        }

        void force_last_weight_to_1 (
            bool should_last_weight_be_1
        )
        {
            last_weight_1 = should_last_weight_be_1;
            if (last_weight_1)
                prior.set_size(0);
        }

        void set_prior (
            const trained_function_type& prior_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(prior_.basis_vectors.size() == 1 &&
                        prior_.alpha(0) == 1,
                "\t void svm_c_linear_trainer::set_prior()"
                << "\n\t The supplied prior could not have been created by this object's train() method."
                << "\n\t prior_.basis_vectors.size(): " << prior_.basis_vectors.size()
                << "\n\t prior_.alpha(0):             " << prior_.alpha(0)
                << "\n\t this: " << this
                );

            prior = sparse_to_dense(prior_.basis_vectors(0));
            prior_b = prior_.b;
            learn_nonnegative_weights = false;
            last_weight_1 = false;
        }

        bool has_prior (
        ) const
        {
            return prior.size() != 0;
        }

        void set_c (
            scalar_type C
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(C > 0,
                "\t void svm_c_linear_trainer::set_c()"
                << "\n\t C must be greater than 0"
                << "\n\t C:    " << C
                << "\n\t this: " << this
                );

            Cpos = C;
            Cneg = C;
        }

        const scalar_type get_c_class1 (
        ) const
        {
            return Cpos;
        }

        const scalar_type get_c_class2 (
        ) const
        {
            return Cneg;
        }

        void set_c_class1 (
            scalar_type C
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(C > 0,
                "\t void svm_c_linear_trainer::set_c_class1()"
                << "\n\t C must be greater than 0"
                << "\n\t C:    " << C
                << "\n\t this: " << this
                );

            Cpos = C;
        }

        void set_c_class2 (
            scalar_type C
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(C > 0,
                "\t void svm_c_linear_trainer::set_c_class2()"
                << "\n\t C must be greater than 0"
                << "\n\t C:    " << C
                << "\n\t this: " << this
                );

            Cneg = C;
        }

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y
        ) const
        {
            scalar_type obj;
            return do_train(mat(x),mat(y),obj);
        }

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y,
            scalar_type& svm_objective
        ) const
        {
            return do_train(mat(x),mat(y),svm_objective);
        }

    private:

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> do_train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y,
            scalar_type& svm_objective
        ) const
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(is_learning_problem(x,y) == true,
                "\t decision_function svm_c_linear_trainer::train(x,y)"
                << "\n\t invalid inputs were given to this function"
                << "\n\t x.nr(): " << x.nr()
                << "\n\t y.nr(): " << y.nr()
                << "\n\t x.nc(): " << x.nc()
                << "\n\t y.nc(): " << y.nc()
                << "\n\t is_learning_problem(x,y): " << is_learning_problem(x,y)
                );
#ifdef ENABLE_ASSERTS
            for (long i = 0; i < x.size(); ++i)
            {
                DLIB_ASSERT(y(i) == +1 || y(i) == -1,
                    "\t decision_function svm_c_linear_trainer::train(x,y)"
                    << "\n\t invalid inputs were given to this function"
                    << "\n\t y("<<i<<"): " << y(i)
                );
            }
#endif

            typedef matrix<scalar_type,0,1> w_type;
            w_type w;

            const unsigned long num_dims = max_index_plus_one(x);

            unsigned long num_nonnegative = 0;
            if (learn_nonnegative_weights)
            {
                num_nonnegative = num_dims;
            }

            unsigned long force_weight_1_idx = std::numeric_limits<unsigned long>::max();
            if (last_weight_1)
            {
                force_weight_1_idx = num_dims-1;
            }

            if (has_prior())
            {
                if (is_matrix<sample_type>::value)
                {
                    // make sure requires clause is not broken
                    DLIB_CASSERT(num_dims == (unsigned long)prior.size(),
                        "\t decision_function svm_c_linear_trainer::train(x,y)"
                        << "\n\t The dimension of the training vectors must match the dimension of\n"
                        << "\n\t those used to create the prior."
                        << "\n\t num_dims:     " << num_dims
                        << "\n\t prior.size(): " << prior.size()
                    );
                }
                const unsigned long dims = std::max(num_dims, (unsigned long)prior.size());
                // In the case of sparse sample vectors, it is possible that the input
                // vector dimensionality is larger than the prior vector dimensionality.
                // We need to check for this case and pad prior with zeros if it is the
                // case.
                matrix<scalar_type,0,1> prior_temp = join_cols(join_cols(prior,
                                                                         zeros_matrix<scalar_type>(dims-prior.size(),1)),
                                                                         mat(prior_b));

                svm_objective = solver(
                    make_oca_problem_c_svm<w_type>(Cpos, Cneg, x, y, verbose, eps, max_iterations, dims),
                    w,
                    prior_temp);
            }
            else
            {
                svm_objective = solver(
                    make_oca_problem_c_svm<w_type>(Cpos, Cneg, x, y, verbose, eps, max_iterations, num_dims),
                    w,
                    num_nonnegative,
                    force_weight_1_idx);
            }

            // put the solution into a decision function and then return it
            decision_function<kernel_type> df;
            df.b = static_cast<scalar_type>(w(w.size()-1));
            df.basis_vectors.set_size(1);
            // Copy the plane normal into the output basis vector.  The output vector might be a
            // sparse vector container so we need to use this special kind of copy to handle that case.
            // As an aside, the reason for using max_index_plus_one() and not just w.size()-1 is because
            // doing it this way avoids an inane warning from gcc that can occur in some cases.
            const long out_size = max_index_plus_one(x);
            assign(df.basis_vectors(0), matrix_cast<scalar_type>(colm(w, 0, out_size)));
            df.alpha.set_size(1);
            df.alpha(0) = 1;

            return df;
        }

        scalar_type Cpos;
        scalar_type Cneg;
        oca solver;
        scalar_type eps;
        bool verbose;
        unsigned long max_iterations;
        bool learn_nonnegative_weights;
        bool last_weight_1;
        matrix<scalar_type,0,1> prior;
        scalar_type prior_b;
    };

// ----------------------------------------------------------------------------------------

}

// ----------------------------------------------------------------------------------------

#endif // DLIB_SVM_C_LiNEAR_TRAINER_Hh_


dlib C++ Library - svm_c_trainer.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SVm_C_TRAINER_Hh_
#define DLIB_SVm_C_TRAINER_Hh_

//#include "local/make_label_kernel_matrix.h"

#include "svm_c_trainer_abstract.h"
#include <cmath>
#include <limits>
#include <sstream>
#include "../matrix.h"
#include "../algs.h"

#include "function.h"
#include "kernel.h"
#include "../optimization/optimization_solve_qp3_using_smo.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename K
        >
    class svm_c_trainer
    {
    public:
        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 decision_function<kernel_type> trained_function_type;

        svm_c_trainer (
        ) :
            Cpos(1),
            Cneg(1),
            cache_size(200),
            eps(0.001)
        {
        }

        svm_c_trainer (
            const kernel_type& kernel_,
            const scalar_type& C_
        ) :
            kernel_function(kernel_),
            Cpos(C_),
            Cneg(C_),
            cache_size(200),
            eps(0.001)
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(0 < C_,
                "\tsvm_c_trainer::svm_c_trainer(kernel,C)"
                << "\n\t invalid inputs were given to this function"
                << "\n\t C_: " << C_
                );
        }

        void set_cache_size (
            long cache_size_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(cache_size_ > 0,
                "\tvoid svm_c_trainer::set_cache_size(cache_size_)"
                << "\n\t invalid inputs were given to this function"
                << "\n\t cache_size: " << cache_size_
                );
            cache_size = cache_size_;
        }

        long get_cache_size (
        ) const
        {
            return cache_size;
        }

        void set_epsilon (
            scalar_type eps_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(eps_ > 0,
                "\tvoid svm_c_trainer::set_epsilon(eps_)"
                << "\n\t invalid inputs were given to this function"
                << "\n\t eps_: " << eps_
                );
            eps = eps_;
        }

        const scalar_type get_epsilon (
        ) const
        {
            return eps;
        }

        void set_kernel (
            const kernel_type& k
        )
        {
            kernel_function = k;
        }

        const kernel_type& get_kernel (
        ) const
        {
            return kernel_function;
        }

        void set_c (
            scalar_type C
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(C > 0,
                "\t void svm_c_trainer::set_c()"
                << "\n\t C must be greater than 0"
                << "\n\t C:    " << C
                << "\n\t this: " << this
                );

            Cpos = C;
            Cneg = C;
        }

        const scalar_type get_c_class1 (
        ) const
        {
            return Cpos;
        }

        const scalar_type get_c_class2 (
        ) const
        {
            return Cneg;
        }

        void set_c_class1 (
            scalar_type C
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(C > 0,
                "\t void svm_c_trainer::set_c_class1()"
                << "\n\t C must be greater than 0"
                << "\n\t C:    " << C
                << "\n\t this: " << this
                );

            Cpos = C;
        }

        void set_c_class2 (
            scalar_type C
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(C > 0,
                "\t void svm_c_trainer::set_c_class2()"
                << "\n\t C must be greater than 0"
                << "\n\t C:    " << C
                << "\n\t this: " << this
                );

            Cneg = C;
        }

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y
        ) const
        {
            return do_train(mat(x), mat(y));
        }

        void swap (
            svm_c_trainer& item
        )
        {
            exchange(kernel_function, item.kernel_function);
            exchange(Cpos,            item.Cpos);
            exchange(Cneg,            item.Cneg);
            exchange(cache_size,      item.cache_size);
            exchange(eps,             item.eps);
        }

    private:

    // ------------------------------------------------------------------------------------

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> do_train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y
        ) const
        {
            typedef typename K::scalar_type scalar_type;
            typedef typename decision_function<K>::sample_vector_type sample_vector_type;
            typedef typename decision_function<K>::scalar_vector_type scalar_vector_type;

            // make sure requires clause is not broken
            DLIB_ASSERT(is_binary_classification_problem(x,y) == true,
                "\tdecision_function svm_c_trainer::train(x,y)"
                << "\n\t invalid inputs were given to this function"
                << "\n\t x.nr(): " << x.nr()
                << "\n\t y.nr(): " << y.nr()
                << "\n\t x.nc(): " << x.nc()
                << "\n\t y.nc(): " << y.nc()
                << "\n\t is_binary_classification_problem(x,y): " << is_binary_classification_problem(x,y)
                );

            scalar_vector_type alpha;

            solve_qp3_using_smo<scalar_vector_type> solver;

            solver(symmetric_matrix_cache<float>((diagm(y)*kernel_matrix(kernel_function,x)*diagm(y)), cache_size),
            //solver(symmetric_matrix_cache<float>(make_label_kernel_matrix(kernel_matrix(kernel_function,x),y), cache_size),
                   uniform_matrix<scalar_type>(y.size(),1,-1),
                   y,
                   0,
                   Cpos,
                   Cneg,
                   alpha,
                   eps);

            scalar_type b;
            calculate_b(y,alpha,solver.get_gradient(),Cpos,Cneg,b);
            alpha = pointwise_multiply(alpha,y);

            // count the number of support vectors
            const long sv_count = (long)sum(alpha != 0);

            scalar_vector_type sv_alpha;
            sample_vector_type support_vectors;

            // size these column vectors so that they have an entry for each support vector
            sv_alpha.set_size(sv_count);
            support_vectors.set_size(sv_count);

            // load the support vectors and their alpha values into these new column matrices
            long idx = 0;
            for (long i = 0; i < alpha.nr(); ++i)
            {
                if (alpha(i) != 0)
                {
                    sv_alpha(idx) = alpha(i);
                    support_vectors(idx) = x(i);
                    ++idx;
                }
            }

            // now return the decision function
            return decision_function<K> (sv_alpha, b, kernel_function, support_vectors);
        }

    // ------------------------------------------------------------------------------------

        template <
            typename scalar_vector_type,
            typename scalar_vector_type2
            >
        void calculate_b(
            const scalar_vector_type2& y,
            const scalar_vector_type& alpha,
            const scalar_vector_type& df,
            const scalar_type& Cpos,
            const scalar_type& Cneg,
            scalar_type& b
        ) const
        {
            using namespace std;
            long num_free = 0;
            scalar_type sum_free = 0;

            scalar_type upper_bound = -numeric_limits<scalar_type>::infinity();
            scalar_type lower_bound = numeric_limits<scalar_type>::infinity();

            for(long i = 0; i < alpha.nr(); ++i)
            {
                if(y(i) == 1)
                {
                    if(alpha(i) == Cpos)
                    {
                        if (df(i) > upper_bound)
                            upper_bound = df(i);
                    }
                    else if(alpha(i) == 0)
                    {
                        if (df(i) < lower_bound)
                            lower_bound = df(i);
                    }
                    else
                    {
                        ++num_free;
                        sum_free += df(i);
                    }
                }
                else
                {
                    if(alpha(i) == Cneg)
                    {
                        if (-df(i) < lower_bound)
                            lower_bound = -df(i);
                    }
                    else if(alpha(i) == 0)
                    {
                        if (-df(i) > upper_bound)
                            upper_bound = -df(i);
                    }
                    else
                    {
                        ++num_free;
                        sum_free -= df(i);
                    }
                }
            }

            if(num_free > 0)
                b = sum_free/num_free;
            else
                b = (upper_bound+lower_bound)/2;
        }

    // ------------------------------------------------------------------------------------

        kernel_type kernel_function;
        scalar_type Cpos;
        scalar_type Cneg;
        long cache_size;
        scalar_type eps;
    }; // end of class svm_c_trainer

// ----------------------------------------------------------------------------------------

    template <typename K>
    void swap (
        svm_c_trainer<K>& a,
        svm_c_trainer<K>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SVm_C_TRAINER_Hh_


dlib C++ Library - svm_nu_trainer.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SVm_NU_TRAINER_Hh_
#define DLIB_SVm_NU_TRAINER_Hh_

//#include "local/make_label_kernel_matrix.h"

#include "svm_nu_trainer_abstract.h"
#include <cmath>
#include <limits>
#include <sstream>
#include "../matrix.h"
#include "../algs.h"
#include "../serialize.h"

#include "function.h"
#include "kernel.h"
#include "../optimization/optimization_solve_qp2_using_smo.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename K
        >
    class svm_nu_trainer
    {
    public:
        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 decision_function<kernel_type> trained_function_type;

        svm_nu_trainer (
        ) :
            nu(0.1),
            cache_size(200),
            eps(0.001)
        {
        }

        svm_nu_trainer (
            const kernel_type& kernel_,
            const scalar_type& nu_
        ) :
            kernel_function(kernel_),
            nu(nu_),
            cache_size(200),
            eps(0.001)
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(0 < nu && nu <= 1,
                "\tsvm_nu_trainer::svm_nu_trainer(kernel,nu)"
                << "\n\t invalid inputs were given to this function"
                << "\n\t nu: " << nu
                );
        }

        void set_cache_size (
            long cache_size_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(cache_size_ > 0,
                "\tvoid svm_nu_trainer::set_cache_size(cache_size_)"
                << "\n\t invalid inputs were given to this function"
                << "\n\t cache_size: " << cache_size_
                );
            cache_size = cache_size_;
        }

        long get_cache_size (
        ) const
        {
            return cache_size;
        }

        void set_epsilon (
            scalar_type eps_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(eps_ > 0,
                "\tvoid svm_nu_trainer::set_epsilon(eps_)"
                << "\n\t invalid inputs were given to this function"
                << "\n\t eps: " << eps_
                );
            eps = eps_;
        }

        const scalar_type get_epsilon (
        ) const
        {
            return eps;
        }

        void set_kernel (
            const kernel_type& k
        )
        {
            kernel_function = k;
        }

        const kernel_type& get_kernel (
        ) const
        {
            return kernel_function;
        }

        void set_nu (
            scalar_type nu_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(0 < nu_ && nu_ <= 1,
                "\tvoid svm_nu_trainer::set_nu(nu_)"
                << "\n\t invalid inputs were given to this function"
                << "\n\t nu: " << nu_
                );
            nu = nu_;
        }

        const scalar_type get_nu (
        ) const
        {
            return nu;
        }

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y
        ) const
        {
            return do_train(mat(x), mat(y));
        }

        void swap (
            svm_nu_trainer& item
        )
        {
            exchange(kernel_function, item.kernel_function);
            exchange(nu,              item.nu);
            exchange(cache_size,      item.cache_size);
            exchange(eps,             item.eps);
        }

    private:

    // ------------------------------------------------------------------------------------

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> do_train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y
        ) const
        {
            typedef typename K::scalar_type scalar_type;
            typedef typename decision_function<K>::sample_vector_type sample_vector_type;
            typedef typename decision_function<K>::scalar_vector_type scalar_vector_type;

            // make sure requires clause is not broken
            DLIB_ASSERT(is_binary_classification_problem(x,y) == true,
                "\tdecision_function svm_nu_trainer::train(x,y)"
                << "\n\t invalid inputs were given to this function"
                << "\n\t x.nr(): " << x.nr()
                << "\n\t y.nr(): " << y.nr()
                << "\n\t x.nc(): " << x.nc()
                << "\n\t y.nc(): " << y.nc()
                << "\n\t is_binary_classification_problem(x,y): " << is_binary_classification_problem(x,y)
                );

            scalar_vector_type alpha;

            solve_qp2_using_smo<scalar_vector_type> solver;

            solver(symmetric_matrix_cache<float>((diagm(y)*kernel_matrix(kernel_function,x)*diagm(y)), cache_size),
            //solver(symmetric_matrix_cache<float>(make_label_kernel_matrix(kernel_matrix(kernel_function,x),y), cache_size),
                   y,
                   nu,
                   alpha,
                   eps);

            scalar_type rho, b;
            calculate_rho_and_b(y,alpha,solver.get_gradient(),rho,b);
            alpha = pointwise_multiply(alpha,y)/rho;

            // count the number of support vectors
            const long sv_count = (long)sum(alpha != 0);

            scalar_vector_type sv_alpha;
            sample_vector_type support_vectors;

            // size these column vectors so that they have an entry for each support vector
            sv_alpha.set_size(sv_count);
            support_vectors.set_size(sv_count);

            // load the support vectors and their alpha values into these new column matrices
            long idx = 0;
            for (long i = 0; i < alpha.nr(); ++i)
            {
                if (alpha(i) != 0)
                {
                    sv_alpha(idx) = alpha(i);
                    support_vectors(idx) = x(i);
                    ++idx;
                }
            }

            // now return the decision function
            return decision_function<K> (sv_alpha, b, kernel_function, support_vectors);
        }

    // ------------------------------------------------------------------------------------

        template <
            typename scalar_vector_type,
            typename scalar_vector_type2,
            typename scalar_type
            >
        void calculate_rho_and_b(
            const scalar_vector_type2& y,
            const scalar_vector_type& alpha,
            const scalar_vector_type& df,
            scalar_type& rho,
            scalar_type& b
        ) const
        {
            using namespace std;
            long num_p_free = 0;
            long num_n_free = 0;
            scalar_type sum_p_free = 0;
            scalar_type sum_n_free = 0;

            scalar_type upper_bound_p = -numeric_limits<scalar_type>::infinity();
            scalar_type upper_bound_n = -numeric_limits<scalar_type>::infinity();
            scalar_type lower_bound_p = numeric_limits<scalar_type>::infinity();
            scalar_type lower_bound_n = numeric_limits<scalar_type>::infinity();

            for(long i = 0; i < alpha.nr(); ++i)
            {
                if(y(i) == 1)
                {
                    if(alpha(i) == 1)
                    {
                        if (df(i) > upper_bound_p)
                            upper_bound_p = df(i);
                    }
                    else if(alpha(i) == 0)
                    {
                        if (df(i) < lower_bound_p)
                            lower_bound_p = df(i);
                    }
                    else
                    {
                        ++num_p_free;
                        sum_p_free += df(i);
                    }
                }
                else
                {
                    if(alpha(i) == 1)
                    {
                        if (df(i) > upper_bound_n)
                            upper_bound_n = df(i);
                    }
                    else if(alpha(i) == 0)
                    {
                        if (df(i) < lower_bound_n)
                            lower_bound_n = df(i);
                    }
                    else
                    {
                        ++num_n_free;
                        sum_n_free += df(i);
                    }
                }
            }

            scalar_type r1,r2;
            if(num_p_free > 0)
                r1 = sum_p_free/num_p_free;
            else
                r1 = (upper_bound_p+lower_bound_p)/2;

            if(num_n_free > 0)
                r2 = sum_n_free/num_n_free;
            else
                r2 = (upper_bound_n+lower_bound_n)/2;

            rho = (r1+r2)/2;
            b = (r1-r2)/2/rho;
        }

    // ------------------------------------------------------------------------------------

        kernel_type kernel_function;
        scalar_type nu;
        long cache_size;
        scalar_type eps;
    }; // end of class svm_nu_trainer

// ----------------------------------------------------------------------------------------

    template <typename K>
    void swap (
        svm_nu_trainer<K>& a,
        svm_nu_trainer<K>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SVm_NU_TRAINER_Hh_


dlib C++ Library - svm_one_class_trainer.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SVm_ONE_CLASS_TRAINER_Hh_
#define DLIB_SVm_ONE_CLASS_TRAINER_Hh_

#include "svm_one_class_trainer_abstract.h"
#include <cmath>
#include <limits>
#include <sstream>
#include "../matrix.h"
#include "../algs.h"

#include "function.h"
#include "kernel.h"
#include "../optimization/optimization_solve_qp3_using_smo.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename K
        >
    class svm_one_class_trainer
    {
    public:
        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 decision_function<kernel_type> trained_function_type;

        svm_one_class_trainer (
        ) :
            nu(0.1),
            cache_size(200),
            eps(0.001)
        {
        }

        svm_one_class_trainer (
            const kernel_type& kernel_,
            const scalar_type& nu_
        ) :
            kernel_function(kernel_),
            nu(nu_),
            cache_size(200),
            eps(0.001)
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(0 < nu && nu <= 1,
                "\tsvm_one_class_trainer::svm_one_class_trainer(kernel,nu)"
                << "\n\t invalid inputs were given to this function"
                << "\n\t nu: " << nu
                );
        }

        void set_cache_size (
            long cache_size_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(cache_size_ > 0,
                "\tvoid svm_one_class_trainer::set_cache_size(cache_size_)"
                << "\n\t invalid inputs were given to this function"
                << "\n\t cache_size: " << cache_size_
                );
            cache_size = cache_size_;
        }

        long get_cache_size (
        ) const
        {
            return cache_size;
        }

        void set_epsilon (
            scalar_type eps_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(eps_ > 0,
                "\tvoid svm_one_class_trainer::set_epsilon(eps_)"
                << "\n\t invalid inputs were given to this function"
                << "\n\t eps: " << eps_
                );
            eps = eps_;
        }

        const scalar_type get_epsilon (
        ) const
        {
            return eps;
        }

        void set_kernel (
            const kernel_type& k
        )
        {
            kernel_function = k;
        }

        const kernel_type& get_kernel (
        ) const
        {
            return kernel_function;
        }

        void set_nu (
            scalar_type nu_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(0 < nu_ && nu_ <= 1,
                "\tvoid svm_one_class_trainer::set_nu(nu_)"
                << "\n\t invalid inputs were given to this function"
                << "\n\t nu: " << nu_
                );
            nu = nu_;
        }

        const scalar_type get_nu (
        ) const
        {
            return nu;
        }

        template <
            typename in_sample_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x
        ) const
        {
            return do_train(mat(x));
        }

        void swap (
            svm_one_class_trainer& item
        )
        {
            exchange(kernel_function, item.kernel_function);
            exchange(nu,              item.nu);
            exchange(cache_size,      item.cache_size);
            exchange(eps,             item.eps);
        }

    private:

    // ------------------------------------------------------------------------------------

        template <
            typename in_sample_vector_type
            >
        const decision_function<kernel_type> do_train (
            const in_sample_vector_type& x
        ) const
        {
            typedef typename K::scalar_type scalar_type;
            typedef typename decision_function<K>::sample_vector_type sample_vector_type;
            typedef typename decision_function<K>::scalar_vector_type scalar_vector_type;

            // make sure requires clause is not broken
            DLIB_ASSERT(is_col_vector(x) && x.size() > 0,
                "\tdecision_function svm_one_class_trainer::train(x)"
                << "\n\t invalid inputs were given to this function"
                << "\n\t x.nr(): " << x.nr()
                << "\n\t x.nc(): " << x.nc()
                );

            scalar_vector_type alpha;

            solve_qp3_using_smo<scalar_vector_type> solver;

            solver(symmetric_matrix_cache<float>(kernel_matrix(kernel_function,x), cache_size),
                   zeros_matrix<scalar_type>(x.size(),1),
                   ones_matrix<scalar_type>(x.size(),1),
                   nu*x.size(),
                   1,
                   1,
                   alpha,
                   eps);

            scalar_type rho;
            calculate_rho(alpha,solver.get_gradient(),rho);

            // count the number of support vectors
            const long sv_count = (long)sum(alpha != 0);

            scalar_vector_type sv_alpha;
            sample_vector_type support_vectors;

            // size these column vectors so that they have an entry for each support vector
            sv_alpha.set_size(sv_count);
            support_vectors.set_size(sv_count);

            // load the support vectors and their alpha values into these new column matrices
            long idx = 0;
            for (long i = 0; i < alpha.nr(); ++i)
            {
                if (alpha(i) != 0)
                {
                    sv_alpha(idx) = alpha(i);
                    support_vectors(idx) = x(i);
                    ++idx;
                }
            }

            // now return the decision function
            return decision_function<K> (sv_alpha, rho, kernel_function, support_vectors);
        }

    // ------------------------------------------------------------------------------------

        template <
            typename scalar_vector_type
            >
        void calculate_rho(
            const scalar_vector_type& alpha,
            const scalar_vector_type& df,
            scalar_type& rho
        ) const
        {
            using namespace std;
            long num_p_free = 0;
            scalar_type sum_p_free = 0;

            scalar_type upper_bound_p;
            scalar_type lower_bound_p;

            find_min_and_max(df, upper_bound_p, lower_bound_p);

            for(long i = 0; i < alpha.nr(); ++i)
            {
                if(alpha(i) == 1)
                {
                    if (df(i) > upper_bound_p)
                        upper_bound_p = df(i);
                }
                else if(alpha(i) == 0)
                {
                    if (df(i) < lower_bound_p)
                        lower_bound_p = df(i);
                }
                else
                {
                    ++num_p_free;
                    sum_p_free += df(i);
                }
            }

            scalar_type r1;
            if(num_p_free > 0)
                r1 = sum_p_free/num_p_free;
            else
                r1 = (upper_bound_p+lower_bound_p)/2;

            rho = r1;
        }

        kernel_type kernel_function;
        scalar_type nu;
        long cache_size;
        scalar_type eps;
    }; // end of class svm_one_class_trainer

// ----------------------------------------------------------------------------------------

    template <typename K>
    void swap (
        svm_one_class_trainer<K>& a,
        svm_one_class_trainer<K>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SVm_ONE_CLASS_TRAINER_Hh_


dlib C++ Library - svm_rank_trainer.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SVM_RANK_TrAINER_Hh_
#define DLIB_SVM_RANK_TrAINER_Hh_

#include "svm_rank_trainer_abstract.h"

#include "ranking_tools.h"
#include "../algs.h"
#include "../optimization.h"
#include "function.h"
#include "kernel.h"
#include "sparse_vector.h"
#include <iostream>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_type,
        typename sample_type
        >
    class oca_problem_ranking_svm : public oca_problem<matrix_type >
    {
    public:
        /*
            This class is used as part of the implementation of the svm_rank_trainer
            defined towards the end of this file.
        */

        typedef typename matrix_type::type scalar_type;

        oca_problem_ranking_svm(
            const scalar_type C_,
            const std::vector<ranking_pair<sample_type> >& samples_,
            const bool be_verbose_,
            const scalar_type eps_,
            const unsigned long max_iter,
            const unsigned long dims_
        ) :
            samples(samples_),
            C(C_),
            be_verbose(be_verbose_),
            eps(eps_),
            max_iterations(max_iter),
            dims(dims_)
        {
        }

        virtual scalar_type get_c (
        ) const
        {
            return C;
        }

        virtual long get_num_dimensions (
        ) const
        {
            return dims;
        }

        virtual bool optimization_status (
            scalar_type current_objective_value,
            scalar_type current_error_gap,
            scalar_type current_risk_value,
            scalar_type current_risk_gap,
            unsigned long num_cutting_planes,
            unsigned long num_iterations
        ) const
        {
            if (be_verbose)
            {
                using namespace std;
                cout << "objective:     " << current_objective_value << endl;
                cout << "objective gap: " << current_error_gap << endl;
                cout << "risk:          " << current_risk_value << endl;
                cout << "risk gap:      " << current_risk_gap << endl;
                cout << "num planes:    " << num_cutting_planes << endl;
                cout << "iter:          " << num_iterations << endl;
                cout << endl;
            }

            if (num_iterations >= max_iterations)
                return true;

            if (current_risk_gap < eps)
                return true;

            return false;
        }

        virtual bool risk_has_lower_bound (
            scalar_type& lower_bound
        ) const
        {
            lower_bound = 0;
            return true;
        }

        virtual void get_risk (
            matrix_type& w,
            scalar_type& risk,
            matrix_type& subgradient
        ) const
        {
            subgradient.set_size(w.size(),1);
            subgradient = 0;
            risk = 0;

            // Note that we want the risk value to be in terms of the fraction of overall
            // rank flips.  So a risk of 0.1 would mean that rank flips happen < 10% of the
            // time.

            std::vector<double> rel_scores;
            std::vector<double> nonrel_scores;
            std::vector<unsigned long> rel_counts;
            std::vector<unsigned long> nonrel_counts;

            unsigned long total_pairs = 0;

            // loop over all the samples and compute the risk and its subgradient at the current solution point w
            for (unsigned long i = 0; i < samples.size(); ++i)
            {
                rel_scores.resize(samples[i].relevant.size());
                nonrel_scores.resize(samples[i].nonrelevant.size());

                for (unsigned long k = 0; k < rel_scores.size(); ++k)
                    rel_scores[k] = dot(samples[i].relevant[k], w);

                for (unsigned long k = 0; k < nonrel_scores.size(); ++k)
                    nonrel_scores[k] = dot(samples[i].nonrelevant[k], w) + 1;

                count_ranking_inversions(rel_scores, nonrel_scores, rel_counts, nonrel_counts);

                total_pairs += rel_scores.size()*nonrel_scores.size();

                for (unsigned long k = 0; k < rel_counts.size(); ++k)
                {
                    if (rel_counts[k] != 0)
                    {
                        risk -= rel_counts[k]*rel_scores[k];
                        subtract_from(subgradient, samples[i].relevant[k], rel_counts[k]);
                    }
                }

                for (unsigned long k = 0; k < nonrel_counts.size(); ++k)
                {
                    if (nonrel_counts[k] != 0)
                    {
                        risk += nonrel_counts[k]*nonrel_scores[k];
                        add_to(subgradient, samples[i].nonrelevant[k], nonrel_counts[k]);
                    }
                }

            }

            const scalar_type scale = 1.0/total_pairs;

            risk *= scale;
            subgradient = scale*subgradient;
        }

    private:

    // -----------------------------------------------------
    // -----------------------------------------------------

        const std::vector<ranking_pair<sample_type> >& samples;
        const scalar_type C;

        const bool be_verbose;
        const scalar_type eps;
        const unsigned long max_iterations;
        const unsigned long dims;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_type,
        typename sample_type,
        typename scalar_type
        >
    oca_problem_ranking_svm<matrix_type, sample_type> make_oca_problem_ranking_svm (
        const scalar_type C,
        const std::vector<ranking_pair<sample_type> >& samples,
        const bool be_verbose,
        const scalar_type eps,
        const unsigned long max_iterations,
        const unsigned long dims
    )
    {
        return oca_problem_ranking_svm<matrix_type, sample_type>(
            C, samples, be_verbose, eps, max_iterations, dims);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename K
        >
    class svm_rank_trainer
    {

    public:
        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 decision_function<kernel_type> trained_function_type;

        // You are getting a compiler error on this line because you supplied a non-linear kernel
        // to the svm_rank_trainer object.  You have to use one of the linear kernels with this
        // trainer.
        COMPILE_TIME_ASSERT((is_same_type<K, linear_kernel<sample_type> >::value ||
                             is_same_type<K, sparse_linear_kernel<sample_type> >::value ));

        svm_rank_trainer (
        )
        {
            C = 1;
            verbose = false;
            eps = 0.001;
            max_iterations = 10000;
            learn_nonnegative_weights = false;
            last_weight_1 = false;
        }

        explicit svm_rank_trainer (
            const scalar_type& C_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(C_ > 0,
                "\t svm_rank_trainer::svm_rank_trainer()"
                << "\n\t C_ must be greater than 0"
                << "\n\t C_:    " << C_
                << "\n\t this: " << this
                );

            C = C_;
            verbose = false;
            eps = 0.001;
            max_iterations = 10000;
            learn_nonnegative_weights = false;
            last_weight_1 = false;
        }

        void set_epsilon (
            scalar_type eps_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(eps_ > 0,
                "\t void svm_rank_trainer::set_epsilon()"
                << "\n\t eps_ must be greater than 0"
                << "\n\t eps_: " << eps_
                << "\n\t this: " << this
                );

            eps = eps_;
        }

        const scalar_type get_epsilon (
        ) const { return eps; }

        unsigned long get_max_iterations (
        ) const { return max_iterations; }

        void set_max_iterations (
            unsigned long max_iter
        )
        {
            max_iterations = max_iter;
        }

        void be_verbose (
        )
        {
            verbose = true;
        }

        void be_quiet (
        )
        {
            verbose = false;
        }

        bool forces_last_weight_to_1 (
        ) const
        {
            return last_weight_1;
        }

        void force_last_weight_to_1 (
            bool should_last_weight_be_1
        )
        {
            last_weight_1 = should_last_weight_be_1;
            if (last_weight_1)
                prior.set_size(0);
        }

        void set_oca (
            const oca& item
        )
        {
            solver = item;
        }

        const oca get_oca (
        ) const
        {
            return solver;
        }

        const kernel_type get_kernel (
        ) const
        {
            return kernel_type();
        }

        bool learns_nonnegative_weights (
        ) const { return learn_nonnegative_weights; }

        void set_learns_nonnegative_weights (
            bool value
        )
        {
            learn_nonnegative_weights = value;
            if (learn_nonnegative_weights)
                prior.set_size(0);
        }

        void set_prior (
            const trained_function_type& prior_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(prior_.basis_vectors.size() == 1 &&
                        prior_.alpha(0) == 1,
                "\t void svm_rank_trainer::set_prior()"
                << "\n\t The supplied prior could not have been created by this object's train() method."
                << "\n\t prior_.basis_vectors.size(): " << prior_.basis_vectors.size()
                << "\n\t prior_.alpha(0):             " << prior_.alpha(0)
                << "\n\t this: " << this
                );

            prior = sparse_to_dense(prior_.basis_vectors(0));
            learn_nonnegative_weights = false;
            last_weight_1 = false;
        }

        bool has_prior (
        ) const
        {
            return prior.size() != 0;
        }

        void set_c (
            scalar_type C_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(C_ > 0,
                "\t void svm_rank_trainer::set_c()"
                << "\n\t C_ must be greater than 0"
                << "\n\t C_:    " << C_
                << "\n\t this: " << this
                );

            C = C_;
        }

        const scalar_type get_c (
        ) const
        {
            return C;
        }

        const decision_function<kernel_type> train (
            const std::vector<ranking_pair<sample_type> >& samples
        ) const
        {
            // make sure requires clause is not broken
            DLIB_CASSERT(is_ranking_problem(samples) == true,
                "\t decision_function svm_rank_trainer::train(samples)"
                << "\n\t invalid inputs were given to this function"
                << "\n\t samples.size(): " << samples.size()
                << "\n\t is_ranking_problem(samples): " << is_ranking_problem(samples)
                );

            typedef matrix<scalar_type,0,1> w_type;
            w_type w;

            const unsigned long num_dims = max_index_plus_one(samples);

            unsigned long num_nonnegative = 0;
            if (learn_nonnegative_weights)
            {
                num_nonnegative = num_dims;
            }

            unsigned long force_weight_1_idx = std::numeric_limits<unsigned long>::max();
            if (last_weight_1)
            {
                force_weight_1_idx = num_dims-1;
            }

            if (has_prior())
            {
                if (is_matrix<sample_type>::value)
                {
                    // make sure requires clause is not broken
                    DLIB_CASSERT(num_dims == (unsigned long)prior.size(),
                        "\t decision_function svm_rank_trainer::train(samples)"
                        << "\n\t The dimension of the training vectors must match the dimension of\n"
                        << "\n\t those used to create the prior."
                        << "\n\t num_dims:     " << num_dims
                        << "\n\t prior.size(): " << prior.size()
                    );
                }
                const unsigned long dims = std::max(num_dims, (unsigned long)prior.size());
                // In the case of sparse sample vectors, it is possible that the input
                // vector dimensionality is larger than the prior vector dimensionality.
                // We need to check for this case and pad prior with zeros if it is the
                // case.
                if ((unsigned long)prior.size() < dims)
                {
                    matrix<scalar_type,0,1> prior_temp = join_cols(prior, zeros_matrix<scalar_type>(dims-prior.size(),1));
                    solver( make_oca_problem_ranking_svm<w_type>(C, samples, verbose, eps, max_iterations, dims),
                        w,
                        prior_temp);
                }
                else
                {
                    solver( make_oca_problem_ranking_svm<w_type>(C, samples, verbose, eps, max_iterations, dims),
                        w,
                        prior);
                }

            }
            else
            {
                solver( make_oca_problem_ranking_svm<w_type>(C, samples, verbose, eps, max_iterations, num_dims),
                    w,
                    num_nonnegative,
                    force_weight_1_idx);
            }

            // put the solution into a decision function and then return it
            decision_function<kernel_type> df;
            df.b = 0;
            df.basis_vectors.set_size(1);
            // Copy the results into the output basis vector.  The output vector might be a
            // sparse vector container so we need to use this special kind of copy to
            // handle that case.
            assign(df.basis_vectors(0), matrix_cast<scalar_type>(w));
            df.alpha.set_size(1);
            df.alpha(0) = 1;

            return df;
        }

        const decision_function<kernel_type> train (
            const ranking_pair<sample_type>& sample
        ) const
        {
            return train(std::vector<ranking_pair<sample_type> >(1, sample));
        }

    private:

        scalar_type C;
        oca solver;
        scalar_type eps;
        bool verbose;
        unsigned long max_iterations;
        bool learn_nonnegative_weights;
        bool last_weight_1;
        matrix<scalar_type,0,1> prior;
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SVM_RANK_TrAINER_Hh_


dlib C++ Library - svr_linear_trainer.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SVR_LINEAR_TrAINER_Hh_
#define DLIB_SVR_LINEAR_TrAINER_Hh_

#include "svr_linear_trainer_abstract.h"

#include "../algs.h"
#include "../optimization.h"
#include "function.h"
#include "kernel.h"
#include "sparse_vector.h"
#include <iostream>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_type,
        typename sample_type
        >
    class oca_problem_linear_svr : public oca_problem<matrix_type >
    {
    public:
        /*
            This class is used as part of the implementation of the svr_linear_trainer
            defined towards the end of this file.
        */

        typedef typename matrix_type::type scalar_type;

        oca_problem_linear_svr(
            const scalar_type C_,
            const std::vector<sample_type>& samples_,
            const std::vector<scalar_type>& targets_,
            const bool be_verbose_,
            const scalar_type eps_,
            const scalar_type eps_insensitivity_,
            const unsigned long max_iter
        ) :
            samples(samples_),
            targets(targets_),
            C(C_),
            be_verbose(be_verbose_),
            eps(eps_),
            eps_insensitivity(eps_insensitivity_),
            max_iterations(max_iter)
        {
        }

        virtual scalar_type get_c (
        ) const
        {
            return C;
        }

        virtual long get_num_dimensions (
        ) const
        {
            // plus one for the bias term
            return max_index_plus_one(samples) + 1;
        }

        virtual bool optimization_status (
            scalar_type current_objective_value,
            scalar_type current_error_gap,
            scalar_type current_risk_value,
            scalar_type current_risk_gap,
            unsigned long num_cutting_planes,
            unsigned long num_iterations
        ) const
        {
            current_risk_value /= samples.size();
            current_risk_gap /= samples.size();
            if (be_verbose)
            {
                using namespace std;
                cout << "objective:     " << current_objective_value << endl;
                cout << "objective gap: " << current_error_gap << endl;
                cout << "risk:          " << current_risk_value << endl;
                cout << "risk gap:      " << current_risk_gap << endl;
                cout << "num planes:    " << num_cutting_planes << endl;
                cout << "iter:          " << num_iterations << endl;
                cout << endl;
            }

            if (num_iterations >= max_iterations)
                return true;

            if (current_risk_gap < eps*eps_insensitivity)
                return true;

            return false;
        }

        virtual bool risk_has_lower_bound (
            scalar_type& lower_bound
        ) const
        {
            lower_bound = 0;
            return true;
        }

        virtual void get_risk (
            matrix_type& w,
            scalar_type& risk,
            matrix_type& subgradient
        ) const
        {
            subgradient.set_size(w.size(),1);
            subgradient = 0;
            risk = 0;

            // loop over all the samples and compute the risk and its subgradient at the current solution point w
            for (unsigned long i = 0; i < samples.size(); ++i)
            {
                const long w_size_m1 = w.size()-1;
                const scalar_type prediction = dot(colm(w,0,w_size_m1), samples[i]) - w(w_size_m1);

                if (std::abs(prediction - targets[i]) > eps_insensitivity)
                {
                    if (prediction < targets[i])
                    {
                        subtract_from(subgradient, samples[i]);
                        subgradient(w_size_m1) += 1;
                    }
                    else
                    {
                        add_to(subgradient, samples[i]);
                        subgradient(w_size_m1) -= 1;
                    }

                    risk += std::abs(prediction - targets[i]) - eps_insensitivity;
                }
            }
        }

    private:

    // -----------------------------------------------------
    // -----------------------------------------------------

        const std::vector<sample_type>& samples;
        const std::vector<scalar_type>& targets;
        const scalar_type C;

        const bool be_verbose;
        const scalar_type eps;
        const scalar_type eps_insensitivity;
        const unsigned long max_iterations;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename matrix_type,
        typename sample_type,
        typename scalar_type
        >
    oca_problem_linear_svr<matrix_type, sample_type> make_oca_problem_linear_svr (
        const scalar_type C,
        const std::vector<sample_type>& samples,
        const std::vector<scalar_type>& targets,
        const bool be_verbose,
        const scalar_type eps,
        const scalar_type eps_insensitivity,
        const unsigned long max_iterations
    )
    {
        return oca_problem_linear_svr<matrix_type, sample_type>(
            C, samples, targets, be_verbose, eps, eps_insensitivity, max_iterations);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename K
        >
    class svr_linear_trainer
    {

    public:
        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 decision_function<kernel_type> trained_function_type;

        // You are getting a compiler error on this line because you supplied a non-linear kernel
        // to the svr_linear_trainer object.  You have to use one of the linear kernels with this
        // trainer.
        COMPILE_TIME_ASSERT((is_same_type<K, linear_kernel<sample_type> >::value ||
                             is_same_type<K, sparse_linear_kernel<sample_type> >::value ));

        svr_linear_trainer (
        )
        {
            C = 1;
            verbose = false;
            eps = 0.01;
            max_iterations = 10000;
            learn_nonnegative_weights = false;
            last_weight_1 = false;
            eps_insensitivity = 0.1;
        }

        explicit svr_linear_trainer (
            const scalar_type& C_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(C_ > 0,
                "\t svr_linear_trainer::svr_linear_trainer()"
                << "\n\t C_ must be greater than 0"
                << "\n\t C_:    " << C_
                << "\n\t this: " << this
                );

            C = C_;
            verbose = false;
            eps = 0.01;
            max_iterations = 10000;
            learn_nonnegative_weights = false;
            last_weight_1 = false;
            eps_insensitivity = 0.1;
        }

        void set_epsilon (
            scalar_type eps_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(eps_ > 0,
                "\t void svr_linear_trainer::set_epsilon()"
                << "\n\t eps_ must be greater than 0"
                << "\n\t eps_: " << eps_
                << "\n\t this: " << this
                );

            eps = eps_;
        }

        const scalar_type get_epsilon (
        ) const { return eps; }

        void set_epsilon_insensitivity (
            scalar_type eps_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(eps_ > 0,
                "\tvoid svr_linear_trainer::set_epsilon_insensitivity(eps_)"
                << "\n\t invalid inputs were given to this function"
                << "\n\t eps_: " << eps_
                );
            eps_insensitivity = eps_;
        }

        const scalar_type get_epsilon_insensitivity (
        ) const
        {
            return eps_insensitivity;
        }

        unsigned long get_max_iterations (
        ) const { return max_iterations; }

        void set_max_iterations (
            unsigned long max_iter
        )
        {
            max_iterations = max_iter;
        }

        void be_verbose (
        )
        {
            verbose = true;
        }

        void be_quiet (
        )
        {
            verbose = false;
        }

        bool forces_last_weight_to_1 (
        ) const
        {
            return last_weight_1;
        }

        void force_last_weight_to_1 (
            bool should_last_weight_be_1
        )
        {
            last_weight_1 = should_last_weight_be_1;
        }

        void set_oca (
            const oca& item
        )
        {
            solver = item;
        }

        const oca get_oca (
        ) const
        {
            return solver;
        }

        const kernel_type get_kernel (
        ) const
        {
            return kernel_type();
        }

        bool learns_nonnegative_weights (
        ) const { return learn_nonnegative_weights; }

        void set_learns_nonnegative_weights (
            bool value
        )
        {
            learn_nonnegative_weights = value;
        }

        void set_c (
            scalar_type C_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(C_ > 0,
                "\t void svr_linear_trainer::set_c()"
                << "\n\t C_ must be greater than 0"
                << "\n\t C_:    " << C_
                << "\n\t this: " << this
                );

            C = C_;
        }

        const scalar_type get_c (
        ) const
        {
            return C;
        }

        const decision_function<kernel_type> train (
            const std::vector<sample_type>& samples,
            const std::vector<scalar_type>& targets
        ) const
        {
            // make sure requires clause is not broken
            DLIB_CASSERT(is_learning_problem(samples, targets) == true,
                "\t decision_function svr_linear_trainer::train(samples, targets)"
                << "\n\t invalid inputs were given to this function"
                << "\n\t samples.size(): " << samples.size()
                << "\n\t targets.size(): " << targets.size()
                << "\n\t is_learning_problem(samples,targets): " << is_learning_problem(samples,targets)
                );

            typedef matrix<scalar_type,0,1> w_type;
            w_type w;

            const unsigned long num_dims = max_index_plus_one(samples);

            unsigned long num_nonnegative = 0;
            if (learn_nonnegative_weights)
            {
                num_nonnegative = num_dims;
            }

            unsigned long force_weight_1_idx = std::numeric_limits<unsigned long>::max();
            if (last_weight_1)
            {
                force_weight_1_idx = num_dims-1;
            }

            solver( make_oca_problem_linear_svr<w_type>(C, samples, targets, verbose, eps, eps_insensitivity, max_iterations),
                    w,
                    num_nonnegative,
                    force_weight_1_idx);

            // put the solution into a decision function and then return it
            decision_function<kernel_type> df;
            df.b = static_cast<scalar_type>(w(w.size()-1));
            df.basis_vectors.set_size(1);
            // Copy the plane normal into the output basis vector.  The output vector might be a
            // sparse vector container so we need to use this special kind of copy to handle that case.
            // As an aside, the reason for using max_index_plus_one() and not just w.size()-1 is because
            // doing it this way avoids an inane warning from gcc that can occur in some cases.
            const long out_size = max_index_plus_one(samples);
            assign(df.basis_vectors(0), matrix_cast<scalar_type>(colm(w, 0, out_size)));
            df.alpha.set_size(1);
            df.alpha(0) = 1;

            return df;
        }

    private:

        scalar_type C;
        oca solver;
        scalar_type eps;
        bool verbose;
        unsigned long max_iterations;
        bool learn_nonnegative_weights;
        bool last_weight_1;
        scalar_type eps_insensitivity;
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SVR_LINEAR_TrAINER_Hh_


dlib C++ Library - svr_trainer.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SVm_EPSILON_REGRESSION_TRAINER_Hh_
#define DLIB_SVm_EPSILON_REGRESSION_TRAINER_Hh_

#include "svr_trainer_abstract.h"
#include <cmath>
#include <limits>
#include "../matrix.h"
#include "../algs.h"

#include "function.h"
#include "kernel.h"
#include "../optimization/optimization_solve_qp3_using_smo.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename K
        >
    class svr_trainer
    {
    public:
        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 decision_function<kernel_type> trained_function_type;

        svr_trainer (
        ) :
            C(1),
            eps_insensitivity(0.1),
            cache_size(200),
            eps(0.001)
        {
        }

        void set_cache_size (
            long cache_size_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(cache_size_ > 0,
                "\tvoid svr_trainer::set_cache_size(cache_size_)"
                << "\n\t invalid inputs were given to this function"
                << "\n\t cache_size: " << cache_size_
                );
            cache_size = cache_size_;
        }

        long get_cache_size (
        ) const
        {
            return cache_size;
        }

        void set_epsilon (
            scalar_type eps_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(eps_ > 0,
                "\tvoid svr_trainer::set_epsilon(eps_)"
                << "\n\t invalid inputs were given to this function"
                << "\n\t eps_: " << eps_
                );
            eps = eps_;
        }

        const scalar_type get_epsilon (
        ) const
        {
            return eps;
        }

        void set_epsilon_insensitivity (
            scalar_type eps_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(eps_ > 0,
                "\tvoid svr_trainer::set_epsilon_insensitivity(eps_)"
                << "\n\t invalid inputs were given to this function"
                << "\n\t eps_: " << eps_
                );
            eps_insensitivity = eps_;
        }

        const scalar_type get_epsilon_insensitivity (
        ) const
        {
            return eps_insensitivity;
        }

        void set_kernel (
            const kernel_type& k
        )
        {
            kernel_function = k;
        }

        const kernel_type& get_kernel (
        ) const
        {
            return kernel_function;
        }

        void set_c (
            scalar_type C_
        )
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(C_ > 0,
                "\t void svr_trainer::set_c()"
                << "\n\t C must be greater than 0"
                << "\n\t C_:    " << C_
                << "\n\t this: " << this
                );

            C = C_;
        }

        const scalar_type get_c (
        ) const
        {
            return C;
        }

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y
        ) const
        {
            return do_train(mat(x), mat(y));
        }

        void swap (
            svr_trainer& item
        )
        {
            exchange(kernel_function, item.kernel_function);
            exchange(C,            item.C);
            exchange(eps_insensitivity, item.eps_insensitivity);
            exchange(cache_size,      item.cache_size);
            exchange(eps,             item.eps);
        }

    private:

    // ------------------------------------------------------------------------------------

        template <typename M>
        struct op_quad
        {
            explicit op_quad(
                const M& m_
            ) : m(m_) {}

            const M& m;

            typedef typename M::type type;
            typedef type const_ret_type;
            const static long cost = M::cost + 2;

            inline const_ret_type apply ( long r, long c) const
            {
                if (r < m.nr())
                {
                    if (c < m.nc())
                    {
                        return m(r,c);
                    }
                    else
                    {
                        return -m(r,c-m.nc());
                    }
                }
                else
                {
                    if (c < m.nc())
                    {
                        return -m(r-m.nr(),c);
                    }
                    else
                    {
                        return m(r-m.nr(),c-m.nc());
                    }
                }
            }

            const static long NR = 2*M::NR;
            const static long NC = 2*M::NC;
            typedef typename M::mem_manager_type mem_manager_type;
            typedef typename M::layout_type layout_type;

            long nr () const { return 2*m.nr(); }
            long nc () const { return 2*m.nc(); }

            template <typename U> bool aliases               ( const matrix_exp<U>& item) const
            { return m.aliases(item); }
            template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const
            { return m.aliases(item); }
        };

        template <
            typename EXP
            >
        const matrix_op<op_quad<EXP> >  make_quad (
            const matrix_exp<EXP>& m
        ) const
        /*!
            ensures
                - returns the following matrix:
                     m -m
                    -m  m
                - I.e. returns a matrix that is twice the size of m and just
                  contains copies of m and -m
        !*/
        {
            typedef op_quad<EXP> op;
            return matrix_op<op>(op(m.ref()));
        }

    // ------------------------------------------------------------------------------------

        template <
            typename in_sample_vector_type,
            typename in_scalar_vector_type
            >
        const decision_function<kernel_type> do_train (
            const in_sample_vector_type& x,
            const in_scalar_vector_type& y
        ) const
        {
            typedef typename K::scalar_type scalar_type;
            typedef typename decision_function<K>::sample_vector_type sample_vector_type;
            typedef typename decision_function<K>::scalar_vector_type scalar_vector_type;

            // make sure requires clause is not broken
            DLIB_ASSERT(is_learning_problem(x,y) == true,
                "\tdecision_function svr_trainer::train(x,y)"
                << "\n\t invalid inputs were given to this function"
                << "\n\t x.nr(): " << x.nr()
                << "\n\t y.nr(): " << y.nr()
                << "\n\t x.nc(): " << x.nc()
                << "\n\t y.nc(): " << y.nc()
                );

            scalar_vector_type alpha;

            solve_qp3_using_smo<scalar_vector_type> solver;

            solver(symmetric_matrix_cache<float>(make_quad(kernel_matrix(kernel_function,x)), cache_size),
                   uniform_matrix<scalar_type>(2*x.size(),1, eps_insensitivity) + join_cols(y,-y),
                   join_cols(uniform_matrix<scalar_type>(x.size(),1,1), uniform_matrix<scalar_type>(x.size(),1,-1)),
                   0,
                   C,
                   C,
                   alpha,
                   eps);

            scalar_type b;
            calculate_b(alpha,solver.get_gradient(),C,b);

            alpha = -rowm(alpha,range(0,x.size()-1)) + rowm(alpha,range(x.size(), alpha.size()-1));

            // count the number of support vectors
            const long sv_count = (long)sum(alpha != 0);

            scalar_vector_type sv_alpha;
            sample_vector_type support_vectors;

            // size these column vectors so that they have an entry for each support vector
            sv_alpha.set_size(sv_count);
            support_vectors.set_size(sv_count);

            // load the support vectors and their alpha values into these new column matrices
            long idx = 0;
            for (long i = 0; i < alpha.nr(); ++i)
            {
                if (alpha(i) != 0)
                {
                    sv_alpha(idx) = alpha(i);
                    support_vectors(idx) = x(i);
                    ++idx;
                }
            }

            // now return the decision function
            return decision_function<K> (sv_alpha, -b, kernel_function, support_vectors);
        }

    // ------------------------------------------------------------------------------------

        template <
            typename scalar_vector_type
            >
        void calculate_b(
            const scalar_vector_type& alpha,
            const scalar_vector_type& df,
            const scalar_type& C,
            scalar_type& b
        ) const
        {
            using namespace std;
            long num_free = 0;
            scalar_type sum_free = 0;

            scalar_type upper_bound = -numeric_limits<scalar_type>::infinity();
            scalar_type lower_bound = numeric_limits<scalar_type>::infinity();

            find_min_and_max(df, upper_bound, lower_bound);

            for(long i = 0; i < alpha.nr(); ++i)
            {
                if(i < alpha.nr()/2)
                {
                    if(alpha(i) == C)
                    {
                        if (df(i) > upper_bound)
                            upper_bound = df(i);
                    }
                    else if(alpha(i) == 0)
                    {
                        if (df(i) < lower_bound)
                            lower_bound = df(i);
                    }
                    else
                    {
                        ++num_free;
                        sum_free += df(i);
                    }
                }
                else
                {
                    if(alpha(i) == C)
                    {
                        if (-df(i) < lower_bound)
                            lower_bound = -df(i);
                    }
                    else if(alpha(i) == 0)
                    {
                        if (-df(i) > upper_bound)
                            upper_bound = -df(i);
                    }
                    else
                    {
                        ++num_free;
                        sum_free -= df(i);
                    }
                }
            }

            if(num_free > 0)
                b = sum_free/num_free;
            else
                b = (upper_bound+lower_bound)/2;
        }

    // ------------------------------------------------------------------------------------

        kernel_type kernel_function;
        scalar_type C;
        scalar_type eps_insensitivity;
        long cache_size;
        scalar_type eps;
    }; // end of class svr_trainer

// ----------------------------------------------------------------------------------------

    template <typename K>
    void swap (
        svr_trainer<K>& a,
        svr_trainer<K>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SVm_EPSILON_REGRESSION_TRAINER_Hh_


dlib C++ Library - track_association_function.h

// Copyright (C) 2014  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_TRACK_ASSOCiATION_FUNCTION_Hh_
#define DLIB_TRACK_ASSOCiATION_FUNCTION_Hh_

#include "track_association_function_abstract.h"
#include <vector>
#include <iostream>
#include "../algs.h"
#include "../serialize.h"
#include "assignment_function.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename detection_type
        >
    class feature_extractor_track_association
    {
    public:
        typedef typename detection_type::track_type track_type;
        typedef typename track_type::feature_vector_type feature_vector_type;

        typedef detection_type lhs_element;
        typedef track_type rhs_element;

        feature_extractor_track_association() : num_dims(0), num_nonnegative(0) {}

        explicit feature_extractor_track_association (
            unsigned long num_dims_,
            unsigned long num_nonnegative_
        ) : num_dims(num_dims_), num_nonnegative(num_nonnegative_) {}

        unsigned long num_features(
        ) const { return num_dims; }

        unsigned long num_nonnegative_weights (
        ) const { return num_nonnegative; }

        void get_features (
            const detection_type& det,
            const track_type& track,
            feature_vector_type& feats
        ) const
        {
            track.get_similarity_features(det, feats);
        }

        friend void serialize (const feature_extractor_track_association& item, std::ostream& out)
        {
            serialize(item.num_dims, out);
            serialize(item.num_nonnegative, out);
        }

        friend void deserialize (feature_extractor_track_association& item, std::istream& in)
        {
            deserialize(item.num_dims, in);
            deserialize(item.num_nonnegative, in);
        }

    private:
        unsigned long num_dims;
        unsigned long num_nonnegative;
    };

// ----------------------------------------------------------------------------------------

    template <
        typename detection_type_
        >
    class track_association_function
    {
    public:

        typedef detection_type_ detection_type;
        typedef typename detection_type::track_type track_type;
        typedef assignment_function<feature_extractor_track_association<detection_type> > association_function_type;

        track_association_function() {}

        track_association_function (
            const association_function_type& assoc_
        ) : assoc(assoc_)
        {
        }

        const association_function_type& get_assignment_function (
        ) const
        {
            return assoc;
        }

        void operator() (
            std::vector<track_type>& tracks,
            const std::vector<detection_type>& dets
        ) const
        {
            std::vector<long> assignments = assoc(dets, tracks);
            std::vector<bool> updated_track(tracks.size(), false);
            // now update all the tracks with the detections that associated to them.
            for (unsigned long i = 0; i < assignments.size(); ++i)
            {
                if (assignments[i] != -1)
                {
                    tracks[assignments[i]].update_track(dets[i]);
                    updated_track[assignments[i]] = true;
                }
                else
                {
                    track_type new_track;
                    new_track.update_track(dets[i]);
                    tracks.push_back(new_track);
                }
            }

            // Now propagate all the tracks that didn't get any detections.
            for (unsigned long i = 0; i < updated_track.size(); ++i)
            {
                if (!updated_track[i])
                    tracks[i].propagate_track();
            }
        }

        friend void serialize (const track_association_function& item, std::ostream& out)
        {
            int version = 1;
            serialize(version, out);
            serialize(item.assoc, out);
        }
        friend void deserialize (track_association_function& item, std::istream& in)
        {
            int version = 0;
            deserialize(version, in);
            if (version != 1)
                throw serialization_error("Unexpected version found while deserializing dlib::track_association_function.");

            deserialize(item.assoc, in);
        }

    private:

        assignment_function<feature_extractor_track_association<detection_type> > assoc;
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_TRACK_ASSOCiATION_FUNCTION_Hh_


dlib C++ Library - sync_extension_kernel_1.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SYNC_EXTENSION_KERNEl_1_
#define DLIB_SYNC_EXTENSION_KERNEl_1_

#include "../threads.h"
#include "../algs.h"
#include "sync_extension_kernel_abstract.h"

namespace dlib
{

    template <
        typename base
        >
    class sync_extension_kernel_1 : public base
    {

        rmutex m;
        rsignaler s;

        public:

        sync_extension_kernel_1 () : s(m) {}

        template < typename T >
        sync_extension_kernel_1 (const T& one) : base(one),s(m) {}
        template < typename T, typename U >
        sync_extension_kernel_1 (const T& one, const U& two) : base(one,two),s(m) {}

        const rmutex& get_mutex(
        ) const { return m; }

        void lock (
        ) const { m.lock(); }

        void unlock (
        ) const { m.unlock(); }

        void wait (
        ) const { s.wait(); }

        bool wait_or_timeout (
            unsigned long milliseconds
        ) const { return s.wait_or_timeout(milliseconds); }

        void broadcast (
        ) const { s.broadcast(); }

        void signal (
        ) const { s.signal(); }

    };

    template <
        typename base
        >
    inline void swap (
        sync_extension_kernel_1<base>& a,
        sync_extension_kernel_1<base>& b
    ) { a.swap(b); }

}

#endif // DLIB_SYNC_EXTENSION_KERNEl_1_


dlib/test/CMakeLists.txt

#
# 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.4)

# 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
   crc32.cpp
   create_iris_datafile.cpp
   data_io.cpp
   directed_graph.cpp
   discriminant_pca.cpp
   disjoint_subsets.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
   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
   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
   sammon.cpp
   scan_image.cpp
   sequence.cpp
   sequence_labeler.cpp
   sequence_segmenter.cpp
   serialize.cpp
   set.cpp
   sldf.cpp
   sliding_buffer.cpp
   smart_pointers.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
   )

# create a variable called target_name and set it to the string "dtest"
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 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()

# Tell cmake to link our target executable to dlib.
include(../cmake)
TARGET_LINK_LIBRARIES(${target_name} dlib )

if (NOT DLIB_NO_GUI_SUPPORT)
   add_subdirectory(gui)
   add_subdirectory(examples)
endif()


dlib C++ Library - example.cpp

// 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;


dlib C++ Library - example_args.cpp

// 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;


dlib C++ Library - main.cpp

// 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;


dlib C++ Library - tester.cpp

// 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;
        }
    }

// -----------------------------------------------------------------------------


dlib C++ Library - tester.h

// 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(_exp, __LINE__, __FILE__, #_exp);

#define DLIB_TEST_MSG(_exp,_message)                                        \
    {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());                                 \
    }}

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_


dlib C++ Library - auto_mutex_extension.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_AUTO_MUTEX_EXTENSIOn_
#define DLIB_AUTO_MUTEX_EXTENSIOn_

#include "threads_kernel.h"
#include "rmutex_extension.h"
#include "read_write_mutex_extension.h"
#include "auto_mutex_extension_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class auto_mutex
    {
        /*!
            INITIAL VALUE
                - if (m != 0) then
                    - the mutex pointed to by m is locked
                - if (r != 0) then
                    - the mutex pointed to by r is locked
                - if (rw != 0) then
                    - the mutex pointed to by rw is locked
                - exactly one of r, m, or rw is not 0.

            CONVENTION
                - if (m != 0) then
                    - the mutex pointed to by m is locked
                - if (r != 0) then
                    - the mutex pointed to by r is locked
                - if (rw != 0) then
                    - the mutex pointed to by rw is locked
                - exactly one of r, m, or rw is not 0.
        !*/
    public:

        explicit auto_mutex (
            const mutex& m_
        ) : m(&m_),
            r(0),
            rw(0)
        {
            m->lock();
        }

        explicit auto_mutex (
            const rmutex& r_
        ) : m(0),
            r(&r_),
            rw(0)
        {
            r->lock();
        }

        explicit auto_mutex (
            const read_write_mutex& rw_
        ) : m(0),
            r(0),
            rw(&rw_)
        {
            rw->lock();
        }

        void unlock()
        {
            if (m != 0)
            {
                m->unlock();
                m = 0;
            }
            else if (r != 0)
            {
                r->unlock();
                r = 0;
            }
            else if (rw != 0)
            {
                rw->unlock();
                rw = 0;
            }
        }

        ~auto_mutex (
        )
        {
            unlock();
        }

    private:

        const mutex* m;
        const rmutex* r;
        const read_write_mutex* rw;

        // restricted functions
        auto_mutex(auto_mutex&);        // copy constructor
        auto_mutex& operator=(auto_mutex&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------

    class auto_mutex_readonly
    {
    public:

        explicit auto_mutex_readonly (
            const read_write_mutex& rw_
        ) : rw(rw_), _has_write_lock(false), _has_read_lock(true)
        {
            rw.lock_readonly();
        }

        ~auto_mutex_readonly (
        )
        {
            unlock();
        }

        void lock_readonly (
        )
        {
            if (!_has_read_lock)
            {
                unlock();
                rw.lock_readonly();
                _has_read_lock = true;
            }
        }

        void lock_write (
        )
        {
            if (!_has_write_lock)
            {
                unlock();
                rw.lock();
                _has_write_lock = true;
            }
        }

        void unlock (
        )
        {
            if (_has_write_lock)
            {
                rw.unlock();
                _has_write_lock = false;
            }
            else if (_has_read_lock)
            {
                rw.unlock_readonly();
                _has_read_lock = false;
            }
        }

        bool has_read_lock (
        ) { return _has_read_lock; }

        bool has_write_lock (
        ) { return _has_write_lock; }

    private:

        const read_write_mutex& rw;
        bool _has_write_lock;
        bool _has_read_lock;

        // restricted functions
        auto_mutex_readonly(auto_mutex_readonly&);        // copy constructor
        auto_mutex_readonly& operator=(auto_mutex_readonly&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_AUTO_MUTEX_EXTENSIOn_


dlib C++ Library - auto_mutex_extension_abstract.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_AUTO_MUTEX_EXTENSIOn_ABSTRACT_
#ifdef DLIB_AUTO_MUTEX_EXTENSIOn_ABSTRACT_

#include "threads_kernel_abstract.h"
#include "rmutex_extension_abstract.h"
#include "read_write_mutex_extension_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class auto_mutex
    {
        /*!
            INITIAL VALUE
                The mutex given in the constructor is locked and associated with this
                object.

            WHAT THIS OBJECT REPRESENTS
                This object represents a mechanism for automatically locking and unlocking
                a mutex object.
        !*/
    public:

        explicit auto_mutex (
            const mutex& m
        );
        /*!
            ensures
                - #*this is properly initialized
                - m will be locked
        !*/

        explicit auto_mutex (
            const rmutex& m
        );
        /*!
            ensures
                - #*this is properly initialized
                - m will be locked
        !*/

        explicit auto_mutex (
            const read_write_mutex& m
        );
        /*!
            ensures
                - #*this is properly initialized
                - m will be locked via m.lock() (i.e. a write lock will be obtained)
        !*/

        void unlock(
        );
        /*!
            ensures
                - if (unlock() has not already been called) then
                    - The mutex associated with *this has been unlocked.  This is useful if
                      you want to unlock a mutex before the auto_mutex destructor executes.
        !*/

        ~auto_mutex (
        );
        /*!
            ensures
                - all resources allocated by *this have been freed
                - calls unlock()
        !*/

    private:
        // restricted functions
        auto_mutex(auto_mutex&);        // copy constructor
        auto_mutex& operator=(auto_mutex&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------

    class auto_mutex_readonly
    {
        /*!
            INITIAL VALUE
                The mutex given in the constructor is locked using a read-only lock and
                associated with this object.

            WHAT THIS OBJECT REPRESENTS
                This object represents a mechanism for automatically locking and unlocking
                a read_write_mutex object.  In particular, a readonly lock is used.
        !*/
    public:

        explicit auto_mutex_readonly (
            const read_write_mutex& m
        );
        /*!
            ensures
                - #*this is properly initialized
                - a readonly lock will be obtained on m using m.lock_readonly()
                - #has_read_lock() == true
        !*/

        ~auto_mutex_readonly (
        );
        /*!
            ensures
                - all resources allocated by *this have been freed
                - the mutex associated with *this has been unlocked
        !*/

        bool has_read_lock (
        );
        /*!
            ensures
                - returns true if this object has called read_write_mutex::lock_readonly()
                  on its associated mutex and has yet to release that lock.
        !*/

        bool has_write_lock (
        );
        /*!
            ensures
                - returns true if this object has called read_write_mutex::lock() on its
                  associated mutex and has yet to release that lock.
        !*/

        void lock_readonly (
        );
        /*!
            ensures
                - This function converts the lock on the associated mutex into a readonly lock.
                  Specifically:
                  if (!has_read_lock()) then
                    - if (has_write_lock()) then
                        - unlocks the associated mutex and then relocks it by calling
                          read_write_mutex::lock_readonly()
                    - else
                        - locks the associated mutex by calling read_write_mutex::lock_readonly()
                - #has_read_lock() == true
                - Note that the lock switch is not atomic.  This means that whatever
                  resource is protected by the mutex might have been modified during the
                  call to lock_readonly().
        !*/

        void lock_write (
        );
        /*!
            ensures
                - This function converts the lock on the associated mutex into a write lock.
                  Specifically:
                  if (!has_write_lock()) then
                    - if (has_read_lock()) then
                        - unlocks the associated mutex and then relocks it by calling
                          read_write_mutex::lock()
                    - else
                        - locks the associated mutex by calling read_write_mutex::lock()
                - #has_write_lock() == true
                - Note that the lock switch is not atomic.  This means that whatever
                  resource is protected by the mutex might have been modified during the
                  call to lock_write().
        !*/

        void unlock (
        );
        /*!
            ensures
                - if (has_read_lock() || has_write_lock()) then
                    - unlocks the associated mutex.  This is useful if you want to unlock a
                      mutex before the auto_mutex_readonly destructor executes.
                - #has_read_lock() == false
                - #has_write_lock() == false
        !*/

    private:
        // restricted functions
        auto_mutex_readonly(auto_mutex_readonly&);        // copy constructor
        auto_mutex_readonly& operator=(auto_mutex_readonly&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_AUTO_MUTEX_EXTENSIOn_ABSTRACT_


dlib C++ Library - auto_unlock_extension.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_AUTO_UNLOCK_EXTENSIOn_
#define DLIB_AUTO_UNLOCK_EXTENSIOn_

#include "threads_kernel.h"
#include "rmutex_extension.h"
#include "read_write_mutex_extension.h"
#include "auto_unlock_extension_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class auto_unlock
    {
        /*!
            INITIAL VALUE
                - if (m != 0) then
                    - the mutex pointed to by m is locked
                - if (r != 0) then
                    - the mutex pointed to by r is locked
                - if (rw != 0) then
                    - the mutex pointed to by rw is locked
                - exactly one of r, m, or rw is not 0.

            CONVENTION
                - if (m != 0) then
                    - the mutex pointed to by m is locked
                - if (r != 0) then
                    - the mutex pointed to by r is locked
                - if (rw != 0) then
                    - the mutex pointed to by rw is locked
                - exactly one of r, m, or rw is not 0.
        !*/
    public:

        explicit auto_unlock (
            const mutex& m_
        ) : m(&m_),
            r(0),
            rw(0)
        {}

        explicit auto_unlock (
            const rmutex& r_
        ) : m(0),
            r(&r_),
            rw(0)
        {}

        explicit auto_unlock (
            const read_write_mutex& rw_
        ) : m(0),
            r(0),
            rw(&rw_)
        {}

        ~auto_unlock (
        )
        {
            if (m != 0)
                m->unlock();
            else if (r != 0)
                r->unlock();
            else
                rw->unlock();
        }

    private:

        const mutex* m;
        const rmutex* r;
        const read_write_mutex* rw;

        // restricted functions
        auto_unlock(auto_unlock&);        // copy constructor
        auto_unlock& operator=(auto_unlock&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------

    class auto_unlock_readonly
    {

    public:

        explicit auto_unlock_readonly (
            const read_write_mutex& rw_
        ) :
            rw(rw_)
        {}

        ~auto_unlock_readonly (
        )
        {
            rw.unlock_readonly();
        }

    private:

        const read_write_mutex& rw;

        // restricted functions
        auto_unlock_readonly(auto_unlock_readonly&);        // copy constructor
        auto_unlock_readonly& operator=(auto_unlock_readonly&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_AUTO_UNLOCK_EXTENSIOn_


dlib C++ Library - auto_unlock_extension_abstract.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_AUTO_UNLOCK_EXTENSIOn_ABSTRACT_
#ifdef DLIB_AUTO_UNLOCK_EXTENSIOn_ABSTRACT_

#include "threads_kernel_abstract.h"
#include "rmutex_extension_abstract.h"
#include "read_write_mutex_extension_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class auto_unlock
    {
        /*!
            INITIAL VALUE
                The mutex given in the constructor is associated with this object.

            WHAT THIS OBJECT REPRESENTS
                This object represents a mechanism for automatically unlocking
                a mutex object.  It is useful when you already have a locked mutex
                and want to make sure it gets unlocked even if an exception is thrown
                or you quit the function at a weird spot.
        !*/
    public:

        explicit auto_unlock (
            const mutex& m
        );
        /*!
            ensures
                - #*this is properly initialized
                - does not modify m in any way
        !*/

        explicit auto_unlock (
            const rmutex& m
        );
        /*!
            ensures
                - #*this is properly initialized
                - does not modify m in any way
        !*/

        explicit auto_unlock (
            const read_write_mutex& m
        );
        /*!
            ensures
                - #*this is properly initialized
                - does not modify m in any way
        !*/

        ~auto_unlock (
        );
        /*!
            ensures
                - all resources allocated by *this have been freed
                - calls unlock() on the mutex associated with *this
        !*/

    private:
        // restricted functions
        auto_unlock(auto_unlock&);        // copy constructor
        auto_unlock& operator=(auto_unlock&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------

    class auto_unlock_readonly
    {
        /*!
            INITIAL VALUE
                The mutex given in the constructor is associated with this object.

            WHAT THIS OBJECT REPRESENTS
                This object represents a mechanism for automatically unlocking
                a read_write_mutex object.  It is useful when you already have a locked mutex
                and want to make sure it gets unlocked even if an exception is thrown
                or you quit the function at a weird spot.  Note that the mutex
                is unlocked by calling unlock_readonly() on it.
        !*/
    public:

        explicit auto_unlock_readonly (
            const read_write_mutex& m
        );
        /*!
            ensures
                - #*this is properly initialized
                - does not modify m in any way
        !*/

        ~auto_unlock_readonly (
        );
        /*!
            ensures
                - all resources allocated by *this have been freed
                - calls unlock_readonly() on the mutex associated with *this
        !*/

    private:
        // restricted functions
        auto_unlock_readonly(auto_unlock_readonly&);        // copy constructor
        auto_unlock_readonly& operator=(auto_unlock_readonly&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_AUTO_UNLOCK_EXTENSIOn_ABSTRACT_


dlib C++ Library - create_new_thread_extension.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_CREATE_NEW_THREAD_EXTENSIOn_
#define DLIB_CREATE_NEW_THREAD_EXTENSIOn_

#include "threads_kernel_abstract.h"
#include "create_new_thread_extension_abstract.h"
#include "../threads.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        void (T::*funct)()
        >
    inline void dlib_create_new_thread_helper (
        void* obj
    )
    {
        T* o = static_cast<T*>(obj);
        (o->*funct)();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        void (T::*funct)()
        >
    inline bool create_new_thread (
        T& obj
    )
    {
        return create_new_thread(dlib_create_new_thread_helper<T,funct>,&obj);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_CREATE_NEW_THREAD_EXTENSIOn_


dlib C++ Library - create_new_thread_extension_abstract.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_CREATE_NEW_THREAD_EXTENSIOn_ABSTRACT_
#ifdef DLIB_CREATE_NEW_THREAD_EXTENSIOn_ABSTRACT_

#include "threads_kernel_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename T,
        void (T::*funct)()
        >
    bool create_new_thread (
        T& obj
    );
    /*!
        ensures
            - creates a new thread and calls obj.*funct() from it.
            - returns true upon success and false upon failure to create the new thread.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_CREATE_NEW_THREAD_EXTENSIOn_ABSTRACT_


dlib C++ Library - multithreaded_object_extension.cpp

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MULTITHREADED_OBJECT_EXTENSIOn_CPP
#define DLIB_MULTITHREADED_OBJECT_EXTENSIOn_CPP

#include "multithreaded_object_extension.h"
#include "create_new_thread_extension.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    multithreaded_object::
    multithreaded_object (
    ):
        s(m_),
        is_running_(false),
        should_stop_(false),
        threads_started(0)
    {
    }

// ----------------------------------------------------------------------------------------

    multithreaded_object::
    ~multithreaded_object (
    )
    {
        try
        {
            DLIB_ASSERT(number_of_threads_alive() == 0,
                   "\tmultithreaded_object::~multithreaded_object()"
                   << "\n\tYou have let a multithreaded object destruct itself before terminating its threads"
                   << "\n\tthis: " << this
            );
        }
        catch (std::exception& e)
        {
            std::cerr << e.what() << std::endl;
            assert(false);
            abort();
        }
    }

// ----------------------------------------------------------------------------------------

    void multithreaded_object::
    clear (
    )
    {
        auto_mutex M(m_);
        stop();
        wait();
        dead_threads.clear();
        is_running_ = false;
        should_stop_ = false;
    }

// ----------------------------------------------------------------------------------------

    bool multithreaded_object::
    is_running (
    ) const
    {
        auto_mutex M(m_);
        return is_running_;
    }

// ----------------------------------------------------------------------------------------

    unsigned long multithreaded_object::
    number_of_threads_registered (
    ) const
    {
        auto_mutex M(m_);
        return thread_ids.size() + dead_threads.size();
    }

// ----------------------------------------------------------------------------------------

    unsigned long multithreaded_object::
    number_of_threads_alive (
    ) const
    {
        auto_mutex M(m_);
        return threads_started;
    }

// ----------------------------------------------------------------------------------------

    void multithreaded_object::
    wait (
    ) const
    {
        auto_mutex M(m_);

        DLIB_ASSERT(thread_ids.is_in_domain(get_thread_id()) == false,
               "\tvoid multithreaded_object::wait()"
               << "\n\tYou can NOT call this function from one of the threads registered in this object"
               << "\n\tthis: " << this
        );

        while (threads_started > 0)
            s.wait();
    }

// ----------------------------------------------------------------------------------------

    void multithreaded_object::
    start (
    )
    {
        auto_mutex M(m_);
        const unsigned long num_threads_registered = dead_threads.size() + thread_ids.size();
        // start any dead threads
        for (unsigned long i = threads_started; i < num_threads_registered; ++i)
        {
            if (create_new_thread<multithreaded_object,&multithreaded_object::thread_helper>(*this) == false)
            {
                should_stop_ = true;
                is_running_ = false;
                throw thread_error();
            }
            ++threads_started;
        }
        is_running_ = true;
        should_stop_ = false;
        s.broadcast();
    }

// ----------------------------------------------------------------------------------------

    void multithreaded_object::
    pause (
    )
    {
        auto_mutex M(m_);
        is_running_ = false;
    }

// ----------------------------------------------------------------------------------------

    void multithreaded_object::
    stop (
    )
    {
        auto_mutex M(m_);
        should_stop_ = true;
        is_running_ = false;
        s.broadcast();
    }

// ----------------------------------------------------------------------------------------

    bool multithreaded_object::
    should_stop (
    ) const
    {
        auto_mutex M(m_);
        DLIB_ASSERT(thread_ids.is_in_domain(get_thread_id()),
               "\tbool multithreaded_object::should_stop()"
               << "\n\tYou can only call this function from one of the registered threads in this object"
               << "\n\tthis: " << this
        );
        while (is_running_ == false && should_stop_ == false)
            s.wait();
        return should_stop_;
    }

// ----------------------------------------------------------------------------------------

    multithreaded_object::raii_thread_helper::
    raii_thread_helper(
        multithreaded_object& self_,
        thread_id_type id_
    ) : self(self_), id(id_){}

    multithreaded_object::raii_thread_helper::
    ~raii_thread_helper()
    {
        auto_mutex M(self.m_);
        if (self.thread_ids.is_in_domain(id))
        {
            mfp temp;
            thread_id_type id_temp;
            self.thread_ids.remove(id,id_temp,temp);
            // put this thread's registered function back into the dead_threads queue
            self.dead_threads.enqueue(temp);
        }

        --self.threads_started;
        // If this is the last thread to terminate then
        // signal that that is the case.
        if (self.threads_started == 0)
        {
            self.is_running_ = false;
            self.should_stop_ = false;
            self.s.broadcast();
        }
    }

// ----------------------------------------------------------------------------------------

    void multithreaded_object::
    thread_helper(
    )
    {
        mfp mf;
        thread_id_type id = get_thread_id();

        // this guy's destructor does all the necessary cleanup in this function
        raii_thread_helper raii(*this, id);

        // if there is a dead_thread sitting around then pull it
        // out and put it into mf
        {
            auto_mutex M(m_);
            if (dead_threads.size() > 0)
            {
                dead_threads.dequeue(mf);
                mfp temp(mf);
                thread_ids.add(id,temp);
            }
        }

        if (mf.is_set())
        {
            // call the registered thread function
            mf();
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MULTITHREADED_OBJECT_EXTENSIOn_CPP


dlib C++ Library - multithreaded_object_extension.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_MULTITHREADED_OBJECT_EXTENSIOn_
#define DLIB_MULTITHREADED_OBJECT_EXTENSIOn_

#include "multithreaded_object_extension_abstract.h"
#include "threads_kernel.h"
#include "auto_mutex_extension.h"
#include "rmutex_extension.h"
#include "rsignaler_extension.h"
#include "../algs.h"
#include "../assert.h"
#include "../map.h"
#include "../member_function_pointer.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class multithreaded_object
    {
        /*!
            INITIAL VALUE
                - is_running_ == false
                - should_stop_ == false
                - thread_ids.size() == 0
                - dead_threads.size() == 0
                - threads_started == 0

            CONVENTION
                - number_of_threads_registered() == thread_ids.size() + dead_threads.size()
                - number_of_threads_alive() == threads_started

                - is_running() == is_running_
                - should_stop() == should_stop_

                - thread_ids == a map of current thread ids to the member function
                  pointers that that thread runs.
                - threads_started == the number of threads that have been spawned to run
                  thread_helper but haven't ended yet.

                - dead_threads == a queue that contains all the member function pointers
                  for threads that are currently registered but not running

                - m_ == the mutex used to protect all our variables
                - s == the signaler for m_
        !*/

    public:

        multithreaded_object (
        );

        virtual ~multithreaded_object (
        ) = 0;

        void clear (
        );

        bool is_running (
        ) const;

        unsigned long number_of_threads_alive (
        ) const;

        unsigned long number_of_threads_registered (
        ) const;

        void wait (
        ) const;

        void start (
        );

        void pause (
        );

        void stop (
        );

    protected:

        bool should_stop (
        ) const;

        template <
            typename T
            >
        void register_thread (
            T& object,
            void (T::*thread)()
        )
        {
            auto_mutex M(m_);
            try
            {
                mfp mf;
                mf.set(object,thread);
                dead_threads.enqueue(mf);
                if (is_running_)
                    start();
            }
            catch (...)
            {
                is_running_ = false;
                should_stop_ = true;
                s.broadcast();
                throw;
            }
        }

    private:

        class raii_thread_helper
        {
        public:
            raii_thread_helper(multithreaded_object& self_, thread_id_type id_);
            ~raii_thread_helper();

            multithreaded_object& self;
            thread_id_type id;
        };

        void thread_helper(
        );

        typedef member_function_pointer<> mfp;

        rmutex m_;
        rsignaler s;
        map<thread_id_type,mfp,memory_manager<char>::kernel_2a>::kernel_1a thread_ids;
        queue<mfp,memory_manager<char>::kernel_2a>::kernel_1a dead_threads;

        bool is_running_;
        bool should_stop_;
        unsigned long threads_started;

        // restricted functions
        multithreaded_object(multithreaded_object&);        // copy constructor
        multithreaded_object& operator=(multithreaded_object&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------

}

#ifdef NO_MAKEFILE
#include "multithreaded_object_extension.cpp"
#endif

#endif // DLIB_MULTITHREADED_OBJECT_EXTENSIOn_


dlib C++ Library - multithreaded_object_extension_abstract.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_MULTITHREADED_OBJECT_EXTENSIOn_ABSTRACT_
#ifdef DLIB_MULTITHREADED_OBJECT_EXTENSIOn_ABSTRACT_

#include "threads_kernel_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class multithreaded_object
    {
        /*!
            INITIAL VALUE
                - is_running() == false
                - number_of_threads_alive() == 0
                - number_of_threads_registered() == 0

            WHAT THIS OBJECT REPRESENTS
                This object represents a multithreaded object.  It is similar to
                the threaded_object except it allows you to have many threads in a
                single object rather than just one.  To use it you inherit from it
                and register the member functions in your new class that you want
                to run in their own threads by calling register_thread().  Then when
                you call start() it will spawn all the registered functions
                in their own threads.
        !*/

    public:

        multithreaded_object (
        );
        /*!
            ensures
                - #*this is properly initialized
            throws
                - std::bad_alloc
                - dlib::thread_error
                    the constructor may throw this exception if there is a problem
                    gathering resources to create threading objects.
        !*/

        virtual ~multithreaded_object (
        ) = 0;
        /*!
            requires
                - number_of_threads_alive() == 0
                  (i.e. in the destructor for the object you derive from this one you
                  must wait for all the threads to end.)
            ensures
                - all resources allocated by *this have been freed.
        !*/

        void clear(
        );
        /*!
            ensures
                - #*this has its initial value
                - blocks until all threads have terminated
            throws
                - std::bad_alloc or dlib::thread_error
                    if an exception is thrown then *this is unusable
                    until clear() is called and succeeds
        !*/

        bool is_running (
        ) const;
        /*!
            ensures
                - if (number_of_threads_alive() > 0 && the threads are currently supposed to be executing) then
                    - returns true
                - else
                    - returns false
        !*/

        unsigned long number_of_threads_alive (
        ) const;
        /*!
            ensures
                - returns the number of threads that are currently alive (i.e.
                  the number of threads that have started but not yet terminated)
        !*/

        unsigned long number_of_threads_registered (
        ) const;
        /*!
            ensures
                - returns the number of threads that have been registered by
                  calls to register_thread()
        !*/

        void wait (
        ) const;
        /*!
            requires
                - is not called from one of this object's threads
            ensures
                - if (number_of_threads_alive() > 0) then
                    - blocks until all the threads in this object have terminated
                      (i.e. blocks until number_of_threads_alive() == 0)
        !*/

        void start (
        );
        /*!
            ensures
                - #number_of_threads_alive() == number_of_threads_registered()
                - #is_running() == true
                - #should_stop() == false
                - all the threads registered are up and running.
            throws
                - std::bad_alloc or dlib::thread_error
                    If either of these exceptions are thrown then
                    #is_running() == false and should_stop() == true
        !*/

        void pause (
        );
        /*!
            ensures
                - #is_running() == false
        !*/

        void stop (
        );
        /*!
            ensures
                - #should_stop() == true
                - #is_running() == false
        !*/

    protected:

        template <
            typename T
            >
        void register_thread (
            T& object,
            void (T::*thread)()
        );
        /*!
            requires
                - (object.*thread)() forms a valid function call
                - the thread function does not throw
            ensures
                - registers the member function pointed to by thread as one of the threads
                  that runs when is_running() == true
                - #number_of_threads_registered() == number_of_threads_registered() + 1
                - if (is_running() == true)
                    - spawns this new member function in its own thread
                    - #number_of_threads_alive() += number_of_threads_alive() + 1
            throws
                - std::bad_alloc or dlib::thread_error
                    If either of these exceptions are thrown then
                    #is_running() == false and should_stop() == true
        !*/

        bool should_stop (
        ) const;
        /*!
            requires
                - is only called from one of the registered threads in this object
            ensures
                - if (is_running() == false && should_stop() == false) then
                    - blocks until (#is_running() == true || #should_stop() == true)
                - if (this thread is supposed to terminate) then
                    - returns true
                - else
                    - returns false
        !*/

    private:

        // restricted functions
        multithreaded_object(multithreaded_object&);        // copy constructor
        multithreaded_object& operator=(multithreaded_object&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MULTITHREADED_OBJECT_EXTENSIOn_ABSTRACT_


dlib C++ Library - parallel_for_extension.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_PARALLEL_FoR_Hh_
#define DLIB_PARALLEL_FoR_Hh_

#include "parallel_for_extension_abstract.h"
#include "thread_pool_extension.h"
#include "../console_progress_indicator.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    namespace impl
    {

        template <typename T>
        class helper_parallel_for
        {
        public:
            helper_parallel_for (
                T& obj_,
                void (T::*funct_)(long)
            ) :
                obj(obj_),
                funct(funct_)
            {}

            T& obj;
            void (T::*funct)(long);

            void process_block (long begin, long end)
            {
                for (long i = begin; i < end; ++i)
                    (obj.*funct)(i);
            }
        };

        template <typename T>
        class helper_parallel_for_funct
        {
        public:
            helper_parallel_for_funct (
                const T& funct_
            ) : funct(funct_) {}

            const T& funct;

            void run(long i)
            {
                funct(i);
            }
        };

        template <typename T>
        class helper_parallel_for_funct2
        {
        public:
            helper_parallel_for_funct2 (
                const T& funct_
            ) : funct(funct_) {}

            const T& funct;

            void run(long begin, long end)
            {
                funct(begin, end);
            }
        };
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <typename T>
    void parallel_for_blocked (
        thread_pool& tp,
        long begin,
        long end,
        T& obj,
        void (T::*funct)(long, long),
        long chunks_per_thread = 8
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(begin <= end && chunks_per_thread > 0,
            "\t void parallel_for_blocked()"
            << "\n\t Invalid inputs were given to this function"
            << "\n\t begin: " << begin
            << "\n\t end:   " << end
            << "\n\t chunks_per_thread: " << chunks_per_thread
            );

        if (tp.num_threads_in_pool() != 0)
        {
            const long num = end-begin;
            const long num_workers = static_cast<long>(tp.num_threads_in_pool());
            // How many samples to process in a single task (aim for chunks_per_thread jobs per worker)
            const long block_size = std::max(1L, num/(num_workers*chunks_per_thread));
            for (long i = 0; i < num; i+=block_size)
            {
                tp.add_task(obj, funct, begin+i, begin+std::min(i+block_size, num));
            }
            tp.wait_for_all_tasks();
        }
        else
        {
            // Since there aren't any threads in the pool we might as well just invoke
            // the function directly since that's all the thread_pool object would do.
            // But doing it ourselves skips a mutex lock.
            (obj.*funct)(begin, end);
        }
    }

// ----------------------------------------------------------------------------------------

    template <typename T>
    void parallel_for_blocked (
        unsigned long num_threads,
        long begin,
        long end,
        T& obj,
        void (T::*funct)(long, long),
        long chunks_per_thread = 8
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(begin <= end && chunks_per_thread > 0,
            "\t void parallel_for_blocked()"
            << "\n\t Invalid inputs were given to this function"
            << "\n\t begin: " << begin
            << "\n\t end:   " << end
            << "\n\t chunks_per_thread: " << chunks_per_thread
            );

        thread_pool tp(num_threads);
        parallel_for_blocked(tp, begin, end, obj, funct, chunks_per_thread);
    }

// ----------------------------------------------------------------------------------------

    template <typename T>
    void parallel_for_blocked (
        thread_pool& tp,
        long begin,
        long end,
        const T& funct,
        long chunks_per_thread = 8
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(begin <= end && chunks_per_thread > 0,
            "\t void parallel_for_blocked()"
            << "\n\t Invalid inputs were given to this function"
            << "\n\t begin: " << begin
            << "\n\t end:   " << end
            << "\n\t chunks_per_thread: " << chunks_per_thread
            );

        impl::helper_parallel_for_funct2<T> helper(funct);
        parallel_for_blocked(tp, begin, end,  helper, &impl::helper_parallel_for_funct2<T>::run,  chunks_per_thread);
    }

// ----------------------------------------------------------------------------------------

    template <typename T>
    void parallel_for_blocked (
        unsigned long num_threads,
        long begin,
        long end,
        const T& funct,
        long chunks_per_thread = 8
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(begin <= end && chunks_per_thread > 0,
            "\t void parallel_for_blocked()"
            << "\n\t Invalid inputs were given to this function"
            << "\n\t begin: " << begin
            << "\n\t end:   " << end
            << "\n\t chunks_per_thread: " << chunks_per_thread
            );

        thread_pool tp(num_threads);
        parallel_for_blocked(tp, begin, end, funct, chunks_per_thread);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <typename T>
    void parallel_for (
        thread_pool& tp,
        long begin,
        long end,
        T& obj,
        void (T::*funct)(long),
        long chunks_per_thread = 8
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(begin <= end && chunks_per_thread > 0,
            "\t void parallel_for()"
            << "\n\t Invalid inputs were given to this function"
            << "\n\t begin: " << begin
            << "\n\t end:   " << end
            << "\n\t chunks_per_thread: " << chunks_per_thread
            );

        impl::helper_parallel_for<T> helper(obj, funct);
        parallel_for_blocked(tp, begin, end, helper, &impl::helper_parallel_for<T>::process_block, chunks_per_thread);
    }

// ----------------------------------------------------------------------------------------

    template <typename T>
    void parallel_for (
        unsigned long num_threads,
        long begin,
        long end,
        T& obj,
        void (T::*funct)(long),
        long chunks_per_thread = 8
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(begin <= end && chunks_per_thread > 0,
            "\t void parallel_for()"
            << "\n\t Invalid inputs were given to this function"
            << "\n\t begin: " << begin
            << "\n\t end:   " << end
            << "\n\t chunks_per_thread: " << chunks_per_thread
            );

        thread_pool tp(num_threads);
        parallel_for(tp, begin, end, obj, funct, chunks_per_thread);
    }

// ----------------------------------------------------------------------------------------

    template <typename T>
    void parallel_for (
        thread_pool& tp,
        long begin,
        long end,
        const T& funct,
        long chunks_per_thread = 8
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(begin <= end && chunks_per_thread > 0,
            "\t void parallel_for()"
            << "\n\t Invalid inputs were given to this function"
            << "\n\t begin: " << begin
            << "\n\t end:   " << end
            << "\n\t chunks_per_thread: " << chunks_per_thread
            );

        impl::helper_parallel_for_funct<T> helper(funct);
        parallel_for(tp, begin, end,  helper, &impl::helper_parallel_for_funct<T>::run,  chunks_per_thread);
    }

// ----------------------------------------------------------------------------------------

    template <typename T>
    void parallel_for (
        unsigned long num_threads,
        long begin,
        long end,
        const T& funct,
        long chunks_per_thread = 8
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(begin <= end && chunks_per_thread > 0,
            "\t void parallel_for()"
            << "\n\t Invalid inputs were given to this function"
            << "\n\t begin: " << begin
            << "\n\t end:   " << end
            << "\n\t chunks_per_thread: " << chunks_per_thread
            );

        thread_pool tp(num_threads);
        parallel_for(tp, begin, end, funct, chunks_per_thread);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    namespace impl
    {
        template <typename T>
        class parfor_verbose_helper
        {
        public:
            parfor_verbose_helper(T& obj_, void (T::*funct_)(long), long begin, long end) :
                obj(obj_), funct(funct_), pbar(end-begin)
            {
                count = 0;
                wrote_to_screen = pbar.print_status(0);
            }

            ~parfor_verbose_helper()
            {
                if (wrote_to_screen)
                    std::cout << std::endl;
            }

            mutable long count;
            T& obj;
            void (T::*funct)(long);
            mutable console_progress_indicator pbar;
            mutable bool wrote_to_screen;
            mutex m;

            void operator()(long i) const
            {
                (obj.*funct)(i);
                {
                    auto_mutex lock(m);
                    wrote_to_screen = pbar.print_status(++count) || wrote_to_screen;
                }
            }

        };

        template <typename T>
        class parfor_verbose_helper3
        {
        public:
            parfor_verbose_helper3(T& obj_, void (T::*funct_)(long,long), long begin, long end) :
                obj(obj_), funct(funct_), pbar(end-begin)
            {
                count = 0;
                wrote_to_screen = pbar.print_status(0);
            }

            ~parfor_verbose_helper3()
            {
                if (wrote_to_screen)
                    std::cout << std::endl;
            }

            mutable long count;
            T& obj;
            void (T::*funct)(long,long);
            mutable console_progress_indicator pbar;
            mutable bool wrote_to_screen;
            mutex m;

            void operator()(long begin, long end) const
            {
                (obj.*funct)(begin, end);
                {
                    auto_mutex lock(m);
                    count += end-begin;
                    wrote_to_screen = pbar.print_status(count) || wrote_to_screen;
                }
            }
        };

        template <typename T>
        class parfor_verbose_helper2
        {
        public:
            parfor_verbose_helper2(const T& obj_, long begin, long end) : obj(obj_), pbar(end-begin)
            {
                count = 0;
                wrote_to_screen = pbar.print_status(0);
            }

            ~parfor_verbose_helper2()
            {
                if (wrote_to_screen)
                    std::cout << std::endl;
            }

            mutable long count;
            const T& obj;
            mutable console_progress_indicator pbar;
            mutable bool wrote_to_screen;
            mutex m;

            void operator()(long i) const
            {
                obj(i);
                {
                    auto_mutex lock(m);
                    wrote_to_screen = pbar.print_status(++count) || wrote_to_screen;
                }
            }

            void operator()(long begin, long end) const
            {
                obj(begin, end);
                {
                    auto_mutex lock(m);
                    count += end-begin;
                    wrote_to_screen = pbar.print_status(count) || wrote_to_screen;
                }
            }
        };
    }

    template <typename T>
    void parallel_for_verbose (
        thread_pool& tp,
        long begin,
        long end,
        T& obj,
        void (T::*funct)(long),
        long chunks_per_thread = 8
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(begin <= end && chunks_per_thread > 0,
            "\t void parallel_for_verbose()"
            << "\n\t Invalid inputs were given to this function"
            << "\n\t begin: " << begin
            << "\n\t end:   " << end
            << "\n\t chunks_per_thread: " << chunks_per_thread
            );

        impl::parfor_verbose_helper<T> helper(obj, funct, begin, end);
        parallel_for(tp, begin, end, helper, chunks_per_thread);
    }

// ----------------------------------------------------------------------------------------

    template <typename T>
    void parallel_for_verbose (
        unsigned long num_threads,
        long begin,
        long end,
        T& obj,
        void (T::*funct)(long),
        long chunks_per_thread = 8
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(begin <= end && chunks_per_thread > 0,
            "\t void parallel_for_verbose()"
            << "\n\t Invalid inputs were given to this function"
            << "\n\t begin: " << begin
            << "\n\t end:   " << end
            << "\n\t chunks_per_thread: " << chunks_per_thread
            );

        impl::parfor_verbose_helper<T> helper(obj, funct, begin, end);
        parallel_for(num_threads, begin, end, helper, chunks_per_thread);
    }

// ----------------------------------------------------------------------------------------

    template <typename T>
    void parallel_for_verbose (
        thread_pool& tp,
        long begin,
        long end,
        const T& funct,
        long chunks_per_thread = 8
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(begin <= end && chunks_per_thread > 0,
            "\t void parallel_for_verbose()"
            << "\n\t Invalid inputs were given to this function"
            << "\n\t begin: " << begin
            << "\n\t end:   " << end
            << "\n\t chunks_per_thread: " << chunks_per_thread
            );

        impl::parfor_verbose_helper2<T> helper(funct, begin, end);
        parallel_for(tp, begin, end,  helper, chunks_per_thread);
    }

// ----------------------------------------------------------------------------------------

    template <typename T>
    void parallel_for_verbose (
        unsigned long num_threads,
        long begin,
        long end,
        const T& funct,
        long chunks_per_thread = 8
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(begin <= end && chunks_per_thread > 0,
            "\t void parallel_for_verbose()"
            << "\n\t Invalid inputs were given to this function"
            << "\n\t begin: " << begin
            << "\n\t end:   " << end
            << "\n\t chunks_per_thread: " << chunks_per_thread
            );

        impl::parfor_verbose_helper2<T> helper(funct, begin, end);
        parallel_for(num_threads, begin, end, helper, chunks_per_thread);
    }

// ----------------------------------------------------------------------------------------

    template <typename T>
    void parallel_for_blocked_verbose (
        thread_pool& tp,
        long begin,
        long end,
        T& obj,
        void (T::*funct)(long,long),
        long chunks_per_thread = 8
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(begin <= end && chunks_per_thread > 0,
            "\t void parallel_for_blocked_verbose()"
            << "\n\t Invalid inputs were given to this function"
            << "\n\t begin: " << begin
            << "\n\t end:   " << end
            << "\n\t chunks_per_thread: " << chunks_per_thread
            );

        impl::parfor_verbose_helper3<T> helper(obj, funct, begin, end);
        parallel_for_blocked(tp, begin, end, helper, chunks_per_thread);
    }

// ----------------------------------------------------------------------------------------

    template <typename T>
    void parallel_for_blocked_verbose (
        unsigned long num_threads,
        long begin,
        long end,
        T& obj,
        void (T::*funct)(long,long),
        long chunks_per_thread = 8
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(begin <= end && chunks_per_thread > 0,
            "\t void parallel_for_blocked_verbose()"
            << "\n\t Invalid inputs were given to this function"
            << "\n\t begin: " << begin
            << "\n\t end:   " << end
            << "\n\t chunks_per_thread: " << chunks_per_thread
            );

        impl::parfor_verbose_helper3<T> helper(obj, funct, begin, end);
        parallel_for_blocked(num_threads, begin, end, helper, chunks_per_thread);
    }

// ----------------------------------------------------------------------------------------

    template <typename T>
    void parallel_for_blocked_verbose (
        thread_pool& tp,
        long begin,
        long end,
        const T& funct,
        long chunks_per_thread = 8
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(begin <= end && chunks_per_thread > 0,
            "\t void parallel_for_blocked_verbose()"
            << "\n\t Invalid inputs were given to this function"
            << "\n\t begin: " << begin
            << "\n\t end:   " << end
            << "\n\t chunks_per_thread: " << chunks_per_thread
            );

        impl::parfor_verbose_helper2<T> helper(funct, begin, end);
        parallel_for_blocked(tp, begin, end,  helper, chunks_per_thread);
    }

// ----------------------------------------------------------------------------------------

    template <typename T>
    void parallel_for_blocked_verbose (
        unsigned long num_threads,
        long begin,
        long end,
        const T& funct,
        long chunks_per_thread = 8
    )
    {
        // make sure requires clause is not broken
        DLIB_ASSERT(begin <= end && chunks_per_thread > 0,
            "\t void parallel_for_blocked_verbose()"
            << "\n\t Invalid inputs were given to this function"
            << "\n\t begin: " << begin
            << "\n\t end:   " << end
            << "\n\t chunks_per_thread: " << chunks_per_thread
            );

        impl::parfor_verbose_helper2<T> helper(funct, begin, end);
        parallel_for_blocked(num_threads, begin, end, helper, chunks_per_thread);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_PARALLEL_FoR_Hh_


dlib C++ Library - parallel_for_extension_abstract.h

// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_PARALLEL_FoR_ABSTRACT_Hh_
#ifdef DLIB_PARALLEL_FoR_ABSTRACT_Hh_

#include "thread_pool_extension_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <typename T>
    void parallel_for_blocked (
        thread_pool& tp,
        long begin,
        long end,
        T& obj,
        void (T::*funct)(long, long),
        long chunks_per_thread = 8
    );
    /*!
        requires
            - begin <= end
            - chunks_per_thread > 0
            - funct does not throw any exceptions
        ensures
            - This is a convenience function for submitting a block of jobs to a thread_pool.
              In particular, given the half open range [begin, end), this function will
              split the range into approximately tp.num_threads_in_pool()*chunks_per_thread
              blocks, which it will then submit to the thread_pool.  The given thread_pool
              will then call (obj.*funct)() on each of the subranges.
            - To be precise, suppose we have broken the range [begin, end) into the
              following subranges:
                - [begin[0], end[0])
                - [begin[1], end[1])
                - [begin[2], end[2])
                  ...
                - [begin[n], end[n])
              Then parallel_for_blocked() submits each of these subranges to tp for
              processing such that (obj.*funct)(begin[i], end[i]) is invoked for all valid
              values of i.  Moreover, the subranges are non-overlapping and completely
              cover the total range of [begin, end).
            - This function will not perform any memory allocations or create any system
              resources such as mutex objects.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    void parallel_for_blocked (
        unsigned long num_threads,
        long begin,
        long end,
        T& obj,
        void (T::*funct)(long, long),
        long chunks_per_thread = 8
    );
    /*!
        requires
            - begin <= end
            - chunks_per_thread > 0
            - funct does not throw any exceptions
        ensures
            - This function is equivalent to the following block of code:
                thread_pool tp(num_threads);
                parallel_for_blocked(tp, begin, end, obj, funct, chunks_per_thread);
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    void parallel_for_blocked (
        thread_pool& tp,
        long begin,
        long end,
        const T& funct,
        long chunks_per_thread = 8
    );
    /*!
        requires
            - chunks_per_thread > 0
            - begin <= end
            - funct does not throw any exceptions
        ensures
            - This is a convenience function for submitting a block of jobs to a
              thread_pool.  In particular, given the range [begin, end), this function will
              split the range into approximately tp.num_threads_in_pool()*chunks_per_thread
              blocks, which it will then submit to the thread_pool.  The given thread_pool
              will then call funct() on each of the subranges.
            - To be precise, suppose we have broken the range [begin, end) into the
              following subranges:
                - [begin[0], end[0])
                - [begin[1], end[1])
                - [begin[2], end[2])
                  ...
                - [begin[n], end[n])
              Then parallel_for_blocked() submits each of these subranges to tp for
              processing such that funct(begin[i], end[i]) is invoked for all valid values
              of i.
            - This function will not perform any memory allocations or create any system
              resources such as mutex objects.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    void parallel_for_blocked (
        unsigned long num_threads,
        long begin,
        long end,
        const T& funct,
        long chunks_per_thread = 8
    );
    /*!
        requires
            - begin <= end
            - chunks_per_thread > 0
            - funct does not throw any exceptions
        ensures
            - This function is equivalent to the following block of code:
                thread_pool tp(num_threads);
                parallel_for_blocked(tp, begin, end, funct, chunks_per_thread);
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <typename T>
    void parallel_for (
        thread_pool& tp,
        long begin,
        long end,
        T& obj,
        void (T::*funct)(long),
        long chunks_per_thread = 8
    );
    /*!
        requires
            - begin <= end
            - chunks_per_thread > 0
            - funct does not throw any exceptions
        ensures
            - This function is equivalent to the following function call:
              parallel_for_blocked(tp, begin, end, [&](long begin_sub, long end_sub)
                {
                  for (long i = begin_sub; i < end_sub; ++i)
                      (obj.*funct)(i);
                }, chunks_per_thread);
            - Therefore, this routine invokes (obj.*funct)(i) for all i in the range
              [begin, end).  However, it does so using tp.num_threads_in_pool() parallel
              threads.
            - This function will not perform any memory allocations or create any system
              resources such as mutex objects.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    void parallel_for (
        unsigned long num_threads,
        long begin,
        long end,
        T& obj,
        void (T::*funct)(long),
        long chunks_per_thread = 8
    );
    /*!
        requires
            - begin <= end
            - chunks_per_thread > 0
            - funct does not throw any exceptions
        ensures
            - This function is equivalent to the following block of code:
                thread_pool tp(num_threads);
                parallel_for(tp, begin, end, obj, funct, chunks_per_thread);
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    void parallel_for (
        thread_pool& tp,
        long begin,
        long end,
        const T& funct,
        long chunks_per_thread = 8
    );
    /*!
        requires
            - begin <= end
            - chunks_per_thread > 0
            - funct does not throw any exceptions
        ensures
            - This function is equivalent to the following function call:
              parallel_for_blocked(tp, begin, end, [&](long begin_sub, long end_sub)
                {
                  for (long i = begin_sub; i < end_sub; ++i)
                      funct(i);
                }, chunks_per_thread);
            - Therefore, this routine invokes funct(i) for all i in the range [begin, end).
              However, it does so using tp.num_threads_in_pool() parallel threads.
            - This function will not perform any memory allocations or create any system
              resources such as mutex objects.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    void parallel_for (
        unsigned long num_threads,
        long begin,
        long end,
        const T& funct,
        long chunks_per_thread = 8
    );
    /*!
        requires
            - begin <= end
            - chunks_per_thread > 0
            - funct does not throw any exceptions
        ensures
            - This function is equivalent to the following block of code:
                thread_pool tp(num_threads);
                parallel_for(tp, begin, end, funct, chunks_per_thread);
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <typename T>
    void parallel_for_verbose (
        thread_pool& tp,
        long begin,
        long end,
        T& obj,
        void (T::*funct)(long),
        long chunks_per_thread = 8
    );
    /*!
        requires
            - begin <= end
            - chunks_per_thread > 0
            - funct does not throw any exceptions
        ensures
            - This function is identical to the parallel_for() routine defined above except
              that it will print messages to cout showing the progress in executing the
              parallel for loop.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    void parallel_for_verbose (
        unsigned long num_threads,
        long begin,
        long end,
        T& obj,
        void (T::*funct)(long),
        long chunks_per_thread = 8
    );
    /*!
        requires
            - begin <= end
            - chunks_per_thread > 0
            - funct does not throw any exceptions
        ensures
            - This function is identical to the parallel_for() routine defined above except
              that it will print messages to cout showing the progress in executing the
              parallel for loop.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    void parallel_for_verbose (
        thread_pool& tp,
        long begin,
        long end,
        const T& funct,
        long chunks_per_thread = 8
    );
    /*!
        requires
            - begin <= end
            - chunks_per_thread > 0
            - funct does not throw any exceptions
        ensures
            - This function is identical to the parallel_for() routine defined above except
              that it will print messages to cout showing the progress in executing the
              parallel for loop.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    void parallel_for_verbose (
        unsigned long num_threads,
        long begin,
        long end,
        const T& funct,
        long chunks_per_thread = 8
    );
    /*!
        requires
            - begin <= end
            - chunks_per_thread > 0
            - funct does not throw any exceptions
        ensures
            - This function is identical to the parallel_for() routine defined above except
              that it will print messages to cout showing the progress in executing the
              parallel for loop.
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <typename T>
    void parallel_for_blocked_verbose (
        thread_pool& tp,
        long begin,
        long end,
        T& obj,
        void (T::*funct)(long,long),
        long chunks_per_thread = 8
    );
    /*!
        requires
            - begin <= end
            - chunks_per_thread > 0
            - funct does not throw any exceptions
        ensures
            - This function is identical to the parallel_for_blocked() routine defined
              above except that it will print messages to cout showing the progress in
              executing the parallel for loop.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    void parallel_for_blocked_verbose (
        unsigned long num_threads,
        long begin,
        long end,
        T& obj,
        void (T::*funct)(long,long),
        long chunks_per_thread = 8
    );
    /*!
        requires
            - begin <= end
            - chunks_per_thread > 0
            - funct does not throw any exceptions
        ensures
            - This function is identical to the parallel_for_blocked() routine defined
              above except that it will print messages to cout showing the progress in
              executing the parallel for loop.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    void parallel_for_blocked_verbose (
        thread_pool& tp,
        long begin,
        long end,
        const T& funct,
        long chunks_per_thread = 8
    );
    /*!
        requires
            - begin <= end
            - chunks_per_thread > 0
            - funct does not throw any exceptions
        ensures
            - This function is identical to the parallel_for_blocked() routine defined
              above except that it will print messages to cout showing the progress in
              executing the parallel for loop.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    void parallel_for_blocked_verbose (
        unsigned long num_threads,
        long begin,
        long end,
        const T& funct,
        long chunks_per_thread = 8
    );
    /*!
        requires
            - begin <= end
            - chunks_per_thread > 0
            - funct does not throw any exceptions
        ensures
            - This function is identical to the parallel_for_blocked() routine defined
              above except that it will print messages to cout showing the progress in
              executing the parallel for loop.
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_PARALLEL_FoR_ABSTRACT_Hh_


dlib C++ Library - posix.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_THREADS_KERNEl_1_
#include "threads_kernel_2.h"
#endif


dlib C++ Library - read_write_mutex_extension.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_READ_WRITE_MUTEX_EXTENSIOn_
#define DLIB_READ_WRITE_MUTEX_EXTENSIOn_

#include "threads_kernel.h"
#include "read_write_mutex_extension_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class read_write_mutex
    {
        /*!
            INITIAL VALUE
                - max_locks == defined by constructor
                - available_locks == max_locks
                - write_lock_in_progress == false
                - write_lock_active == false

            CONVENTION
                - Each time someone gets a read only lock they take one of the "available locks"
                  and each write lock takes all possible locks (i.e. max_locks).  The number of
                  available locks is recorded in available_locks.  Any time you try to lock this
                  object and there aren't available locks you have to wait.

                - max_locks == max_readonly_locks()

                - if (some thread is on the process of obtaining a write lock) then
                    - write_lock_in_progress == true
                - else
                    - write_lock_in_progress == false

                - if (some thread currently has a write lock on this mutex) then
                    - write_lock_active == true
                - else
                    - write_lock_active == false
        !*/

    public:

        read_write_mutex (
        ) : s(m),
            max_locks(0xFFFFFFFF),
            available_locks(max_locks),
            write_lock_in_progress(false),
            write_lock_active(false)
        {}

        explicit read_write_mutex (
            unsigned long max_locks_
        ) : s(m),
            max_locks(max_locks_),
            available_locks(max_locks_),
            write_lock_in_progress(false),
            write_lock_active(false)
        {
            // make sure requires clause is not broken
            DLIB_ASSERT(max_locks > 0,
                "\t read_write_mutex::read_write_mutex(max_locks)"
                << "\n\t You must give a non-zero value for max_locks"
                << "\n\t this: " << this
                );
        }

        ~read_write_mutex (
        )
        {}

        void lock (
        ) const
        {
            m.lock();

            // If another write lock is already in progress then wait for it to finish
            // before we start trying to grab all the available locks.  This way we
            // don't end up fighting over the locks.
            while (write_lock_in_progress)
                s.wait();

            // grab the right to perform a write lock
            write_lock_in_progress = true;

            // now start grabbing all the locks
            unsigned long locks_obtained = available_locks;
            available_locks = 0;
            while (locks_obtained != max_locks)
            {
                s.wait();
                locks_obtained += available_locks;
                available_locks = 0;
            }

            write_lock_in_progress = false;
            write_lock_active = true;

            m.unlock();
        }

        void unlock (
        ) const
        {
            m.lock();

            // only do something if there really was a lock in place
            if (write_lock_active)
            {
                available_locks = max_locks;
                write_lock_active = false;
                s.broadcast();
            }

            m.unlock();
        }

        void lock_readonly (
        ) const
        {
            m.lock();

            while (available_locks == 0)
                s.wait();

            --available_locks;

            m.unlock();
        }

        void unlock_readonly (
        ) const
        {
            m.lock();

            // If this condition is false then it means there are no more readonly locks
            // to free.  So we don't do anything.
            if (available_locks != max_locks && !write_lock_active)
            {
                ++available_locks;

                // only perform broadcast when there is another thread that might be listening
                if (available_locks == 1 || write_lock_in_progress)
                {
                    s.broadcast();
                }
            }

            m.unlock();
        }

        unsigned long max_readonly_locks (
        ) const
        {
            return max_locks;
        }

    private:
        mutex m;
        signaler s;
        const unsigned long max_locks;
        mutable unsigned long available_locks;
        mutable bool write_lock_in_progress;
        mutable bool write_lock_active;

        // restricted functions
        read_write_mutex(read_write_mutex&);        // copy constructor
        read_write_mutex& operator=(read_write_mutex&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_READ_WRITE_MUTEX_EXTENSIOn_


dlib C++ Library - read_write_mutex_extension_abstract.h

// Copyright (C) 2010  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_READWRITE_MUTEX_EXTENSIOn_ABSTRACT_
#ifdef DLIB_READWRITE_MUTEX_EXTENSIOn_ABSTRACT_

#include "threads_kernel_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class read_write_mutex
    {
        /*!
            INITIAL VALUE
                read_write_mutex is in the fully unlocked state

            WHAT THIS OBJECT REPRESENTS
                This object represents a mutex intended to be used for synchronous
                thread control of shared data. When a thread wants to access some
                shared data it locks out other threads by calling lock() and calls
                unlock() when it is finished.

                This mutex also has the additional ability to distinguish between
                a lock for the purposes of modifying some shared data, a write lock,
                and a lock for the purposes of only reading shared data, a readonly
                lock.  The lock() and unlock() functions are used for write locks while
                the lock_readonly() and unlock_readonly() are for readonly locks.

                The difference between a readonly and write lock can be understood as
                follows.  The read_write_mutex will allow many threads to obtain simultaneous
                readonly locks but will only allow a single thread to obtain a write lock.
                Moreover, while the write lock is obtained no other threads are allowed
                to have readonly locks.
        !*/
    public:

        read_write_mutex (
        );
        /*!
            ensures
                - #*this is properly initialized
                - max_readonly_locks() == 0xFFFFFFFF
                  (i.e. about 4 billion)
            throws
                - dlib::thread_error
                    the constructor may throw this exception if there is a problem
                    gathering resources to create the read_write_mutex.
        !*/

        explicit read_write_mutex (
            unsigned long max_locks
        );
        /*!
            requires
                - max_locks > 0
            ensures
                - #*this is properly initialized
                - max_readonly_locks() == max_locks
            throws
                - dlib::thread_error
                    the constructor may throw this exception if there is a problem
                    gathering resources to create the read_write_mutex.
        !*/

        ~read_write_mutex (
        );
        /*!
            requires
                - *this is not locked
            ensures
                - all resources allocated by *this have been freed
        !*/

        void lock (
        ) const;
        /*!
            requires
                - The thread calling this function does not have any kind of lock on this
                  object
            ensures
                - if (there is any kind of lock on *this) then
                    - the calling thread is put to sleep until a write lock becomes available.
                      Once available, a write lock is obtained on this mutex and this function
                      terminates.
                - else
                    - a write lock is obtained on this mutex and the calling thread is not put to sleep
        !*/

        void unlock (
        ) const;
        /*!
            ensures
                - if (there is a write lock on *this) then
                    - #*this is unlocked (i.e. other threads may now lock this object)
                - else
                    - the call to unlock() has no effect
        !*/

        unsigned long max_readonly_locks (
        ) const;
        /*!
            ensures
                - returns the maximum number of concurrent readonly locks this object will allow.
        !*/

        void lock_readonly (
        ) const;
        /*!
            requires
                - The thread calling this function does not already have a write
                  lock on this object
            ensures
                - if (there is a write lock on *this or there are no free readonly locks) then
                    - the calling thread is put to sleep until there is no longer a write lock
                      and a free readonly lock is available.  Once this is the case, a readonly
                      lock is obtained and this function terminates.
                - else
                    - a readonly lock is obtained on *this and the calling thread is not put
                      to sleep.  Note that multiple readonly locks can be obtained at once.
        !*/

        void unlock_readonly (
        ) const;
        /*!
            ensures
                - if (there is a readonly lock on *this) then
                    - one readonly lock is removed from *this.
                - else
                    - the call to unlock_readonly() has no effect.
        !*/

    private:
        // restricted functions
        read_write_mutex(read_write_mutex&);        // copy constructor
        read_write_mutex& operator=(read_write_mutex&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_READWRITE_MUTEX_EXTENSIOn_ABSTRACT_


dlib C++ Library - rmutex_extension.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_RMUTEX_EXTENSIOn_
#define DLIB_RMUTEX_EXTENSIOn_

#include "threads_kernel.h"
#include "rmutex_extension_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class rmutex
    {
        /*!
            INITIAL VALUE
                count == 0
                thread_id == 0

            CONVENTION
                - count == lock_count()

                - if (no thread currently has a lock on this mutex) then
                    - count == 0
                - else
                    - count == the number of times the thread that owns this mutex has
                      called lock()
                    - thread_id == the id of this thread.
        !*/
    public:

        rmutex (
        ) : s(m),
            thread_id(0),
            count(0)
        {}

        ~rmutex (
        )
        {}

        unsigned long lock_count (
        ) const
        {
            return count;
        }

        void lock (
            unsigned long times = 1
        ) const
        {
            const thread_id_type current_thread_id = get_thread_id();
            m.lock();
            if (thread_id == current_thread_id)
            {
                // we already own this mutex in this case
                count += times;
            }
            else
            {
                // wait for our turn to claim this rmutex
                while (count != 0)
                    s.wait();

                count = times;
                thread_id = current_thread_id;
            }
            m.unlock();
        }

        void unlock (
            unsigned long times = 1
        ) const
        {
            const thread_id_type current_thread_id = get_thread_id();
            m.lock();
            if (thread_id == current_thread_id)
            {
                if (count <= times)
                {
                    count = 0;
                    s.signal();
                }
                else
                {
                    count -= times;
                }
            }
            m.unlock();
        }

    private:
        mutex m;
        signaler s;
        mutable thread_id_type thread_id;
        mutable unsigned long count;

        // restricted functions
        rmutex(rmutex&);        // copy constructor
        rmutex& operator=(rmutex&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_RMUTEX_EXTENSIOn_


dlib C++ Library - rmutex_extension_abstract.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_RMUTEX_EXTENSIOn_ABSTRACT_
#ifdef DLIB_RMUTEX_EXTENSIOn_ABSTRACT_

#include "threads_kernel_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class rmutex
    {
        /*!
            INITIAL VALUE
                rmutex is in the unlocked state

            WHAT THIS OBJECT REPRESENTS
                This object represents a recursive mutex intended to be used for synchronous
                thread control of shared data. When a thread wants to access some
                shared data it locks out other threads by calling lock() and calls
                unlock() when it is finished.

                The difference between this and the normal mutex object is that it is safe to
                call lock() from a thread that already has a lock on this mutex.  Doing
                so just increments a counter but otherwise has no effect on the mutex.
                Note that unlock() must be called for each call to lock() to release the
                mutex.
        !*/
    public:

        rmutex (
        );
        /*!
            ensures
                - #*this is properly initialized
            throws
                - dlib::thread_error
                    the constructor may throw this exception if there is a problem
                    gathering resources to create the rmutex.
        !*/

        ~rmutex (
        );
        /*!
            requires
                - *this is not locked
            ensures
                - all resources allocated by *this have been freed
        !*/

        unsigned long lock_count (
        ) const;
        /*!
            requires
                - the calling thread has a lock on this mutex
            ensures
                - returns the number of times the thread has called lock()
        !*/

        void lock (
            unsigned long times = 1
        ) const;
        /*!
            ensures
                - if (*this is currently locked by another thread) then
                    - the thread that called lock() on *this is put to sleep until
                      it becomes available.
                    - #lock_count() == times
                - if (*this is currently unlocked) then
                    - #*this becomes locked and the current thread is NOT put to sleep
                      but now "owns" #*this
                    - #lock_count() == times
                - if (*this is locked and owned by the current thread) then
                    - the calling thread retains its lock on *this and isn't put to sleep.
                    - #lock_count() == lock_count() + times
        !*/

        void unlock (
            unsigned long times = 1
        ) const;
        /*!
            ensures
                - if (*this is currently locked and owned by the thread calling unlock) then
                    - if (lock_count() <= times ) then
                        - #*this is unlocked (i.e. other threads may now lock this object)
                    - else
                        - #*this will remain locked
                        - #lock_count() == lock_count() - times
                - else
                    - the call to unlock() has no effect
        !*/

    private:
        // restricted functions
        rmutex(rmutex&);        // copy constructor
        rmutex& operator=(rmutex&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_RMUTEX_EXTENSIOn_ABSTRACT_


dlib C++ Library - rsignaler_extension.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_RSIGNALER_EXTENSIOn_
#define DLIB_RSIGNALER_EXTENSIOn_

#include "rsignaler_extension_abstract.h"
#include "rmutex_extension.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class rsignaler
    {
    public:
        rsignaler (
            const rmutex& associated_mutex
        ) :
            assoc_mutex(associated_mutex),
            s(m)
        {}

        ~rsignaler (
        )
        {}

        void wait (
        ) const
        {
            m.lock();
            const unsigned long lock_count = assoc_mutex.lock_count();
            assoc_mutex.unlock(lock_count);
            s.wait();
            m.unlock();
            assoc_mutex.lock(lock_count);
        }

        bool wait_or_timeout (
            unsigned long milliseconds
        ) const
        {
            m.lock();
            const unsigned long lock_count = assoc_mutex.lock_count();
            assoc_mutex.unlock(lock_count);
            bool res = s.wait_or_timeout(milliseconds);
            m.unlock();
            assoc_mutex.lock(lock_count);
            return res;
        }

        void signal (
        ) const
        {
            m.lock();
            s.signal();
            m.unlock();
        }

        void broadcast (
        ) const
        {
            m.lock();
            s.broadcast();
            m.unlock();
        }

        const rmutex& get_mutex (
        ) const { return assoc_mutex; }

    private:

        const rmutex& assoc_mutex;
        mutex m;
        signaler s;

        // restricted functions
        rsignaler(rsignaler&);        // copy constructor
        rsignaler& operator=(rsignaler&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_RSIGNALER_EXTENSIOn_


dlib C++ Library - rsignaler_extension_abstract.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_RSIGNALER_EXTENSIOn_ABSTRACT_
#ifdef DLIB_RSIGNALER_EXTENSIOn_ABSTRACT_

#include "threads_kernel_abstract.h"
#include "rmutex_extension_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class rsignaler
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object represents an event signaling system for threads.  It gives
                a thread the ability to wake up other threads that are waiting for a
                particular signal.

                Each rsignaler object is associated with one and only one rmutex object.
                More than one rsignaler object may be associated with a single rmutex
                but a signaler object may only be associated with a single rmutex.

                NOTE:
                You must guard against spurious wakeups.  This means that a thread
                might return from a call to wait even if no other thread called
                signal.  This is rare but must be guarded against.

                Also note that this object is identical to the signaler object
                except that it works with rmutex objects rather than mutex objects.
        !*/

    public:

        rsignaler (
            const rmutex& associated_mutex
        );
        /*!
            ensures
                - #*this is properly initialized
                - #get_mutex() == associated_mutex
            throws
                - dlib::thread_error
                    the constructor may throw this exception if there is a problem
                    gathering resources to create the signaler.
        !*/

        ~rsignaler (
        );
        /*!
            ensures
                - all resources allocated by *this have been freed
        !*/

        void wait (
        ) const;
        /*!
            requires
                - get_mutex() is locked and owned by the calling thread
            ensures
                - atomically unlocks get_mutex() and blocks the calling thread
                - calling thread may wake if another thread calls signal() or broadcast()
                  on *this
                - when wait() returns the calling thread again has a lock on get_mutex()
        !*/

        bool wait_or_timeout (
            unsigned long milliseconds
        ) const;
        /*!
            requires
                - get_mutex() is locked and owned by the calling thread
            ensures
                - atomically unlocks get_mutex() and blocks the calling thread
                - calling thread may wake if another thread calls signal() or broadcast()
                  on *this
                - after the specified number of milliseconds has elapsed the calling thread
                  will wake once get_mutex() is free
                - when wait returns the calling thread again has a lock on get_mutex()

                - returns false if the call to wait_or_timeout timed out
                - returns true if the call did not time out
        !*/

        void signal (
        ) const;
        /*!
            ensures
                - if (at least one thread is waiting on *this) then
                    - at least one of the waiting threads will wake
        !*/

        void broadcast (
        ) const;
        /*!
            ensures
                - any and all threads waiting on *this will wake
        !*/

        const rmutex& get_mutex (
        ) const;
        /*!
            ensures
                - returns a const reference to the rmutex associated with *this
        !*/

    private:
        // restricted functions
        rsignaler(rsignaler&);        // copy constructor
        rsignaler& operator=(rsignaler&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_RSIGNALER_EXTENSIOn_ABSTRACT_


dlib C++ Library - thread_function_extension.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_THREAD_FUNCTIOn_
#define DLIB_THREAD_FUNCTIOn_

#include "thread_function_extension_abstract.h"
#include "threads_kernel.h"
#include "auto_mutex_extension.h"
#include "threaded_object_extension.h"
#include "../smart_pointers.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class thread_function : private threaded_object
    {

        class base_funct
        {
        public:
            virtual void go() = 0;
            virtual ~base_funct() {}
        };

        template <typename F, typename T1, typename T2, typename T3, typename T4>
        class super_funct_4 : public base_funct
        {
        public:
            super_funct_4 ( F funct, T1 arg1, T2 arg2, T3 arg3, T4 arg4) :
                f(funct),
                a1(arg1),
                a2(arg2),
                a3(arg3),
                a4(arg4)
            {
            }

            void go() { f(a1, a2, a3, a4); }

            F f;
            T1 a1;
            T2 a2;
            T3 a3;
            T4 a4;
        };

        template <typename F, typename T1, typename T2, typename T3>
        class super_funct_3 : public base_funct
        {
        public:
            super_funct_3 ( F funct, T1 arg1, T2 arg2, T3 arg3):
                f(funct),
                a1(arg1),
                a2(arg2),
                a3(arg3)
            {
            }

            void go() { f(a1, a2, a3); }

            F f;
            T1 a1;
            T2 a2;
            T3 a3;
        };

        template <typename F, typename T1, typename T2>
        class super_funct_2 : public base_funct
        {
        public:
            super_funct_2 ( F funct, T1 arg1, T2 arg2) :
                f(funct),
                a1(arg1),
                a2(arg2)
            {
            }

            void go() { f(a1, a2); }

            F f;
            T1 a1;
            T2 a2;
        };

        template <typename F, typename T>
        class super_funct_1 : public base_funct
        {
        public:
            super_funct_1 ( F funct, T arg) : f(funct), a(arg)
            {
            }

            void go() { f(a); }

            F f;
            T a;
        };

        template <typename F>
        class super_funct_0 : public base_funct
        {
        public:
            super_funct_0 ( F funct) : f(funct)
            {
            }

            void go() { f(); }

            F f;
        };

    public:

        template <typename F>
        thread_function (
            F funct
        )
        {
            f.reset(new super_funct_0<F>(funct));
            start();
        }

        template <typename F, typename T>
        thread_function (
            F funct,
            T arg
        )
        {
            f.reset(new super_funct_1<F,T>(funct,arg));
            start();
        }

        template <typename F, typename T1, typename T2>
        thread_function (
            F funct,
            T1 arg1,
            T2 arg2
        )
        {
            f.reset(new super_funct_2<F,T1,T2>(funct, arg1, arg2));
            start();
        }

        template <typename F, typename T1, typename T2, typename T3>
        thread_function (
            F funct,
            T1 arg1,
            T2 arg2,
            T3 arg3
        )
        {
            f.reset(new super_funct_3<F,T1,T2,T3>(funct, arg1, arg2, arg3));
            start();
        }

        template <typename F, typename T1, typename T2, typename T3, typename T4>
        thread_function (
            F funct,
            T1 arg1,
            T2 arg2,
            T3 arg3,
            T4 arg4
        )
        {
            f.reset(new super_funct_4<F,T1,T2,T3,T4>(funct, arg1, arg2, arg3, arg4));
            start();
        }

        ~thread_function (
        )
        {
            threaded_object::wait();
        }

        bool is_alive (
        ) const
        {
            return threaded_object::is_alive();
        }

        void wait (
        ) const
        {
            threaded_object::wait();
        }

    private:

        void thread ()
        {
            f->go();
        }

        scoped_ptr<base_funct> f;

        // restricted functions
        thread_function(thread_function&);        // copy constructor
        thread_function& operator=(thread_function&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_THREAD_FUNCTIOn_


dlib C++ Library - thread_function_extension_abstract.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_THREAD_FUNCTIOn_ABSTRACT_
#ifdef DLIB_THREAD_FUNCTIOn_ABSTRACT_

#include "threads_kernel_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class thread_function
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object represents a thread on a global C++ function or function
                object.  That is, it allows you to run a function in its own thread.
        !*/
    public:

        template <typename F>
        thread_function (
            F funct
        );
        /*!
            ensures
                - #*this is properly initialized
                - the function funct has been started in its own thread
            throws
                - std::bad_alloc
                - dlib::thread_error
                    the constructor may throw this exception if there is a problem
                    gathering resources to create threading objects.
        !*/

        template <typename F, typename T1>
        thread_function (
            F funct,
            T1 arg1
        );
        /*!
            ensures
                - #*this is properly initialized
                - A thread has been created and it will call funct(arg1)
            throws
                - std::bad_alloc
                - dlib::thread_error
                    the constructor may throw this exception if there is a problem
                    gathering resources to create threading objects.
        !*/

        template <typename F, typename T1, typename T2>
        thread_function (
            F funct,
            T1 arg1,
            T2 arg2
        );
        /*!
            ensures
                - #*this is properly initialized
                - A thread has been created and it will call funct(arg1, arg2)
            throws
                - std::bad_alloc
                - dlib::thread_error
                    the constructor may throw this exception if there is a problem
                    gathering resources to create threading objects.
        !*/

        template <typename F, typename T1, typename T2, typename T3>
        thread_function (
            F funct,
            T1 arg1,
            T2 arg2,
            T3 arg3
        );
        /*!
            ensures
                - #*this is properly initialized
                - A thread has been created and it will call funct(arg1, arg2, arg3)
            throws
                - std::bad_alloc
                - dlib::thread_error
                    the constructor may throw this exception if there is a problem
                    gathering resources to create threading objects.
        !*/

        template <typename F, typename T1, typename T2, typename T3, typename T4>
        thread_function (
            F funct,
            T1 arg1,
            T2 arg2,
            T3 arg3,
            T4 arg4
        );
        /*!
            ensures
                - #*this is properly initialized
                - A thread has been created and it will call funct(arg1, arg2, arg3, arg4)
            throws
                - std::bad_alloc
                - dlib::thread_error
                    the constructor may throw this exception if there is a problem
                    gathering resources to create threading objects.
        !*/

        ~thread_function (
        );
        /*!
            ensures
                - all resources allocated by *this have been freed.
                - blocks until is_alive() == false
        !*/

        bool is_alive (
        ) const;
        /*!
            ensures
                - if (this object's thread has yet to terminate) then
                    - returns true
                - else
                    - returns false
        !*/

        void wait (
        ) const;
        /*!
            ensures
                - if (is_alive() == true) then
                    - blocks until this object's thread terminates
        !*/

    private:

        // restricted functions
        thread_function(thread_function&);        // copy constructor
        thread_function& operator=(thread_function&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_THREAD_FUNCTIOn_ABSTRACT_


dlib C++ Library - thread_pool_extension.cpp

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_THREAD_POOl_CPPh_
#define DLIB_THREAD_POOl_CPPh_

#include "thread_pool_extension.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    thread_pool_implementation::
    thread_pool_implementation (
        unsigned long num_threads
    ) :
        task_done_signaler(m),
        task_ready_signaler(m),
        we_are_destructing(false)
    {
        tasks.resize(num_threads);
        for (unsigned long i = 0; i < num_threads; ++i)
        {
            register_thread(*this, &thread_pool_implementation::thread);
        }

        start();
    }

// ----------------------------------------------------------------------------------------

    void thread_pool_implementation::
    shutdown_pool (
    )
    {
        {
            auto_mutex M(m);

            // first wait for all pending tasks to finish
            bool found_task = true;
            while (found_task)
            {
                found_task = false;
                for (unsigned long i = 0; i < tasks.size(); ++i)
                {
                    // If task bucket i has a task that is currently supposed to be processed
                    if (tasks[i].is_empty() == false)
                    {
                        found_task = true;
                        break;
                    }
                }

                if (found_task)
                    task_done_signaler.wait();
            }

            // now tell the threads to kill themselves
            we_are_destructing = true;
            task_ready_signaler.broadcast();
        }

        wait();
    }

// ----------------------------------------------------------------------------------------

    thread_pool_implementation::
    ~thread_pool_implementation()
    {
        shutdown_pool();
    }

// ----------------------------------------------------------------------------------------

    unsigned long thread_pool_implementation::
    num_threads_in_pool (
    ) const
    {
        auto_mutex M(m);
        return tasks.size();
    }

// ----------------------------------------------------------------------------------------

    void thread_pool_implementation::
    wait_for_task (
        uint64 task_id
    ) const
    {
        auto_mutex M(m);
        if (tasks.size() != 0)
        {
            const unsigned long idx = task_id_to_index(task_id);
            while (tasks[idx].task_id == task_id)
                task_done_signaler.wait();
        }
    }

// ----------------------------------------------------------------------------------------

    void thread_pool_implementation::
    wait_for_all_tasks (
    ) const
    {
        const thread_id_type thread_id = get_thread_id();

        auto_mutex M(m);
        bool found_task = true;
        while (found_task)
        {
            found_task = false;
            for (unsigned long i = 0; i < tasks.size(); ++i)
            {
                // If task bucket i has a task that is currently supposed to be processed
                // and it originated from the calling thread
                if (tasks[i].is_empty() == false && tasks[i].thread_id == thread_id)
                {
                    found_task = true;
                    break;
                }
            }

            if (found_task)
                task_done_signaler.wait();
        }
    }

// ----------------------------------------------------------------------------------------

    bool thread_pool_implementation::
    is_worker_thread (
        const thread_id_type id
    ) const
    {
        for (unsigned long i = 0; i < worker_thread_ids.size(); ++i)
        {
            if (worker_thread_ids[i] == id)
                return true;
        }

        // if there aren't any threads in the pool then we consider all threads
        // to be worker threads
        if (tasks.size() == 0)
            return true;
        else
            return false;
    }

// ----------------------------------------------------------------------------------------

    void thread_pool_implementation::
    thread (
    )
    {
        {
            // save the id of this worker thread into worker_thread_ids
            auto_mutex M(m);
            thread_id_type id = get_thread_id();
            worker_thread_ids.push_back(id);
        }

        task_state_type task;
        while (we_are_destructing == false)
        {
            long idx = 0;

            // wait for a task to do
            { auto_mutex M(m);
                while ( (idx = find_ready_task()) == -1 && we_are_destructing == false)
                    task_ready_signaler.wait();

                if (we_are_destructing)
                    break;

                tasks[idx].is_being_processed = true;
                task = tasks[idx];
            }

            // now do the task
            if (task.bfp)
                task.bfp();
            else if (task.mfp0)
                task.mfp0();
            else if (task.mfp1)
                task.mfp1(task.arg1);
            else if (task.mfp2)
                task.mfp2(task.arg1, task.arg2);

            // Now let others know that we finished the task.  We do this
            // by clearing out the state of this task
            { auto_mutex M(m);
                tasks[idx].is_being_processed = false;
                tasks[idx].task_id = 0;
                tasks[idx].bfp.clear();
                tasks[idx].mfp0.clear();
                tasks[idx].mfp1.clear();
                tasks[idx].mfp2.clear();
                tasks[idx].arg1 = 0;
                tasks[idx].arg2 = 0;
                task_done_signaler.broadcast();
            }

        }
    }

// ----------------------------------------------------------------------------------------

    long thread_pool_implementation::
    find_empty_task_slot (
    ) const
    {
        for (unsigned long i = 0; i < tasks.size(); ++i)
        {
            if (tasks[i].is_empty())
                return i;
        }

        return -1;
    }

// ----------------------------------------------------------------------------------------

    long thread_pool_implementation::
    find_ready_task (
    ) const
    {
        for (unsigned long i = 0; i < tasks.size(); ++i)
        {
            if (tasks[i].is_ready())
                return i;
        }

        return -1;
    }

// ----------------------------------------------------------------------------------------

    uint64 thread_pool_implementation::
    make_next_task_id (
        long idx
    )
    {
        uint64 id = tasks[idx].next_task_id * tasks.size() + idx;
        tasks[idx].next_task_id += 1;
        return id;
    }

// ----------------------------------------------------------------------------------------

    unsigned long thread_pool_implementation::
    task_id_to_index (
        uint64 id
    ) const
    {
        return static_cast<unsigned long>(id%tasks.size());
    }

// ----------------------------------------------------------------------------------------

    uint64 thread_pool_implementation::
    add_task_internal (
        const bfp_type& bfp,
        shared_ptr<function_object_copy>& item
    )
    {
        auto_mutex M(m);
        const thread_id_type my_thread_id = get_thread_id();

        // find a thread that isn't doing anything
        long idx = find_empty_task_slot();
        if (idx == -1 && is_worker_thread(my_thread_id))
        {
            // this function is being called from within a worker thread and there
            // aren't any other worker threads free so just perform the task right
            // here

            M.unlock();
            bfp();

            // return a task id that is both non-zero and also one
            // that is never normally returned.  This way calls
            // to wait_for_task() will never block given this id.
            return 1;
        }

        // wait until there is a thread that isn't doing anything
        while (idx == -1)
        {
            task_done_signaler.wait();
            idx = find_empty_task_slot();
        }

        tasks[idx].thread_id = my_thread_id;
        tasks[idx].task_id = make_next_task_id(idx);
        tasks[idx].bfp = bfp;
        tasks[idx].function_copy.swap(item);

        task_ready_signaler.signal();

        return tasks[idx].task_id;
    }

// ----------------------------------------------------------------------------------------

    bool thread_pool_implementation::
    is_task_thread (
    ) const
    {
        auto_mutex M(m);
        return is_worker_thread(get_thread_id());
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_THREAD_POOl_CPPh_


dlib C++ Library - thread_pool_extension.h

// Copyright (C) 2008  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_THREAD_POOl_Hh_
#define DLIB_THREAD_POOl_Hh_

#include "thread_pool_extension_abstract.h"
#include "multithreaded_object_extension.h"
#include "../member_function_pointer.h"
#include "../bound_function_pointer.h"
#include "threads_kernel.h"
#include "auto_mutex_extension.h"
#include "../uintn.h"
#include "../array.h"
#include "../smart_pointers_thread_safe.h"
#include "../smart_pointers.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class thread_pool_implementation;

    template <
        typename T
        >
    class future
    {
        /*!
            INITIAL VALUE
                - task_id == 0
                - tp.get() == 0

            CONVENTION
                - is_ready() == (tp.get() == 0)
                - get() == var

                - if (tp.get() != 0)
                    - tp == a pointer to the thread_pool_implementation that is using this future object
                    - task_id == the task id of the task in the thread pool tp that is using
                      this future object.
        !*/
    public:

        future (
        ) : task_id(0) {}

        future (
            const T& item
        ) : task_id(0), var(item) {}

        future (
            const future& item
        ) :task_id(0), var(item.get()) {}

        ~future (
        ) { wait(); }

        future& operator=(
            const T& item
        ) { get() = item; return *this; }

        future& operator=(
            const future& item
        ) { get() = item.get(); return *this; }

        operator T& (
        ) { return get(); }

        operator const T& (
        ) const { return get(); }

        T& get (
        ) { wait(); return var; }

        const T& get (
        ) const { wait(); return var; }

        bool is_ready (
        ) const { return tp.get() == 0; }

    private:

        friend class thread_pool;

        inline void wait () const;

        mutable uint64 task_id;
        mutable shared_ptr_thread_safe<thread_pool_implementation> tp;

        T var;
    };

// ----------------------------------------------------------------------------------------

    template <typename T>
    inline void swap (
        future<T>& a,
        future<T>& b
    ) { dlib::exchange(a.get(), b.get()); }
    // Note that dlib::exchange() just calls std::swap.  I'm only using it because
    // this works around some bugs in certain compilers.

// ----------------------------------------------------------------------------------------

    template <typename T> bool operator== (const future<T>& a, const future<T>& b) { return a.get() == b.get(); }
    template <typename T> bool operator!= (const future<T>& a, const future<T>& b) { return a.get() != b.get(); }
    template <typename T> bool operator<= (const future<T>& a, const future<T>& b) { return a.get() <= b.get(); }
    template <typename T> bool operator>= (const future<T>& a, const future<T>& b) { return a.get() >= b.get(); }
    template <typename T> bool operator<  (const future<T>& a, const future<T>& b) { return a.get() <  b.get(); }
    template <typename T> bool operator>  (const future<T>& a, const future<T>& b) { return a.get() >  b.get(); }

    template <typename T> bool operator== (const future<T>& a, const T& b)         { return a.get() == b; }
    template <typename T> bool operator== (const T& a,         const future<T>& b) { return a       == b.get(); }
    template <typename T> bool operator!= (const future<T>& a, const T& b)         { return a.get() != b; }
    template <typename T> bool operator!= (const T& a,         const future<T>& b) { return a       != b.get(); }
    template <typename T> bool operator<= (const future<T>& a, const T& b)         { return a.get() <= b; }
    template <typename T> bool operator<= (const T& a,         const future<T>& b) { return a       <= b.get(); }
    template <typename T> bool operator>= (const future<T>& a, const T& b)         { return a.get() >= b; }
    template <typename T> bool operator>= (const T& a,         const future<T>& b) { return a       >= b.get(); }
    template <typename T> bool operator<  (const future<T>& a, const T& b)         { return a.get() <  b; }
    template <typename T> bool operator<  (const T& a,         const future<T>& b) { return a       <  b.get(); }
    template <typename T> bool operator>  (const future<T>& a, const T& b)         { return a.get() >  b; }
    template <typename T> bool operator>  (const T& a,         const future<T>& b) { return a       >  b.get(); }

// ----------------------------------------------------------------------------------------

    class thread_pool_implementation : private multithreaded_object
    {
        /*!
            CONVENTION
                - num_threads_in_pool() == tasks.size()
                - if (the destructor has been called) then
                    - we_are_destructing == true
                - else
                    - we_are_destructing == false

                - is_task_thread() == is_worker_thread(get_thread_id())

                - m == the mutex used to protect everything in this object
                - worker_thread_ids == an array that contains the thread ids for
                  all the threads in the thread pool
        !*/
        typedef bound_function_pointer::kernel_1a_c bfp_type;

        friend class thread_pool;
        explicit thread_pool_implementation (
            unsigned long num_threads
        );

    public:
        ~thread_pool_implementation(
        );

        void wait_for_task (
            uint64 task_id
        ) const;

        unsigned long num_threads_in_pool (
        ) const;

        void wait_for_all_tasks (
        ) const;

        bool is_task_thread (
        ) const;

        template <typename T>
        uint64 add_task (
            T& obj,
            void (T::*funct)()
        )
        {
            auto_mutex M(m);
            const thread_id_type my_thread_id = get_thread_id();

            // find a thread that isn't doing anything
            long idx = find_empty_task_slot();
            if (idx == -1 && is_worker_thread(my_thread_id))
            {
                // this function is being called from within a worker thread and there
                // aren't any other worker threads free so just perform the task right
                // here

                M.unlock();
                (obj.*funct)();

                // return a task id that is both non-zero and also one
                // that is never normally returned.  This way calls
                // to wait_for_task() will never block given this id.
                return 1;
            }

            // wait until there is a thread that isn't doing anything
            while (idx == -1)
            {
                task_done_signaler.wait();
                idx = find_empty_task_slot();
            }

            tasks[idx].thread_id = my_thread_id;
            tasks[idx].task_id = make_next_task_id(idx);
            tasks[idx].mfp0.set(obj,funct);

            task_ready_signaler.signal();

            return tasks[idx].task_id;
        }

        template <typename T>
        uint64 add_task (
            T& obj,
            void (T::*funct)(long),
            long arg1
        )
        {
            auto_mutex M(m);
            const thread_id_type my_thread_id = get_thread_id();

            // find a thread that isn't doing anything
            long idx = find_empty_task_slot();
            if (idx == -1 && is_worker_thread(my_thread_id))
            {
                // this function is being called from within a worker thread and there
                // aren't any other worker threads free so just perform the task right
                // here

                M.unlock();
                (obj.*funct)(arg1);

                // return a task id that is both non-zero and also one
                // that is never normally returned.  This way calls
                // to wait_for_task() will never block given this id.
                return 1;
            }

            // wait until there is a thread that isn't doing anything
            while (idx == -1)
            {
                task_done_signaler.wait();
                idx = find_empty_task_slot();
            }

            tasks[idx].thread_id = my_thread_id;
            tasks[idx].task_id = make_next_task_id(idx);
            tasks[idx].mfp1.set(obj,funct);
            tasks[idx].arg1 = arg1;

            task_ready_signaler.signal();

            return tasks[idx].task_id;
        }

        template <typename T>
        uint64 add_task (
            T& obj,
            void (T::*funct)(long,long),
            long arg1,
            long arg2
        )
        {
            auto_mutex M(m);
            const thread_id_type my_thread_id = get_thread_id();

            // find a thread that isn't doing anything
            long idx = find_empty_task_slot();
            if (idx == -1 && is_worker_thread(my_thread_id))
            {
                // this function is being called from within a worker thread and there
                // aren't any other worker threads free so just perform the task right
                // here

                M.unlock();
                (obj.*funct)(arg1, arg2);

                // return a task id that is both non-zero and also one
                // that is never normally returned.  This way calls
                // to wait_for_task() will never block given this id.
                return 1;
            }

            // wait until there is a thread that isn't doing anything
            while (idx == -1)
            {
                task_done_signaler.wait();
                idx = find_empty_task_slot();
            }

            tasks[idx].thread_id = my_thread_id;
            tasks[idx].task_id = make_next_task_id(idx);
            tasks[idx].mfp2.set(obj,funct);
            tasks[idx].arg1 = arg1;
            tasks[idx].arg2 = arg2;

            task_ready_signaler.signal();

            return tasks[idx].task_id;
        }

        struct function_object_copy
        {
            virtual ~function_object_copy(){}
        };

        template <typename T>
        struct function_object_copy_instance : function_object_copy
        {
            function_object_copy_instance(const T& item_) : item(item_) {}
            T item;
            virtual ~function_object_copy_instance(){}
        };

        uint64 add_task_internal (
            const bfp_type& bfp,
            shared_ptr<function_object_copy>& item
        );
        /*!
            ensures
                - adds a task to call the given bfp object.
                - swaps item into the internal task object which will have a lifetime
                  at least as long as the running task.
                - returns the task id for this new task
        !*/

        uint64 add_task_internal (
            const bfp_type& bfp
        ) { shared_ptr<function_object_copy> temp; return add_task_internal(bfp, temp); }
        /*!
            ensures
                - adds a task to call the given bfp object.
                - returns the task id for this new task
        !*/

        void shutdown_pool (
        );
        /*!
            ensures
                - causes all threads to terminate and blocks the
                  caller until this happens.
        !*/

    private:

        bool is_worker_thread (
            const thread_id_type id
        ) const;
        /*!
            requires
                - m is locked
            ensures
                - if (thread with given id is one of the thread pool's worker threads or num_threads_in_pool() == 0) then
                    - returns true
                - else
                    - returns false
        !*/

        void thread (
        );
        /*!
            this is the function that executes the threads in the thread pool
        !*/

        long find_empty_task_slot (
        ) const;
        /*!
            requires
                - m is locked
            ensures
                - if (there is currently a empty task slot) then
                    - returns the index of that task slot in tasks
                    - there is a task slot
                - else
                    - returns -1
        !*/

        long find_ready_task (
        ) const;
        /*!
            requires
                - m is locked
            ensures
                - if (there is currently a task to do) then
                    - returns the index of that task in tasks
                - else
                    - returns -1
        !*/

        uint64 make_next_task_id (
            long idx
        );
        /*!
            requires
                - m is locked
                - 0 <= idx < tasks.size()
            ensures
                - returns the next index to be used for tasks that are placed in
                  tasks[idx]
        !*/

        unsigned long task_id_to_index (
            uint64 id
        ) const;
        /*!
            requires
                - m is locked
                - num_threads_in_pool() != 0
            ensures
                - returns the index in tasks corresponding to the given id
        !*/

        struct task_state_type
        {
            task_state_type() : is_being_processed(false), task_id(0), next_task_id(2), arg1(0), arg2(0) {}

            bool is_ready () const
            /*!
                ensures
                    - if (is_empty() == false && no thread is currently processing this task) then
                        - returns true
                    - else
                        - returns false
            !*/
            {
                return !is_being_processed && !is_empty();
            }

            bool is_empty () const
            /*!
                ensures
                    - if (this task state is empty.  i.e. it doesn't contain a task to be processed) then
                        - returns true
                    - else
                        - returns false
            !*/
            {
                return task_id == 0;
            }

            bool is_being_processed;  // true when a thread is working on this task
            uint64 task_id; // the id of this task.  0 means this task is empty
            thread_id_type thread_id; // the id of the thread that requested this task

            uint64 next_task_id;

            long arg1;
            long arg2;

            member_function_pointer<> mfp0;
            member_function_pointer<long> mfp1;
            member_function_pointer<long,long> mfp2;
            bfp_type bfp;

            shared_ptr<function_object_copy> function_copy;

        };

        array<task_state_type> tasks;
        array<thread_id_type> worker_thread_ids;

        mutex m;
        signaler task_done_signaler;
        signaler task_ready_signaler;
        bool we_are_destructing;

        // restricted functions
        thread_pool_implementation(thread_pool_implementation&);        // copy constructor
        thread_pool_implementation& operator=(thread_pool_implementation&);    // assignment operator

    };

// ----------------------------------------------------------------------------------------

    class thread_pool
    {
        /*!
            This object is just a shell that holds a shared_ptr_thread_safe
            to the real thread_pool_implementation object.  The reason for doing
            it this way is so that we can allow any mixture of destruction orders
            between thread_pool objects and futures.  Whoever gets destroyed
            last cleans up the thread_pool_implementation resources.
        !*/
        typedef bound_function_pointer::kernel_1a_c bfp_type;

    public:
        explicit thread_pool (
            unsigned long num_threads
        )
        {
            impl.reset(new thread_pool_implementation(num_threads));
        }

        ~thread_pool (
        )
        {
            impl->shutdown_pool();
        }

        void wait_for_task (
            uint64 task_id
        ) const { impl->wait_for_task(task_id); }

        unsigned long num_threads_in_pool (
        ) const { return impl->num_threads_in_pool(); }

        void wait_for_all_tasks (
        ) const { impl->wait_for_all_tasks(); }

        bool is_task_thread (
        ) const { return impl->is_task_thread(); }

        template <typename T>
        uint64 add_task (
            T& obj,
            void (T::*funct)()
        )
        {
            return impl->add_task(obj, funct);
        }

        template <typename T>
        uint64 add_task (
            T& obj,
            void (T::*funct)(long),
            long arg1
        )
        {
            return impl->add_task(obj, funct, arg1);
        }

        template <typename T>
        uint64 add_task (
            T& obj,
            void (T::*funct)(long,long),
            long arg1,
            long arg2
        )
        {
            return impl->add_task(obj, funct, arg1, arg2);
        }

        // --------------------

        template <typename F>
        uint64 add_task (
            F& function_object
        )
        {
            COMPILE_TIME_ASSERT(is_function<F>::value == false);
            COMPILE_TIME_ASSERT(is_pointer_type<F>::value == false);

            bfp_type temp;
            temp.set(function_object);
            uint64 id = impl->add_task_internal(temp);

            return id;
        }

        template <typename F>
        uint64 add_task_by_value (
            const F& function_object
        )
        {
            thread_pool_implementation::function_object_copy_instance<F>* ptr = 0;
            ptr = new thread_pool_implementation::function_object_copy_instance<F>(function_object);
            shared_ptr<thread_pool_implementation::function_object_copy> function_copy(ptr);

            bfp_type temp;
            temp.set(ptr->item);
            uint64 id = impl->add_task_internal(temp, function_copy);

            return id;
        }

        template <typename T>
        uint64 add_task (
            const T& obj,
            void (T::*funct)() const
        )
        {
            bfp_type temp;
            temp.set(obj,funct);
            uint64 id = impl->add_task_internal(temp);

            return id;
        }

        template <typename T>
        uint64 add_task_by_value (
            const T& obj,
            void (T::*funct)() const
        )
        {
            thread_pool_implementation::function_object_copy_instance<const T>* ptr = 0;
            ptr = new thread_pool_implementation::function_object_copy_instance<const T>(obj);
            shared_ptr<thread_pool_implementation::function_object_copy> function_copy(ptr);

            bfp_type temp;
            temp.set(ptr->item,funct);
            uint64 id = impl->add_task_internal(temp, function_copy);

            return id;
        }

        template <typename T>
        uint64 add_task_by_value (
            const T& obj,
            void (T::*funct)()
        )
        {
            thread_pool_implementation::function_object_copy_instance<T>* ptr = 0;
            ptr = new thread_pool_implementation::function_object_copy_instance<T>(obj);
            shared_ptr<thread_pool_implementation::function_object_copy> function_copy(ptr);

            bfp_type temp;
            temp.set(ptr->item,funct);
            uint64 id = impl->add_task_internal(temp, function_copy);

            return id;
        }

        uint64 add_task (
            void (*funct)()
        )
        {
            bfp_type temp;
            temp.set(funct);
            uint64 id = impl->add_task_internal(temp);

            return id;
        }

        // --------------------

        template <typename F, typename A1>
        uint64 add_task (
            F& function_object,
            future<A1>& arg1
        )
        {
            COMPILE_TIME_ASSERT(is_function<F>::value == false);
            COMPILE_TIME_ASSERT(is_pointer_type<F>::value == false);

            bfp_type temp;
            temp.set(function_object,arg1.get());
            uint64 id = impl->add_task_internal(temp);

            // tie the future to this task
            arg1.task_id = id;
            arg1.tp = impl;
            return id;
        }

        template <typename F, typename A1>
        uint64 add_task_by_value (
            const F& function_object,
            future<A1>& arg1
        )
        {
            thread_pool_implementation::function_object_copy_instance<F>* ptr = 0;
            ptr = new thread_pool_implementation::function_object_copy_instance<F>(function_object);
            shared_ptr<thread_pool_implementation::function_object_copy> function_copy(ptr);

            bfp_type temp;
            temp.set(ptr->item, arg1.get());
            uint64 id = impl->add_task_internal(temp, function_copy);

            // tie the future to this task
            arg1.task_id = id;
            arg1.tp = impl;
            return id;
        }

        template <typename T, typename T1, typename A1>
        uint64 add_task (
            T& obj,
            void (T::*funct)(T1),
            future<A1>& arg1
        )
        {
            bfp_type temp;
            temp.set(obj,funct,arg1.get());
            uint64 id = impl->add_task_internal(temp);

            // tie the future to this task
            arg1.task_id = id;
            arg1.tp = impl;
            return id;
        }

        template <typename T, typename T1, typename A1>
        uint64 add_task_by_value (
            const T& obj,
            void (T::*funct)(T1),
            future<A1>& arg1
        )
        {
            thread_pool_implementation::function_object_copy_instance<T>* ptr = 0;
            ptr = new thread_pool_implementation::function_object_copy_instance<T>(obj);
            shared_ptr<thread_pool_implementation::function_object_copy> function_copy(ptr);

            bfp_type temp;
            temp.set(ptr->item,funct,arg1.get());
            uint64 id = impl->add_task_internal(temp, function_copy);

            // tie the future to this task
            arg1.task_id = id;
            arg1.tp = impl;
            return id;
        }

        template <typename T, typename T1, typename A1>
        uint64 add_task (
            const T& obj,
            void (T::*funct)(T1) const,
            future<A1>& arg1
        )
        {
            bfp_type temp;
            temp.set(obj,funct,arg1.get());
            uint64 id = impl->add_task_internal(temp);

            // tie the future to this task
            arg1.task_id = id;
            arg1.tp = impl;
            return id;
        }

        template <typename T, typename T1, typename A1>
        uint64 add_task_by_value (
            const T& obj,
            void (T::*funct)(T1) const,
            future<A1>& arg1
        )
        {
            thread_pool_implementation::function_object_copy_instance<const T>* ptr = 0;
            ptr = new thread_pool_implementation::function_object_copy_instance<const T>(obj);
            shared_ptr<thread_pool_implementation::function_object_copy> function_copy(ptr);

            bfp_type temp;
            temp.set(ptr->item,funct,arg1.get());
            uint64 id = impl->add_task_internal(temp, function_copy);

            // tie the future to this task
            arg1.task_id = id;
            arg1.tp = impl;
            return id;
        }

        template <typename T1, typename A1>
        uint64 add_task (
            void (*funct)(T1),
            future<A1>& arg1
        )
        {
            bfp_type temp;
            temp.set(funct,arg1.get());
            uint64 id = impl->add_task_internal(temp);

            // tie the future to this task
            arg1.task_id = id;
            arg1.tp = impl;
            return id;
        }

        // --------------------

        template <typename F, typename A1, typename A2>
        uint64 add_task (
            F& function_object,
            future<A1>& arg1,
            future<A2>& arg2
        )
        {
            COMPILE_TIME_ASSERT(is_function<F>::value == false);
            COMPILE_TIME_ASSERT(is_pointer_type<F>::value == false);

            bfp_type temp;
            temp.set(function_object, arg1.get(), arg2.get());
            uint64 id = impl->add_task_internal(temp);

            // tie the future to this task
            arg1.task_id = id;
            arg1.tp = impl;
            arg2.task_id = id;
            arg2.tp = impl;
            return id;
        }

        template <typename F, typename A1, typename A2>
        uint64 add_task_by_value (
            const F& function_object,
            future<A1>& arg1,
            future<A2>& arg2
        )
        {
            thread_pool_implementation::function_object_copy_instance<F>* ptr = 0;
            ptr = new thread_pool_implementation::function_object_copy_instance<F>(function_object);
            shared_ptr<thread_pool_implementation::function_object_copy> function_copy(ptr);

            bfp_type temp;
            temp.set(ptr->item, arg1.get(), arg2.get());
            uint64 id = impl->add_task_internal(temp, function_copy);

            // tie the future to this task
            arg1.task_id = id;
            arg1.tp = impl;
            arg2.task_id = id;
            arg2.tp = impl;
            return id;
        }

        template <typename T, typename T1, typename A1,
                              typename T2, typename A2>
        uint64 add_task (
            T& obj,
            void (T::*funct)(T1,T2),
            future<A1>& arg1,
            future<A2>& arg2
        )
        {
            bfp_type temp;
            temp.set(obj, funct, arg1.get(), arg2.get());
            uint64 id = impl->add_task_internal(temp);

            // tie the futures to this task
            arg1.task_id = id;
            arg1.tp = impl;
            arg2.task_id = id;
            arg2.tp = impl;
            return id;
        }

        template <typename T, typename T1, typename A1,
                              typename T2, typename A2>
        uint64 add_task_by_value (
            const T& obj,
            void (T::*funct)(T1,T2),
            future<A1>& arg1,
            future<A2>& arg2
        )
        {
            thread_pool_implementation::function_object_copy_instance<T>* ptr = 0;
            ptr = new thread_pool_implementation::function_object_copy_instance<T>(obj);
            shared_ptr<thread_pool_implementation::function_object_copy> function_copy(ptr);

            bfp_type temp;
            temp.set(ptr->item, funct, arg1.get(), arg2.get());
            uint64 id = impl->add_task_internal(temp, function_copy);

            // tie the futures to this task
            arg1.task_id = id;
            arg1.tp = impl;
            arg2.task_id = id;
            arg2.tp = impl;
            return id;
        }

        template <typename T, typename T1, typename A1,
                              typename T2, typename A2>
        uint64 add_task (
            const T& obj,
            void (T::*funct)(T1,T2) const,
            future<A1>& arg1,
            future<A2>& arg2
        )
        {
            bfp_type temp;
            temp.set(obj, funct, arg1.get(), arg2.get());
            uint64 id = impl->add_task_internal(temp);

            // tie the futures to this task
            arg1.task_id = id;
            arg1.tp = impl;
            arg2.task_id = id;
            arg2.tp = impl;
            return id;
        }

        template <typename T, typename T1, typename A1,
                              typename T2, typename A2>
        uint64 add_task_by_value (
            const T& obj,
            void (T::*funct)(T1,T2) const,
            future<A1>& arg1,
            future<A2>& arg2
        )
        {
            thread_pool_implementation::function_object_copy_instance<const T>* ptr = 0;
            ptr = new thread_pool_implementation::function_object_copy_instance<const T>(obj);
            shared_ptr<thread_pool_implementation::function_object_copy> function_copy(ptr);

            bfp_type temp;
            temp.set(ptr->item, funct, arg1.get(), arg2.get());
            uint64 id = impl->add_task_internal(temp, function_copy);

            // tie the futures to this task
            arg1.task_id = id;
            arg1.tp = impl;
            arg2.task_id = id;
            arg2.tp = impl;
            return id;
        }

        template <typename T1, typename A1,
                  typename T2, typename A2>
        uint64 add_task (
            void (*funct)(T1,T2),
            future<A1>& arg1,
            future<A2>& arg2
        )
        {
            bfp_type temp;
            temp.set(funct, arg1.get(), arg2.get());
            uint64 id = impl->add_task_internal(temp);

            // tie the futures to this task
            arg1.task_id = id;
            arg1.tp = impl;
            arg2.task_id = id;
            arg2.tp = impl;
            return id;
        }

        // --------------------

        template <typename F, typename A1, typename A2, typename A3>
        uint64 add_task (
            F& function_object,
            future<A1>& arg1,
            future<A2>& arg2,
            future<A3>& arg3
        )
        {
            COMPILE_TIME_ASSERT(is_function<F>::value == false);
            COMPILE_TIME_ASSERT(is_pointer_type<F>::value == false);

            bfp_type temp;
            temp.set(function_object, arg1.get(), arg2.get(), arg3.get());
            uint64 id = impl->add_task_internal(temp);

            // tie the future to this task
            arg1.task_id = id;
            arg1.tp = impl;
            arg2.task_id = id;
            arg2.tp = impl;
            arg3.task_id = id;
            arg3.tp = impl;
            return id;
        }

        template <typename F, typename A1, typename A2, typename A3>
        uint64 add_task_by_value (
            const F& function_object,
            future<A1>& arg1,
            future<A2>& arg2,
            future<A3>& arg3
        )
        {
            thread_pool_implementation::function_object_copy_instance<F>* ptr = 0;
            ptr = new thread_pool_implementation::function_object_copy_instance<F>(function_object);
            shared_ptr<thread_pool_implementation::function_object_copy> function_copy(ptr);

            bfp_type temp;
            temp.set(ptr->item, arg1.get(), arg2.get(), arg3.get());
            uint64 id = impl->add_task_internal(temp, function_copy);

            // tie the future to this task
            arg1.task_id = id;
            arg1.tp = impl;
            arg2.task_id = id;
            arg2.tp = impl;
            arg3.task_id = id;
            arg3.tp = impl;
            return id;
        }

        template <typename T, typename T1, typename A1,
                              typename T2, typename A2,
                              typename T3, typename A3>
        uint64 add_task (
            T& obj,
            void (T::*funct)(T1,T2,T3),
            future<A1>& arg1,
            future<A2>& arg2,
            future<A3>& arg3
        )
        {
            bfp_type temp;
            temp.set(obj, funct, arg1.get(), arg2.get(), arg3.get());
            uint64 id = impl->add_task_internal(temp);

            // tie the futures to this task
            arg1.task_id = id;
            arg1.tp = impl;
            arg2.task_id = id;
            arg2.tp = impl;
            arg3.task_id = id;
            arg3.tp = impl;
            return id;
        }

        template <typename T, typename T1, typename A1,
                              typename T2, typename A2,
                              typename T3, typename A3>
        uint64 add_task_by_value (
            const T& obj,
            void (T::*funct)(T1,T2,T3),
            future<A1>& arg1,
            future<A2>& arg2,
            future<A3>& arg3
        )
        {
            thread_pool_implementation::function_object_copy_instance<T>* ptr = 0;
            ptr = new thread_pool_implementation::function_object_copy_instance<T>(obj);
            shared_ptr<thread_pool_implementation::function_object_copy> function_copy(ptr);

            bfp_type temp;
            temp.set(ptr->item, funct, arg1.get(), arg2.get(), arg3.get());
            uint64 id = impl->add_task_internal(temp, function_copy);

            // tie the futures to this task
            arg1.task_id = id;
            arg1.tp = impl;
            arg2.task_id = id;
            arg2.tp = impl;
            arg3.task_id = id;
            arg3.tp = impl;
            return id;
        }

        template <typename T, typename T1, typename A1,
                              typename T2, typename A2,
                              typename T3, typename A3>
        uint64 add_task (
            const T& obj,
            void (T::*funct)(T1,T2,T3) const,
            future<A1>& arg1,
            future<A2>& arg2,
            future<A3>& arg3
        )
        {
            bfp_type temp;
            temp.set(obj, funct, arg1.get(), arg2.get(), arg3.get());
            uint64 id = impl->add_task_internal(temp);

            // tie the futures to this task
            arg1.task_id = id;
            arg1.tp = impl;
            arg2.task_id = id;
            arg2.tp = impl;
            arg3.task_id = id;
            arg3.tp = impl;
            return id;
        }

        template <typename T, typename T1, typename A1,
                              typename T2, typename A2,
                              typename T3, typename A3>
        uint64 add_task_by_value (
            const T& obj,
            void (T::*funct)(T1,T2,T3) const,
            future<A1>& arg1,
            future<A2>& arg2,
            future<A3>& arg3
        )
        {
            thread_pool_implementation::function_object_copy_instance<const T>* ptr = 0;
            ptr = new thread_pool_implementation::function_object_copy_instance<const T>(obj);
            shared_ptr<thread_pool_implementation::function_object_copy> function_copy(ptr);

            bfp_type temp;
            temp.set(ptr->item, funct, arg1.get(), arg2.get(), arg3.get());
            uint64 id = impl->add_task_internal(temp, function_copy);

            // tie the futures to this task
            arg1.task_id = id;
            arg1.tp = impl;
            arg2.task_id = id;
            arg2.tp = impl;
            arg3.task_id = id;
            arg3.tp = impl;
            return id;
        }

        template <typename T1, typename A1,
                  typename T2, typename A2,
                  typename T3, typename A3>
        uint64 add_task (
            void (*funct)(T1,T2,T3),
            future<A1>& arg1,
            future<A2>& arg2,
            future<A3>& arg3
        )
        {
            bfp_type temp;
            temp.set(funct, arg1.get(), arg2.get(), arg3.get());
            uint64 id = impl->add_task_internal(temp);

            // tie the futures to this task
            arg1.task_id = id;
            arg1.tp = impl;
            arg2.task_id = id;
            arg2.tp = impl;
            arg3.task_id = id;
            arg3.tp = impl;
            return id;
        }

        // --------------------

        template <typename F, typename A1, typename A2, typename A3, typename A4>
        uint64 add_task (
            F& function_object,
            future<A1>& arg1,
            future<A2>& arg2,
            future<A3>& arg3,
            future<A4>& arg4
        )
        {
            COMPILE_TIME_ASSERT(is_function<F>::value == false);
            COMPILE_TIME_ASSERT(is_pointer_type<F>::value == false);

            bfp_type temp;
            temp.set(function_object, arg1.get(), arg2.get(), arg3.get(), arg4.get());
            uint64 id = impl->add_task_internal(temp);

            // tie the future to this task
            arg1.task_id = id;
            arg1.tp = impl;
            arg2.task_id = id;
            arg2.tp = impl;
            arg3.task_id = id;
            arg3.tp = impl;
            arg4.task_id = id;
            arg4.tp = impl;
            return id;
        }

        template <typename F, typename A1, typename A2, typename A3, typename A4>
        uint64 add_task_by_value (
            const F& function_object,
            future<A1>& arg1,
            future<A2>& arg2,
            future<A3>& arg3,
            future<A4>& arg4
        )
        {
            thread_pool_implementation::function_object_copy_instance<F>* ptr = 0;
            ptr = new thread_pool_implementation::function_object_copy_instance<F>(function_object);
            shared_ptr<thread_pool_implementation::function_object_copy> function_copy(ptr);

            bfp_type temp;
            temp.set(ptr->item, arg1.get(), arg2.get(), arg3.get(), arg4.get());
            uint64 id = impl->add_task_internal(temp, function_copy);

            // tie the future to this task
            arg1.task_id = id;
            arg1.tp = impl;
            arg2.task_id = id;
            arg2.tp = impl;
            arg3.task_id = id;
            arg3.tp = impl;
            arg4.task_id = id;
            arg4.tp = impl;
            return id;
        }

        template <typename T, typename T1, typename A1,
                              typename T2, typename A2,
                              typename T3, typename A3,
                              typename T4, typename A4>
        uint64 add_task (
            T& obj,
            void (T::*funct)(T1,T2,T3,T4),
            future<A1>& arg1,
            future<A2>& arg2,
            future<A3>& arg3,
            future<A4>& arg4
        )
        {
            bfp_type temp;
            temp.set(obj, funct, arg1.get(), arg2.get(), arg3.get(), arg4.get());
            uint64 id = impl->add_task_internal(temp);

            // tie the futures to this task
            arg1.task_id = id;
            arg1.tp = impl;
            arg2.task_id = id;
            arg2.tp = impl;
            arg3.task_id = id;
            arg3.tp = impl;
            arg4.task_id = id;
            arg4.tp = impl;
            return id;
        }

        template <typename T, typename T1, typename A1,
                              typename T2, typename A2,
                              typename T3, typename A3,
                              typename T4, typename A4>
        uint64 add_task_by_value (
            const T& obj,
            void (T::*funct)(T1,T2,T3,T4),
            future<A1>& arg1,
            future<A2>& arg2,
            future<A3>& arg3,
            future<A4>& arg4
        )
        {
            thread_pool_implementation::function_object_copy_instance<T>* ptr = 0;
            ptr = new thread_pool_implementation::function_object_copy_instance<T>(obj);
            shared_ptr<thread_pool_implementation::function_object_copy> function_copy(ptr);

            bfp_type temp;
            temp.set(ptr->item, funct, arg1.get(), arg2.get(), arg3.get(), arg4.get());
            uint64 id = impl->add_task_internal(temp, function_copy);

            // tie the futures to this task
            arg1.task_id = id;
            arg1.tp = impl;
            arg2.task_id = id;
            arg2.tp = impl;
            arg3.task_id = id;
            arg3.tp = impl;
            arg4.task_id = id;
            arg4.tp = impl;
            return id;
        }

        template <typename T, typename T1, typename A1,
                              typename T2, typename A2,
                              typename T3, typename A3,
                              typename T4, typename A4>
        uint64 add_task (
            const T& obj,
            void (T::*funct)(T1,T2,T3,T4) const,
            future<A1>& arg1,
            future<A2>& arg2,
            future<A3>& arg3,
            future<A4>& arg4
        )
        {
            bfp_type temp;
            temp.set(obj, funct, arg1.get(), arg2.get(), arg3.get(), arg4.get());
            uint64 id = impl->add_task_internal(temp);

            // tie the futures to this task
            arg1.task_id = id;
            arg1.tp = impl;
            arg2.task_id = id;
            arg2.tp = impl;
            arg3.task_id = id;
            arg3.tp = impl;
            arg4.task_id = id;
            arg4.tp = impl;
            return id;
        }

        template <typename T, typename T1, typename A1,
                              typename T2, typename A2,
                              typename T3, typename A3,
                              typename T4, typename A4>
        uint64 add_task_by_value (
            const T& obj,
            void (T::*funct)(T1,T2,T3,T4) const,
            future<A1>& arg1,
            future<A2>& arg2,
            future<A3>& arg3,
            future<A4>& arg4
        )
        {
            thread_pool_implementation::function_object_copy_instance<const T>* ptr = 0;
            ptr = new thread_pool_implementation::function_object_copy_instance<const T>(obj);
            shared_ptr<thread_pool_implementation::function_object_copy> function_copy(ptr);

            bfp_type temp;
            temp.set(ptr->item, funct, arg1.get(), arg2.get(), arg3.get(), arg4.get());
            uint64 id = impl->add_task_internal(temp, function_copy);

            // tie the futures to this task
            arg1.task_id = id;
            arg1.tp = impl;
            arg2.task_id = id;
            arg2.tp = impl;
            arg3.task_id = id;
            arg3.tp = impl;
            arg4.task_id = id;
            arg4.tp = impl;
            return id;
        }

        template <typename T1, typename A1,
                  typename T2, typename A2,
                  typename T3, typename A3,
                  typename T4, typename A4>
        uint64 add_task (
            void (*funct)(T1,T2,T3,T4),
            future<A1>& arg1,
            future<A2>& arg2,
            future<A3>& arg3,
            future<A4>& arg4
        )
        {
            bfp_type temp;
            temp.set(funct, arg1.get(), arg2.get(), arg3.get(), arg4.get());
            uint64 id = impl->add_task_internal(temp);

            // tie the futures to this task
            arg1.task_id = id;
            arg1.tp = impl;
            arg2.task_id = id;
            arg2.tp = impl;
            arg3.task_id = id;
            arg3.tp = impl;
            arg4.task_id = id;
            arg4.tp = impl;
            return id;
        }

    private:

        shared_ptr_thread_safe<thread_pool_implementation> impl;

        // restricted functions
        thread_pool(thread_pool&);        // copy constructor
        thread_pool& operator=(thread_pool&);    // assignment operator

    };

// ----------------------------------------------------------------------------------------

    template <typename T>
    void future<T>::
    wait (
    ) const
    {
        if (tp)
        {
            tp->wait_for_task(task_id);
            tp.reset();
            task_id = 0;
        }
    }

}

// ----------------------------------------------------------------------------------------

#ifdef NO_MAKEFILE
#include "thread_pool_extension.cpp"
#endif

#endif // DLIB_THREAD_POOl_Hh_


dlib C++ Library - thread_specific_data_extension.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_THREAD_SPECIFIC_DATA_EXTENSIOn_
#define DLIB_THREAD_SPECIFIC_DATA_EXTENSIOn_

#include "thread_specific_data_extension_abstract.h"
#include "threads_kernel_abstract.h"
#include "../binary_search_tree.h"
#include "auto_mutex_extension.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    class thread_specific_data
    {
        /*!
            CONVENTION
                - for all valid ID:
                  (*items[ID]) == pointer to the data for thread with id ID
        !*/
    public:

        thread_specific_data (
        )
        {
            thread_end_handler_calls_left = 0;
        }

        ~thread_specific_data (
        )
        {
            // We should only call the unregister_thread_end_handler function if there are
            // some outstanding callbacks we expect to get.  Otherwise lets avoid calling it
            // since the dlib state that maintains the registered thread end handlers may have
            // been destructed already (since the program might be in the process of terminating).
            bool call_unregister = false;
            m.lock();
            if (thread_end_handler_calls_left > 0)
                call_unregister = true;
            m.unlock();

            if (call_unregister)
                unregister_thread_end_handler(const_cast<thread_specific_data&>(*this),&thread_specific_data::thread_end_handler);

            auto_mutex M(m);
            items.reset();
            while (items.move_next())
            {
                delete items.element().value();
            }
        }

        inline T& data (
        ) { return get_data(); }

        inline const T& data (
        ) const { return get_data(); }

    private:

        T& get_data (
        ) const
        {
            thread_id_type id = get_thread_id();
            auto_mutex M(m);

            T** item = items[id];
            if (item)
            {
                return **item;
            }
            else
            {
                // register an end handler for this thread so long as it is a dlib created thread.
                T* new_item = new T;

                bool in_tree = false;
                try
                {
                    T* temp_item = new_item;
                    thread_id_type temp_id = id;
                    items.add(temp_id,temp_item);
                    in_tree = true;

                    if (is_dlib_thread(id))
                    {
                        register_thread_end_handler(const_cast<thread_specific_data&>(*this),&thread_specific_data::thread_end_handler);
                        ++thread_end_handler_calls_left;
                    }
                }
                catch (...)
                {
                    if (in_tree)
                    {
                        items.destroy(id);
                    }
                    delete new_item;
                    throw;
                }

                return *new_item;
            }
        }

        void thread_end_handler (
        )
        {
            const thread_id_type id = get_thread_id();
            thread_id_type junk = 0;
            T* item = 0;
            auto_mutex M(m);
            --thread_end_handler_calls_left;
            if (items[id])
            {
                items.remove(id,junk,item);
                delete item;
            }
        }

        mutable typename binary_search_tree<thread_id_type,T*>::kernel_2a items;
        mutex m;
        mutable long thread_end_handler_calls_left;

        // restricted functions
        thread_specific_data(thread_specific_data&);        // copy constructor
        thread_specific_data& operator=(thread_specific_data&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_THREAD_SPECIFIC_DATA_EXTENSIOn_


dlib C++ Library - thread_specific_data_extension_abstract.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_THREAD_SPECIFIC_DATA_EXTENSIOn_ABSTRACT_
#ifdef DLIB_THREAD_SPECIFIC_DATA_EXTENSIOn_ABSTRACT_

#include "threads_kernel_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    class thread_specific_data
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object represents a container of thread specific data.  When
                a thread calls the data() member function it gets a reference to a T object
                that is specific to its own thread.  Each subsequent call to data() from that
                thread returns the same instance.  Also note that when a thread ends
                the instance of its data() object gets destroyed and freed (if the thread
                was created by the dlib library).  So any pointers or references to the object
                will be invalid after the thread has ended.
        !*/
    public:

        thread_specific_data (
        );
        /*!
            ensures
                - #*this is properly initialized
        !*/

        ~thread_specific_data (
        );
        /*!
            ensures
                - all resources allocated by *this have been freed.  This includes
                  all the thread specific data returned by the data() functions.
        !*/

        T& data (
        );
        /*!
            ensures
                - if (the calling thread has NOT called this->data() before) then
                    - constructs an instance of T that is specific to the calling
                      thread.
                - returns a reference to the T instance that was constructed for
                  the calling thread.
            throws
                - std::bad_alloc or any exception thrown by T's constructor
                  If an exception is thrown then the call to data() will have
                  no effect on *this.
        !*/

        const T& data (
        ) const;
        /*!
            ensures
                - if (the calling thread has NOT called this->data() before) then
                    - constructs an instance of T that is specific to the calling
                      thread.
                - returns a const reference to the T instance that was constructed for
                  the calling thread.
            throws
                - std::bad_alloc or any exception thrown by T's constructor
                  If an exception is thrown then the call to data() will have
                  no effect on *this.
        !*/

    private:
        // restricted functions
        thread_specific_data(thread_specific_data&);        // copy constructor
        thread_specific_data& operator=(thread_specific_data&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_THREAD_SPECIFIC_DATA_EXTENSIOn_ABSTRACT_


dlib C++ Library - threaded_object_extension.cpp

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_THREADED_OBJECT_EXTENSIOn_CPP
#define DLIB_THREADED_OBJECT_EXTENSIOn_CPP

#include "threaded_object_extension.h"
#include "create_new_thread_extension.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    threaded_object::
    threaded_object (
    ):
        s(m_),
        id1(0),
        is_running_(false),
        is_alive_(false),
        should_stop_(false),
        id_valid(false)
    {
    }

// ----------------------------------------------------------------------------------------

    threaded_object::
    ~threaded_object (
    )
    {
        try
        {
            DLIB_ASSERT(is_alive() == false,
                   "\tthreaded_object::~threaded_object()"
                   << "\n\tYou have let a threaded object destruct itself before terminating its thread"
                   << "\n\tthis: " << this
            );
        }
        catch (std::exception& e)
        {
            std::cerr << e.what() << std::endl;
            assert(false);
            abort();
        }
    }

// ----------------------------------------------------------------------------------------

    bool threaded_object::
    is_running (
    ) const
    {
        auto_mutex M(m_);

        DLIB_ASSERT(id1 != get_thread_id() || id_valid == false,
               "\tbool threaded_object::is_running()"
               << "\n\tYou can NOT call this function from the thread that executes threaded_object::thread"
               << "\n\tthis: " << this
        );

        return is_running_;
    }

// ----------------------------------------------------------------------------------------

    bool threaded_object::
    is_alive (
    ) const
    {
        auto_mutex M(m_);

        DLIB_ASSERT(id1 != get_thread_id() || id_valid == false,
               "\tbool threaded_object::is_alive()"
               << "\n\tYou can NOT call this function from the thread that executes threaded_object::thread"
               << "\n\tthis: " << this
        );

        return is_alive_;
    }

// ----------------------------------------------------------------------------------------

    void threaded_object::
    wait (
    ) const
    {
        auto_mutex M(m_);

        DLIB_ASSERT(id1 != get_thread_id() || id_valid == false,
               "\tvoid threaded_object::wait()"
               << "\n\tYou can NOT call this function from the thread that executes threaded_object::thread"
               << "\n\tthis: " << this
        );

        while (is_alive_)
            s.wait();
    }

// ----------------------------------------------------------------------------------------

    void threaded_object::
    start (
    )
    {
        auto_mutex M(m_);

        DLIB_ASSERT(id1 != get_thread_id() || id_valid == false,
               "\tvoid threaded_object::start()"
               << "\n\tYou can NOT call this function from the thread that executes threaded_object::thread"
               << "\n\tthis: " << this
        );

        if (is_alive_ == false)
        {
            if (create_new_thread<threaded_object,&threaded_object::thread_helper>(*this) == false)
            {
                is_running_ = false;
                throw thread_error();
            }
        }
        is_alive_ = true;
        is_running_ = true;
        should_stop_ = false;
        s.broadcast();
    }

// ----------------------------------------------------------------------------------------

    void threaded_object::
    restart (
    )
    {
        auto_mutex M(m_);

        DLIB_ASSERT(id1 != get_thread_id() || id_valid == false,
               "\tvoid threaded_object::restart()"
               << "\n\tYou can NOT call this function from the thread that executes threaded_object::thread"
               << "\n\tthis: " << this
        );

        if (is_alive_ == false)
        {
            if (create_new_thread<threaded_object,&threaded_object::thread_helper>(*this) == false)
            {
                is_running_ = false;
                throw thread_error();
            }
            should_respawn_ = false;
        }
        else
        {
            should_respawn_ = true;
        }
        is_alive_ = true;
        is_running_ = true;
        should_stop_ = false;
        s.broadcast();
    }

// ----------------------------------------------------------------------------------------

    void threaded_object::
    set_respawn (
    )
    {
        auto_mutex M(m_);

        DLIB_ASSERT(id1 != get_thread_id() || id_valid == false,
               "\tvoid threaded_object::set_respawn()"
               << "\n\tYou can NOT call this function from the thread that executes threaded_object::thread"
               << "\n\tthis: " << this
        );

        should_respawn_ = true;
    }

// ----------------------------------------------------------------------------------------

    bool threaded_object::
    should_respawn (
    ) const
    {
        auto_mutex M(m_);

        DLIB_ASSERT(id1 != get_thread_id() || id_valid == false,
               "\tbool threaded_object::should_respawn()"
               << "\n\tYou can NOT call this function from the thread that executes threaded_object::thread"
               << "\n\tthis: " << this
        );

        return should_respawn_;
    }

// ----------------------------------------------------------------------------------------

    void threaded_object::
    pause (
    )
    {
        auto_mutex M(m_);

        DLIB_ASSERT(id1 != get_thread_id() || id_valid == false,
               "\tvoid threaded_object::pause()"
               << "\n\tYou can NOT call this function from the thread that executes threaded_object::thread"
               << "\n\tthis: " << this
        );

        is_running_ = false;
    }

// ----------------------------------------------------------------------------------------

    void threaded_object::
    stop (
    )
    {
        auto_mutex M(m_);

        DLIB_ASSERT(id1 != get_thread_id() || id_valid == false,
               "\tvoid threaded_object::stop()"
               << "\n\tYou can NOT call this function from the thread that executes threaded_object::thread"
               << "\n\tthis: " << this
        );

        should_stop_ = true;
        is_running_ = false;
        should_respawn_ = false;
        s.broadcast();
    }

// ----------------------------------------------------------------------------------------

    bool threaded_object::
    should_stop (
    ) const
    {
        auto_mutex M(m_);
        DLIB_ASSERT(is_alive_ && id1 == get_thread_id() && id_valid == true,
               "\tbool threaded_object::should_stop()"
               << "\n\tYou can only call this function from the thread that executes threaded_object::thread"
               << "\n\tthis: " << this
        );
        while (is_running_ == false && should_stop_ == false)
            s.wait();
        return should_stop_;
    }

// ----------------------------------------------------------------------------------------

    void threaded_object::
    thread_helper(
    )
    {
#ifdef ENABLE_ASSERTS
        id1 = get_thread_id();
        id_valid = true;
#endif
        while (true)
        {
            m_.lock();
            should_respawn_ = false;
            m_.unlock();

            thread();

            auto_mutex M(m_);

            if (should_respawn_)
                continue;

#ifdef ENABLE_ASSERTS
            id_valid = false;
#endif

            is_alive_ = false;
            is_running_ = false;
            should_stop_ = false;
            s.broadcast();

            return;
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_THREADED_OBJECT_EXTENSIOn_CPP


dlib C++ Library - threaded_object_extension.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_THREADED_OBJECT_EXTENSIOn_
#define DLIB_THREADED_OBJECT_EXTENSIOn_

#include "threaded_object_extension_abstract.h"
#include "threads_kernel.h"
#include "auto_mutex_extension.h"
#include "../algs.h"
#include "../assert.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class threaded_object
    {
        /*!
            INITIAL VALUE
                - is_running_ == false
                - is_alive_ == false
                - should_stop_ == false
                - should_respawn_ == false

#ifdef ENABLE_ASSERTS
                - id_valid == false
                - id1 == get_main_thread_id()
#endif

            CONVENTION
                - is_running() == is_running_
                - is_alive() == is_alive_
                - should_stop() == should_stop_
                - should_respawn() == should_respawn_

#ifdef ENABLE_ASSERTS
                - if (when thread() is executing) then
                    - id1 == the id of the running thread
                    - id_valid == true
                - else
                    - id1 == an undefined value
                    - id_valid == false
#endif

                - m_ == the mutex used to protect all our variables
                - s == the signaler for m_
        !*/

    public:

        threaded_object (
        );

        virtual ~threaded_object (
        );

        bool is_running (
        ) const;

        bool is_alive (
        ) const;

        void wait (
        ) const;

        void start (
        );

        void restart (
        );

        void set_respawn (
        );

        bool should_respawn (
        ) const;

        void pause (
        );

        void stop (
        );

    protected:

        bool should_stop (
        ) const;

    private:

        void thread_helper(
        );

        virtual void thread (
        ) = 0;

        mutex m_;
        signaler s;
        thread_id_type id1;
        bool is_running_;
        bool is_alive_;
        bool should_stop_;
        bool should_respawn_;
        bool id_valid;

        // restricted functions
        threaded_object(threaded_object&);        // copy constructor
        threaded_object& operator=(threaded_object&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------

}

#ifdef NO_MAKEFILE
#include "threaded_object_extension.cpp"
#endif

#endif // DLIB_THREADED_OBJECT_EXTENSIOn_


dlib C++ Library - threaded_object_extension_abstract.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_THREADED_OBJECT_EXTENSIOn_ABSTRACT_
#ifdef DLIB_THREADED_OBJECT_EXTENSIOn_ABSTRACT_

#include "threads_kernel_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class threaded_object
    {
        /*!
            INITIAL VALUE
                - is_running() == false
                - is_alive() == false
                - should_respawn() == false

            WHAT THIS OBJECT REPRESENTS
                This object represents a simple threaded object.  To use it you inherit
                from it and define the thread() function.  Then when you call start()
                it will spawn a thread that calls this->thread().
        !*/
    public:

        threaded_object (
        );
        /*!
            ensures
                - #*this is properly initialized
            throws
                - std::bad_alloc
                - dlib::thread_error
                    the constructor may throw this exception if there is a problem
                    gathering resources to create threading objects.
        !*/

        virtual ~threaded_object (
        );
        /*!
            requires
                - is_alive() == false
                  (i.e. in the destructor for the object you derive from this one you
                  must wait for this->thread() to end.)
            ensures
                - all resources allocated by *this have been freed.
        !*/

        bool is_running (
        ) const;
        /*!
            requires
                - is not called from this->thread()
            ensures
                - if (is_alive() && this->thread() is currently supposed to be executing) then
                    - returns true
                - else
                    - returns false
        !*/

        bool is_alive (
        ) const;
        /*!
            requires
                - is not called from this->thread()
            ensures
                - if (this->thread() has been called by some thread and has yet to terminate) then
                    - returns true
                - else
                    - returns false
        !*/

        void wait (
        ) const;
        /*!
            requires
                - is not called from this->thread()
            ensures
                - if (is_alive() == true) then
                    - blocks until this->thread() terminates
        !*/

        void start (
        );
        /*!
            requires
                - is not called from this->thread()
            ensures
                - #is_alive() == true
                - #is_running() == true
                - #should_stop() == false
            throws
                - std::bad_alloc or dlib::thread_error
                    If either of these exceptions are thrown then
                    #is_alive() == false and #is_running() == false
        !*/

        void set_respawn (
        );
        /*!
            requires
                - is not called from this->thread()
            ensures
                - #should_respawn() == true
        !*/

        bool should_respawn (
        ) const;
        /*!
            requires
                - is not called from this->thread()
            ensures
                - returns true if the thread will automatically restart upon termination and
                  false otherwise.  Note that every time a thread starts it sets should_respawn()
                  back to false.  Therefore, a single call to set_respawn() can cause at most
                  one respawn to occur.
        !*/

        void restart (
        );
        /*!
            requires
                - is not called from this->thread()
            ensures
                - This function atomically executes set_respawn() and start().  The precise meaning of this
                  is defined below.
                - if (is_alive()) then
                    - #should_respawn() == true
                - else
                    - #should_respawn() == false
                - #is_alive() == true
                - #is_running() == true
                - #should_stop() == false
            throws
                - std::bad_alloc or dlib::thread_error
                    If either of these exceptions are thrown then
                    #is_alive() == false and #is_running() == false
        !*/

        void pause (
        );
        /*!
            requires
                - is not called from this->thread()
            ensures
                - #is_running() == false
        !*/

        void stop (
        );
        /*!
            requires
                - is not called from this->thread()
            ensures
                - #should_stop() == true
                - #is_running() == false
                - #should_respawn() == false
        !*/

    protected:

        bool should_stop (
        ) const;
        /*!
            requires
                - is only called from the thread that executes this->thread()
            ensures
                - calls to this function block until (#is_running() == true || #should_stop() == true)
                - if (this thread is supposed to terminate) then
                    - returns true
                - else
                    - returns false
        !*/

    private:

        virtual void thread (
        ) = 0;
        /*!
            requires
                - is executed in its own thread
                - is only executed in one thread at a time
            throws
                - does not throw any exceptions
        !*/

        // restricted functions
        threaded_object(threaded_object&);        // copy constructor
        threaded_object& operator=(threaded_object&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_THREADED_OBJECT_EXTENSIOn_ABSTRACT_


dlib C++ Library - threads_kernel.h

// Copyright (C) 2006  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_THREADs_KERNEL_
#define DLIB_THREADs_KERNEL_

#include "../platform.h"

#ifdef WIN32
#include "windows.h"
#endif

#ifndef WIN32
#include "posix.h"
#endif

#endif // DLIB_THREADs_KERNEL_


dlib C++ Library - threads_kernel_1.cpp

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_THREADS_KERNEL_1_CPp_
#define DLIB_THREADS_KERNEL_1_CPp_

#include "../platform.h"

#ifdef WIN32

#include "threads_kernel_1.h"

#include <process.h>

namespace dlib
{
    namespace threads_kernel_shared_helpers
    {

    // -----------------------------------------------------------------------------------

        struct info
        {
            void* param;
            void (*funct)(void*);
        };

    // -----------------------------------------------------------------------------------

        unsigned int __stdcall thread_starter (
            void* param
        )
        {
            info* alloc_p = static_cast<info*>(param);
            info p = *alloc_p;
            delete alloc_p;

            p.funct(p.param);
            return 0;
        }

    // -----------------------------------------------------------------------------------

        bool spawn_thread (
            void (*funct)(void*),
            void* param
        )
        {
            info* p;
            try { p = new info; }
            catch (...) { return false; }

            p->funct = funct;
            p->param = param;

            unsigned int garbage;

            HANDLE thandle = (HANDLE)_beginthreadex (NULL,0,thread_starter,p,0,&garbage);
            // make thread and add it to the pool

            // return false if _beginthreadex didn't work
            if ( thandle == 0)
            {
                delete p;
                return false;
            }

            // throw away the thread handle
            CloseHandle(thandle);
            return true;
        }

    // -----------------------------------------------------------------------------------

    }

}

#endif // WIN32

#endif // DLIB_THREADS_KERNEL_1_CPp_


dlib C++ Library - threads_kernel_1.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_THREADS_KERNEl_1_
#define DLIB_THREADS_KERNEl_1_

#ifdef DLIB_ISO_CPP_ONLY
#error "DLIB_ISO_CPP_ONLY is defined so you can't use this OS dependent code.  Turn DLIB_ISO_CPP_ONLY off if you want to use it."
#endif

#include "threads_kernel_abstract.h"

#include "../windows_magic.h"
#include <windows.h>
#include "../algs.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    typedef DWORD thread_id_type;

    inline thread_id_type get_thread_id (
    )
    {
        return GetCurrentThreadId();
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // mutex object
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    // forward declaration of signaler
    class signaler;

    class mutex
    {
    public:

        mutex (
        )
        {
            InitializeCriticalSection(&cs);
        }

        ~mutex (
        ) { DeleteCriticalSection(&cs); }

        void lock (
        ) const { EnterCriticalSection(&cs); }

        void unlock (
        ) const { LeaveCriticalSection(&cs); }

    private:

        mutable CRITICAL_SECTION cs;

        // restricted functions
        mutex(mutex&);        // copy constructor
        mutex& operator=(mutex&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // signaler object
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class signaler
    {

    public:
        signaler (
            const mutex& associated_mutex
        ) :
            hSemaphore(CreateSemaphore (NULL, 0, 100000000, NULL)),
            waiters(0),
            hCountSema(CreateSemaphore (NULL,0,100000000,NULL)),
            m(associated_mutex)
        {
            if (hSemaphore == NULL || hCountSema == NULL)
            {
                if (hSemaphore != NULL)
                {
                    CloseHandle(hSemaphore);
                }

                if (hCountSema != NULL)
                {
                    CloseHandle(hCountSema);
                }

                throw dlib::thread_error(ECREATE_SIGNALER,
        "in function signaler::signaler() an error occurred making the signaler"
                );
            }
        }

        ~signaler (
        ) { CloseHandle(hSemaphore); CloseHandle(hCountSema);}

        void wait (
        ) const
        {
            // get a lock on the mutex for the waiters variable
            waiters_mutex.lock();
            // mark that one more thread will be waiting on this signaler
            ++waiters;
            // release the mutex for waiters
            waiters_mutex.unlock();

            // release the associated mutex
            m.unlock();

            // wait for the semaphore to be signaled
            WaitForSingleObject (hSemaphore,INFINITE);

            // signal that we are awake
            ReleaseSemaphore(hCountSema,(LONG)1,NULL);

            // relock the associated mutex
            m.lock();
        }

        bool wait_or_timeout (
            unsigned long milliseconds
        ) const
        {
            // get a lock on the mutex for the waiters variable
            waiters_mutex.lock();
            // mark that one more thread will be waiting on this signaler
            ++waiters;
            // release the mutex for waiters
            waiters_mutex.unlock();

            // release the associated mutex
            m.unlock();

            bool value;

            // wait for the semaphore to be signaled
            if ( WaitForSingleObject (hSemaphore, milliseconds ) == WAIT_TIMEOUT )
            {
                // in this case we should decrement waiters because we are returning
                // due to a timeout rather than because someone called signal() or
                // broadcast().
                value = false;

                // signal that we are awake
                ReleaseSemaphore(hCountSema,(LONG)1,NULL);

                // get a lock on the mutex for the waiters variable
                waiters_mutex.lock();
                // mark that one less thread will be waiting on this signaler.
                if (waiters != 0)
                    --waiters;
                // release the mutex for waiters
                waiters_mutex.unlock();
            }
            else
            {
                value = true;

                // signal that we are awake
                ReleaseSemaphore(hCountSema,(LONG)1,NULL);
            }

            // relock the associated mutex
            m.lock();

            return value;
        }

        void signal (
        ) const
        {
            // get a lock on the mutex for the waiters variable
            waiters_mutex.lock();

            if (waiters > 0)
            {
                --waiters;
                // make the semaphore release one waiting thread
                ReleaseSemaphore(hSemaphore,1,NULL);

                // wait for signaled thread to wake up
                WaitForSingleObject(hCountSema,INFINITE);
            }

            // release the mutex for waiters
            waiters_mutex.unlock();
        }

        void broadcast (
        ) const
        {
            // get a lock on the mutex for the waiters variable
            waiters_mutex.lock();

            if (waiters > 0)
            {
                // make the semaphore release all the waiting threads
                ReleaseSemaphore(hSemaphore,(LONG)waiters,NULL);

                // wait for count to be zero
                for (unsigned long i = 0; i < waiters; ++i)
                {
                    WaitForSingleObject(hCountSema,INFINITE);
                }

                waiters = 0;
            }

            // release the mutex for waiters
            waiters_mutex.unlock();
        }

        const mutex& get_mutex (
        ) const { return m; }

    private:

        mutable HANDLE hSemaphore;

        mutable unsigned long waiters;
        mutex waiters_mutex;

        mutable HANDLE hCountSema;

        const mutex& m;

        // restricted functions
        signaler(signaler&);        // copy constructor
        signaler& operator=(signaler&);    // assignment operator
    };

// ----------------------------------------------------------------------------------------

    namespace threads_kernel_shared_helpers
    {
        bool spawn_thread (
            void (*funct)(void*),
            void* param
        );
        /*!
            is identical to create_new_thread() but just doesn't use any thread pooling.
        !*/
    }

// ----------------------------------------------------------------------------------------

}

#include "threads_kernel_shared.h"

#ifdef NO_MAKEFILE
#include "threads_kernel_1.cpp"
#endif

#endif // DLIB_THREADS_KERNEl_1_


dlib C++ Library - threads_kernel_2.cpp

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_THREADS_KERNEL_2_CPp_
#define DLIB_THREADS_KERNEL_2_CPp_

#include "../platform.h"

#ifdef POSIX

#include "threads_kernel_2.h"

namespace dlib
{
    namespace threads_kernel_shared_helpers
    {

    // -----------------------------------------------------------------------------------

        struct info
        {
            void* param;
            void (*funct)(void*);
        };

    // -----------------------------------------------------------------------------------

        void* thread_starter (
            void* param
        )
        {
            info* alloc_p = static_cast<info*>(param);
            info p = *alloc_p;
            delete alloc_p;

            // detach self
            pthread_detach(pthread_self());

            p.funct(p.param);
            return 0;
        }

    // -----------------------------------------------------------------------------------

        bool spawn_thread (
            void (*funct)(void*),
            void* param
        )
        {
            info* p;
            try { p = new info; }
            catch (...) { return false; }

            p->funct = funct;
            p->param = param;

            pthread_t thread_id;
            if ( pthread_create (&thread_id, 0, thread_starter, p) )
            {
                delete p;
                return false;
            }
            return true;
        }

    // -----------------------------------------------------------------------------------

    }

}

#endif // POSIX

#endif // DLIB_THREADS_KERNEL_2_CPp_


dlib C++ Library - threads_kernel_2.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_THREADS_KERNEl_2_
#define DLIB_THREADS_KERNEl_2_

#ifdef DLIB_ISO_CPP_ONLY
#error "DLIB_ISO_CPP_ONLY is defined so you can't use this OS dependent code.  Turn DLIB_ISO_CPP_ONLY off if you want to use it."
#endif

#include "threads_kernel_abstract.h"
#include <pthread.h>
#include <errno.h>
#include <sys/time.h>
#include "../algs.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    typedef pthread_t thread_id_type;

    inline thread_id_type get_thread_id (
    )
    {
        return pthread_self();
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // mutex object
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    // forward declaration of signaler
    class signaler;

    class mutex
    {
        // give signaler access to hMutex
        friend class signaler;
    public:

        mutex (
        )
        {
            if (pthread_mutex_init(&myMutex,0))
            {
                throw dlib::thread_error(ECREATE_MUTEX,
        "in function mutex::mutex() an error occurred making the mutex"
                );
            }
        }

        ~mutex (
        ) { pthread_mutex_destroy(&myMutex); }

        void lock (
        ) const { pthread_mutex_lock(&myMutex); }

        void unlock (
        ) const { pthread_mutex_unlock(&myMutex); }

    private:

        mutable pthread_mutex_t myMutex;

        // restricted functions
        mutex(mutex&);        // copy constructor
        mutex& operator=(mutex&);    // assignement opertor
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // signaler object
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class signaler
    {

    public:

        signaler (
            const mutex& assoc_mutex
        ) :
            associated_mutex(&assoc_mutex.myMutex),
            m(assoc_mutex)
        {
            if (pthread_cond_init(&cond,0))
            {
                throw dlib::thread_error(ECREATE_SIGNALER,
        "in function signaler::signaler() an error occurred making the signaler"
                );
            }
        }

        ~signaler (
        ) { pthread_cond_destroy(&cond); }

        void wait (
        ) const
        {
            pthread_cond_wait(&cond,associated_mutex);
        }

        bool wait_or_timeout (
            unsigned long milliseconds
        ) const
        {
            timespec time_to_wait;

            timeval curtime;
            gettimeofday(&curtime,0);

            // get the time and adjust the timespec object by the appropriate amount
            time_to_wait.tv_sec = milliseconds/1000 + curtime.tv_sec;
            time_to_wait.tv_nsec = curtime.tv_usec;
            time_to_wait.tv_nsec *= 1000;
            time_to_wait.tv_nsec += (milliseconds%1000)*1000000;

            time_to_wait.tv_sec += time_to_wait.tv_nsec/1000000000;
            time_to_wait.tv_nsec = time_to_wait.tv_nsec%1000000000;

            if ( pthread_cond_timedwait(&cond,associated_mutex,&time_to_wait) == ETIMEDOUT)
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        void signal (
        ) const { pthread_cond_signal(&cond); }

        void broadcast (
        ) const { pthread_cond_broadcast(&cond); }

        const mutex& get_mutex (
        ) const { return m; }

    private:

        pthread_mutex_t* const associated_mutex;
        mutable pthread_cond_t  cond;
        const mutex& m;

        // restricted functions
        signaler(signaler&);        // copy constructor
        signaler& operator=(signaler&);    // assignement opertor
    };

// ----------------------------------------------------------------------------------------

    namespace threads_kernel_shared_helpers
    {
        bool spawn_thread (
            void (*funct)(void*),
            void* param
        );
        /*!
            is identical to create_new_thread() but just doesn't use any thread pooling.
        !*/
    }

// ----------------------------------------------------------------------------------------

}

#include "threads_kernel_shared.h"

#ifdef NO_MAKEFILE
#include "threads_kernel_2.cpp"
#endif

#endif // DLIB_THREADS_KERNEl_2_


dlib C++ Library - threads_kernel_shared.cpp

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_THREADS_KERNEL_SHARED_CPp_
#define DLIB_THREADS_KERNEL_SHARED_CPp_

#include "threads_kernel_shared.h"
#include "../assert.h"
#include "../platform.h"
#include <iostream>

// The point of this block of code is to cause a link time error that will prevent a user
// from compiling part of their application with DLIB_ASSERT enabled and part with them
// disabled since doing that would be a violation of C++'s one definition rule.
extern "C"
{
#ifdef ENABLE_ASSERTS
    int USER_ERROR__missing_dlib_all_source_cpp_file__OR__inconsistent_use_of_DEBUG_or_ENABLE_ASSERTS_preprocessor_directives;
#else
    int USER_ERROR__missing_dlib_all_source_cpp_file__OR__inconsistent_use_of_DEBUG_or_ENABLE_ASSERTS_preprocessor_directives_;
#endif
}

#ifndef DLIB_THREAD_POOL_TIMEOUT
// default to 30000 milliseconds
#define DLIB_THREAD_POOL_TIMEOUT 30000
#endif

namespace dlib
{

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// threader functions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    namespace threads_kernel_shared
    {

        bool thread_pool_has_been_destroyed = false;

// ----------------------------------------------------------------------------------------

        threader& thread_pool (
        )
        {
            static threader* thread_pool = new threader;
            return *thread_pool;
        }

// ----------------------------------------------------------------------------------------

        struct threader_destruct_helper
        {
            // cause the thread pool to begin its destruction process when
            // global objects start to be destroyed
            ~threader_destruct_helper()
            {
                thread_pool().destruct_if_ready();
            }
        };
        static threader_destruct_helper a;

// ----------------------------------------------------------------------------------------

        bool threader::
        is_dlib_thread (
            thread_id_type id
        )
        {
            auto_mutex M(data_mutex);
            return thread_ids.is_member(id);
        }

// ----------------------------------------------------------------------------------------

        threader::
        threader (
        ) :
            total_count(0),
            function_pointer(0),
            pool_count(0),
            data_ready(data_mutex),
            data_empty(data_mutex),
            destruct(false),
            destructed(data_mutex),
            do_not_ever_destruct(false)
        {
#ifdef WIN32
            // Trying to destroy the global thread pool when we are part of a DLL and the
            // DLL is being unloaded can sometimes lead to weird behavior.  For example, in
            // the python interpreter you will get the interpreter to hang.  Or if we are
            // part of a MATLAB mex file and the file is being unloaded there can also be
            // similar weird issues.  So when we are using dlib on windows we just disable
            // the destruction of the global thread pool since it doesn't matter anyway.
            // It's resources will just get freed by the OS.  This is even the recommended
            // thing to do by Microsoft (http://blogs.msdn.com/b/oldnewthing/archive/2012/01/05/10253268.aspx).
            //
            // As an aside, it's worth pointing out that the reason we try and free
            // resources on program shutdown on other operating systems is so we can have
            // clean reports from tools like valgrind which check for memory leaks.  But
            // trying to do this on windows is a lost cause so we give up in this case and
            // follow the Microsoft recommendation.
            do_not_ever_destruct = true;
#endif // WIN32
        }

// ----------------------------------------------------------------------------------------

        threader::
        ~threader (
        )
        {
            data_mutex.lock();
            destruct = true;
            data_ready.broadcast();

            // wait for all the threads to end
            while (total_count > 0)
                destructed.wait();

            thread_pool_has_been_destroyed = true;
            data_mutex.unlock();
        }

// ----------------------------------------------------------------------------------------

        void threader::
        destruct_if_ready (
        )
        {
            if (do_not_ever_destruct)
                return;

            data_mutex.lock();

            // if there aren't any active threads, just maybe some sitting around
            // in the pool then just destroy the threader
            if (total_count == pool_count)
            {
                destruct = true;
                data_ready.broadcast();
                data_mutex.unlock();
                delete this;
            }
            else
            {
                // There are still some user threads running so there isn't
                // much we can really do.  Just let the program end without
                // cleaning up threading resources.
                data_mutex.unlock();
            }
        }

// ----------------------------------------------------------------------------------------

        void threader::
        call_end_handlers (
        )
        {
            reg.m.lock();
            const thread_id_type id = get_thread_id();
            thread_id_type id_copy;
            member_function_pointer<> mfp;

            // Remove all the member function pointers for this thread from the tree
            // and call them.
            while (reg.reg[id] != 0)
            {
                reg.reg.remove(id,id_copy,mfp);
                reg.m.unlock();
                mfp();
                reg.m.lock();
            }
            reg.m.unlock();
        }

    // ------------------------------------------------------------------------------------

        bool threader::
        create_new_thread (
            void (*funct)(void*),
            void* param
        )
        {

            // get a lock on the data mutex
            auto_mutex M(data_mutex);

            // loop to ensure that the new function pointer is in the data
            while (true)
            {
                // if the data is empty then add new data and quit loop
                if (function_pointer == 0)
                {
                    parameter = param;
                    function_pointer = funct;
                    break;
                }
                else
                {
                    // wait for data to become empty
                    data_empty.wait();
                }
            }

            // get a thread for this new data
            // if a new thread must be created
            if (pool_count == 0)
            {
                // make thread and add it to the pool
                if ( threads_kernel_shared_helpers::spawn_thread(thread_starter, this) == false )
                {
                    function_pointer = 0;
                    parameter = 0;
                    data_empty.signal();
                    return false;
                }
                ++total_count;
            }
            // wake up a thread from the pool
            else
            {
                data_ready.signal();
            }

            return true;
        }

    // ------------------------------------------------------------------------------------

        void thread_starter (
            void* object
        )
        {
            // get a reference to the calling threader object
            threader& self = *static_cast<threader*>(object);

            {
            auto_mutex M(self.data_mutex);

            // add this thread id
            thread_id_type thread_id = get_thread_id();
            self.thread_ids.add(thread_id);

            // indicate that this thread is now in the thread pool
            ++self.pool_count;

            while (self.destruct == false)
            {
                // if data is ready then process it and launch the thread
                // if its not ready then go back into the pool
                while (self.function_pointer != 0)
                {
                    // indicate that this thread is now out of the thread pool
                    --self.pool_count;

                    // get the data for the function call
                    void (*funct)(void*) = self.function_pointer;
                    void* param = self.parameter;
                    self.function_pointer = 0;

                    // signal that the data is now empty
                    self.data_empty.signal();

                    self.data_mutex.unlock();
                    // Call funct with its intended parameter.  If this function throws then
                    // we intentionally let the exception escape the thread and result in whatever
                    // happens when it gets caught by the OS (generally the program is terminated).
                    funct(param);
                    self.call_end_handlers();

                    self.data_mutex.lock();

                    // indicate that this thread is now back in the thread pool
                    ++self.pool_count;
                }

                if (self.destruct == true)
                    break;

                // if we timed out and there isn't any work to do then
                // this thread will quit this loop and end.
                if (self.data_ready.wait_or_timeout(DLIB_THREAD_POOL_TIMEOUT) == false &&
                    self.function_pointer == 0)
                    break;

            }

            // remove this thread id from thread_ids
            thread_id = get_thread_id();
            self.thread_ids.destroy(thread_id);

            // indicate that this thread is now out of the thread pool
            --self.pool_count;
            --self.total_count;

            self.destructed.signal();

            } // end of auto_mutex M(self.data_mutex) block
        }

    // ------------------------------------------------------------------------------------

    }

// ----------------------------------------------------------------------------------------

    bool is_dlib_thread (
        thread_id_type id
    )
    {
        return threads_kernel_shared::thread_pool().is_dlib_thread(id);
    }

    bool is_dlib_thread (
    )
    {
        return is_dlib_thread(get_thread_id());
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_THREADS_KERNEL_SHARED_CPp_


dlib C++ Library - threads_kernel_shared.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_THREADS_KERNEl_SHARED_
#define DLIB_THREADS_KERNEl_SHARED_

// this file should be included at the bottom of one of the thread kernel headers for a
// specific platform.
//#include "../threads.h"
#include "auto_mutex_extension.h"
#include "../binary_search_tree.h"
#include "../member_function_pointer.h"
#include "../memory_manager.h"
#include "../queue.h"
#include "../set.h"

extern "C"
{
// =========================>>> WHY YOU ARE GETTING AN ERROR HERE <<<=========================
// The point of this block of code is to cause a link time error that will prevent a user
// from compiling part of their application with DLIB_ASSERT enabled and part with it
// disabled since doing that would be a violation of C++'s one definition rule.  So if you
// are getting an error here then you are either not enabling DLIB_ASSERT consistently
// (e.g. by compiling part of your program in a debug mode and part in a release mode) or
// you have simply forgotten to compile dlib/all/source.cpp into your application.
// =========================>>> WHY YOU ARE GETTING AN ERROR HERE <<<=========================
#ifdef ENABLE_ASSERTS
    extern int USER_ERROR__missing_dlib_all_source_cpp_file__OR__inconsistent_use_of_DEBUG_or_ENABLE_ASSERTS_preprocessor_directives;
    inline int dlib_check_consistent_assert_usage() { USER_ERROR__missing_dlib_all_source_cpp_file__OR__inconsistent_use_of_DEBUG_or_ENABLE_ASSERTS_preprocessor_directives = 0; return 0; }
#else
    extern int USER_ERROR__missing_dlib_all_source_cpp_file__OR__inconsistent_use_of_DEBUG_or_ENABLE_ASSERTS_preprocessor_directives_;
    inline int dlib_check_consistent_assert_usage() { USER_ERROR__missing_dlib_all_source_cpp_file__OR__inconsistent_use_of_DEBUG_or_ENABLE_ASSERTS_preprocessor_directives_ = 0; return 0; }
#endif
    const int dlib_check_assert_helper_variable = dlib_check_consistent_assert_usage();
}

namespace dlib
{

// ----------------------------------------------------------------------------------------

    namespace threads_kernel_shared
    {
        void thread_starter (
            void*
        );

        class threader
        {
            /*!
                INITIAL VALUE
                    - pool_count == 0 and
                    - data_ready is associated with the mutex data_mutex
                    - data_empty is associated with the mutex data_mutex
                    - destructed is associated with the mutex data_mutex
                    - destruct == false
                    - total_count == 0
                    - function_pointer == 0
                    - do_not_ever_destruct == false

                CONVENTION
                    - data_ready is associated with the mutex data_mutex
                    - data_empty is associated with the mutex data_mutex
                    - data_ready == a signaler used signal when there is new data waiting
                      to start a thread with.
                    - data_empty == a signaler used to signal when the data is now empty
                    - pool_count == the number of suspended threads in the thread pool
                    - total_count == the number of threads that are executing anywhere.  i.e.
                      pool_count + the ones that are currently running some user function.
                    - if (function_pointer != 0) then
                        - parameter == a void pointer pointing to the parameter which
                          should be used to start the next thread
                        - function_pointer == a pointer to the next function to make a
                          new thread with

                    - if (the destructor is running) then
                        - destruct == true
                    - else
                        - destruct == false

                    - thread_ids is locked by the data_mutex
                    - thread_ids == a set that contains the thread id for each thread spawned by this
                      object.
            !*/

        public:
            threader (
            );

            ~threader (
            );

            void destruct_if_ready (
            );
            /*!
                ensures
                    - if (there are no threads currently running and we haven't set do_not_ever_destruct) then
                        - calls delete this
                    - else
                        - does nothing
            !*/

            bool create_new_thread (
                void (*funct)(void*),
                void* param
            );

            template <
                typename T
                >
            void unregister_thread_end_handler (
                T& obj,
                void (T::*handler)()
            )
            {
                member_function_pointer<> mfp, junk_mfp;
                mfp.set(obj,handler);

                thread_id_type junk_id;

                // find any member function pointers in the registry that point to the same
                // thing as mfp and remove them
                auto_mutex M(reg.m);
                reg.reg.reset();
                while (reg.reg.move_next())
                {
                    while (reg.reg.current_element_valid() && reg.reg.element().value() == mfp)
                    {
                        reg.reg.remove_current_element(junk_id, junk_mfp);
                    }
                }
            }

            template <
                typename T
                >
            void register_thread_end_handler (
                T& obj,
                void (T::*handler)()
            )
            {
                thread_id_type id = get_thread_id();
                member_function_pointer<> mfp;
                mfp.set(obj,handler);

                auto_mutex M(reg.m);
                reg.reg.add(id,mfp);
            }

            bool is_dlib_thread (
                thread_id_type id
            );

        private:

            friend void thread_starter (
                void*
            );

            void call_end_handlers (
            );
            /*!
                ensures
                    - calls the registered end handlers for the calling thread and
                      then removes them from reg.reg
            !*/

            // private data
            set<thread_id_type,memory_manager<char>::kernel_2b>::kernel_1b_c thread_ids;
            unsigned long total_count;
            void* parameter;
            void (*function_pointer)(void*);
            unsigned long pool_count;
            mutex data_mutex;           // mutex to protect the above data
            signaler data_ready;        // signaler to signal when there is new data
            signaler data_empty;        // signaler to signal when the data is empty
            bool destruct;
            signaler destructed;        // signaler to signal when a thread has ended
            bool do_not_ever_destruct;

            struct registry_type
            {
                mutex m;
                binary_search_tree<
                    thread_id_type,
                    member_function_pointer<>,
                    memory_manager<char>::kernel_2a
                    >::kernel_2a_c reg;
            };

            // stuff for the register_thread_end_handler
            registry_type reg;

            // restricted functions
            threader(threader&);        // copy constructor
            threader& operator=(threader&);    // assignement opertor

        };

    // ------------------------------------------------------------------------------------

        threader& thread_pool (
        );
        /*!
            ensures
                - returns a reference to the global threader object
        !*/

    // ------------------------------------------------------------------------------------

        extern bool thread_pool_has_been_destroyed;
    }

    bool is_dlib_thread (
        thread_id_type id
    );

    bool is_dlib_thread (
    );

// ----------------------------------------------------------------------------------------

    inline bool create_new_thread (
        void (*funct)(void*),
        void* param
    )
    {
        try
        {
            // now make this thread
            return threads_kernel_shared::thread_pool().create_new_thread(funct,param);
        }
        catch (std::bad_alloc&)
        {
            return false;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    inline void register_thread_end_handler (
        T& obj,
        void (T::*handler)()
    )
    {
        DLIB_ASSERT(is_dlib_thread(),
               "\tvoid register_thread_end_handler"
            << "\n\tYou can't register a thread end handler for a thread dlib didn't spawn."
            );

        threads_kernel_shared::thread_pool().register_thread_end_handler(obj,handler);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    inline void unregister_thread_end_handler (
        T& obj,
        void (T::*handler)()
    )
    {
        // Check if the thread pool has been destroyed and if it has then don't do anything.
        // This bool here is always true except when the program has started to terminate and
        // the thread pool object has been destroyed.  This if is here to catch other global
        // objects that have destructors that try to call unregister_thread_end_handler().
        // Without this check we get into trouble if the thread pool is destroyed before these
        // objects.
        if (threads_kernel_shared::thread_pool_has_been_destroyed == false)
            threads_kernel_shared::thread_pool().unregister_thread_end_handler(obj,handler);
    }

// ----------------------------------------------------------------------------------------

}

#ifdef NO_MAKEFILE
#include "threads_kernel_shared.cpp"
#endif

#endif // DLIB_THREADS_KERNEl_SHARED_


dlib C++ Library - windows.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_THREADS_KERNEl_2_
#include "threads_kernel_1.h"
#endif


dlib C++ Library - timeout.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_TIMEOUT_KERNEl_1_
#define DLIB_TIMEOUT_KERNEl_1_

#include "../threads.h"
#include "../algs.h"
#include "../misc_api.h"
#include "timeout_abstract.h"
#include "../uintn.h"
#include "../timer.h"

#ifdef _MSC_VER
// this is to disable the "'this' : used in base member initializer list"
// warning you get from some of the GUI objects since all the objects
// require that their parent class be passed into their constructor.
// In this case though it is totally safe so it is ok to disable this warning.
#pragma warning(disable : 4355)
#endif // _MSC_VER

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class timeout
    {
        /*!
            INITIAL VALUE
                - b == a pointer to some kind of bind object

            CONVENTION
                - b == a pointer to some kind of bind object
        !*/

        class bind
        {
        public:
            virtual void go() = 0;
            virtual ~bind() {}
        };

        template <typename T>
        class functor : public bind
        {
        public:
            functor(const T& f) : function(f) {}
            T function;
            void go() { function(); }
        };

        template <typename T, typename R>
        class zero : public bind
        {
        public:
            T* object;
            R (T::*callback_function)();
            void go() { (object->*callback_function)(); }

        };

        template <typename T, typename R, typename U>
        class one : public bind
        {
        public:
            T* object;
            R (T::*callback_function)(U);
            U val;
            void go() { (object->*callback_function)(val); }
        };

    public:

        // This typedef is here for backwards compatibility with previous versions of dlib.
        typedef timeout kernel_1a;

        template <
            typename T
            >
        timeout (
            T callback_function,
            unsigned long ms_to_timeout
        ) :
            t(*this,&timeout::trigger_timeout)
        {
            b = new functor<T>(callback_function);
            t.set_delay_time(ms_to_timeout);
            t.start();
        }

        template <
            typename T
            >
        timeout (
            T& object,
            void (T::*callback_function)(),
            unsigned long ms_to_timeout
        ):
            t(*this,&timeout::trigger_timeout)
        {
            zero<T,void>* B = new zero<T,void>;
            b = B;
            B->object = &object;
            B->callback_function = callback_function;
            t.set_delay_time(ms_to_timeout);
            t.start();
        }

        template <
            typename T,
            typename U
            >
        timeout (
            T& object,
            void (T::*callback_function)(U callback_function_argument),
            unsigned long ms_to_timeout,
            U callback_function_argument
        ):
            t(*this,&timeout::trigger_timeout)
        {
            one<T,void,U>* B = new one<T,void,U>;
            b = B;
            B->object = &object;
            B->callback_function = callback_function;
            B->val = callback_function_argument;
            t.set_delay_time(ms_to_timeout);
            t.start();
        }

        template <
            typename T
            >
        timeout (
            T& object,
            int (T::*callback_function)(),
            unsigned long ms_to_timeout
        ):
            t(*this,&timeout::trigger_timeout)
        {
            zero<T,int>* B = new zero<T,int>;
            b = B;
            B->object = &object;
            B->callback_function = callback_function;
            t.set_delay_time(ms_to_timeout);
            t.start();
        }

        template <
            typename T,
            typename U
            >
        timeout (
            T& object,
            int (T::*callback_function)(U callback_function_argument),
            unsigned long ms_to_timeout,
            U callback_function_argument
        ):
            t(*this,&timeout::trigger_timeout)
        {
            one<T,int,U>* B = new one<T,int,U>;
            b = B;
            B->object = &object;
            B->callback_function = callback_function;
            B->val = callback_function_argument;
            t.set_delay_time(ms_to_timeout);
            t.start();
        }

        virtual ~timeout (
        )
        {
            t.stop_and_wait();
            delete b;
        }

    private:

        void trigger_timeout ()
        {
            b->go();
            t.stop();
        }

        dlib::timer<timeout> t;
        bind* b;

        // restricted functions
        timeout(const timeout&);        // copy constructor
        timeout& operator=(const timeout&);    // assignment operator

    };

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_TIMEOUT_KERNEl_1_


dlib C++ Library - timer.cpp

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_TIMER_cPPh_
#define DLIB_TIMER_cPPh_

#include "timer.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    timer_global_clock::
    timer_global_clock(
    ):
        s(m),
        shutdown(false),
        running(false)
    {
    }

// ----------------------------------------------------------------------------------------

    timer_global_clock::
    ~timer_global_clock()
    {
        m.lock();
        shutdown = true;
        s.signal();
        m.unlock();
        wait();
    }

// ----------------------------------------------------------------------------------------

    void timer_global_clock::
    add (
        timer_base* r
    )
    {
        if (r->in_global_clock == false)
        {
            // if the thread isn't running then start it up
            if (!running)
            {
                start();
                running = true;
            }

            uint64 t = ts.get_timestamp() + r->delay*1000;
            tm.reset();
            if (!tm.move_next() || t < tm.element().key())
            {
                // we need to make the thread adjust its next time to
                // trigger if this new event occurrs sooner than the
                // next event in tm
                s.signal();
            }
            timer_base* rtemp = r;
            uint64 ttemp = t;
            tm.add(ttemp,rtemp);
            r->next_time_to_run = t;
            r->in_global_clock = true;
        }
    }

// ----------------------------------------------------------------------------------------

    void timer_global_clock::
    remove (
        timer_base* r
    )
    {
        if (r->in_global_clock)
        {
            tm.position_enumerator(r->next_time_to_run-1);
            do
            {
                if (tm.element().value() == r)
                {
                    uint64 t;
                    timer_base* rtemp;
                    tm.remove_current_element(t,rtemp);
                    r->in_global_clock = false;
                    break;
                }
            } while (tm.move_next());
        }
    }

// ----------------------------------------------------------------------------------------

    void timer_global_clock::
    adjust_delay (
        timer_base* r,
        unsigned long new_delay
    )
    {
        if (r->in_global_clock)
        {
            remove(r);
            // compute the new next_time_to_run and store it in t
            uint64 t = r->next_time_to_run;
            t -= r->delay*1000;
            t += new_delay*1000;

            tm.reset();
            if (!tm.move_next() || t < tm.element().key())
            {
                // we need to make the thread adjust its next time to
                // trigger if this new event occurrs sooner than the
                // next event in tm
                s.signal();
            }

            // set this incase add throws
            r->running = false;
            r->delay = new_delay;

            timer_base* rtemp = r;
            uint64 ttemp = t;
            tm.add(ttemp,rtemp);
            r->next_time_to_run = t;
            r->in_global_clock = true;

            // put this back now that we know add didn't throw
            r->running = true;

        }
        else
        {
            r->delay = new_delay;
        }
    }

// ----------------------------------------------------------------------------------------

    void timer_global_clock::
    thread()
    {
        auto_mutex M(m);
        while (!shutdown)
        {
            unsigned long delay = 100000;

            tm.reset();
            tm.move_next();
            // loop and start all the action functions for timers that should have
            // triggered.
            while(tm.current_element_valid())
            {
                const uint64 cur_time = ts.get_timestamp();
                uint64 t = tm.element().key();
                // if the next event in tm is ready to trigger
                if (t <= cur_time + 999)
                {
                    // remove this event from the tm map
                    timer_base* r = tm.element().value();
                    timer_base* rtemp;
                    tm.remove_current_element(t,rtemp);
                    r->in_global_clock = false;

                    // if this timer is still "running" then start its action function
                    if (r->running)
                    {
                        r->restart();
                    }
                }
                else
                {
                    // there aren't any more timers that should trigger so we compute
                    // the delay to the next timer event.
                    delay = static_cast<unsigned long>((t - cur_time)/1000);
                    break;
                }
            }

            s.wait_or_timeout(delay);
        }
    }

// ----------------------------------------------------------------------------------------

    shared_ptr_thread_safe<timer_global_clock> get_global_clock()
    {
        static shared_ptr_thread_safe<timer_global_clock> d(new timer_global_clock);
        return d;
    }

// ----------------------------------------------------------------------------------------

    // do this just to make sure get_global_clock() gets called at program startup
    class timer_global_clock_helper
    {
    public:
        timer_global_clock_helper()
        {
            get_global_clock();
        }
    };
    static timer_global_clock_helper call_get_global_clock;

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_TIMER_cPPh_


dlib C++ Library - timer.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_TIMEr_Hh_
#define DLIB_TIMEr_Hh_

#include "../threads.h"
#include "../algs.h"
#include "../misc_api.h"
#include "timer_abstract.h"
#include "../uintn.h"
#include "../binary_search_tree.h"
#include "../smart_pointers_thread_safe.h"
#include "timer_heavy.h"

namespace dlib
{

    struct timer_base : public threaded_object
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This object contains the base members of the timer object.
                It exists so that we can access them from outside any templated functions.
        !*/

        unsigned long delay;
        // these are only modified by the global_clock
        uint64 next_time_to_run;
        timestamper ts;
        bool running;
        bool in_global_clock;
    };

// ----------------------------------------------------------------------------------------

    class timer_global_clock : private threaded_object
    {
        /*!
            This object sets up a timer that triggers the action function
            for timer objects that are tracked inside this object.
            INITIAL VALUE
                - shutdown == false
                - running == false

            CONVENTION
                - if (shutdown) then
                    - thread() should terminate
                - else (running) then
                    - thread() is running

                - tm[time] == pointer to a timer_base object
        !*/
        typedef binary_search_tree<uint64,timer_base*,memory_manager<char>::kernel_2b>::kernel_2a_c time_map;
    public:

        ~timer_global_clock();

        void add (
            timer_base* r
        );
        /*!
            requires
                - m is locked
            ensures
                - starts the thread if it isn't already started
                - adds r to tm
                - #r->in_global_clock == true
                - updates r->next_time_to_run appropriately according to
                    r->delay
        !*/

        void remove (
            timer_base* r
        );
        /*!
            requires
                - m is locked
            ensures
                - if (r is in tm) then
                    - removes r from tm
                - #r->in_global_clock == false
        !*/

        void adjust_delay (
            timer_base* r,
            unsigned long new_delay
        );
        /*!
            requires
                - m is locked
            ensures
                - #r->delay == new_delay
                - if (r->in_global_clock) then
                    - the time to the next event will have been appropriately adjusted
        !*/

        mutex m;

        friend shared_ptr_thread_safe<timer_global_clock> get_global_clock();

    private:
        timer_global_clock();

        time_map tm;
        signaler s;
        bool shutdown;
        bool running;
        timestamper ts;

        void thread();
        /*!
            ensures
                - spawns timer tasks as is appropriate
        !*/
    };
    shared_ptr_thread_safe<timer_global_clock> get_global_clock();
    /*!
        ensures
            - returns the global instance of the timer_global_clock object
    !*/

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    class timer : private timer_base
    {
        /*!
            INITIAL VALUE
                - running   == false
                - delay     == 1000
                - ao        == a pointer to the action_object()
                - af        == a pointer to the action_function()
                - in_global_clock == false
                - next_time_to_run == 0
                - gc == get_global_clock()

            CONVENTION
                - the mutex used to lock everything is gc->m
                - running == is_running()
                - delay == delay_time()
                - *ao == action_object()
                - af == action_function()
                - if (!running) then
                    - in_global_clock == false
                - else
                    - next_time_to_run == the next time this timer should run according
                      to the timestamper in the global_clock
        !*/

    public:

        // These typedefs are here for backwards compatibility with previous versions of
        // dlib.
        typedef timer_heavy<T> kernel_1a;
        typedef timer kernel_2a;

        typedef void (T::*af_type)();

        timer(
            T& ao_,
            af_type af_
        );

        virtual ~timer(
        );

        void clear(
        );

        af_type action_function (
        ) const;

        const T& action_object (
        ) const;

        T& action_object (
        );

        bool is_running (
        ) const;

        unsigned long delay_time (
        ) const;

        void set_delay_time (
            unsigned long milliseconds
        );

        void start (
        );

        void stop (
        );

        void stop_and_wait (
        );

    private:

        void thread (
        );
        /*!
            ensures
                - calls the action function
        !*/

        // data members
        T& ao;
        const af_type af;
        shared_ptr_thread_safe<timer_global_clock> gc;

        // restricted functions
        timer(const timer&);        // copy constructor
        timer& operator=(const timer&);    // assignment operator

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    timer<T>::
    timer(
        T& ao_,
        af_type af_
    ) :
        ao(ao_),
        af(af_),
        gc(get_global_clock())
    {
        delay = 1000;
        next_time_to_run = 0;
        running = false;
        in_global_clock = false;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    timer<T>::
    ~timer(
    )
    {
        clear();
        wait();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    void timer<T>::
    clear(
    )
    {
        auto_mutex M(gc->m);
        running = false;
        gc->remove(this);
        delay = 1000;
        next_time_to_run = 0;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    typename timer<T>::af_type timer<T>::
    action_function (
    ) const
    {
        return af;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    const T& timer<T>::
    action_object (
    ) const
    {
        return ao;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    T& timer<T>::
    action_object (
    )
    {
        return ao;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    bool timer<T>::
    is_running (
    ) const
    {
        auto_mutex M(gc->m);
        return running;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    unsigned long timer<T>::
    delay_time (
    ) const
    {
        auto_mutex M(gc->m);
        return delay;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    void timer<T>::
    set_delay_time (
        unsigned long milliseconds
    )
    {
        auto_mutex M(gc->m);
        gc->adjust_delay(this,milliseconds);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    void timer<T>::
    start (
    )
    {
        auto_mutex M(gc->m);
        if (!running)
        {
            gc->add(this);
            running = true;
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    void timer<T>::
    stop (
    )
    {
        gc->m.lock();
        running = false;
        gc->remove(this);
        gc->m.unlock();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    void timer<T>::
    thread (
    )
    {
        // call the action function
        (ao.*af)();
        auto_mutex M(gc->m);
        if (running)
        {
            gc->remove(this);
            gc->add(this);
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    void timer<T>::
    stop_and_wait (
    )
    {
        gc->m.lock();
        running = false;
        gc->remove(this);
        gc->m.unlock();
        wait();
    }

// ----------------------------------------------------------------------------------------

}

#ifdef NO_MAKEFILE
#include "timer.cpp"
#endif

#endif // DLIB_TIMEr_Hh_


dlib C++ Library - timer_heavy.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_TIMER_KERNEl_1_
#define DLIB_TIMER_KERNEl_1_

#include "../threads.h"
#include "../algs.h"
#include "../misc_api.h"
#include "timer_abstract.h"

namespace dlib
{

    template <
        typename T
        >
    class timer_heavy
    {
        /*!
            WHAT THIS OBJECT REPRESENTS
                This is an implementation of the timer_abstract.h interface.  It is very
                simple and uses only one thread which is always alive in a timer_heavy.
                The reason this object exists is for historical reasons.  Originally, the
                dlib::timer was a multi-implementation component and the timer_heavy was
                its first implementation.  It was superseded later by the more efficient
                dlib::timer.  However, timer_heavy is still around so that
                dlib::timer::kernel_1a has something to refer to.  This way, old client
                code which somehow depends on the same thread always calling a timer action
                function isn't going to be disrupted.

            INITIAL VALUE
                - running   == false
                - delay     == 1000
                - ao        == a pointer to the action_object()
                - af        == a pointer to the action_function()
                - m         == a mutex that locks everything in this class
                - s         == a signaler for mutex m
                - stop_running == false

            CONVENTION
                - running && !stop_running == is_running()
                - delay == delay_time()
                - *ao == action_object()
                - af == action_function()

                - if (running) then
                    - there is a thread running
                - if (is_running()) then
                    - next_time_to_run == the time when the next execution of the action
                      function should occurr.  (the time is given by ts.get_timestamp())

                - stop_running is used to tell the thread to quit.  If it is
                  set to true then the thread should end.
        !*/

    public:

        typedef void (T::*af_type)();

        timer_heavy(
            T& ao_,
            af_type af_
        );

        virtual ~timer_heavy(
        );

        void clear(
        );

        af_type action_function (
        ) const;

        const T& action_object (
        ) const;

        T& action_object (
        );

        bool is_running (
        ) const;

        unsigned long delay_time (
        ) const;

        void set_delay_time (
            unsigned long milliseconds
        );

        void start (
        );

        void stop (
        );

        void stop_and_wait (
        );

    private:

        void thread (
        );
        /*!
            requires
                - is run in its own thread
            ensures
                - calls the action function for the given timer object in the manner
                  specified by timer_kernel_abstract.h
        !*/

        // data members
        T& ao;
        const af_type af;
        unsigned long delay;
        mutex m;
        signaler s;

        bool running;
        bool stop_running;
        timestamper ts;
        uint64 next_time_to_run;

        // restricted functions
        timer_heavy(const timer_heavy<T>&);        // copy constructor
        timer_heavy<T>& operator=(const timer_heavy<T>&);    // assignment operator

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    timer_heavy<T>::
    timer_heavy(
        T& ao_,
        af_type af_
    ) :
        ao(ao_),
        af(af_),
        delay(1000),
        s(m),
        running(false),
        stop_running(false)
    {
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    timer_heavy<T>::
    ~timer_heavy(
    )
    {
        stop_and_wait();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    void timer_heavy<T>::
    clear(
    )
    {
        m.lock();
        stop_running = true;
        delay = 1000;
        s.broadcast();
        m.unlock();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    typename timer_heavy<T>::af_type timer_heavy<T>::
    action_function (
    ) const
    {
        return af;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    const T& timer_heavy<T>::
    action_object (
    ) const
    {
        return ao;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    T& timer_heavy<T>::
    action_object (
    )
    {
        return ao;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    bool timer_heavy<T>::
    is_running (
    ) const
    {
        auto_mutex M(m);
        return running && !stop_running;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    unsigned long timer_heavy<T>::
    delay_time (
    ) const
    {
        auto_mutex M(m);
        return delay;
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    void timer_heavy<T>::
    set_delay_time (
        unsigned long milliseconds
    )
    {
        m.lock();

        // if (is_running()) then we should adjust next_time_to_run
        if (running && !stop_running)
        {
            next_time_to_run -= delay*1000;
            next_time_to_run += milliseconds*1000;
        }

        delay = milliseconds;
        s.broadcast();
        m.unlock();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    void timer_heavy<T>::
    start (
    )
    {
        auto_mutex M(m);

        // if (is_running() == false) then reset the countdown to the next call
        // to the action_function()
        if ( (running && !stop_running) == false)
            next_time_to_run = ts.get_timestamp() + delay*1000;

        stop_running = false;
        if (running == false)
        {
            running = true;

            // start the thread
            if (create_new_thread<timer_heavy,&timer_heavy::thread>(*this) == false)
            {
                running = false;
                throw dlib::thread_error("error creating new thread in timer_heavy::start");
            }
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    void timer_heavy<T>::
    stop (
    )
    {
        m.lock();
        stop_running = true;
        s.broadcast();
        m.unlock();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    void timer_heavy<T>::
    thread (
    )
    {
        auto_mutex M(m);
        unsigned long delay_remaining;
        uint64 current_time = ts.get_timestamp();

        if (current_time < next_time_to_run)
            delay_remaining = static_cast<unsigned long>((next_time_to_run-current_time)/1000);
        else
            delay_remaining = 0;

        while (stop_running == false)
        {
            if (delay_remaining > 0)
                s.wait_or_timeout(delay_remaining);

            if (stop_running)
                break;

            current_time = ts.get_timestamp();
            if (current_time < next_time_to_run)
            {
                // then we woke up too early so we should keep waiting
                delay_remaining = static_cast<unsigned long>((next_time_to_run-current_time)/1000);

                // rounding might make this be zero anyway.  So if it is
                // then we will say we have hit the next time to run.
                if (delay_remaining > 0)
                    continue;
            }

            // call the action function
            m.unlock();
            (ao.*af)();
            m.lock();

            current_time = ts.get_timestamp();
            next_time_to_run = current_time + delay*1000;
            delay_remaining = delay;
        }
        running = false;
        stop_running = false;
        s.broadcast();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T
        >
    void timer_heavy<T>::
    stop_and_wait (
    )
    {
        m.lock();
        if (running)
        {
            // make the running thread terminate
            stop_running = true;

            s.broadcast();
            // wait for the thread to quit
            while (running)
                s.wait();
        }
        m.unlock();
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_TIMER_KERNEl_1_


dlib C++ Library - tokenizer_kernel_1.cpp

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_TOKENIZER_KERNEL_1_CPp_
#define DLIB_TOKENIZER_KERNEL_1_CPp_
#include "tokenizer_kernel_1.h"

#include <iostream>
#include <cstdio>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    tokenizer_kernel_1::
    tokenizer_kernel_1 (
    ) :
        headset(0),
        bodyset(0),
        have_peeked(false)
    {
        try
        {
            headset = new bool[UCHAR_MAX];
            bodyset = new bool[UCHAR_MAX];

            clear();
        }
        catch (...)
        {
            if (headset) delete [] headset;
            if (bodyset) delete [] headset;
            throw;
        }
    }

// ----------------------------------------------------------------------------------------

    tokenizer_kernel_1::
    ~tokenizer_kernel_1 (
    )
    {
        delete [] bodyset;
        delete [] headset;
    }

// ----------------------------------------------------------------------------------------

    void tokenizer_kernel_1::
    clear(
    )
    {
        using namespace std;

        in = 0;
        streambuf = 0;
        have_peeked = false;

        head = "_" + lowercase_letters() + uppercase_letters();
        body = "_" + lowercase_letters() + uppercase_letters() + numbers();

        for (unsigned long i = 0; i < UCHAR_MAX; ++i)
        {
            headset[i] = false;
            bodyset[i] = false;
        }

        for (string::size_type i = 0; i < head.size(); ++i)
            headset[static_cast<unsigned char>(head[i])] = true;
        for (string::size_type i = 0; i < body.size(); ++i)
            bodyset[static_cast<unsigned char>(body[i])] = true;
    }

// ----------------------------------------------------------------------------------------

    void tokenizer_kernel_1::
    set_stream (
        std::istream& in_
    )
    {
        in = &in_;
        streambuf = in_.rdbuf();
        have_peeked = false;
    }

// ----------------------------------------------------------------------------------------

    bool tokenizer_kernel_1::
    stream_is_set (
    ) const
    {
        return (in != 0);
    }

// ----------------------------------------------------------------------------------------

    std::istream& tokenizer_kernel_1::
    get_stream (
    ) const
    {
        return *in;
    }

// ----------------------------------------------------------------------------------------

    void tokenizer_kernel_1::
    get_token (
        int& type,
        std::string& token
    )
    {
        if (!have_peeked)
        {
            std::streambuf::int_type ch;
            ch = streambuf->sbumpc();

            switch (ch)
            {
            case EOF:
                type = END_OF_FILE;
                token.clear();
                return;

            case '\n':
                type = END_OF_LINE;
                token = "\n";
                return;

            case '\r':
            case ' ':
            case '\t':
                type = WHITE_SPACE;
                token = static_cast<char>(ch);
                ch = streambuf->sgetc();
                while ((ch == ' ' || ch == '\t' || ch == '\r') && ch != EOF)
                {
                    token += static_cast<char>(ch);
                    ch = streambuf->snextc();
                }
                return;

            default:
                if (headset[static_cast<unsigned char>(ch)])
                {
                    type = IDENTIFIER;
                    token = static_cast<char>(ch);
                    ch = streambuf->sgetc();
                    while ( bodyset[static_cast<unsigned char>(ch)] && ch != EOF )
                    {
                        token += static_cast<char>(ch);
                        ch = streambuf->snextc();
                    }
                }
                else if ('0' <= ch && ch <= '9')
                {
                    type = NUMBER;
                    token = static_cast<char>(ch);
                    ch = streambuf->sgetc();
                    while (('0' <= ch && ch <= '9') && ch != EOF)
                    {
                        token += static_cast<char>(ch);
                        ch = streambuf->snextc();
                    }
                }
                else
                {
                    type = CHAR;
                    token = static_cast<char>(ch);
                }
                return;
            } // switch (ch)
        }

        // if we get this far it means we have peeked so we should
        // return the peek data.
        type = next_type;
        token = next_token;
        have_peeked = false;
    }

// ----------------------------------------------------------------------------------------

    int tokenizer_kernel_1::
    peek_type (
    ) const
    {
        const_cast<tokenizer_kernel_1*>(this)->get_token(next_type,next_token);
        have_peeked = true;
        return next_type;
    }

// ----------------------------------------------------------------------------------------

    const std::string& tokenizer_kernel_1::
    peek_token (
    ) const
    {
        const_cast<tokenizer_kernel_1*>(this)->get_token(next_type,next_token);
        have_peeked = true;
        return next_token;
    }

// ----------------------------------------------------------------------------------------

    void tokenizer_kernel_1::
    swap (
        tokenizer_kernel_1& item
    )
    {
        exchange(in,item.in);
        exchange(streambuf,item.streambuf);
        exchange(head,item.head);
        exchange(body,item.body);
        exchange(bodyset,item.bodyset);
        exchange(headset,item.headset);
        exchange(have_peeked,item.have_peeked);
        exchange(next_type,item.next_type);
        exchange(next_token,item.next_token);
    }

// ----------------------------------------------------------------------------------------

    void tokenizer_kernel_1::
    set_identifier_token (
        const std::string& head_,
        const std::string& body_
    )
    {
        using namespace std;

        head = head_;
        body = body_;

        for (unsigned long i = 0; i < UCHAR_MAX; ++i)
        {
            headset[i] = false;
            bodyset[i] = false;
        }

        for (string::size_type i = 0; i < head.size(); ++i)
            headset[static_cast<unsigned char>(head[i])] = true;
        for (string::size_type i = 0; i < body.size(); ++i)
            bodyset[static_cast<unsigned char>(body[i])] = true;
    }

// ----------------------------------------------------------------------------------------

    const std::string tokenizer_kernel_1::
    get_identifier_head (
    ) const
    {
        return head;
    }

// ----------------------------------------------------------------------------------------

    const std::string tokenizer_kernel_1::
    get_identifier_body (
    ) const
    {
        return body;
    }

// ----------------------------------------------------------------------------------------

    const std::string tokenizer_kernel_1::
    lowercase_letters (
    ) const
    {
        return std::string("abcdefghijklmnopqrstuvwxyz");
    }

// ----------------------------------------------------------------------------------------

    const std::string tokenizer_kernel_1::
    uppercase_letters (
    ) const
    {
        return std::string("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
    }

// ----------------------------------------------------------------------------------------

    const std::string tokenizer_kernel_1::
    numbers (
    ) const
    {
        return std::string("0123456789");
    }

// ----------------------------------------------------------------------------------------

}
#endif // DLIB_TOKENIZER_KERNEL_1_CPp_


dlib C++ Library - tokenizer_kernel_1.h

// Copyright (C) 2005  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_TOKENIZER_KERNEl_1_
#define DLIB_TOKENIZER_KERNEl_1_

#include <string>
#include <iosfwd>
#include <climits>
#include "../algs.h"
#include "tokenizer_kernel_abstract.h"

namespace dlib
{

    class tokenizer_kernel_1
    {
        /*!
            INITIAL VALUE
                - in == 0
                - streambuf == 0
                - have_peeked == false
                - head == "_" + lowercase_letters() + uppercase_letters()
                - body == "_" + lowercase_letters() + uppercase_letters() + numbers()
                - headset == pointer to an array of UCHAR_MAX bools and set according
                  to the CONVENTION.
                - bodyset == pointer to an array of UCHAR_MAX bools and set according
                  to the CONVENTION.

            CONVENTION
                - if (stream_is_set()) then
                    - get_stream() == *in
                    - streambuf == in->rdbuf()
                - else
                    - in == 0
                    - streambuf == 0

                - body == get_identifier_body()
                - head == get_identifier_head()

                - if (the char x appears in head) then
                    - headset[static_cast<unsigned char>(x)] == true
                - else
                    - headset[static_cast<unsigned char>(x)] == false

                - if (the char x appears in body) then
                    - bodyset[static_cast<unsigned char>(x)] == true
                - else
                    - bodyset[static_cast<unsigned char>(x)] == false

                - if (have_peeked) then
                    - next_token == the next token to be returned from get_token()
                    - next_type == the type of token in peek_token
        !*/

    public:

        // The name of this enum is irrelevant but on some compilers (gcc on MAC OS X) not having it named
        // causes an error for whatever reason
        enum some_random_name
        {
            END_OF_LINE,
            END_OF_FILE,
            IDENTIFIER,
            CHAR,
            NUMBER,
            WHITE_SPACE
        };

        tokenizer_kernel_1 (
        );

        virtual ~tokenizer_kernel_1 (
        );

        void clear(
        );

        void set_stream (
            std::istream& in
        );

        bool stream_is_set (
        ) const;

        std::istream& get_stream (
        ) const;

        void get_token (
            int& type,
            std::string& token
        );

        void swap (
            tokenizer_kernel_1& item
        );

        void set_identifier_token (
            const std::string& head,
            const std::string& body
        );

        int peek_type (
        ) const;

        const std::string& peek_token (
        ) const;

        const std::string get_identifier_head (
        ) const;

        const std::string get_identifier_body (
        ) const;

        const std::string lowercase_letters (
        ) const;

        const std::string uppercase_letters (
        ) const;

        const std::string numbers (
        ) const;

    private:

        // restricted functions
        tokenizer_kernel_1(const tokenizer_kernel_1&);        // copy constructor
        tokenizer_kernel_1& operator=(const tokenizer_kernel_1&);    // assignment operator

        // data members
        std::istream* in;
        std::streambuf* streambuf;
        std::string head;
        std::string body;
        bool* headset;
        bool* bodyset;

        mutable std::string next_token;
        mutable int next_type;
        mutable bool have_peeked;
    };

    inline void swap (
        tokenizer_kernel_1& a,
        tokenizer_kernel_1& b
    ) { a.swap(b); }

}

#ifdef NO_MAKEFILE
#include "tokenizer_kernel_1.cpp"
#endif

#endif // DLIB_TOKENIZER_KERNEl_1


dlib C++ Library - tokenizer_kernel_c.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_TOKENIZER_KERNEl_C_
#define DLIB_TOKENIZER_KERNEl_C_

#include "tokenizer_kernel_abstract.h"
#include "../assert.h"
#include <string>
#include <iostream>

namespace dlib
{

    template <
        typename tokenizer
        >
    class tokenizer_kernel_c : public tokenizer
    {

        public:
            std::istream& get_stream (
            ) const;

            void get_token (
                int& type,
                std::string& token
            );

            void set_identifier_token (
                const std::string& head,
                const std::string& body
            );

            int peek_type (
            ) const;

            const std::string& peek_token (
            ) const;
    };

    template <
        typename tokenizer
        >
    inline void swap (
        tokenizer_kernel_c<tokenizer>& a,
        tokenizer_kernel_c<tokenizer>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename tokenizer
        >
    void tokenizer_kernel_c<tokenizer>::
    set_identifier_token (
        const std::string& head,
        const std::string& body
    )
    {
        using namespace std;
        // make sure requires clause is not broken
        DLIB_CASSERT( head.find_first_of(" \r\t\n0123456789") == string::npos &&
                body.find_first_of(" \r\t\n") == string::npos ,
            "\tvoid tokenizer::set_identifier_token()"
            << "\n\tyou can't define the IDENTIFIER token this way."
            << "\n\thead: " << head
            << "\n\tbody: " << body
            << "\n\tthis: " << this
            );

        // call the real function
        tokenizer::set_identifier_token(head,body);
    }

// ----------------------------------------------------------------------------------------

    template <
        typename tokenizer
        >
    std::istream& tokenizer_kernel_c<tokenizer>::
    get_stream (
    ) const
    {
        // make sure requires clause is not broken
        DLIB_CASSERT( this->stream_is_set() == true,
            "\tstd::istream& tokenizer::get_stream()"
            << "\n\tyou must set a stream for this object before you can get it"
            << "\n\tthis: " << this
            );

        // call the real function
        return tokenizer::get_stream();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename tokenizer
        >
    int tokenizer_kernel_c<tokenizer>::
    peek_type (
    ) const
    {
        // make sure requires clause is not broken
        DLIB_CASSERT( this->stream_is_set() == true,
            "\tint tokenizer::peek_type()"
            << "\n\tyou must set a stream for this object before you peek at what it contains"
            << "\n\tthis: " << this
            );

        // call the real function
        return tokenizer::peek_type();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename tokenizer
        >
    const std::string& tokenizer_kernel_c<tokenizer>::
    peek_token (
    ) const
    {
        // make sure requires clause is not broken
        DLIB_CASSERT( this->stream_is_set() == true,
            "\tint tokenizer::peek_token()"
            << "\n\tyou must set a stream for this object before you peek at what it contains"
            << "\n\tthis: " << this
            );

        // call the real function
        return tokenizer::peek_token();
    }

// ----------------------------------------------------------------------------------------

    template <
        typename tokenizer
        >
    void tokenizer_kernel_c<tokenizer>::
    get_token (
        int& type,
        std::string& token
    )
    {
        // make sure requires clause is not broken
        DLIB_CASSERT( this->stream_is_set() == true,
            "\tvoid tokenizer::get_token()"
            << "\n\tyou must set a stream for this object before you can get tokens from it."
            << "\n\tthis: " << this
            );

        // call the real function
        tokenizer::get_token(type,token);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_TOKENIZER_KERNEl_C_


dlib C++ Library - type_safe_union_kernel.h

// Copyright (C) 2009  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_TYPE_SAFE_UNIOn_h_
#define DLIB_TYPE_SAFE_UNIOn_h_

#include "type_safe_union_kernel_abstract.h"
#include "../algs.h"
#include "../noncopyable.h"
#include "../serialize.h"
#include <new>
#include <iostream>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    class bad_type_safe_union_cast : public std::bad_cast
    {
    public:
          virtual const char * what() const throw()
          {
              return "bad_type_safe_union_cast";
          }
    };

// ----------------------------------------------------------------------------------------

    struct _void{};
    inline void serialize( const _void&, std::ostream&){}
    inline void deserialize(  _void&, std::istream&){}

// ----------------------------------------------------------------------------------------

    template <
        typename T1,
        typename T2 = _void,
        typename T3 = _void,
        typename T4 = _void,
        typename T5 = _void,
        typename T6 = _void,
        typename T7 = _void,
        typename T8 = _void,
        typename T9 = _void,
        typename T10 = _void,

        typename T11 = _void,
        typename T12 = _void,
        typename T13 = _void,
        typename T14 = _void,
        typename T15 = _void,
        typename T16 = _void,
        typename T17 = _void,
        typename T18 = _void,
        typename T19 = _void,
        typename T20 = _void
        >
    class type_safe_union : noncopyable
    {
        /*!
            CONVENTION
                - is_empty() ==  (type_identity == 0)
                - contains<T>() == (type_identity == get_type_id<T>())
                - mem.get() == the block of memory on the stack which is
                  where objects in the union are stored
        !*/

    private:

        template <typename T, typename U>
        void invoke_on (
            T& obj,
            U& item
        ) const
        {
            obj(item);
        }

        template <typename T>
        void invoke_on (
            T& ,
            _void
        ) const
        {
        }

        const static size_t max_size = tmax<tmax<tmax<tmax<tmax<tmax<tmax<tmax<tmax<tmax<
                                       tmax<tmax<tmax<tmax<tmax<tmax<tmax<tmax<tmax<sizeof(T1),
                                                        sizeof(T2)>::value,
                                                        sizeof(T3)>::value,
                                                        sizeof(T4)>::value,
                                                        sizeof(T5)>::value,
                                                        sizeof(T6)>::value,
                                                        sizeof(T7)>::value,
                                                        sizeof(T8)>::value,
                                                        sizeof(T9)>::value,
                                                        sizeof(T10)>::value,
                                                        sizeof(T11)>::value,
                                                        sizeof(T12)>::value,
                                                        sizeof(T13)>::value,
                                                        sizeof(T14)>::value,
                                                        sizeof(T15)>::value,
                                                        sizeof(T16)>::value,
                                                        sizeof(T17)>::value,
                                                        sizeof(T18)>::value,
                                                        sizeof(T19)>::value,
                                                        sizeof(T20)>::value;

        // --------------------------------------------

        // member data
        stack_based_memory_block<max_size> mem;
        int type_identity;

        // --------------------------------------------

        template <typename T>
        void validate_type() const
        {
            // ERROR: You are trying to get a type of object that isn't
            // representable by this type_safe_union.  I.e. The given
            // type T isn't one of the ones given to this object's template
            // arguments.
            COMPILE_TIME_ASSERT(( is_same_type<T,T1>::value ||
                                 is_same_type<T,T2>::value ||
                                 is_same_type<T,T3>::value ||
                                 is_same_type<T,T4>::value ||
                                 is_same_type<T,T5>::value ||
                                 is_same_type<T,T6>::value ||
                                 is_same_type<T,T7>::value ||
                                 is_same_type<T,T8>::value ||
                                 is_same_type<T,T9>::value ||
                                 is_same_type<T,T10>::value ||

                                 is_same_type<T,T11>::value ||
                                 is_same_type<T,T12>::value ||
                                 is_same_type<T,T13>::value ||
                                 is_same_type<T,T14>::value ||
                                 is_same_type<T,T15>::value ||
                                 is_same_type<T,T16>::value ||
                                 is_same_type<T,T17>::value ||
                                 is_same_type<T,T18>::value ||
                                 is_same_type<T,T19>::value ||
                                 is_same_type<T,T20>::value
                                    ));

        }

        struct destruct_helper
        {
            template <typename T>
            void operator() (T& item) const
            {
                item.~T();
            }
        };

        void destruct (
        )
        /*!
            ensures
                - #is_empty() == true
        !*/
        {
            // destruct whatever is in this object
            apply_to_contents(destruct_helper());

            // mark this object as being empty
            type_identity = 0;
        }

        template <typename T>
        void construct (
        )
        {
            if (type_identity != get_type_id<T>())
            {
                destruct();
                new(mem.get()) T();
                type_identity = get_type_id<T>();
            }
        }

        template <typename T>
        void construct (
            const T& item
        )
        {
            if (type_identity != get_type_id<T>())
            {
                destruct();
                new(mem.get()) T(item);
                type_identity = get_type_id<T>();
            }
        }

        template <typename T>
        T& unchecked_get(
        )
        /*!
            requires
                - contains<T>() == true
            ensures
                - returns a non-const reference to the T object
        !*/
        {
            return *static_cast<T*>(mem.get());
        }

        template <typename T>
        const T& unchecked_get(
        ) const
        /*!
            requires
                - contains<T>() == true
            ensures
                - returns a const reference to the T object
        !*/
        {
            return *static_cast<const T*>(mem.get());
        }

        template <typename T>
        void operator() (T& item)
        /*
            This function is used by the swap function of this class.  See that
            function to see how this works.
        */
        {
            exchange(get<T>(), item);
        }

    public:

        typedef T1 type1;
        typedef T2 type2;
        typedef T3 type3;
        typedef T4 type4;
        typedef T5 type5;
        typedef T6 type6;
        typedef T7 type7;
        typedef T8 type8;
        typedef T9 type9;
        typedef T10 type10;
        typedef T11 type11;
        typedef T12 type12;
        typedef T13 type13;
        typedef T14 type14;
        typedef T15 type15;
        typedef T16 type16;
        typedef T17 type17;
        typedef T18 type18;
        typedef T19 type19;
        typedef T20 type20;

        type_safe_union() : type_identity(0)
        {
        }

        template <typename T>
        type_safe_union (
            const T& item
        ) : type_identity(0)
        {
            validate_type<T>();
            construct(item);
        }

        ~type_safe_union()
        {
            destruct();
        }

        template <typename T>
        static int get_type_id (
        )
        {
            if (is_same_type<T,T1>::value) return 1;
            if (is_same_type<T,T2>::value) return 2;
            if (is_same_type<T,T3>::value) return 3;
            if (is_same_type<T,T4>::value) return 4;
            if (is_same_type<T,T5>::value) return 5;

            if (is_same_type<T,T6>::value) return 6;
            if (is_same_type<T,T7>::value) return 7;
            if (is_same_type<T,T8>::value) return 8;
            if (is_same_type<T,T9>::value) return 9;
            if (is_same_type<T,T10>::value) return 10;

            if (is_same_type<T,T11>::value) return 11;
            if (is_same_type<T,T12>::value) return 12;
            if (is_same_type<T,T13>::value) return 13;
            if (is_same_type<T,T14>::value) return 14;
            if (is_same_type<T,T15>::value) return 15;

            if (is_same_type<T,T16>::value) return 16;
            if (is_same_type<T,T17>::value) return 17;
            if (is_same_type<T,T18>::value) return 18;
            if (is_same_type<T,T19>::value) return 19;
            if (is_same_type<T,T20>::value) return 20;

            // return a number that doesn't match any of the
            // valid states of type_identity
            return -1;
        }

        template <typename T>
        bool contains (
        ) const
        {
            return type_identity == get_type_id<T>();
        }

        bool is_empty (
        ) const
        {
            return type_identity == 0;
        }

    public:

        template <
            typename t1, typename t2, typename t3, typename t4, typename t5,
            typename t6, typename t7, typename t8, typename t9, typename t10,
            typename t11, typename t12, typename t13, typename t14, typename t15,
            typename t16, typename t17, typename t18, typename t19, typename t20
            >
        friend void serialize (
            const type_safe_union<t1,t2,t3,t4,t5,t6,t7,t8,t9,t10, t11,t12,t13,t14,t15,t16,t17,t18,t19,t20>& item,
            std::ostream& out
        );

        template <
            typename T
            >
        void apply_to_contents (
            T& obj
        )
        {
            switch (type_identity)
            {
                // do nothing because we are empty
                case 0: break;

                case 1: invoke_on(obj,unchecked_get<T1>());  break;
                case 2: invoke_on(obj,unchecked_get<T2>());  break;
                case 3: invoke_on(obj,unchecked_get<T3>());  break;
                case 4: invoke_on(obj,unchecked_get<T4>());  break;
                case 5: invoke_on(obj,unchecked_get<T5>());  break;

                case 6: invoke_on(obj,unchecked_get<T6>());  break;
                case 7: invoke_on(obj,unchecked_get<T7>());  break;
                case 8: invoke_on(obj,unchecked_get<T8>());  break;
                case 9: invoke_on(obj,unchecked_get<T9>());  break;
                case 10: invoke_on(obj,unchecked_get<T10>());  break;

                case 11: invoke_on(obj,unchecked_get<T11>());  break;
                case 12: invoke_on(obj,unchecked_get<T12>());  break;
                case 13: invoke_on(obj,unchecked_get<T13>());  break;
                case 14: invoke_on(obj,unchecked_get<T14>());  break;
                case 15: invoke_on(obj,unchecked_get<T15>());  break;

                case 16: invoke_on(obj,unchecked_get<T16>());  break;
                case 17: invoke_on(obj,unchecked_get<T17>());  break;
                case 18: invoke_on(obj,unchecked_get<T18>());  break;
                case 19: invoke_on(obj,unchecked_get<T19>());  break;
                case 20: invoke_on(obj,unchecked_get<T20>());  break;
            }
        }

        template <
            typename T
            >
        void apply_to_contents (
            const T& obj
        )
        {
            switch (type_identity)
            {
                // do nothing because we are empty
                case 0: break;

                case 1: invoke_on(obj,unchecked_get<T1>());  break;
                case 2: invoke_on(obj,unchecked_get<T2>());  break;
                case 3: invoke_on(obj,unchecked_get<T3>());  break;
                case 4: invoke_on(obj,unchecked_get<T4>());  break;
                case 5: invoke_on(obj,unchecked_get<T5>());  break;

                case 6: invoke_on(obj,unchecked_get<T6>());  break;
                case 7: invoke_on(obj,unchecked_get<T7>());  break;
                case 8: invoke_on(obj,unchecked_get<T8>());  break;
                case 9: invoke_on(obj,unchecked_get<T9>());  break;
                case 10: invoke_on(obj,unchecked_get<T10>());  break;

                case 11: invoke_on(obj,unchecked_get<T11>());  break;
                case 12: invoke_on(obj,unchecked_get<T12>());  break;
                case 13: invoke_on(obj,unchecked_get<T13>());  break;
                case 14: invoke_on(obj,unchecked_get<T14>());  break;
                case 15: invoke_on(obj,unchecked_get<T15>());  break;

                case 16: invoke_on(obj,unchecked_get<T16>());  break;
                case 17: invoke_on(obj,unchecked_get<T17>());  break;
                case 18: invoke_on(obj,unchecked_get<T18>());  break;
                case 19: invoke_on(obj,unchecked_get<T19>());  break;
                case 20: invoke_on(obj,unchecked_get<T20>());  break;
            }
        }

        template <
            typename T
            >
        void apply_to_contents (
            T& obj
        ) const
        {
            switch (type_identity)
            {
                // do nothing because we are empty
                case 0: break;

                case 1: invoke_on(obj,unchecked_get<T1>());  break;
                case 2: invoke_on(obj,unchecked_get<T2>());  break;
                case 3: invoke_on(obj,unchecked_get<T3>());  break;
                case 4: invoke_on(obj,unchecked_get<T4>());  break;
                case 5: invoke_on(obj,unchecked_get<T5>());  break;

                case 6: invoke_on(obj,unchecked_get<T6>());  break;
                case 7: invoke_on(obj,unchecked_get<T7>());  break;
                case 8: invoke_on(obj,unchecked_get<T8>());  break;
                case 9: invoke_on(obj,unchecked_get<T9>());  break;
                case 10: invoke_on(obj,unchecked_get<T10>());  break;

                case 11: invoke_on(obj,unchecked_get<T11>());  break;
                case 12: invoke_on(obj,unchecked_get<T12>());  break;
                case 13: invoke_on(obj,unchecked_get<T13>());  break;
                case 14: invoke_on(obj,unchecked_get<T14>());  break;
                case 15: invoke_on(obj,unchecked_get<T15>());  break;

                case 16: invoke_on(obj,unchecked_get<T16>());  break;
                case 17: invoke_on(obj,unchecked_get<T17>());  break;
                case 18: invoke_on(obj,unchecked_get<T18>());  break;
                case 19: invoke_on(obj,unchecked_get<T19>());  break;
                case 20: invoke_on(obj,unchecked_get<T20>());  break;
            }
        }

        template <
            typename T
            >
        void apply_to_contents (
            const T& obj
        ) const
        {
            switch (type_identity)
            {
                // do nothing because we are empty
                case 0: break;

                case 1: invoke_on(obj,unchecked_get<T1>());  break;
                case 2: invoke_on(obj,unchecked_get<T2>());  break;
                case 3: invoke_on(obj,unchecked_get<T3>());  break;
                case 4: invoke_on(obj,unchecked_get<T4>());  break;
                case 5: invoke_on(obj,unchecked_get<T5>());  break;

                case 6: invoke_on(obj,unchecked_get<T6>());  break;
                case 7: invoke_on(obj,unchecked_get<T7>());  break;
                case 8: invoke_on(obj,unchecked_get<T8>());  break;
                case 9: invoke_on(obj,unchecked_get<T9>());  break;
                case 10: invoke_on(obj,unchecked_get<T10>());  break;

                case 11: invoke_on(obj,unchecked_get<T11>());  break;
                case 12: invoke_on(obj,unchecked_get<T12>());  break;
                case 13: invoke_on(obj,unchecked_get<T13>());  break;
                case 14: invoke_on(obj,unchecked_get<T14>());  break;
                case 15: invoke_on(obj,unchecked_get<T15>());  break;

                case 16: invoke_on(obj,unchecked_get<T16>());  break;
                case 17: invoke_on(obj,unchecked_get<T17>());  break;
                case 18: invoke_on(obj,unchecked_get<T18>());  break;
                case 19: invoke_on(obj,unchecked_get<T19>());  break;
                case 20: invoke_on(obj,unchecked_get<T20>());  break;
            }
        }

        void swap (
            type_safe_union& item
        )
        {
            // if both *this and item contain the same type of thing
            if (type_identity == item.type_identity)
            {
                // swap the things in this and item.
                item.apply_to_contents(*this);
            }
            else if (type_identity == 0)
            {
                // *this doesn't contain anything.  So swap this and item and
                // then destruct item.
                item.apply_to_contents(*this);
                item.destruct();
            }
            else if (item.type_identity == 0)
            {
                // *this doesn't contain anything.  So swap this and item and
                // then destruct this.
                apply_to_contents(item);
                destruct();
            }
            else
            {
                type_safe_union temp;
                // swap *this into temp
                apply_to_contents(temp);
                // swap item into *this
                item.apply_to_contents(*this);
                // swap temp into item
                temp.apply_to_contents(item);
            }
        }

        template <typename T>
        T& get(
        )
        {
            validate_type<T>();
            construct<T>();
            return *static_cast<T*>(mem.get());
        }

        template <typename T>
        const T& cast_to (
        ) const
        {
            validate_type<T>();
            if (contains<T>())
                return *static_cast<const T*>(mem.get());
            else
                throw bad_type_safe_union_cast();
        }

        template <typename T>
        T& cast_to (
        )
        {
            validate_type<T>();
            if (contains<T>())
                return *static_cast<T*>(mem.get());
            else
                throw bad_type_safe_union_cast();
        }

        template <typename T>
        type_safe_union& operator= ( const T& item) { get<T>() = item; return *this; }

    };

// ----------------------------------------------------------------------------------------

    template <
        typename T1, typename T2, typename T3, typename T4, typename T5,
        typename T6, typename T7, typename T8, typename T9, typename T10,
        typename T11, typename T12, typename T13, typename T14, typename T15,
        typename T16, typename T17, typename T18, typename T19, typename T20
        >
    inline void swap (
        type_safe_union<T1,T2,T3,T4,T5,T6,T7,T8,T9,T10, T11,T12,T13,T14,T15,T16,T17,T18,T19,T20>& a,
        type_safe_union<T1,T2,T3,T4,T5,T6,T7,T8,T9,T10, T11,T12,T13,T14,T15,T16,T17,T18,T19,T20>& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------

    template <
        typename from,
        typename T1, typename T2, typename T3, typename T4, typename T5,
        typename T6, typename T7, typename T8, typename T9, typename T10,
        typename T11, typename T12, typename T13, typename T14, typename T15,
        typename T16, typename T17, typename T18, typename T19, typename T20
        >
    struct is_convertible<from,
        type_safe_union<T1,T2,T3,T4,T5,T6,T7,T8,T9,T10, T11,T12,T13,T14,T15,T16,T17,T18,T19,T20> >
    {
        const static bool value = is_convertible<from,T1>::value ||
                                  is_convertible<from,T2>::value ||
                                  is_convertible<from,T3>::value ||
                                  is_convertible<from,T4>::value ||
                                  is_convertible<from,T5>::value ||
                                  is_convertible<from,T6>::value ||
                                  is_convertible<from,T7>::value ||
                                  is_convertible<from,T8>::value ||
                                  is_convertible<from,T9>::value ||
                                  is_convertible<from,T10>::value ||
                                  is_convertible<from,T11>::value ||
                                  is_convertible<from,T12>::value ||
                                  is_convertible<from,T13>::value ||
                                  is_convertible<from,T14>::value ||
                                  is_convertible<from,T15>::value ||
                                  is_convertible<from,T16>::value ||
                                  is_convertible<from,T17>::value ||
                                  is_convertible<from,T18>::value ||
                                  is_convertible<from,T19>::value ||
                                  is_convertible<from,T20>::value;
    };

// ----------------------------------------------------------------------------------------

    namespace impl_tsu
    {
        struct serialize_helper
        {
            /*
                This is a function object to help us serialize type_safe_unions
            */

            std::ostream& out;
            serialize_helper(std::ostream& out_): out(out_) {}
            template <typename T>
            void operator() (const T& item) const { serialize(item, out); }
        };
    }

    template <
        typename T1, typename T2, typename T3, typename T4, typename T5,
        typename T6, typename T7, typename T8, typename T9, typename T10,
        typename T11, typename T12, typename T13, typename T14, typename T15,
        typename T16, typename T17, typename T18, typename T19, typename T20
        >
    void serialize (
        const type_safe_union<T1,T2,T3,T4,T5,T6,T7,T8,T9,T10, T11,T12,T13,T14,T15,T16,T17,T18,T19,T20>& item,
        std::ostream& out
    )
    {
        try
        {
            // save the type_identity
            serialize(item.type_identity, out);
            item.apply_to_contents(dlib::impl_tsu::serialize_helper(out));
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while serializing an object of type type_safe_union");
        }
    }

// ----------------------------------------------------------------------------------------

    template <
        typename T1, typename T2, typename T3, typename T4, typename T5,
        typename T6, typename T7, typename T8, typename T9, typename T10,
        typename T11, typename T12, typename T13, typename T14, typename T15,
        typename T16, typename T17, typename T18, typename T19, typename T20
        >
    void deserialize (
        type_safe_union<T1,T2,T3,T4,T5,T6,T7,T8,T9,T10, T11,T12,T13,T14,T15,T16,T17,T18,T19,T20>&  item,
        std::istream& in
    )
    {
        try
        {
            typedef type_safe_union<T1,T2,T3,T4,T5,T6,T7,T8,T9,T10, T11,T12,T13,T14,T15,T16,T17,T18,T19,T20> tsu_type;

            int type_identity;
            deserialize(type_identity, in);
            switch (type_identity)
            {
                // swap an empty type_safe_union into item since it should be in the empty state
                case 0: tsu_type().swap(item); break;

                case 1: deserialize(item.template get<T1>(), in);  break;
                case 2: deserialize(item.template get<T2>(), in);  break;
                case 3: deserialize(item.template get<T3>(), in);  break;
                case 4: deserialize(item.template get<T4>(), in);  break;
                case 5: deserialize(item.template get<T5>(), in);  break;

                case 6: deserialize(item.template get<T6>(), in);  break;
                case 7: deserialize(item.template get<T7>(), in);  break;
                case 8: deserialize(item.template get<T8>(), in);  break;
                case 9: deserialize(item.template get<T9>(), in);  break;
                case 10: deserialize(item.template get<T10>(), in);  break;

                case 11: deserialize(item.template get<T11>(), in);  break;
                case 12: deserialize(item.template get<T12>(), in);  break;
                case 13: deserialize(item.template get<T13>(), in);  break;
                case 14: deserialize(item.template get<T14>(), in);  break;
                case 15: deserialize(item.template get<T15>(), in);  break;

                case 16: deserialize(item.template get<T16>(), in);  break;
                case 17: deserialize(item.template get<T17>(), in);  break;
                case 18: deserialize(item.template get<T18>(), in);  break;
                case 19: deserialize(item.template get<T19>(), in);  break;
                case 20: deserialize(item.template get<T20>(), in);  break;

                default: throw serialization_error("Corrupt data detected while deserializing type_safe_union");
            }
        }
        catch (serialization_error& e)
        {
            throw serialization_error(e.info + "\n   while deserializing an object of type type_safe_union");
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_TYPE_SAFE_UNIOn_h_


dlib C++ Library - unicode.cpp

// Copyright (C) 2008 Keita Mochizuki, Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_UNICODe_CPp_
#define DLIB_UNICODe_CPp_
#include "unicode.h"
#include <cwchar>
#include "../string.h"
#include <vector>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    static const unichar SURROGATE_FIRST_TOP = 0xD800;
    static const unichar SURROGATE_SECOND_TOP = 0xDC00;
    static const unichar SURROGATE_CLEARING_MASK = 0x03FF;
    static const unichar SURROGATE_TOP = SURROGATE_FIRST_TOP;
    static const unichar SURROGATE_END = 0xE000;
    static const unichar SMP_TOP = 0x10000;
    static const int VALID_BITS = 10;

// ----------------------------------------------------------------------------------------

    template <typename T> bool is_surrogate(T ch)
    {
        return (zero_extend_cast<unichar>(ch) >= SURROGATE_TOP &&
                zero_extend_cast<unichar>(ch) < SURROGATE_END);
    }

// ----------------------------------------------------------------------------------------

    template <typename T> unichar surrogate_pair_to_unichar(T first, T second)
    {
        return ((first & SURROGATE_CLEARING_MASK) << VALID_BITS) | ((second & SURROGATE_CLEARING_MASK) + SMP_TOP);
    }
    //110110 0000000000
    //110111 0000000000

// ----------------------------------------------------------------------------------------

    void unichar_to_surrogate_pair(unichar input, unichar &first, unichar &second)
    {
        first = ((input - SMP_TOP) >> VALID_BITS) | SURROGATE_FIRST_TOP;
        second = (input & SURROGATE_CLEARING_MASK) | SURROGATE_SECOND_TOP;
    }

// ----------------------------------------------------------------------------------------

    template <int N> void wstr2ustring_t(const wchar_t *src, size_t src_len, ustring &dest);

    template <> void wstr2ustring_t<4>(const wchar_t *src, size_t , ustring &dest)
    {
        dest.assign((const unichar *)(src));
    }

    template <> void wstr2ustring_t<2>(const wchar_t *src, size_t src_len, ustring &dest)
    {
        size_t wlen = 0;
        for (size_t i = 0; i < src_len; i++)
        {
            is_surrogate(src[i]) ? i++, wlen++ : wlen++;
        }
        dest.resize(wlen);
        for (size_t i = 0, ii = 0; ii < src_len; ++i)
        {
            if (is_surrogate(src[ii]))
            {
                dest[i] = surrogate_pair_to_unichar(src[ii], src[ii+1]);
                ii += 2;
            }else
            {
                dest[i] = zero_extend_cast<unichar>(src[ii]);
                ii++;
            }
        }
    }

// ----------------------------------------------------------------------------------------

    const ustring convert_wstring_to_utf32(const std::wstring &src)
    {
        ustring dest;
        wstr2ustring_t<sizeof(wchar_t)>(src.c_str(), src.size(), dest);
        return dest;
    }

// ----------------------------------------------------------------------------------------

    template <int N> struct ustring2wstr
    {
    };

    // for the environment of sizeof(wchar_t) == 2 (i.e. Win32)
    template <> struct ustring2wstr<2>
    {
        wchar_t *wstr;
        size_t wlen;
        ustring2wstr(const ustring &src){
            wlen = 0;
            for (size_t i = 0; i < src.length(); ++i)
            {
                if (src[i] < SMP_TOP) wlen++;
                else wlen += 2;
            }
            wstr = new wchar_t[wlen+1];
            wstr[wlen] = L'\0';

            size_t wi = 0;
            for (size_t i = 0; i < src.length(); ++i)
            {
                if (src[i] < SMP_TOP)
                {
                    wstr[wi++] = (wchar_t)src[i];
                }else
                {
                    unichar high, low;
                    unichar_to_surrogate_pair(src[i], high, low);
                    wstr[wi++] = (wchar_t)high;
                    wstr[wi++] = (wchar_t)low;
                }
            }
        }
        ~ustring2wstr()
        {
            delete[] wstr;
        }
    };

    // for the environment of sizeof(wchar_t) == 4 (i.e. Unix gcc)
    template <> struct ustring2wstr<4>
    {
        const wchar_t *wstr;
        size_t wlen;
        ustring2wstr(const ustring &src){
            wstr = (const wchar_t *)(src.c_str());
            wlen = src.size();
        }
    };

// ----------------------------------------------------------------------------------------

    const std::wstring convert_utf32_to_wstring(const ustring &src)
    {
        ustring2wstr<sizeof(wchar_t)> conv(src);
        std::wstring dest(conv.wstr);
        return dest;
    }

// ----------------------------------------------------------------------------------------

    const std::wstring convert_mbstring_to_wstring(const std::string &src)
    {
        std::vector<wchar_t> wstr(src.length()+5);
        std::mbstowcs(&wstr[0], src.c_str(), src.length()+1);
        return std::wstring(&wstr[0]);
    }

// ----------------------------------------------------------------------------------------

    const std::string convert_wstring_to_mbstring(const std::wstring &src)
    {
        using namespace std;
        std::string str;
        str.resize((src.length() + 1) * MB_CUR_MAX);
        wcstombs(&str[0], src.c_str(), str.size());
        return std::string(&str[0]);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_UNICODe_CPp_


dlib C++ Library - unicode.h

// Copyright (C) 2007  Davis E. King (davis@dlib.net), and Nils Labugt
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_UNICODe_H_
#define DLIB_UNICODe_H_

#include "../uintn.h"
#include "../algs.h"
#include "unicode_abstract.h"
#include <string>
#include <cstring>

#include <fstream>

namespace dlib
{

// ----------------------------------------------------------------------------------------

    typedef uint32 unichar;

#if defined(__GNUC__) && __GNUC__ < 4 && __GNUC_MINOR__ < 4
    struct unichar_traits
    {
        typedef dlib::unichar    char_type;
        typedef dlib::unichar    int_type;
        typedef std::streamoff   off_type;
        typedef std::streampos   pos_type;
        typedef std::mbstate_t   state_type;

        static void assign(char_type& c1, const char_type& c2) { c1 = c2; }
        static bool eq(const char_type& c1, const char_type& c2) { return c1 == c2; }
        static bool lt(const char_type& c1, const char_type& c2) { return c1 < c2; }
        static int compare(const char_type* s1, const char_type* s2, size_t n)
        {
            for (size_t i = 0; i < n; ++i)
            {
                if (s1[i] < s2[i])
                    return -1;
                else if (s1[i] > s2[i])
                    return 1;
            }
            return 0;
        }

        static size_t length(const char_type* s)
        {
            size_t i = 0;
            while (s[i] != 0)
                ++i;
            return i;
        }

        static const char_type* find(const char_type* s, size_t n,
                                     const char_type& a)
        {
            for (size_t i = 0; i < n; ++i)
            {
                if (s[i] == a)
                {
                    return s+i;
                }
            }
            return 0;
        }

        static char_type* move(char_type* s1, const char_type* s2, size_t n)
        {
            return static_cast<char_type*>(std::memmove(s1, s2, sizeof(char_type)*n));
        }

        static char_type* copy(char_type* s1, const char_type* s2, size_t n)
        {
            for (size_t i = 0; i < n; ++i)
                s1[i] = s2[i];

            return s1;
        }

        static char_type* assign(char_type* s, size_t n, char_type a)
        {
            for (size_t i = 0; i < n; ++i)
                s[i] = a;

            return s;
        }

        static int_type not_eof(const int_type& c)
        {
            if (!eq_int_type(c,eof()))
                return to_int_type(c);
            else
                return 0;
        }

        static char_type to_char_type(const int_type& c) { return static_cast<char_type>(c); }
        static int_type to_int_type(const char_type& c) { return zero_extend_cast<int_type>(c); }

        static bool eq_int_type(const int_type& c1, const int_type& c2) { return c1 == c2; }

        static int_type eof() { return static_cast<int_type>(EOF); }
    };

    typedef std::basic_string<unichar, unichar_traits> ustring;
#else
    typedef std::basic_string<unichar> ustring;
#endif

// ----------------------------------------------------------------------------------------

    namespace unicode_helpers
    {

        template <
            typename charT
            >
        int u8_to_u32(
            charT& result,
            std::istream& in
        )
        /*!
            ensures
                - if (there just wasn't any more data and we hit EOF) then
                    - returns 0
                - else if (we decoded another character without error) then
                    - #result == the decoded character
                    - returns the number of bytes consumed to make this character
                - else
                    - some error occurred
                    - returns -1
        !*/
        {
            int val = in.get();
            if (val == EOF)
                return 0;

            unichar ch[4];
            ch[0] = zero_extend_cast<unichar>(val);
            if ( ch[0] < 0x80 )
            {
                result = static_cast<charT>(ch[0]);
                return 1;
            }
            if ( ( ch[0] & ~0x3F ) == 0x80 )
            {
                // invalid leading byte
                return -1;
            }
            if ( ( ch[0] & ~0x1F ) == 0xC0 )
            {
                val = in.get();
                if ( val == EOF )
                    return -1;

                ch[1] = zero_extend_cast<unichar>(val);
                if ( ( ch[1] & ~0x3F ) != 0x80 )
                    return -1; // invalid tail
                if ( ( ch[0] & ~0x01 ) == 0xC0 )
                    return -1; // overlong form
                ch[0] &= 0x1F;
                ch[1] &= 0x3F;
                result = static_cast<charT>(( ch[0] << 6 ) | ch[1]);
                return 2;
            }
            if ( ( ch[0] & ~0x0F ) == 0xE0 )
            {
                for ( unsigned n = 1;n < 3;n++ )
                {
                    val = in.get();
                    if ( val == EOF )
                        return -1;
                    ch[n] = zero_extend_cast<unichar>(val);
                    if ( ( ch[n] & ~0x3F ) != 0x80 )
                        return -1; // invalid tail
                    ch[n] &= 0x3F;
                }
                ch[0] &= 0x0F;
                result = static_cast<charT>(( ch[0] << 12 ) | ( ch[1] << 6 ) | ch[2]);
                if ( result < 0x0800 )
                    return -1; // overlong form
                if ( result >= 0xD800 && result < 0xE000 )
                    return -1; // invalid character (UTF-16 surrogate pairs)
                if ( result >= 0xFDD0 && result <= 0xFDEF )
                    return -1; // noncharacter
                if ( result >= 0xFFFE )
                    return -1; // noncharacter
                return 3;
            }
            if ( ( ch[0] & ~0x07 ) == 0xF0 )
            {
                for ( unsigned n = 1;n < 4;n++ )
                {
                    val = in.get();
                    if ( val == EOF )
                        return -1;
                    ch[n] = zero_extend_cast<unichar>(val);
                    if ( ( ch[n] & ~0x3F ) != 0x80 )
                        return -1; // invalid tail
                    ch[n] &= 0x3F;
                }
                if ( ( ch[0] ^ 0xF6 ) < 4 )
                    return -1;
                ch[0] &= 0x07;
                result  = static_cast<charT>(( ch[0] << 18 ) | ( ch[1] << 12 ) | ( ch[2] << 6 ) | ch[3]);
                if ( result < 0x10000 )
                    return -1; // overlong form
                if ( (result & 0xFFFF) >= 0xFFFE )
                    return -1; // noncharacter
                return 4;
            }
            return -1;
        }

    // ------------------------------------------------------------------------------------

        template <typename charT>
        class basic_utf8_streambuf : public std::basic_streambuf<charT>
        {
        public:
            basic_utf8_streambuf (
                std::ifstream& fin_
            ) :
                fin(fin_)
            {
                this->setg(in_buffer+max_putback,
                     in_buffer+max_putback,
                     in_buffer+max_putback);
            }

        protected:

            typedef typename std::basic_streambuf<charT>::int_type int_type;

            // input functions
            int_type underflow(
            )
            {
                if (this->gptr() < this->egptr())
                {
                    return zero_extend_cast<int_type>(*this->gptr());
                }

                int num_put_back = static_cast<int>(this->gptr() - this->eback());
                if (num_put_back > max_putback)
                {
                    num_put_back = max_putback;
                }

                // copy the putback characters into the putback end of the in_buffer
                std::memmove(in_buffer+(max_putback-num_put_back), this->gptr()-num_put_back, num_put_back);

                // fill the buffer with characters
                int n = in_buffer_size-max_putback;
                int i;
                for (i = 0; i < n; ++i)
                {
                    charT ch;
                    if (unicode_helpers::u8_to_u32(ch,fin) > 0)
                    {
                        (in_buffer+max_putback)[i] = ch;
                    }
                    else
                    {
                        break;
                    }
                }

                if (i == 0)
                {
                    // an error occurred or we hit EOF
                    return EOF;
                }

                // reset in_buffer pointers
                this->setg (in_buffer+(max_putback-num_put_back),
                      in_buffer+max_putback,
                      in_buffer+max_putback+i);

                return zero_extend_cast<int_type>(*this->gptr());
            }

        private:
            std::ifstream& fin;
            static const int max_putback = 4;
            static const int in_buffer_size = 10;
            charT in_buffer[in_buffer_size];
        };
    }

// ----------------------------------------------------------------------------------------

    template <typename T>
    bool is_combining_char(
        const T ch_
    )
    {
        const unichar ch = zero_extend_cast<unichar>(ch_);
        if ( ch < 0x300 ) return false;
        if ( ch < 0x370 ) return true;

        if ( ch < 0x800 )
        {
            if ( ch < 0x483 )return false;if ( ch < 0x48A )return true;

            if ( ch < 0x591 )return false;if ( ch < 0x5D0 )
            {
                if ( ch == 0x5C0 )return false;
                if ( ch == 0x5C3 )return false;
                if ( ch == 0x5C6 )return false;
                return true;
            }
            if ( ch < 0x610 )return false;if ( ch < 0x616 )return true;
            if ( ch < 0x64B )return false;if ( ch < 0x660 )return true;

            if ( ch == 0x670 )return true;

            if ( ch < 0x6D6 )return false;if ( ch < 0x6EE )
            {
                if ( ch == 0x6DD )return false;
                if ( ch == 0x6E5 )return false;
                if ( ch == 0x6E6 )return false;
                if ( ch == 0x6E9 )return false;
                return true;
            }
            if ( ch == 0x711 )return true;

            if ( ch < 0x730 )return false;if ( ch < 0x74B )return true;
            if ( ch < 0x7A6 )return false;if ( ch < 0x7B1 )return true;
            if ( ch < 0x7EB )return false;if ( ch < 0x7F4 )return true;
            return false;
        }
        if ( ch < 0xA00 )
        {
            if ( ch < 0x901 )return false;if ( ch < 0x904 )return true;
            if ( ch < 0x93C )return false;if ( ch < 0x955 )
            {
                if ( ch == 0x93D )return false;
                if ( ch == 0x950 )return false;
                return true;
            }
            if ( ch < 0x962 )return false;if ( ch < 0x964 )return true;
            if ( ch < 0x981 )return false;if ( ch < 0x984 )return true;
            if ( ch < 0x9BC )return false;if ( ch < 0x9D8 )
            {
                if ( ch == 0x9BD )return false;
                if ( ch == 0x9CE )return false;
                return true;
            }
            if ( ch < 0x9E2 )return false;if ( ch < 0x9E4 )return true;
            return false;
        }
        if ( ch < 0xC00 )
        {
            if ( ch < 0xA01 )return false;if ( ch < 0xA04 )return true;
            if ( ch < 0xA3C )return false;if ( ch < 0xA4E )return true;
            if ( ch < 0xA70 )return false;if ( ch < 0xA72 )return true;
            if ( ch < 0xA81 )return false;if ( ch < 0xA84 )return true;
            if ( ch < 0xABC )return false;if ( ch < 0xACE )
            {
                if ( ch == 0xABD )return false;
                return true;
            }
            if ( ch < 0xAE2 )return false;if ( ch < 0xAE4 )return true;
            if ( ch < 0xB01 )return false;if ( ch < 0xB04 )return true;
            if ( ch < 0xB3C )return false;if ( ch < 0xB58 )
            {
                if ( ch == 0xB3D )return false;
                return true;
            }
            if ( ch == 0xB82 )return true;

            if ( ch < 0xBBE )return false;if ( ch < 0xBD8 )return true;

            if ( ch == 0xBF4 )return true;
            if ( ch == 0xBF8 )return true;
            return false;
        }
        if(ch < 0xE00)
        {
            if ( ch < 0xC01 )return false;if ( ch < 0xC04 )return true;
            if ( ch < 0xC3E )return false;if ( ch < 0xC57 )return true;
            if ( ch < 0xC82 )return false;if ( ch < 0xC84 )return true;
            if ( ch < 0xCBC )return false;if ( ch < 0xCD7 )
            {
                if ( ch == 0xCBD )return false;
                return true;
            }
            if ( ch < 0xCE2 )return false;if ( ch < 0xCE4 )return true;
            if ( ch < 0xD02 )return false;if ( ch < 0xD04 )return true;
            if ( ch < 0xD3E )return false;if ( ch < 0xD58 )return true;
            if ( ch < 0xD82 )return false;if ( ch < 0xD84 )return true;
            if ( ch < 0xDCA )return false;if ( ch < 0xDF4 )return true;
            return false;
        }
        if(ch < 0x1000)
        {
            if ( ch == 0xE31 )return true;

            if ( ch < 0xE34 )return false;if ( ch < 0xE3B )return true;
            if ( ch < 0xE47 )return false;if ( ch < 0xE4F )return true;

            if ( ch == 0xEB1 )return true;

            if ( ch < 0xEB4 )return false;if ( ch < 0xEBD )return true;
            if ( ch < 0xEC8 )return false;if ( ch < 0xECE )return true;
            if ( ch < 0xF18 )return false;if ( ch < 0xF1A )return true;

            if ( ch == 0xF35 )return true;
            if ( ch == 0xF37 )return true;
            if ( ch == 0xF39 )return true;

            if ( ch < 0xF3E )return false;if ( ch < 0xF40 )return true;
            if ( ch < 0xF71 )return false;if ( ch < 0xF88 )
            {
                if ( ch == 0xF85 )return false;
                return true;
            }
            if ( ch < 0xF90 )return false;if ( ch < 0xFBD )return true;

            if ( ch == 0xFC6 )return true;
            return false;
        }
        if ( ch < 0x1800 )
        {
            if ( ch < 0x102C )return false;if ( ch < 0x1040 )return true;
            if ( ch < 0x1056 )return false;if ( ch < 0x105A )return true;

            if ( ch == 0x135F )return true;

            if ( ch < 0x1712 )return false;if ( ch < 0x1715 )return true;
            if ( ch < 0x1732 )return false;if ( ch < 0x1735 )return true;
            if ( ch < 0x1752 )return false;if ( ch < 0x1754 )return true;
            if ( ch < 0x1772 )return false;if ( ch < 0x1774 )return true;
            if ( ch < 0x17B6 )return false;if ( ch < 0x17D4 )return true;

            if ( ch == 0x17DD )return true;
            return false;
        }
        if(ch < 0x2000)
        {
            if ( ch < 0x180B )return false;if ( ch < 0x180E )return true;

            if ( ch == 0x18A9 )return true;

            if ( ch < 0x1920 )return false;if ( ch < 0x193C )return true;
            if ( ch < 0x19B0 )return false;if ( ch < 0x19C1 )return true;
            if ( ch < 0x19C8 )return false;if ( ch < 0x19CA )return true;
            if ( ch < 0x1A17 )return false;if ( ch < 0x1A1C )return true;
            if ( ch < 0x1B00 )return false;if ( ch < 0x1B05 )return true;
            if ( ch < 0x1B34 )return false;if ( ch < 0x1B45 )return true;
            if ( ch < 0x1B6B )return false;if ( ch < 0x1B74 )return true;
            if ( ch < 0x1DC0 )return false;if ( ch < 0x1E00 )return true;
            return false;
        }
        if ( ch < 0x20D0 )return false;if ( ch < 0x2100 )return true;
        if ( ch < 0x302A )return false;if ( ch < 0x3030 )return true;
        if ( ch < 0x3099 )return false;if ( ch < 0x309B )return true;

        if ( ch == 0xA802 )return true;
        if ( ch == 0xA806 )return true;
        if ( ch == 0xA80B )return true;

        if ( ch < 0xA823 )return false;if ( ch < 0xA828 )return true;

        if ( ch == 0xFB1E )return true;

        if ( ch < 0xFE00 )return false;if ( ch < 0xFE10 )return true;
        if ( ch < 0xFE20 )return false;if ( ch < 0xFE30 )return true;
        if ( ch < 0x10A01 )return false;if ( ch < 0x10A10 )return true;
        if ( ch < 0x10A38 )return false;if ( ch < 0x10A40 )return true;
        if ( ch < 0x1D165 )return false;if ( ch < 0x1D16A )return true;
        if ( ch < 0x1D16D )return false;if ( ch < 0x1D173 )return true;
        if ( ch < 0x1D17B )return false;if ( ch < 0x1D183 )return true;
        if ( ch < 0x1D185 )return false;if ( ch < 0x1D18C )return true;
        if ( ch < 0x1D1AA )return false;if ( ch < 0x1D1AE )return true;
        if ( ch < 0x1D242 )return false;if ( ch < 0x1D245 )return true;
        if ( ch < 0xE0100 )return false;if ( ch < 0xE01F0 )return true;
        return false;
    }

// ----------------------------------------------------------------------------------------

    class invalid_utf8_error : public error
    {
    public:
        invalid_utf8_error():error(EUTF8_TO_UTF32) {}
    };

    inline const ustring convert_utf8_to_utf32 (
        const std::string& str
    )
    {
        using namespace unicode_helpers;
        ustring temp;
        std::istringstream sin(str);

        temp.reserve(str.size());

        int status;
        unichar ch;
        while ( (status = u8_to_u32(ch,sin)) > 0)
            temp.push_back(ch);

        if (status < 0)
            throw invalid_utf8_error();

        return temp;
    }

// ----------------------------------------------------------------------------------------

    bool is_surrogate(unichar ch);

    unichar surrogate_pair_to_unichar(unichar first, unichar second);

    void unichar_to_surrogate_pair(unichar unicode, unichar &first, unichar &second);

    const ustring convert_wstring_to_utf32 (
        const std::wstring &wstr
    );

    const std::wstring convert_utf32_to_wstring (
        const ustring &src
    );

    const std::wstring convert_mbstring_to_wstring (
        const std::string &src
    );

    const std::string convert_wstring_to_mbstring(
        const std::wstring &src
    );

// ----------------------------------------------------------------------------------------

    template <typename charT>
    class basic_utf8_ifstream : public std::basic_istream<charT>
    {
    public:

        basic_utf8_ifstream (
        ) : std::basic_istream<charT>(&buf), buf(fin) {}

        basic_utf8_ifstream (
            const char* file_name,
            std::ios_base::openmode mode = std::ios::in
        ) :
            std::basic_istream<charT>(&buf),
            buf(fin)
        {
            fin.open(file_name,mode);
            // make this have the same error state as fin
            this->clear(fin.rdstate());
        }

        basic_utf8_ifstream (
            const std::string& file_name,
            std::ios_base::openmode mode = std::ios::in
        ) :
            std::basic_istream<charT>(&buf),
            buf(fin)
        {
            fin.open(file_name.c_str(),mode);
            // make this have the same error state as fin
            this->clear(fin.rdstate());
        }

        void open(
            const std::string& file_name,
            std::ios_base::openmode mode = std::ios::in
        )
        {
            open(file_name.c_str(),mode);
        }

        void open (
            const char* file_name,
            std::ios_base::openmode mode = std::ios::in
        )
        {
            fin.close();
            fin.clear();
            fin.open(file_name,mode);
            // make this have the same error state as fin
            this->clear(fin.rdstate());
        }

        void close (
        )
        {
            fin.close();
            // make this have the same error state as fin
            this->clear(fin.rdstate());
        }

    private:

        std::ifstream fin;
        unicode_helpers::basic_utf8_streambuf<charT> buf;
    };

    typedef basic_utf8_ifstream<unichar> utf8_uifstream;
    typedef basic_utf8_ifstream<wchar_t> utf8_wifstream;

// ----------------------------------------------------------------------------------------

}

#ifdef NO_MAKEFILE
#include "unicode.cpp"
#endif

#endif // DLIB_UNICODe_H_


dlib C++ Library - vectorstream.h

// Copyright (C) 2012  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_VECTORStREAM_Hh_
#define DLIB_VECTORStREAM_Hh_

#include "vectorstream_abstract.h"

#include <cstring>
#include <iostream>
#include <streambuf>
#include <vector>
#include <cstdio>
#include "../algs.h"

#ifdef _MSC_VER
// Disable the warning about inheriting from std::iostream 'via dominance' since this warning is a warning about
// visual studio conforming to the standard and is ignorable.  See http://connect.microsoft.com/VisualStudio/feedback/details/733720/inheriting-from-std-fstream-produces-c4250-warning
// for further details if interested.
#pragma warning(disable : 4250)
#endif // _MSC_VER

namespace dlib
{
    class vectorstream : public std::iostream
    {
        class vector_streambuf : public std::streambuf
        {
            typedef std::vector<char>::size_type size_type;
            size_type read_pos; // buffer[read_pos] == next byte to read from buffer
        public:
            std::vector<char>& buffer;

            vector_streambuf(
                std::vector<char>& buffer_
            ) :
                read_pos(0),
                buffer(buffer_)
            {}

            void seekg(size_type pos)
            {
                read_pos = pos;
            }

            // ------------------------ OUTPUT FUNCTIONS ------------------------

            int_type overflow ( int_type c)
            {
                if (c != EOF) buffer.push_back(static_cast<char>(c));
                return c;
            }

            std::streamsize xsputn ( const char* s, std::streamsize num)
            {
                buffer.insert(buffer.end(), s, s+num);
                return num;
            }

            // ------------------------ INPUT FUNCTIONS ------------------------

            int_type underflow(
            )
            {
                if (read_pos < buffer.size())
                    return static_cast<unsigned char>(buffer[read_pos]);
                else
                    return EOF;
            }

            int_type uflow(
            )
            {
                if (read_pos < buffer.size())
                    return static_cast<unsigned char>(buffer[read_pos++]);
                else
                    return EOF;
            }

            int_type pbackfail(
                int_type c
            )
            {
                // if they are trying to push back a character that they didn't read last
                // that is an error
                const unsigned long prev = read_pos-1;
                if (c != EOF && prev < buffer.size() &&
                    c != static_cast<unsigned char>(buffer[prev]))
                {
                    return EOF;
                }

                read_pos = prev;
                return 1;
            }

            std::streamsize xsgetn (
                char* s,
                std::streamsize n
            )
            {
                if (read_pos < buffer.size())
                {
                    const size_type num = std::min<size_type>(n, buffer.size()-read_pos);
                    std::memcpy(s, &buffer[read_pos], num);
                    read_pos += num;
                    return num;
                }
                return 0;
            }

        };

    public:

        vectorstream (
            std::vector<char>& buffer
        ) :
            std::iostream(&buf),
            buf(buffer)
        {}

        std::istream& seekg (
            std::streampos pos
        )
        {
            buf.seekg(pos);
            return *this;
        }

    private:
        vector_streambuf buf;
    };
}

#endif // DLIB_VECTORStREAM_Hh_


dlib C++ Library - xml_parser_kernel_1.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_XML_PARSER_KERNEl_1_
#define DLIB_XML_PARSER_KERNEl_1_

#include "xml_parser_kernel_abstract.h"

#include <sstream>
#include <string>
#include <fstream>
#include <iostream>
#include "xml_parser_kernel_interfaces.h"
#include "../algs.h"
#include <cstdio>
#include "../map.h"
#include "../stack.h"
#include "../sequence.h"
#include "../memory_manager.h"

namespace dlib
{

    class xml_parser
    {
        typedef dlib::map<std::string,std::string,memory_manager<char>::kernel_2a>::kernel_1b map;
        typedef dlib::stack<std::string,memory_manager<char>::kernel_2a>::kernel_1a stack;
        typedef sequence<document_handler*>::kernel_2a seq_dh;
        typedef sequence<error_handler*>::kernel_2a seq_eh;

         /*!
            INITIAL VALUE
                dh_list.size() == 0
                eh_list.size() == 0

            CONVENTION
                dh_list == a sequence of pointers to all the document_handlers that
                           have been added to the xml_parser
                eh_list == a sequence of pointers to all the error_handlers that
                           have been added to the xml_parser

                map is used to implement the attribute_list interface
                stack is used just inside the parse function
                seq_dh is used to make the dh_list member variable
                seq_eh is used to make the eh_list member variable
        !*/

        public:

            // These typedefs are here for backwards compatibily with previous versions of
            // dlib.
            typedef xml_parser kernel_1a;
            typedef xml_parser kernel_1a_c;

            xml_parser(
            ) {}

            virtual ~xml_parser(
            ){}

            inline void clear(
            );

            inline void parse (
                std::istream& in
            );

            inline void add_document_handler (
                document_handler& item
            );

            inline void add_error_handler (
                error_handler& item
            );

            inline void swap (
                xml_parser& item
            );

        private:

            // -----------------------------------

            // attribute_list interface implementation
            class attrib_list : public attribute_list
            {
            public:
                // the list of attribute name/value pairs
                map list;

                bool is_in_list (
                    const std::string& key
                ) const
                {
                    return list.is_in_domain(key);
                }

                const std::string& operator[] (
                    const std::string& key
                ) const
                {
                    return list[key];
                }

                bool at_start (
                ) const { return list.at_start(); }

                void reset (
                ) const { return list.reset(); }

                bool current_element_valid (
                ) const { return list.current_element_valid(); }

                const type& element (
                ) const { return list.element(); }

                type& element (
                ) { return list.element(); }

                bool move_next (
                ) const { return list.move_next(); }

                unsigned long size (
                ) const { return list.size(); }
            };

            // -----------------------------------

            enum token_type
            {
                element_start, // the first tag of an element
                element_end,   // the last tag of an element
                empty_element, // the singular tag of an empty element
                pi,            // processing instruction
                chars,         // the non-markup data between tags
                chars_cdata,   // the data from a CDATA section
                eof,           // this token is returned when we reach the end of input
                error,         // this token indicates that the tokenizer couldn't
                               // determine which category the next token fits into
                dtd,           // this token is for an entire dtd
                comment        // this is a token for comments
            };
            /*
                notes about the tokens:
                    the tokenizer guarantees that the following tokens to not
                    contain the '<' character except as the first character of the token
                    element_start, element_end, empty_element, and pi.  they also only
                    contain the '>' characer as their last character.

                    it is also guaranteed that pi is at least of the form <??>.  that
                    is to say that it always always begins with <? and ends with ?>.

                    it is also guaranteed that all markup tokens will begin with the '<'
                    character and end with the '>'. there won't be any leading or
                    trailing whitespaces.   this whitespace is considered a chars token.
            */

            // private member functions
            inline void get_next_token(
                std::istream& in,
                std::string& token_text,
                int& token_kind,
                unsigned long& line_number
            );
            /*!
                ensures
                    gets the next token from in and puts it in token_text and
                    token_kind == the kind of the token found and
                    line_number is incremented every time a '\n' is encountered and
                    entity references are translated into the characters they represent
                    only for chars tokens
            !*/

            inline int parse_element (
                const std::string& token,
                std::string& name,
                attrib_list& atts
            );
            /*!
                requires
                    token is a token of kind start_element or empty_element
                ensures
                    gets the element name and puts it into the string name and
                    parses out the attributes and puts them into the attribute_list atts

                    return 0 upon success or
                    returns -1 if it failed to parse token
            !*/

            inline int parse_pi (
                const std::string& token,
                std::string& target,
                std::string& data
            );
            /*!
                requires
                    token is a token of kind pi
                ensures
                    the target from the processing instruction is put into target and
                    the data from the processing instruction is put into data

                    return 0 upon success or
                    returns -1 if it failed to parse token
            !*/

            inline int parse_element_end (
                const std::string& token,
                std::string& name
            );
            /*!
                requires
                    token is a token of kind element_end
                ensures
                    the name from the ending element tag is put into the string name

                    return 0 upon success or
                    returns -1 if it failed to parse token
            !*/

            inline int change_entity (
                std::istream& in
            );
            /*!
                ensures
                    performs the following translations and returns the new character
                                amp;   -> &
                                lt;    -> <
                                gt;    -> >
                                apos;  -> '
                                quot;  -> "

                    or returns -1 if we hit an undefined entity reference or EOF.
                            (i.e. it was not one of the entities listed above)

            !*/

            // -----------------------------------

            // private member data
            seq_dh dh_list;
            seq_eh eh_list;

            // -----------------------------------

            // restricted functions: assignment and copy construction
            xml_parser(xml_parser&);
            xml_parser& operator= (
                        xml_parser&
                        );

    };

    inline void swap (
        xml_parser& a,
        xml_parser& b
    ) { a.swap(b); }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    void xml_parser::
    clear(
    )
    {
        // unregister all event handlers
        eh_list.clear();
        dh_list.clear();
    }

// ----------------------------------------------------------------------------------------

    void xml_parser::
    parse (
        std::istream& in
    )
    {
        DLIB_CASSERT ( in.fail() == false ,
            "\tvoid xml_parser::parse"
            << "\n\tthe input stream must not be in the fail state"
            << "\n\tthis: " << this
            );

        // save which exceptions in will throw and make it so it won't throw any
        // for the life of this function
        std::ios::iostate old_exceptions = in.exceptions();
        // set it to not throw anything
        in.exceptions(std::ios::goodbit);

        try
        {
            unsigned long line_number = 1;

            // skip any whitespace before the start of the document
            while (in.peek() == ' ' || in.peek() == '\t' || in.peek() == '\n' || in.peek() == '\r' )
            {
                if (in.peek() == '\n')
                    ++line_number;
                in.get();
            }

            stack tags; // this stack contains the last start tag seen
            bool seen_fatal_error = false;
            bool seen_root_tag = false;  // this is true after we have seen the root tag

            // notify all the document_handlers that we are about to being parsing
            for (unsigned long i = 0; i < dh_list.size(); ++i)
            {
                dh_list[i]->start_document();
            }

            std::string chars_buf; // used to collect chars data between consecutive
                                // chars and chars_cdata tokens so that
                                // document_handlers receive all chars data between
                                // tags in one call

            // variables to be used with the parsing functions
            attrib_list atts;
            std::string name;
            std::string target;
            std::string data;

            // variables to use with the get_next_token() function
            std::string token_text;
            int token_kind;

            get_next_token(in,token_text,token_kind,line_number);

            while (token_kind != eof)
            {
                bool is_empty = false;  // this becomes true when this token is an empty_element

                switch (token_kind)
                {

                case empty_element: is_empty = true;
                case element_start:
                    {
                        seen_root_tag = true;

                        int status = parse_element(token_text,name,atts);
                        // if there was no error parsing the element
                        if (status == 0)
                        {
                            // notify all the document_handlers
                            for (unsigned long i = 0; i < dh_list.size(); ++i)
                            {
                                dh_list[i]->start_element(line_number,name,atts);
                                if (is_empty)
                                    dh_list[i]->end_element(line_number,name);
                            }
                        }
                        else
                        {
                            seen_fatal_error = true;
                        }

                        // if this is an element_start token then push the name of
                        // the element on to the stack
                        if (token_kind == element_start)
                        {
                            tags.push(name);
                        }

                    }break;

                // ----------------------------------------

                case element_end:
                    {

                        int status = parse_element_end (token_text,name);

                        // if there was no error parsing the element
                        if (status == 0)
                        {
                            // make sure this ending element tag matches the last start
                            // element tag we saw
                            if ( tags.size() == 0 || name != tags.current())
                            {
                                // they don't match so signal a fatal error
                                seen_fatal_error = true;
                            }
                            else
                            {
                                // notify all the document_handlers
                                for (unsigned long i = 0; i < dh_list.size(); ++i)
                                {
                                    dh_list[i]->end_element(line_number,name);
                                }

                                // they match so throw away this element name
                                tags.pop(name);
                            }
                        }
                        else
                        {
                            seen_fatal_error = true;
                        }

                    }break;

                // ----------------------------------------

                case pi:
                    {

                        int status = parse_pi (token_text,target,data);
                        // if there was no error parsing the element
                        if (status == 0)
                        {
                            // notify all the document_handlers
                            for (unsigned long i = 0; i < dh_list.size(); ++i)
                            {
                                dh_list[i]->processing_instruction(line_number,target,data);
                            }
                        }
                        else
                        {
                            // notify all the error_handlers
                            for (unsigned long i = 0; i < eh_list.size(); ++i)
                            {
                                eh_list[i]->error(line_number);
                            }
                        }
                        while (in.peek() == ' ' || in.peek() == '\t' || in.peek() == '\n' || in.peek() == '\r' )
                        {
                            if (in.peek() == '\n')
                                ++line_number;
                            in.get();
                        }

                    }break;

                // ----------------------------------------

                case chars:
                    {
                        if (tags.size() != 0)
                        {
                            chars_buf += token_text;
                        }
                        else if (token_text.find_first_not_of(" \t\r\n") != std::string::npos)
                        {
                            // you can't have non whitespace chars data outside the root element
                            seen_fatal_error = true;
                        }
                    }break;

                // ----------------------------------------

                case chars_cdata:
                    {
                        if (tags.size() != 0)
                        {
                            chars_buf += token_text;
                        }
                        else
                        {
                            // you can't have chars_data outside the root element
                            seen_fatal_error = true;
                        }
                    }break;

                // ----------------------------------------

                case eof:
                    break;

                // ----------------------------------------

                case error:
                    {
                        seen_fatal_error = true;
                    }break;

                // ----------------------------------------

                case dtd:       // fall though
                case comment:   // do nothing
                    break;

                // ----------------------------------------

                }

                // if there was a fatal error then quit loop
                if (seen_fatal_error)
                    break;

                // if we have seen the last tag then quit the loop
                if (tags.size() == 0 && seen_root_tag)
                    break;

                get_next_token(in,token_text,token_kind,line_number);

                // if the next token is not a chars or chars_cdata token then flush
                // the chars_buf to the document_handlers
                if ( (token_kind != chars) &&
                    (token_kind != chars_cdata) &&
                    (token_kind != dtd) &&
                    (token_kind != comment) &&
                    (chars_buf.size() != 0)
                    )
                {
                    // notify all the document_handlers
                    for (unsigned long i = 0; i < dh_list.size(); ++i)
                    {
                        dh_list[i]->characters(chars_buf);
                    }
                    chars_buf.erase();
                }

            } //while (token_kind != eof)

            // you can't have any unmatched tags or any fatal erros
            if (tags.size() != 0 || seen_fatal_error)
            {
                // notify all the error_handlers
                for (unsigned long i = 0; i < eh_list.size(); ++i)
                {
                    eh_list[i]->fatal_error(line_number);
                }

            }

            // notify all the document_handlers that we have ended parsing
            for (unsigned long i = 0; i < dh_list.size(); ++i)
            {
                dh_list[i]->end_document();
            }

        }
        catch (...)
        {
            // notify all the document_handlers that we have ended parsing
            for (unsigned long i = 0; i < dh_list.size(); ++i)
            {
                dh_list[i]->end_document();
            }

            // restore the old exception settings to in
            in.exceptions(old_exceptions);

            // don't forget to rethrow the exception
            throw;
        }

        // restore the old exception settings to in
        in.exceptions(old_exceptions);

    }

// ----------------------------------------------------------------------------------------

    void xml_parser::
    add_document_handler (
        document_handler& item
    )
    {
        document_handler* temp = &item;
        dh_list.add(dh_list.size(),temp);
    }

// ----------------------------------------------------------------------------------------

    void xml_parser::
    add_error_handler (
        error_handler& item
    )
    {
        error_handler* temp = &item;
        eh_list.add(eh_list.size(),temp);
    }

// ----------------------------------------------------------------------------------------

    void xml_parser::
    swap (
        xml_parser& item
    )
    {
        dh_list.swap(item.dh_list);
        eh_list.swap(item.eh_list);
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // private member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    void xml_parser::
    get_next_token(
        std::istream& in,
        std::string& token_text,
        int& token_kind,
        unsigned long& line_number
    )
    {

        token_text.erase();

        std::istream::int_type ch1 = in.get();
        std::istream::int_type ch2;

        switch (ch1)
        {

        // -----------------------------------------

            // this is the start of some kind of a tag
        case '<':
            {
                ch2 = in.get();
                switch (ch2)
                {

                // ---------------------------------

                    // this is a dtd, comment, or chars_cdata token
                case '!':
                    {
                        // if this is a CDATA section *******************************
                        if ( in.peek() == '[')
                        {
                            token_kind = chars_cdata;

                            // throw away the '['
                            in.get();

                            // make sure the next chars are CDATA[
                            std::istream::int_type ch = in.get();
                            if (ch != 'C')
                                token_kind = error;
                            ch = in.get();
                            if (ch != 'D')
                                token_kind = error;
                            ch = in.get();
                            if (ch != 'A')
                                token_kind = error;
                            ch = in.get();
                            if (ch != 'T')
                                token_kind = error;
                            ch = in.get();
                            if (ch != 'A')
                                token_kind = error;
                            ch = in.get();
                            if (ch != '[')
                                token_kind = error;
                            // if this is an error token then end
                            if (token_kind == error)
                                break;

                            // get the rest of the chars and put them into token_text
                            int brackets_seen = 0; // this is the number of ']' chars
                                                   // we have seen in a row
                            bool seen_closing = false; // true if we have seen ]]>
                            do
                            {
                                ch = in.get();

                                if (ch == '\n')
                                    ++line_number;

                                token_text += ch;

                                // if this is the closing
                                if (brackets_seen == 2 && ch == '>')
                                    seen_closing = true;
                                // if we are seeing a bracket
                                else if (ch == ']')
                                    ++brackets_seen;
                                // if we didn't see a bracket
                                else
                                    brackets_seen = 0;

                            } while ( (!seen_closing) && (ch != EOF) );

                            // check if this is an error token
                            if (ch == EOF)
                            {
                                token_kind = error;
                            }
                            else
                            {
                                token_text.erase(token_text.size()-3);
                            }

                        }
                        // this is a comment token ****************************
                        else if (in.peek() == '-')
                        {

                            token_text += ch1;
                            token_text += ch2;
                            token_text += '-';

                            token_kind = comment;

                            // throw away the '-' char
                            in.get();

                            // make sure the next char is another '-'
                            std::istream::int_type ch = in.get();
                            if (ch != '-')
                            {
                                token_kind = error;
                                break;
                            }

                            token_text += '-';

                            // get the rest of the chars and put them into token_text
                            int hyphens_seen = 0; // this is the number of '-' chars
                                                   // we have seen in a row
                            bool seen_closing = false; // true if we have seen ]]>
                            do
                            {
                                ch = in.get();

                                if (ch == '\n')
                                    ++line_number;

                                token_text += ch;

                                // if this should be a closing block
                                if (hyphens_seen == 2)
                                {
                                    if (ch == '>')
                                        seen_closing = true;
                                    else // this isn't a closing so make it signal error
                                        ch = EOF;
                                }
                                // if we are seeing a hyphen
                                else if (ch == '-')
                                    ++hyphens_seen;
                                // if we didn't see a hyphen
                                else
                                    hyphens_seen = 0;

                            } while ( (!seen_closing) && (ch != EOF) );

                            // check if this is an error token
                            if (ch == EOF)
                            {
                                token_kind = error;
                            }

                        }
                        else // this is a dtd token *************************
                        {

                            token_text += ch1;
                            token_text += ch2;
                            int bracket_depth = 1;  // this is the number of '<' chars seen
                                                    // minus the number of '>' chars seen

                            std::istream::int_type ch;
                            do
                            {
                                ch = in.get();
                                if (ch == '>')
                                    --bracket_depth;
                                else if (ch == '<')
                                    ++bracket_depth;
                                else if (ch == '\n')
                                    ++line_number;

                                token_text += ch;

                            } while ( (bracket_depth > 0) && (ch != EOF) );

                            // make sure we didn't just hit EOF
                            if (bracket_depth == 0)
                            {
                                token_kind = dtd;
                            }
                            else
                            {
                                token_kind = error;
                            }
                        }
                    }
                    break;

                // ---------------------------------

                    // this is a pi token
                case '?':
                    {
                        token_text += ch1;
                        token_text += ch2;
                        std::istream::int_type ch;

                        do
                        {
                            ch = in.get();
                            token_text += ch;
                            if (ch == '\n')
                                ++line_number;
                            // else if we hit a < then thats an error
                            else if (ch == '<')
                                ch = EOF;
                        } while (ch != '>' && ch != EOF);
                        // if we hit the end of the pi
                        if (ch == '>')
                        {
                            // make sure there was a trailing '?'
                            if ( (token_text.size() > 3) &&
                                (token_text[token_text.size()-2] != '?')
                                )
                            {
                                token_kind = error;
                            }
                            else
                            {
                                token_kind = pi;
                            }
                        }
                        // if we hit EOF unexpectidely then error
                        else
                        {
                            token_kind = error;
                        }
                    }
                    break;

                // ---------------------------------

                    // this is an error token
                case EOF:
                    {
                        token_kind = error;
                    }
                    break;

                // ---------------------------------
                    // this is an element_end token
                case '/':
                    {
                        token_kind = element_end;
                        token_text += ch1;
                        token_text += ch2;
                        std::istream::int_type ch;
                        do
                        {
                            ch = in.get();
                            if (ch == '\n')
                                ++line_number;
                            // else if we hit a < then thats an error
                            else if (ch == '<')
                                ch = EOF;
                            token_text += ch;
                        } while ( (ch != '>') && (ch != EOF));

                        // check if this is an error token
                        if (ch == EOF)
                        {
                            token_kind = error;
                        }
                    }
                    break;

                // ---------------------------------

                    // this is an element_start or empty_element token
                default:
                    {

                        token_text += ch1;
                        token_text += ch2;
                        std::istream::int_type ch = '\0';
                        std::istream::int_type last;
                        do
                        {
                            last = ch;
                            ch = in.get();
                            if (ch == '\n')
                                ++line_number;
                            // else if we hit a < then thats an error
                            else if (ch == '<')
                                ch = EOF;
                            token_text += ch;
                        } while ( (ch != '>') && (ch != EOF));

                        // check if this is an error token
                        if (ch == EOF)
                        {
                            token_kind = error;
                        }
                        // if this is an empty_element
                        else if (last == '/')
                        {
                            token_kind = empty_element;
                        }
                        else
                        {
                            token_kind = element_start;
                        }

                    }
                    break;

                // ---------------------------------

                }

            }
            break;

        // -----------------------------------------

            // this is an eof token
        case EOF:
            {
                token_kind = eof;
            }
            break;

        // -----------------------------------------

            // this is a chars token
        default:
            {
                if (ch1 == '\n')
                {
                    ++line_number;
                    token_text += ch1;
                }
                // if the first thing in this chars token is an entity reference
                else if (ch1 == '&')
                {

                    int temp = change_entity(in);
                    if (temp == -1)
                    {
                        token_kind = error;
                        break;
                    }
                    else
                    {
                        token_text += temp;
                    }
                }
                else
                {
                    token_text += ch1;
                }

                token_kind = chars;

                std::istream::int_type ch = 0;
                while (in.peek() != '<' && in.peek() != EOF)
                {
                    ch = in.get();

                    if (ch == '\n')
                        ++line_number;

                    // if this is one of the predefined entity references then change it
                    if (ch == '&')
                    {
                        int temp = change_entity(in);
                        if (temp == -1)
                        {
                            ch = EOF;
                            break;
                        }
                        else
                            token_text += temp;
                    }
                    else
                    {
                        token_text += ch;
                    }
                }

                // if this is an error token
                if (ch == EOF)
                {
                    token_kind = error;
                }

            }
            break;

        // -----------------------------------------

        }

    }

// ----------------------------------------------------------------------------------------

    int xml_parser::
    parse_element (
        const std::string& token,
        std::string& name,
        attrib_list& atts
    )
    {
        name.erase();
        atts.list.clear();

        // there must be at least one character between the <>
        if (token[1] == '>')
            return -1;

        std::string::size_type i;
        std::istream::int_type ch = token[1];
        i = 2;

        // fill out name.  the name can not contain any of the following characters
        while ( (ch != '>') &&
                (ch != ' ') &&
                (ch != '=') &&
                (ch != '/') &&
                (ch != '\t') &&
                (ch != '\r') &&
                (ch != '\n')
            )
        {
            name += ch;
            ch = token[i];
            ++i;
        }

        // skip any whitespaces
        while ( ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' )
        {
             ch = token[i];
             ++i;
        }

        // find any attributes
        while (ch != '>' && ch != '/')
        {
            std::string attribute_name;
            std::string attribute_value;

            // fill out attribute_name
            while ( (ch != '=') &&
                    (ch != ' ') &&
                    (ch != '\t') &&
                    (ch != '\r') &&
                    (ch != '\n') &&
                    (ch != '>')
                    )
            {
                attribute_name += ch;
                ch = token[i];
                ++i;
            }

            // you can't have empty attribute names
            if (attribute_name.size() == 0)
                return -1;

            // if we hit > too early then return error
            if (ch == '>')
                return -1;

            // skip any whitespaces
            while (ch == ' ' || ch == '\t' || ch =='\n' || ch =='\r')
            {
                ch = token[i];
                ++i;
            }

            // the next char should be a '=', error if it's not
            if (ch != '=')
                return -1;

            // get the next char
            ch = token[i];
            ++i;

            // skip any whitespaces
            while (ch == ' ' || ch == '\t' || ch =='\n' || ch =='\r')
            {
                ch = token[i];
                ++i;
            }

            // get the delimiter for the attribute value
            std::istream::int_type delimiter = ch; // this should be either a ' or " character
            ch = token[i];  // get the next char
            ++i;
            if (delimiter != '\'' && delimiter!='"')
                return -1;

            // fill out attribute_value
            while ( (ch != delimiter) &&
                    (ch != '>')
                    )
            {
                attribute_value += ch;
                ch = token[i];
                ++i;
            }

            // if there was no delimiter then this is an error
            if (ch == '>')
            {
                return -1;
            }

            // go to the next char
            ch = token[i];
            ++i;

            // the next char must be either a '>' or '/' (denoting the end of the tag)
            // or a white space character
            if (ch != '>' && ch != ' ' && ch != '/' && ch != '\t' && ch !='\n' && ch !='\r')
                return -1;

            // skip any whitespaces
            while (ch == ' ' || ch == '\t' || ch =='\n' || ch =='\r')
            {
                ch = token[i];
                ++i;
            }

            // add attribute_value and attribute_name to atts
            if (atts.list.is_in_domain(attribute_name))
            {
                // attributes may not be multiply defined
                return -1;
            }
            else
            {
                atts.list.add(attribute_name,attribute_value);
            }

        }

        // you can't have an element with no name
        if (name.size() == 0)
            return -1;

        return 0;

    }

// ----------------------------------------------------------------------------------------

    int xml_parser::
    parse_pi (
        const std::string& token,
        std::string& target,
        std::string& data
    )
    {
        target.erase();
        data.erase();

        std::istream::int_type ch = token[2];
        std::string::size_type i = 3;
        while (ch != ' ' && ch != '?' && ch != '\t' && ch != '\n' && ch!='\r')
        {
            target += ch;
            ch = token[i];
            ++i;
        }
        if (target.size() == 0)
            return -1;

        // if we aren't at a ? character then go to the next character
        if (ch != '?' )
        {
            ch = token[i];
            ++i;
        }

        // if we still aren't at the end of the processing instruction then
        // set this stuff in the data section
        while (ch != '?')
        {
            data += ch;
            ch = token[i];
            ++i;
        }

        return 0;
    }

// ----------------------------------------------------------------------------------------

    int xml_parser::
    parse_element_end (
        const std::string& token,
        std::string& name
    )
    {
        name.erase();
        std::string::size_type end = token.size()-1;
        for (std::string::size_type i = 2; i < end; ++i)
        {
            if (token[i] == ' ' || token[i] == '\t' || token[i] == '\n'|| token[i] == '\r')
                break;
            name += token[i];
        }

        if (name.size() == 0)
            return -1;

        return 0;
    }

// ----------------------------------------------------------------------------------------

    int xml_parser::
    change_entity (
        std::istream& in
    )
    {

        std::istream::int_type buf[6];

        buf[1] = in.get();

        // if this is an undefined entity reference then return error
        if (buf[1] != 'a' &&
            buf[1] != 'l' &&
            buf[1] != 'g' &&
            buf[1] != 'q'
            )
            return -1;

        buf[2] = in.get();
        // if this is an undefined entity reference then return error
        if (buf[2] != 'm' &&
            buf[2] != 't' &&
            buf[2] != 'p' &&
            buf[2] != 'u'
            )
            return -1;

        buf[3] = in.get();
        // if this is an undefined entity reference then return error
        if (buf[3] != 'p' &&
            buf[3] != ';' &&
            buf[3] != 'o'
            )
            return -1;

        // check if this is &lt; or &gt;
        if  (buf[3] == ';')
        {
            if (buf[2] != 't')
                return -1;

            // if this is &lt; then return '<'
            if (buf[1] == 'l')
                return '<';
            // if this is &gt; then return '>'
            if (buf[1] == 'g')
                return '>';

            // it is neither so it must be an undefined entity reference
            return -1;
        }

        buf[4] = in.get();
        // if this should be &amp;
        if (buf[4] == ';')
        {
            // if this is not &amp; then return error
            if (buf[1] != 'a' ||
                buf[2] != 'm' ||
                buf[3] != 'p'
                )
                return -1;

            return '&';
        }

        buf[5] = in.get();

        // if this should be &apos;
        if (buf[1] == 'a' &&
            buf[2] == 'p' &&
            buf[3] == 'o' &&
            buf[4] == 's' &&
            buf[5] == ';'
            )
            return '\'';

        // if this should be &quot;
        if (buf[1] == 'q' &&
            buf[2] == 'u' &&
            buf[3] == 'o' &&
            buf[4] == 't' &&
            buf[5] == ';'
            )
            return '"';

        // it was an undefined entity reference
        return -1;

    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class xml_parse_error : public error
    {
    public:
        xml_parse_error(
            const std::string& a
        ): error(a) {}
    };

    namespace impl
    {
        class default_xml_error_handler : public error_handler
        {
            std::string filename;

        public:

            default_xml_error_handler (
            ) {}

            default_xml_error_handler (
                const std::string& filename_
            ) :filename(filename_) {}

            virtual void error (
                const unsigned long
            )
            {
                // just ignore non-fatal errors
            }

            virtual void fatal_error (
                const unsigned long line_number
            )
            {
                std::ostringstream sout;
                if (filename.size() != 0)
                    sout << "There is a fatal error on line " << line_number << " in the XML file '"<<filename<<"'.";
                else
                    sout << "There is a fatal error on line " << line_number << " in the XML being processed.";

                throw xml_parse_error(sout.str());
            }
        };
    }

    inline void parse_xml (
        std::istream& in,
        document_handler& dh,
        error_handler& eh
    )
    {
        if (!in)
            throw xml_parse_error("Unexpected end of file during xml parsing.");
        xml_parser parser;
        parser.add_document_handler(dh);
        parser.add_error_handler(eh);
        parser.parse(in);
    }

    inline void parse_xml (
        std::istream& in,
        error_handler& eh,
        document_handler& dh
    )
    {
        if (!in)
            throw xml_parse_error("Unexpected end of file during xml parsing.");
        xml_parser parser;
        parser.add_document_handler(dh);
        parser.add_error_handler(eh);
        parser.parse(in);
    }

    inline void parse_xml (
        std::istream& in,
        error_handler& eh
    )
    {
        if (!in)
            throw xml_parse_error("Unexpected end of file during xml parsing.");
        xml_parser parser;
        parser.add_error_handler(eh);
        parser.parse(in);
    }

    inline void parse_xml (
        std::istream& in,
        document_handler& dh
    )
    {
        if (!in)
            throw xml_parse_error("Unexpected end of file during xml parsing.");
        xml_parser parser;
        parser.add_document_handler(dh);
        impl::default_xml_error_handler eh;
        parser.add_error_handler(eh);
        parser.parse(in);
    }

// ----------------------------------------------------------------------------------------

    inline void parse_xml (
        const std::string& filename,
        document_handler& dh,
        error_handler& eh
    )
    {
        std::ifstream in(filename.c_str());
        if (!in)
            throw xml_parse_error("Unable to open file '" + filename + "'.");
        xml_parser parser;
        parser.add_document_handler(dh);
        parser.add_error_handler(eh);
        parser.parse(in);
    }

    inline void parse_xml (
        const std::string& filename,
        error_handler& eh,
        document_handler& dh
    )
    {
        std::ifstream in(filename.c_str());
        if (!in)
            throw xml_parse_error("Unable to open file '" + filename + "'.");
        xml_parser parser;
        parser.add_document_handler(dh);
        parser.add_error_handler(eh);
        parser.parse(in);
    }

    inline void parse_xml (
        const std::string& filename,
        error_handler& eh
    )
    {
        std::ifstream in(filename.c_str());
        if (!in)
            throw xml_parse_error("Unable to open file '" + filename + "'.");
        xml_parser parser;
        parser.add_error_handler(eh);
        parser.parse(in);
    }

    inline void parse_xml (
        const std::string& filename,
        document_handler& dh
    )
    {
        std::ifstream in(filename.c_str());
        if (!in)
            throw xml_parse_error("Unable to open file '" + filename + "'.");
        xml_parser parser;
        parser.add_document_handler(dh);
        impl::default_xml_error_handler eh(filename);
        parser.add_error_handler(eh);
        parser.parse(in);
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_XML_PARSER_KERNEl_1_


dlib C++ Library - xml_parser_kernel_interfaces.h

// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_XML_PARSER_KERNEl_INTERFACES_
#define DLIB_XML_PARSER_KERNEl_INTERFACES_

#include <string>
#include "../interfaces/enumerable.h"
#include "../interfaces/map_pair.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class attribute_list : public enumerable<map_pair<std::string,std::string> >
    {

        /*!
            WHAT THIS OBJECT REPRESENTS
                this object represents a list of the attributes found in
                an XML element.  each attribute is associated with a value.
        !*/

    public:

        inline virtual ~attribute_list (
        ) =0;

        virtual bool is_in_list (
            const std::string& key
        ) const =0;
        /*!
            ensures
                - returns true if there is an attribute named key in the list
                - returns false
        !*/

        virtual const std::string& operator[] (
            const std::string& key
        ) const =0;
        /*!
            requires
                - is_in_list(key) == true
            ensures
                - returns a const reference to the value associated with the
                  attribute named key.
        !*/

    protected:

        // restricted functions
        attribute_list& operator=(attribute_list&) {return *this;}
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class document_handler
    {
        /*!
            EXCEPTIONS
                a document_handler is allowed to throw any exception

            WHAT THIS OBJECT REPRESENTS
                this object is an interface for handling the basic events
                generated by an XML parser
        !*/

    public:

        inline virtual ~document_handler (
        ) =0;

        virtual void start_document (
        )=0;
        /*!
            requires
                - is called when the document parsing begins
        !*/

        virtual void end_document (
        )=0;
        /*!
            requires
                - is called after the document parsing has ended.  note that this
                  is always called, even if an error occurs.
        !*/

        virtual void start_element (
            const unsigned long line_number,
            const std::string& name,
            const dlib::attribute_list& atts
        )=0;
        /*!
            requires
                - is called when an opening element tag is encountered.
                - line_number == the line number where the opening tag for this element
                  was encountered.
                - name == the name of the element encountered
                - atts == a list containing all the attributes in this element and their
                  associated values
        !*/

        virtual void end_element (
            const unsigned long line_number,
            const std::string& name
        )=0;
        /*!
            requires
                - is called when a closing element tag is encountered. (note that this
                  includes tags such as <example_tag/>.  I.e. the previous tag would
                  trigger a start_element() callback as well as an end_element() callback)
                - line_number == the line number where the closing tag for this
                  element was encountered and
                - name == the name of the element encountered
        !*/

        virtual void characters (
            const std::string& data
        )=0;
        /*!
            requires
                - is called just before we encounter a start_element, end_element, or
                  processing_instruction tag but only if there was data between the
                  last and next tag.
                  (i.e. data will never be "")
                - data == all the normal non-markup data and CDATA between the next and
                  last tag in the document.
        !*/

        virtual void processing_instruction (
            const unsigned long line_number,
            const std::string& target,
            const std::string& data
        )=0;
        /*!
            requires
                - is called when a processing instruction is encountered
                - line_number == the line number where this processing instruction
                  was encountered
                - target == the target value for this processing instruction
                - data == the data value for this processing instruction
        !*/

    protected:

        // restricted functions
        document_handler& operator=(document_handler&) { return *this; }
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    class error_handler
    {
        /*!
            EXCEPTIONS
                an error_handler is allowed to throw any exception

            WHAT THIS OBJECT REPRESENTS
                this object is an interface for handling the error/warning
                events generated by an XML parser
        !*/

    public:

        inline virtual ~error_handler (
        ) =0;

        virtual void error (
            const unsigned long line_number
        )=0;
        /*!
            requires
                - is called when an error that does NOT require the parser to halt
                  is encountered. (i.e. somewhat minor errors in the input)
                - line_number == the line number where this error was encountered

            the following events trigger an error:
                an invalid processing instruction
        !*/

        virtual void fatal_error (
            const unsigned long line_number
        )=0;
        /*!
            requires
                - is called when an error that requires the parser to abort its parsing
                  is encountered (i.e. fatal errors in the input)
                - line_number == the line number where this fatal error was encountered

            the following events trigger a fatal_error:
                Everything other than the events listed above for error.
                Also note that encountering an entity reference other than the
                predefined ones listed in xml_parser_kernel_abstract is a fatal_error.
                Hitting EOF before the closing tag for the document is also a fatal_error.
        !*/

    protected:

        // restricted functions
        error_handler& operator=(error_handler&) { return *this;}
    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    document_handler::~document_handler (
    ){}
    attribute_list::~attribute_list (
    ){}
    error_handler::~error_handler (
    ){}

}

#endif // DLIB_XML_PARSER_KERNEl_INTERFACES_


examples/CMakeLists.txt

#
# 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.4)

PROJECT(examples)

include(../dlib/cmake)

# Tell CMake to compile a program.  We do this with the ADD_EXECUTABLE()
# statement which takes the name of the output executable and then a list of
# .cpp files to compile.  Here each example consists of only one .cpp file but
# in general you will make programs that const of many .cpp files.
ADD_EXECUTABLE(assignment_learning_ex assignment_learning_ex.cpp)
# Then we tell it to link with dlib.
TARGET_LINK_LIBRARIES(assignment_learning_ex dlib)

# Since there are a lot of examples I'm going to use a macro to simply this
# CMakeLists.txt file.  However, usually you will create only one executable in
# your cmake projects and use the syntax shown above.
MACRO(add_example name)
   ADD_EXECUTABLE(${name} ${name}.cpp)
   TARGET_LINK_LIBRARIES(${name} dlib )
ENDMACRO()

#here we apply our macros
add_example(3d_point_cloud_ex)
add_example(bayes_net_ex)
add_example(bayes_net_from_disk_ex)
add_example(bayes_net_gui_ex)
add_example(bridge_ex)
add_example(bsp_ex)
add_example(compress_stream_ex)
add_example(config_reader_ex)
add_example(custom_trainer_ex)
add_example(dir_nav_ex)
add_example(empirical_kernel_map_ex)
add_example(face_detection_ex)
add_example(face_landmark_detection_ex)
add_example(fhog_ex)
add_example(fhog_object_detector_ex)
add_example(file_to_code_ex)
add_example(graph_labeling_ex)
add_example(gui_api_ex)
add_example(hough_transform_ex)
add_example(image_ex)
add_example(integrate_function_adapt_simp_ex)
add_example(iosockstream_ex)
add_example(kcentroid_ex)
add_example(kkmeans_ex)
add_example(krls_ex)
add_example(krls_filter_ex)
add_example(krr_classification_ex)
add_example(krr_regression_ex)
add_example(learning_to_track_ex)
add_example(least_squares_ex)
add_example(linear_manifold_regularizer_ex)
add_example(logger_custom_output_ex)
add_example(logger_ex)
add_example(logger_ex_2)
add_example(matrix_ex)
add_example(matrix_expressions_ex)
add_example(max_cost_assignment_ex)
add_example(member_function_pointer_ex)
add_example(mlp_ex)
add_example(model_selection_ex)
add_example(mpc_ex)
add_example(multiclass_classification_ex)
add_example(multithreaded_object_ex)
add_example(object_detector_advanced_ex)
add_example(object_detector_ex)
add_example(one_class_classifiers_ex)
add_example(optimization_ex)
add_example(parallel_for_ex)
add_example(pipe_ex)
add_example(pipe_ex_2)
add_example(quantum_computing_ex)
add_example(queue_ex)
add_example(rank_features_ex)
add_example(running_stats_ex)
add_example(rvm_ex)
add_example(rvm_regression_ex)
add_example(sequence_labeler_ex)
add_example(sequence_segmenter_ex)
add_example(server_http_ex)
add_example(server_iostream_ex)
add_example(sockets_ex)
add_example(sockstreambuf_ex)
add_example(std_allocator_ex)
add_example(surf_ex)
add_example(svm_c_ex)
add_example(svm_ex)
add_example(svm_pegasos_ex)
add_example(svm_rank_ex)
add_example(svm_sparse_ex)
add_example(svm_struct_ex)
add_example(svr_ex)
add_example(thread_function_ex)
add_example(thread_pool_ex)
add_example(threaded_object_ex)
add_example(threads_ex)
add_example(timer_ex)
add_example(train_object_detector)
add_example(train_shape_predictor_ex)
add_example(using_custom_kernels_ex)
add_example(video_tracking_ex)
add_example(xml_parser_ex)

find_package(OpenCV)
if (OpenCV_FOUND)
   include_directories(${OpenCV_INCLUDE_DIRS})

   ADD_EXECUTABLE(webcam_face_pose_ex webcam_face_pose_ex.cpp)
   TARGET_LINK_LIBRARIES(webcam_face_pose_ex dlib ${OpenCV_LIBS} )
endif()

if (DLIB_LINK_WITH_SQLITE3)
   add_example(sqlite_ex)
endif()


Index — dlib documentation

Navigation

  • index
  • modules |
  • dlib documentation »

Index

A | B | C | D | E | F | G | H | I | L | M | N | O | P | R | S | T | U | V | W | X | Y

A

add_left_right_image_flips (dlib.simple_object_detector_training_options attribute)
add_overlay() (dlib.image_window method)
allow_negative_weights (dlib.segmenter_params attribute)
append() (dlib.array method)
(dlib.points method)
(dlib.ranges method)
(dlib.rangess method)
(dlib.ranking_pairs method)
(dlib.rectangles method)
(dlib.sparse_ranking_pairs method)
(dlib.sparse_vector method)
(dlib.sparse_vectors method)
(dlib.sparse_vectorss method)
(dlib.vectors method)
(dlib.vectorss method)
apply_cca_transform() (in module dlib)
area() (dlib.drectangle method)
(dlib.rectangle method)
array (class in dlib)
assignment_cost() (in module dlib)
average_precision (dlib.simple_test_results attribute)

B

be_quiet() (dlib.svm_c_trainer_linear method)
(dlib.svm_c_trainer_sparse_linear method)
(dlib.svm_rank_trainer method)
(dlib.svm_rank_trainer_sparse method)
be_verbose (dlib.segmenter_params attribute)
(dlib.shape_predictor_training_options attribute)
(dlib.simple_object_detector_training_options attribute)
be_verbose() (dlib.svm_c_trainer_linear method)
(dlib.svm_c_trainer_sparse_linear method)
(dlib.svm_rank_trainer method)
(dlib.svm_rank_trainer_sparse method)
begin (dlib.range attribute)
blue (dlib.rgb_pixel attribute)
bottom() (dlib.drectangle method)
(dlib.rectangle method)

C

C (dlib.segmenter_params attribute)
(dlib.simple_object_detector_training_options attribute)
c (dlib.svm_rank_trainer attribute)
(dlib.svm_rank_trainer_sparse attribute)
c_class1 (dlib.svm_c_trainer_histogram_intersection attribute)
(dlib.svm_c_trainer_linear attribute)
(dlib.svm_c_trainer_radial_basis attribute)
(dlib.svm_c_trainer_sparse_histogram_intersection attribute)
(dlib.svm_c_trainer_sparse_linear attribute)
(dlib.svm_c_trainer_sparse_radial_basis attribute)
c_class2 (dlib.svm_c_trainer_histogram_intersection attribute)
(dlib.svm_c_trainer_linear attribute)
(dlib.svm_c_trainer_radial_basis attribute)
(dlib.svm_c_trainer_sparse_histogram_intersection attribute)
(dlib.svm_c_trainer_sparse_linear attribute)
(dlib.svm_c_trainer_sparse_radial_basis attribute)
cache_size (dlib.svm_c_trainer_histogram_intersection attribute)
(dlib.svm_c_trainer_radial_basis attribute)
(dlib.svm_c_trainer_sparse_histogram_intersection attribute)
(dlib.svm_c_trainer_sparse_radial_basis attribute)
cascade_depth (dlib.shape_predictor_training_options attribute)
cca() (in module dlib)
cca_outputs (class in dlib)
center() (dlib.drectangle method)
(dlib.rectangle method)
clear() (dlib.array method)
(dlib.points method)
(dlib.ranges method)
(dlib.rangess method)
(dlib.ranking_pairs method)
(dlib.rectangles method)
(dlib.sparse_ranking_pairs method)
(dlib.sparse_vector method)
(dlib.sparse_vectors method)
(dlib.sparse_vectorss method)
(dlib.vectors method)
(dlib.vectorss method)
clear_overlay() (dlib.image_window method)
contains() (dlib.drectangle method)
(dlib.rectangle method)
correlation_tracker (class in dlib)
correlations (dlib.cca_outputs attribute)
cross_validate_ranking_trainer() (in module dlib)
cross_validate_sequence_segmenter() (in module dlib)
cross_validate_trainer() (in module dlib)
cross_validate_trainer_threaded() (in module dlib)

D

dcenter() (dlib.drectangle method)
(dlib.rectangle method)
detection_window_size (dlib.simple_object_detector_training_options attribute)
dlib (module)
dot() (in module dlib)
drectangle (class in dlib)

E

end (dlib.range attribute)
epsilon (dlib.segmenter_params attribute)
(dlib.simple_object_detector_training_options attribute)
(dlib.svm_c_trainer_histogram_intersection attribute)
(dlib.svm_c_trainer_linear attribute)
(dlib.svm_c_trainer_radial_basis attribute)
(dlib.svm_c_trainer_sparse_histogram_intersection attribute)
(dlib.svm_c_trainer_sparse_linear attribute)
(dlib.svm_c_trainer_sparse_radial_basis attribute)
(dlib.svm_rank_trainer attribute)
(dlib.svm_rank_trainer_sparse attribute)
extend() (dlib.array method)
(dlib.points method)
(dlib.ranges method)
(dlib.rangess method)
(dlib.ranking_pairs method)
(dlib.rectangles method)
(dlib.sparse_ranking_pairs method)
(dlib.sparse_vector method)
(dlib.sparse_vectors method)
(dlib.sparse_vectorss method)
(dlib.vectors method)
(dlib.vectorss method)

F

f1 (dlib.segmenter_test attribute)
feature_pool_region_padding (dlib.shape_predictor_training_options attribute)
feature_pool_size (dlib.shape_predictor_training_options attribute)
fhog_object_detector (class in dlib)
find_candidate_object_locations() (in module dlib)
first (dlib.pair attribute)
force_last_weight_to_1 (dlib.svm_c_trainer_linear attribute)
(dlib.svm_c_trainer_sparse_linear attribute)
(dlib.svm_rank_trainer attribute)
(dlib.svm_rank_trainer_sparse attribute)
full_object_detection (class in dlib)

G

gamma (dlib.svm_c_trainer_radial_basis attribute)
(dlib.svm_c_trainer_sparse_radial_basis attribute)
get_frontal_face_detector() (in module dlib)
get_position() (dlib.correlation_tracker method)
green (dlib.rgb_pixel attribute)

H

has_prior (dlib.svm_c_trainer_linear attribute)
(dlib.svm_c_trainer_sparse_linear attribute)
(dlib.svm_rank_trainer attribute)
(dlib.svm_rank_trainer_sparse attribute)
height() (dlib.drectangle method)
(dlib.rectangle method)
hit_enter_to_continue() (in module dlib)

I

image_window (class in dlib)
intersect() (dlib.drectangle method)
(dlib.rectangle method)
is_empty() (dlib.drectangle method)
(dlib.rectangle method)

L

lambda_param (dlib.shape_predictor_training_options attribute)
learns_nonnegative_weights (dlib.svm_c_trainer_linear attribute)
(dlib.svm_c_trainer_sparse_linear attribute)
(dlib.svm_rank_trainer attribute)
(dlib.svm_rank_trainer_sparse attribute)
left() (dlib.drectangle method)
(dlib.rectangle method)
load_libsvm_formatted_data() (in module dlib)
Ltrans (dlib.cca_outputs attribute)

M

make_sparse_vector() (in module dlib)
matrix (class in dlib)
max_cache_size (dlib.segmenter_params attribute)
max_cost_assignment() (in module dlib)
max_index_plus_one() (in module dlib)
max_iterations (dlib.svm_c_trainer_linear attribute)
(dlib.svm_c_trainer_sparse_linear attribute)
(dlib.svm_rank_trainer attribute)
(dlib.svm_rank_trainer_sparse attribute)

N

nc() (dlib.matrix method)
nonrelevant (dlib.ranking_pair attribute)
(dlib.sparse_ranking_pair attribute)
nr() (dlib.matrix method)
nu (dlib.shape_predictor_training_options attribute)
num_parts (dlib.full_object_detection attribute)
num_test_splits (dlib.shape_predictor_training_options attribute)
num_threads (dlib.segmenter_params attribute)
(dlib.simple_object_detector_training_options attribute)
num_trees_per_cascade_level (dlib.shape_predictor_training_options attribute)

O

oversampling_amount (dlib.shape_predictor_training_options attribute)

P

pair (class in dlib)
part() (dlib.full_object_detection method)
parts() (dlib.full_object_detection method)
point (class in dlib)
points (class in dlib)
precision (dlib.segmenter_test attribute)
(dlib.simple_test_results attribute)

R

random_seed (dlib.shape_predictor_training_options attribute)
range (class in dlib)
ranges (class in dlib)
rangess (class in dlib)
ranking_pair (class in dlib)
ranking_pairs (class in dlib)
recall (dlib.segmenter_test attribute)
(dlib.simple_test_results attribute)
rect (dlib.full_object_detection attribute)
rectangle (class in dlib)
rectangles (class in dlib)
red (dlib.rgb_pixel attribute)
relevant (dlib.ranking_pair attribute)
(dlib.sparse_ranking_pair attribute)
resize() (dlib.array method)
(dlib.points method)
(dlib.ranges method)
(dlib.rangess method)
(dlib.ranking_pairs method)
(dlib.rectangles method)
(dlib.sparse_ranking_pairs method)
(dlib.sparse_vector method)
(dlib.sparse_vectors method)
(dlib.sparse_vectorss method)
(dlib.vector method)
(dlib.vectors method)
(dlib.vectorss method)
rgb_pixel (class in dlib)
right() (dlib.drectangle method)
(dlib.rectangle method)
Rtrans (dlib.cca_outputs attribute)
run() (dlib.fhog_object_detector method)

S

save() (dlib.fhog_object_detector method)
(dlib.shape_predictor method)
(dlib.simple_object_detector method)
save_libsvm_formatted_data() (in module dlib)
second (dlib.pair attribute)
segmenter_params (class in dlib)
segmenter_test (class in dlib)
segmenter_type (class in dlib)
set_c() (dlib.svm_c_trainer_histogram_intersection method)
(dlib.svm_c_trainer_linear method)
(dlib.svm_c_trainer_radial_basis method)
(dlib.svm_c_trainer_sparse_histogram_intersection method)
(dlib.svm_c_trainer_sparse_linear method)
(dlib.svm_c_trainer_sparse_radial_basis method)
set_image() (dlib.image_window method)
set_prior() (dlib.svm_c_trainer_linear method)
(dlib.svm_c_trainer_sparse_linear method)
(dlib.svm_rank_trainer method)
(dlib.svm_rank_trainer_sparse method)
set_size() (dlib.matrix method)
(dlib.vector method)
set_title() (dlib.image_window method)
shape (dlib.matrix attribute)
(dlib.vector attribute)
shape_predictor (class in dlib)
shape_predictor_training_options (class in dlib)
simple_object_detector (class in dlib)
simple_object_detector_training_options (class in dlib)
simple_test_results (class in dlib)
solve_structural_svm_problem() (in module dlib)
sparse_ranking_pair (class in dlib)
sparse_ranking_pairs (class in dlib)
sparse_vector (class in dlib)
sparse_vectors (class in dlib)
sparse_vectorss (class in dlib)
start_track() (dlib.correlation_tracker method)
svm_c_trainer_histogram_intersection (class in dlib)
svm_c_trainer_linear (class in dlib)
svm_c_trainer_radial_basis (class in dlib)
svm_c_trainer_sparse_histogram_intersection (class in dlib)
svm_c_trainer_sparse_linear (class in dlib)
svm_c_trainer_sparse_radial_basis (class in dlib)
svm_rank_trainer (class in dlib)
svm_rank_trainer_sparse (class in dlib)

T

test_binary_decision_function() (in module dlib)
test_ranking_function() (in module dlib)
test_regression_function() (in module dlib)
test_sequence_segmenter() (in module dlib)
test_shape_predictor() (in module dlib)
test_simple_object_detector() (in module dlib)
top() (dlib.drectangle method)
(dlib.rectangle method)
train() (dlib.svm_c_trainer_histogram_intersection method)
(dlib.svm_c_trainer_linear method)
(dlib.svm_c_trainer_radial_basis method)
(dlib.svm_c_trainer_sparse_histogram_intersection method)
(dlib.svm_c_trainer_sparse_linear method)
(dlib.svm_c_trainer_sparse_radial_basis method)
(dlib.svm_rank_trainer method)
(dlib.svm_rank_trainer_sparse method)
train_sequence_segmenter() (in module dlib)
train_shape_predictor() (in module dlib)
train_simple_object_detector() (in module dlib)
tree_depth (dlib.shape_predictor_training_options attribute)

U

update() (dlib.correlation_tracker method)
use_BIO_model (dlib.segmenter_params attribute)
use_high_order_features (dlib.segmenter_params attribute)

V

vector (class in dlib)
vectors (class in dlib)
vectorss (class in dlib)

W

wait_until_closed() (dlib.image_window method)
weights (dlib.segmenter_type attribute)
width() (dlib.drectangle method)
(dlib.rectangle method)
window_size (dlib.segmenter_params attribute)

X

x (dlib.point attribute)

Y

y (dlib.point attribute)

Quick search

Enter search terms or a module, class or function name.

Navigation

  • index
  • modules |
  • dlib documentation »
© Copyright 2013, Davis E. King. Created using Sphinx 1.1.3.


Python Module Index — dlib documentation

Navigation

  • index
  • modules |
  • dlib documentation »

Python Module Index

d
d
dlib

Quick search

Enter search terms or a module, class or function name.

Navigation

  • index
  • modules |
  • dlib documentation »
© Copyright 2013, Davis E. King. Created using Sphinx 1.1.3.


.. image:: ../dlib-logo.png
   :alt: Dlib C++ Library
   :target: http://dlib.net

Dlib is principally a C++ library, however, you can use a number of its tools
from python applications.  This page documents the python API for working with
these dlib tools.  If you haven't done so already, you should probably look at
the python example programs first before consulting this reference.  These
example programs are little mini-tutorials for using dlib from python.  They
are listed on the left of the main dlib web page.

Classes
==============================================

.. include:: classes.txt

Functions
==============================================

.. include:: functions.txt

Detailed API Listing
==============================================

.. toctree::
   :maxdepth: 2

.. automodule:: dlib
   :members:
   :undoc-members: